运行《Python深度学习》配套代码生成异常热力图:问题源于Google Colab还是代码错误?
问题排查:不是Colab的问题,是模型结构不匹配导致的
我帮你仔细梳理了代码,发现问题完全不是Google Colab平台的问题,而是你选用的模型和原书《Python深度学习》里的示例模型结构差异极大,导致热力图生成逻辑失效。具体来说:
核心问题:Keras Hub封装模型 vs 原书原生模型
原书第十章用的是Keras内置的keras.applications.xception.Xception模型,但你用的是keras_hub.models.ImageClassifier.from_preset("xception_41_imagenet")——这是Keras Hub封装好的高级分类器,它的内部层命名、分类器结构和原生Xception完全不一样:
- 你指定的
block14_sepconv2_act是原生Xception的最后卷积层名称,但Keras Hub的Xception backbone里的层名可能是其他命名(比如block14_sepconv2_activation),直接调用会导致逻辑错误 - 代码里遍历的
pooler、predictions层是Keras Hub封装的组件,和原书里原生Xception的avg_pool+全连接层的分类逻辑完全不同,梯度计算自然会出错
另外还有一个小问题:你没有对输入图片做Xception要求的预处理(归一化、尺寸调整),这也会干扰模型的预测和梯度计算结果。
修正后的代码(和原书逻辑完全对齐)
把模型替换成原书用的原生Xception,加上正确的预处理,就能生成符合预期的热力图:
import keras import numpy as np import matplotlib.pyplot as plt import tensorflow as tf from tensorflow.keras import ops # 加载图片并做Xception要求的预处理 img_path = keras.utils.get_file( fname="elephant.jpg", origin="https://img-datasets.s3.amazonaws.com/elephant.jpg", ) # Xception要求输入尺寸为299x299 img = keras.utils.load_img(img_path, target_size=(299, 299)) img_array = keras.utils.img_to_array(img) img_array = np.expand_dims(img_array, axis=0) # 应用Xception专属的预处理 img_array = keras.applications.xception.preprocess_input(img_array) # 使用原书的原生Xception模型(带ImageNet权重) model = keras.applications.xception.Xception(weights="imagenet") # 查看预测结果(验证模型正常工作) preds = model.predict(img_array) print("Top 3预测结果:", keras.applications.xception.decode_predictions(preds, top=3)[0]) # 原书的最后卷积层名称,原生Xception确实是block14_sepconv2_act last_conv_layer_name = "block14_sepconv2_act" last_conv_layer = model.get_layer(last_conv_layer_name) last_conv_layer_model = keras.Model(model.inputs, last_conv_layer.output) # 重构分类器部分,匹配原生Xception的结构 classifier_input = keras.Input(shape=last_conv_layer.output.shape[1:]) x = model.get_layer("avg_pool")(classifier_input) # 原生Xception的全局平均池化层 x = model.get_layer("predictions")(x) # 原生Xception的全连接预测层 classifier_model = keras.Model(classifier_input, x) def get_top_class_gradients(img_array): last_conv_layer_output = last_conv_layer_model(img_array) with tf.GradientTape() as tape: tape.watch(last_conv_layer_output) preds = classifier_model(last_conv_layer_output) top_pred_index = ops.argmax(preds[0]) top_class_channel = preds[:, top_pred_index] grads = tape.gradient(top_class_channel, last_conv_layer_output) return grads, last_conv_layer_output grads, last_conv_layer_output = get_top_class_gradients(img_array) grads = ops.convert_to_numpy(grads) last_conv_layer_output = ops.convert_to_numpy(last_conv_layer_output) # 计算权重并生成热力图 pooled_grads = np.mean(grads, axis=(0, 1, 2)) last_conv_layer_output = last_conv_layer_output[0].copy() for i in range(pooled_grads.shape[-1]): last_conv_layer_output[:, :, i] *= pooled_grads[i] heatmap = np.mean(last_conv_layer_output, axis=-1) heatmap = np.maximum(heatmap, 0) heatmap /= np.max(heatmap) # 显示热力图 plt.matshow(heatmap) plt.show()
修正点说明
- 替换成
keras.applications.xception.Xception,和原书模型结构完全一致 - 添加了Xception要求的输入尺寸调整(299x299)和专属预处理
- 重构了分类器部分,匹配原生Xception的
avg_pool和predictions层 - 运行这段代码后,生成的热力图会聚焦在大象的身体区域,和原书预期结果一致
内容的提问来源于stack exchange,提问作者HMPtwo
相关产品推荐
相关产品推荐

