使用optimizer.compute_gradients
或tf.gradient
获得原始渐变
然后做你想做的
最后,使用optimizer.apply_gradients
我从github找到了一个例子
0
使用optimizer.compute_gradients
或tf.gradient
获得原始渐变
然后做你想做的
最后,使用optimizer.apply_gradients
我从github找到了一个例子
0
最通用的方法是使用https://www.tensorflow.org/api_docs/python/tf/RegisterGradient
下面,我实现了反向传播的梯度裁剪,可以与matmul
一起使用,如此处所示,或任何其他操作:
import tensorflow as tf
import numpy as np
# from https://gist.github.com/harpone/3453185b41d8d985356cbe5e57d67342
def py_func(func, inp, Tout, stateful=True, name=None, grad=None):
# Need to generate a unique name to avoid duplicates:
rnd_name = 'PyFuncGrad' + str(np.random.randint(0, 1E+8))
tf.RegisterGradient(rnd_name)(grad)
g = tf.get_default_graph()
with g.gradient_override_map({"PyFunc": rnd_name}):
return tf.py_func(func, inp, Tout, stateful=stateful, name=name)
def clip_grad(x, clip_value, name=None):
""""
scales backpropagated gradient so that
its L2 norm is no more than `clip_value`
"""
with tf.name_scope(name, "ClipGrad", [x]) as name:
return py_func(lambda x : x,
[x],
[tf.float32],
name=name,
grad=lambda op, g : tf.clip_by_norm(g, clip_value))[0]
用法示例:
with tf.Session() as sess:
x = tf.constant([[1., 2.], [3., 4.]])
y = tf.constant([[1., 2.], [3., 4.]])
print('without clipping')
z = tf.matmul(x, y)
print(tf.gradients(tf.reduce_sum(z), x)[0].eval())
print('with clipping')
z = tf.matmul(clip_grad(x, 1.0), clip_grad(y, 0.5))
print(tf.gradients(tf.reduce_sum(z), x)[0].eval())
print('with clipping between matmuls')
z = tf.matmul(clip_grad(tf.matmul(x, y), 1.0), y)
print(tf.gradients(tf.reduce_sum(z), x)[0].eval())
输出:
without clipping
[[ 3. 7.]
[ 3. 7.]]
with clipping
[[ 0.278543 0.6499337]
[ 0.278543 0.6499337]]
with clipping between matmuls
[[ 1.57841039 3.43536377]
[ 1.57841039 3.43536377]]
0
假设正向计算为
y = f(x)
而您希望它像
y = b(x)
一个简单的技巧将是:
y = b(x) + tf.stop_gradient(f(x) - b(x))
0
对于TensorFlow 1.7和TensorFlow 2.0,请看编辑打击。
首先定义您的自定义渐变:
@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
0
我想替换或修改tensorflow中图的运算或部分渐变。如果可以在计算中使用现有的梯度,那将是理想的。
在某些方面,这与
tf.stop_gradient()
的工作相反:我不希望添加一个在计算梯度时会被忽略的计算,而是要一个仅在计算梯度时使用的计算。一个简单的例子就是简单地通过将梯度乘以常数来缩放比例(但不将正向计算乘以常数)。另一个例子是将梯度裁剪到给定范围的东西。