CNNs:ZFNet之基于AlexNet特征可视化实验分析
- 导言
- 基于AlexNet网络的实验分析
- 实验一:不同卷积层特征提取分析
- 实验二:不同卷积层提取特征收敛分析
- ZFNet网络介绍
- 基于`ZFNet`网络的实验分析
- 实验三:针对AlexNet特征提取改善可视化
- 实验四:特征不变性实验分析
- 实验五:局部遮挡敏感性分析
- 实验六:局部相关性分析
导言
上一篇我们介绍了如何利用Deconvnet
网络进行特征可视化操作,本篇我们将基于Deconvnet
对文献中的相关实验进行分析,并验证一些结论。除此之外,我们还将针对实验现象对对AlexNet
网络进行微调(ZFNet
),并对网络进行简单介绍。然后基于ZFNet
进行实验分析。
基于AlexNet网络的实验分析
实验一:不同卷积层特征提取分析
实验条件:
- 模型数据集:ImageNet 2010 training set(1.0 million images, spread over 1000 different classes)
- 模型
AlexNet
- 下图中,在2-5层是在验证数据集中的特征图中抽取前9个最大激活所对应的图片和喂到
Deconvnet
中得到的像素空间的特征。
第一层卷积:是极高和极低的频率信息的混合,几乎不覆盖中频(边缘信息+颜色信息)
第二层卷积:比第一层卷积提取出来的信息更加抽象,但仍主要是由边缘信息和颜色信息组成。
随着层数的增加,提取出来的特征越来越偏向“语义特征”。
第五层中右上角的一组图像中,看似几乎没有共同特征,但网络却学习到了背景草地的特征。
实验二:不同卷积层提取特征收敛分析
- 基于
AlexNet
在训练过程中特征演。下图中,展示了给定特征图的最强激活投影到像素空间中的特征。注意:色彩对比度认为的增强了,为了突出显示特征
可以从上图中发现,随着层数的增加,卷积层提取的特征更加偏向语义特征,且提取出来的语义特征需要更大的epoch
才能提取出来;模型的底层网络在epoch
很小便可以收敛。
下图为基于AlexNet
网络在第一层卷积层核第二层卷积层提取特征后进行特征可视化的结果。可以从图(a)中看到实验中出现了无明显特征的特征图,在图(b)中可以看到明显的混乱网格的现象。其中“混乱网格”的出现是由于在使用卷积核对上一输入进行卷积时,步长过大造成的。所以针对此实验现象,文章提出了基于AlexNet
的改进网络ZFNet
。
ZFNet网络介绍
针对AlexNet
的实验现象,文章针对ImageNet
数据集对AlexNet
进行了微调,可以有效解决混乱网格和dead
特征。
首先,让我们先看一下ZFNet
的网络结构:
import torch
import torch.nn as nn
from collections import OrderedDict
from torchsummary import summary
class ZFNet(nn.Module):
def __init__(self, class_num = 5):
super(ZFNet, self).__init__()
self.features = nn.Sequential(
# input[3, 224, 224] output[96, 110, 110]
nn.Conv2d(3, 96, kernel_size=7, stride=2, padding=1),
nn.ReLU(inplace=True),
# output[96, 55, 55]
nn.MaxPool2d(kernel_size=3, stride=2, padding=1, return_indices=True),
# output[256, 26, 26]
nn.Conv2d(96, 256, kernel_size=5, stride=2),
nn.ReLU(inplace=True),
# output[256, 13, 13]
nn.MaxPool2d(kernel_size=3, stride=2, padding=1, return_indices=True),
# output[384, 13, 13]
nn.Conv2d(256, 384, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
# output[384, 13, 13]
nn.Conv2d(384, 384, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
# output[256, 13, 13]
nn.Conv2d(384, 256, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
# output[256, 6, 6]
nn.MaxPool2d(kernel_size=3, stride=2, return_indices=True),
)
self.classifier = nn.Sequential(
nn.Linear(256 * 6 * 6, 4096),
nn.ReLU(inplace=True),
nn.Dropout(p=0.5),
nn.Linear(4096, 4096),
nn.ReLU(inplace=True),
nn.Linear(4096, class_num),
)
# index of conv
self.conv_layer_indices = [0, 3, 6, 8, 10]
# feature maps
self.feature_maps = OrderedDict()
# switch
self.pool_locs = OrderedDict()
def forward(self, x):
for idx, layer in enumerate(self.features):
if isinstance(layer, nn.MaxPool2d):
x, location = layer(x)
self.pool_locs[idx] = location
self.feature_maps[idx] = x
else:
x = layer(x)
self.feature_maps[idx] = x
x = torch.flatten(x, start_dim=1)
x = self.classifier(x)
return x
if __name__ == "__main__":
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = ZFNet().to(device)
summary(model, (3, 224, 224))
本节对网络细节不再展开叙述,其网络结构与AlexNet
基本一致,仅仅修改了一些卷积参数,具体网络分析,请参考AlexNet网络介绍。这里我们使用torchsummary
对网络参数和结构进行打印。
==========================================================================================
Layer (type:depth-idx) Output Shape Param #
==========================================================================================
├─Sequential: 1 [] --
| └─Conv2d: 2-1 [-1, 96, 110, 110] 14,208
| └─ReLU: 2-2 [-1, 96, 110, 110] --
| └─MaxPool2d: 2-3 [-1, 96, 55, 55] --
| └─Conv2d: 2-4 [-1, 256, 26, 26] 614,656
| └─ReLU: 2-5 [-1, 256, 26, 26] --
| └─MaxPool2d: 2-6 [-1, 256, 13, 13] --
| └─Conv2d: 2-7 [-1, 384, 13, 13] 885,120
| └─ReLU: 2-8 [-1, 384, 13, 13] --
| └─Conv2d: 2-9 [-1, 384, 13, 13] 1,327,488
| └─ReLU: 2-10 [-1, 384, 13, 13] --
| └─Conv2d: 2-11 [-1, 256, 13, 13] 884,992
| └─ReLU: 2-12 [-1, 256, 13, 13] --
| └─MaxPool2d: 2-13 [-1, 256, 6, 6] --
├─Sequential: 1-1 [-1, 5] --
| └─Linear: 2-14 [-1, 4096] 37,752,832
| └─ReLU: 2-15 [-1, 4096] --
| └─Dropout: 2-16 [-1, 4096] --
| └─Linear: 2-17 [-1, 4096] 16,781,312
| └─ReLU: 2-18 [-1, 4096] --
| └─Linear: 2-19 [-1, 5] 20,485
==========================================================================================
Total params: 58,281,093
Trainable params: 58,281,093
Non-trainable params: 0
Total mult-adds (G): 1.22
==========================================================================================
Input size (MB): 0.57
Forward/backward pass size (MB): 11.57
Params size (MB): 222.32
Estimated Total Size (MB): 234.46
==========================================================================================
基于ZFNet
网络的实验分析
实验三:针对AlexNet特征提取改善可视化
将网络修改完后,仍然对同一数据集进行最大激活的特征可视化。可以看到ZFNet
可以有效的改善dead
特征和混乱网格特征。
实验四:特征不变性实验分析
文章中通过对割草机、西施犬、非洲鳄鱼、鹦鹉和娱乐中心进行平移、缩放和旋转分别对第一层卷积层和第七层对原始图像的特征向量计算欧式距离以及显示变换后网络对正确类别对应的概率。
结论:
- a2、b2、c2表明第一层卷积层稍微对图像做物理上的修改,修改后的
feature map
和原始的feature map
之间的欧式距离会急剧增大。 - 竖直平移和缩放导致变化后的
feature map
与原始的feature map
之间的欧式距离变化呈线性且变化很小而非急剧变化,旋转变换的欧式距离变换也十分小,说明以上的变化对网络深层影响很小(网络越深,越倾向提取语义信息)
实验五:局部遮挡敏感性分析
通过对不同的狗的同一部位进行遮挡,以及随机遮挡分析网络对识别准确率的影响。由表所示,对不同的的狗遮挡同一部位,其激活在第五层和第七层的相对变化较小,而随机遮挡的激活变化会增大。
这揭示了网络使用并非使用的关键局部信息进行分类,而是使用了周围的信息进行分类。
实验六:局部相关性分析
本实验通过对同一物体的不同部位进行遮挡实验,以分析局部信息对物体识别的影响。
下图中:
- 第一列是原图遮挡示意图
- 第二列是灰色方块在不同位置遮挡生成的feature map叠加求和结果(强度图)
- 第三列是不经遮挡的原图喂到网络,找到第五层激活最大的feature map,将其用反卷积的方法重构到原始像素空间
- 第四列是遮挡不同不问,识别出来正确类别的概率
- 第五列是遮挡不同部位,识别出来的列别
通过第三列我们可以看到,当我们遮挡住了物体主要特征部分,如狗的脸,车的轮胎以及狗本身时,识别出来的正确的概率会大大降低。
当然,这里有一些问题:
-
为什么在原图中遮挡了左上角,在feature map中左上角能体现出来?
在卷积神经网络中,feature map保留了部分spatial信息 -
为什么在第五层网络提取出来脸,但是网络最后提取的ground truth是阿富汗猎犬?
网络不仅仅使用激活最大的feature map,它是综合了所有的feature map