Découverte de la librairie PyTorch

Pour commencer, nous introduisons les tableaux de dimension $n$ également appelé tenseur (tensor en anglais). Si vous avez travaillé avec NumPy, le package de calcul scientifique le plus utilisé en Python, cette partie vous sera familière. Quel que soit le framework que vous utilisez, sa classe tensor (ndarray dans MXNet, Tensor dans PyTorch et TensorFlow) est similaire à celle de NumPy appelée ndarray avec quelques caractéristiques particulières. Premièrement, le GPU est bien supporté pour accélérer le calcul alors que NumPy ne prend en charge que les calculs effectués par le CPU. Deuxièmement, la classe tensor supporte la différenciation automatique. Ces propriétés rendent la classe tensorielle adaptée à l'apprentissage profond. Tout au long de ce notebook, lorsque tenseurs, nous faisons référence à des instances de la classe tensor, sauf indication contraire.

Pour commencer

Pour commencer, nous importons torch. Notez que bien qu'elle soit appelée PyTorch, nous devons importer torch au lieu de pytorch.

Un tenseur représente un tableau (éventuellement multidimensionnel) de valeurs numériques. Avec un seul axe (une dimension), un tenseur est appelé un vecteur. Avec deux axes, un tenseur est appelé matrice. Avec $k > 2$ axes, nous abandonnons les noms spécialisés et désignons simplement l'objet comme un tenseur d'ordre $k$. PyTorch fournit une variété de fonctions pour créer de nouveaux tenseurs pré-remplis avec des valeurs numériques. Par exemple, en utilisant $arange(n)$, nous pouvons créer un vecteur de valeurs uniformément espacées, commençant à $0$ (inclus) et finissant à $n$ (non inclus). Par défaut, la taille de l'intervalle est de $1$. Sauf indication contraire, les nouveaux tenseurs sont stockés en mémoire principale et prédisposés pour calcul par CPU.

Opérations arithmétiques

Concaténation ou stacking

Opérations logiques

Opérations dites de Broadcasting

Indexation ou slicing

Gestion de la mémoire

L'exécution d'opérations peut entraîner l'allocation d'une nouvelle mémoire pour accueillir les résultats. Par exemple, si nous écrivons $Y = X + Y$, nous déréférencerons le tenseur vers lequel $Y$ pointait et pointerons $Y$ vers la nouvelle la mémoire nouvellement allouée. Dans l'exemple suivant, nous le démontrons avec la fonction id() de Python qui nous donne l'adresse exacte de l'objet référencé en mémoire. Après avoir exécuté $Y = Y + X$, nous constaterons que id(Y) pointe vers un emplacement différent. Cela est dû au fait que Python évalue d'abord $Y + X$, allouant une nouvelle mémoire pour le résultat, puis fait pointer $Y$ vers ce nouvel emplacement en mémoire.

Heureusement, il est facile d'effectuer des opérations in-place.

Convertir vers d'autres objets Python

Un peu d'algèbre linéaire

Matrices

Tenseurs

Réduction

Dérivation automatique

Un exemple simple

Comme exemple jouet, on s'intéresse à la dérivation de la fonction $y = 2 x^\prime x$ par rapport à au vecteur $x$ (un vecteur est une colonne en algèbre).

Avant même de calculer le gradient de $y$ par rapport à $x$ , nous aurons besoin d'un endroit pour le stocker. Il est important de ne pas allouer une nouvelle mémoire à chaque fois que nous prenons une dérivée par rapport à un paramètre, car nous mettrons souvent à jour les mêmes paramètres des milliers ou des millions de fois et nous pourrions rapidement manquer de mémoire. Notez que le gradient d'une fonction à valeur scalaire par rapport à un vecteur $x$ est lui-même à valeur vectorielle et a la même forme que $x$.

Calculons maintenant $y$

Comme $x$ est un vecteur de longueur 4, un produit scalaire de $x$ par $x$ est effectué, ce qui donne la sortie scalaire que nous attribuons à $y$. Ensuite, nous pouvons calculer automatiquement le gradient de $y$ par rapport à chaque composante de $x$ en appelant la fonction de rétropropagation et en affichant le gradient.

Le gradient de la fonction $y = 2 x^\prime x$ par rapport à $x$ devrait être $4x$. Vérifions rapidement que notre gradient souhaité a été calculé correctement.

Calculons maintenant une autre fonction de $x$

Backward pour variables non-scalaires

Techniquement, lorsque $y$ n'est pas un scalaire, l'interprétation la plus naturelle de la dérivation d'un vecteur $y$ par rapport à un vecteur $x$ est une matrice. Pour des $y$ et $x$ d'ordre supérieur et de dimension supérieure, le résultat de la dérivation pourrait être un tenseur d'ordre supérieur.