transponster27's picture
upload scripts
73b7d9e verified
Raw
History Blame Contribute Delete
5.61 kB
from pathlib import Path
import json
import pickle
import torch
import torch.nn as nn
from torch.optim import Adam
from torch.optim.lr_scheduler import ReduceLROnPlateau
from src.logger import get_logger
from src.model import build_model
logger = get_logger(__name__)
def train(
train_loader,
val_loader,
target_epochs=50
):
logger.info("Training pipeline started")
# Directories
Path("models").mkdir(exist_ok=True)
Path("outputs").mkdir(exist_ok=True)
Path("outputs/reports").mkdir(parents=True, exist_ok=True)
model_path = Path("models/resnet_cifar10.pth")
best_model_path = Path("models/best_resnet_cifar10.pth")
history_file = Path("outputs/history.pkl")
# Device
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
logger.info(f"Device: {device}")
# Model
model = build_model().to(device)
criterion = nn.CrossEntropyLoss(
label_smoothing=0.1
)
optimizer = Adam(
model.parameters(),
lr=1e-4,
weight_decay=1e-4
)
scheduler = ReduceLROnPlateau(
optimizer,
mode="min",
factor=0.5,
patience=3
)
# Resume Training
start_epoch = 0
if model_path.exists():
logger.info(
"Loading checkpoint"
)
checkpoint = torch.load(
model_path,
map_location=device
)
model.load_state_dict(
checkpoint["model"]
)
optimizer.load_state_dict(
checkpoint["optimizer"]
)
scheduler.load_state_dict(
checkpoint["scheduler"]
)
start_epoch = checkpoint[
"epoch"
]
logger.info(
f"Resuming from epoch {start_epoch}"
)
# Loss + Optimizer
criterion = nn.CrossEntropyLoss(label_smoothing=0.1)
optimizer = Adam(
model.parameters(),
lr=1e-4,
weight_decay=1e-4
)
scheduler = ReduceLROnPlateau(
optimizer,
mode="min",
factor=0.5,
patience=3
)
# History
if history_file.exists():
with open(history_file, "rb") as f:
history = pickle.load(f)
else:
history = {
"loss": [],
"accuracy": [],
"val_loss": [],
"val_accuracy": []
}
# Early stopping
best_val_loss = float("inf")
patience = 5
early_counter = 0
# Training loop
for epoch in range(start_epoch, target_epochs):
logger.info(f"Epoch {epoch+1}/{target_epochs}")
# TRAIN
model.train()
train_loss = 0.0
correct = 0
total = 0
for images, labels in train_loader:
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()
preds = outputs.argmax(dim=1)
correct += (preds == labels).sum().item()
total += labels.size(0)
train_loss /= len(train_loader)
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()
preds = outputs.argmax(dim=1)
val_correct += (preds == labels).sum().item()
val_total += labels.size(0)
val_loss /= len(val_loader)
val_acc = val_correct / val_total
scheduler.step(val_loss)
logger.info(
f"Train Loss: {train_loss:.4f} | Train Acc: {train_acc:.4f}"
)
logger.info(
f"Val Loss: {val_loss:.4f} | Val Acc: {val_acc:.4f}"
)
# HISTORY
history["loss"].append(train_loss)
history["accuracy"].append(train_acc)
history["val_loss"].append(val_loss)
history["val_accuracy"].append(val_acc)
# SAVE LAST MODEL
torch.save(
{
"epoch": epoch + 1,
"model":
model.state_dict(),
"optimizer":
optimizer.state_dict(),
"scheduler":
scheduler.state_dict(),
"best_val_loss":
best_val_loss
},
model_path
)
# SAVE BEST MODEL
if val_loss < best_val_loss:
best_val_loss = val_loss
early_counter = 0
torch.save(
model.state_dict(),
best_model_path
)
logger.info(
"New best model saved"
)
else:
early_counter += 1
# SAVE STATE
with open(history_file, "wb") as f:
pickle.dump(history, f)
# EARLY STOPPING
if early_counter >= patience:
logger.info("Early stopping triggered")
break
logger.info("Training completed")
return history