Emita NaN con Adam Solver

Estoy entrenando redes con el solucionador Adam y me encontré con el problema, esa optimización llega a ‘nan’ en algún momento, pero la pérdida parece disminuir bastante bien hasta ese punto. Ocurre solo para algunas configuraciones específicas y después de un par de miles de iteraciones. Por ejemplo, la red con tamaño de lote 5 tendrá el problema, mientras que con un tamaño de lote de uno funciona. Así que empecé a depurar mi código:

1) Lo primero que me vino a la mente es comprobar las entradas cuando la red alcanza ‘nan’, pero parecen razonables (verdad del terreno correctamente etiquetado y entrada con un rango de valores aceptable)

2) Durante la búsqueda, descubrí tf.verify_tensor_all_finite(..) y puse eso en todo mi código para ver, qué tensor se convierte en “nan”. Podría reducir el problema a las siguientes líneas:

 kernel = tf.verify_tensor_all_finite(kernel, 'kernel') in_tensor = tf.verify_tensor_all_finite(in_tensor, 'in_tensor') tmp_result = tf.nn.conv2d_transpose(value=in_tensor, filter=kernel, output_shape=output_shape, strides=strides, padding='SAME') tmp_result = tf.verify_tensor_all_finite(tmp_result, 'convres') 

Lo que arroja un error, que lee:

 InvalidArgumentError (see above for traceback): convres : Tensor had NaN values [[Node: upconv_logits5_fs/VerifyFinite_2/CheckNumerics = CheckNumerics[T=DT_FLOAT, _class=["loc:@upconv_logits5_fs/conv2d_transpose"], message="convres", _device="/job:localhost/replica:0/task:0/gpu:0"](upconv_logits5_fs/conv2d_transpose)]] [[Node: Adam/update/_2794 = _Recv[client_terminated=false, recv_device="/job:localhost/replica:0/task:0/cpu:0", send_device="/job:localhost/replica:0/task:0/gpu:0", send_device_incarnation=1, tensor_name="edge_154_Adam/update", tensor_type=DT_FLOAT, _device="/job:localhost/replica:0/task:0/cpu:0"]()]] 

Ahora no estoy seguro de lo que pasó aquí.

Supongo que, durante el paso hacia adelante, todo salió bien, porque la pérdida escalar no provocó un error y también el kernel y la entrada eran números válidos. Parece que algún nodo de actualización de Adam modifica el valor de mi upconv_logits5_fs hacia nan. Esta operación de convolución transpuesta es la última de mi red y, por lo tanto, la primera en actualizarse.

Estoy trabajando con una pérdida tf.nn.softmax_cross_entropy_with_logits() y puse tf.verify_tensor_all_finite() en todas las entradas y salidas, pero no activan errores. La única conclusión que puedo sacar es que podría haber un problema numérico con el solucionador de Adam.

  • ¿Qué opinas de esa conclusión?
  • ¿Alguien tiene alguna idea de cómo proceder o qué podría intentar?

Su ayuda es muy apreciada.

EDITAR: Pude resolver mi problema aumentando el parámetro epsilon de los solucionadores de 1e-8 a 1e-4. Parecía que algunos de mis parámetros tienden a tener muy poca variación a cero y eso dio lugar a tf.sqrt(0.0 + epsilon) , lo que causó problemas numéricos.

Había corrido al mismo problema varias veces. La razón detrás de este problema es mediante el uso de softmax y crossentropy. Entonces, cuando está calculando el gradiente y el buceo a cero o inf, está obteniendo nan, que se está propagando, arroje todos sus parámetros.

Algunos consejos para evitar este problema.

  • si el error comienza a boost, NaN aparece después: divergente debido a una tasa de aprendizaje demasiado alta
  • si los NaN aparecen repentinamente: unidades de saturación que producen un gradiente no diferenciable
  • Cálculo de NaN debido a log (0)
  • NaN debido a problemas de punto flotante (a pesos altos) o activaciones en la salida
  • 0/0, inf / inf, inf * peso …

soluciones:

  • reducir la tasa de aprendizaje
  • Cambiar la inicialización del peso.
  • Usa la norma L2
  • Softmax seguro (pequeño valor agregado al registro (x))
  • recorte de gradiente

En mi caso, la tasa de aprendizaje resolvió el problema, pero todavía estoy trabajando para optimizarlo más.

Un paso adicional que no se incluyó en la respuesta de Feras y me costó un día de depuración.

Aumentar la precisión de tus variables. Tenía una red donde se definían muchas variables como float16. La red funcionó bien para todos los optimizadores, excepto Adam y Adadelt. Después de horas de depuración ft.float64 a ft.float64 y funcionó.

Este es un problema de estabilidad numérica. Le sugeriría que intente una tasa de aprendizaje más baja para ver si eso resuelve su problema.