基于迁移学习ResNet50实现类激活图及计算图断开问题求解
访问ResNet50内部层的方法
你可以直接通过model.layers[0]获取封装在Sequential内的ResNet50 functional对象,之后通过两种方式访问内部层:
- 按索引访问:
model.layers[0].layers[index] - 更稳定的按名称访问:
model.layers[0].get_layer('层名'),ResNet50内置的全局平均池化层名称为avg_pool,最后一个卷积层的名称为conv5_block3_out,不会随TensorFlow版本变化出现索引偏移问题。
计算图断开问题的解决方案
你报错的核心原因是直接引用了ResNet50内部的输入层作为CAM模型的输入,该输入节点和你外层Sequential模型的输入节点是相互独立的,没有建立张量连接,因此计算图判定为链路断开。
正确的构建方式是直接复用你训练好的整个模型的输入作为CAM模型的输入,代码如下:
import tensorflow as tf import numpy as np # 提取目标层 last_conv_layer = model.layers[0].get_layer('conv5_block3_out') final_dense_layer = model.layers[1] # 构建CAM模型,输入直接用外层模型的输入 cam_model = tf.keras.Model( inputs=model.input, outputs=[last_conv_layer.output, final_dense_layer.output] )
类激活图计算示例
你可以用以下代码生成对应类别的激活图:
def generate_cam(preprocessed_img, target_class_idx): # preprocessed_img为预处理后的输入,shape为(1, 180, 180, 3) conv_feature_map, pred = cam_model.predict(preprocessed_img, verbose=0) conv_feature_map = conv_feature_map[0] # 获取对应类别的全连接层权重 dense_weights = final_dense_layer.get_weights()[0] class_weights = dense_weights[:, target_class_idx] # 加权求和生成CAM cam = np.zeros(conv_feature_map.shape[:2], dtype=np.float32) for channel_idx, weight in enumerate(class_weights): cam += weight * conv_feature_map[:, :, channel_idx] # 归一化到0-1区间 cam = (cam - cam.min()) / (cam.max() - cam.min()) return cam
内容的提问来源于stack exchange,提问作者akilesh raj
相关产品推荐
相关产品推荐

