AlexNet论文翻译及解读
摘要
1、网络结构
卷积层:5个(其中一些后面跟着最大池化层)
全连接层:3个(连接着一个最终是1000路的softmax)
2、tips
非饱和神经元,使用GPU实现
Dropout正则化方法:减少全连接层过拟合现象
3、结果
15.3%的错误率
一、介绍
Imagenet数据集:包含1500万张22000种类别的高分辨率图像
Alexnet模型还需要有先验知识
1、本文的特别贡献
① 训练了一个很大的CNN
② 基于GPU实施2D卷积
③ 网络中包含了大量新的、不经常出现的特征(在第三部分出现)
④ 有效技巧阻止过拟合(第四部分出现)
⑤ 5个卷积层和3个全连接层(这种深度已经使得性能达到最优,若是移去一层卷积层(每个卷积层都包含着不超过总模型的1%的参数)则性能将变差)
2、some notes
① 网络大小的限制因素:GPU的显存、训练时间(人为想去控制的)
② 训练时间:5~6天。训练工具:2块GTX 580 GPU(显存3G)
③ 将来可以提升性能的限制因素:更快的GPU、更大的数据集
二、数据集
ILSVRC挑战赛:用的数据集都是ImageNet的子数据集(训练集:120万张,验证集:5万张,测试集:15万张)
ImageNet习惯提交两种错误率报告:TOP-1错误率和TOP-5错误率。
Top-5错误率
一个图片经过网络,得到预测类别的概率,如果概率前五(top-5)中包含正确答案,即认为正确。top-5错误率就是Top-5 = (正确标记 不在 模型输出的前5个最佳标记中的样本数)/ 总样本数。
Top-1错误率
一个图片,如果概率最大的是正确答案,才认为正确。Top-1 = (正确标记 不是 模型输出的最佳标记的样本数)/ 总样本数。
————————————————
版权声明:本文为CSDN博主「JanzeeLiu」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_36415932/article/details/83029564
1、对数据集的处理方法
下采样图片到256*256(ImageNet图片集分辨率不一)
下采样方法:给定一个举行图像,首先重新缩放图像使短边的长度为256,然后从结果中裁剪出图像中心的256×256的图片
下采样(图像插值) | 上采样(降采样) | |
---|---|---|
目的 | 1)使得图像符合显示区域的大小 2)生成对应图像的缩略图 | 放大原图,从而使得图像可以显示在更高分辨率的显示设备上 |
原理 | 对于一幅图像I尺寸为M×N,对其进行s倍下采样,即得到(M/s)*(N/s)尺寸的得分辨率图像,当然s应该是M和N的公约数才行,如果考虑的是矩阵形式的图像,就是把原始图像s×s窗口内的图像变成一个像素,这个像素点的值就是窗口内所有像素的均值。 | 图像放大几乎都是采用内插值方法,即在原有图像像素的基础上在像素点之间采用合适的插值算法插入新的元素。 |
对图像的处理:没有进行预处理,只是将输入图像做了去均值操作。在居中的像素的原始RGB值训练网络。
三、网络结构
网络架构示意图,显示了两个GPU具体的工作划分:一个 GPU 运行顶层部分,而另一个 GPU 运行底层部分。GPU 仅在某些层进行通信。 网络的输入为 150,528 维。
1、非线性激活函数:ReLU
用ReLU而不用tanh和softmax原因:深度卷积神经网络中ReLU的训练速度更快。
此图表示在CIFAR-10数据集上用ReLu(实线)训练到达25%错误率所需的迭代次数比用tanh要少得多(快至少6倍)
2、在多个GPU上并行训练
①将一半的神经元放置到不同的两块GPU,使用的小trick是GPU只在特定的层中通信
②产生的体系结构与“柱状”CNN相似,使得这种结构训练出的模型错误率相较于在一个GPU上训练每个卷积层中内核为一半的网络相比要降低了1.7%(top-1)和1.2(top-5)
③双GPU网络比单GPU网络训练速度更快【单GPU网络实际上与最终卷积层中的双GPU网络具有相同数量的内核, 这是因为网络的大部分参数都在第一个全连接层中,该层将最后一个卷积层作为输入。 因此,为了使两个网络拥有大致相同数量的参数,我们没有将最终卷积层的大小减半(也没有将后面的全连接层大小减半)。因此这种类比是相对“偏心”的,更加偏向于单GPU网络,因为它要比减半后的双GPU网络更大】
3、局部响应归一化(LRN)
归一化(Normalization 和 Min-Max Scaling)和标准化(Normalization)的原理以及作用
①归一化的意义:1) 提高准确率、收敛速度;2) 消除奇异样本数据影响
②两者区别:
1)归一化:其实是将数据集归属到0-1范围内,从公式可以看出,他的缩放和最大值、最小值有关系
2)标准化:他的输出范围并不是0-1,而是负无穷到正无穷,他的缩放是和所有点都有关系,并且处理后的特征是符合标准正态分布(均值为0,方差为1)
特别注意:1)归一化和标准化均不会改变数据分布;2)归一化缩放的比例仅仅和极值有关,而标准化缩放的比例和整体数据集有关
③使用场景
- 对输出结果范围有要求,用归一化
- 存在异常值和较多噪音,用标准化
- 数据较为稳定,不存在极端的最大最小值,用归一化
————————————————
版权声明:本文为CSDN博主「拼命_小李」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/m0_43432638/article/details/92798662
正则化(Regularization):主要用于避免过拟合的产生和减少网络误差。
局部响应归一化处理方法类似于生物神经元的横向抑制机制,可以理解为将局部响应最大的再放大,并抑制其他响应较小的(放大局部显著特征,作用还是提高鲁棒性)。在用ReLU非线性层之后用到局部响应归一化在特定的层。
作用:用LRN方法后减少了误差分别为1.4%(top-1)和1.2%(top-5)
4、重叠最大池化层
①作用:
1)相对于传统的no-overlapping pooling,采用Overlapping Pooling不仅可以提升预测精度,同时一定程度上可以减缓过拟合。
2)相比于正常池化(步长s=2,窗口z=2) 重叠池化(步长s=2,窗口z=3) 可以减少top-1, top-5分别为0.4% 和0.3%;重叠池化可以避免过拟合。
②结果:相较传统池化错误率分别下降0.4%(top-1)和0.3%(top-5)
5、整个架构
①此架构的优点:网络架构最大化了多项式罗杰斯特回归目标,相当于最大化预测分布下的训练样本中正确标签的对数概率的平均值。(此为softmax定义)
②架构简述:
1)第2、4、5个卷积层只与同一GPU上的前一层内核图相连接,第3个卷积层与第二个的所有内核图都有通连。
2)FC层与之前层的所有神经元均相连
3)LRN跟在第1、2个卷积层后面
4)重叠最大池化层跟在LRN层和第5个卷积层之后。
5)5个卷积层和3个FC层输出均作ReLU处理
③AlexNet运作流程
conv1:输入→卷积→ReLU→局部响应归一化→重叠最大池化层
conv2:卷积→ReLU→局部响应归一化→重叠最大池化层
conv3:卷积→ReLU
conv4:卷积→ReLU
conv5:卷积→ReLU→重叠最大池化层(经过这层之后还要进行flatten展平操作)
FC1:全连接→ReLU→Dropout
FC2:全连接→ReLU→Dropout
FC3(可看作softmax层):全连接→ReLU→Softmax
四、减少过拟合
两种方法:数据增强和Dropout
1、数据增强
最简单、常用的方法:保留标签转换
本文方法优点:不需要过多运算、不需占据很多内存。同时用CPU处理转换操作,用GPU训练模型。
①第一种方式:生成图像平移、水平翻转
通过随机截取输入中固定大小的图片,并做水平翻转,扩大数据集,减少过拟合情况,数据集可扩大到原来的2048倍 :(256-224)^2 * 2 = 2048。在做预测时,取出测试图片的十张patch(四角+中间,再翻转)作为输入,十张patch在softmax层输出取平均值作为最后的输出结果。
②第二种方式:改变训练图片的RGB通道值
对ImageNet训练集的RGB像素值做PCA(主成分分析),对每一张训练图片,加上多个找到的主成分,增加的幅度与相应的特征值乘以均值为0标准差为0.1的高斯分布的随机变量成正比。
作用:经过做PCA分析的处理,减少了模型的过拟合现象。可以得到一个自然图像的性质,改变图像的光照的颜色和强度,目标的特性是不变的,并且这样的处理有利于减少过拟合。
结果:TOP-1错误率减少了1%
2、Dropout
方法:将每个隐藏神经元的输出设置为0的概率为0.5,以这种方式被扔出去的神经元不对网络的前向以及后向传播做出贡献。
作用:dropout技术减少了神经元之间的耦合,在每一次传播的过程中,hidden层的参与传播的神经元不同,整个模型的网络就不相同了,这样就会强迫网络学习更robust的特征,从而提高了模型的鲁棒性。
注:对采用dropout技术的层,都将输出乘以0.5,这是一个由指数级数量的Dropout网络产生的预测分布下的几何平均的合理近似值。
应用于AlexNet网络:在前两个FC层都用到了Dropout。Dropout方法使得错误率收敛所需的迭代次数增加了将近一倍,能够很好的防止过拟合。
五、学习的一些细节
超参数设定:用随机梯度下降法训练模型,batch size = 128,momentum = 0.9,权重衰减 = 0.0005(当作正则化器使用,可以减少模型的训练误差),学习率=0.01。
初始化:①从标准差为0.01,均值为0的高斯分布初始化每一层的权重。②将第2、4、5个卷积层和全连接起来的隐藏层的神经元偏置初始化为常数1(这样的初始化通过为ReLU提供正的输入加速了初期阶段网络的学习)③将剩余层的神经元偏置初始化为常数0。
学习率:所有层均相等,在训练中会人为调整。我们遵循的启发式方法是,当验证集的错误率不再随当前学习率提高时,将学习率除以 10。学习率初始化为0.01并在终止前减少三次。
六、结果分析
1、量化评估
两个GPU表现出的专门性不同, GPU 1 上的内核很大程度上与颜色无关,而 GPU 2 上的内核很大程度上与颜色相关。 这种专门化发生在每次运行期间,并且独立于任何特定的随机权重初始化。
通过计算其对 8 个测试图像的前 5 个预测来定性地评估网络所学到的知识。大部分都是合理的
七、讨论
我们的结果表明,一个大型的深度卷积神经网络能够使用纯监督学习在极具挑战性的数据集上实现破纪录的结果。 值得注意的是,如果删除单个卷积层,我们的网络性能会下降。 例如,移除任何中间层会导致网络的 top-1 性能损失约 2%。 因此,深度对于实现我们的结果确实很重要。
为了简化我们的实验,我们没有使用任何无监督的预训练,即使我们认为它会有所帮助,特别是如果我们获得足够的计算能力来显著增加网络的大小而没有获得相应增加的标记数据量。 到目前为止,我们的结果已经得到了改善,因为我们已经使我们的网络更大并且训练的时间更长,但是为了匹配人类视觉系统的推断时间路径,我们还有很多工作要做。 最终,我们希望在视频序列上使用非常大且深度的卷积网络,其中短时结构提供了非常有用的信息,而这些信息在静态图像中缺失或不太明显。
果确实很重要。
为了简化我们的实验,我们没有使用任何无监督的预训练,即使我们认为它会有所帮助,特别是如果我们获得足够的计算能力来显著增加网络的大小而没有获得相应增加的标记数据量。 到目前为止,我们的结果已经得到了改善,因为我们已经使我们的网络更大并且训练的时间更长,但是为了匹配人类视觉系统的推断时间路径,我们还有很多工作要做。 最终,我们希望在视频序列上使用非常大且深度的卷积网络,其中短时结构提供了非常有用的信息,而这些信息在静态图像中缺失或不太明显。
谈谈自己的理解和总结
结论:整体上AlexNet参数计算量大,较臃肿,但是使用的一些小Tips为后面经典网络的提出奠定了基础。
Tip1→使用LRN层(局部响应归一化):给神经元一个侧向抑制效果,即一个神经元激活之后,其他神经元会受到抑制,这和生物规律有着相似之处。AlexNet论文认为LRN可以很好防止过拟合,但是此Tip在VGG中被抛弃,原因是该操作基本没有作用而会增加计算量。
Tip2→重叠池化:AlexNet认为此层可以防止过拟合,但是后面的网络也不采取这种操作了。
Tip3→数据增强:扩充训练集,采用水平翻转、随即裁剪和对RGB通道进行颜色和光照变换(PCA)的方法。
Tip4→dropout:用在全连接层有效防止过拟合。
dropout作用角度①:打破神经元之间的联合依赖适应性。
dropout作用角度②:模型集成。若dropout率采用0.5,而该层神经元有10个神经元,也就是说这10个神经元各有一半的概率存在或不存在,即可以当作把2^10个模型集成在了该层。
dropout作用角度③:数据增强的作用。
Tip5→使用ReLU非线性激活函数:使得训练速度更快。
AlexNet代码实现
# 值得注意的一点:原图输入224 × 224,实际上进行了随机裁剪,实际大小为227 × 227。
import torch.nn as nn
import torch
# 将双GPU合并为一个,所以每一层的通道数都要翻倍
class AlexNet(nn.Module):
def __init__(self, num_classes=1000, init_weights=False):
super(AlexNet, self).__init__()
self.features = nn.Sequential(
nn.Conv2d(3, 96, kernel_size=11, stride=4, padding=0), # [3, 227, 227] → [96, 55, 55]
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=3, stride=2, padding=0), # [96, 55, 55] → [96, 27, 27]
nn.Conv2d(48, 256, kernel_size=5, stride=1, padding=2), # [96, 27, 27] → [256, 27, 27]
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=3, stride=2), # [256, 27, 27] → [256, 13, 13]
nn.Conv2d(256, 384, kernel_size=3, stride=1, padding=1), # [256, 13, 13] → [384, 13, 13]
nn.ReLU(inplace=True),
nn.Conv2d(384, 384, kernel_size=3, stride=1, padding=1), # [384, 13, 13] → [384, 13, 13]
nn.ReLU(inplace=True),
nn.Conv2d(384, 256, kernel_size=3, stride=1, padding=1), # [384, 13, 13] → [256, 13, 13]
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=3, stride=2, padding=0), # [256, 13, 13] → [256, 6, 6]
)
self.classifier = nn.Sequential(
nn.Dropout(p=0.5),
nn.Linear(256 * 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)
x = self.classifier(x)
return x
def _initialize_weights(self):
for m in self.modules():
if isinstance(m, nn.Conv2d):
nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
if m.bias is not None:
nn.init.constant_(m.bias, 0)
elif isinstance(m, nn.Linear):
nn.init.normal_(m.weight, 0, 0.01)
nn.init.constant_(m.bias, 0)