在Google Colab中使用Keras Vis(GradCAM、显著性图)的问题及替代方案
解决Keras Vis依赖旧版Scipy的问题及替代方案
一、不降级Scipy,修复Keras Vis的使用
Keras Vis报错的核心是scipy.misc.imresize被弃用,无需降级Scipy,通过以下两种方法即可修复:
1. 猴子补丁(Monkey Patch)替换imresize函数
直接在代码开头添加补丁,用PIL库的resize功能替代弃用的imresize,无需修改Keras Vis源码:
# 安装依赖(Colab默认已装PIL,若未装则执行) !pip install pillow import scipy.misc from PIL import Image import numpy as np # 定义替代imresize的函数 def imresize(arr, size, interp='bilinear', mode=None): # 将numpy数组转换为PIL图像 img = Image.fromarray(arr.astype(np.uint8) if mode == 'RGB' else arr) # 调整尺寸(注意PIL的size是(width, height),和scipy的(height, width)相反) resized_img = img.resize( size[::-1], Image.Resampling.BILINEAR if interp == 'bilinear' else Image.Resampling.NEAREST ) # 转回numpy数组 return np.array(resized_img) # 替换scipy.misc.imresize scipy.misc.imresize = imresize # 现在可以正常导入并使用Keras Vis from vis.visualization import visualize_cam
2. 修改Keras Vis源码中的imresize调用
找到Keras Vis的工具类文件,替换其中的imresize依赖:
# 定位Keras Vis的utils.py文件路径 !find /usr/local/lib/python3.8/dist-packages -name "utils.py" | grep vis # 假设输出路径为/usr/local/lib/python3.8/dist-packages/vis/utils/utils.py,编辑该文件 # 1. 替换导入语句:将from scipy.misc import imresize改为 from PIL import Image import numpy as np # 2. 找到调用imresize的代码(如resized = imresize(...)),替换为: # resized = np.array(Image.fromarray(arr).resize(size[::-1], Image.Resampling.BILINEAR)) # 可以用sed命令批量替换(仅针对简单情况) !sed -i 's/from scipy.misc import imresize/from PIL import Image\nimport numpy as np/' /usr/local/lib/python3.8/dist-packages/vis/utils/utils.py !sed -i 's/imresize(\(.*\), \(.*\))/np.array(Image.fromarray(\1).resize(\2[::-1], Image.Resampling.BILINEAR))/' /usr/local/lib/python3.8/dist-packages/vis/utils/utils.py
二、替代Keras Vis的现代可视化库
由于Keras Vis已停止维护,推荐使用以下活跃维护的替代库:
1. tf-keras-vis
专为TensorFlow/Keras设计的可视化库,是Keras Vis的官方替代,支持TF 2.x,无需依赖旧版Scipy:
# 安装 !pip install tf-keras-vis # 生成GradCAM示例 from tensorflow.keras.applications.vgg16 import VGG16, preprocess_input from tensorflow.keras.preprocessing.image import load_img, img_to_array from tf_keras_vis.gradcam import Gradcam import matplotlib.pyplot as plt import numpy as np # 加载模型和图像 model = VGG16(weights='imagenet', include_top=True) img = load_img('cat.jpg', target_size=(224, 224)) x = img_to_array(img) x = np.expand_dims(x, axis=0) x = preprocess_input(x) # 定义目标损失(取预测概率最高的类别) def loss(output): return output[:, np.argmax(output[0])] # 生成并可视化GradCAM热力图 gradcam = Gradcam(model, clone=True) cam = gradcam(loss, x) plt.imshow(img) plt.imshow(cam[0], cmap='jet', alpha=0.5) plt.axis('off') plt.show()
2. Captum
PyTorch官方的可解释AI库,同时支持TensorFlow模型,提供多种归因方法(显著性图、GradCAM、Integrated Gradients等):
# 安装 !pip install captum # TensorFlow模型使用GradCAM示例 import tensorflow as tf from tensorflow.keras.applications.vgg16 import VGG16, preprocess_input from tensorflow.keras.preprocessing.image import load_img, img_to_array from captum.attr import LayerGradCam import matplotlib.pyplot as plt model = VGG16(weights='imagenet', include_top=True) img = load_img('cat.jpg', target_size=(224, 224)) x = img_to_array(img) x = np.expand_dims(x, axis=0) x = preprocess_input(x) # 选择最后一层卷积层作为目标层 target_layer = model.get_layer('block5_conv3') layer_gradcam = LayerGradCam(model, target_layer) # 计算归因(指定目标类别,例如猫的类别ID为281) attr = layer_gradcam.attribute(x, target=281) # 调整热力图尺寸并可视化 attr = tf.image.resize(attr, (224, 224)) plt.imshow(img) plt.imshow(attr[0].numpy(), cmap='jet', alpha=0.5) plt.axis('off') plt.show()
3. 手动实现GradCAM/显著性图
如果不想依赖第三方库,手动实现核心逻辑也很简单,以GradCAM为例:
import tensorflow as tf from tensorflow.keras.applications.vgg16 import VGG16, preprocess_input from tensorflow.keras.preprocessing.image import load_img, img_to_array import matplotlib.pyplot as plt import numpy as np model = VGG16(weights='imagenet', include_top=True) # 创建包含最后卷积层输出和模型预测的新模型 last_conv_layer = model.get_layer('block5_conv3') heatmap_model = tf.keras.Model([model.inputs], [last_conv_layer.output, model.output]) # 加载并预处理图像 img = load_img('cat.jpg', target_size=(224, 224)) x = img_to_array(img) x = np.expand_dims(x, axis=0) x = preprocess_input(x) # 计算梯度 with tf.GradientTape() as tape: conv_outputs, predictions = heatmap_model(x) class_idx = tf.argmax(predictions[0]) loss = predictions[:, class_idx] grads = tape.gradient(loss, conv_outputs) pooled_grads = tf.reduce_mean(grads, axis=(0, 1, 2)) # 生成热力图 conv_outputs = conv_outputs[0] heatmap = tf.matmul(conv_outputs, pooled_grads[..., tf.newaxis]) heatmap = tf.squeeze(heatmap) heatmap = tf.maximum(heatmap, 0) / tf.math.reduce_max(heatmap) # 调整尺寸并可视化 heatmap = tf.image.resize(tf.expand_dims(heatmap, axis=-1), (224, 224)) plt.imshow(img) plt.imshow(heatmap.numpy()[..., 0], cmap='jet', alpha=0.5) plt.axis('off') plt.show()
内容的提问来源于stack exchange,提问作者Chira
相关产品推荐
相关产品推荐

