卷积网络可解释性复现 | Grad-CAM | ICCV | 2017 (2)

其中关键的地方是:

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 self.gradients = [] def save_gradient(self, grad): self.gradients.append(grad) def __call__(self, x): outputs = [] self.gradients = [] for name, module in self.model._modules.items(): x = module(x) if name in self.target_layers: x.register_hook(self.save_gradient) 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 get_gradients(self): return self.feature_extractor.gradients 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 class GradCam: 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 one_hot = torch.from_numpy(one_hot).requires_grad_(True) if self.cuda: one_hot = one_hot.cuda() one_hot = torch.sum(one_hot * output) self.feature_module.zero_grad() self.model.zero_grad() one_hot.backward(retain_graph=True) grads_val = self.extractor.get_gradients()[-1].cpu().data.numpy() 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

把这一段复制到自己的代码中后,可以参考下面的代码逻辑,简单改写自己的代码即可实现可视化(看不懂的话还是看github):

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) for data,target in val_loader: 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] grayscale_cam = grad_cam(d) ax = fig.add_subplot(3,3,i+1) draw(ax,grayscale_cam,d) break

输出图像为:

卷积网络可解释性复现 | Grad-CAM | ICCV | 2017

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzdxyf.html