PyTorch提取中间层特征? - 知乎 https://www.zhihu.com/question/68384370

借助PyTorch Hook机制

PyTorch提取中间层特征? - 袁坤的回答 - 知乎 https://www.zhihu.com/question/68384370/answer/419741762

建议使用hook,在不改变网络forward函数的基础上提取所需的特征或者梯度,在调用阶段对module使用即可获得所需梯度或者特征。

  1. inter_feature = {}
  2. inter_gradient = {}
  3. def make_hook(name, flag):
  4. if flag == 'forward':
  5. def hook(m, input, output):
  6. inter_feature[name] = input
  7. return hook
  8. elif flag == 'backward':
  9. def hook(m, input, output):
  10. inter_gradient[name] = output
  11. return hook
  12. else:
  13. assert False
  14. m.register_forward_hook(make_hook(name, 'forward'))
  15. m.register_backward_hook(make_hook(name, 'backward'))

在前向计算和反向计算的时候即可达到类似钩子的作用,中间变量已经被放置于 inter_featureinter_gradient

  1. output = model(input) # achieve intermediate feature
  2. loss = criterion(output, target)
  3. loss.backward() # achieve backward intermediate gradients

最后可根据需求是否释放hook。

  1. m.remove()

PyTorch提取中间层特征? - 涩醉的回答 - 知乎 https://www.zhihu.com/question/68384370/answer/751212803

通过pytorch的hook机制简单实现了一下,只输出conv层的特征图。

详细可以看下面的blog:涩醉:pytorch使用hook打印中间特征图、计算网络算力等

懒得跳转,可以直接看下面这份代码。

  1. import torch
  2. from torchvision.models import resnet18
  3. import torch.nn as nn
  4. from torchvision import transforms
  5. import matplotlib.pyplot as plt
  6. def viz(module, input):
  7. x = input[0][0]
  8. #最多显示4张图
  9. min_num = np.minimum(4, x.size()[0])
  10. for i in range(min_num):
  11. plt.subplot(1, 4, i+1)
  12. plt.imshow(x[i])
  13. plt.show()
  14. import cv2
  15. import numpy as np
  16. def main():
  17. t = transforms.Compose([transforms.ToPILImage(),
  18. transforms.Resize((224, 224)),
  19. transforms.ToTensor(),
  20. transforms.Normalize(mean=[0.485, 0.456, 0.406],
  21. std=[0.229, 0.224, 0.225])
  22. ])
  23. device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
  24. model = resnet18(pretrained=True).to(device)
  25. for name, m in model.named_modules():
  26. # if not isinstance(m, torch.nn.ModuleList) and \
  27. # not isinstance(m, torch.nn.Sequential) and \
  28. # type(m) in torch.nn.__dict__.values():
  29. # 这里只对卷积层的feature map进行显示
  30. if isinstance(m, torch.nn.Conv2d):
  31. m.register_forward_pre_hook(viz)
  32. img = cv2.imread('/Users/edgar/Desktop/cat.jpeg')
  33. img = t(img).unsqueeze(0).to(device)
  34. with torch.no_grad():
  35. model(img)
  36. if __name__ == '__main__':
  37. main()

借助模型类的属性传递

PyTorch提取中间层特征? - 登高居士的回答 - 知乎 https://www.zhihu.com/question/68384370/answer/812588336

如何得到中间层特征:如果只想得到中间层特征,而不需要得到 gradient 之类的,那么不需要hook函数这么复杂。只需要在forward函数中添加一行代码,将feature赋值给self变量即可,即 self.feature_map = feature 给一个例子:

  1. # Define a Convolutional Neural Network
  2. class Net(nn.Module):
  3. def __init__(self, kernel_size=5, n_filters=16, n_layers=3):
  4. xxx
  5. def forward(self, x):
  6. x = self.body(self.head(x))
  7. self.featuremap1 = x # 核心代码
  8. return F.relu(self.fc(x))
  9. model_ft = Net()
  10. train_model(model_ft)
  11. feature_output1 = model_ft.featuremap1.transpose(1,0).cpu().detach()

这样就得到了 feature_map ,并保存到了feature_output变量中。如何显示中间层特征:给出一个简单显示代码

  1. def feature_imshow(inp, title=None):
  2. """Imshow for Tensor."""
  3. inp = inp.detach().numpy().transpose((1, 2, 0))
  4. mean = np.array([0.5, 0.5, 0.5])
  5. std = np.array([0.5, 0.5, 0.5])
  6. inp = std * inp + mean
  7. inp = np.clip(inp, 0, 1)
  8. plt.imshow(inp)
  9. if title is not None:
  10. plt.title(title)
  11. plt.pause(0.001) # pause a bit so that plots are updated
  12. out = torchvision.utils.make_grid(feature_ouput1)
  13. feature_imshow(out)

结果图如下:
提取中间层特征 - 图1