web-dev-qa-db-fra.com

Comment appliquer l'écrêtage dégradé dans TensorFlow?

Considérant le exemple de code .

Je voudrais savoir comment appliquer l'écrêtage de gradient sur ce réseau sur le RNN où il est possible d'exploser des gradients.

tf.clip_by_value(t, clip_value_min, clip_value_max, name=None)

Ceci est un exemple qui pourrait être utilisé, mais où puis-je introduire ceci? Dans 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)

Mais cela n’a aucun sens car le tenseur _X est l’entrée et non le grad, qu'est-ce qui doit être coupé?

Dois-je définir mon propre optimiseur à cet effet ou existe-t-il une option plus simple?

85
Arsenal Fanatic

L'écrêtage de dégradé doit avoir lieu après le calcul des dégradés, mais avant de les appliquer pour mettre à jour les paramètres du modèle. Dans votre exemple, ces deux choses sont gérées par la méthode AdamOptimizer.minimize().

Pour découper vos dégradés, vous devez explicitement les calculer, les découper et les appliquer comme décrit dans la section cette section de la documentation sur l'API de TensorFlow . Plus précisément, vous devrez substituer l'appel à la méthode minimize() par ce qui suit:

optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate)
gvs = optimizer.compute_gradients(cost)
capped_gvs = [(tf.clip_by_value(grad, -1., 1.), var) for grad, var in gvs]
train_op = optimizer.apply_gradients(capped_gvs)
129
Styrke

En dépit de ce qui semble être populaire, vous voudrez probablement découper l’ensemble du dégradé selon sa norme globale:

optimizer = tf.train.AdamOptimizer(1e-3)
gradients, variables = Zip(*optimizer.compute_gradients(loss))
gradients, _ = tf.clip_by_global_norm(gradients, 5.0)
optimize = optimizer.apply_gradients(Zip(gradients, variables))

Couper chaque matrice de dégradé individuellement change leur échelle relative mais est également possible:

optimizer = tf.train.AdamOptimizer(1e-3)
gradients, variables = Zip(*optimizer.compute_gradients(loss))
gradients = [
    None if gradient is None else tf.clip_by_norm(gradient, 5.0)
    for gradient in gradients]
optimize = optimizer.apply_gradients(Zip(gradients, variables))
104
danijar

Ceci est en fait correctement expliqué dans la documentation. :

L'appel à minim () prend en charge le calcul des gradients et leur application aux variables. Si vous souhaitez traiter les dégradés avant de les appliquer, vous pouvez utiliser l'optimiseur en trois étapes:

  • Calculez les gradients avec compute_gradients ().
  • Traitez les dégradés à votre guise.
  • Appliquez les dégradés traités avec apply_gradients ().

Et dans l'exemple qu'ils fournissent, ils utilisent ces 3 étapes:

# Create an optimizer.
opt = GradientDescentOptimizer(learning_rate=0.1)

# Compute the gradients for a list of variables.
grads_and_vars = opt.compute_gradients(loss, <list of variables>)

# grads_and_vars is a list of tuples (gradient, variable).  Do whatever you
# need to the 'gradient' part, for example cap them, etc.
capped_grads_and_vars = [(MyCapper(gv[0]), gv[1]) for gv in grads_and_vars]

# Ask the optimizer to apply the capped gradients.
opt.apply_gradients(capped_grads_and_vars)

Ici MyCapper est une fonction quelconque qui coiffe votre dégradé. La liste des fonctions utiles (autres que tf.clip_by_value()) est ici .

9
Salvador Dali

Pour ceux qui voudraient comprendre l’idée de coupure de gradient (par norme):

Chaque fois que la norme de gradient est supérieure à un seuil particulier, nous découpons la norme de gradient de sorte qu'elle reste dans les limites du seuil. Ce seuil est parfois défini sur _5_.

Soit le gradient g et le seuil max_norm_threshold soit j .

Maintenant, si || g || > j , nous faisons:

g = ( j * g )/|| g ||

Ceci est l’implémentation effectuée dans tf.clip_by_norm

7
kmario23

IMO, la meilleure solution consiste à emballer votre optimiseur avec l'estimateur décorateur de TF tf.contrib.estimator.clip_gradients_by_norm:

original_optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate)
optimizer = tf.contrib.estimator.clip_gradients_by_norm(original_optimizer, clip_norm=5.0)
train_op = optimizer.minimize(loss)

De cette façon, il vous suffit de définir cette option une fois, et non de l'exécuter après chaque calcul de gradients.

Documentation: https://www.tensorflow.org/api_docs/python/tf/contrib/estimator/clip_gradients_by_norm

4
Ido Cohn

En règle générale, l'écrêtage de gradient aide en cas d'éclatement ou d'élimination des gradients. Dites que votre perte est trop élevée, ce qui entraînera des gradients exponentiels à traverser le réseau, ce qui peut entraîner des valeurs de Nan. Pour résoudre ce problème, nous découpons les gradients dans une plage spécifique (-1 à 1 ou dans une plage quelconque selon les conditions).

clipped_value=tf.clip_by_value(grad, -range, +range), var) for grad, var in grads_and_vars

où grads _and_vars sont les paires de gradients (que vous calculez via tf.compute_gradients) et leurs variables auxquelles ils seront appliqués.

Après l'écrêtage, nous appliquons simplement sa valeur à l'aide d'un optimiseur. optimizer.apply_gradients(clipped_value)

2
Raj