如何在TensorFlow中应用渐变剪裁?

Ars*_*tic 90 python machine-learning deep-learning lstm tensorflow

考虑示例代码.

我想知道如何在可能爆炸梯度的RNN上对此网络应用渐变剪辑.

tf.clip_by_value(t, clip_value_min, clip_value_max, name=None)
Run Code Online (Sandbox Code Playgroud)

这是一个可以使用的示例,但我在哪里介绍这个?在defN的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)
Run Code Online (Sandbox Code Playgroud)

但是这没有意义,因为张量_X是输入而不是渐变的被剪裁的东西?

我是否必须为此定义自己的优化器,还是有更简单的选项?

Sty*_*rke 133

在计算渐变之后,但在应用它们来更新模型的参数之前,需要进行梯度裁剪.在您的示例中,这两个方面都由AdamOptimizer.minimize()方法处理.

为了剪切渐变,您需要显式计算,剪辑和应用它们,如本节TensorFlow的API文档中所述.具体来说,您需要使用以下内容替换调用minimize()方法:

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)
Run Code Online (Sandbox Code Playgroud)

  • 实际上剪辑渐变的正确方法(根据tensorflow文档,计算机科学家和逻辑)是使用`tf.clip_by_global_norm`,正如@danijar所建议的那样 (7认同)
  • 好了吧`optimizer.apply_gradients(capped_gvs)`需要分配给某些东西`x = optimizer.apply_gradients(capped_gvs)`然后在你的会话中你可以训练为`x.run(...)` (6认同)
  • Styrke,谢谢你的帖子.您知道实际运行优化器迭代的后续步骤是什么吗?通常,优化器被实例化为`optimizer = tf.train.AdamOptimizer(learning_rate = learning_rate).minimize(cost)`然后优化器的迭代完成为`optimizer.run()`但是使用`optimizer.run() `在这种情况下似乎不起作用? (4认同)
  • 向@ remi-cuingnet大喊[编辑建议](http://stackoverflow.com/review/suggested-edits/12543496).(不幸的是被匆忙的审稿人拒绝了) (3认同)

dan*_*jar 108

尽管看起来很受欢迎,但您可能希望通过其全局规范来剪切整个渐变:

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))
Run Code Online (Sandbox Code Playgroud)

单独剪切每个渐变矩阵会改变它们的相对比例,但也可能:

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))
Run Code Online (Sandbox Code Playgroud)

  • `clip_by_global_norm()`的好例子!这在tensorflow文档中也被描述为"执行渐变剪辑的正确方法":https://www.tensorflow.org/versions/r1.2/api_docs/python/tf/clip_by_global_norm (9认同)
  • @Escachator这是经验性的,取决于你的模型和可能的任务.我所做的是可视化渐变范数`tf.global_norm(gradients)`以查看它的通常范围,然后在其上方剪辑一点以防止异常值弄乱训练. (8认同)
  • @ reese0106不,`optimizer.minimize(loss)`只是计算和应用渐变的简写.您可以使用`sess.run(optimize)`在我的回答中运行示例. (2认同)

Sal*_*ali 9

实际上在文档中对此进行了适当的解释.:

调用minimize()会同时计算渐变并将它们应用于变量.如果要在应用渐变之前处理渐变,可以分三步使用优化器:

  • 使用compute_gradients()计算渐变.
  • 根据需要处理渐变.
  • 使用apply_gradients()应用已处理的渐变.

在他们提供的示例中,他们使用以下3个步骤:

# 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)
Run Code Online (Sandbox Code Playgroud)

MyCapper是限制渐变的任何函数.有用的功能列表(除了tf.clip_by_value())在这里.


Nic*_*ais 8

tf.keras 很容易!

optimizer = tf.keras.optimizers.Adam(clipvalue=1.0)
Run Code Online (Sandbox Code Playgroud)

此优化器会将所有梯度剪辑到 之间的值[-1.0, 1.0]

请参阅文档

  • 另外,如果我们使用自定义训练并使用“optimizer.apply_gradients”,我们需要在调用此方法之前修剪梯度。在这种情况下,我们需要“gradients = [(tf.clip_by_value(grad, -1., 1.), var) for grad, var ingradients]”,然后是“.apply_graidents”。 (3认同)
  • 它还支持 `clipnorm` 和显然的 `global_clipnorm`:optimizer = tf.keras.optimizers.Adam(global_clipnorm=5.0) (2认同)

kma*_*o23 7

对于那些想要理解渐变剪辑(通过规范)的人:

只要梯度范数大于特定阈值,我们就会剪切梯度范数,使其保持在阈值范围内.此阈值有时设置为5.

设梯度为g,max_norm_threshold为j.

现在,如果|| g || > j,我们这样做:

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

这是在中完成的实现 tf.clip_by_norm


Ido*_*ohn 5

IMO 最好的解决方案是用 TF 的 estimator 装饰器包装您的优化器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)
Run Code Online (Sandbox Code Playgroud)

这样你只需要定义一次,而不是在每次梯度计算后运行它。

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