tf.GradientTape returns None 渐变
tf.GradientTape returns None for gradient
我正在使用 tf.GradientTape().gradient() 来计算 representer point,它可用于计算给定训练示例对给定测试示例的“影响”。给定测试示例 x_t
和训练示例 x_i
的表示点计算为其特征表示 f_t
和 f_i
的点积,乘以权重 alpha_i
.
注意:这种方法的细节对于理解问题不是必需的,因为主要问题是让渐变带起作用。话虽如此,我已经为感兴趣的任何人提供了下面一些细节的屏幕截图。
计算alpha_i需要微分,因为它表示如下:
在上面的等式中,L 是标准损失函数(multiclass classification 的分类交叉熵)和 phi 是 softmax 之前的激活输出(所以它的长度是数字classes)。此外 alpha_i
可以进一步分解为 alpha_ij
,它是针对特定的 class j
计算的。因此,我们只获得与测试示例的预测 class 对应的 pre-softmax 输出 phi_j
(具有最高最终预测的 class)。
我使用 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
现在假设模型已经过训练,我想计算给定训练示例对给定测试示例预测的影响,也许是为了模型 understanding/debugging 目的。
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: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)
,它就不再是 returns None。不确定为什么会这样?在切片张量上计算梯度有问题吗? “观察”太多变量有问题吗?我用渐变胶带的工作不多,所以我不确定修复方法是什么,但希望得到帮助。
对于任何感兴趣的人,这里有更多详细信息:
我从未见过你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
在 计算损失之后。那损失怎么就靠它了?
我正在使用 tf.GradientTape().gradient() 来计算 representer point,它可用于计算给定训练示例对给定测试示例的“影响”。给定测试示例 x_t
和训练示例 x_i
的表示点计算为其特征表示 f_t
和 f_i
的点积,乘以权重 alpha_i
.
注意:这种方法的细节对于理解问题不是必需的,因为主要问题是让渐变带起作用。话虽如此,我已经为感兴趣的任何人提供了下面一些细节的屏幕截图。
计算alpha_i需要微分,因为它表示如下:
在上面的等式中,L 是标准损失函数(multiclass classification 的分类交叉熵)和 phi 是 softmax 之前的激活输出(所以它的长度是数字classes)。此外 alpha_i
可以进一步分解为 alpha_ij
,它是针对特定的 class j
计算的。因此,我们只获得与测试示例的预测 class 对应的 pre-softmax 输出 phi_j
(具有最高最终预测的 class)。
我使用 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
现在假设模型已经过训练,我想计算给定训练示例对给定测试示例预测的影响,也许是为了模型 understanding/debugging 目的。
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: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)
,它就不再是 returns None。不确定为什么会这样?在切片张量上计算梯度有问题吗? “观察”太多变量有问题吗?我用渐变胶带的工作不多,所以我不确定修复方法是什么,但希望得到帮助。
对于任何感兴趣的人,这里有更多详细信息:
我从未见过你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
在 计算损失之后。那损失怎么就靠它了?