Visual Explanations from Deep Networks via Gradient-based Localization”

## 1 综述

CAM的全称是Class Activation Mapping，对于分类问题，我们可以直观的通过这种方法，来进行解释方向的可视化。

## 2 CAM

CAM的原理是实现可解释性的根本，所以我通俗易懂的讲一讲。

```self.model.features.zero_grad()
one_hot.backward(retain_graph=True)#仅包含有最大概率值，然后进行反向传播
weights = np.mean(grads_val, axis=(2, 3))[0, :]#求平均，就是上面这段公式
# 简单的说上面的逻辑就是先反向传播之后，然后获取对应位置的梯度，然后计算平均。```

## 4 pytorch完整代码

```class FeatureExtractor():
""" Class for extracting activations and
registering gradients from targetted intermediate layers """
def __init__(self, model, target_layers):
self.model = model
self.target_layers = target_layers
def __call__(self, x):
outputs = []
for name, module in self.model._modules.items():
x = module(x)
if name in self.target_layers:
outputs += [x]
return outputs, x
class ModelOutputs():
""" Class for making a forward pass, and getting:
1. The network output.
2. Activations from intermeddiate targetted layers.
3. Gradients from intermeddiate targetted layers. """
def __init__(self, model, feature_module, target_layers):
self.model = model
self.feature_module = feature_module
self.feature_extractor = FeatureExtractor(self.feature_module, target_layers)
def __call__(self, x):
target_activations = []
for name, module in self.model._modules.items():
if module == self.feature_module:
target_activations, x = self.feature_extractor(x)
elif "avgpool" in name.lower():
x = module(x)
x = x.view(x.size(0),-1)
else:
if name is 'classifier':
x = x.view(x.size(0), -1)
x = module(x)
return target_activations, x
def __init__(self, model, feature_module, target_layer_names, use_cuda):
self.model = model
self.feature_module = feature_module
self.model.eval()
self.cuda = use_cuda
if self.cuda:
self.model = model.cuda()
self.extractor = ModelOutputs(self.model, self.feature_module, target_layer_names)
def forward(self, input_img):
return self.model(input_img)
def __call__(self, input_img, target_category=None):
if self.cuda:
input_img = input_img.cuda()
features, output = self.extractor(input_img)
if target_category == None:
target_category = np.argmax(output.cpu().data.numpy())
one_hot = np.zeros((1, output.size()[-1]), dtype=np.float32)
one_hot[0][target_category] = 1
if self.cuda:
one_hot = one_hot.cuda()

one_hot = torch.sum(one_hot * output)
one_hot.backward(retain_graph=True)
target = features[-1]
target = target.cpu().data.numpy()[0, :]
weights = np.mean(grads_val, axis=(2, 3))[0, :]
cam = np.zeros(target.shape[1:], dtype=np.float32)
for i, w in enumerate(weights):
cam += w * target[i, :, :]
cam = np.maximum(cam, 0)
cam = cv2.resize(cam, input_img.shape[2:])
cam = cam - np.min(cam)
cam = cam / np.max(cam)
return cam```

```grad_cam = GradCam(model = model,feature_module = model.features,target_layer_names=['11'],use_cuda=True)
def draw(ax,grayscale_cam,data):
heatmap = cv2.applyColorMap(np.uint8(255 * grayscale_cam), cv2.COLORMAP_JET)
heatmap = heatmap + data.detach().cpu().numpy()[0,0].reshape(28,28,1).repeat(3,axis=2)
heatmap = heatmap / np.max(heatmap)
ax.imshow(heatmap)
if torch.cuda.is_available():
data = data.cuda()
target = target.cuda()
# 绘制9张可视化图
fig = plt.figure(figsize=(12,12))
for i in range(9):
d = data[i:i+1]