VggNet网络结构详解
#图像识别网络结构详解
一、概述
VGG在2014年由牛津大学著名研究组VGG (Visual Geometry Group) 提出,斩获该年ImageNet竞赛中 Localization Task (定位任务) 第一名 和 Classification Task (分类任务) 第二名。
二、网络详解
VGG16相比AlexNet的一个改进是采用连续的几个3x3的卷积核代替AlexNet中的较大卷积核(11x11,7x7,5x5)。对于给定的感受野(与输出有关的输入图片的局部大小),采用堆积的小卷积核是优于采用大的卷积核,因为多层非线性层可以增加网络深度来保证学习更复杂的模式,而且代价还比较小(参数更少)。
简单来说,在VGG中,使用了3个3x3卷积核来代替7x7卷积核,使用了2个3x3卷积核来代替5*5卷积核,这样做的主要目的是在保证具有相同感知野的条件下,提升了网络的深度,在一定程度上提升了神经网络的效果。比如,3个步长为1的3x3卷积核的一层层叠加作用可看成一个大小为7的感受野(其实就表示3个3x3连续卷积相当于一个7x7卷积),其参数总量为 3x(9xC^2) ,如果直接使用7x7卷积核,其参数总量为 49x(C^2) ,这里 C指的是输入和输出的通道数。很明显,27x(C^2)小于 49x(C^2),即减少了参数;而且3x3卷积核有利于更好地保持图像性质。下表1为各个网络配置,表2为VGG-19网络各层详细情况,图1为VGG-16结构图
表1:各个网络的配置
表2:VGG-19网络各层详细
图1 VGG-16网络结构图
三、VGGNet改进点总结
1 使用更小的33卷积核,和更深的网络。两个33卷积核的堆叠相对于55卷积核的视野,三个33卷积核的堆叠相当于77卷积核的视野。这样一方面可以减少参数(3个堆叠的33结构只有77结构参数数量的(333)/(77)=55%);另一方面拥有更多的非线性变换,增加了CNN对特征的学习能力。
2 在VGGNet的卷积结构中,引入1*1的卷积核,在不影响输入输出维度的情况下,引入非线性变换,增加网络的表达能力,降低计算量。
3 训练时,先训练级别简单(层数较浅)的VGGNet的A级网络,然后使用A级网络的权重来初始化后面的复杂模型,加快训练的收敛速度。
4 采用了Multi-Scale的方法来训练和预测。可以增加训练的数据量,防止模型过拟合,提升预测准确率。
注:Single-Scale: 是指把一张图片送到CNN;
Multi-Scale:一般会送到CNN十张图片:比如高宽是256Χ256的图片,Multi-Scale会在它的四个角以及中心进行裁剪 ,将其裁剪为10张 224Χ 224 的图片,然后再进行翻转,总共十张图片,最后全部送到 CNN。
四、VGGNet存在问题
唯一的不足是,在进行反向传播时,中间的卷积层可能会导致占用更多的内存。
五、VGG代码
代码如下(示例):
import torch.nn as nn
import torch__all__ = ['VGG', 'vgg11', 'vgg11_bn', 'vgg13', 'vgg13_bn', 'vgg16', 'vgg16_bn','vgg19_bn', 'vgg19',
]
model_urls = {'vgg11': 'https://download.pytorch.org/models/vgg11-bbd30ac9.pth','vgg13': 'https://download.pytorch.org/models/vgg13-c768596a.pth','vgg16': 'https://download.pytorch.org/models/vgg16-397923af.pth','vgg19': 'https://download.pytorch.org/models/vgg19-dcbb9e9d.pth','vgg11_bn': 'https://download.pytorch.org/models/vgg11_bn-6002323d.pth','vgg13_bn': 'https://download.pytorch.org/models/vgg13_bn-abd245e5.pth','vgg16_bn': 'https://download.pytorch.org/models/vgg16_bn-6c64b313.pth','vgg19_bn': 'https://download.pytorch.org/models/vgg19_bn-c79401a0.pth',
}
1.定义分类网络结构
代码如下(示例):
class VGG(nn.Module):# 定义初始化函数def __init__(self, features, num_classes=1000, init_weights=True):super(VGG, self).__init__()self.features = featuresself.avgpool = nn.AdaptiveAvgPool2d((7, 7))self.classifier = nn.Sequential(nn.Dropout(0.4),nn.Linear(512 * 7 * 7, 4096),nn.ReLU6(True),nn.Dropout(0.4),nn.Linear(4096, 2048),nn.ReLU6(True),nn.Dropout(0.4),nn.Linear(2048, num_classes),)if init_weights:self._initialize_weights()# 定义前向传播函数def forward(self, x):x = self.features(x)x = self.avgpool(x)x = x.view(x.size(0), -1)x = self.classifier(x)return x# 定义初始化权重函数def _initialize_weights(self):for m in self.modules():if isinstance(m, nn.Conv2d):nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')if m.bias is not None:nn.init.constant_(m.bias, 0)elif isinstance(m, nn.BatchNorm2d):nn.init.constant_(m.weight, 1)nn.init.constant_(m.bias, 0)elif isinstance(m, nn.Linear):nn.init.normal_(m.weight, 0, 0.01)nn.init.constant_(m.bias, 0)
2 .定义提取特征网络结构函数
代码如下(示例):
def make_layers(cfg:list, batch_norm=False):layers = []in_channels = 3for v in cfg:if v == 'M':layers += [nn.MaxPool2d(kernel_size=2, stride=2)]else:conv2d = nn.Conv2d(in_channels, v, kernel_size=3, padding=1)if batch_norm:layers += [conv2d, nn.BatchNorm2d(v), nn.ReLU(inplace=True)]else:layers += [conv2d, nn.ReLU(inplace=True)]in_channels = vreturn nn.Sequential(*layers)
cfg = {'A0': [64, 'M', 128, 'M', 256, 256, 'M'],'A1': [64, 'M', 128, 'M', 256, 256, 'M', 512, 512, 'M'],'A': [64, 'M', 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'],'B': [64, 64, 'M', 128, 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'],'D': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 'M', 512, 512, 512, 'M', 512, 512, 512, 'M'],'E': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 256, 'M', 512, 512, 512, 512, 'M', 512, 512, 512, 512, 'M'],
}
3 . 定义实例化给定的配置模型函数
代码如下(示例):
def vgg7(**kwargs):model = VGG(make_layers(cfg['A0']), **kwargs)return modeldef vgg7_bn(**kwargs):model = VGG(make_layers(cfg['A0'], batch_norm=True), **kwargs)return modeldef vgg9(**kwargs):model = VGG(make_layers(cfg['A1']), **kwargs)return modeldef vgg9_bn(**kwargs):model = VGG(make_layers(cfg['A1'], batch_norm=True), **kwargs)return modeldef vgg11(**kwargs):model = VGG(make_layers(cfg['A']), **kwargs)return modeldef vgg11_bn(**kwargs):model = VGG(make_layers(cfg['A'], batch_norm=True), **kwargs)return modeldef vgg13(**kwargs):model = VGG(make_layers(cfg['B']), **kwargs)return modeldef vgg13_bn(**kwargs):model = VGG(make_layers(cfg['B'], batch_norm=True), **kwargs)return modeldef vgg16(**kwargs):model = VGG(make_layers(cfg['D']), **kwargs)return modeldef vgg16_bn(**kwargs):model = VGG(make_layers(cfg['D'], batch_norm=True), **kwargs)return modeldef vgg19(**kwargs):model = VGG(make_layers(cfg['E']), **kwargs)return modeldef vgg19_bn(**kwargs):model = VGG(make_layers(cfg['E'], batch_norm=True), **kwargs)return modelif __name__ == '__main__':# 'VGG', 'vgg11', 'vgg11_bn', 'vgg13', 'vgg13_bn', 'vgg16', 'vgg16_bn', 'vgg19_bn', 'vgg19'# Examplenet13 = vgg13_bn()print(net13)
六 总结
1.在本文中主要介绍了VggNet网络结构以及各层的使用情况。
2.总结了VggNet网络结构的优缺点 。
3.提供了示例代码。
本人水平有限,文章有写的不对的地方欢迎各位指出!!!