Spaces:
Sleeping
Sleeping
| import torch | |
| import torch.nn as nn | |
| from torch.utils.data import DataLoader, random_split | |
| from torchvision import transforms | |
| from tqdm import tqdm | |
| from datasets import load_dataset | |
| from utils.preprocessing import get_transforms | |
| from src.dataset import HumanActionDataset | |
| from models.resnet_model import ResNet18 | |
| import os | |
| def train_model(): | |
| device = torch.device("cuda" if torch.cuda.is_available() else "cpu") | |
| print(f"Using device: {device}") | |
| # Load dataset from Hugging Face | |
| ds = load_dataset("Bingsu/Human_Action_Recognition") | |
| # Get train dataset and apply transforms | |
| transform = get_transforms() | |
| full_dataset = HumanActionDataset(ds["train"], transform=transform) | |
| # Split train into train/val (e.g., 90% train, 10% val) | |
| train_size = int(0.9 * len(full_dataset)) | |
| val_size = len(full_dataset) - train_size | |
| train_dataset, val_dataset = random_split(full_dataset, [train_size, val_size]) | |
| # Use batch size 32 (good balance between speed and generalization on CPU) | |
| train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True, num_workers=4) | |
| val_loader = DataLoader(val_dataset, batch_size=32, shuffle=False, num_workers=4) | |
| # Initialize model | |
| model = ResNet18(num_classes=15).to(device) | |
| criterion = nn.CrossEntropyLoss() | |
| optimizer = torch.optim.Adam(model.parameters(), lr=0.001) | |
| # Scheduler without verbose (fix for your PyTorch version) | |
| scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau( | |
| optimizer, mode='min', factor=0.5, patience=2 | |
| ) | |
| best_val_acc = 0.0 | |
| epochs = 10 | |
| for epoch in range(epochs): | |
| model.train() | |
| train_loss = 0.0 | |
| correct = 0 | |
| total = 0 | |
| loop = tqdm(train_loader, desc=f"Epoch {epoch+1}/{epochs} Training") | |
| for images, labels in loop: | |
| images, labels = images.to(device), labels.to(device) | |
| optimizer.zero_grad() | |
| outputs = model(images) | |
| loss = criterion(outputs, labels) | |
| loss.backward() | |
| optimizer.step() | |
| train_loss += loss.item() * images.size(0) | |
| _, predicted = torch.max(outputs, 1) | |
| total += labels.size(0) | |
| correct += (predicted == labels).sum().item() | |
| loop.set_postfix(loss=loss.item(), acc=correct/total) | |
| train_loss /= total | |
| train_acc = correct / total | |
| # Validation | |
| model.eval() | |
| val_loss = 0.0 | |
| val_correct = 0 | |
| val_total = 0 | |
| with torch.no_grad(): | |
| for images, labels in val_loader: | |
| images, labels = images.to(device), labels.to(device) | |
| outputs = model(images) | |
| loss = criterion(outputs, labels) | |
| val_loss += loss.item() * images.size(0) | |
| _, predicted = torch.max(outputs, 1) | |
| val_total += labels.size(0) | |
| val_correct += (predicted == labels).sum().item() | |
| val_loss /= val_total | |
| val_acc = val_correct / val_total | |
| print(f"Epoch {epoch+1}/{epochs} | " | |
| f"Train Loss: {train_loss:.4f} | Train Acc: {train_acc:.4f} | " | |
| f"Val Loss: {val_loss:.4f} | Val Acc: {val_acc:.4f}") | |
| # Step the scheduler with validation loss | |
| scheduler.step(val_loss) | |
| # Save best model | |
| if val_acc > best_val_acc: | |
| best_val_acc = val_acc | |
| os.makedirs("models", exist_ok=True) | |
| torch.save(model.state_dict(), "models/best_model.pth") | |
| print("Saved best model.") | |
| if __name__ == "__main__": | |
| train_model() | |