3

我有兴趣计算损失的梯度,该梯度是根据 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作为变量,因为在更大的方案中,两者都是动态更新的,据我所知,最好将这些东西保留为变量,而不是不断地重新分配张量。

4

1 回答 1

1

我会尽我所能解释。问题出现在这一行

de_dm = tape.gradient(loss, multipliers_net)

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

multipliers_net.assign(LEARNING_RATE * de_dm)

这出于同样的原因。似乎只接受eager_tensors 希望这有帮助

于 2019-03-15T23:17:22.257 回答