回答思路
VGG的改进点
VGG的核心思想还是探索网络的深度,VGG16、VGG19分别为16层和19层。主要创新点包括:
由之前的7x7,5x5大卷积核,采用了固定3x3较小的卷积核,层数增加带了更强的非线性,使模型的判别能力更强;
虽然层数增加,因为使用了较小的卷积核,所以反而在卷积层减小了参数数量,与大卷积核相比相当于增加了正则化。
将最后三层全连接层改为卷积层,可以应对不同尺寸的输入,并在最后输出直接求平均。
训练和预测时的技巧:训练时先训练级别A的简单网络,再复用A网络的权重来初始化后面的几个复杂模型,这样训练收敛的速度更快。预测时采用Multi-Scale的方法,同时还再训练时VGGNet也使用了Multi-Scale的方法做数据增强
3x3卷积核的作用
前面提到,之前的7x7,5x5大卷积核,为了保证感受野,提取全局的特征。而vgg网络就提出,多个较小卷积核叠加感受野等于一个大的卷积核
2个33卷积核叠加,可代替一个55的卷积核
同样的,3个3x3的卷积核叠加,则可代替一个7x7的卷积核。
1x1卷积核的作用
1x1卷积核的作用
采用非线性激活函数可以提高模型的非线性能力;
专注于跨通道的特征组合;
对feature map在channel层级进行降维或升维。
Vgg net代码示例(包含vgg16和vgg19)
import torch import torch.nn as nn # vgg16,可以看到,带有参数的刚好为16个net_arch16 = [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 'M', 512, 512, 512, 'M', 512, 512, 512, 'M5', "FC1", "FC2", "FC"] # vgg19,基本和vgg16相同,只不过在后3个卷积段中,每个都多了一个卷积层net_arch19 = [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 256, 'M', 512, 512, 512, 512, 'M', 512, 512, 512, 512, 'M5', "FC1", "FC2", "FC"] class VGGNet(nn.Module): def __init__(self, net_arch, num_classes): # net_arch即为上面定义的列表: net_arch16或net_arch19 super(VGGNet, self).__init__() self.num_classes = num_classes layers = [] in_channels = 3 #初始化通道数for arch in net_arch: if arch == 'M': layers.append(nn.MaxPool2d(kernel_size=2, stride=2)) elif arch == 'M5': layers.append(nn.MaxPool2d(kernel_size=3, stride=1, padding=1)) elif arch == "FC1": layers.append(nn.Conv2d(in_channels=512, out_channels=1024, kernel_size=3, padding=6, dilation=6)) layers.append(nn.ReLU(inplace=True)) elif arch == "FC2": layers.append(nn.Conv2d(1024,1024, kernel_size=1)) layers.append(nn.ReLU(inplace=True)) elif arch == "FC": layers.append(nn.Conv2d(1024,self.num_classes, kernel_size=1)) else: layers.append(nn.Conv2d(in_channels=in_channels, out_channels=arch, kernel_size=3, padding=1) layers.append(nn.ReLU(inplace=True)) in_channels=arch self.vgg = nn.ModuleList(layers) def forward(self, input_data): x = input_data for layer in self.vgg: x = layer(x) out = x return out