我正试图为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的所有层都展开。我认为有可能有一个非展开的版本,但我无法实现。这个答案暗示了这是可能的:带有迁移学习的自定义模型上的热图