实现GradCam时Gradients为None



我正试图为tensorflow 2.0模型(使用keras api创建(实现grad-cam,但从磁带返回的渐变始终为None。

我正在遵循上给出的示例https://keras.io/examples/vision/grad_cam/.

我的模型相当简单,但为了调试,我把它换成了tf.keras.applications提供的内置Xception模型(行为没有差异,所以问题一定出在我的代码上(。

# model (not shown here) is Xception from tf.keras.applications
cam_model = tf.keras.models.Model(
[model.inputs],
[model.get_layer(conv_layer_name).output, model.output] # conv_layer_name = 'block14_sepconv2_act'
)
with tf.GradientTape() as tape:
conv_out, predictions = cam_model(image)
class_out = tf.argmax(predictions, axis=-1)
grads = tape.gradient(class_out, conv_out)
if grads is None: # grads is None
raise Exception("Grad cam has recorded no gradient")

这很简单,我不明白为什么梯度是None。我怀疑磁带可能没有录音,但考虑到colabhttps://colab.research.google.com/github/keras-team/keras-io/blob/master/examples/vision/ipynb/grad_cam.ipynb似乎什么都不需要。

有一个相关的问题,但卷积层是不正确的,而这里它确实是正确的层。

编辑

因此,在Xception的情况下,argmax是有问题的,但修复它(例如直接使用预测(对我的模型不起作用。这是型号定义代码:

backbone = VGG16(
include_top=False,
weights='imagenet',
input_shape=(*size, 3),
pooling='max'
)
backbone.trainable = False
net = Sequential()
for layer in backbone.layers:
net.add(layer)
net.add(Flatten())
net.add(Dense(256, activation='relu'))
net.add(Dense(128, activation='relu'))
net.add(Dense(len(CLASSES), activation='softmax'))

这是在tensorflow 2.8.0中,在GPU上。

与@AloneTogether一样,argmax的结果是不可微的,因此应用tape.gradients(...)后的None结果是正常的,因为无法计算梯度。

虽然argmax的结果无法区分,但可以通过以下方式选择正确的激活:

class_pred = tf.argmax(predictions, axis=-1)
class_out = predictions[:, class_pred]

这解决了这个问题(通过使用Xception(。

另一个问题,使用我的完整模型,是在尝试访问VGG16的内层时出现断开连接图错误。通过使用VGG16的输入作为模型的第一层,并使用VGG116的输出作为下一个可用层(使用功能性的API(,我能够以一种有点不令人满意的方式解决这个问题:

x = vgg16.output
x = Flatten()(x)
...
return Model(vgg16.input, x)

网络的图形将被完全扩展,这意味着你将不会有";vgg";块,但VGG的所有层都展开。我认为有可能有一个非展开的版本,但我无法实现。这个答案暗示了这是可能的:带有迁移学习的自定义模型上的热图

最新更新