Tensorflow无法通过变量获得梯度,但可以使用Tensor

时间:2019-03-14 05:58:24

标签: python tensorflow eager-execution

我对计算损耗的梯度感兴趣,该梯度是根据TensorFlow与Eager Execution中的矩阵乘法乘积计算得出的。如果乘积计算为张量,则可以这样做,但是如果将其assign()固定在变量中,则不能这样做。这是精巧的简化代码:

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_netmultiplier_net保留为变量,因为在较大的方案中,两者都是动态更新的,并且据我所知,最好将它们保留为变量,而不是不断地重新分配张量。

1 个答案:

答案 0 :(得分:1)

我将尽我所能解释。 该行中出现问题

de_dm = tape.gradient(loss, multipliers_net)

如果在“有问题”和“没有问题”两种情况下print(tape.watched_variables(),您都会看到在第一种情况下,磁带“监视”相同的multipliers_net变量两次。 您可以尝试tape.reset()tape.watch(),但是只要您将assign op传递给它,它就不会起作用。 如果您在multipliers_net.assign(any_variable)内尝试tf.GradientTape(),则会发现它不起作用。但是如果您尝试分配产生张量的东西,例如tf.ones_like(),它将起作用。

multipliers_net.assign(LEARNING_RATE * de_dm)

这是出于相同的原因。似乎只接受eager_tensors 希望对您有帮助