Tensorflow 无法通过变量获取梯度,但可以通过张量获取梯度
Tensorflow cannot get gradient wrt a Variable, but can wrt a Tensor
我对计算损失的梯度很感兴趣,损失的梯度是通过使用 Eager Execution 的 TensorFlow 中的矩阵乘积计算得出的。如果乘积被计算为张量,我可以这样做,但如果它被 assign()
ed 到一个变量,我就不能这样做。这是 大大 减少的代码:
import tensorflow as tf
import numpy as np
tf.enable_eager_execution()
multipliers_net = tf.get_variable("multipliers", shape=(1, 3, 3, 1),
initializer=tf.random_normal_initializer())
activations_net = tf.Variable(tf.ones_like(multipliers_net))
output_indices = [(0, 1, 2, 0)]
def step():
global activations_net
#### PROBLEMATIC ####
activations_net.assign(multipliers_net * activations_net)
#### NO PROBLEM ####
# activations_net = multipliers_net * activations_net
return tf.gather_nd(activations_net, output_indices)
def train(targets):
for y in targets:
with tf.GradientTape() as tape:
out = step()
print("OUT", out)
loss = tf.reduce_mean(tf.square(y - out))
print("LOSS", loss)
de_dm = tape.gradient(loss, multipliers_net)
print("GRADIENT", de_dm, sep="\n")
multipliers_net.assign(LEARNING_RATE * de_dm)
targets = [[2], [3], [4], [5]]
train(targets)
就目前而言,此代码将显示正确的 OUT 和 LOSS 值,但 GRADIENT 将打印为 None。但是,如果 "PROBLEMATIC" 下面的行被注释掉而 "NO PROBLEM" 没有被注释掉,那么梯度计算就很好了。我推断这是因为在第二种情况下,activations_net
变成了张量,但我不知道为什么这突然使梯度可计算,而之前不是。
我很确定我应该保留 activations_net
和 multiplier_net
作为变量,因为在更大的方案中,两者都是动态更新的,据我所知,这样的东西是最好的保留为变量而不是不断重新分配张量。
我会尽力解释我所知道的。
问题出现在这一行
de_dm = tape.gradient(loss, multipliers_net)
如果您在 "PROBLEMATIC" 和 "NO PROBLEM" 两种情况下都 print(tape.watched_variables()
,您会看到在第一种情况下磁带 'watches' 相同的 multipliers_net
变量两次.
你可以试试tape.reset()
和tape.watch()
,但是只要你把assign op传进去就没有效果了。
如果你在 tf.GradientTape()
中尝试 multipliers_net.assign(any_variable)
,你会发现它不起作用。但是如果你尝试分配一些产生张量的东西,例如tf.ones_like()
,会起作用的。
multipliers_net.assign(LEARNING_RATE * de_dm)
这也是出于同样的原因。好像只接受eager_tensors
希望这有帮助
我对计算损失的梯度很感兴趣,损失的梯度是通过使用 Eager Execution 的 TensorFlow 中的矩阵乘积计算得出的。如果乘积被计算为张量,我可以这样做,但如果它被 assign()
ed 到一个变量,我就不能这样做。这是 大大 减少的代码:
import tensorflow as tf
import numpy as np
tf.enable_eager_execution()
multipliers_net = tf.get_variable("multipliers", shape=(1, 3, 3, 1),
initializer=tf.random_normal_initializer())
activations_net = tf.Variable(tf.ones_like(multipliers_net))
output_indices = [(0, 1, 2, 0)]
def step():
global activations_net
#### PROBLEMATIC ####
activations_net.assign(multipliers_net * activations_net)
#### NO PROBLEM ####
# activations_net = multipliers_net * activations_net
return tf.gather_nd(activations_net, output_indices)
def train(targets):
for y in targets:
with tf.GradientTape() as tape:
out = step()
print("OUT", out)
loss = tf.reduce_mean(tf.square(y - out))
print("LOSS", loss)
de_dm = tape.gradient(loss, multipliers_net)
print("GRADIENT", de_dm, sep="\n")
multipliers_net.assign(LEARNING_RATE * de_dm)
targets = [[2], [3], [4], [5]]
train(targets)
就目前而言,此代码将显示正确的 OUT 和 LOSS 值,但 GRADIENT 将打印为 None。但是,如果 "PROBLEMATIC" 下面的行被注释掉而 "NO PROBLEM" 没有被注释掉,那么梯度计算就很好了。我推断这是因为在第二种情况下,activations_net
变成了张量,但我不知道为什么这突然使梯度可计算,而之前不是。
我很确定我应该保留 activations_net
和 multiplier_net
作为变量,因为在更大的方案中,两者都是动态更新的,据我所知,这样的东西是最好的保留为变量而不是不断重新分配张量。
我会尽力解释我所知道的。 问题出现在这一行
de_dm = tape.gradient(loss, multipliers_net)
如果您在 "PROBLEMATIC" 和 "NO PROBLEM" 两种情况下都 print(tape.watched_variables()
,您会看到在第一种情况下磁带 'watches' 相同的 multipliers_net
变量两次.
你可以试试tape.reset()
和tape.watch()
,但是只要你把assign op传进去就没有效果了。
如果你在 tf.GradientTape()
中尝试 multipliers_net.assign(any_variable)
,你会发现它不起作用。但是如果你尝试分配一些产生张量的东西,例如tf.ones_like()
,会起作用的。
multipliers_net.assign(LEARNING_RATE * de_dm)
这也是出于同样的原因。好像只接受eager_tensors
希望这有帮助