ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

pytorch-grad-cam 实战:如何为 Vision Transformer(ViT)与 Swin Transformer 生成 GradCAM 热力图

pytorch-grad-cam 实战:如何为 Vision Transformer(ViT)与 Swin Transformer 生成 GradCAM 热力图 人工智能AI 可解释性计算机视觉深度学习【免费下载链接】pytorch-grad-camAdvanced AI Explainability for computer vision. Support for CNNs, Vision Transformers, Classification, Object detection, Segmentation, Image similarity and more.项目地址https://gitcode.com/gh_mirrors/py/pytorch-grad-cam点击查看免费下载本文以 tutorials/vision_transformers.md 为核心脉络系统讲解在pytorch-grad-cam中为 ViT 与 Swin Transformer 等非卷积架构生成类激活热力图CAM的关键技巧如何编写reshape_transform将 Transformer 的序列化张量还原成二维空间图像以及如何正确挑选target_layers并辅以仓库源码与完整可运行示例帮助你快速将可解释性分析迁移到任意新的 Transformer 架构上。一、问题背景CAM 方法为何在 Transformer 上失效pytorch-grad-cam中的 GradCAM、ScoreCAM、GradCAM、AblationCAM、XGradCAM、EigenCAM、EigenGradCAM、LayerCAM、FullGrad 等大量像素归因方法最初都是为 CNN 分类模型设计的。它们的核心假设是目标层的激活与梯度是形如BATCH × C × H × W的四维空间特征图可以按通道加权后直接求和得到二维热力图。而 Vision Transformer 打破了这一假设在 ViTDeiT 中层输出张量形状通常是BATCH × 197 × 192在 Swin Transformer 中层输出形状通常是BATCH × 49 × 1024这种BATCH × 序列长度 × 通道数的排列既没有空间高度/宽度维度又混入了特殊 token如 class token直接交给 CAM 方法会因维度不匹配而无法生成热力图。这正是reshape_transform存在的意义它负责把序列化的激活与梯度翻译回BATCH × C × H × W的多通道空间图像从而复用整套 CAM 计算管线。二、Vision TransformerViT上的 GradCAM2.1 理解 ViT 的输出张量结构以deit_tiny_patch16_224为例输入224×224图像被切分为14×14 196个16×16的 patch加上一个 class token序列长度为 197。因此中间层输出为BATCH × 197 × 192第 0 个元素class token用于最终分类第 1196 个元素对应图像中14×14个 patch 的表示。因此我们可以把后 196 个元素视为一张14×14的空间图像每个位置有 192 个通道。在 reshape_transforms.py 中仓库提供了与教程一致的内置实现vit_reshape_transformdef vit_reshape_transform(tensor, height14, width14): result tensor[:, 1:, :].reshape(tensor.size(0), height, width, tensor.size(2)) # Bring the channels to the first dimension, # like in CNNs. result result.transpose(2, 3).transpose(1, 2) return result这里tensor[:, 1:, :]的作用正是剔除 class token只保留 196 个 patch 的表示随后reshape得到BATCH × 14 × 14 × 192两次transpose将通道维度挪到第 1 维最终变成 CNN 风格的BATCH × 192 × 14 × 14。2.2 把 reshape_transform 传给 CAM 构造器所有 CAM 类的构造器见 base_cam.py都接收一个可选的reshape_transform参数GradCAM(modelmodel, target_layerstarget_layers, reshape_transformreshape_transform) def reshape_transform(tensor, height14, width14): result tensor[:, 1 : , :].reshape(tensor.size(0), height, width, tensor.size(2)) # Bring the channels to the first dimension, # like in CNNs. result result.transpose(2, 3).transpose(1, 2) return result从源码看该函数不仅作用于激活值也作用于梯度。在 activations_and_gradients.py 中save_activation与save_gradient两个 hook 都会在记录前调用self.reshape_transform(...)保证后续 CAM 方法拿到的激活与梯度是同一套空间布局def save_activation(self, module, input, output): activation output if self.detach: if self.reshape_transform is not None: activation self.reshape_transform(activation) self.activations.append(activation.cpu().detach()) ... def save_gradient(self, module, input, output): ... def _store_grad(grad): if self.detach: if self.reshape_transform is not None: grad self.reshape_transform(grad) self.gradients [grad.cpu().detach()] self.gradients ...2.3 如何选择 target_layer教程中特别强调了一个容易踩坑的细节不要选最后一层。由于最终分类是在最后一个注意力块计算出的 class token 上完成的最后一层中14×14个 patch 通道对输出没有任何影响其梯度恒为 0生成的 CAM 将毫无意义。正确做法是选择最后一个注意力块之前的任意层例如target_layers [model.blocks[-1].norm1]这也是 vit_example.py 中的实际取值。2.4 完整可运行的 ViT 示例仓库中的 usage_examples/vit_example.py 给出了端到端实现核心流程如下import torch from pytorch_grad_cam import GradCAM, ScoreCAM, GradCAMPlusPlus, AblationCAM, \ XGradCAM, EigenCAM, EigenGradCAM, LayerCAM, FullGrad from pytorch_grad_cam.utils.image import show_cam_on_image, preprocess_image from pytorch_grad_cam.ablation_layer import AblationLayerVit # 加载 DeiT 模型也可以换成其他 ViT 变体 model torch.hub.load(facebookresearch/deit:main, deit_tiny_patch16_224, pretrainedTrue).to(device).eval() target_layers [model.blocks[-1].norm1] # 除 AblationCAM 需要专用 AblationLayerVit 外其余方法直接传 reshape_transform 即可 cam GradCAM(modelmodel, target_layerstarget_layers, reshape_transformreshape_transform) rgb_img cv2.imread(args.image_path, 1)[:, :, ::-1] rgb_img cv2.resize(rgb_img, (224, 224)) rgb_img np.float32(rgb_img) / 255 input_tensor preprocess_image(rgb_img, mean[0.5, 0.5, 0.5], std[0.5, 0.5, 0.5]).to(device) # None 表示取最高得分类别也可以传入自定义 targets targets None cam.batch_size 32 # ScoreCAM / AblationCAM 支持批量加速 grayscale_cam cam(input_tensorinput_tensor, targetstargets, eigen_smoothargs.eigen_smooth, aug_smoothargs.aug_smooth)[0, :] cam_image show_cam_on_image(rgb_img, grayscale_cam)该示例还支持通过--method参数在gradcam / gradcam / scorecam / xgradcam / ablationcam / eigencam / eigengradcam / layercam / fullgrad之间切换并支持--aug_smooth测试时增强平滑与--eigen_smooth取第一主成分降噪运行方式如python usage_examples/vit_example.py --image-path ./examples/dog_cat.jfif --method gradcamViT 上的实际热力图效果可参见 README.md 中 ViT 对比表的输出样例例如 examples/vit_dog_gradcam_cam.jpg 与 examples/vit_cat_scorecam_cam.jpg。三、Swin Transformer 上的 GradCAM3.1 理解 Swin 的输出张量结构Swin Transformer 与 ViT 的一个关键区别是它没有 class token。以swin_base_patch4_window7_224为例其最后一个 stage 输出张量形状通常为BATCH × 49 × 1024其中 49 个位置正好构成一张7×7的空间图像每个位置有 1024 个通道。3.2 reshape_transform 实现与 ViT 相比Swin 的 reshape_transform 只多了一个区别不需要剔除任何 token直接 reshape 即可。仓库内置实现swinT_reshape_transform位于 reshape_transforms.pydef swinT_reshape_transform(tensor, height7, width7): result tensor.reshape(tensor.size(0), height, width, tensor.size(2)) # Bring the channels to the first dimension, # like in CNNs. result result.transpose(2, 3).transpose(1, 2) return result传入 CAM 构造器的方式与 ViT 完全一致GradCAM(modelmodel, target_layerstarget_layers, reshape_transformreshape_transform)3.3 如何选择 target_layer教程指出由于 Swin Transformer 没有 ViT 中的cls_token我们会使用最后一个 stage 的最后一个 block 产生的全部7×7图像。因此应选择最后一个注意力块之前的层例如target_layers [model.layers[-1].blocks[-1].norm1]而 swinT_example.py 中实际使用的是倒数第二个 LayerNorm 层model.layers[-1].blocks[-1].norm2——两者都在最终注意力块之前均可正常工作。可见取最终 attention block 之前的层是一类通用选法具体取norm1还是norm2可结合实际输出灵活调整。3.4 完整可运行的 Swin 示例usage_examples/swinT_example.py 使用timm加载预训练模型核心流程与 ViT 示例对称import timm from pytorch_grad_cam import GradCAM, ScoreCAM, GradCAMPlusPlus, AblationCAM, \ XGradCAM, EigenCAM, EigenGradCAM, LayerCAM, FullGrad from pytorch_grad_cam.utils.image import show_cam_on_image, preprocess_image from pytorch_grad_cam.ablation_layer import AblationLayerVit model timm.create_model(swin_base_patch4_window7_224, pretrainedTrue) model.eval() target_layers [model.layers[-1].blocks[-1].norm2] cam GradCAM(modelmodel, target_layerstarget_layers, reshape_transformreshape_transform) rgb_img cv2.imread(args.image_path, 1)[:, :, ::-1] rgb_img cv2.resize(rgb_img, (224, 224)) rgb_img np.float32(rgb_img) / 255 input_tensor preprocess_image(rgb_img, mean[0.5, 0.5, 0.5], std[0.5, 0.5, 0.5]) cam.batch_size 32 grayscale_cam cam(input_tensorinput_tensor, targetsNone, eigen_smoothargs.eigen_smooth, aug_smoothargs.aug_smooth)[0, :] cam_image show_cam_on_image(rgb_img, grayscale_cam)Swin 上的结果样例同样收录于 README.md例如 examples/swinT_cat_gradcam_cam.jpg 与 examples/swinT_dog_scorecam_cam.jpg。四、原理深挖reshape_transform 在底层如何参与 CAM 计算理解 hook 机制有助于你为其他 Transformer 变体如跨模态模型、新的 tokenizer 设计编写自己的 reshape_transform注册 hook构造 CAM 时ActivationsAndGradients 会对每个target_layer注册两个forward_hook——save_activation记录经 reshape 后的激活save_gradient通过output.register_hook记录经 reshape 后的梯度。前向与反向base_cam.py 的forward中模型前向完成后按np.argmax自动确定最高得分类别或使用你传入的targets随后对损失做loss.backward(retain_graphTrue)。加权与聚合get_cam_image依据激活是 4 维2D 卷积还是 5 维3D 卷积做通道加权np.maximum(cam, 0)截断负值再由scale_cam_image缩放回输入图像分辨率多个 target_layer 的结果默认取均值聚合见 base_cam.py。由于 reshape_transform 同时作用于激活与梯度只要你的转换函数保持空间位置对应关系正确GradCAM、ScoreCAM、EigenCAM 等所有依赖通道加权空间特征的方法都能无缝工作。五、进阶适配AblationCAM 在 Transformer 上的专用实现AblationCAM 需要逐通道切除激活后再观察输出变化其底层操作依赖BATCH × C × H × W的卷积式索引output[i, self.indices[i], :] 0。Transformer 的BATCH × N × C布局无法直接索引因此仓库在 ablation_layer.py 中提供了专用类AblationLayerVitclass AblationLayerVit(AblationLayer): def __call__(self, x): output self.activations output output.transpose(1, len(output.shape) - 1) # 通道移到倒数第二维 for i in range(output.size(0)): if torch.min(output) 0: output[i, self.indices[i], :] 0 else: ABLATION_VALUE 1e7 output[i, self.indices[i], :] torch.min(output) - ABLATION_VALUE output output.transpose(len(output.shape) - 1, 1) # 换回原布局 return output它通过两次transpose在消融时临时把布局调整为类卷积形式完成后换回原样从而复用父类AblationLayer的通道选择逻辑基于 SVD 投影的 objectiveness mask见 ablation_layer.py。在 vit_example.py 与 swinT_example.py 中使用 AblationCAM 时都会显式传入ablation_layerAblationLayerVit()if args.method ablationcam: cam methodsargs.method)六、总结把任意 Transformer 架构接入 pytorch-grad-cam 的通用三步法结合 tutorials/vision_transformers.md 与源码实现可以提炼出将任何新型 Transformer 架构接入本仓库的通用流程分析层输出形状前向打印目标层的输出确认BATCH × N × C中N对应的空间网格如 ViT 的 196 14×14Swin 的 49 7×7并确认是否存在需要剔除的特殊 token如 class token、[CLS]。编写 reshape_transform剔除特殊 token如有reshape成BATCH × H × W × C再用两次transpose将通道移到第 1 维仓库在 reshape_transforms.py 中已内置vit_reshape_transform与swinT_reshape_transform可作为模板直接复制修改。挑选 target_layer选最终注意力块之前的任意层如model.blocks[-1].norm1、model.layers[-1].blocks[-1].norm1避免梯度恒为 0 的最后一层若使用 AblationCAM还需传入AblationLayerVit()。完成这三步后pytorch-grad-cam的整套 CAM 方法GradCAM、ScoreCAM、GradCAM、AblationCAM、XGradCAM、EigenCAM、EigenGradCAM、LayerCAM、FullGrad 等见 pytorch_grad_cam/init.py即可直接作用于你的 ViT、Swin 或未来新架构这也是官方教程中这可以作为未来其他架构的起点这一表述的完整含义。赞分享人工智能AI 可解释性计算机视觉深度学习【免费下载链接】pytorch-grad-camAdvanced AI Explainability for computer vision. Support for CNNs, Vision Transformers, Classification, Object detection, Segmentation, Image similarity and more.项目地址https://gitcode.com/gh_mirrors/py/pytorch-grad-cam点击查看免费下载相关推荐pytorch-grad-cam进阶Vision Transformer注意力热力图生成技巧pytorch grad cam进阶Vision Transformer注意力热力图生成技巧 你是否在使用Vision TransformerViT时遇到人工智能AI 可解释性计算机视觉深度学习使用 PyTorch 实现 Grad-CAM 并绘制分类网络热力图从 CNN 到 ViT / Swin Transformer 的完整实践指南使用 PyTorch 实现 Grad CAM 并绘制分类网络热力图从 CNN 到 ViT / Swin Transformer 的完整实践指南 Grad CA示例工程终极指南如何用pytorch-grad-cam实现Swin Transformer注意力机制可视化终极指南如何用pytorch grad cam实现Swin Transformer注意力机制可视化 在深度学习和计算机视觉领域 pytorch grad c人工智能AI 可解释性计算机视觉深度学习创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表