tf.gradients()和tf.stop_gradient()

参考 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 between x and y 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

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wanderer001

ROIAlign原理

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值