• 【Pytorch深度学习开发实践学习】【AlexNet】经典算法复现-Pytorch实现AlexNet神经网络(1)model.py


    在这里插入图片描述

    算法简介

    AlexNet是人工智能深度学习在CV领域的开山之作,是最先把深度卷积神经网络应用于图像分类领域的研究成果,对后面的诸多研究起到了巨大的引领作用,因此有必要学习这个算法并能够实现它。

    主要的创新点在于:

    1. 首次使用GPU进行神经网络加速训练
    2. 使用使用了非饱和的激活函数ReLU,而不是传统的sigmoid和tanh
    3. 使用了数据增强手段抑制过拟合
    4. 提出了Dropout随机失活抑制过拟合
    5. 提出了LRN局部响应归一化
    6. 使用了重叠池化抑制过拟合

    model.py代码讲解

    import torch.nn as nn
    import torch
    
    
    class AlexNet(nn.Module):
        def __init__(self, num_classes=1000, init_weights=False):
            super(AlexNet, self).__init__()
            self.features = nn.Sequential(
                nn.Conv2d(3, 48, kernel_size=11, stride=4, padding=2),  # input[3, 224, 224]  使用48个11*11的卷积核,步长为4,padding为2 output[48, 55, 55]
                nn.ReLU(inplace=True),
                nn.MaxPool2d(kernel_size=3, stride=2),                  # input[48, 55, 55]  output[48, 27, 27]
                nn.Conv2d(48, 128, kernel_size=5, padding=2),           # output[128, 27, 27]
                nn.ReLU(inplace=True),
                nn.MaxPool2d(kernel_size=3, stride=2),                  # output[128, 13, 13]
                nn.Conv2d(128, 192, kernel_size=3, padding=1),          # output[192, 13, 13]
                nn.ReLU(inplace=True),
                nn.Conv2d(192, 192, kernel_size=3, padding=1),          # output[192, 13, 13]
                nn.ReLU(inplace=True),
                nn.Conv2d(192, 128, kernel_size=3, padding=1),          # output[128, 13, 13]
                nn.ReLU(inplace=True),
                nn.MaxPool2d(kernel_size=3, stride=2),                  # output[128, 6, 6]
            )
            self.classifier = nn.Sequential(
                nn.Dropout(p=0.5),
                nn.Linear(128 * 6 * 6, 2048),
                nn.ReLU(inplace=True),
                nn.Dropout(p=0.5),
                nn.Linear(2048, 2048),
                nn.ReLU(inplace=True),
                nn.Linear(2048, num_classes),
            )
        
    
        def forward(self, x):
            x = self.features(x)
            x = torch.flatten(x, start_dim=1)
            x = self.classifier(x)
            return x
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    model.py的全部代码如上
    现在逐行进行分析

    class AlexNet(nn.Module):
        def __init__(self, num_classes=1000, init_weights=False):
            super(AlexNet, self).__init__()
            self.features = nn.Sequential(
                nn.Conv2d(3, 48, kernel_size=11, stride=4, padding=2),  # input[3, 224, 224]  使用48个11*11的卷积核,步长为4,padding为2 output[48, 55, 55]
                nn.ReLU(inplace=True),
                nn.MaxPool2d(kernel_size=3, stride=2),                  # input[48, 55, 55]  output[48, 27, 27]
                nn.Conv2d(48, 128, kernel_size=5, padding=2),           # output[128, 27, 27]
                nn.ReLU(inplace=True),
                nn.MaxPool2d(kernel_size=3, stride=2),                  # output[128, 13, 13]
                nn.Conv2d(128, 192, kernel_size=3, padding=1),          # output[192, 13, 13]
                nn.ReLU(inplace=True),
                nn.Conv2d(192, 192, kernel_size=3, padding=1),          # output[192, 13, 13]
                nn.ReLU(inplace=True),
                nn.Conv2d(192, 128, kernel_size=3, padding=1),          # output[128, 13, 13]
                nn.ReLU(inplace=True),
                nn.MaxPool2d(kernel_size=3, stride=2),                  # output[128, 6, 6]
            )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    class AlexNet(nn.Module):
    定义了一个AlexNet的类,这个类继承了nn.Module
    def init(self,num_classes=1000):
    定义了类的初始化函数,它有个可选的参数 num_classes是我们这个神经网络在输出的分类数

    super(AlexNet,self).__init()
    这是为了调用父类的初始化函数

    self.features = nn.Sequential()
    在这里插入图片描述
    这里非常重要,我们可以去Pytorch的官方文档上看看,
    官方的解释是:
    模块将按照传入构造函数的顺序添加到其中。另外,也可以传入一个有序字典的模块。Sequential的forward()方法接受任何输入,并将其转发给它包含的第一个模块。然后,对于每个后续模块,它将输出“链接”到输入,最终返回最后一个模块的输出。
    Sequential相对于手动调用一系列模块的优势在于,它允许将整个容器视为单个模块,这样对Sequential执行的转换将应用于其存储的每个模块(它们分别是Sequential的注册子模块)。
    Sequential和torch.nn.ModuleList之间有什么区别?ModuleList就像它的名字一样-用于存储Module的列表!另一方面,Sequential中的层以级联方式连接。

    论文中的AlexNet网络结构图如下:
    在这里插入图片描述
    AlexNet是第一个网络结构开始变得更加复杂的神经网络模型(Lenet)只有两个卷积层和两个全连接层,而AlexNet有5个卷积层和3个全连接层,对于逐渐复杂的网络结构,我们可以利用Sequential函数搭建序列化的网络模块

    比如这里我们首先定义了一个features模块
    nn.Conv2d(3, 48, kernel_size=11, stride=4, padding=2),
    第一个卷积层 输入是2242243 48个1111的卷积核 步长是4,填充是2
    输出是55
    55*48

    nn.ReLU(inplace=True),ReLU激活函数

    nn.MaxPool2d(kernel_size=3, stride=2),
    定义一个最大池化层,使用3x3的池化核,步长为2。这将进一步减少特征图的尺寸。

    nn.Conv2d(48, 128, kernel_size=5, padding=2),
    又是一个卷积层,输入是272748 128个55的卷积核 填充是2,输出是2727*128

    然后以此类推
    nn.ReLU(inplace=True),
    nn.MaxPool2d(kernel_size=3, stride=2), 又是激活函数和池化,池化后输出 1313128
    nn.Conv2d(128, 192, kernel_size=3, padding=1), 输入1313128 输出1313192

    nn.ReLU(inplace=True),
    nn.Conv2d(192, 192, kernel_size=3, padding=1),输入1313192 输出1313192

    nn.ReLU(inplace=True),
    nn.Conv2d(192, 128, kernel_size=3, padding=1), 输入1313192
    输出1313128

    nn.ReLU(inplace=True),
    nn.MaxPool2d(kernel_size=3, stride=2), 输入1313128 输出 66128

    self.classifier = nn.Sequential(
                nn.Dropout(p=0.5),
                nn.Linear(128 * 6 * 6, 2048),
                nn.ReLU(inplace=True),
                nn.Dropout(p=0.5),
                nn.Linear(2048, 2048),
                nn.ReLU(inplace=True),
                nn.Linear(2048, num_classes),
            )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    第二个模块,上一个是5层卷积层加3层池化层提取特征
    下面这个模块就是全连接层做分类

    首先是drouput随机失活抑制过拟合的操作
    然后是 nn.Linear(128 * 6 * 6, 2048),12866的原因是全连接层是接着前面的最后一个也是第三个池化层,池化层的输出就是12866
    后面再接两个全连接层,最后一个全连接层的输出就是对1000个类的预测结果

       def forward(self, x):
            x = self.features(x)
            x = torch.flatten(x, start_dim=1)
            x = self.classifier(x)
            return x
    
    • 1
    • 2
    • 3
    • 4
    • 5

    def forward(self, x):

    定义一个名为forward的方法,这是PyTorch中自定义神经网络层或模型的标准做法。这个方法描述了输入数据x通过网络的前向传播过程。
    x = self.features(x)
    将输入数据x传递给feature模块
    x = torch.flatten(x, start_dim=1)

    使用PyTorch的flatten函数将特征图x在指定的维度(start_dim=1,通常是指从第二个维度开始,即特征图的深度维度)展平。这通常是为了将多维的特征图转换为一维的张量,以便输入到全连接层。
    这里要重点说明一下,在feature后输出的x是一个四维的参数(B,C,H,W)分别是batchsize channel 高、宽 而这个函数的意思是从第二维channel开始,对后三维 通道数、宽、高进行展开,转为一维的向量输入全连接层

    x = self.classifier(x)
    将展平后的特征x传递给classifier
    return x
    返回经过分类器处理后的输出。

  • 相关阅读:
    delve如何使用?
    go使用grpc
    Spring Cloud Alibaba 核心理论 CAP与BASE理论简单理解(5)
    asp毕业设计——基于asp+access的网上远程教育网设计与实现(毕业论文+程序源码)——网上远程教育网
    Linux/shell基础命令
    python如何进行内存管理
    【C语言】指针和数组笔试题解析(2)
    Pytorch学习笔记 (参考官方教程)
    Tomcat10的坑
    华为荣耀手机,开启开发者选项,hbuilder调试依然找不到
  • 原文地址:https://blog.csdn.net/weixin_44184852/article/details/136361299