Ogoun09gerbad
Final Update: Robust UI and Models
a3fe311
Raw
History Blame Contribute Delete
4.66 kB
import torch
from torch import nn
from tqdm import tqdm
import matplotlib.pyplot as plt
class Trainer:
def __init__(self, model, train_dataloader, val_dataloader, test_dataloader,
lr, wd, epochs, device):
self.epochs = epochs
self.model = model
self.train_dataloader = train_dataloader
self.val_dataloader = val_dataloader
self.test_dataloader = test_dataloader
self.device = device
self.optimizer = torch.optim.Adam(model.parameters(), lr=lr, weight_decay=wd)
self.scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(self.optimizer, T_max=epochs, eta_min=1e-6)
self.criterion = nn.CrossEntropyLoss()
self.patience = 10
self.no_improve = 0
self.best_acc = 0
def train(self, save=True, plot=False):
self.train_acc = []
self.train_loss = []
self.val_accs = []
self.val_losses = []
for epoch in range(self.epochs):
self.model.train()
total_loss = 0
total_correct = 0
total_samples = 0
progress_bar = tqdm(self.train_dataloader, desc=f"Epoch {epoch + 1}/{self.epochs}", leave=False)
for inputs, labels in progress_bar:
inputs, labels = inputs.to(self.device), labels.to(self.device)
self.optimizer.zero_grad()
outputs = self.model(inputs)
loss = self.criterion(outputs, labels)
loss.backward()
self.optimizer.step()
_, preds = outputs.max(1)
total_correct += (preds == labels).sum().item()
total_samples += labels.size(0)
total_loss += loss.item() * labels.size(0)
avg_acc = 100.0 * total_correct / total_samples
avg_loss = total_loss / total_samples
progress_bar.set_postfix({'Acc': f'{avg_acc:.2f}%', 'Loss': f'{avg_loss:.4f}'})
self.scheduler.step()
self.train_acc.append(avg_acc)
self.train_loss.append(avg_loss)
# VALIDATION
val_acc, val_loss = self.evaluate(self.val_dataloader)
self.val_accs.append(val_acc)
self.val_losses.append(val_loss)
print(f"\nEpoch {epoch+1}/{self.epochs}")
print(f"Train Loss: {avg_loss:.4f} | Train Acc: {avg_acc:.2f}%")
print(f"Val Loss: {val_loss:.4f} | Val Acc: {val_acc:.2f}%")
if val_acc > self.best_acc:
self.best_acc = val_acc
self.no_improve = 0
if save:
torch.save(self.model.state_dict(), "geraud_model.pth")
print(f" Best model saved (val_acc={val_acc:.2f}%)")
else:
self.no_improve += 1
print(f"No improvement ({self.no_improve}/{self.patience})")
if self.no_improve >= self.patience:
print(" Early stopping triggered")
break
if plot:
self.plot_training_history()
@torch.no_grad()
def evaluate(self, dataloader):
self.model.eval()
total_loss, total_correct, total_samples = 0, 0, 0
for inputs, labels in tqdm(dataloader, desc="Evaluating", leave=False):
inputs, labels = inputs.to(self.device), labels.to(self.device)
outputs = self.model(inputs)
loss = self.criterion(outputs, labels)
_, preds = outputs.max(1)
total_correct += (preds == labels).sum().item()
total_samples += labels.size(0)
total_loss += loss.item() * labels.size(0)
return 100.0 * total_correct / total_samples, total_loss / total_samples
def test(self):
print("\n Final Test Evaluation:")
return self.evaluate(self.test_dataloader)
def plot_training_history(self):
epochs = range(1, len(self.train_loss) + 1)
plt.figure(figsize=(12, 5))
# Accuracy plot
plt.subplot(1, 2, 1)
plt.plot(epochs, self.train_acc, label="Train Accuracy")
plt.plot(epochs, self.val_accs, label="Validation Accuracy")
plt.title("Accuracy")
plt.legend()
# Loss plot
plt.subplot(1, 2, 2)
plt.plot(epochs, self.train_loss, label="Train Loss")
plt.plot(epochs, self.val_losses, label="Validation Loss")
plt.title("Loss")
plt.legend()
plt.tight_layout()
plt.savefig("training_history.png")
plt.show()