AlexNet网络详解与pytorch实现

最近在学习B站一个up主的视频,很棒。故决定在学习过程中进行笔记整理和总结。(无它,自用自勉)

给出收藏的博主笔记及up主笔记,以便自己日后查找翻阅。博主链接-AlexNet

(内里给出几篇参考博客可读)

AlexNet详解

        AlexNet与LeNet的架构非常相似,但也存在显著差异。其比LeNet5要深得多,由八层组成:五个卷积层、两个全连接隐藏层和一个全连接输出层;AlexNet采用ReLU而非Sigmoid作为激活函数。由于早期的GPU显存有限,所以原版AlexNet采用了双数据流设计,使每个GPU只负责存储和计算模型的一半参数。同时,AlexNet通过dropout控制全连接层的模型复杂度,而LeNet只使用了权重衰减。

在这里插入图片描述

使用Dropout的方式在网络正向传播过程中随机失活一部分神经元,以减少过拟合 

在这里插入图片描述

在这里插入图片描述

可以发现,除 Conv1 外,AlexNet 的其余卷积层都是在改变特征矩阵的深度,而池化层则只改变(减小)其尺寸。

AlexNet网络详解与pytorch实现_第1张图片

1.各层详解

Conv1

在这里插入图片描述

注意:原作者实验时用了两块GPU并行计算,上下两组图的结构是一样的。

  • 输入:input_size = [224, 224, 3]
  • 卷积层:

kernels = 48 * 2 = 96 组卷积核(输出深度)、kernel_size = 11

padding = [1, 2] ()、stride = 4

  • 输出:output_size = [55, 55, 96]

经 Conv1 卷积后的输出层尺寸为:

                                        Output = \frac{​{W - F + 2P}}{S} + 1 = \frac{​{224 - 11 + (1 + 2)}}{4} + 1 = 55

Maxpool1

在这里插入图片描述

  • 输入:input_size = [55, 55, 96]
  • 池化层:(只改变尺寸,不改变深度channel)

kernel_size = 3、 padding = 0、 stride = 2

  • 输出:output_size = [27, 27, 96]

经 Maxpool1 后的输出层尺寸为:

                                              Output = \frac{​{W - F}}{S} + 1 = \frac{​{55 - 3}}{2} + 1 = 27

Conv2

在这里插入图片描述

  • 输入:input_size = [27, 27, 96]
  • 卷积层:

          kernels = 128 * 2 = 256 组卷积核 、 kernel_size = 5
          padding = [2, 2]       、   stride = 1

  • 输出:output_size = [27, 27, 256]

经 Conv2 卷积后的输出层尺寸为:

                                   Output = \frac{​{W - F + 2P}}{S} + 1 = \frac{​{27 - 5 + 2*2}}{1} + 1 =27

Maxpool2

在这里插入图片描述

  • 输入:input_size = [27, 27, 256]
  • 池化层:(只改变尺寸,不改变深度channel)

                   kernel_size = 3 、padding = 0 、stride = 2

  • 输出:output_size = [13, 13, 256]

经 Maxpool2 后的输出层尺寸为:

                                        Output = \frac{​{W - F}}{S} + 1 = \frac{​{27 - 3}}{2} + 1 = 13

Conv3

在这里插入图片描述

  • 输入:input_size = [13, 13, 256]
  • 卷积层:

               kernels = 192* 2 = 384 组卷积核、kernel_size = 3

               padding = [1, 1] 、 stride = 1

  • 输出:output_size = [13, 13, 384]

经 Conv3 卷积后的输出层尺寸为:

                                    Output = \frac{​{W - F + 2P}}{S} + 1 = \frac{​{13 - 3 + 2*1}}{1} + 1 =13

Conv4

在这里插入图片描述

  • 输入:input_size = [13, 13, 384]
  • 卷积层:

                 kernels = 192* 2 = 384 组卷积核  、  kernel_size = 3
                 padding = [1, 1]  、  stride = 1

  • 输出:output_size = [13, 13, 384]

经 Conv4 卷积后的输出层尺寸为:

                                     Output = \frac{​{W - F + 2P}}{S} + 1 = \frac{​{13 - 3 + 2*1}}{1} + 1 =13

Conv5

在这里插入图片描述

  • 输入:input_size = [13, 13, 384]
  • 卷积层:

                  kernels = 128* 2 = 256 组卷积核  、  kernel_size = 3
                  padding = [1, 1]  、  stride = 1

  • 输出:output_size = [13, 13, 256]

经 Conv5 卷积后的输出层尺寸为:

                                      Output = \frac{​{W - F + 2P}}{S} + 1 = \frac{​{13 - 3 + 2*1}}{1} + 1 =13

Maxpool3
在这里插入图片描述

  • 输入:input_size = [13, 13, 256]
  • 池化层:(只改变尺寸,不改变深度channel)

                 kernel_size = 3  、  padding = 0  、 stride = 2

  • 输出:output_size = [6, 6, 256]

经 Maxpool3 后的输出层尺寸为:

                                        Output = \frac{​{W - F}}{S} + 1 = \frac{​{13 - 3 }}{2} + 1 =6

FC1、FC2、FC3

Maxpool3 → (6*6*256) → FC1 → 2048 → FC2 → 2048 → FC3 → 1000(可根据数据集的类别数进行修改)

AlexNet网络详解与pytorch实现_第2张图片

 2.模型代码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__()
        # 用nn.Sequential()将网络打包成一个模块,精简代码
        self.features = nn.Sequential(   # 卷积层-用于提取图像特征
            # 参数卷积核个数(深度)只取一半
            nn.Conv2d(3, 48, kernel_size=11, stride=4, padding=2),  # input[3, 224, 224]  output[48, 55, 55]
            nn.ReLU(inplace=True), # 函数详解附链接
            # inplace为True,将会改变输入的数据 ,否则不会改变原输入,只会产生新的输出。
            # 省去了反复申请与释放内存的时间,直接代替原来的值。类似C语言中址传递
            nn.MaxPool2d(kernel_size=3, stride=2),                  # 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),			   # Dropout 随机失活神经元,比例默认为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),
        )
        if init_weights:
            self._initialize_weights()
            
	# 前向传播过程
    def forward(self, x):
        x = self.features(x)
        x = torch.flatten(x, start_dim=1)	# (从channel这个维度开始)展平后再传入全连接层
        x = self.classifier(x)
        return x
        
	# 初始化网络权重参数,实际上 pytorch 在构建网络时会自动初始化权重
    def _initialize_weights(self):
        for m in self.modules():
            if isinstance(m, nn.Conv2d):                            # 若是卷积层
                nn.init.kaiming_normal_(m.weight, mode='fan_out',   # 用(何)kaiming_normal_法初始化权重
                                        nonlinearity='relu')
                if m.bias is not None:
                    nn.init.constant_(m.bias, 0)                    # 初始化偏重为0
            elif isinstance(m, nn.Linear):            # 若是全连接层
                nn.init.normal_(m.weight, 0, 0.01)    # 正态分布初始化
                nn.init.constant_(m.bias, 0)          # 初始化偏重为0

PyTorch------nn.ReLU(inplace = True)详解

你可能感兴趣的:(深度学习,神经网络,深度学习)