深度学习之图像分类(二)-- pytorch查看中间层特征矩阵以及卷积核参数
深度学习之图像分类(二)pytorch查看中间层特征矩阵以及卷积核参数
在开始学习深度学习图像分类模型Backbone理论知识之前,先看看如何在 pytorch 框架中查看中间层特征矩阵以及卷积核参数,学习视频源于 Bilibili。
耳听为虚,眼见为实!可视化 feature maps 以及 kernel weights 在论文展示中非常重要,同时对于个人分析神经网络学习的特性也至关重要。本文学习的完整代码详见 此处。
1. 可视化 feature maps
import torch
from alexnet_model import AlexNet
from resnet_model import resnet34
import matplotlib.pyplot as plt
import numpy as np
from PIL import Image
from torchvision import transforms
"""
class AlexNet(nn.Module):
...
def forward(self, x):
# 存储网络中间结果
outputs = []
for name, module in self.features.named_children():
x = module(x)
if name in ["0", "3", "6"]:
outputs.append(x)
# 网络正向传播过程返回的是中间结果
return outputs
"""
data_transform = transforms.Compose(
[transforms.Resize((224, 224)),
transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
model = AlexNet(num_classes=5)
model_weight_path = "./AlexNet.pth"
model.load_state_dict(torch.load(model_weight_path))
print(model)
img = Image.open("../tulip.jpg")
img = data_transform(img)
img = torch.unsqueeze(img, dim=0)
out_put = model(img)
for feature_map in out_put:
im = np.squeeze(feature_map.detach().numpy())
im = np.transpose(im, [1, 2, 0])
plt.figure()
for i in range(12):
ax = plt.subplot(3, 4, i+1)
plt.imshow(im[:, :, i], cmap='gray')
plt.show()
以 AlexNet 为例,下图展示了测试的原始图片:
下图打印了第一个卷积层计算得到的前 12 个通道的特征图,每个特征图的切片中可以通过明暗程度来理解卷积层 1 所关注的信息,其中越亮的地方就是卷积核越感兴趣的地方。通过对比原图发现,由于这是卷积层 1 输出的特征矩阵,所以基本还是能看出一些原始图的信息。
卷积层 2 输出的信息如下所示,由于越往后,抽象程度越高,所以越来越不像所看到的花了。另外有些卷积核没有起到什么作用的,卷积之后得到的特征矩阵都是黑色的,说明根本就没有学到什么有用的信息。
如果之前不增加 cmap='gray' 的话,图片如下所示:
相比而言,使用 ResNet 得到的结果则更好,第一个卷积层输出结果可见它检测到了纹理信息,以及高亮部分展示了花朵等等。ResNet 的 layer 1 输出的特征图结果也比 AlexNet 很多全黑的要好。可能有两个原因造成这种情况,首先是 ResNet 本身比 AlexNet 要好;其次则是 ResNet 使用了迁移学习,用了 ImageNet 预训练的权重来训练的。
哦豁,如果想看全连接层的输出特征矩阵怎么办呢?
2. 可视化 kernel weights
同样以 AlexNet 和 ResNet 为例。
import torch
from alexnet_model import AlexNet
from resnet_model import resnet34
import matplotlib.pyplot as plt
import numpy as np
model = AlexNet(num_classes=5)
model_weight_path = "./AlexNet.pth"
model.load_state_dict(torch.load(model_weight_path))
print(model)
weights_keys = model.state_dict().keys()
for key in weights_keys:
if "num_batches_tracked" in key:
continue
weight_t = model.state_dict()[key].numpy()
weight_mean = weight_t.mean()
weight_std = weight_t.std(ddof=1)
weight_min = weight_t.min()
weight_max = weight_t.max()
print("mean is {}, std is {}, min is {}, max is {}".format(weight_mean,
weight_std,
weight_max,
weight_min))
plt.close()
weight_vec = np.reshape(weight_t, [-1])
plt.hist(weight_vec, bins=50)
plt.title(key)
plt.show()
下图展示了卷积层 1 的权重以及 bias 的分布。
(有时候能看到,很多卷积核参数都是 0…)
|