AlexNet

简介

2012年,Khrizhevsky,Sutskever和Hinton凭借8层的卷积神经网络 AlexNet,以很大的优势赢得了ImageNet 2012图像识别挑战赛,识别错误率比第二名低大概10个百分点。

网络结构

conv1 阶段

  • 输入数据:227×227×3
  • 卷积核:11×11×3;步长:4;数量:96
  • 卷积后数据:55×55×96
  • relu1后的数据:55×55×96
  • Max pool1的核:3×3,步长:2
  • Max pool1后的数据:27×27×96
  • norm1:local_size=5 (LRN(Local Response Normalization) 局部响应归一化)
  • 最后的输出:27×27×96

这里需要注意,输入Input的图像规格: 224x224x3 (RGB图像),实际上会经过预处理变为227x227x3

conv2 阶段

  • 输入数据:27×27×96
  • 卷积核:5×5;步长:1;数量:256
  • 卷积后数据:27×27×256 (做了Same padding,使得卷积后图像大小不变。)
  • relu2后的数据:27×27×256
  • Max pool2的核:3×3,步长:2
  • Max pool2后的数据:13×13×256
  • norm2:local_size=5 (LRN(Local Response Normalization) 局部响应归一化)
  • 最后的输出:13×13×256

conv3 阶段

  • 输入数据:13×13×256
  • 卷积核:3×3;步长:1;数量:384
  • 卷积后数据:13×13×384 (做了Same padding,使得卷积后图像大小不变。)
  • relu3后的数据:13×13×384
  • 最后的输出:13×13×384

conv4 阶段

  • 输入数据:13×13×384
  • 卷积核:3×3;步长:1;数量(也就是输出个数):384
  • 卷积后数据:13×13×384 (做了Same padding(相同补白),使得卷积后图像大小不变。)
  • relu4后的数据:13×13×384
  • 最后的输出:13×13×384

conv5 阶段

  • 输入数据:13×13×384
  • 卷积核:3×3;步长:1;数量:256
  • 卷积后数据:13×13×256 (做了Same padding,使得卷积后图像大小不变。)
  • relu5后的数据:13×13×256
  • Max pool5的核:3×3,步长:2
  • Max pool2后的数据:6×6×256
  • 最后的输出:6×6×256

fc6 阶段

  • 输入数据:6×6×256
  • 全连接输出:4096×1
  • relu6后的数据:4096×1
  • drop out6后数据:4096×1
  • 最后的输出:4096×1

fc7 阶段

  • 输入数据:4096×1
  • 全连接输出:4096×1
  • relu7后的数据:4096×1
  • drop out7后数据:4096×1
  • 最后的输出:4096×1

fc8阶段

  • 输入数据:4096×1
  • 全连接输出:1000

fc8输出一千种分类的概率。

改进

Relu激活函数

AlexNet采用了ReLU (Rectified Linear Unit)激活函数ReLU的表达式为:

\[f(x)=\max (0, x) \]

传统的激活函数一般是sigmoid和tanh两种饱和非线性函数。在使用梯度下降算法进行训练时,使用这些饱和的非线性函数会比使用非饱和的非线性函数ReLU慢很多,模型收敛需要更长的时间。因此AlexNet在卷积层和全连接层后面都使用了ReLU。

上图是论文中使用ReLU和tanh作为激活函数的典型四层网络的在数据集CIFAR-10s实验中,error rate收敛到0.25时的收敛曲线,可以很明显的看到收敛速度的差距,虚线为tanh,实线是ReLUs。

多GPU训练

由于早期GPU显存的限制,AlexNet使用了双数据流的设计,以让网络中一半的节点能存入一个GPU。这两个数据流,也就是说两个GPU只在一部分层进行通信,这样达到限制GPU同步时的额外开销的效果。有幸的是,GPU在过去几年得到了长足的发展,除了一些特殊的结构外,我们也就不再需要这样的特别设计了。

局部响应归一化层

局部响应归一化层(Local Response Normalization Layer)

在神经网络中,我们用激活函数将神经元的输出做一个非线性映射,但是tanh和sigmoid这些传统的激活函数的值域都是有范围的,但是ReLU激活函数得到的值域没有一个区间,所以要对ReLU得到的结果进行归一化。也就是Local Response Normalization。局部响应归一化的方法如下面的公式:

  • \(a_{(x, y)}^{i}\) 代表的是ReLU在第 \(i\) 个kernel的(x, y)位置的输出;
  • \(n\) 表示的是 \(a_{(x, y)}^{i}\) 的邻居个数;
  • \(N\) 表示该kernel的总数量;
  • \(b_{(x, y)}^{i}\) 表示的是LRN的结果。

我们看下图,每一个矩形表示的一个卷积核生成的feature map。所有的pixel已经经过了ReLU激活函数,现在我们都要对具体的pixel进行局部的归一化。

假设绿色箭头指向的是第i个kernel对应的map,其余的四个蓝色箭头是它周围的邻居kernel层对应的map,假设矩形中间的绿色的pixel的位置为(x, y),那么我需要提取出来进行局部归一化的数据就是周围邻居kernel对应的map的(x, y)位置的pixel的值。也就是上面式子中的\(a_{(x, y)}^{j}\)。然后把这些邻居pixel的值平方再加和。乘以一个系数 \(\alpha\) 再加上一个常数 $ \mathrm{k}$ 然后 \(\beta\) 次幂,就是分母,分子就是第i个kernel对应的map的(x, y)位置的pixel值。

论文中说在验证集中参数为:
\(k=2, n=5, \alpha=10^{-4}, \beta=0.75\)

  • LRN层只存在于第一层卷积层和第二层卷积层的激活函数后面
  • 引入LRN的主要目的,主要是为了防止过拟合,增加模型的泛化能力
  • LRN只对数据相邻区域做归一化处理,不改变数据的大小和维度

Overlapping Pooling

Overlapping Pooling(重叠池化)就是池化操作在部分像素上有重合。池化核大小是pool_size x pool_size,步长是stride ,如果pool_size=stride,则是正常池化,如果stride < pool_size, 则是重叠池化。官方文档中说明,重叠池化的运用减少了top-5和top-1错误率的0.4%0.3%。重叠池化有避免过拟合的作用。

减轻过拟合

Data Augmentation (数据增益)

  • 平移、水平翻转

保留原数据集样本的label,对图片做各种变换以增加样本数,具体又采用了两种方法。这些变换是在CPU上进行的,即在使用GPU训练的同时,用CPU对之后的图片进行变换。
每张图片处理为256×256的大小,但网络结构图中的输入却为224×224,这是因为在256×256大小的图片上使用了一个224×224的滑动窗口,将每个滑动窗口中的内容作为输入,这样就能将整个数据集扩大到原来的(256−224)×(256−224)=1024倍,然后再对这些图片做一个镜像,这样数据集总共扩大了1024×2=2048倍。

在测试集上测试的时候,对于每张图片,随机选取5个224×224的滑动窗口,然后做它们的镜像,即将每个测试样本变为10条测试数据,把对这10条测试数据预测结果的均值作为对该测试样本的最终预测。

  • 改变RGB通道的强度

对每个RGB图片的像素 \(I_{x y}=\left[I_{x y}^{R}, I_{x y}^{G}, I_{x y}^{B}\right]^{T}\) 变为:

\[I_{x y}=\left[I_{x y}^{R}, I_{x y}^{G}, I_{x y}^{B}\right]^{T}+\left[p_{1}, p_{2}, p_{3}\right]\left[\alpha_{1} \lambda_{1}, \alpha_{2} \lambda_{2}, \alpha_{3} \lambda_{3}\right]^{T} \]

\(p\)\(\lambda\) 是RGB值3x3协方差矩阵的特征向量和特征值。

\(\alpha\) 是均值为1标准差为0.1的高斯随机变量。

这么做的原因是利用了自然图片的一条重要性质:物体的鉴别特征并不会因为图片强度和颜色的变化而变化,也就是说,一定程度上改变图片的对比度、亮度、物体的颜色,并不会影响我们对物体的识别。在ImageNet上使用这个方法,降低了1%的top-1 error。

drop out

相当于一种模型集成。 每个隐藏层神经元的输入以0.5的概率输出为0。输出为0的神经元相当于从网络中去除,不参与前向计算和反向传播。所以对于每次输入,神经网络都会使用不同的结构。

  • Dropout会使模型收敛的时间变长。
  • 注意在测试时需要将Dropout关闭。

学习细节

训练时采用随机梯度下降,batch size为128,momentum为0.9,weight decay为0.0005,权值更新的公式为:

\[\begin{aligned} v_{i+1} & :=0.9 \cdot v_{i}-0.0005 \cdot \epsilon \cdot w_{i}-\epsilon \cdot\left\langle\left.\frac{\partial L}{\partial w}\right|_{w_{i}}\right\rangle_{D_{i}} \\ w_{i+1} & :=w_{i}+v_{i+1} \end{aligned} \]

其中 \(i\) 表示迭代次数,\(v\) 为动量项,\(\epsilon\) 为学习率,\(\left\langle\left.\frac{\partial L}{\partial w}\right|_{w_{i}}\right\rangle_{D_{i}}\)表示目标函数 \(L\)\(w=w_{i}\) 时关于 \(w\) 的导数,计算时分别代入第 \(i\) 个batch \(D_{i}\) 中的所有样本(batch size为128),然后取均值。

关于weight decay,实际上确定了目标函数最后面添加正则项(L2 penalty,对权重的平方和的惩罚)的系数,梯度下降时就会多减去一个权重的一次项(由平方项求导得到)。

关于AlexNet的初始化,每一层权重的初始化符合均值为0,标准差为0.01的高斯分布。第二、四、五个卷积层和所有FC层的bias unit初始化为1,其它层为0。每一层的学习率都相同,初始值设为0.01,当模型在验证集上的error rate不再增加时,将学习率除以10。

总结

  • 使用了激活函数ReLU
  • 防止过拟合:数据扩充,DropOut
  • LRN 局部归一化层的使用
  • 多GPU实现
posted @ 2019-04-24 22:08  youngliu91  阅读(652)  评论(0)    收藏  举报