2

是否可以部分使用 TensorFlow 的tf.gradients()函数,即 - 从某个张量的损失和该张量的权重计算梯度,然后将它们相乘以获得从损失到权重的原始梯度?

例如,设W,b一些权重,设x一个网络的输入,设y0表示标签。

假设一个前向图,例如

h=Wx+b
y=tanh(h)
loss=mse(y-y0)

我们可以计算tf.gradients(loss,W)然后应用(跳过一些细节)optimizer.apply_gradients()来更新W

然后我尝试使用 提取中间张量,var=tf.get_default_graph().get_tensor_by_name(...)然后计算两个梯度:g1=tf.gradients(loss,var)g2=tf.gradients(var,W)。然后,根据链式法则,我会期望 和 的维度能够计算g1出来g2,以便我可以g=g1*g2在某种意义上写作,然后返回tf.gradients(loss,W)

不幸的是,这种情况并非如此。尺寸不正确。每个渐变的维度都是“wrt 变量”的维度,因此第一个渐变和第二个渐变之间没有对应关系。我错过了什么,我该怎么做?

谢谢。

4

3 回答 3

1

tf.gradients将对输入张量的梯度求和。为避免这种情况,您必须将张量拆分为标量并应用于tf.gradients每个标量:

import tensorflow as tf

x = tf.ones([1, 10])

w = tf.get_variable("w", initializer=tf.constant(0.5, shape=[10, 5]))
out = tf.matmul(x, w)
out_target = tf.constant(0., shape=[5])

loss = tf.reduce_mean(tf.square(out - out_target))

grad = tf.gradients(loss, x)

part_grad_1 = tf.gradients(loss, out)
part_grad_2 = tf.concat([tf.gradients(i, x) for i in tf.split(out, 5, axis=1)], axis=1)

grad_by_parts = tf.matmul(part_grad_1, part_grad_2)

init = tf.global_variables_initializer()

with tf.Session() as sess:
    sess.run(init)
    print(sess.run([grad]))
    print(sess.run([grad_by_parts]))
于 2018-04-28T19:32:44.140 回答
0

来自文档tf.gradients(强调我的)

在 xs 中构造 ys 与 x 之和的符号导数.

如果ys在多维中存在任何张量,则reduce_sum在对标量的结果列表本身求和之前对其进行求和,然后再进行微分。这就是为什么输出梯度与xs.

这也解释了为什么损失在张量流中可以是多维的:它们在微分之前被隐含地求和。

于 2018-04-28T19:26:55.460 回答
0

对于未来的读者:

Tensorflow 已经取得了一些进步,对于 tf2.7(甚至可能是更早的版本),您可以使用 tf.GradientTape.jacobian 来避免总和超过目标的尺寸

https://www.tensorflow.org/guide/advanced_autodiff#jacobians

于 2021-11-23T08:55:01.513 回答