Bonjour ! Dans les leçons précédentes, nous avons assemblé les briques fondamentales pour l'entraînement d'un réseau de neurones. Vous savez comment définir un modèle avec nn.Module, comment lui fournir des données via un DataLoader, comment le faire apprendre avec une boucle d'entraînement et comment mesurer ses performances avec une boucle d'évaluation.
Aujourd'hui, nous allons assembler toutes ces pièces pour construire et entraîner votre premier projet de deep learning de bout en bout. Nous prendrons un jeu de données tabulaires — similaire à ce que vous avez manipulé avec Pandas et Scikit-learn — et nous entraînerons un réseau de neurones pour effectuer une tâche de classification. Cette leçon est l'aboutissement de tout ce que vous avez appris jusqu'à présent, et elle vous donnera un plan de travail complet pour vos futurs projets.
La feuille de route d'un projet PyTorch
Avant de plonger dans le code, regardons la vue d'ensemble. Presque tous les projets de deep learning suivent un schéma similaire, magnifiquement illustré dans le diagramme ci-dessous.
Notre leçon d'aujourd'hui suivra précisément ce flux :
- Préparation des données : Charger, nettoyer et préparer nos données pour PyTorch.
- Définition du modèle : Construire l'architecture de notre réseau de neurones.
- Entraînement et validation : Implémenter la boucle qui entraîne et évalue le modèle.
- Évaluation finale : Utiliser le modèle entraîné pour faire des prédictions.
1. Préparation des données pour PyTorch
La première étape consiste à transformer nos données brutes en un format que PyTorch peut utiliser efficacement. Cela implique généralement plusieurs sous-étapes que vous avez déjà rencontrées dans les modules précédents.
- Chargement et division des données : On charge les données (par exemple, depuis un fichier CSV ou une bibliothèque comme Scikit-learn) et on les divise en ensembles d'entraînement et de test.
- Mise à l'échelle (Scaling) : Les réseaux de neurones sont sensibles à l'échelle des données. Il est donc crucial de normaliser ou standardiser les caractéristiques (features).
- Conversion en Tenseurs : PyTorch travaille avec des tenseurs. Nous devons donc convertir nos tableaux NumPy en tenseurs PyTorch.
- Création de
DatasetetDataLoader: Ce sont les outils de PyTorch pour gérer les données.Datasetest un objet qui encapsule nos données et permet d'y accéder par index.DataLoaderprend unDatasetet nous fournit des lots (batches) de données, ce qui est essentiel pour l'entraînement par descente de gradient stochastique.
La vidéo suivante est un excellent "crash course" qui met en œuvre toutes les étapes de cette leçon sur le jeu de données "Breast Cancer" de Scikit-learn.
Approfondissement : Créer un Dataset personnalisé
TensorDataset est pratique lorsque vos données tiennent déjà en mémoire sous forme de tenseurs. Cependant, pour des jeux de données plus grands ou plus complexes, vous créerez souvent votre propre classe Dataset en héritant de torch.utils.data.Dataset. C'est une compétence clé.
Pour cela, vous devez implémenter trois méthodes principales :
__init__(self, ...): Le constructeur, où vous chargez vos données (par exemple, lire un fichier CSV avec Pandas).__len__(self): Doit retourner le nombre total d'échantillons dans votre jeu de données.__getitem__(self, idx): Doit retourner le i-ème échantillon (caractéristiques et étiquette) de votre jeu de données.
La vidéo suivante vous montre comment implémenter une telle classe pour un jeu de données tabulaires.
2. Définir le Modèle, la Perte et l'Optimiseur
Une fois les données prêtes, l'étape suivante consiste à définir les trois composants principaux de notre entraînement :
- Le Modèle : Nous allons définir une classe qui hérite de
nn.Module. À l'intérieur, nous définirons nos couches (principalement desnn.Linearpour les données tabulaires) et la fonctionforwardqui décrit comment les données traversent le réseau. - La Fonction de Perte (Criterion) : Elle mesure à quel point les prédictions du modèle sont erronées. Pour la classification binaire,
nn.BCELoss(Binary Cross-Entropy Loss) ounn.BCEWithLogitsLossest le choix standard.BCEWithLogitsLossest souvent préféré car il est numériquement plus stable (il combine une couche Sigmoid et la perte BCE). - L'Optimiseur : C'est l'algorithme qui met à jour les poids du modèle pour minimiser la perte.
optim.Adamest un choix très populaire et robuste qui fonctionne bien dans la plupart des cas.
Reprenons notre "crash course" vidéo pour voir comment ces trois éléments sont mis en place.
3. La Boucle d'Entraînement Complète
Nous arrivons au cœur du processus. C'est ici que nous allons itérer sur nos données, faire des prédictions, calculer la perte et mettre à jour le modèle, époque après époque. Les étapes à l'intérieur de la boucle d'entraînement sont maintenant familières.
Le code ci-dessous rassemble tout : une boucle sur les époques, et à l'intérieur de chaque époque, une boucle sur les lots de données fournis par le DataLoader.
# Définir le nombre d'époques
num_epochs = 20
# Mettre le modèle sur le bon appareil (CPU ou GPU)
model.to(device)
for epoch in range(num_epochs):
# Mettre le modèle en mode entraînement
model.train()
running_loss = 0.0
# Itérer sur les lots du DataLoader d'entraînement
for inputs, labels in train_loader:
# Mettre les données sur le bon appareil
inputs, labels = inputs.to(device), labels.to(device)
# 1. Mise à zéro des gradients de l'optimiseur
optimizer.zero_grad()
# 2. Passe avant : faire des prédictions
outputs = model(inputs)
# 3. Calculer la perte
loss = criterion(outputs, labels)
# 4. Rétropropagation : calculer les gradients
loss.backward()
# 5. Mise à jour des poids
optimizer.step()
# Accumuler la perte pour l'affichage
running_loss += loss.item()
# Afficher la perte moyenne pour l'époque
print(f"Epoch {epoch+1}/{num_epochs}, Loss: {running_loss/len(train_loader)}")
# (Optionnel mais recommandé) Exécuter une boucle d'évaluation sur le jeu de validation ici
La vidéo "Crash Course" implémente cette logique très clairement.
4. Évaluation et Prédiction
Une fois le modèle entraîné, il nous faut évaluer sa performance sur des données qu'il n'a jamais vues : l'ensemble de test. Cette boucle est plus simple car nous n'avons pas besoin de calculer de gradients ni de mettre à jour les poids. Comme nous l'avons vu dans la leçon précédente, nous utilisons with torch.no_grad(): et model.eval().
Enfin, pour faire une prédiction sur une nouvelle donnée, le processus est le même :
- Prétraiter la nouvelle donnée exactement de la même manière que les données d'entraînement (notamment la mise à l'échelle).
- La convertir en tenseur.
- La passer au modèle (en mode
eval).
La dernière partie de la vidéo montre exactement cela.
Conclusion
Félicitations ! Vous avez maintenant parcouru toutes les étapes nécessaires pour mener à bien un projet de classification sur données tabulaires avec PyTorch. Vous disposez d'un modèle de travail que vous pouvez adapter à de nombreux autres problèmes.
Points clés à retenir :
- Un projet PyTorch suit un flux structuré : préparation des données, définition du modèle, configuration de l'entraînement, boucle d'entraînement/évaluation, et utilisation du modèle.
- Les données doivent être transformées en tenseurs et gérées avec les classes
DatasetetDataLoaderpour un entraînement efficace par lots. - Le modèle est défini comme une classe héritant de
nn.Module, avec les couches dans__init__et la logique de passe avant dansforward. - La boucle d'entraînement est le cœur du processus, orchestrant la passe avant, le calcul de la perte, la rétropropagation et la mise à jour des poids via l'optimiseur.
- L'évaluation sur un jeu de test distinct, en mode
model.eval()ettorch.no_grad(), est cruciale pour mesurer la performance réelle du modèle.
Maintenant que vous maîtrisez les réseaux de neurones feedforward sur des données structurées, nous sommes prêts à explorer des architectures plus spécialisées. Dans la prochaine leçon, nous nous plongerons dans le monde de la vision par ordinateur en découvrant les réseaux de neurones convolutifs (CNNs), conçus spécifiquement pour traiter des données comme les images.