您當前的位置:首頁 > 書法

PyTorch 實現 GradCAM

作者:由 deephub 發表于 書法時間:2021-08-01

Grad-CAM 概述:給定影象和感興趣的類別作為輸入,我們透過模型的 CNN 部分前向傳播影象,然後透過特定於任務的計算獲得該類別的原始分數。 除了期望的類別(虎),所有類別的梯度都設定為零,該類別設定為 1。然後將該訊號反向傳播到卷積特徵圖,我們將其結合起來計算粗略的 Grad-CAM 定位( 藍色熱圖)它表示模型在做出特定決策時必須檢視的位置。 最後,我們將熱圖與反向傳播逐點相乘,以獲得高解析度和特定於概念的引導式 Grad-CAM 視覺化。

在本文中,我們將學習如何在 PyTorch 中繪製 GradCam [1]。

為了獲得 GradCam 輸出,我們需要啟用圖和這些啟用圖的梯度。

讓我們直接跳到程式碼中!!

引入相應的包

import numpy as np

import matplotlib as mpl

import matplotlib。pyplot as plt

import torch

import torch。nn as nn

from torchvision import models

from skimage。io import imread

from skimage。transform import resize

我們將使用鉤子函式從所需的層和張量獲得啟用對映和梯度。在本教程中,我們將從ResNet50的layer4中獲取啟用對映,並對相同的輸出張量進行梯度。

class GradCamModel(nn。Module):

def __init__(self):

super()。__init__()

self。gradients = None

self。tensorhook = []

self。layerhook = []

self。selected_out = None

#PRETRAINED MODEL

self。pretrained = models。resnet50(pretrained=True)

self。layerhook。append(self。pretrained。layer4。register_forward_hook(self。forward_hook()))

for p in self。pretrained。parameters():

p。requires_grad = True

def activations_hook(self,grad):

self。gradients = grad

def get_act_grads(self):

return self。gradients

def forward_hook(self):

def hook(module, inp, out):

self。selected_out = out

self。tensorhook。append(out。register_hook(self。activations_hook))

return hook

def forward(self,x):

out = self。pretrained(x)

return out, self。selected_out

我們向ResNet50模型的層新增一個前向鉤子。前向鉤子接受該層的輸入和該層的輸出作為引數。對於輸出張量,我們使用register_hook方法註冊一個鉤子。這個方法註冊一個向後掛鉤到一個張量,並且每次計算梯度時呼叫這個張量。它的輸入引數是相對於輸出張量的梯度。

以下是宣告模型例項

gcmodel = GradCamModel()。to(‘cuda:0’)

讀取圖片

PyTorch 實現 GradCAM

PyTorch 實現 GradCAM

img = imread(‘/content/tiger。jfif’) #‘bulbul。jpg’

img = resize(img, (224,224), preserve_range = True)

img = np。expand_dims(img。transpose((2,0,1)),0)

img /= 255。0

mean = np。array([0。485, 0。456, 0。406])。reshape((1,3,1,1))

std = np。array([0。229, 0。224, 0。225])。reshape((1,3,1,1))

img = (img — mean)/std

inpimg = torch。from_numpy(img)。to(‘cuda:0’, torch。float32)

計算類梯度啟用對映

out, acts = gcmodel(inpimg)

acts = acts。detach()。cpu()

loss = nn。CrossEntropyLoss()(out,torch。from_numpy(np。array([600]))。to(‘cuda:0’))

loss。backward()

grads = gcmodel。get_act_grads()。detach()。cpu()

pooled_grads = torch。mean(grads, dim=[0,2,3])。detach()。cpu()

for i in range(acts。shape[1]):

acts[:,i,:,:] += pooled_grads[i]

heatmap_j = torch。mean(acts, dim = 1)。squeeze()

heatmap_j_max = heatmap_j。max(axis = 0)[0]

heatmap_j /= heatmap_j_max

現在,需要調整熱圖的大小和顏色。

調整大小

heatmap_j = resize(heatmap_j,(224,224),preserve_range=True)

顏色對映

cmap = mpl。cm。get_cmap(‘jet’,256)

heatmap_j2 = cmap(heatmap_j,alpha = 0。2)

視覺化

fig, axs = plt。subplots(1,1,figsize = (5,5))

axs。imshow((img*std+mean)[0]。transpose(1,2,0))

axs。imshow(heatmap_j2)

plt。show()

結果如下

PyTorch 實現 GradCAM

PyTorch 實現 GradCAM

我們換一種更清晰的方式檢視熱圖

heatmap_j3 = (heatmap_j > 0。75)

視覺化

fig, axs = plt。subplots(1,1,figsize = (5,5))

axs。imshow(((img*std+mean)[0]。transpose(1,2,0))*heatmap_j3)

plt。show()

結果

PyTorch 實現 GradCAM

PyTorch 實現 GradCAM

最後我們移除剛才設定的鉤子

for h in gcmodel。layerhook:

h。remove()

for h in gcmodel。tensorhook:

h。remove()

引用

[1] R。 R。 Selvaraju, M。 Cogswell, A。 Das, R。 Vedantam, D。 Parikh and D。 Batra, “Grad-CAM: Visual Explanations from Deep Networks via Gradient-Based Localization,” 2017 IEEE International Conference on Computer Vision (ICCV), 2017, pp。 618–626, doi: 10。1109/ICCV。2017。74。

本文作者: the owl

標簽: self  Heatmap  img  out  hook