Tensorflow:如何替换或修改渐变?

新手上路,请多包涵

我想替换或修改 op 的梯度或张量流中图形的一部分。如果我可以在计算中使用现有的梯度,那将是理想的。

在某些方面,这与 tf.stop_gradient() 的作用相反:我想要一个仅在计算梯度时使用的计算,而不是添加在计算梯度时被忽略的计算。

一个简单的例子是通过将梯度乘以一个常数来简单地缩放梯度(但不将前向计算乘以一个常数)。另一个例子是将渐变剪切到给定范围的东西。

原文由 Alex I 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 683
2 个回答

对于 TensorFlow 1.7 和 TensorFlow 2.0,请查看 edit blow。


首先定义您的自定义渐变:

 @tf.RegisterGradient("CustomGrad")
def _const_mul_grad(unused_op, grad):
  return 5.0 * grad

由于您不希望在前向传递中发生任何事情,因此请使用新梯度覆盖身份操作的梯度:

 g = tf.get_default_graph()
with g.gradient_override_map({"Identity": "CustomGrad"}):
  output = tf.identity(input, name="Identity")

这是一个工作示例,其中一个层在向后传递中剪切渐变并且在向前传递中不执行任何操作,使用相同的方法:

 import tensorflow as tf

@tf.RegisterGradient("CustomClipGrad")
def _clip_grad(unused_op, grad):
  return tf.clip_by_value(grad, -0.1, 0.1)

input = tf.Variable([3.0], dtype=tf.float32)

g = tf.get_default_graph()
with g.gradient_override_map({"Identity": "CustomClipGrad"}):
  output_clip = tf.identity(input, name="Identity")
grad_clip = tf.gradients(output_clip, input)

# output without gradient clipping in the backwards pass for comparison:
output = tf.identity(input)
grad = tf.gradients(output, input)

with tf.Session() as sess:
  sess.run(tf.global_variables_initializer())
  print("with clipping:", sess.run(grad_clip)[0])
  print("without clipping:", sess.run(grad)[0])

针对 TensorFlow 1.7 和 TensorFlow 2.0 进行编辑

从 1.7 开始,有一种新的方法可以用更短的语法重新定义梯度,这也适用于 Tensorflow 2.0。它还允许同时重新定义多个操作的梯度。以下是上面的示例,为 TensorFlow 1.7 和 TensorFlow 2.0 重写:

在向后传递中缩放梯度的层:

 @tf.custom_gradient
def scale_grad_layer(x):
  def grad(dy):
    return 5.0 * dy
  return tf.identity(x), grad

在向后传递中剪切渐变的图层示例:

 @tf.custom_gradient
def clip_grad_layer(x):
  def grad(dy):
    return tf.clip_by_value(dy, -0.1, 0.1)
  return tf.identity(x), grad

原文由 BlueSun 发布,翻译遵循 CC BY-SA 4.0 许可协议

假设正向计算是

y = f(x)

你想让它反向传播

y = b(x)

一个简单的黑客将是:

 y = b(x) + tf.stop_gradient(f(x) - b(x))

原文由 Bily 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题