声明:
在tensorflow中,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)
先不给出参数的意义~
对求导函数而言,其主要功能即求导公式: ∂ y ∂ x \frac {\partial y}{\partial x} ∂x∂y。在tensorflow中, y y y和 x x x都是tensor。
更进一步,tf.gradients()
接受求导值ys
和xs
不仅可以是tensor,还可以是list,形如[tensor1, tensor2, …, tensorn]。当ys
和xs
都是list时,它们的求导关系为:
gradients()
adds ops to the graph to output the derivatives ofys
with respect toxs
. It returns a list ofTensor
of lengthlen(xs)
where each tensor is thesum(dy/dx)
for y inys
.
意思是:
tf.gradients()
实现ys
对xs
求导len(xs)
ys
=[y1, y2],xs
=[x1, x2, x3]。则,真实的计算过程为:
以线性回归为例,实践tf.gradients()
的基础功能。线性回归: y = 3 × x + 2 y = 3 \times x + 2 y=3×x+2
import numpy as np
import tensorflow as tf
sess = tf.Session()
x_input = tf.placeholder(tf.float32, name='x_input')
y_input = tf.placeholder(tf.float32, name='y_input')
w = tf.Variable(2.0, name='weight')
b = tf.Variable(1.0, name='biases')
y = tf.add(tf.multiply(x_input, w), b)
loss_op = tf.reduce_sum(tf.pow(y_input - y, 2)) / (2 * 32)
train_op = tf.train.GradientDescentOptimizer(0.01).minimize(loss_op)
gradients_node = tf.gradients(loss_op, w)
print(gradients_node)
'''tensorboard'''
# tf.summary.scalar('norm_grads', gradients_node)
# tf.summary.histogram('norm_grads', gradients_node)
# merged = tf.summary.merge_all()
# writer = tf.summary.FileWriter('log')
init = tf.global_variables_initializer()
sess.run(init)
'''构造数据集'''
x_pure = np.random.randint(-10, 100, 32)
x_train = x_pure + np.random.randn(32) / 10 # 为x加噪声
y_train = 3 * x_pure + 2 + np.random.randn(32) / 10 # 为y加噪声
for i in range(20):
_, gradients, loss = sess.run([train_op, gradients_node, loss_op],
feed_dict={x_input: x_train[i], y_input: y_train[i]})
print("epoch: {} \t loss: {} \t gradients: {}".format(i, loss, gradients))
sess.close()
输出:
epoch: 0 loss: 94.6083221436 gradients: [-187.66052]
epoch: 1 loss: 1.52120530605 gradients: [3.0984864]
epoch: 2 loss: 101.41834259 gradients: [241.91911]
...
epoch: 18 loss: 0.0215022582561 gradients: [-0.44370675]
epoch: 19 loss: 0.0189439821988 gradients: [-0.31349587]
可以看到梯度逐渐减小,说明模型逐渐收敛。同时也可以看到参数更新的方向主要是梯度下降的方向(尽管伴随着震荡)。
其他参数都不太常用(其实是比较难用)。
grad_ys
也是一个list,其长度等于len(ys)
。这个参数的意义在于对xs
中的每个元素的求导加权种。
假设grad_ys
=[grad_ys1, grad_ys2, grad_ys3],xs
=[x1, x2, x3],则list中每个元素,如grad_ys1的shape与xs
的shape相同。
举个简单的例子:
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 = 3 * w1 + 2 * w2+ w3
z2 = -1 * w3 + w4
grads = tf.gradients([z1, z2], [w1, w2, w3, w4], grad_ys=[[-2.0, -3.0, -4.0], [-2.0, -3.0, -4.0]])
with tf.Session() as sess:
tf.global_variables_initializer().run()
print(sess.run(grads))
如果不考虑参数grad_ys
,输出应该是:
[array([ 3., 3., 3.], dtype=float32),
array([ 2., 2., 2.], dtype=float32),
array([ 0., 0., 0.], dtype=float32),
array([ 1., 1., 1.], dtype=float32)]
现在在权重参数grad_ys = [[-2.0, -3.0, -4.0], [-2.0, -3.0, -4.0]]
的加权下,输出实际为:
[array([ -6., -9., -12.], dtype=float32),
array([-4., -6., -8.], dtype=float32),
array([0., 0., 0.], dtype=float32),
array([-2., -3., -4.], dtype=float32)]
stop_gradients
也是一个list,list中的元素是tensorflow graph中的op,一旦进入这个list,将不会被计算梯度,更重要的是,在该op之后的BP计算都不会运行。
例如:
a = tf.constant(0.)
b = 2 * a
c = a + b
g = tf.gradients(c, [a, b])
计算得g = [3.0, 1.0]。因为 ∂ c ∂ a = ∂ a ∂ a + ∂ b ∂ a = 3.0 \frac {\partial c}{\partial a} = \frac {\partial a}{\partial a} + \frac {\partial b}{\partial a} =3.0 ∂a∂c=∂a∂a+∂a∂b=3.0
但如果冻结operator a和b的梯度计算:
a = tf.constant(0.)
b = 2 * a
g = tf.gradients(a + b, [a, b], stop_gradients=[a, b])
计算得g=[1.0, 1.0]。
上面的代码也等效于:
a = tf.stop_gradient(tf.constant(0.))
b = tf.stop_gradient(2 * a)
g = tf.gradients(a + b, [a, b])