【深度学习】使用块的网络(VGG)

虽然 AlexNet 证明深层神经网络卓有成效,但它没有提供一个通用的模板来指导后续的研究人员设计新的网络。

也就是说尽管我知道了更深更大的网络更有效,但是不清楚怎么让它更深更大,从而起到一个更好的效果。

于是,研究人员开始从单个神经元的角度思考问题,发展到整个层,现在又转向块,重复层的模式。

使用块的想法首先出现在牛津大学的视觉几何组的 VGG 网络中,通过使用循环和子程序,可以很容易地在任何现代深度学习框架的代码中实现这些重复的架构。

一、VGG 块

经典卷积神经网络的基本组成部分是下面的这个序列:

  1. 带填充以保持分辨率的卷积层;
  2. 非线性激活函数;
  3. 汇聚层。

而一个 VGG 块与之类似,由一系列卷积层组成,后面再加上用于空间下采样的最大汇聚层。

VGG 块有 3 个参数可以控制:卷积层数、输入通道数和输出通道数。以上一节的 AlexNet 架构为例,其可以看成 3 个 VGG 块和 3 个全连接层组成。

其中,第一个 VGG 块卷积层数是 1,输入通道是 1,输出通道是 96;第二个 VGG 块卷积层数是 1,输入通道数是前一个块的输出通道数,输出通道数是 256;第三个块卷积层数为 3,输入通道为 256,输出通道为 384。

代码实现如下:

python 复制代码
def vgg_block(num_convs, in_channels, out_channels):   # 定义vgg块
    layers = []
    for _ in range(num_convs):
        layers.append(nn.Conv2d(in_channels, out_channels,
                                kernel_size=3, padding=1))   # 加入卷积层
        layers.append(nn.ReLU())                             # 加入激活函数
        in_channels = out_channels        # 下一层的输入通道数为上一层的输出通道数
    layers.append(nn.MaxPool2d(kernel_size=2, stride=2))     # 加入池化层
    return nn.Sequential(*layers)

二、VGG 网络

有了 VGG 块,我们可以很轻松地构造起 VGG 网络:将定义好的 VGG 块拼起来,最后加上全连接层即可。

由于各层的输入通道数和输出通道数是串联起来的,在定义 VGG 网络时我们实际上只需要传入每个 VGG 块的卷积层数和输出通道数即可。

代码实现如下:

python 复制代码
def vgg(conv_arch):         # 构造 VGG 网络
    conv_blks = []
    in_channels = 1         # 初始输入通道数
    # 卷积层部分
    for (num_convs, out_channels) in conv_arch:
        conv_blks.append(vgg_block(num_convs, in_channels, out_channels))
        in_channels = out_channels

    return nn.Sequential(
        *conv_blks, nn.Flatten(),
        # 全连接层部分
        # 原始输入经过5层汇聚层后,大小变为 7*7
        nn.Linear(out_channels * 7 * 7, 4096), nn.ReLU(), nn.Dropout(0.5),
        nn.Linear(4096, 4096), nn.ReLU(), nn.Dropout(0.5),
        nn.Linear(4096, 10))

我们可以构造一个类似 Fashion-MNIST 数据集中图像的输入数据样本,来观察网络中各层的输出尺寸。

python 复制代码
X = torch.randn(size=(1, 1, 224, 224))
    for blk in net:
        X = blk(X)
        print(blk.__class__.__name__, 'output shape:\t', X.shape)

各层输出结果如下。初始输入尺寸是 224 × \times × 224,经过 5 个 vgg 块中的最大汇聚层,尺寸缩小为 7 × \times × 7。

注意,输入的四个数字分别代表批量数、通道数、高度和宽度。

随后展平成向量,大小为 512\\times 7 7 7\\times7=25088,接着通过全连接层,最后输出对应于所有分类类别的 10 维向量。

python 复制代码
Sequential output shape:	 torch.Size([1, 64, 112, 112])
Sequential output shape:	 torch.Size([1, 128, 56, 56])
Sequential output shape:	 torch.Size([1, 256, 28, 28])
Sequential output shape:	 torch.Size([1, 512, 14, 14])
Sequential output shape:	 torch.Size([1, 512, 7, 7])
Flatten output shape:	 torch.Size([1, 25088])
Linear output shape:	 torch.Size([1, 4096])
ReLU output shape:	 torch.Size([1, 4096])
Dropout output shape:	 torch.Size([1, 4096])
Linear output shape:	 torch.Size([1, 4096])
ReLU output shape:	 torch.Size([1, 4096])
Dropout output shape:	 torch.Size([1, 4096])
Linear output shape:	 torch.Size([1, 10])

训练模型

为减小计算量,加快训练速度,我们构建通道数较少的 VGG 网络,便足够用于训练 Fashion-MNIST 数据集了。

python 复制代码
    conv_arch = ((1, 64), (1, 128), (2, 256), (2, 512), (2, 512))    # VGG架构
    ratio = 4     # 通道数减少的比例
    small_conv_arch = [(pair[0], pair[1] // ratio) for pair in conv_arch]
    net = vgg(small_conv_arch)

除了使用较高的学习率外(0.05),其余训练的代码和 AlexNet 一模一样。

另外这次的代码加入了计时。

训练的相关结果如下,可以发现效果是不错的,精度突破了 90%。不过这次运行时间比 AlexNet 长得多,而且这还只是缩小版的 VGG。

python 复制代码
第10轮的训练损失为0.179
第10轮的训练精度为0.933
第10轮的测试集精度为0.918
486.4 examples/sec on cuda:0

总结一下:

  1. 不同的 VGG 模型可以通过每个 VGG 块中的卷积层数量和输出通道数量的差异来定义。
  2. 块的使用让网络的定义变得相当简洁,而且它可以帮助我们有效地进行复杂网络的设计。
  3. 在 VGG 论文中,作者发现,深层且窄(3\\times3)的卷积比浅层而宽的卷积更为有效。

本次模型训练的代码见附件:

相关推荐
β添砖java5 分钟前
深度学习(20)深度卷积神经网络AlexNet
人工智能·深度学习·cnn
weixin_4080996727 分钟前
身份证OCR识别如何做到99.9%准确率?揭秘石榴智能六大核心技术(矫正/完整度/翻拍检测/头像提取)
图像处理·人工智能·ocr·api接口·身份证识别·石榴智能
林小卫很行28 分钟前
Obsidian 入门39:怎么创建自己的 Skill?我把五步拆给你看
人工智能
WJ.Polar36 分钟前
Scapy基本应用
linux·运维·网络·python
Baihai_IDP39 分钟前
为什么 AI Agent 重新爱上了文件系统(Filesystems)
人工智能·llm·agent
MATLAB代码顾问1 小时前
Transformer时序预测:PatchTST原理与PyTorch实现
pytorch·深度学习·transformer
灵机一物1 小时前
灵机一物AI原生电商小程序、PC端(已上线)-Token成产研新KPI:2026年,AI提效、数字员工与研发效能变革
人工智能
薛定猫AI1 小时前
【深度解析】Pi 极简终端 Coding Agent:为什么 4 个工具反而更适合 AI 编程?
人工智能
@insist1231 小时前
信息安全工程师-入侵检测核心技术、APT 应对与工程实践
网络·安全·软考·信息安全工程师·软件水平考试