文章目录
ImageNet Classification with Deep Convolutional Neural Network
历史意义
1、拉开卷积神经网络统治计算机视觉的序幕
2、加速计算机视觉应用落地
Abstract
1、比赛数据集上运行效果极佳
2、AlexNet由五个conv层和3个fullconnection层构成,参数众多(the net contains eight layers with weights : first five are convolutional and the remaining three are fully-connected)
3、采用ReLu作为激活函数,同时使用GPU加快训练
4、采用Dropout减轻过拟合
Introduction and dataset
AlexNet’s struction
结构特点
1、ReLu Nonlinearrity
(1)使网络训练更快(2)防止梯度消失(相较于Sigmoid,没有饱和点)(3)使网络具有稀疏性
2、Training on Multiple GPUs
3、Local Response Normalization(LRN,局部响应标准化){现在已经被BN取代}
有助于AlexNet泛化能力提升,灵感来自于真实神经元的侧抑制(lateral inhibition)
侧抑制:细胞分化时,他对周围cell产生抑制信号,阻止其他cell向相同方向分化,最终表现为细胞命运的不同
(i表示channel_size;j平方累加索引,代表从j-i的像素值平方求和;x,y表示像素位置;a表示feature map中i对应像素的具体值;N表示feature map里面最内层向量的列数;其余参量均为超参数)
4、Overlapping Pooling(重叠池化)
通过设置stride=2,kernel_size=3实现池化探测区域存在重叠部分
训练技巧
1、Data Augmentation(数据增强)
针对位置
训练阶段:
(1)图片统一缩放至256256
(2)随机位置裁剪出224224区域
(3)随机进行水平翻转
测试阶段:
(1)图片统一缩放至256256
(2)裁剪出5个224224区域
(3)均进行水平翻转,共得到10张224*224图片
针对颜色
通过PCA方法修改RGB通道的像素值,实现颜色扰动
2、Dropout(随机失活)
随机:dropout probability(p=0.5)【训练和测试两个阶段的数据尺度变化测试时,神经元输出值乘以p】
失活:weight = 0
Summary
1、ReLU;2、LRN;3、Overlapping;4、Augmentation;5、Dropout
代码复现
ps:博主手撕的是pytorch里面封装的AlexNet,里面部分参数可能会和原文有所差异
import torch
import torch.nn as nn
class AlexNet(nn.Module):
def __init__(self, num_classes):
super(AlexNet, self).__init__()
# 第一次卷积操作
self.conv1 = nn.Sequential(nn.Conv2d(3, 64, kernel_size=11, stride=4, padding=2),
nn.ReLU(inplace=True))
# 第一次池化操作
self.pool1 = nn.MaxPool2d(kernel_size=3, stride=2)
# 第二次卷积操作
self.conv2 = nn.Sequential(nn.Conv2d(64, 192, kernel_size=5, padding=2),
nn.ReLU(inplace=True))
# 第二次池化
self.pool2 = nn.MaxPool2d(kernel_size=3, stride=2)
# 第三次卷积操作
self.conv3 = nn.Sequential(nn.Conv2d(192, 384, kernel_size=3, padding=1),
nn.ReLU(inplace=True))
# 第四次卷积操作
self.conv4 = nn.Sequential(nn.Conv2d(384, 256, kernel_size=3, padding=1),
nn.ReLU(inplace=True))
# 第五次卷积操作
self.conv5 = nn.Sequential(nn.Conv2d(256, 256, kernel_size=3, padding=1),
nn.ReLU(inplace=True))
# 第三次池化
self.pool3 = 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: torch.Tensor):
print("输入图像尺寸为{}".format(x.size()))
x = self.conv1(x)
print("经过第一次卷积后图像尺寸为{}".format(x.size()))
x = self.pool1(x)
print("经过第一次池化后图像尺寸为{}".format(x.size()))
x = self.conv2(x)
print("经过第二次卷积后图像尺寸为{}".format(x.size()))
x = self.pool2(x)
print("经过第二次池化后图像尺寸为{}".format(x.size()))
x = self.conv3(x)
print("经过第三次卷积后图像尺寸为{}".format(x.size()))
x = self.conv4(x)
print("经过第四次卷积后图像尺寸为{}".format(x.size()))
x = self.conv5(x)
print("经过第五次卷积后图像尺寸为{}".format(x.size()))
x = self.pool3(x)
print("经过第三次池化后图像尺寸为{}".format(x.size()))
x = self.avgpool(x)
print("经过平均池化后图像尺寸为{}".format(x.size()))
x = torch.flatten(x, 1) # flatten(x,1)是按照x的第1个维度拼接(按照列来拼接,横向拼接)
print("经过拉伸后图像尺寸为{}".format(x.size()))
x = self.classifier(x)
print("经过三层全连接后图像尺寸为{}".format(x.size()))
return x
if __name__ == "__main__":
import torch as t
input = t.randn(1, 3, 224, 224)
net = AlexNet(2)
out = net(input)
运行效果
1、模型接受的是4D的tensor,因此再导入模型时需要将3D彩图转换为含有batch_size的tensor
2、不使用LRN
3、增加AdaptiveAvgPool2d
4、pytorch中封装的kernel_num有所变化