L'entraînement : un casse-tête mathématique
Si vous vous êtes accrochés sur les pages précédentes (félicitations !), alors vous avez retenu qu’un réseau de neurones, c’est un empilement de couches qui se traduit par des produits matriciels et des MAC à gogo. Or, il y a bien un hic : ces calculs sont faits à partir des données d’entrée, mais aussi des poids/biais du réseau. Et ces derniers ne peuvent pas sortir du chapeau : il faut un moyen de les trouver et les fixer ! C’est ce que l’on nomme entraînement. Grâce à une technique (matheuse, comme toujours !) du nom de rétropropagation du gradient, il est possible de corriger petit à petit un réseau de neurones, à condition de posséder la sortie de référence d’une donnée d’entrée, et de bien choisir un paramètre nommé taux d’apprentissage (learning rate). Ce dernier quantifie à quel point le réseau est modifié pour coller à la nouvelle données. S’il est trop faible, l’entraînement va durer plus longtemps que nécessaire. Trop gros, il ne permettra pas de trouver le point optimal du réseau (comme si vous cherchiez une aiguille dans une botte de foin… en bougeant votre bras d’un mètre à chaque fois !).
Le principe
L’idée est logique : comparer la sortie du réseau actuelle avec celle désirée, et corriger en traversant les couches depuis celles de la sortie vers celles des entrées de manière à minimiser l’écart entre la prédiction et la sortie de référence. De ce fait, les couches externes sont plus facilement touchées, là où les couches internes ont besoin de plusieurs exemples pour arriver à quelque chose de satisfaisant, un phénomène connu sous le nom de disparition du gradient. Et par « plusieurs exemples », comprendre « plusieurs milliers, voir dizaines de milliers », d’autant plus que le réseau est profond… Cela signifie ainsi qu’un réseau performant a besoin d’énormément de données déjà annotées pour arriver à son mode de fonctionnement optimal, en plus d’une capacité de calcul tout aussi importante pour réaliser l’entraînement.
Le calcul de cette différence itérée de gradient et la taille des données d’entrées font de l’apprentissage une tâche bien plus gourmande que l’inférence (c’est-à-dire l’utilisation simple du réseau pour sa fonction, par exemple la reconnaissance d’image ou l’upscaling).
Certaines techniques ont cependant vu le jour pour combattre ce phénomène, telle l’intégration de LSTM (cf page 3) et l’utilisation de réseaux résiduels (voir ResNet, page 4) permettant, à l’entraînement, de rapprocher les couches les plus profondes pour combattre cette disparition du gradient, avec un succès tel que la majorité des réseaux actuels reprennent cette notion de résidus : des connexions directes entre couches non successives pour les rapprocher mathématiquement de la sortie. De même, les couches inférieures sont les plus proches des données, et sont donc plus propices à apprendre les caractéristiques propres à celles-ci, plutôt que les caractéristiques de la tâche demandée. Il est donc bénéfique de partir d’un réseau déjà entraîné sur une tâche (reconnaître des chats, par exemple) pour réaliser une autre tâche (reconnaître les chiens) en ne modifiant que les couches les plus externes ; un phénomène nommé Transfert Learning.
L’entraînement d’un réseau, c’est ça : une passe de prédiction (sens normal) pour obtenir l’état actuel du réseau, et une passe en sens inverse (rétropropagation) pour corriger les poids et biais des neurones en fonction d’une sortie de référence connue.
De plus, il est courant de réutiliser plusieurs fois les mêmes images lors de l’entraînement pour en extraire le maximum d’information, et être certains que toutes les couches ont bien subi l’influence de toutes les images : on nomme ainsi une epoch un passage complet de toutes les données pour l’apprentissage, sachant qu’un réseau peut s’entraîner en plusieurs dizaines voire centaines d’epoch. Dans le même esprit, il est également courant d’enrichir sa base de données en effectuant quelques transformations, par exemple en dupliquant des images pour leur apposer un effet « miroir ». Enfin, puisqu’une couche de neurones effectue un produit matrice-vecteur, il est plus commode d’en effectuer tout un tas en parallèle pour obtenir les produits matrice-matrice si chère aux Tensor Cores et autres NPU. Pour cela, les données sont regroupées en batch, dont la taille représente simplement le nombre de ces entrées données en parallèle au réseau. Plus ce nombre est grand, plus l’entraînement sera rapide (la magie du parallélisme), mais plus le besoin en mémoire (typiquement VRAM !) sera grand.
Le prétraitement des données d’entraînement est une étape cruciale dans la réalisation d’un réseau, tout autant que l’architecture de réseau lui-même. Un dicton classique en statistique est « garbage in, garbage out » : « Données pourries ? Sorties pourries ! ». Un grand classique consiste à normaliser les données : par exemple rendre les images de même taille.
Un autre exemple de l’importance des données est le DLSS. Dans ce cas, NVIDIA utilise un réseau pour réaliser de la super-résolution en temps réel : rajouter des pixels pour passer d’une image basse définition en meilleure définition. Dans sa version 1, le DLSS ne reposait que sur des données des images brutes : avec toute sa bonne volonté, il lui était difficile de proposer un rendu impeccable dans toutes les situations. Avec la version 2, l’intégration des vecteurs de mouvement dans les entrées a permis un rendu visuellement supérieur. Évidemment, l’architecture du réseau a aussi dû être modifiée, mais les contraintes de performances (le bousin doit être plus rapide que le rendu !) font que ces modifications n’ont pas pu être extrêmes.
Ainsi, pour pouvoir décider si un chat est sur une image, il vous faut donc une GTX 4080 et 10 000 images dont vous savez à l’avance si un chat y est présent ou non. Ces données ne se baladant pas dans la nature, il est courant pour certaines entreprises peu scrupuleuses de se servir allègrement sur le web, d’où les récentes avancées en matière de législation. D’autres entreprises se sont par ailleurs spécialisées dans la production de ces données, par exemple en payant à bas coût des humains dans des pays émergents pour effectuer ces tâches à la main.
Il convient également de noter que le réseau apprendra des données passées en entrée. Ainsi, il est courant d’observer des comportements biaisés de réseau de neurones, qui reflètent simplement les biais de la base d’entraînement. Par exemple, des chercheurs se sont aperçus qu’un réseau classifiant les animaux était en fait sensible à.... la présence de neige ou non sur l’image pour repérer une panthère des neiges. Malin, certainement, mais pas du tout ce que l’on souhaitait !
Et en pratique ?
Hé bien, en pratique, tout est bien plus corsé. Car on pourrait imaginer laisser le réseau apprendre parfaitement (les maths nous disent bien que le réseau peut apprendre n’importe quoi avec suffisamment de temps !), et une fois que le réseau sait effectuer sa tâche parfaitement notre base de donnée d’entraînement, le tour est joué.
Hé bien pas du tout ! Vous risquez dans ce cas de tomber dans le surapprentissage : le réseau a été trop entraîné et a fait du par-cœur : au lieu de la généralisation souhaitée (apprendre qu’un chat est un être mignon à quatre pattes), il a juste appris à reconnaître tous les chats utilisés lors de l’entraînement et plus rien d’autre. Pas glop ! À l’inverse, manquer de temps lors de l’entraînement crée un sous-apprentissage : les performances du réseau seront en dessous de leur plein potentiel. C’est probablement la meilleure explication aux contre-performances du DLSS lorsqu’il est intégré « à la va-vite » dans un jeu récent.
Exemple de sous-apprentissage, d’apprentissage correct et de surapprentissage. Le réseau apprend la courbe rouge, qui sert à séparer le « groupe des croix » du « groupe des ronds ». Tout à gauche, le réseau n’a pas assez appris, car il n’a pas « vu » la courbe. Au milieu, l’apprentissage est satisfaisant. À droite, le réseau a sur-appris et reflète des artefacts propres aux données (typiquement des erreurs dans le jeu de données d’entraînement).
Pour y remédier, une méthode nommée early stopping consiste à conserver une partie des données de l’entraînement comme un témoin du surapprentissage, et arrêter cet apprentissage lorsque les performances du réseau se dégradent. Mieux, pour éviter de « perdre » les informations de cet échantillon témoin, il est possible de remélanger les données et recommencer le procédé pour toujours plus de précision.
Une autre illustration du phénomène sur sur- et sous-apprentissage. Au fur et à mesure de l’entraînement (i.e. nombre d’epoch), le réseau s’améliore à la fois sur les données d’entraînement et celle de test (« précision globale »). Après un trop grand nombre d’epoch, le réseau comment à faire du par cœur, et sa précision en utilisation réelle diminue : pouf, le surapprentissage est là !
Du fait du surapprentissage, il est complètement sans intérêt d’évaluer un réseau sur des données déjà utilisées lors de l’entraînement. Il s’agit au mieux d’une négligence, et au pire d’une arnaque pure et simple : bien sûr que le réseau va performer correctement sur ces données, il les connaît ! Un réseau est donc systématiquement évalué sur sa précision à effectuer sa tâche sur des données qu’il n’a jamais vues. Cela explique notamment pourquoi le DLSS était au début implémenté différemment en fonction des jeux : la tâche est ô combien plus simple. Dans le même genre, une IA générative recrachant parfaitement un tableau ou une photo de son jeu de données d’apprentissage sera un autre car de surapprentissage évident.
(Presque) inspiré d’une histoire vraie. L’important n’est pas tant l’outil que son utilisation !
Bon à savoir !
Une mesure de la complexité d'un réseau (et, indirectement, de sa difficulté / capacité de calcul nécessaire à être entraîné) est le nombre de paramètres, c'est-à-dire le nombre de poids et de biais différents utilisés dans le réseau, qui doivent donc être étalonnés lors de l’entraînement... un nombre qui a explosé en même temps que le hardware : LeNet en compte 1516, là où StableDiffusion dans sa version 2.x en requiert... 860 millions !
Terminons cette page avec un peu plus de vulgarisation, si l’envie vous prend de creuser le sujet !
Apprendre, c’est bien, encore faut-il pouvoir le faire rapidement ! Rendez-vous à la page suivante pour comprendre (enfin !) les liens entre matériel et IA, en quoi les NPU intégrés sur Meteor Lake et les Ryzen with AI diffèrent des GPU et ce qui pourrait (ou pas !) arriver dans nos machines d’ici quelques années.
Merci beaucoup pour cet article, j'en avais bien besoin. J'ai découvert de nombreux détails, notamment la problématique du sur apprentissage.
Heureux de t'avoir été utile :D !
Pas encore lu, mais sur la vignette miniature de la colonne des dossiers, j'ai bien cru que c'était le majeur qu'il tendait. Ça commence bien...
"F*ck, la race humaine" 🤣