VGGNet模型
1. VGGNet模型介绍1.1 VGGNet的结构1.2 VGGNet结构举例2. VGGNet的PyTorch实现2.1 导入相应的包2.2 基本网络单元block2.3 实现VGGNet2.4 训练网络1. VGGNet模型介绍
VGG Net由牛津大学的视觉几何组(Visual Geometry Group)和 Google DeepMind公司的研究员一起研发的的深度卷积神经网络,在 ILSVRC 上取得了第二名的成绩,将 Top-5错误率降到7.3%。它主要的贡献是展示出网络的深度(depth)是算法优良性能的关键部分。目前使用比较多的网络结构主要有ResNet(152-1000层), GooleNet(22层), VGGNet(19层),大多数模型都是基于这几个模型上改进,采用新的优化算法,多模型融合等。到目前为止,VGGNet 依然经常被用来提取图像特征
1.1 VGGNet的结构
VGGNet的网络结构如下图所示。VGGNet包含很多级别的网络,深度从11层到19层不等,比较常用的是VGGNet-16和VGGNet-19。VGGNet把网络分成了5段,每段都把多个3x3的卷积网络串联在一起,每段卷积后面接一个最大池化层,最后面是3个全连接层和一个softmax层。数个相同的填充为1、窗口形状为3×33\times 33×3的卷积层,接上一个步幅为2、窗口形状为2×22\times 22×2的最大池化层。卷积层保持输入的高和宽不变,而池化层则对其减半。
图1. VGGNet 各级别网络结构图与网络参数量
1.2 VGGNet结构举例
下图是VGG16结构图
图2. VGG16 结构图
输入是大小为224x224x3的RGB图像,预处理(preprocession)时计算出三个通道的平均值,在每个像素上减去平均值(处理后迭代更少,更快收敛)。
图像经过一系列卷积层处理,在卷积层中使用了非常小的3x3卷积核,在有些卷积层里则使用了1x1的卷积核。
卷积层步长(stride)设置为1个,3x3卷积层的填充(padding)设置为1。池化层采用max pooling,共有5层,在一部分卷积层后,max-pooling的窗口是2*2,步长设置为2。
卷积层之后是三个全连接层(fully-connected layers,FC)。前两个全连接层均有4096个通道,第三个全连接层有1000个通道,用来分类。所有网络的全连接层配置相同。
全连接层后是Softmax,用来分类。
所有隐藏层(每个conv层中间)都使用ReLU作为激活函数。VGGNet不使用局部响应标准化(LRN),这种标准化并不能在ILSVRC数据集上提升性能,却导致更多的内存消耗和计算时间(LRN:Local Response Normalization,局部响应归一化,用于增强网络的泛化能力)。
下图是VGGNet与AlexNet的结构对比图:
图3. VGGNet与AlexNet 结构对比图
2. VGGNet的PyTorch实现
2.1 导入相应的包
import timeimport torchfrom torch import nn, optimimport torchvisionimport numpy as npimport syssys.path.append("/home/kesci/input/") import d2lzh1981 as d2limport osimport torch.nn.functional as F
2.2 基本网络单元block
def vgg_block(num_convs, in_channels, out_channels): #卷积层个数,输入通道数,输出通道数blk = []for i in range(num_convs):if i == 0:# 第一层卷积层的输入是in_channels,输出是out_channelsblk.append(nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1))else:# 之后的卷积层输入和输出都是out_channelsblk.append(nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1))# 激活函数是ReLUblk.append(nn.ReLU())# 最后加载最大池化层blk.append(nn.MaxPool2d(kernel_size=2, stride=2)) # 这里会使宽高减半# 返回组合的网络return nn.Sequential(*blk)
2.3 实现VGGNet
# 定义基本参数conv_arch = ((1, 1, 64), (1, 64, 128), (2, 128, 256), (2, 256, 512), (2, 512, 512))# 经过5个vgg_block, 宽高会减半5次, 变成 224/32 = 7fc_features = 512 * 7 * 7 # c * w * hfc_hidden_units = 4096 # 任意# VGGNetdef vgg(conv_arch, fc_features, fc_hidden_units=4096):net = nn.Sequential()# 卷积层部分for i, (num_convs, in_channels, out_channels) in enumerate(conv_arch):# 每经过一个vgg_block都会使宽高减半net.add_module("vgg_block_" + str(i+1), vgg_block(num_convs, in_channels, out_channels))# 全连接层部分net.add_module("fc", nn.Sequential(d2l.FlattenLayer(),nn.Linear(fc_features, fc_hidden_units),nn.ReLU(),nn.Dropout(0.5),nn.Linear(fc_hidden_units, fc_hidden_units),nn.ReLU(),nn.Dropout(0.5),nn.Linear(fc_hidden_units, 10)))return net
2.4 训练网络
# 缩放比例ratio = 8# 因为数据集比较少,所以一定程序的缩减参数能够防止过拟合现象small_conv_arch = [(1, 1, 64//ratio), (1, 64//ratio, 128//ratio), (2, 128//ratio, 256//ratio), (2, 256//ratio, 512//ratio), (2, 512//ratio, 512//ratio)]net = vgg(small_conv_arch, fc_features // ratio, fc_hidden_units // ratio)# 小批量中的样本数batchsize=16#batch_size = 64# 如出现“out of memory”的报错信息,可减小batch_size或resize# train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size, resize=224)# 开始训练lr, num_epochs = 0.001, 5# 优化函数是Adam函数optimizer = torch.optim.Adam(net.parameters(), lr=lr)d2l.train_ch5(net, train_iter, test_iter, batch_size, optimizer, device, num_epochs)