AlexNet:ImageNet classification with deep convolutional neural networks

卷积神经网络从这里开始开始火起来,主要内容包括:(1)使用relu训练网络;(2)使用LRN层;(3)使用数据增强;(4)使用dropout;(5)使用重叠池化

什么是 AlexNet?

  • AlexNet-20230408135804
  • AlexNet是由Alex Krizhevsky 提出的首个应用于图像分类的深层卷积神经网络
  • AlexNet和LeNet 很像,基础模块均是:卷积+激活+下采样,但是AlexNet更深

AlexNet的网络结构?

  • 训练阶段: 每张训练图片256x256,然后我们随机裁剪出224x224大小的图片,作为CNN的输入进行训练
  • 测试阶段: 输入256x256大小的图片,我们从图片的5个指定的方位(上下左右+中间)进行裁剪出5张224x224大小的图片,然后水平镜像一下再裁剪5张,这样总共有10张;然后我们把这10张裁剪图片分别送入已经训练好的CNN中,分别预测结果,最后用这10个结果的平均作为最后的输出
  • 8个学习层,包括5个卷积层和3个全连接层,其余层为 局部响应归一化(Local Response Normalization,LRN)层,池化层,softmax 输出层

AlexNet的损失函数?

  • AlexNet输入是图片(c,h,w),输出是1000,表示该图片的分类结果
  • AlexNet使用交叉熵损失(CrossEntropyLoss) 计算损失

Alexnet中为什么选择使用relu作为激活函数,而不是tanh?

  • tanh 是饱和激活函数,而 Relu 是非饱和的,饱和激活函数更难训练网络,非饱和函数可以让梯度传播到更深层的网络中
  • 在同等训练效果下,使用relu比tanh训练更快
    AlexNet-20230408135806

Alexnet如何使用多GPU进行训练?

  • AlexNet-20230408135804
  • 将每层一半的内核(或神经元)分别放在2个GPU上
  • 第三层从第二层的2个GPU获取输入,而第四层从第三层的各自GPU获取输入
  • GPU的交叉连接,类似交叉验证,减低了模型过拟合,最终使得分类top-1,top5错误率降低1.7%和1.2%
  • AlexNet通过通过分组filter训练模型,类似于分组卷积(Group Convolution) ,之所以能减少过拟合,本质是分组卷积降低了filter之间的依赖,相当于正则化(regularization)模型,详细查看:为什么分组卷积有用

如何理解Alexnet中的重叠池化?

  • 重叠池化(Overlapping Pooling)使得Alexnet在ImageNet上的top-1和top-5的错误率分别降低了0.4%和0.3%
  • 使用后,过拟合 (overfitting)现象出现减少

AlexNet如何减少过拟合?

  • 数据增强:(1)取4角+中心的224*224区域并进行平移及水平翻转,获得10倍数据量;(2)PCA颜色调整: 比如说,如果你的图片呈现紫色,即主要含有红色和蓝色,绿色很少,然后PCA颜色增强算法就会对红色和蓝色增减很多,绿色变化相对少一点,所以使总体的颜色保持一致
  • 使用丢弃正则化(Dropout):避免过拟合的同时,也较少模型收敛时间

为什么输入到AlexNet网络的图片必须大小固定?

  • 卷积层不管原图或featrue map的大小,不需要固定
  • 全连接层因为需要固定输出数量,所以需要固定尺寸输入,导致网络需要固定输入
  • 一般在前处理上使用resize或corp的操作,将数据变为固定尺寸输入;也可以使用空间金字塔池化(Spatial Pyramid Pooling,SPP)将不同大小的图片转为一致的尺寸

如何使用 Pytorch 定义 AlexNet?

  • 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
     class AlexNet(nn.Module):
    def __init__(self, num_classes=1000):
    super(AlexNet, self).__init__()
    self.features = nn.Sequential(
    nn.Conv2d(3, 64, kernel_size=11, stride=4, padding=2),
    nn.ReLU(inplace=True),
    nn.MaxPool2d(kernel_size=3, stride=2),
    nn.Conv2d(64, 192, kernel_size=5, padding=2),
    nn.ReLU(inplace=True),
    nn.MaxPool2d(kernel_size=3, stride=2),
    nn.Conv2d(192, 384, kernel_size=3, padding=1),
    nn.ReLU(inplace=True),
    nn.Conv2d(384, 256, kernel_size=3, padding=1),
    nn.ReLU(inplace=True),
    nn.Conv2d(256, 256, kernel_size=3, padding=1),
    nn.ReLU(inplace=True),
    nn.MaxPool2d(kernel_size=3, stride=2),
    )
    self.avgpool = nn.AdaptiveAvgPool2d((6, 6))
    self.classifier = nn.Sequential(
    nn.Dropout(),
    nn.Linear(256 * 6 * 6, 4096),
    nn.ReLU(inplace=True),
    nn.Dropout(),
    nn.Linear(4096, 4096),
    nn.ReLU(inplace=True),
    nn.Linear(4096, num_classes),
    )
    def forward(self, x):
    x = self.features(x)
    x = self.avgpool(x)
    x = torch.flatten(x, 1)
    x = self.classifier(x)
    return x