参考 tf.stop_gradient - 云+社区 - 腾讯云
1、tf.gradients()
tf.gradients(
ys,
xs,
grad_ys=None,
name='gradients',
colocate_gradients_with_ops=False,
gate_gradients=False,
aggregation_method=None,
stop_gradients=None,
unconnected_gradients=tf.UnconnectedGradients.NONE
)
参数:
- ys: 要微分的张量或张量列表。
- xs: 用于微分的张量或列表。
- grad_ys:可选。一个张量或张量列表,其大小与y相同,并保持y中每个y的梯度。用于对求和后加权。
- name: 可选名称,用于将所有渐变操作分组在一起。默认为“梯度”。
- colocate_gradients_with_ops: 如果为真,请尝试使用相应的op来合并渐变。
- gate_gradients: 如果为真,在操作返回的渐变周围添加一个元组。这避免了一些竞争条件。
- aggregation_method: 指定用于合并渐变项的方法。可接受的值是类AggregationMethod中定义的常量。
- stop_gradients: 可选。一个张量或张量的列表,不需要微分。
- unconnected_gradients: 可选。指定给定输入张量断开连接时返回的梯度值。可接受的值是在类tf中定义的常量。UnconnectedGradients,默认值为none。
返回值:
- xs中每个x的sum(dy/dx)的列表。
可能产生的异常:
LookupError
: if one of the operations betweenx
andy
does not have a registered gradient function.ValueError
: if the arguments are invalid.RuntimeError
: if called in Eager mode.
ys和xs都是张量或张量列表。grad_ys是一个张量列表,包含了ys接收到的梯度。列表的长度必须与ys相同。gradient()将ops添加到图中,输出ys对xs的导数。它返回一个长度为len(xs)的张量列表,其中每个张量都是y在ys中的和(dy/dx)。grad_ys是一个与ys长度相同的张量列表,它包含ys中每个y的初始梯度。当grad_ys为0时,为y中的每个y填充一个'1'的张量,其形状为y。用户可以提供自己的初始grad_y来计算导数,使用每个y的不同初始梯度(例如,如果想对每个y中的每个值使用不同的梯度权重)。stop_gradients是一个张量或张量列表,它被认为是关于所有xs的常数。这些张量不会反向传播,就像它们已经使用stop_gradient显式断开连接一样。除此之外,这允许计算偏导数而不是全导数。
例:
a = tf.constant(0.)
b = 2 * a
g = tf.gradients(a + b, [a, b], stop_gradients=[a, b])
这里的偏导数g的值为[1.0,1.0],与全导数tf相比。梯度(a + b, [a, b]),考虑a对b的影响,取值为[3.0,1.0]。
请注意,上述内容相当于:
a = tf.stop_gradient(tf.constant(0.))
b = tf.stop_gradient(2 * a)
g = tf.gradients(a + b, [a, b])
stop_gradients提供了一种在图已经构建好之后停止梯度的方法,而tf.stop_gradient在构建图期间停止梯度。当这两种方法结合时,反向传播在两个tf处都停止。tf.stop_gradient节点和stop_gradients中的节点,以最先遇到的节点为准。所有整数张量对于所有xs都被认为是常量,就像它们包含在stop_gradients中一样。unconnected_gradients确定如果图中每个x未连接到ys,则为xs中的每个x返回的值。默认情况下,这不是用来防止错误的。从数学上讲,这些梯度是零,可以使用“零”选项来请求。tf.UnconnectedGradients提供了以下选项和行为:
unconnected_gradients确定如果图中每个x未连接到ys,则为xs中的每个x返回的值。默认情况下,这不是用来防止错误的。从数学上讲,这些梯度是零,可以使用“零”选项来请求。UnconnectedGradients提供了以下选项和行为:
a = tf.ones([1, 2])
b = tf.ones([3, 1])
g1 = tf.gradients([b], [a], unnconnected_gradients='none')
sess.run(g1) # [None]
g2 = tf.gradients([b], [a], unconnected_gradients='zero')
sess.run(g2) # [array([[0., 0.]], dtype=float32)]
2、tf.stop_gradient()
停止梯度计算。当在一个图中执行时,这个op按原样输出它的输入张量。当构建ops来计算梯度时,该op会阻止将其输入的贡献考虑在内。通常情况下,梯度发生器通过递归找出对其计算有贡献的输入,将ops添加到图中,计算指定“损失”的导数。如果将这个op插入到图中,它的输入将被梯度生成器屏蔽。它们没有考虑到计算梯度。当你想用TensorFlow计算一个值,但需要假设该值是常量时,这是非常有用的。一些例子包括:
- EM算法中m步不应该包含通过e步输出的反向传播。
- 玻尔兹曼机的对比发散训练,当对能量函数进行微分时,训练不能通过从模型中生成样本的图进行反向传播。
- 对抗性训练,在对抗性示例生成过程中不应该有任何支持。
参数:
- input: 一个张量。
- name: 操作的名称(可选)。
返回值:
- 一个张量。具有与输入相同的类型。
例:
# 1、计算梯度
import tensorflow as tf
w1 = tf.get_variable('w1', shape=[3])
w2 = tf.get_variable('w2', shape=[3])
w3 = tf.get_variable('w3', shape=[3])
w4 = tf.get_variable('w4', shape=[3])
z1 = w1 + w2+ w3
z2 = w3 + w4
grads = tf.gradients([z1, z2], [w1, w2, w3, w4], grad_ys=[tf.convert_to_tensor([2.,2.,3.]),
tf.convert_to_tensor([3.,2.,4.])])
with tf.Session() as sess:
tf.global_variables_initializer().run()
print(sess.run(grads))
Outout:
-------------------------------------
[array([2., 2., 3.], dtype=float32),
array([2., 2., 3.], dtype=float32),
array([5., 4., 7.], dtype=float32),
array([3., 2., 4.], dtype=float32)]
-------------------------------------
# 2、阻挡节点BP的梯度
import tensorflow as tf
w1 = tf.Variable(2.0)
w2 = tf.Variable(2.0)
a = tf.multiply(w1, 3.0)
a_stoped = tf.stop_gradient(a)
# b=w1*3.0*w2
b = tf.multiply(a_stoped, w2)
gradients = tf.gradients(b, xs=[w1, w2])
print(gradients)
# 可见,一个节点被 stop之后,这个节点上的梯度,就无法再向前BP了。由于w1变量的梯度只能来自a节点,所
# 以,计算梯度返回的是None。
Output:
--------------------------------------------------------------------------
[None, <tf.Tensor 'gradients/Mul_1_grad/Mul_1:0' shape=() dtype=float32>]
--------------------------------------------------------------------------
import tensorflow as tf
a = tf.Variable(1.0)
b = tf.Variable(1.0)
c = tf.add(a, b)
c_stoped = tf.stop_gradient(c)
d = tf.add(a, b)
e = tf.add(c_stoped, d)
# e = c + d = a + b + a + b
gradients = tf.gradients(e, xs=[a, b])
with tf.Session() as sess:
tf.global_variables_initializer().run()
print(sess.run(gradients))
# 虽然 c节点被stop了,但是a,b还有从d传回的梯度,所以还是可以输出梯度值的。
Output:
-----------
[1.0, 1.0]
-----------
import tensorflow as tf
w1 = tf.Variable(2.0)
w2 = tf.Variable(2.0)
a = tf.multiply(w1, 3.0)
a_stoped = tf.stop_gradient(a)
# b=w1*3.0*w2
b = tf.multiply(a_stoped, w2)
opt = tf.train.GradientDescentOptimizer(0.1)
gradients = tf.gradients(b, xs=tf.trainable_variables())
tf.summary.histogram(gradients[0].name, gradients[0])
# 这里会报错,因为gradients[0]是None
#其它地方都会运行正常,无论是梯度的计算还是变量的更新。总觉着tensorflow这么设计有点不好,
#不如改成流过去的梯度为0
train_op = opt.apply_gradients(zip(gradients, tf.trainable_variables()))
print(gradients)
with tf.Session() as sess:
tf.global_variables_initializer().run()
print(sess.run(train_op))
print(sess.run([w1, w2]))
# 3、求高阶导数
import tensorflow as tf
with tf.device('/cpu:0'):
a = tf.constant(1.)
b = tf.pow(a, 2)
grad = tf.gradients(ys=b, xs=a) # 一阶导
print(grad[0])
grad_2 = tf.gradients(ys=grad[0], xs=a) # 二阶导
grad_3 = tf.gradients(ys=grad_2[0], xs=a) # 三阶导
print(grad_3)
with tf.Session() as sess:
print(sess.run(grad_3))
Output:
--------------------------------------------------------------------------------------
Tensor("gradients/Pow_grad/Reshape:0", shape=(), dtype=float32, device=/device:CPU:0)
[<tf.Tensor 'gradients_2/gradients_1/gradients/Pow_grad/Pow_grad/Pow_grad/Reshape:0' shape=() dtype=float32>]
[0.0]
---------------------------------------------------------------------------------------
原链接:
tf.gradients | TensorFlow Core v2.7.0
https://tensorflow.google.cn/versions/r1.11/api_docs/python/tf/stop_gradient?hl=en