web-dev-qa-db-fra.com

Causes communes de nans pendant la formation

J'ai remarqué qu'un événement fréquent lors de l'entraînement est l'introduction de NAN.

Souvent, il semble être introduit par les poids dans les couches de produit intérieur/entièrement connecté ou de convolution exploser.

Est-ce que cela se produit parce que le calcul du gradient explose? Ou est-ce à cause de l'initialisation du poids (si oui, pourquoi l'initialisation du poids a-t-elle cet effet)? Ou est-ce que cela est probablement dû à la nature des données d'entrée?

La question primordiale est simplement la suivante: Quelle est la raison la plus fréquente selon laquelle les NAN surviennent pendant l’entraînement? Et deuxièmement, quelles sont certaines méthodes pour lutter contre cela (et pourquoi fonctionnent-elles)?

69
Aidan Gomez

Bonne question.
Je suis tombé sur ce phénomène plusieurs fois. Voici mes observations:


Gradient sauter

Raison: les grands gradients jettent le processus d'apprentissage hors-piste.

Ce à quoi vous pouvez vous attendre: En regardant le journal d'exécution, vous devriez regarder les valeurs de perte par itération. Vous remarquerez que la perte commence à croître significativement d'itération en itération, la perte sera éventuellement trop importante pour être représentée par une variable à virgule flottante et elle deviendra nan .

Que pouvez-vous faire: Diminuer le base_lr (dans le solveur.prototxt) par un ordre de grandeur (au moins). Si vous avez plusieurs couches de perte, vous devez consulter le journal pour voir quelle couche est responsable de l’aggravation du gradient et diminuer le loss_weight (dans train_val.prototxt) pour cette couche spécifique, au lieu de la règle générale base_lr.


Mauvaise politique de taux d'apprentissage et params

Raison: caffe ne parvient pas à calculer un taux d'apprentissage valide et obtient 'inf' ou 'nan' au lieu de cela, ce taux invalide multiplie toutes les mises à jour et donc invalide tous les paramètres.

Ce à quoi vous devez vous attendre: En regardant le journal d'exécution, vous devriez voir que le taux d'apprentissage lui-même devient 'nan', par exemple:

... sgd_solver.cpp:106] Iteration 0, lr = -nan

Que pouvez-vous faire: corrigez tous les paramètres affectant le taux d'apprentissage dans votre 'solver.prototxt' fichier.
Par exemple, si vous utilisez lr_policy: "poly" et vous oubliez de définir max_iter paramètre, vous allez vous retrouver avec lr = nan...
Pour plus d’informations sur le taux d’apprentissage dans caffe, voir ce fil .


Fonction de perte défectueuse

Raison: Parfois, les calculs de perte dans les couches de perte entraînent l'apparition de nans. Par exemple, Alimentation InfogainLoss couche avec des valeurs non normalisées , en utilisant un calque de perte personnalisé avec des bugs, etc.

Ce à quoi vous devez vous attendre: En regardant le journal d'exécution, vous ne remarquerez probablement rien d'inhabituel: la perte diminue progressivement, et tout à coup un nan apparaît.

Que pouvez-vous faire: Voyez si vous pouvez reproduire l'erreur, ajoutez une impression à la couche de perte et corrigez l'erreur.

Par exemple: Une fois, j'ai utilisé une perte qui a normalisé la pénalité par la fréquence d'apparition d'étiquettes dans un lot. Il se trouve que si l'une des étiquettes de formation n'apparaissait pas du tout dans le lot, la perte calculée produisait nans. Dans ce cas, travailler avec un nombre de lots suffisant (par rapport au nombre d'étiquettes dans le jeu) était suffisant pour éviter cette erreur.


Entrée défectueuse

Raison: vous avez une entrée avec nan dedans!

Ce à quoi vous devez vous attendre: une fois que le processus d'apprentissage "touche" cette entrée défectueuse - la sortie devient nan. En regardant le journal d'exécution, vous ne remarquerez probablement rien d'inhabituel: la perte diminue progressivement, et tout à coup un nan apparaît.

Que pouvez-vous faire: reconstruisez vos jeux de données en entrée (lmdb/leveldn/hdf5 ...) pour vous assurer de ne pas avoir de mauvais fichiers image dans votre ensemble formation/validation. Pour le débogage, vous pouvez construire un réseau simple qui lit la couche d’entrée, a une perte fictive au dessus de celle-ci et traverse toutes les entrées: si l’une d’entre elles est défectueuse, ce réseau factice devrait également produire nan.


stride supérieur à la taille du noyau dans "Pooling" couche

Pour une raison quelconque, en choisissant stride> kernel_size pour le regroupement peut entraîner des résultats avec nans. Par exemple:

layer {
  name: "faulty_pooling"
  type: "Pooling"
  bottom: "x"
  top: "y"
  pooling_param {
    pool: AVE
    stride: 5
    kernel: 3
  }
}

résultats avec nans dans y.


Instabilités dans "BatchNorm"

Il a été signalé que sous certains paramètres "BatchNorm" La couche peut générer nans en raison d'instabilités numériques.
Ce problème a été soulevé dans bvlc/caffe et PR # 5136 tente de le réparer.


Récemment, j'ai pris conscience de debug_info flag: paramètre debug_info: true dans 'solver.prototxt' fera en sorte que caffe print inscrive plus d’informations de débogage (y compris les gradients et les valeurs d’activation) au cours de la formation: Cette information peut aide à repérer les explosions de gradient et d’autres problèmes dans le processus de formation .

106
Shai

Cette réponse ne concerne pas une cause de nans, mais propose plutôt un moyen d’aider à le déboguer. Vous pouvez avoir cette couche python:

class checkFiniteLayer(caffe.Layer):
  def setup(self, bottom, top):
    self.prefix = self.param_str
  def reshape(self, bottom, top):
    pass
  def forward(self, bottom, top):
    for i in xrange(len(bottom)):
      isbad = np.sum(1-np.isfinite(bottom[i].data[...]))
      if isbad>0:
        raise Exception("checkFiniteLayer: %s forward pass bottom %d has %.2f%% non-finite elements" %
                        (self.prefix,i,100*float(isbad)/bottom[i].count))
  def backward(self, top, propagate_down, bottom):
    for i in xrange(len(top)):
      if not propagate_down[i]:
        continue
      isf = np.sum(1-np.isfinite(top[i].diff[...]))
        if isf>0:
          raise Exception("checkFiniteLayer: %s backward pass top %d has %.2f%% non-finite elements" %
                          (self.prefix,i,100*float(isf)/top[i].count))

Ajout de cette couche dans votre train_val.prototxt à certains moments, vous pensez que cela peut causer des problèmes:

layer {
  type: "Python"
  name: "check_loss"
  bottom: "fc2"
  top: "fc2"  # "in-place" layer
  python_param {
    module: "/path/to/python/file/check_finite_layer.py" # must be in $PYTHONPATH
    layer: "checkFiniteLayer"
    param_str: "prefix-check_loss" # string for printouts
  }
}
3
Shai

Dans mon cas, ne pas définir le biais dans les couches de convolution/déconvolution en était la cause.

Solution: ajoutez ce qui suit aux paramètres de la couche de convolution.

biais_filler {type: "constante" valeur: 0}

3
izady