回答思路
VGG网络是很早的文章了,那时候学术界主要关注的任务还是图像分类,参加ILSVRC-ImageNet比赛,提高ImageNet数据集的结果,同期还有vgg19、alexNet、inception v1-3,以及非常经典的resnet网络。
AlexNet因为受限于显存大小,作为副产品,提出了分组卷积;网络结构更深,使用了relu激活函数、使用max pooling替代mean pooling,使用了dropout
VGGNet使用3x3、1x1的卷积核,取代之前网络的大卷积核(如7x7); 网络深度达到19层
Inception and GoogLeNet谷歌提出的模型,致敬LeNet; 之前模型都是往深度考虑,inception网络则是往宽度考虑
ResNet何凯明大佬的经典论文,残差思想很棒;残差可以缓解梯度消失和梯度爆炸,网络深度达到152层。
早期网络的改进都是往模型深度上考虑的,认为模型越深,把卷积层堆叠得越来越多,效果就越好。
网络结构图出自inception论文
因为1x1、3x3或5x5等不同的卷积运算与池化操作可以获得输入图像的不同信息,并行处理这些运算并结合所有结果将获得更好的图像表征。
此后,inception还有几个变体,整体思想没有变化,做了几点改进:
Inception V2
学习VGGNet的特点,用两个33卷积代替55卷积,可以降低参数量。
提出BN算法。就是对输入层信息分布标准化处理,使得规范化为N(0,1)的高斯分布,收敛速度大大提高。
Inception V3
学习Factorization into small convolutions的思想,将一个二维卷积拆分成两个较小卷积,例如将7x7卷积拆成1x7卷积和7x1卷积。这样做的好处是降低参数量。paper中指出,通过这种非对称的卷积拆分,比对称的拆分为几个相同的卷积效果更好,可以处理更多,更丰富的空间特征。
Inception V4
借鉴了微软的ResNet网络结构思想。
Inception block代码示例
import torch from torch import nn import torch.nn.functional as F class BasicConv2d(nn.Module): def __init__(self, in_channels, out_channels, **kwargs): super(BasicConv2d, self).__init__() self.conv = nn.Conv2d(in_channels, out_channels, bias=False, **kwargs) self.bn = nn.BatchNorm2d(out_channels, eps=0.001) def forward(self, x): x = self.conv(x) x = self.bn(x) return F.relu(x, inplace=True) # inception block class InceptionA(nn.Module): def __init__(self, in_channels, pool_features): super(InceptionA, self).__init__() #定义1*1卷积的分支self.branch1x1 = BasicConv2d(in_channels, 64, kernel_size=1) #定义5*5卷积的分支self.branch5x5_1 = BasicConv2d(in_channels, 48, kernel_size=1) self.branch5x5_2 = BasicConv2d(48, 64, kernel_size=5, padding=2) #定义3*3卷积的分支self.branch3x3dbl_1 = BasicConv2d(in_channels, 64, kernel_size=1) self.branch3x3dbl_2 = BasicConv2d(64, 96, kernel_size=3, padding=1) self.branch3x3dbl_3 = BasicConv2d(96, 96, kernel_size=3, padding=1) self.branch_pool = BasicConv2d(in_channels, pool_features, kernel_size=1) def forward(self, x): branch1x1 = self.branch1x1(x) branch5x5 = self.branch5x5_1(x) branch5x5 = self.branch5x5_2(branch5x5) branch3x3dbl = self.branch3x3dbl_1(x) branch3x3dbl = self.branch3x3dbl_2(branch3x3dbl) branch3x3dbl = self.branch3x3dbl_3(branch3x3dbl) branch_pool = F.avg_pool2d(x, kernel_size=3, stride=1, padding=1) branch_pool = self.branch_pool(branch_pool) #三个分支concat outputs = [branch1x1, branch5x5, branch3x3dbl, branch_pool] return torch.cat(outputs, 1)