• 《动手学深度学习 Pytorch版》 7.2 使用块的网络(VGG)


    import torch
    from torch import nn
    from d2l import torch as d2l
    
    • 1
    • 2
    • 3

    7.2.1 VGG 块

    AlexNet 没有提供一个通用的模板来指导后续的研究人员设计新的网络,如今研究人员转向了块的角度思考问题。通过使用循环和子程序,可以很容易地在任何现代深度学习框架的代码中实现这些重复的架构。

    经典的卷积神经网络的基本组成部分如下:

    - 带填充以保持分辨率的卷积层
    
    - 非线性激活层
    
    - 汇聚层
    
    • 1
    • 2
    • 3
    • 4
    • 5

    VGG 块与之类似,由一系列卷积层组成,再加上用于空间降采样的汇聚层。

    def vgg_block(num_convs, in_channels, out_channels):  # 卷积核数量,输入通道数,输出通道数
        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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    为什么 VGG 块选择堆 3 × 3 3\times 3 3×3 而不是 5 × 5 5\times 5 5×5

    主要是因为在同样的算力下,堆层数多但是核小的 3 × 3 3\times 3 3×3 要比堆核大但是层数少的 5 × 5 5\times 5 5×5 效果要好。简言之,卷积层深度的影响要大于卷积核大小的影响。

    7.2.2 VGG 网络

    VGG 网络可以分为两部分:

    - 第一部分由卷积层和汇聚层构成
    
    - 第二部分由全连接层组成
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    conv_arch = ((1, 64), (1, 128), (2, 256), (2, 512), (2, 512))
    
    def vgg(conv_arch):
        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(),
            # 全连接层部分
            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))
    
    net = vgg(conv_arch)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    X = torch.randn(size=(1, 1, 224, 224))
    for blk in net:
        X = blk(X)
        print(blk.__class__.__name__,'output shape:\t',X.shape)
    
    • 1
    • 2
    • 3
    • 4
    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])
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    7.2.3 训练模型

    ratio = 4
    small_conv_arch = [(pair[0], pair[1] // ratio) for pair in conv_arch]  # 构建一个通道较少的模型以减少运算量
    net = vgg(small_conv_arch)
    
    • 1
    • 2
    • 3
    lr, num_epochs, batch_size = 0.05, 10, 128
    train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size, resize=224)
    d2l.train_ch6(net, train_iter, test_iter, num_epochs, lr, d2l.try_gpu())  # 大约需要三十五分钟,慎跑
    
    • 1
    • 2
    • 3
    loss 0.188, train acc 0.929, test acc 0.908
    327.1 examples/sec on cuda:0
    
    • 1
    • 2

    在这里插入图片描述

    练习

    (1)打印层的尺寸时,我们只看到 8 个结果,而不是 11 个结果。剩余的 3 层信息去哪了?

    因为 3 到 8 层是以两两一组的块的形式显示的。


    (2)与 AlexNet 相比,VGG 的计算要慢得多,而且还需要更多的显存。分析出现这种情况的原因。

    层数更多,提取的特征也多。


    (3)尝试将Fashion-MNIST数据集图像的高度和宽度从224改为96。这对实验有什么影响?

    conv_arch96 = ((1, 64), (1, 128), (2, 256), (2, 512), (2, 512))
    
    def vgg96(conv_arch):
        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(),
            nn.Linear(out_channels * 3 * 3, 4096), nn.ReLU(), nn.Dropout(0.5),
            nn.Linear(4096, 4096), nn.ReLU(), nn.Dropout(0.5),
            nn.Linear(4096, 10))
    
    ratio = 4
    small_conv_arch = [(pair[0], pair[1] // ratio) for pair in conv_arch96]
    net96 = vgg96(small_conv_arch)
    
    lr, num_epochs, batch_size = 0.05, 10, 128
    train_iter96, test_iter96 = d2l.load_data_fashion_mnist(batch_size, resize=96)
    d2l.train_ch6(net96, train_iter96, test_iter96, num_epochs, lr, d2l.try_gpu())  # 快多了
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    loss 0.218, train acc 0.919, test acc 0.904
    1496.5 examples/sec on cuda:0
    
    • 1
    • 2

    在这里插入图片描述

    训练速度大幅加快,模型精度略有损失。


    (4)请参考VGG论文 (Simonyan and Zisserman, 2014)中的表1构建其他常见模型,如VGG-16或VGG-19。

    跑不了一点,累了,略。

  • 相关阅读:
    MybatisPlus(简单CURD,MP的实体类注解,MP条件查询,MP分页查询,MP批量操作,乐观锁,代码生成器)
    Java 基于 SpringBoot+Vue 的留守儿童关爱网站
    Java使用lowagie根据模版动态生成PDF(无需额外设置系统字体)
    简单的用Python实现一下,采集某牙视频,多个视频翻页下载
    docker mysql 容器中执行mysql脚本文件并解决乱码
    JVM判断对象是否存活之引用计数法、可达性分析
    【PostgreSQL】解决PostgreSQL时区(TimeZone)问题
    2251: 【区赛】【海曙2017】波波爱看NBA
    Java 基础面试300题 (261-290)
    IO泛泛而谈
  • 原文地址:https://blog.csdn.net/qq_43941037/article/details/133032350