Que dois-je faire lorsque mon réseau de neurones n'apprend pas?

148

J'entraîne un réseau de neurones mais la perte d'entraînement ne diminue pas. Comment puis-je réparer cela?

Je ne parle pas de surajustement ou de régularisation. Je demande comment résoudre le problème où les performances de mon réseau n'améliorent pas l' ensemble de formation .


Cette question est délibérément générale, de sorte que les autres questions sur la manière de former un réseau de neurones peuvent être fermées comme une copie de celle-ci, avec l’attitude suivante: "si vous donnez un poisson à un homme, vous le nourrissez pendant une journée, mais homme à pêcher, vous pouvez le nourrir pour le reste de sa vie ". Voir ce méta filetage pour une discussion: Quelle est la meilleure façon de répondre aux questions de "mon réseau de neurones ne fonctionne pas, merci de le corriger"?

Si votre réseau de neurones ne se généralise pas bien, voir: Que dois-je faire si mon réseau de neurones ne se généralise pas bien?

Sycorax
la source
1
Voici le cas où le NN ne pourrait pas progresser. youtu.be/iakFfOmanJU?t=144
Joshua
4
Le blog d'Ivanov "Les raisons pour lesquelles votre réseau de neurones ne fonctionne pas ", en particulier les sections II, III et IV, pourrait être utile.
user5228

Réponses:

187

Le test unitaire est ton ami

Il y a un dicton parmi les écrivains qui dit: "Toute écriture est en train de ré-écrire" - c'est-à-dire que la majeure partie de l'écriture est en révision. Pour les programmeurs (ou au moins les scientifiques de données), l'expression pourrait être reformulée comme suit: "Tout le codage est un débogage".

Chaque fois que vous écrivez du code, vous devez vérifier qu'il fonctionne comme prévu. La meilleure méthode que j'ai jamais trouvée pour vérifier l'exactitude consiste à diviser votre code en petits segments et à vérifier que chaque segment fonctionne. Cela peut être fait en comparant la sortie du segment à ce que vous savez être la bonne réponse. Ceci s'appelle le test unitaire . Écrire de bons tests unitaires est essentiel pour devenir un bon statisticien / expert en données / expert en apprentissage automatique / praticien des réseaux neuronaux. Il n'y a tout simplement pas de substitut.

Vous devez vérifier que votre code est exempt de bugs avant de pouvoir ajuster les performances du réseau! Sinon, vous pourriez aussi bien réorganiser les chaises longues sur le RMS Titanic .

Deux caractéristiques des réseaux de neurones rendent la vérification encore plus importante que pour d’autres types d’apprentissage automatique ou de modèles statistiques.

  1. Les réseaux de neurones ne sont pas des algorithmes "standard" au sens de la régression aléatoire par forêt ou logistique. Même pour les réseaux simples à feed-forward, il incombe en grande partie à l'utilisateur de prendre de nombreuses décisions concernant la configuration, la connexion, l'initialisation et l'optimisation du réseau. Cela signifie écrire du code et écrire du code signifie déboguer.

  2. Même lorsqu'un code de réseau neuronal s'exécute sans lever d'exception, le réseau peut toujours présenter des bugs! Ces bogues pourraient même être du type insidieux pour lequel le réseau s’entraînera, mais rester bloqué à une solution sous-optimale, ou le réseau résultant ne possède pas l’architecture souhaitée. ( Ceci est un exemple de la différence entre une erreur syntaxique et sémantique .)

Ce billet de niveau moyen , " Comment tester un code d’apprentissage machine ", de Chase Roberts, décrit plus en détail les tests unitaires pour les modèles d’apprentissage automatique. J'ai emprunté cet exemple de code buggy de l'article:

def make_convnet(input_image):
    net = slim.conv2d(input_image, 32, [11, 11], scope="conv1_11x11")
    net = slim.conv2d(input_image, 64, [5, 5], scope="conv2_5x5")
    net = slim.max_pool2d(net, [4, 4], stride=4, scope='pool1')
    net = slim.conv2d(input_image, 64, [5, 5], scope="conv3_5x5")
    net = slim.conv2d(input_image, 128, [3, 3], scope="conv4_3x3")
    net = slim.max_pool2d(net, [2, 2], scope='pool2')
    net = slim.conv2d(input_image, 128, [3, 3], scope="conv5_3x3")
    net = slim.max_pool2d(net, [2, 2], scope='pool3')
    net = slim.conv2d(input_image, 32, [1, 1], scope="conv6_1x1")
    return net

Voyez-vous l'erreur? Beaucoup des différentes opérations ne sont pas réellement utilisées car les résultats précédents sont remplacés par de nouvelles variables. L'utilisation de ce bloc de code dans un réseau entraîne toujours la formation et les poids vont être mis à jour et la perte peut même diminuer - mais le code ne fait certainement pas ce qui était prévu. (L’auteur est également incohérent quant à l’utilisation de guillemets simples ou doubles, mais c’est purement stylistique.)

Les erreurs de programmation les plus courantes relatives aux réseaux de neurones sont

  • Les variables sont créées mais jamais utilisées (généralement à cause d'erreurs copier / coller);
  • Les expressions pour les mises à jour en dégradé sont incorrectes.
  • Les mises à jour de poids ne sont pas appliquées;
  • Les fonctions de perte ne sont pas mesurées sur la bonne échelle (par exemple, la perte d'entropie croisée peut être exprimée en termes de probabilité ou de logits)
  • La perte n'est pas appropriée pour la tâche (par exemple, utilisation de la perte catégorique par entropie croisée pour une tâche de régression).

Ramper avant de marcher; Marchez avant de courir

Les réseaux neuronaux larges et profonds, ainsi que les réseaux neuronaux avec câblage exotique, constituent actuellement le point chaud de l'apprentissage automatique. Mais ces réseaux ne naissent pas complètement formés. leurs concepteurs ont construit pour eux à partir de petites unités. Commencez par créer un petit réseau avec une seule couche masquée et vérifiez qu’il fonctionne correctement. Ajoutez ensuite progressivement la complexité du modèle et vérifiez que chacun de ces éléments fonctionne également.

  • Trop peu de neurones dans une couche peuvent restreindre la représentation apprise par le réseau, entraînant un sous-ajustement. Trop de neurones peuvent provoquer une surcharge car le réseau «mémorisera» les données d'apprentissage.

    Même si vous pouvez prouver mathématiquement que seul un petit nombre de neurones est nécessaire pour modéliser un problème, il est fréquent que le fait de disposer de "quelques" neurones supplémentaires permette à l'optimiseur de trouver plus facilement une "bonne" configuration. (Mais je ne pense pas que quiconque comprenne parfaitement pourquoi c'est le cas.) Je donne un exemple de cela dans le contexte du problème XOR ici: Mes itérations ne sont-elles pas nécessaires pour former NN pour XOR avec une MSE <0,001 trop élevée? .

  • Le choix du nombre de couches masquées permet au réseau d’apprendre une abstraction à partir des données brutes. L'apprentissage en profondeur fait fureur ces jours-ci, et les réseaux avec un grand nombre de couches ont donné des résultats impressionnants. Mais ajouter trop de couches cachées peut rendre le processus trop compliqué ou rendre très difficile l'optimisation du réseau.

  • Choisir un câblage de réseau intelligent peut faire beaucoup de travail pour vous. Votre source de données est-elle adaptée aux architectures de réseau spécialisées? Les réseaux de neurones convolutifs peuvent obtenir des résultats impressionnants avec des sources de données "structurées", des données image ou audio. Les réseaux de neurones récurrents peuvent bien fonctionner avec des types de données séquentiels, tels que des données en langage naturel ou des séries chronologiques. Les connexions résiduelles peuvent améliorer les réseaux à feed-forward profonds.

La formation de réseau de neurones est comme le crochetage

Pour obtenir des résultats à la pointe de la technologie, voire simplement de bons résultats, vous devez avoir configuré toutes les pièces configurées pour fonctionner ensemble . Configurer une configuration de réseau neuronal qui apprend réellement ressemble beaucoup à la sélection d’un verrou: toutes les pièces doivent être alignées correctement. Tout comme il ne suffit pas d'avoir un seul gobelet au bon endroit, il ne suffit pas non plus de ne configurer que l'architecture ou l'optimiseur correctement.

Régler les choix de configuration n’est pas aussi simple que de dire qu’un type de choix de configuration (taux d’apprentissage, par exemple) est plus ou moins important qu’un autre (nombre d’unités, par exemple), car tous ces choix interagissent avec tous les autres choix. le choix peut bien faire en combinaison avec un autre choix fait ailleurs .

Ceci est une liste non exhaustive des options de configuration qui ne sont pas non plus des options de régularisation ou des options d'optimisation numérique.

Tous ces sujets sont des domaines de recherche actifs.

L'optimisation non convexe est difficile

La fonction objective d'un réseau de neurones n'est convexe que lorsqu'il n'y a pas d'unités cachées, que toutes les activations sont linéaires et que la matrice de conception est à rang plein - car cette configuration est identique- ment un problème de régression ordinaire.

Dans tous les autres cas, le problème d'optimisation est non convexe et l'optimisation non convexe est difficile. Les défis de la formation des réseaux de neurones sont bien connus (voir: Pourquoi est-il difficile de former des réseaux de neurones profonds? ). De plus, les réseaux de neurones ont un très grand nombre de paramètres, ce qui nous limite aux méthodes de premier ordre (voir: Pourquoi la méthode de Newton n'est-elle pas largement utilisée dans l'apprentissage automatique? ). C'est un domaine de recherche très actif.

  • Réglage du taux d' apprentissage trop important entraînera l'optimisation de diverger, parce que vous sauter d'un côté du « canyon » à l'autre. Définir ce paramètre trop petit vous empêchera de faire de réels progrès et permettra probablement au bruit inhérent à SGD de submerger vos estimations de gradient.

  • L'écrêtage du dégradé redimensionne la norme du dégradé s'il dépasse un certain seuil. J'avais l'habitude de penser qu'il s'agissait d'un paramètre "set-and-oublier", généralement à 1,0, mais j'ai constaté que je pouvais améliorer considérablement le modèle de langage LSTM en le réglant sur 0,25. Je ne sais pas pourquoi.

  • La planification du taux d'apprentissage peut diminuer le taux d'apprentissage au cours de la formation. D'après mon expérience, essayer d'utiliser l'ordonnancement ressemble beaucoup à regex : il remplace un problème ("Comment apprendre à continuer après une certaine époque?") Par deux problèmes ("Comment apprendre à continuer après une certaine époque?" ? "et" Comment choisir un bon programme? "). D'autres personnes insistent sur le fait que la planification est essentielle. Je vous laisse décider.

  • Le choix d’une taille de mini-lot correcte peut influencer indirectement le processus d’apprentissage, puisqu’un mini-lot plus grand aura tendance à présenter une variance moins grande ( ) qu’un mini-lot plus petit. Vous souhaitez que le mini-lot soit suffisamment volumineux pour indiquer la direction du gradient, mais suffisamment petit pour que SGD puisse régulariser votre réseau.

  • Il existe un certain nombre de variantes sur la descente de gradient stochastique qui utilisent l'impulsion, les vitesses d'apprentissage adaptatives, les mises à jour de Nesterov, etc. pour améliorer le SGD vanille. Concevoir un meilleur optimiseur est un domaine de recherche actif. Quelques exemples:

  • À sa sortie, l'optimiseur Adam a suscité beaucoup d'intérêt. Toutefois, des recherches récentes ont montré que SGD avec élan pouvait dépasser les méthodes de gradient adaptatives pour les réseaux de neurones. " La valeur marginale des méthodes de gradients adaptatifs dans l'apprentissage automatique " par Ashia C. Wilson, Rebecca Roelofs, Mitchell Stern, Nathan Srebro et Benjamin Recht

  • Par ailleurs, cet article très récent propose un nouvel optimiseur de taux d’apprentissage adaptatif censé combler l’écart entre les méthodes de taux adaptatif et SGD avec élan. " Combler les lacunes en matière de généralisation des méthodes de gradients adaptatifs dans la formation de réseaux neuronaux profonds " par Jinghui Chen, Quanquan Gu

    Les méthodes de gradient adaptatif, qui adoptent des informations de gradient historiques pour ajuster automatiquement le taux d'apprentissage, se sont avérées généraliser moins que la descente de gradient stochastique (SGD) avec dynamique dans la formation de réseaux neuronaux profonds. Cela laisse la question de savoir comment combler l’écart de généralisation des méthodes de gradient adaptatif. Dans ce travail, nous montrons que les méthodes de gradient adaptatives telles que Adam, Amsgrad, sont parfois "trop ​​adaptées". Nous concevons un nouvel algorithme, appelé méthode d'estimation partiellement adaptative du moment (Padam), qui unifie Adam / Amsgrad avec SGD pour obtenir le meilleur des deux mondes. Des expériences sur des points de référence standard montrent que Padam peut maintenir une vitesse de convergence rapide identique à celle d’Adam / Amsgrad tout en généralisant, ainsi que le SGD dans l’entraînement de réseaux neuronaux profonds.

Normalisation

L'ampleur des données peut faire une grande différence en matière de formation.

Régularisation

Le choix et le réglage de la régularisation du réseau sont des éléments clés de la construction d’un modèle qui généralise bien (c’est-à-dire un modèle qui n’est pas sur-ajusté aux données de formation). Cependant, au moment où votre réseau s'efforce de réduire la perte de données d'apprentissage - lorsque le réseau n'apprend pas - la régularisation peut masquer le problème.

Lorsque mon réseau n'apprend pas, je désactive toute régularisation et vérifie que le réseau non régularisé fonctionne correctement. Ensuite, je rajoute chaque pièce de régularisation et vérifie que chacune d’elles fonctionne en cours de route.

Cette tactique peut indiquer où une régularisation pourrait être mal définie. Certains exemples sont

Tenir un journal de bord des expériences

Lorsque je configure un réseau de neurones, je ne code pas dans les paramètres. À la place, je le fais dans un fichier de configuration (par exemple, JSON) qui est lu et utilisé pour renseigner les détails de la configuration du réseau au moment de l'exécution. Je garde tous ces fichiers de configuration. Si je modifie un paramètre, je crée un nouveau fichier de configuration. Enfin, j’ajoute comme commentaire toutes les pertes par époque pour la formation et la validation.

k

Par exemple, je voulais en savoir plus sur les modèles de langage LSTM. J'ai donc décidé de créer un bot Twitter qui écrit de nouveaux tweets en réponse à d'autres utilisateurs de Twitter. J'y ai travaillé pendant mon temps libre, entre les études supérieures et mon travail. Cela a pris environ un an et j'ai parcouru environ 150 modèles différents avant de créer un modèle qui répond à mes attentes: générer un nouveau texte en langue anglaise qui (en quelque sorte) a du sens. (Un point de blocage important, et une partie de la raison pour laquelle il a fallu tant de tentatives, est qu'il n'était pas suffisant d'obtenir simplement une faible perte hors échantillon, car des modèles précoces à faible perte avaient réussi à mémoriser les données de formation, il ne s'agissait donc que de reproduire textuellement des blocs de texte pertinents en réponse à des invites - il a fallu quelques ajustements pour rendre le modèle plus spontané et conserver une faible perte.)

Sycorax
la source
11
Beaucoup de bons conseils là-bas. Il est intéressant de noter combien de vos commentaires sont similaires aux commentaires que j'ai faits (ou que j'ai vus faire d'autres) en relation avec le débogage de l'estimation des paramètres ou des prédictions pour des modèles complexes avec des schémas d'échantillonnage MCMC. (Par exemple, le code peut sembler fonctionner s'il n'est pas correctement implémenté.)
Glen_b
11
@Glen_b Je ne pense pas que les meilleures pratiques de codage soient suffisamment mises en avant dans la plupart des programmes de statistiques / d'apprentissage automatique, c'est pourquoi j'ai tellement insisté sur ce point. J'ai vu un certain nombre de publications de NN où OP a laissé un commentaire du type "oh, j'ai trouvé un bogue maintenant que ça marche."
Sycorax le
7
J'enseigne un cours de programmation en science des données en python. Nous effectuons des tests de fonctionnement et des tests unitaires le premier jour, en tant que concepts fondamentaux. Combattre le bon combat.
Matthew Drury
8
+1 pour "tout le codage est un débogage". Je suis étonné de voir combien d’affiches sur SO semblent penser que le codage est un exercice simple nécessitant peu d’effort; qui s'attendent à ce que leur code fonctionne correctement la première fois qu'ils l'exécutent; et qui semblent être incapables de procéder quand ce n'est pas le cas. Ce qui est amusant, c’est qu’ils ont à moitié raison: coder, c’est facile, mais programmer est difficile.
Bob Jarvis
41

Les réponses postées sont excellentes et je voulais ajouter quelques "tests de santé mentale" qui m'ont beaucoup aidé par le passé.

1) Entraînez votre modèle sur un seul point de données. Si cela fonctionne, entraînez-le sur deux entrées avec des sorties différentes.

Ceci vérifie quelques petites choses. Premièrement, il vous montre rapidement que votre modèle est capable d'apprendre en vérifiant si votre modèle peut sur-adapter vos données. Dans mon cas, je fais constamment des erreurs stupides en faisant des Dense(1,activation='softmax')vs contre Dense(1,activation='sigmoid')des prédictions binaires, et le premier donne des résultats incohérents.

Si votre modèle ne parvient pas à surajuster quelques points de données, il est soit trop petit (ce qui est peu probable à notre époque), soit quelque chose ne va pas dans sa structure ou dans son algorithme d'apprentissage.

2) Faites attention à votre perte initiale.

L=-0,3dans(0.5)-0,7dans(0.5)0,7 . Ceci est dû au fait que votre modèle devrait commencer à deviner de façon aléatoire.

-0,3dans(0,99)-0,7dans(0,01)=3.2

Vous pouvez étudier cela davantage en faisant prédire votre modèle sur quelques milliers d'exemples, puis en histogrammant les sorties. Ceci est particulièrement utile pour vérifier que vos données sont correctement normalisées. Par exemple, si vous vous attendez à ce que votre sortie soit fortement biaisée par rapport à 0, il peut être judicieux de transformer vos sorties attendues (vos données d'apprentissage) en prenant les racines carrées de la sortie attendue. Cela évitera les problèmes de gradient pour les sigmoids saturés, à la sortie.

3) Généraliser vos sorties de modèle pour déboguer

Par exemple, imaginez que vous utilisez un LSTM pour effectuer des prédictions à partir de données chronologiques. Peut-être que dans votre exemple, vous ne vous souciez que de la dernière prédiction, votre LSTM génère donc une valeur unique et non une séquence. Basculez le LSTM pour renvoyer les prévisions à chaque étape (en keras, c'est return_sequences=True). Ensuite, vous pouvez jeter un coup d'œil à vos sorties d'état caché après chaque étape et vous assurer qu'elles sont réellement différentes. Une application de cela consiste à s'assurer que lorsque vous masquez vos séquences (c'est-à-dire qu'elles sont complétées avec des données pour les rendre égales), le LSTM ignore correctement vos données masquées. Sans généraliser votre modèle, vous ne trouverez jamais ce problème .

4) Regardez les couches individuelles

Tensorboard fournit un moyen utile de visualiser vos sorties de couche . Cela peut aider à s'assurer que les entrées / sorties sont correctement normalisées dans chaque couche. Il peut également intercepter des activations de buggy. Vous pouvez également interroger les sorties de couche dans keras sur un lot de prédictions, puis rechercher des couches dont les activations sont faussement suspectes (toutes les 0 ou toutes les valeurs non nulles).

5) Construisez d'abord un modèle plus simple

Vous avez décidé que la meilleure approche pour résoudre votre problème consiste à utiliser un CNN combiné à un détecteur de boîte de délimitation, qui traite ensuite les cultures d’image, puis utilise un LSTM pour tout combiner. Il faut 10 minutes à votre GPU pour initialiser votre modèle.

Créez plutôt un lot de fausses données (même forme) et décomposez votre modèle en composants. Créez ensuite des modèles factices à la place de chaque composant (votre "CNN" pourrait simplement être une simple convolution 2x2 à 20 foulées, le LSTM avec seulement 2 unités cachées). Cela vous aidera à vous assurer que la structure de votre modèle est correcte et qu'il n'y a pas de problèmes particuliers. J'ai eu du mal à utiliser un tel modèle pendant un certain temps et lorsque j'ai essayé une version plus simple, j'ai découvert que l'une des couches n'était pas masquée correctement en raison d'un bug de keras. Vous pouvez facilement (et rapidement ) interroger les couches de modèle internes et voir si vous avez configuré votre graphique correctement.

6) Standardisez vos versions de pré-traitement et de paquet

Les réseaux de neurones en particulier sont extrêmement sensibles aux petites modifications de vos données. À titre d’exemple, deux packages de chargement d’image populaires sont cv2and PIL. Juste en vertu de l' ouverture d' un fichier JPEG, ces deux packages produiront des images légèrement différentes . Les différences sont généralement très petites, mais vous constaterez parfois des baisses de performances de modèles dues à ce genre de choses. Cela fait aussi du débogage un cauchemar: vous obtenez un score de validation pendant l’entraînement, puis vous utilisez un chargeur différent et obtenez une précision différente sur le même jeu de données.

Donc, si vous téléchargez le modèle de quelqu'un depuis github, faites très attention à leur prétraitement. Quels chargeurs d'images utilisent-ils? Quelles routines de prétraitement d’images utilisent-ils? Lors du redimensionnement d'une image, quelle interpolation utilisent-ils? Est-ce qu'ils redimensionnent d'abord et ensuite normalisent l'image? Ou l'inverse? Quel est l'ordre des canaux pour les images RVB?

Le moyen le plus sûr de normaliser les packages consiste à utiliser un requirements.txtfichier décrivant tous vos packages, comme dans la configuration de votre système d’apprentissage, jusqu’au keras==2.1.5numéro de version. En théorie, utiliser Docker avec le même processeur graphique que sur votre système de formation devrait alors produire les mêmes résultats.

Alex R.
la source
7
(+1) Vérifier la perte initiale est une excellente suggestion. Je regrette de ne pas l'avoir laissé dans ma réponse.
Sycorax
7
S'assurer que votre modèle peut sur-adapter est une excellente idée. Je suis tellement habitué à penser à l'overfitting comme à une faiblesse que je n'avais jamais explicitement pensé (jusqu'à ce que vous l'ayez mentionnée) que la capacité à l'overfit soit réellement une force.
John Coleman
15

Ne formez pas de réseau de neurones pour commencer!

Toutes les réponses sont bonnes, mais il convient de mentionner un point: y a-t-il quelque chose à apprendre de vos données? (qui pourrait être considéré comme une sorte de test).

Si l'étiquette que vous essayez de prédire est indépendante de vos caractéristiques, il est probable que la perte d'entraînement aura du mal à se réduire.

Commencez plutôt par calibrer une régression linéaire, une forêt aléatoire (ou toute méthode à votre goût, dont le nombre d'hyperparamètres est faible et dont vous pouvez comprendre le comportement).

Ensuite, si vous réalisez des performances décentes sur ces modèles (mieux que des suppositions aléatoires), vous pouvez commencer à accorder un réseau de neurones (et la réponse de @Sycorax résoudra la plupart des problèmes).

RUser4512
la source
5
Xk
11

À la base, le flux de travail de base pour la formation d’un modèle NN / DNN est plus ou moins identique:

  1. définir l'architecture NN (combien de couches, quel type de couches, les connexions entre les couches, les fonctions d'activation, etc.)

  2. lire des données à partir d'une source (Internet, une base de données, un ensemble de fichiers locaux, etc.), consulter quelques exemples (pour s'assurer que l'importation s'est bien déroulée) et effectuer le nettoyage des données si nécessaire. Cette étape n’est pas aussi anodine que les gens le supposent généralement. La raison en est que pour les DNN, nous avons généralement affaire à de gigantesques ensembles de données, de plusieurs ordres de grandeur plus grands que ceux auxquels nous sommes habitués, lorsque nous ajustons des modèles statistiques paramétriques non linéaires plus standard (les NN appartiennent à cette famille, en théorie).

  3. normaliser ou normaliser les données d'une certaine manière. Comme les NN sont des modèles non linéaires, la normalisation des données peut affecter non seulement la stabilité numérique, mais également le temps d’entraînement et les sorties NN (une fonction linéaire telle que la normalisation ne permet pas de basculer avec une fonction hiérarchique non linéaire).

  4. fractionner les données dans la formation / validation / test, ou dans plusieurs plis si vous utilisez la validation croisée.

  5. former le réseau de neurones, tout en contrôlant la perte sur le jeu de validation. Ici, vous pouvez profiter des plaisirs de l'optimisation non convexe, où vous ne savez pas s'il existe une solution, s'il existe plusieurs solutions, quelle est la meilleure solution en termes d'erreur de généralisation et de proximité? il. La comparaison entre la perte de la formation et de la courbe de perte de validation vous guide, bien sûr, mais ne sous - estime pas la vie dure l' attitude de NNS (et surtout DNN): ils montrent souvent (peut - être lentement) la diminution des pertes de formation / validation même si vous avez bugs paralysants dans votre code.

  6. Vérifiez la précision du test et réalisez des diagrammes / tableaux de diagnostic.

  7. Retournez au point 1 car les résultats ne sont pas bons. Réitérer ad nauseam .

Bien sûr, les détails changeront en fonction du cas d'utilisation spécifique, mais en gardant à l'esprit ce canevas approximatif, nous pouvons penser à ce qui est le plus susceptible de mal tourner.

Vérifications d'architecture de base

Cela peut être une source de problèmes. D'habitude je fais ces vérifications préliminaires:

  • recherchez une architecture simple qui convient bien à votre problème (par exemple, MobileNetV2 dans le cas de la classification des images) et appliquez une initialisation appropriée (à ce niveau, la méthode aléatoire convient généralement). Si cela entraîne correctement sur vos données, au moins vous savez qu'il n'y a pas de problèmes criants dans le jeu de données. Si vous ne trouvez pas une architecture simple et testée qui fonctionne dans votre cas, imaginez une base simple . Par exemple, un classificateur Naive Bayes pour la classification (ou même simplement la classe la plus courante), ou un modèle ARIMA pour la prévision de séries chronologiques

  • Construire des tests unitaires. Négliger de le faire (et utiliser le sanglant Jupyter Notebook) est généralement la cause première des problèmes rencontrés dans le code NN que je dois examiner, en particulier lorsque le modèle est censé être déployé en production. Comme la réponse la plus votée a déjà couvert les tests unitaires, je voudrais simplement ajouter qu’il existe une bibliothèque qui prend en charge le développement de tests unitaires pour NN (uniquement dans Tensorflow, malheureusement).

Set d'entraînement

Vérifiez vos données d'entrée. Voyez si vous avez inversé le jeu d’apprentissage et les étiquettes du jeu d’essai, par exemple (m’est arrivé une fois -___-), ou si vous avez importé le mauvais fichier. Examinez quelques exemples d’entrée et les étiquettes associées et assurez-vous qu’elles ont un sens. Vérifiez que les données normalisées sont vraiment normalisées (regardez leur plage). De plus, les ensembles de données du monde réel sont sales: pour la classification, il peut y avoir un niveau élevé de bruit sur les étiquettes (les échantillons ont une étiquette de classe incorrecte) ou pour les prévisions multivariées sur les séries chronologiques, certaines composantes de la série chronologique peuvent manquer de données ( J'ai vu des chiffres aussi élevés que 94% pour certains des intrants).

L'ordre dans lequel l'ensemble d'entraînement est envoyé au filet pendant l'entraînement peut avoir un effet. Essayez un mélange aléatoire du jeu d’entraînement ( sans rompre l’association entre les entrées et les sorties ) et voyez si la perte d’apprentissage diminue.

Enfin, le meilleur moyen de vérifier si vous avez des problèmes d’entraînement est d’utiliser un autre ensemble. Si vous effectuez une classification des images plutôt que les images que vous avez collectées, utilisez un ensemble de données standard tel que CIFAR10 ou CIFAR100 (ou ImageNet, si vous pouvez vous permettre de vous entraîner à cela). Ces ensembles de données sont bien testés: si votre perte d’entraînement diminue ici, mais pas dans votre ensemble de données initial, vous risquez d’avoir des problèmes avec cet ensemble de données.

Faites les tests d'or

J'appelle Golden Tests, deux tests très utiles pour trouver des problèmes dans un NN qui ne s'entraîne pas:

  • réduisez le jeu d’entraînement à 1 ou 2 échantillons et entraînez-vous dessus. Le NN doit immédiatement surajuster le jeu d’entraînement, atteignant une précision de 100% très rapidement sur le jeu d’entraînement, tandis que la précision sur le jeu de validation / test passe à 0%. Si cela ne se produit pas, il y a un bug dans votre code.

  • le test opposé: vous conservez le kit d’entraînement complet, mais vous mélangez les étiquettes. Le NN ne peut apprendre que maintenant en mémorisant le jeu d’entraînement, ce qui signifie que la perte d’entraînement diminuera très lentement, tandis que la perte d’essai augmentera très rapidement. En particulier, vous devriez atteindre la perte de chance aléatoire sur l'ensemble de test . Cela signifie que si vous avez 1000 classes, vous devez atteindre une précision de 0,1%. Si vous ne voyez pas de différence entre la perte d’entraînement avant et après le remaniement des étiquettes, cela signifie que votre code est défectueux (n’oubliez pas que nous avons déjà vérifié les étiquettes de l’entraînement défini dans l’étape précédente).

Vérifiez que votre métrique de formation est logique

La précision (perte 0-1) est une mesure médiocre si vous avez un déséquilibre de classe important. Essayez quelque chose de plus significatif, tel que la perte d'entropie croisée: vous ne voulez pas simplement classer correctement, mais vous souhaitez classer avec une grande précision.

Sortez les gros canons

Si rien n'y fait, il est temps de commencer à jouer avec les hyperparamètres. C’est là le pire aspect de la formation NN, mais il s’agit de gigantesques modèles non identifiables dont les paramètres sont ajustés en résolvant une optimisation non convexe; ces itérations ne peuvent donc souvent pas être évitées.

  • essayez différents optimiseurs: SGD s'entraîne plus lentement, mais l'erreur de généralisation est plus faible, alors qu'Adam s'entraîne plus vite, mais la perte de test a une valeur supérieure.
  • essayez de diminuer la taille du lot
  • augmenter le taux d'apprentissage initialement, puis le décroître, ou utiliser un taux d'apprentissage cyclique
  • ajouter des couches
  • ajouter des unités cachées
  • supprimer la régularisation progressivement (peut-être changer la norme de lot pour quelques couches). La perte d’entraînement devrait maintenant diminuer, mais la perte au test pourrait augmenter.
  • visualiser la distribution des poids et des biais pour chaque couche. Je n'ai jamais eu à venir ici, mais si vous utilisez BatchNorm, vous vous attendriez à des distributions normales à peu près standard. Voir si la norme des poids augmente anormalement avec les époques.
  • si vous obtenez une erreur au moment de la formation, google cette erreur . J’ai perdu un matin en essayant de réparer une architecture qui fonctionnait parfaitement, mais j’ai découvert que la version de Keras que j’avais installée avait une prise en charge buggy multi-GPU et que je devais la mettre à jour. Parfois, je devais faire le contraire (rétrograder une version du paquet).
  • mettez à jour votre CV et commencez à chercher un autre emploi :-)
DeltaIV
la source
+1, mais "vachement Jupyter Notebook"? Voulez-vous commenter cela? :)
amibe
2
Voici pourquoi je déteste les ordinateurs portables Jupyter . TL; DR: état caché, diffing est une douleur, des problèmes de sécurité et il encourage les mauvaises pratiques de programmation, telles que ne pas utiliser les tests d'unité / de régression / d'intégration. Former les NN est déjà assez difficile, sans que les gens oublient les bases de la programmation.
DeltaIV
2
Je suis peut-être trop négatif, mais franchement, j'en ai assez des gens qui clonent des Jupyter Notebooks de GitHub, pensant qu'il ne faudrait que quelques minutes pour adapter le code à leur cas d'utilisation et ensuite venir me plaindre que rien ne fonctionne. Pour l'amour de Cripes, procurez-vous un véritable IDE tel que PyCharm ou VisualStudio Code et créez un code bien structuré, plutôt que de créer un bloc-notes! Surtout si vous envisagez de mettre le modèle en production, cela facilitera grandement les choses.
DeltaIV
2
Lol. 'Jupyter notebook' et 'unit testing' sont anti-corrélés.
Sycorax
2
(+1) C'est un bon article. Les suggestions de tests de randomisation sont vraiment des moyens formidables d’obtenir des réseaux bogués.
Sycorax
6

Si le modèle n'apprend pas, il y a de bonnes chances que votre propagation arrière ne fonctionne pas. Mais il y a tellement de choses qui peuvent mal se passer avec un modèle de boîte noire comme le réseau de neurones, il y a beaucoup de choses que vous devez vérifier. Je pense que Sycorax et Alex fournissent tous deux de très bonnes réponses complètes. Je veux juste ajouter une technique qui n'a pas encore été discutée.

Dans le cours d'apprentissage automatique d'Andrew Ng, il suggère d'exécuter la vérification du gradient.ε

Anthony Lei
la source