Aller au contenu
English
Compte : non connecté, synchronisation possible Mon apprentissage
Selectionner le thème
English

PyTorch : entraîner un réseau de neurones sur CPU

Par mis à jour le

Améliorer cette page

PyTorch est un framework de deep learning très répandu : il permet de définir un réseau de neurones, de l'entraîner sur CPU (le processeur) ou sur GPU (la carte graphique), et de lui faire apprendre des motifs complexes en quelques lignes. Cette leçon, facultative, construit un réseau qui apprend une frontière non linéaire, l'entraîne sur CPU en une fraction de seconde, puis montre ce qu'il a appris.

Vous verrez comment définir un réseau avec torch.nn, la boucle d'entraînement (passe avant, perte, rétropropagation, optimiseur), et pourquoi un réseau réussit là où un modèle linéaire échoue. Elle prolonge la leçon Deep learning. Tous les chiffres viennent d'une exécution sur CPU avec PyTorch 2.14.1 ; la variante GPU est présentée comme option, sans mesure.

  • Installer PyTorch 2.14.1 pour CPU dans un environnement isolé.
  • Définir un réseau de neurones avec torch.nn.
  • Écrire une boucle d'entraînement complète.
  • Choisir le calcul sur CPU ou GPU avec .to(device).
  • Lire la frontière de décision apprise par le réseau.

Il faut savoir écrire un script Python (fonctions, boucles, modules) et lancer un environnement virtuel, comme dans la formation Python : les fondamentaux. Les notions de réseau de neurones, de perte et de rétropropagation viennent de la leçon Deep learning, et la comparaison avec un modèle linéaire de la leçon Régression linéaire. Aucune carte graphique n'est nécessaire.

PyTorch est une bibliothèque Python qui manipule des tenseurs (des tableaux multidimensionnels) avec accélération GPU et différentiation automatique. Ces deux briques sont le coeur du deep learning : les tenseurs portent les données et les poids, l'autograd calcule automatiquement les gradients (de combien et dans quel sens modifier chaque poids) nécessaires à la rétropropagation.

Concrètement, vous décrivez le réseau et la perte à minimiser, et PyTorch se charge de calculer comment ajuster chaque poids. C'est ce qui rend possible l'entraînement de réseaux à des millions de paramètres.

Pour une machine sans carte graphique, on installe la variante CPU de PyTorch dans un environnement virtuel dédié. PyTorch est un paquet volumineux : un venv Python le garde à l'écart de l'environnement conda data de la formation, qui reste réservé à scikit-learn et à Jupyter. Les trois bibliothèques sont épinglées aux versions utilisées pour cette leçon :

Fenêtre de terminal
python3 -m venv venv && source venv/bin/activate
pip install torch==2.14.1 --index-url https://download.pytorch.org/whl/cpu
pip install numpy==2.5.4 matplotlib==3.11.2

L'option --index-url désigne l'index de paquets de PyTorch pour le CPU, à la place de PyPI. Vérifiez l'installation et l'absence de GPU :

import torch
print(torch.__version__)
print(torch.cuda.is_available())
2.14.1+cpu
False

Le suffixe +cpu confirme la variante installée, et False signifie qu'aucun GPU n'est disponible : le code de la leçon choisira donc le CPU tout seul.

Comment exécuter les blocs de code de cette leçon ?

Section intitulée « Comment exécuter les blocs de code de cette leçon ? »

Enregistrez les blocs Python des sections suivantes, dans l'ordre, dans un seul fichier lunes.py, puis lancez python lunes.py dans le venv activé. Chaque bloc réutilise les variables du précédent (model, Xtr, device), et le dernier trace la figure. Deux autres façons de faire échouent, toutes deux mesurées pour cette leçon :

  • le notebook de l'environnement data ne convient pas, car torch n'y est pas installé : import torch y lève ModuleNotFoundError: No module named 'torch' ;
  • le collage dans l'interpréteur interactif ne convient pas non plus : la boucle for suivie d'une instruction en colonne 0, sans ligne vide, lève un SyntaxError.

Le script écrit la figure frontiere.png dans le dossier courant.

Pour montrer l'intérêt d'un réseau de neurones, on utilise un jeu de données qu'un modèle linéaire (une droite de séparation, comme dans la leçon Régression linéaire) ne peut pas séparer : deux lunes entrelacées, 800 points pour l'entraînement et 200 pour le test. On les génère avec NumPy, puis on les convertit en tenseurs placés sur le bon device : le GPU s'il existe, sinon le CPU, comme ici.

import torch, time, numpy as np
from torch import nn
torch.manual_seed(42); np.random.seed(42)
device = "cuda" if torch.cuda.is_available() else "cpu"
def make_moons(n=1000, noise=0.15):
n2 = n // 2; t = np.linspace(0, np.pi, n2)
x1 = np.stack([np.cos(t), np.sin(t)], 1)
x2 = np.stack([1 - np.cos(t), 1 - np.sin(t) - 0.5], 1)
X = np.vstack([x1, x2]); y = np.array([0] * n2 + [1] * n2)
X += noise * np.random.randn(*X.shape)
return X.astype("float32"), y.astype("int64")
X, y = make_moons(1000)
idx = np.random.permutation(len(X)); tr, te = idx[:800], idx[800:]
Xtr = torch.tensor(X[tr]).to(device); ytr = torch.tensor(y[tr]).to(device)
Xte = torch.tensor(X[te]).to(device); yte = torch.tensor(y[te]).to(device)

Un réseau se décrit comme un empilement de couches. Ici, deux couches cachées de 16 neurones avec une activation ReLU, et une sortie à deux classes :

model = nn.Sequential(
nn.Linear(2, 16), nn.ReLU(),
nn.Linear(16, 16), nn.ReLU(),
nn.Linear(16, 2),
).to(device)
opt = torch.optim.Adam(model.parameters(), lr=0.01)
loss_fn = nn.CrossEntropyLoss()

nn.Linear est une couche entièrement connectée, nn.ReLU la fonction d'activation, Adam l'optimiseur qui ajuste les poids, et CrossEntropyLoss la perte adaptée à la classification.

Chaque epoch (ici une passe sur les 800 points d'entraînement à la fois) répète le cycle du schéma : prédire (la passe avant, ou forward), mesurer l'erreur, rétropropager, mettre à jour les poids. Le code ci-dessous l'exécute 200 fois ; ses commentaires nomment l'étape de chaque ligne :

Boucle d'entraînement : données d'entraînement, passe avant qui prédit, perte qui mesure l'écart, rétropropagation qui calcule les gradients, optimiseur qui met à jour les poids, puis itération suivante.Donnéesd'entraînementPasse avant :prédictionPerte :écart avec labonne réponseRétropropagation :gradientsOptimiseur :mise à jourdes poidsitération suivante
Source · SVG
Échap pour fermer, + et − pour zoomer, défilement pour se déplacer. 100 %
t0 = time.time()
for epoch in range(200):
model.train()
opt.zero_grad() # réinitialiser les gradients
loss = loss_fn(model(Xtr), ytr) # forward + perte
loss.backward() # rétropropagation
opt.step() # mise à jour des poids
if (epoch + 1) % 50 == 0:
model.eval()
with torch.no_grad():
acc = (model(Xte).argmax(1) == yte).float().mean().item()
print(f"Epoch {epoch+1} | loss {loss.item():.3f} | accuracy test {acc:.3f}")
print(f"Entraînement en {time.time()-t0:.2f}s sur {device}")

Ce bloc fait partie du même fichier lunes.py que les précédents (voir plus haut comment l'exécuter). Sur CPU, l'entraînement complet donne :

Epoch 50 | loss 0.213 | accuracy test 0.900
Epoch 100 | loss 0.045 | accuracy test 0.990
Epoch 150 | loss 0.023 | accuracy test 0.985
Epoch 200 | loss 0.018 | accuracy test 0.985
Entraînement en 0.12s sur cpu

Le réseau atteint 98,5 % de bonnes réponses (l'exactitude, accuracy en anglais) sur les 200 points de test, en une fraction de seconde sur CPU. La durée varie d'une machine à l'autre ; la perte et l'exactitude se reproduisent grâce aux graines fixées avec la même version de PyTorch sur CPU, mais PyTorch ne garantit pas des résultats identiques entre versions ou plateformes différentes. La perte passe de 0.213 à 0.018 : le réseau apprend.

En colorant chaque zone du plan selon la classe prédite, on voit la frontière de décision que le réseau a construite. Elle épouse la forme courbe des deux lunes, ce qu'une droite ne pourrait jamais faire. Le tracé prédit la classe de chaque point d'une grille de 300 par 300 points, puis colore les zones avec matplotlib ; c'est le dernier bloc de lunes.py :

# ----- tracé de la frontière apprise
import matplotlib.pyplot as plt
xx, yy = np.meshgrid(np.linspace(-1.5, 2.5, 300), np.linspace(-1.2, 1.7, 300))
grille = torch.tensor(np.c_[xx.ravel(), yy.ravel()], dtype=torch.float32).to(device)
model.eval()
with torch.no_grad():
zz = model(grille).argmax(1).cpu().numpy().reshape(xx.shape)
plt.contourf(xx, yy, zz, levels=[-0.5, 0.5, 1.5], alpha=0.3, cmap="coolwarm")
plt.scatter(X[:, 0], X[:, 1], c=y, s=8, cmap="coolwarm")
plt.title("Frontière apprise par le réseau")
plt.savefig("frontiere.png", dpi=120)
print("figure écrite : frontiere.png")

Le paramètre levels donne les bornes des zones colorées : les classes valent 0 et 1, et les bornes -0.5, 0.5 et 1.5 isolent chacune dans sa propre bande. Sans ces niveaux explicites, matplotlib en choisit d'autres et la figure est fausse. La sortie attendue est figure écrite : frontiere.png, et l'image produite ressemble à ceci :

Frontière de décision courbe : deux lunes entrelacées, des points bleus en arche et des points rouges en dessous, séparées par une frontière qui épouse leur courbure entre une zone bleue et une zone rose

C'est toute la puissance d'un réseau de neurones : grâce à ses couches et à ses fonctions d'activation non linéaires, il modélise des relations que les modèles linéaires ne capturent pas.

Les trois erreurs de cette leçon viennent presque toujours de l'endroit où le code s'exécute, pas du code. Le tableau donne le symptôme, sa cause et le geste qui le corrige.

SymptômeCauseSolution
ModuleNotFoundError: No module named 'torch'L'interpréteur lancé n'est pas celui du venv (par exemple le notebook de l'environnement data)Activez le venv avec source venv/bin/activate, puis relancez python lunes.py
SyntaxError: invalid syntaxLes blocs ont été collés dans l'interpréteur : la boucle for suivie d'un print en colonne 0, sans ligne vide, n'est pas acceptéeEnregistrez les blocs dans lunes.py et exécutez le fichier
ModuleNotFoundError: No module named 'matplotlib'L'installation de numpy et matplotlib a été sautéeRelancez pip install numpy==2.5.4 matplotlib==3.11.2 dans le venv

Après correction, la sortie doit afficher les quatre lignes Epoch, la durée, puis figure écrite : frontiere.png.

  1. PyTorch manipule des tenseurs avec CPU ou GPU et différentiation automatique.
  2. Un réseau se décrit comme un empilement de couches avec torch.nn.
  3. La boucle d'entraînement répète : forward, perte, backward, step.
  4. .to(device) rend le code portable entre CPU et GPU sans le changer. Ici, 200 epochs ont pris une fraction de seconde sur CPU, sur la machine de test.
  5. Les couches non linéaires permettent d'apprendre des frontières courbes, hors de portée d'un modèle linéaire.

Contrôle de connaissances

Validez vos connaissances avec ce quiz interactif

6 questions
6 min.
70% requis

Informations

  • Le chronomètre démarre au clic sur Démarrer
  • Questions à choix multiples, vrai/faux et réponses courtes
  • Vous pouvez naviguer entre les questions
  • Les résultats détaillés sont affichés à la fin

Lance le quiz et démarre le chronomètre

Ce projet vous est utile ?

Les guides, formations, quiz et labs restent gratuits. Si vous les utilisez régulièrement, vous pouvez contribuer à leur maintenance et à leur développement.

Devenir membre de soutien (nouvel onglet) Soutenir une fois (nouvel onglet) En savoir plus

Suivez aussi le projet sur LinkedIn