tf.gradients、tf.compute_gradients和tf.stop_gradient

import tensorflow as tf

w = tf.Variable([2., 5.])
# u = tf.Variable([7., 9.])
y = 2 * w
x = 2 * y
z = 2 * x
stop_y = tf.stop_gradient(y)
stop_x = 2 * stop_y
grad1 = tf.gradients(y, w)
grad2 = tf.gradients(x, y)
grad3 = tf.gradients(z, x)
grad4 = tf.gradients(x, w)
grad5 = tf.gradients(z, y)
grad6 = tf.gradients(z, w)
z = 2 * z
grad7 = tf.gradients(z, x)
grad8 = tf.gradients(z, w)
init = tf.global_variables_initializer()
optimizer = tf.train.AdamOptimizer(0.1)
gvs = optimizer.compute_gradients(z)
gvs2 = optimizer.compute_gradients(x)
gvs3 = optimizer.compute_gradients(y)
# gv5 = optimizer.compute_gradients(z, w)
# gvs6 = optimizer.compute_gradients(x, w)
# gvs7 = optimizer.compute_gradients(y, w)
gvs4 = optimizer.compute_gradients(stop_x,stop_y)
# gvs8 = optimizer.compute_gradients(stop_x)
with tf.Session() as sess:
    sess.run(init)
    print('grad1~~~~~~~~~~~~~')
    print(sess.run(grad1))
    print('grad2~~~~~~~~~~~~~')
    print(sess.run(grad2))
    print('grad3~~~~~~~~~~~~~')
    print(sess.run(grad3))
    print('grad4~~~~~~~~~~~~~')
    print(sess.run(grad4))
    print('grad5~~~~~~~~~~~~~')
    print(sess.run(grad5))
    print('grad6~~~~~~~~~~~~~')
    print(sess.run(grad6))
    print('grad7~~~~~~~~~~~~~')
    print(sess.run(grad7))
    print('grad8~~~~~~~~~~~~~')
    print(sess.run(grad8))
    print('grad9~~~~~~~~~~~~~')
    print(sess.run(gvs))
    print(sess.run(gvs2))
    print(sess.run(gvs3))
    print(sess.run(gvs4))

tf.gradients

def gradients(ys,             
          xs,
          grad_ys=None,
          name="gradients",
          colocate_gradients_with_ops=False,
          gate_gradients=False,
          aggregation_method=None,
          stop_gradients=None,
          unconnected_gradients=UnconnectedGradients.NONE)

tf.gradients接收两个位置参数xs和ys,xs和ys是tensor或者tensor列表,返回值是tensor列表。
不论xs是tensor还是tensor列表,都会被当成tensor列表,ys对列表中的每一项求出一个导数,所有导数得到一个新的列表作为返回值。
因为tf.gradients必须传入xs和ys,所以ys的求导必然是针对xs的,而不会根据链式求导法则,一直反向传播到最前面。在使用了stop_gradient时,传给xs的值必须是tf.stop_gradient的节点或者之后的节点,如果是tf.stop_gradient之前的节点则由于stop_gradient的节点被当做了常数,tf.gradients会返回[None]。

tf.compute_gradients

def compute_gradients(self, loss, var_list=None,
                    gate_gradients=GATE_OP,
                    aggregation_method=None,
                    colocate_gradients_with_ops=False,
                    grad_loss=None)
                   	Args:
loss: A Tensor containing the value to minimize or a callable taking
    no arguments which returns the value to minimize. When eager execution
    is enabled it must be a callable.
var_list: Optional list or tuple of `tf.Variable` to update to minimize
    `loss`.  Defaults to the list of variables collected in the graph
    under the key `GraphKeys.TRAINABLE_VARIABLES`.
Returns:
    A list of (gradient, variable) pairs. Variable is always present, but
    gradient can be `None`.

查看optimizer.minimize()的源码可以得知其分两步,第一步就是tf.compute_gradients,第二步是应用所求得的梯度,optimizer.apply_gradients(gvs),因为gvs是梯度和更新变量一一对应的元组列表,所以可以通过apply直接将梯度应用到要更新的变量。
与tf.gradients不同,tf.compute_gradients可以只传入要求导的函数ys即loss,求导变量var_list可以选择传入也可以由tf去收集。返回值是梯度和该梯度要更新的参数组成的元组的列表。
var_list最好还是手动传入,如果自动收集,会收集到不需要的变量,导致返回值为[None],例如当上面的程序加入u后,即使u与z无关,但是由于u被收集到,gvs、gvs2、gvs3处仍然会返回[None],但是如果将其改为gvs5、gvs6、gvs7,那么即使程序中定义了u,程序也会正常运行。
当compute_gradients接收了loss和var_list时,loss会根据接收的var_list进行求导;当compute_gradients只接收一个参数时,那么loss会根据链式求导法则,一直反向求导,直到w,这个时候stop_gradient就可以派上用场了。

import tensorflow as tf

w = tf.Variable([2., 5.])
u = tf.Variable([7., 9.])

x = 2 * w + 3 * u
with tf.Session() as sess:
    tf.global_variables_initializer().run()
    optimizer = tf.train.AdamOptimizer(0.1)
    gvs = optimizer.compute_gradients(x)
    print(sess.run(gvs))
[(array([2., 2.], dtype=float32), array([2., 5.], dtype=float32)), (array([3., 3.], dtype=float32), array([7., 9.], dtype=float32))]

tf.stop_gradient

tf.stop_gradient(y)并不是将节点y做了修改,而是产生了一个与原节点同时存在的新节点,可以认为得到新节点的计算过程与得到原节点的计算过程是相同的,只是新节点会将反向的链式求导阻塞。即compute_graident只传入一个参数loss时,会自动反向链式求导,但是stop_gradient的节点会被当做常数,继续反向求导会得到导数为None,使compute_graident最终返回的结果为None。与tf.gradients相同,当compute_graident传入var_list时,必须传入stop_gradient节点或者之后的节点,如果传入之前的节点,会导致返回值为[None]。

import tensorflow as tf

w = tf.Variable([2., 5.],name='weights')
y = 2 * w
stop_y = tf.stop_gradient(y)
stop_x = 2 * stop_y
init = tf.global_variables_initializer()
optimizer = tf.train.AdamOptimizer(0.1)

gvs4 = optimizer.compute_gradients(stop_x)

with tf.Session() as sess:
    sess.run(init)
    print(gvs4)
[(None, <tf.Variable 'weights:0' shape=(2,) dtype=float32_ref>)]
发布了12 篇原创文章 · 获赞 5 · 访问量 947

猜你喜欢

转载自blog.csdn.net/Seventeen0084/article/details/102553221
tf
今日推荐