You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在TensorFlow的ResNet152V2图像分类模型中实现Grad-CAM以查看激活图/热力图

如何在TensorFlow的ResNet152V2图像分类模型中实现Grad-CAM以查看激活图/热力图

嘿,看起来你已经在基于ResNet152V2的自闭症/非自闭症图像分类项目上取得了不错的进展!想要给你的模型加上Grad-CAM来可视化模型关注的核心区域,这绝对是个能帮你直观理解模型决策逻辑的好想法。我会把实现步骤拆解开来,直接整合到你现有的Train-Predict.py脚本里,你可以照着调整:

第一步:明确Grad-CAM需要用到的模型层

Grad-CAM的核心是利用模型最后一个卷积层的激活输出,结合预测类别的梯度来生成热力图。对于ResNet152V2来说,它的最后一个卷积层默认名称是conv5_block3_out,你可以通过model.summary()输出模型结构来确认这个名称。

第二步:添加Grad-CAM核心函数

在你的脚本导入库的代码之后,或者训练/预测逻辑之前,加入下面这两个核心函数:

def grad_cam(model, img_array, last_conv_layer_name="conv5_block3_out", pred_index=None):
    # 构建能同时输出最后卷积层激活和模型预测结果的新模型
    grad_model = tf.keras.models.Model(
        [model.inputs], [model.get_layer(last_conv_layer_name).output, model.output]
    )

    # 用GradientTape记录梯度信息
    with tf.GradientTape() as tape:
        last_conv_layer_output, preds = grad_model(img_array)
        if pred_index is None:
            pred_index = tf.argmax(preds[0])
        class_channel = preds[:, pred_index]

    # 计算目标类别相对于最后卷积层的梯度
    grads = tape.gradient(class_channel, last_conv_layer_output)
    # 对梯度做全局平均池化,得到每个通道的权重
    pooled_grads = tf.reduce_mean(grads, axis=(0, 1, 2))

    # 用权重加权卷积层输出,生成原始热力图
    last_conv_layer_output = last_conv_layer_output[0]
    heatmap = last_conv_layer_output @ pooled_grads[..., tf.newaxis]
    heatmap = tf.squeeze(heatmap)

    # 归一化热力图到0-1区间,增强可视化效果
    heatmap = tf.maximum(heatmap, 0) / tf.math.reduce_max(heatmap)
    return heatmap.numpy(), preds[0]

def overlay_heatmap(heatmap, img, alpha=0.4, colormap=cv2.COLORMAP_JET):
    # 把热力图放大到和原图一致的尺寸
    heatmap = cv2.resize(heatmap, (img.shape[1], img.shape[0]))
    # 转成RGB格式并应用颜色映射
    heatmap = np.uint8(255 * heatmap)
    heatmap = cv2.applyColorMap(heatmap, colormap)
    # 将热力图叠加到原图上
    superimposed_img = cv2.addWeighted(img, alpha, heatmap, 1 - alpha, 0)
    return superimposed_img

第三步:整合到你的预测流程中

假设你已经加载了训练好的模型(或者训练完成后),可以添加一个带Grad-CAM可视化的预测函数:

def predict_with_gradcam(model, img_path):
    # 加载并预处理测试图片
    img = cv2.imread(img_path)
    img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    img_resized = cv2.resize(img_rgb, (img_size, img_size))
    img_array = np.expand_dims(img_resized, axis=0) / 255.0  # 和训练时的归一化逻辑保持一致

    # 生成热力图和预测结果
    heatmap, preds = grad_cam(model, img_array)
    class_names = ["非自闭症", "自闭症"]  # 根据你的数据集类别调整
    pred_class = class_names[np.argmax(preds)]
    pred_confidence = np.max(preds) * 100

    # 把热力图叠加到原图上
    superimposed_img = overlay_heatmap(heatmap, img_rgb)

    # 可视化三张图:原图、热力图、叠加后的图
    plt.figure(figsize=(12, 6))
    plt.subplot(1, 3, 1)
    plt.imshow(img_rgb)
    plt.title(f"原图\n预测结果: {pred_class} ({pred_confidence:.2f}%)")
    plt.axis("off")

    plt.subplot(1, 3, 2)
    plt.imshow(heatmap, cmap="jet")
    plt.title("Grad-CAM热力图")
    plt.axis("off")

    plt.subplot(1, 3, 3)
    plt.imshow(cv2.cvtColor(superimposed_img, cv2.COLOR_BGR2RGB))
    plt.title("叠加热力图后的原图")
    plt.axis("off")

    plt.show()
    return pred_class, pred_confidence

然后在你的脚本预测逻辑部分(比如training=False时),这样调用即可:

# 加载训练好的模型(和你训练时的模型结构保持一致)
base_model = ResNet152V2(weights=None, include_top=False, input_shape=(img_size, img_size, 3))
model = Sequential([
    base_model,
    GlobalAveragePooling2D(),
    BatchNormalization(),
    Dropout(0.5),
    Dense(128, activation='relu'),
    BatchNormalization(),
    Dropout(0.5),
    Dense(2, activation='softmax')  # 二分类任务,输出单元数为2
])
model.load_weights("trained_weights.hdf5")

# 替换成你的测试图片路径,运行即可看到可视化结果
test_img_path = "path/to/your/test/image.jpg"
predict_with_gradcam(model, test_img_path)

一些小提醒

  • 确认卷积层名称:如果你的模型结构有修改,记得通过model.summary()确认最后一个卷积层的名称,替换到grad_cam函数的last_conv_layer_name参数里。
  • 预处理对齐:确保测试图片的预处理逻辑(比如归一化、尺寸调整)和训练时完全一致,否则热力图可能不准确。
  • 多分类适配:如果是多分类任务,只需要调整class_names列表和模型最后一层Dense的输出单元数即可。

这样修改后,你就能在预测时直观看到模型到底在关注图片的哪些区域,帮你验证模型的决策是否合理~

备注:内容来源于stack exchange,提问作者unknown name

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.16 09:43:07