动手学深度学习(PyTorch实现)(九)--VGGNet模型

1. VGGNet模型介绍

VGG Net由牛津大学的视觉几何组(Visual Geometry Group)和 Google DeepMind公司的研究员一起研发的的深度卷积神经网络,在 ILSVRC 2014 上取得了第二名的成绩,将 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 × 3 3\times 3 的卷积层,接上一个步幅为2、窗口形状为 2 × 2 2\times 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的结构对比图:
Image Name

图3. VGGNet与AlexNet 结构对比图

2. VGGNet的PyTorch实现

2.1 导入相应的包
import time
import torch
from torch import nn, optim
import torchvision
import numpy as np
import sys
sys.path.append("/home/kesci/input/") 
import d2lzh1981 as d2l
import os
import 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_channels
            blk.append(nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1))
        else:
        	# 之后的卷积层输入和输出都是out_channels
            blk.append(nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1))
        # 激活函数是ReLU
        blk.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 = 7
fc_features = 512 * 7 * 7 # c * w * h
fc_hidden_units = 4096 # 任意
# VGGNet
def 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)
发布了163 篇原创文章 · 获赞 188 · 访问量 12万+

猜你喜欢

转载自blog.csdn.net/qq_42580947/article/details/104398250