Causas comunes de nans durante el entrenamiento

Me he dado cuenta de que una ocurrencia frecuente durante el entrenamiento es la introducción de NAN .

Muchas veces parece ser introducido por pesas en capas de producto interno / totalmente conectadas o de convolución que explotan.

¿Esto ocurre porque el cálculo del gradiente está explotando? ¿O se debe a la inicialización del peso (de ser así, por qué la inicialización del peso tiene este efecto)? ¿O es probable que sea causada por la naturaleza de los datos de entrada?

La pregunta principal aquí es simple: ¿Cuál es la razón más común por la cual las NAN ocurren durante el entrenamiento? Y en segundo lugar, ¿cuáles son algunos métodos para combatir esto (y por qué funcionan)?

Buena pregunta.
Me encontré con este fenómeno varias veces. Aquí están mis observaciones:


Gradient blow up

Motivo: los gradientes grandes arrojan el proceso de aprendizaje fuera de la pista.

Lo que debe esperar: mirando el registro de tiempo de ejecución, debe ver los valores de pérdida por iteración. Notarás que la pérdida comienza a crecer significativamente de una iteración a otra, eventualmente la pérdida será demasiado grande para ser representada por una variable de punto flotante y se convertirá en nan .

¿Qué puede hacer? Disminuya el base_lr (en el solucionador.prototxt) en un orden de magnitud (al menos). Si tiene varias capas de pérdida, debe inspeccionar el registro para ver qué capa es responsable de la explosión del degradado y disminuir el loss_weight (en train_val.prototxt) para esa capa específica, en lugar de la base_lr general.


Política de tasa de aprendizaje incorrecta y params

Motivo: caffe no puede calcular una tasa de aprendizaje válida y obtiene 'inf' o 'nan' lugar, esta tasa inválida multiplica todas las actualizaciones y, por lo tanto, invalida todos los parámetros.

Lo que debe esperar: mirando el registro de tiempo de ejecución, debería ver que la tasa de aprendizaje se convierte en 'nan' , por ejemplo:

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

Qué puedes hacer: arregla todos los parámetros que afectan la tasa de aprendizaje en tu archivo 'solver.prototxt' .
Por ejemplo, si usa lr_policy: "poly" y olvida definir el parámetro max_iter , terminará con lr = nan
Para obtener más información acerca de la tasa de aprendizaje en caffe, consulte este hilo .


Faulty Loss function

Motivo: A veces, los cálculos de la pérdida en las capas de pérdida hacen que aparezcan nan . Por ejemplo, Alimentar la capa de InfogainLoss con valores no normalizados , utilizando la capa de pérdida personalizada con errores, etc.

Lo que debe esperar: al observar el registro de tiempo de ejecución probablemente no notará nada inusual: la pérdida disminuye gradualmente, y de repente aparece un nan .

Qué puede hacer: vea si puede reproducir el error, agregue la impresión a la capa de pérdida y elimine el error.

Por ejemplo: una vez que usé una pérdida que normalizó la penalización por la frecuencia de aparición de la etiqueta en un lote. Dio la casualidad de que si una de las tags de entrenamiento no aparecía en el lote, la pérdida calculada producía nan . En ese caso, trabajar con lotes suficientemente grandes (con respecto al número de tags en el conjunto) fue suficiente para evitar este error.


Entrada defectuosa

Motivo: ¡tienes una entrada con nan en ella!

Lo que debe esperar: una vez que el proceso de aprendizaje “golpea” esta entrada defectuosa, la salida se convierte en nan . Al observar el registro de tiempo de ejecución, probablemente no notará nada inusual: la pérdida disminuye gradualmente y, de repente, aparece un nan .

Qué puede hacer: vuelva a comstackr sus conjuntos de datos de entrada (lmdb / leveldn / hdf5 …) asegúrese de que no tiene archivos de imagen defectuosos en su conjunto de entrenamiento / validación. Para la depuración puede construir una red simple que lea la capa de entrada, tenga una pérdida ficticia sobre ella y se ejecute a través de todas las entradas: si una de ellas es defectuosa, esta red ficticia también debe producir nan .


zancada más grande que el tamaño del núcleo en la capa "Pooling"

Por alguna razón, elegir stride > kernel_size para la agrupación puede resultar con nan s. Por ejemplo:

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

resultados con nan s en y .


Inestabilidades en "BatchNorm"

Se informó que bajo algunos ajustes, la capa "BatchNorm" puede dar salida a nan debido a inestabilidades numéricas.
Este problema se planteó en bvlc / caffe y PR # 5136 está intentando solucionarlo.


Recientemente, me di cuenta del indicador debug_info : al establecer debug_info: true en 'solver.prototxt' se imprimirá caffe para registrar más información de depuración (incluyendo magnitudes de gradiente y valores de activación) durante el entrenamiento: Esta información puede ayudar a detectar explosiones de gradientes y otros problemas en el proceso de entrenamiento .

En mi caso, la causa no fue establecer el sesgo en las capas de convolución / deconvolución.

Solución: agregue lo siguiente a los parámetros de la capa de convolución.

bias_filler {tipo: valor “constante”: 0}

Esta respuesta no se trata de una causa para las nan , sino que más bien propone una manera de ayudar a depurarla. Puedes tener esta capa de 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)) 

Agregar esta capa a su train_val.prototxt en ciertos puntos que sospecha pueden causar problemas:

 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 } } 

Estaba tratando de construir un autoencoder escaso y tenía varias capas para inducir la escasez. Mientras ejecutaba mi red, me encontré con los NaN. Al eliminar algunas de las capas (en mi caso, de hecho tuve que eliminar 1), descubrí que los NaN desaparecieron. Por lo tanto, supongo que demasiada dispersión puede conducir a NaN también (algunos cómputos 0/0 pueden haberse invocado?)