Spaces:
Configuration error
Configuration error
Download ml/train.py from Samidha21/emosaic-backend: direct link, hf CLI and curl.
- Browser
- Download file 4.54 kB
-
https://huggingface.co/spaces/Samidha21/emosaic-backend/resolve/main/ml/train.py
- Command line
-
hf download hf://spaces/Samidha21/emosaic-backend/ml/train.py
-
curl -L -o train.py https://huggingface.co/spaces/Samidha21/emosaic-backend/resolve/main/ml/train.py
4.54 kB
| import torch | |
| import torch.nn as nn | |
| from torch.utils.data import DataLoader, random_split | |
| from ml.dataset import build_dataset, get_transform | |
| from ml.model import PatchCNN | |
| # ββ Config ββββββββββββββββββββββββββββββββββββββββββ | |
| BATCH_SIZE = 64 | |
| EPOCHS = 15 | |
| LEARNING_RATE = 0.001 | |
| VAL_SPLIT = 0.2 | |
| CHECKPOINT_PATH = "checkpoints/model.pth" | |
| ADE20K_ROOT = "data/raw/ade20k" | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def train(): | |
| # device β use GPU if available, otherwise CPU | |
| device = torch.device("cuda" if torch.cuda.is_available() else "cpu") | |
| print(f"Training on: {device}") | |
| # ββ Data ββ | |
| print("\nLoading dataset...") | |
| dataset = build_dataset(ADE20K_ROOT, transform=get_transform()) | |
| val_size = int(len(dataset) * VAL_SPLIT) | |
| train_size = len(dataset) - val_size | |
| train_set, val_set = random_split(dataset, [train_size, val_size]) | |
| train_loader = DataLoader( | |
| train_set, | |
| batch_size=BATCH_SIZE, | |
| shuffle=True, | |
| num_workers=0 # keep 0 on Windows to avoid multiprocessing issues | |
| ) | |
| val_loader = DataLoader( | |
| val_set, | |
| batch_size=BATCH_SIZE, | |
| shuffle=False, | |
| num_workers=0 | |
| ) | |
| print(f"Train samples: {train_size}") | |
| print(f"Val samples: {val_size}") | |
| # ββ Model ββ | |
| model = PatchCNN(num_classes=7).to(device) | |
| # ββ Loss ββ | |
| # CrossEntropyLoss = softmax + negative log likelihood | |
| # standard for multi-class classification | |
| criterion = nn.CrossEntropyLoss() | |
| # ββ Optimizer ββ | |
| # Adam β adaptive learning rate, works well out of the box | |
| optimizer = torch.optim.Adam(model.parameters(), lr=LEARNING_RATE) | |
| # ββ LR Scheduler ββ | |
| # reduces learning rate by 0.5 if val loss doesn't improve for 3 epochs | |
| # prevents overshooting the optimal weights late in training | |
| scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau( | |
| optimizer, | |
| patience=3, | |
| factor=0.5 | |
| ) | |
| # ββ Training Loop ββ | |
| best_val_acc = 0.0 | |
| for epoch in range(EPOCHS): | |
| # ββ Train phase ββ | |
| model.train() | |
| train_loss = 0.0 | |
| train_correct = 0 | |
| for batch_idx, (patches, labels) in enumerate(train_loader): | |
| patches = patches.to(device) | |
| labels = labels.to(device) | |
| # forward pass | |
| outputs = model(patches) | |
| loss = criterion(outputs, labels) | |
| # backward pass | |
| optimizer.zero_grad() | |
| loss.backward() | |
| optimizer.step() | |
| train_loss += loss.item() | |
| # count correct predictions | |
| predicted = outputs.argmax(dim=1) | |
| train_correct += (predicted == labels).sum().item() | |
| # print progress every 50 batches | |
| if (batch_idx + 1) % 50 == 0: | |
| print(f" Epoch {epoch+1} | Batch {batch_idx+1}/{len(train_loader)} | Loss: {loss.item():.4f}") | |
| train_acc = train_correct / train_size | |
| # ββ Validation phase ββ | |
| model.eval() | |
| val_loss = 0.0 | |
| val_correct = 0 | |
| with torch.no_grad(): # no gradients needed for validation | |
| for patches, labels in val_loader: | |
| patches = patches.to(device) | |
| labels = labels.to(device) | |
| outputs = model(patches) | |
| loss = criterion(outputs, labels) | |
| val_loss += loss.item() | |
| predicted = outputs.argmax(dim=1) | |
| val_correct += (predicted == labels).sum().item() | |
| val_acc = val_correct / val_size | |
| print(f"\nEpoch {epoch+1}/{EPOCHS}") | |
| print(f" Train Loss: {train_loss/len(train_loader):.4f} | Train Acc: {train_acc:.4f}") | |
| print(f" Val Loss: {val_loss/len(val_loader):.4f} | Val Acc: {val_acc:.4f}") | |
| # step scheduler with val loss | |
| scheduler.step(val_loss / len(val_loader)) | |
| # save best model | |
| if val_acc > best_val_acc: | |
| best_val_acc = val_acc | |
| torch.save(model.state_dict(), CHECKPOINT_PATH) | |
| print(f" β saved best model (val_acc: {val_acc:.4f})") | |
| print(f"\nTraining complete. Best val accuracy: {best_val_acc:.4f}") | |
| print(f"Model saved to {CHECKPOINT_PATH}") | |
| if __name__ == "__main__": | |
| train() |