Cours Python · Module 9: Machine learning
PyTorch - les deux piliers du deep learning
Dans cette leçon4
Les modèles classiques de scikit-learn avaient une limite. Quand les données deviennent énormes et compliquées - des millions de photos d'animaux ramenées du safari - il te faut des réseaux de neurones, et pour les faire tourner, un outil d'un tout autre calibre : PyTorch. Avant de te lancer dans les couches et les optimiseurs, apprends les deux piliers sur lesquels toute la bibliothèque repose - le tensor et l'autograd. Tout le reste n'est que détail d'implémentation.
1pip install torch torchvisiontorchvision voyage toujours avec torch : il apporte les jeux de données et les transformations d'images dont tu auras besoin dès que le safari passera aux photos. Les deux s'installent d'un coup, et l'import tient ensuite en une seule ligne dans ton script.
Premier pilier : le tensor
Le tensor est la boîte à données de base de PyTorch : un tableau multidimensionnel similaire à un array numpy, avec la prise en charge du GPU en plus. Ce n'est pas un algorithme de tri - il ne range rien, il stocke. Ce n'est pas davantage un type de base de données ni un format de fichier : rien ne part sur le disque, tout vit en mémoire pendant l'exécution. Deux superpouvoirs le séparent quand même du tableau NumPy ordinaire : il sait calculer sur la carte graphique, et il sait se souvenir de la façon dont il a été construit. Pour l'instant, traite-le comme un tableau de nombres familier.
1import torch
2
3tensor = torch.tensor([1, 2, 3, 4, 5])
4matrix = torch.tensor([[1, 2], [3, 4], [5, 6]])
5
6zeros = torch.zeros(3, 4) # matrice 3x4 de zeros
7random = torch.rand(3, 3) # valeurs aleatoires 0-1
8
9print(tensor.shape) # taille
10print(tensor.device) # cpu ou cuda (GPU)Tu crées des tensors presque comme en NumPy - torch.from_numpy() fait d'ailleurs le pont dans un sens et .numpy() dans l'autre. Regarde surtout le dernier attribut, device : c'est lui qui trahit le premier superpouvoir, car le tensor sait s'il repose dans la mémoire du processeur (cpu) ou dans celle de la carte graphique (cuda). On y revient dans un instant. Une remarque au passage sur la première ligne : import torch suffit, mais tu croiseras aussi la forme avec alias - le mot-clé import, puis le nom du module torch, puis as, puis le raccourci, ce qui donne import torch as pt.
Les opérations sur les tensors rappellent elles aussi NumPy - tu additionnes, tu multiplies, tu calcules des statistiques :
1a = torch.tensor([[1, 2], [3, 4]], dtype=torch.float32)
2b = torch.tensor([[5, 6], [7, 8]], dtype=torch.float32)
3
4c = a + b # addition element par element
5c = a @ b # multiplication matricielle (operateur @)
6
7print(a.mean()) # moyenne
8print(a.argmax()) # index de la plus grande valeur
9
10reshaped = torch.arange(12).reshape(3, 4) # changement de shapeUne distinction à retenir : + et * travaillent élément par élément, alors que @ est la vraie multiplication matricielle - dans les réseaux de neurones, c'est surtout celle-là que tu emploies. reshape change la shape sans toucher aux données, ce qui te servira pour faire passer des images dans le réseau, et .shape te dit à tout moment quelle forme porte ton tensor. Prends l'habitude de la vérifier : la moitié des bugs de deep learning sont des shapes qui ne tombent pas juste.
Le superpouvoir du tensor : le calcul sur GPU
Voici pourquoi le deep learning tient dans un temps raisonnable. Un réseau enchaîne des milliards de multiplications matricielles, et une carte graphique (GPU) les exécute des centaines de fois plus vite qu'un processeur, parce qu'elle les mène de front au lieu de les prendre l'une après l'autre. Déplacer un tensor sur le GPU tient en une seule méthode.
1device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
2
3tensor = torch.tensor([1, 2, 3]).to(device) # deplace vers le GPU si disponible
4tensor_gpu = torch.rand(3, 3, device='cuda') # ou bien cree directement dessusPour déplacer un tensor vers le GPU, tu écris tensor.to('cuda'), ou son raccourci tensor.cuda() ; le retour vers le processeur se fait par .cpu(). Aucune fonction gpu(tensor), aucune méthode tensor.gpu() ni tensor.accelerate() n'existe - ces noms sonnent bien, mais PyTorch ne les connaît pas. Le motif device = 'cuda' if ... else 'cpu' est le standard du domaine : ton code tourne sur GPU quand il y en a un et sur le processeur sinon, sans une ligne à réécrire. Retiens enfin cette règle : pour s'additionner ou se multiplier, deux tensors doivent reposer sur le même device. Mélanger CPU et GPU est l'erreur numéro un du débutant.
Deuxième pilier : autograd
Passons au second superpouvoir, celui grâce auquel un modèle est capable d'apprendre. Apprendre, c'est corriger des paramètres dans le sens d'une erreur plus faible, et cela réclame des dérivées - les gradients. Autograd sert exactement à cela : au calcul automatique des gradients pour la rétropropagation. Il ne génère pas de code à ta place, il ne charge pas les données - ce sera le travail du DataLoader un peu plus bas - et il ne lance aucun test. Marque un tensor avec requires_grad=True et PyTorch mémorise chaque opération, prêt à remonter le calcul en sens inverse.
1x = torch.tensor([2.0], requires_grad=True)
2y = x ** 2 + 3 * x + 1
3
4y.backward() # calcule la derivee en arriere
5print(x.grad) # dy/dx = 2x + 3 = 7C'est le coeur de PyTorch. Tu n'as écrit que la formule en avant (y = x**2 + 3x + 1), et backward() a calculé la dérivée tout seul - 7, exactement le résultat que tu obtiendrais sur une feuille de papier. Tu n'as dérivé à la main nulle part. Dans un vrai modèle, ce même mécanisme indique comment modifier chaque poids pour faire baisser l'erreur :
1w = torch.tensor([1.0], requires_grad=True)
2b = torch.tensor([0.0], requires_grad=True)
3
4y_pred = w * torch.tensor([2.0]) + b # prediction du modele
5loss = (y_pred - torch.tensor([5.0])) ** 2 # a quel point on se trompe
6
7loss.backward()
8print(w.grad, b.grad) # dans quel sens corriger w et bSuis la logique pas à pas : tu calcules la prédiction, tu calcules l'erreur (loss), tu appelles backward() - et w.grad comme b.grad te disent dans quel sens pousser chaque paramètre pour que l'erreur diminue. Tout l'apprentissage d'un réseau consiste à répéter ce pas des milliers de fois : en avant pour prédire, en arrière pour corriger. Voilà pourquoi autograd est un pilier et non une curiosité de documentation.
Alimenter le modèle : Dataset et DataLoader
Reste une question très pratique : comment nourrir le modèle ? Un réseau apprend par petites portions, les batchs, alors PyTorch te donne deux briques - Dataset emballe tes données, DataLoader les découpe et les mélange.
1from torch.utils.data import Dataset, DataLoader
2
3class SafariDataset(Dataset):
4 def __init__(self, X, y):
5 self.X = torch.tensor(X, dtype=torch.float32)
6 self.y = torch.tensor(y, dtype=torch.long)
7
8 def __len__(self):
9 return len(self.X)
10
11 def __getitem__(self, idx):
12 return self.X[idx], self.y[idx]
13
14dataset = SafariDataset(X_train, y_train)
15dataloader = DataLoader(dataset, batch_size=32, shuffle=True)
16
17for batch_X, batch_y in dataloader:
18 print(batch_X.shape, batch_y.shape)
19 breakTon Dataset doit savoir faire deux choses : dire combien d'exemples il contient (__len__) et en rendre un à partir de son numéro (__getitem__). Le DataLoader prend le relais et sert les données par paquets de 32 (batch_size), en rebattant l'ordre à chaque époque (shuffle=True) - de cette manière, le modèle n'apprend pas l'ordre du fichier au lieu du contenu. Un num_workers supérieur à zéro fait même préparer les batchs par plusieurs processus en parallèle, pendant que le GPU travaille.
Garde deux piliers de cette leçon : le tensor, ce sont les données, un tableau multidimensionnel à la numpy qui sait calculer sur GPU, et l'autograd, c'est le calcul automatique des gradients grâce auquel le modèle apprend. Une fois ces deux idées en place, construire le réseau lui-même n'est plus qu'un empilement de couches.
Tu as repéré une erreur dans cette leçon ?
Teste tes connaissances
Réponds aux questions de cette leçon. Choisis une réponse pour voir tout de suite si elle est correcte.
1. Qu'est-ce qu'un Tensor dans PyTorch ?
2. Comment déplacer un tensor vers le GPU dans PyTorch ?
Voici 2 des 3 questions de cette leçon. Réponds aux autres dans le jeu.
Tâches pratiques dans le jeu
- Tri horizontal
Range l'import de PyTorch avec un alias :
- Éditeur de code
Crée un tensor à partir d'une liste, réalise des opérations mathématiques et vérifie la shape.
- Clique dans l'ordre
Clique sur les boutons pour créer un tensor à partir d'une liste :