【问题标题】:The activation in my CNN does not look correct - or is the heatmap the problem?我的 CNN 中的激活看起来不正确 - 还是热图有问题?
【发布时间】:2019-10-21 23:56:43
【问题描述】:

我正在为我通过 Keras 制作的卷积神经网络制作热图,as described here。当我为 vanilla VGG16 网络运行该算法时,热图看起来不错:

然后我创建了自己的自定义模型,基于 VGG16 网络,但具有自定义顶层:

input_layer = layers.Input(shape=(img_size, img_size, 3), name="model_input")
vgg16_base = VGG16(weights="imagenet", include_top=False, input_tensor=input_layer)
temp_model = vgg16_base.output
temp_model = layers.Flatten()(temp_model)
temp_model = layers.Dense(256, activation="relu")(temp_model)
temp_model = layers.Dense(1, activation="sigmoid")(temp_model)
custom = models.Model(inputs=input_layer, outputs=temp_model)

但是,当我为我自己的自定义网络的同一层(即来自VGG16 基础的最后一个转换层,是我的新网络的一部分)生成热图时,使用完全相同的代码/函数,热图看起来不对:

我的自定义网络的验证/测试准确度为 97-98%,所以我认为它工作正常。那么激活/热图怎么会如此关闭呢?还是我在这里错过了其他东西?

PS:供您参考,热图是通过function listed here 创建的。它是这样调用的:

# Load the image from disk and preprocess it via Keras tools
img_path = "/path/to/image.jpg"
img = image.load_img(img_path, target_size=(224, 224))
img_tensor = image.img_to_array(img)
img_tensor = np.expand_dims(img_tensor, axis=0)
img_tensor = preprocess_input(img_tensor)

# At this point I either load the VGG16 model directly (heatmapü works),
# or I create my own custom VGG16-based model (heatmap does not work)
# The model itself is then stored into the variable "model"

preds = model.predict(img_tensor)
model_prediction = model.output[:, np.argmax(preds[0])]

# Then I call the custom function referred to above
input_layer = model.get_layer("model_input")
conv_layer = model.get_layer("block5_conv3")
plot_conv_heat_map(model_prediction, input_layer, conv_layer, img_tensor, img_path)

【问题讨论】:

  • 你能分享你所有的代码吗?
  • @Priyatham 当然,我添加了更多代码,包括。一个指向我用来生成热图的函数的链接到我的帖子底部。
  • 在您的自定义模型中,您似乎在进行二进制分类,对吧?如果是这样,那么你认为猫的真正标签是0还是1?
  • @today 确实如此,如上所述,我已经在 VGG16 基础之上添加了 Dense 层; CAT 导致 0,DOG 导致 1。
  • 好吧,既然是猫图片,那你可以试试1 - model_prediction,即plot_conv_heat_map(1 - model_prediction, ...)吗?

标签: python machine-learning keras conv-neural-network heatmap


【解决方案1】:

简答:由于您在训练阶段已将狗标记为 1,将猫标记为 0,因此您需要将 model_prediction 替换为 1 - model_prediction 以查找与猫相关的区域:

plot_conv_heat_map(1 - model_prediction, ...)

长答案:当您使用原始 VGG 模型时,最后一层有 1000 个神经元(假设您使用的是预训练的 ImageNet 模型),1000 个不同类别中的每一个都有一个:

# last layer in VGG model
x = layers.Dense(classes, activation='softmax', name='predictions')(x)

每个神经元都有一个从零到一的输出值(条件是输出之和必须为 1)。因此,最活跃的神经元(即输出最高的神经元)对应于预测的类别。所以你会发现它是这样的:

model_prediction = model.output[:, np.argmax(preds[0])]
                                        \
                                         \___ finds the index of the neuron with maximum output

然后将其传递给可视化函数以计算其相对于所选卷积层的梯度并可视化热图:

plot_conv_heat_map(model_prediction, ...)

到目前为止,一切都很好。但是,在您的自定义模型中,您已将问题从多类分类任务转换为二元分类任务,即狗与猫。您正在使用具有单个单元的 sigmoid 层作为最后一层,并将神经元的活动状态(即接近 1 的输出)视为狗,将神经元的非活动状态(即接近 0 的输出)视为猫。所以你的网络本质上是一个狗检测器,如果没有狗,那么我们假设图像中有一只猫。

好吧,你可能会问“这有什么问题?”答案是模型的训练没有问题,而且正如你所建议的,你得到了很好的训练准确性。但是,请记住可视化函数背后的假设:它将具有最高输出的神经元作为输入,该神经元对应于图像中检测到的类别。因此,给您的自定义模型一个猫图像,最后一层的输出将是一个非常低的数字,例如 0.01。所以对这个数字的一​​种解释是,这张图片是狗的概率是 0.01。那么当你将它直接提供给你的可视化函数时会发生什么?是的,你猜对了:它会找到图像中与狗最相关的所有区域!你可能仍然反对“但我给了它一个猫的形象!!!”没关系,因为当狗出现时该神经元会激活,因此当您获取其相对于卷积层的梯度时,与狗最相关的区域将在热图中得到高度表示和显示。但是,如果您给模型一个狗图像,可视化将是正确的。

“那么当我们想要可视化与猫最相关的区域时应该怎么做?”这很简单:只需将该神经元设为猫探测器即可。 “如何?”只需创建它的补充:1 - model_prediction。这为您提供了图像中出现猫的概率。您可以像这样轻松地使用它来绘制图像中与猫相关的区域:

plot_conv_heat_map(1 - model_prediction, ...)

或者,您可以将模型的最后一层更改为具有 2 个具有 softmax 激活的神经元,然后重新训练它:

temp_model = layers.Dense(2, activation="softmax")(temp_model)

这样每个类,即狗和猫,都有自己的神经元,因此在可视化激活热图时不会出现问题。

【讨论】:

  • 哇,这个答案很好。非常感谢你,你真的应该得到赏金!
  • 你是最棒的,(拥抱大哥),你确实值得十个赏金。
猜你喜欢
  • 2011-07-24
  • 2012-01-30
  • 1970-01-01
  • 1970-01-01
  • 2023-03-18
  • 2021-12-11
  • 1970-01-01
  • 2020-10-03
  • 2021-06-10
相关资源
最近更新 更多