machine-learning - tutorial - net forward
Causas comunes de nans durante el entrenamiento (4)
He notado que una ocurrencia frecuente durante el entrenamiento es la introducción de
NAN
.
Muchas veces parece ser introducido por pesos en capas internas de producto / completamente conectadas o convolución.
¿Esto ocurre porque el cálculo de gradiente está explotando? ¿O es debido a la inicialización del peso (si es así, ¿por qué la inicialización del peso tiene este efecto)? ¿O es probable que sea causado por la naturaleza de los datos de entrada?
La pregunta general aquí es simplemente: ¿Cuál es la razón más común para que ocurran NAN durante el entrenamiento? Y en segundo lugar, ¿cuáles son algunos métodos para combatir esto (y por qué funcionan)?
Buena pregunta.
Encontré este fenómeno varias veces.
Aquí están mis observaciones:
Explosión de gradiente
Motivo: los grandes gradientes desvían el proceso de aprendizaje.
Lo que debe esperar:
mirando el registro de tiempo de ejecución, debe mirar los valores de pérdida por iteración.
Notarás que la pérdida comienza a crecer
significativamente
de iteración a iteración, eventualmente la pérdida será demasiado grande para ser representada por una variable de coma flotante y se convertirá en
nan
.
¿Qué puedes hacer?
Disminuye la
base_lr
(en el solver.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 del aumento de gradiente y disminuir el
loss_weight
(en train_val.prototxt) para esa capa específica, en lugar del
base_lr
general.
Mala política de aprendizaje y parámetros
Motivo:
caffe no puede calcular una tasa de aprendizaje válida y obtiene
''inf''
o
''nan''
, esta tasa no válida multiplica todas las actualizaciones y, por lo tanto, invalida todos los parámetros.
Lo que debe esperar:
al observar 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é puede hacer:
corrija todos los parámetros que afectan la velocidad de aprendizaje en su 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 sobre la tasa de aprendizaje en caffe, consulte
este hilo
.
Función de pérdida defectuosa
Motivo: a
veces los cálculos de la pérdida en las capas de pérdida hacen que aparezcan
nan
s.
Por ejemplo, Alimentando la
capa
InfogainLoss
con valores no normalizados
, usando la capa de pérdida personalizada con errores, etc.
Lo que debe esperar:
Al mirar 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: ver si puede reproducir el error, agregar una copia impresa a la capa de pérdida y depurar el error.
Por ejemplo: una vez utilicé 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 etiquetas de entrenamiento no aparecía en el lote, la pérdida calculada producía
nan
s.
En ese caso, trabajar con lotes lo suficientemente grandes (con respecto al número de etiquetas en el conjunto) fue suficiente para evitar este error.
Entrada defectuosa
Motivo:
¡tienes una entrada con
nan
!
Lo que debe esperar:
una vez que el proceso de aprendizaje "golpea" esta entrada - salida defectuosa se convierte en
nan
.
Mirando 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:
reconstruir sus conjuntos de datos de entrada (lmdb / leveldn / hdf5 ...) asegúrese de no tener archivos de imágenes defectuosos en su conjunto de capacitación / validación.
Para la depuración, puede construir una red simple que lea la capa de entrada, tenga una pérdida ficticia encima y recorra todas las entradas: si una de ellas es defectuosa, esta red ficticia también debería producir
nan
.
zancada mayor que el tamaño del núcleo en la capa
"Pooling"
Por alguna razón, elegir
stride
>
kernel_size
para la agrupación puede dar como resultado
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 algunas configuraciones, la capa
"BatchNorm"
puede generar
nan
s debido a inestabilidades numéricas.
Este
issue
se planteó en bvlc / caffe y
issue
está intentando solucionarlo.
Recientemente, me di cuenta del indicador
debug_info
: establecer
debug_info: true
en
''solver.prototxt''
hará que caffe print registre más información de depuración (incluidas las magnitudes de gradiente y los valores de activación) durante el entrenamiento: esta información puede
ayudar a detectar explosiones de gradiente y otros problemas en el proceso de entrenamiento
.
En mi caso, no establecer el sesgo en las capas de convolución / deconvolución fue la causa.
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 de
nan
s, sino que propone una forma 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 puede 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, tuve que eliminar 1), descubrí que los NaN habían desaparecido. Entonces, supongo que demasiada escasez puede conducir a NaN también (¡algunos cálculos 0/0 pueden haberse invocado !?)