可解释性AI:GradCAM介绍

2024-10-11 08:30   重庆  

点击下方卡片,关注“机器视觉与AI深度学习

视觉/图像重干货,第一时间送达!

    随着人工智能的不断进步,我们见证了一些有史以来最复杂的人工智能系统的出现。在 ChatGPT、Microsoft Copilot 和 Google Gemini 等法学硕士浪潮的推动下,这些智能系统正在迅速发展。但就像所有事物一样,即使是人工智能也存在一些缺陷,尤其是在某些情况下是一个黑匣子。
    黑盒模型是指用户不知道模型在进行预测时考虑的特征的模型。输入和输出已知,但内部工作原理未知。一些示例包括深度神经网络,如 CNN、RNN、LSTM 等。
    本文旨在解释可解释的人工智能(很拗口,是吧?)以及解释卷积神经网络预测的解决方案。它将演示使用 PyTorch 实现 GradCAM,并介绍该技术的细节。
可解释的人工智能
    让我们从基础开始。可解释人工智能到底是什么?
    我们已经训练和使用深度神经网络很长一段时间了。随着深度神经网络的大规模采用,我们需要确保模型预测的依据是正确的。尤其是在医疗保健、金融和法律等高风险领域,人工智能决策的基础与决策本身一样重要。在这种情况下,了解决策背后的理由至关重要。
    可解释人工智能背后的想法是以人类能够理解和领悟的方式解释预测。它旨在深入了解模型的“内部”运作。这是为了确保从模型获得的结果基于真正的特征,而不是训练数据中的一些特殊属性。
GradCAM
    GradCAM(梯度加权类激活映射)是一种流行的技术,它使我们能够可视化卷积神经网络做出的决策。使其适合解释 CNN 模型的显着特征如下:
    GradCAM 显示视觉解释来帮助我们定位图像中的类别。
    它适用于涉及 CNN 模型的各种任务。无论是图像分类、字幕制作等。最重要的是,使用 GradCAM 无需重新训练或在模型中进行任何架构更改。
    GradCAM 通过显示各个模型在做出决策时考虑的特征来帮助区分强模型和弱模型。
    听起来不错,但它是如何运作的呢?
    GradCAM 使用来自最终卷积层的梯度来生成定位图,突出显示用于进行预测的图像中的重要区域。
    第一步是前向传递:图像通过 CNN 执行计算并生成所需类别的分数。
    计算梯度:除了我们感兴趣的类别之外的所有梯度都设置为 0。对于所需的类别,梯度设置为 1。然后,通过感兴趣的整流卷积特征图执行反向传播。
    合并后向梯度:然后将后向梯度在两个维度上合并,以计算每个特征图的重要性。这些捕获的权重表示每个特征图对于目标类别的重要性。
    生成热图:然后使用此加权组合来开发热图(定位图)。这向我们展示了模型在为所需类别做出决策时所关注的位置。
    应用经典的 ReLU:然后将整流线性单元应用于热图,仅考虑对所需类别有积极影响的特征。这是为了确保突出显示对目标类别重要的特征。从而改善“类别判别区域”的定位。
    最后,标准化热图:然后将上述步骤生成的结果标准化并显示为测试图像上的覆盖图。
推理
    让我们结合上述所有步骤,使用 PyTorch 创建我们自己的 GradCAM 实现。
def generata_grad_cam(self):    # weights by averaging the gradients    layer_weights=F.adaptive_avg_pool2d(self.backward_gradients,(1,1))    # Combining forward features with weights    grad_cam=torch.mul(self.forward_features,layer_weights).sum(dim=1,keepdim=True)    grad_cam=F.relu(grad_cam)
# resizing GradCAM to the input image grad_cam_image=F.interpolate(grad_cam, size=(224,224), mode='bilinear', align_corners=False) # normalizing GradCAM grad_cam_image=grad_cam_image-torch.min(grad_cam_image) grad_cam_image=grad_cam_image/torch.max(grad_cam_image)
return grad_cam_image
PyTorch Hooks
    钩子是用于在正向和反向传播过程中监控神经网络的强大工具。它们可用于提取中间数据和调试。有两种类型的钩子可用:
    前向钩子:在前向传递过程中执行。能够提取或修改层的输出。
    反向钩子:在反向传播期间执行。有助于检查和修改反向传播期间获得的梯度。

实际操作:

def forward_features_hook(self,module,input,output):    # save forward pass output    self.forward_features=output
def backward_gradients_hook(self,module,grad_input,grad_output): # save backward pass gradients self.backward_gradients=grad_output[0]
下一步是将钩子和 GradCAM 绑在一起:
def __init__(self,model,layer_name):    # Initializing variables and registering hooks    self.model=model    self.forward_features=None    self.backward_gradients=None
self.cam_layer=getattr(self.model,layer_name)
self.cam_layer[-1].register_forward_hook(self.forward_features_hook) self.cam_layer[-1].register_full_backward_hook(self.backward_gradients_hook)
    演示的示例使用 ResNet-152 架构。它是残差网络架构(CNN 的一种)的变体,包含 152 个层,专为计算机视觉领域的任务而设计。我们将使用 PyTorch 提供的预训练模型并执行对象检测。理想情况下,模型将检测到对象,GradCAM 将生成覆盖原始图像的热图。
    ResNet 的最后一层是第 4 层。钩子被注册到这一层以获取权重和梯度。以下是该模型结构的片段:
(layer4): Sequential(    (0): Bottleneck(      (conv1): Conv2d(1024, 512, kernel_size=(1, 1), stride=(1, 1), bias=False)      (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)      (conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)      (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)      (conv3): Conv2d(512, 2048, kernel_size=(1, 1), stride=(1, 1), bias=False)      (bn3): BatchNorm2d(2048, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)      (relu): ReLU(inplace=True)      (downsample): Sequential(        (0): Conv2d(1024, 2048, kernel_size=(1, 1), stride=(2, 2), bias=False)        (1): BatchNorm2d(2048, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)      )    )    (1): Bottleneck(      (conv1): Conv2d(2048, 512, kernel_size=(1, 1), stride=(1, 1), bias=False)      (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)      (conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)      (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)      (conv3): Conv2d(512, 2048, kernel_size=(1, 1), stride=(1, 1), bias=False)      (bn3): BatchNorm2d(2048, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)      (relu): ReLU(inplace=True)    )    (2): Bottleneck(      (conv1): Conv2d(2048, 512, kernel_size=(1, 1), stride=(1, 1), bias=False)      (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)      (conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)      (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)      (conv3): Conv2d(512, 2048, kernel_size=(1, 1), stride=(1, 1), bias=False)      (bn3): BatchNorm2d(2048, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)      (relu): ReLU(inplace=True)    )  )
    就这样吧,让我们看看 GradCAM 的实际应用:
    我们的第一张测试图是这只金毛猎犬 Coco。

Prediction: 207, 'golden retriever', 8.249414
    值越接近 1,表示该特征用于预测,值越接近 0,则模型不使用该特征。结果接近人脑识别狗品种时所考虑的结果。到目前为止,一切顺利。
    然后,我们有这只超级可爱的西伯利亚哈士奇小狗:

Prediction: 250, 'Siberian husky', 8.082574
    看起来不错,并且突出的特点符合预期。
    接下来,让我们看一个有趣的例子:原始图像显示一只虎猫躺在门垫上。该模型正确识别了两个值:门垫和虎猫。对于门垫,它会考虑猫周围的特征,如图所示。对于虎猫预测,该模型将重点放在猫身上。
    这证明了 GradCAM 的能力以及如何使用它来显示 CNN 模型的预测基础。
代码实现:
https://github.com/dev-essbee/gradcam-pytorch.git?source=post_page-----e678a848ad44--------------------------------

—THE END—

觉得有用,麻烦给个赞和在看 

机器视觉与AI深度学习
专注于机器视觉、AI、深度学习等技术最新资讯、实战内容及应用案例的分享,交流!
 最新文章