Projet_AIF_HF / train.py
JulieLaurentt's picture
construction api
d164dd7
Raw
History Blame
5.26 kB
import argparse
from statistics import mean
import torch
import torchvision
import torchvision.transforms as transforms
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from tqdm import tqdm
from torch.utils.tensorboard import SummaryWriter
from torchvision import datasets
from torch.utils.data import DataLoader, random_split
from model import MovieposterNet
# setting device on GPU if available, else CPU
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
def train(net, optimizer, loader, writer,epochs=10):
criterion = nn.CrossEntropyLoss()
for epoch in range(epochs):
running_loss = []
t = tqdm(loader)
for x, y in t:
x, y = x.to(device), y.to(device)
outputs = net(x)
loss = criterion(outputs, y)
running_loss.append(loss.item())
optimizer.zero_grad()
loss.backward()
optimizer.step()
t.set_description(f'training loss: {mean(running_loss)}')
writer.add_scalar('training loss', mean(running_loss), epoch)
def test(model, dataloader):
test_corrects = 0
total = 0
with torch.no_grad():
for x, y in dataloader:
x = x.to(device)
y = y.to(device)
y_hat = model(x).argmax(1)
test_corrects += y_hat.eq(y).sum().item()
total += y.size(0)
return test_corrects / total
if __name__=='__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--exp_name', type=str, default = 'Movieposter', help='experiment name')
parser.add_argument('--epochs', type=int, default = int(10), help='nb of epochs')
parser.add_argument('--batch_size', type=int, default = int(64), help='batch size')
parser.add_argument('--lr', type=float, default = float(1e-3), help='learning rate')
args = parser.parse_args()
print(args.exp_name)
exp_name = args.exp_name
epochs = args.epochs
batch_size = args.batch_size
lr = args.lr
writer = SummaryWriter(f'runs/Movieposter')
# 1. Définition des transformations
# Les posters sont en couleur (3 canaux) et de tailles variées, contrairement à MNIST.
transform = transforms.Compose([
transforms.Resize((224, 224)), # Redimensionnement standard pour les modèles de vision
transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)) # Normalisation sur 3 canaux (RGB)
])
# 2. Chargement du dataset complet
# Le chemin '../' permet de remonter d'un niveau par rapport au dossier 'projet_AIF'
data_dir = '../sorted_movie_posters_paligema'
full_dataset = datasets.ImageFolder(root=data_dir, transform=transform)
# 3. Division en train/test (ex: 80% train, 20% test)
train_size = int(0.8 * len(full_dataset))
test_size = len(full_dataset) - train_size
trainset, testset = random_split(full_dataset, [train_size, test_size])
# 4. Création des DataLoaders
trainloader = DataLoader(trainset, batch_size=batch_size, shuffle=True, num_workers=2)
testloader = DataLoader(testset, batch_size=batch_size, shuffle=False, num_workers=2)
# Accès aux classes (genres)
classes = full_dataset.classes
print(f"Classes détectées : {classes}")
net =MovieposterNet().to(device)
# setting net on device(GPU if available, else CPU)
net = net.to(device)
optimizer = optim.Adam(net.parameters(),weight_decay=1e-4, lr=lr)
train(net, optimizer,trainloader, writer, epochs)
test_acc = test(net,testloader)
print(f'Test accuracy: {test_acc}')
# 1. Gestion du dossier de sauvegarde des poids
import os
if not os.path.exists('weights'):
os.makedirs('weights')
torch.save(net.state_dict(), 'weights/movieposter_net.pth')
# 2. Récupération d'un échantillon de données pour TensorBoard
# On utilise le loader pour obtenir des tenseurs déjà transformés
dataiter = iter(trainloader)
images, labels = next(dataiter)
# On limite à 64 images pour la visualisation et on envoie sur le device
images = images[:64].to(device)
labels = labels[:64].to(device)
# 3. Enregistrement du graphe du modèle
# Vérifiez que les dimensions d'entrée du modèle correspondent (ex: 3, 224, 224)
writer.add_graph(net, images)
# 4. Enregistrement d'une grille d'images
img_grid = torchvision.utils.make_grid(images)
writer.add_image('movieposter_samples', img_grid)
# 5. Projecteur d'embeddings
# get_features() doit être définie dans MovieposterNet pour retourner l'avant-dernière couche
with torch.no_grad():
try:
embeddings = net.get_features(images)
# Conversion des indices en noms de classes pour la lisibilité
metadata = [classes[l] for l in labels]
writer.add_embedding(embeddings,
metadata=metadata,
label_img=images,
global_step=epochs)
except AttributeError:
print("Erreur : La méthode get_features n'est pas définie dans MovieposterNet.")
# 6. Fermeture du SummaryWriter
writer.close()