Réponse courte
Faites quatre vérifications peu coûteuses : la première perte par rapport à ce que le hasard devrait donner, la capacité du modèle à mémoriser 16 exemples, la taille des gradients et l’endroit où passe le temps. Un petit banc de test qui a brisé un modèle de neuf façons a trouvé la cause dans 50 cas sur 50 sur le problème pour lequel il a été réglé et 48 sur 50 sur un autre, et dans aucun de ces neuf cas plus de GPU n’aurait réglé la panne.
Question de suivi Quand une plus grosse machine est-elle vraiment la bonne réponse?
L’entraînement échoue en silence. Il n’y a souvent aucun message d’erreur, juste une perte qui refuse de baisser ou un score qui reste faible. Il est tentant d’y voir un « manque de puissance ». La plupart du temps, c’est un bogue, un réglage ou les données. Une machine plus grosse reproduit la même panne plus vite, à un prix horaire plus élevé.
Ce projet brise exprès un petit réseau, de neuf façons connues, et vérifie si une courte liste de mesures peut nommer chaque panne. Le script est 13_doctor.py. Il s’exécute sur un processeur en quelques minutes tout au plus.
Les quatre vérifications
Plusieurs de ces idées sont les premiers gestes de la recette d’entraînement d’Andrej Karpathy; le code et les règles ont été écrits pour ce projet.
| Vérification | Comment | Ce qu’elle vous dit |
|---|---|---|
| Première perte | Comparer à ln(nombre de classes) : 2,30 pour 10 classes | Beaucoup plus haut signale une mauvaise échelle ou un mauvais départ |
| Mémoriser un petit lot | Viser une perte quasi nulle sur 16 exemples, à quelques taux | S’il n’y arrive pas, arrêtez : le modèle ou la boucle est brisé, ou il est trop petit |
| Taille du gradient dans le temps | Noter la taille globale du gradient; compter les poids qui n’en reçoivent pas | Zéro veut dire que rien ne circule; une hausse constante, que les gradients s’accumulent |
| Où passe le temps | Temps d’attente des données par rapport au temps de calcul | S’il y a de l’attente, un GPU plus rapide restera inactif |
import time, torch, torch.nn.functional as F
def can_memorize(make_model, xb, yb, steps=300):
"""Essaie trois taux sensés. Ignore le taux utilisé par l'exécution en panne."""
best = float("inf")
for lr in (1e-4, 1e-3, 1e-2):
model = make_model()
opt = torch.optim.Adam(model.parameters(), lr)
for _ in range(steps):
loss = F.cross_entropy(model(xb), yb)
opt.zero_grad(); loss.backward(); opt.step()
best = min(best, loss.item())
return best # au-dessus de 0,5 pour 16 exemples : il y a un problème
# dans votre boucle d'entraînement
t0 = time.perf_counter()
xb, yb = next(batches) # le temps passé ici est de l'attente de données
t1 = time.perf_counter()
# ... passe avant, passe arrière, mise à jour ...
t2 = time.perf_counter()
wait += t1 - t0; work += t2 - t1
Neuf pannes et leur apparence
Chaque ligne a été exécutée avec cinq graines sur les chiffres de scikit-learn, 600 étapes. Les nombres sont ceux de la dernière graine. « Attente » est la part du temps passée à obtenir les données. Mesuré ici sur le processeur d’un Apple M5 Max avec PyTorch 2.15.
| Ce qui a été brisé | Exactitude de validation | Exactitude d’entraînement | Attente | Verdict du diagnostic | Une plus grosse machine aide-t-elle? |
|---|---|---|---|---|---|
| Rien (en santé) | 97,1 % | 99,3 % | 9 % | En santé | Seulement si la vitesse vous manque |
| Taux d’apprentissage bien trop élevé | 10,0 % | 10,0 % | 9 % | Instable | Non : baissez le taux |
| Taux d’apprentissage bien trop bas | 13,1 % | 13,1 % | 9 % | Taux trop bas | Non : montez le taux |
| Étiquettes mélangées | 8,9 % | 29,5 % | 9 % | Étiquettes vides de sens | Non : corrigez les étiquettes |
zero_grad oublié | 80,4 % | 79,2 % | 9 % | Gradients accumulés | Non : corrigez la boucle |
| Entrées non mises à l’échelle | 96,2 % | 100 % | 9 % | Échelle des entrées | Non : mettez les entrées à l’échelle |
| Toutes les unités cachées mortes au départ | 10,0 % | 10,1 % | 9 % | Pas de gradient | Non : corrigez le départ ou l’activation |
| Seulement 40 exemples d’entraînement | 78,2 % | 100 % | 2 % | Surapprentissage | Non : plus de données, ou de meilleures |
| Modèle bien trop petit (2 unités) | 23,3 % | 23,5 % | 13 % | Incapable de mémoriser | Non : un plus gros modèle, qui entre probablement |
| Chargement lent des données | 97,1 % | 99,3 % | 84 % | Goulot d’entrée | Non : disque ou chargeurs plus rapides |
Quelques remarques. Un zero_grad oublié, une seule ligne manquante, a quand même atteint 80 %. On dirait un modèle à peaufiner, et vous pourriez le régler pendant des jours. La ligne des entrées montre qu’Adam encaisse d’énormes entrées dans ce petit cas; seule la première perte, bien au-dessus de 2,30, l’a révélé. L’exécution affamée atteint la même exactitude que l’exécution en santé, avec 84 % de son temps en attente : son score ne pouvait donc jamais trahir le problème.
Quelle confiance accorder à ce score?
La première version des règles a obtenu 36 sur 50, dont 0 sur 5 pour le taux trop élevé et les unités mortes. En les réécrivant, avec un test de mémorisation à plusieurs taux et un compte des poids sans gradient, le score sur les chiffres est passé à 50 sur 50. C’est un réglage sur le test, le piège même du projet quatre, et ce 50 n’est donc pas une preuve indépendante.
Pour obtenir un chiffre plus juste, les mêmes règles finales ont été appliquées à un second problème synthétique pour lequel elles n’avaient pas été écrites. Elles ont obtenu 48 sur 50. Les deux échecs portaient sur le modèle trop petit, nommé correctement dans 3 exécutions sur 5. Ces pannes ont aussi été semées une à la fois. Une vraie exécution peut en avoir deux à la fois, et les modèles de langage et les grandes images n’ont pas été testés. Utilisez ces vérifications comme une façon de regarder et prenez les verdicts comme des suggestions.
À essayer : ajoutez ces quatre vérifications à un script d’entraînement que vous avez déjà, puis brisez-le exprès en retirant zero_grad et voyez quelle vérification l’attrape en premier.
Quand une plus grosse machine est-elle vraiment la bonne réponse?
Mesurez-le. Le même code a été exécuté sur le processeur et sur le GPU de la machine :
| Travail | Processeur | GPU | Résultat |
|---|---|---|---|
| Petit modèle, 400 étapes, en santé | 0,16 s | 1,13 s | GPU 7 fois plus lent |
| Même travail, affamé de données | 1,33 s | 2,15 s | GPU encore plus lent |
| Gros modèle (couches de largeur 2 048, lot de 512), 30 étapes | 1,38 s | 0,23 s | GPU 6 fois plus rapide |
Les petits travaux perdent du temps à déplacer les données vers le GPU, et ce coût dépasse le calcul économisé. Le GPU n’a mérité sa place que lorsque le calcul était important. Ce sont les chiffres d’une seule machine, avec le GPU intégré d’Apple; l’autre matériel n’a pas été testé et l’équilibre sera différent.
Une mise à niveau a du sens quand tout ceci est vrai : le modèle mémorise un petit lot et la validation s’améliore; l’attente des données est faible, puisque le guide de réglage de PyTorch énumère des réglages de chargeur à essayer d’abord; le GPU est réellement occupé; et vous avez manqué de mémoire selon le budget du projet sept après avoir essayé les correctifs moins coûteux que sont les adaptateurs, les séquences plus courtes et les points de contrôle. Même là, louer pour une exécution peut être préférable à acheter, et le guide de réglage de Google est une bonne référence pour bien dépenser ses expériences. Une machine plus rapide raccourcit la boucle entre vos expériences, ce qui a une vraie valeur, mais elle n’aide qu’une fois que chaque expérience veut dire quelque chose.
Téléchargez le code de cette série (zip), avec tous les scripts et les résultats enregistrés.
Sources
- A Recipe for Training Neural Networks — Andrej Karpathy, 25 avril 2019
- Performance Tuning Guide — PyTorch
- Deep Learning Tuning Playbook — Google Research
Tiré du Guide de l’intelligence artificielle, par Robert Scales, publié par Holistic Hybrid inc. Partage et adaptation permis selon la licence CC BY-NC-SA 4.0 : citez le guide, mettez un lien vers https://guidetoartificialintelligence.com/fr/apprendre/diagnostiquer-entrainement-avant-plus-grosse-machine/, pas d’usage commercial sans permission, et gardez la même licence.