提问人:Jane Sully 提问时间:8/2/2021 最后编辑:Jane Sully 更新时间:8/3/2021 访问量:1368
tf。GradientTape 返回 None 表示渐变
tf.GradientTape returns None for gradient
问:
我正在使用 tf。GradientTape().gradient() 来计算表示器点,该点可用于计算给定训练样本对给定测试样本的“影响”。给定测试示例和训练示例的表示点计算为其特征表示的点积,并且 乘以权重。x_t
x_i
f_t
f_i
alpha_i
注意:此方法的细节对于理解问题不是必需的,因为主要问题是让渐变磁带工作。话虽如此,我为任何感兴趣的人提供了下面一些细节的屏幕截图。
计算alpha_i需要微分,因为它表示如下:
在上面的等式中,L 是标准损失函数(多类分类的分类交叉熵),phi 是 softmax 激活前的输出(因此它的长度是类数)。此外,还可以进一步分解为 ,它是相对于特定类计算的。因此,我们只得到与测试样本的预测类(具有最高最终预测的类)对应的 pre-softmax 输出。alpha_i
alpha_ij
j
phi_j
我使用MNIST创建了一个简单的设置,并实现了以下内容:
def simple_mnist_cnn(input_shape = (28,28,1)):
input = Input(shape=input_shape)
x = layers.Conv2D(32, kernel_size=(3, 3), activation="relu")(input)
x = layers.MaxPooling2D(pool_size=(2, 2))(x)
x = layers.Conv2D(64, kernel_size=(3, 3), activation="relu")(x)
x = layers.MaxPooling2D(pool_size=(2, 2))(x)
x = layers.Flatten()(x) # feature representation
output = layers.Dense(num_classes, activation=None)(x) # presoftmax activation output
activation = layers.Activation(activation='softmax')(output) # final output with activation
model = tf.keras.Model(input, [x, output, activation], name="mnist_model")
return model
现在假设模型已经训练完毕,我想计算给定训练示例对给定测试示例预测的影响,可能是为了模型理解/调试目的。
with tf.GradientTape() as t1:
f_t, _, pred_t = model(x_t) # get features for misclassified example
f_i, presoftmax_i, pred_i = model(x_i)
# compute dot product of feature representations for x_t and x_i
dotps = tf.reduce_sum(
tf.multiply(f_t, f_i))
# get presoftmax output corresponding to highest predicted class of x_t
phi_ij = presoftmax_i[:,np.argmax(pred_t)]
# y_i is actual label for x_i
cl_loss_i = tf.keras.losses.categorical_crossentropy(pred_i, y_i)
alpha_ij = t1.gradient(cl_loss_i, phi_ij)
# note: alpha_ij returns None currently
k_ij = tf.reduce_sum(tf.multiply(alpha_i, dotps))
上面的代码给出了以下错误,因为 alpha_ij 是 None: 。但是,如果我更改 -> ,它不再返回 None。不知道为什么会这样?在切片张量上计算梯度是否存在问题?“观察”太多变量有问题吗?我没有使用过梯度胶带,所以我不确定修复方法是什么,但希望得到帮助。ValueError: Attempt to convert a value (None) with an unsupported type (<class 'NoneType'>) to a Tensor.
t1.gradient(cl_loss_i, phi_ij)
t1.gradient(cl_loss_i, presoftmax_i)
答:
我从来没有见过你任何张量。请注意,默认情况下,磁带仅进行跟踪。您的代码中是否缺少此内容?否则我看不出是如何工作的。watch
tf.Variable
t1.gradient(cl_loss_i, presoftmax_i)
无论哪种方式,我认为解决它的最简单方法是这样做
all_gradients = t1.gradient(cl_loss_i, presoftmax_i)
desired_gradients = all_gradients[[:,np.argmax(pred_t)]]
因此,只需在渐变之后进行索引即可。请注意,这可能会造成浪费(如果有很多类),因为您计算的梯度比您需要的要多。
为什么(我相信)你的版本不起作用的解释最容易在图中显示,但让我试着解释一下:想象一下有向图中的计算。我们有
presoftmax_i -> pred_i -> cl_loss_i
将损失反向传播到 presoftmax 很容易。但后来你又建立了另一个分支,
presoftmax_i -> presoftmax_ij
现在,当您尝试计算损失相对于 的梯度时,实际上没有反向传播路径(我们只能向后跟随箭头)。另一种思考方式是:你在计算损失后进行计算。那么损失怎么可能取决于它呢?presoftmax_ij
presoftmax_ij
评论
watch
[:,:]
i
_ij
_ij
_ij
评论
np.argmax(pred_t)