Considerando el código de ejemplo .
Me gustaría saber cómo aplicar el recorte de gradiente en esta red en el RNN donde existe la posibilidad de explosiones de gradientes.
tf.clip_by_value(t, clip_value_min, clip_value_max, name=None)
Este es un ejemplo que podría usarse, pero ¿dónde lo introduzco? En la def de RNN
lstm_cell = rnn_cell.BasicLSTMCell(n_hidden, forget_bias=1.0)
# Split data because rnn cell needs a list of inputs for the RNN inner loop
_X = tf.split(0, n_steps, _X) # n_steps
tf.clip_by_value(_X, -1, 1, name=None)
Pero esto no tiene sentido ya que el tensor _X es la entrada y no el grad. ¿Qué se va a recortar?
¿Tengo que definir mi propio Optimizador para esto o hay una opción más simple?
fuente
optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost)
y luego se realiza una iteración del optimizador como,optimizer.run()
pero el usooptimizer.run()
no parece funcionar en este caso.optimizer.apply_gradients(capped_gvs)
que debe asignarse a algo,x = optimizer.apply_gradients(capped_gvs)
luego, dentro de su sesión, puede entrenar comox.run(...)
UserWarning: Converting sparse IndexedSlices to a dense Tensor with 148331760 elements. This may consume a large amount of memory.
De alguna manera mis escasos gradientes se convierten en densos. ¿Alguna idea de cómo superar este problema?tf.clip_by_global_norm
, como lo sugiere @danijarA pesar de lo que parece ser popular, probablemente desee recortar todo el degradado según su norma global:
Recortar cada matriz de degradado cambia individualmente su escala relativa, pero también es posible:
En TensorFlow 2, una cinta calcula los gradientes, los optimizadores provienen de Keras y no necesitamos almacenar la operación de actualización porque se ejecuta automáticamente sin pasarla a una sesión:
fuente
clip_by_global_norm()
! Esto también se describethe correct way to perform gradient clipping
en los documentos de tensorflowtf.global_norm(gradients)
para ver su rango habitual y luego recortar un poco más para evitar que los valores atípicos estropeen el entrenamiento.opt.minimize()
después o llamaría algo diferenteopt.run()
como se sugiere en algunos de los comentarios sobre otras respuestas?optimizer.minimize(loss)
es solo una forma abreviada de calcular y aplicar los degradados. Puede ejecutar el ejemplo en mi respuesta consess.run(optimize)
.tf.estimator.EstimatorSpec(mode, loss=loss, train_op=train_op)
una función de experimento,optimize
¿reemplazaría la míatrain_op
correcta? Ahora mismotrain_op = optimizer.minimize(loss, global_step=global_step))
, estoy tratando de asegurarme de ajustarme en consecuencia ...En realidad, esto se explica correctamente en la documentación. :
Y en el ejemplo que proporcionan, utilizan estos 3 pasos:
Aquí
MyCapper
hay cualquier función que limite su degradado. La lista de funciones útiles (distintas detf.clip_by_value()
) está aquí .fuente
opt.minimize()
después o llamaría algo diferenteopt.run()
como se sugiere en algunos de los comentarios sobre otras respuestas?opt.apply_gradients(...)
a una variable como,train_step
por ejemplo (como lo haría paraopt.minimize()
. Y en su bucle principal lo llama como de costumbre para entrenarsess.run([train_step, ...], feed_dict)
tf.clip_by_global_norm(list_of_tensors)
).Para aquellos que quieran entender la idea del recorte de gradiente (por norma):
Siempre que la norma de gradiente es mayor que un umbral particular, recortamos la norma de gradiente para que permanezca dentro del umbral. Este umbral a veces se establece en
5
.Deje que el gradiente sea gy el max_norm_threshold sea j .
Ahora, si || g || > j , hacemos:
g = ( j * g ) / || g ||
Esta es la implementación realizada en
tf.clip_by_norm
fuente
En mi opinión, la mejor solución es envolver su optimizador con el decorador de estimadores de TF
tf.contrib.estimator.clip_gradients_by_norm
:De esta manera, solo tiene que definir esto una vez y no ejecutarlo después de cada cálculo de gradientes.
Documentación: https://www.tensorflow.org/api_docs/python/tf/contrib/estimator/clip_gradients_by_norm
fuente
El recorte de gradiente básicamente ayuda en caso de explosión o desaparición de gradientes. Diga que su pérdida es demasiado alta, lo que resultará en gradientes exponenciales para fluir a través de la red, lo que puede dar como resultado valores de Nan. Para superar esto, recortamos los degradados dentro de un rango específico (-1 a 1 o cualquier rango según la condición).
clipped_value=tf.clip_by_value(grad, -range, +range), var) for grad, var in grads_and_vars
donde grads _and_vars son los pares de gradientes (que calcula a través de tf.compute_gradients) y sus variables a las que se aplicarán.
Después del recorte, simplemente aplicamos su valor usando un optimizador.
optimizer.apply_gradients(clipped_value)
fuente