由于受到计算机性能的影响,虽然LeNet在图像分类中取得了较好的成绩,但是并没有引起很多的关注。 知道2012年,Alex等人提出的AlexNet网络在ImageNet大赛上以远超第二名的成绩夺冠,卷积神经网络乃至深度学习重新引起了广泛的关注。

AlexNet特点

AlexNet是在LeNet的基础上加深了网络的结构,学习更丰富更高维的图像特征。AlexNet的特点:

  • 更深的网络结构
  • 使用层叠的卷积层,即卷积层+卷积层+池化层来提取图像的特征
  • 使用Dropout抑制过拟合
  • 使用数据增强Data Augmentation抑制过拟合
  • 使用Relu替换之前的sigmoid的作为激活函数
  • 多GPU训练

ReLu作为激活函数

在最初的感知机模型中,输入和输出的关系如下:

\[y = \sum_i{w_ix_i} + b
\]

只是单纯的线性关系,这样的网络结构有很大的局限性:即使用很多这样结构的网络层叠加,其输出和输入仍然是线性关系,无法处理有非线性关系的输入输出。因此,对每个神经元的输出做个非线性的转换也就是,将上面就加权求和\(\sum_i{w_ix_i} + b\)的结果输入到一个非线性函数,也就是激活函数中。 这样,由于激活函数的引入,多个网络层的叠加就不再是单纯的线性变换,而是具有更强的表现能力。

在最初,\(sigmoid\)和\(tanh\)函数最常用的激活函数。

  1. \(sigmoid\)

在网络层数较少时,\(sigmoid\)函数的特性能够很好的满足激活函数的作用:它把一个实数压缩至0到1之间,当输入的数字非常大的时候,结果会接近1;当输入非常大的负数时,则会得到接近0的结果。这种特性,能够很好的模拟神经元在受刺激后,是否被激活向后传递信息(输出为0,几乎不被激活;输出为1,完全被激活)。

\(sigmoid\)一个很大的问题就是梯度饱和。 观察\(sigmoid\)函数的曲线,当输入的数字较大(或较小)时,其函数值趋于不变,其导数变的非常的小。这样,在层数很多的的网络结构中,进行反向传播时,由于很多个很小的\(sigmoid\)导数累成,导致其结果趋于0,权值更新较慢。

  1. ReLu



    针对\(sigmoid\)梯度饱和导致训练收敛慢的问题,在AlexNet中引入了ReLU。ReLU是一个分段线性函数,小于等于0则输出为0;大于0的则恒等输出。相比于\(sigmoid\),ReLU有以下有点:

    • 计算开销下。\(sigmoid\)的正向传播有指数运算,倒数运算,而ReLu是线性输出;反向传播中,\(sigmoid\)有指数运算,而ReLU有输出的部分,导数始终为1.
    • 梯度饱和问题
    • 稀疏性。Relu会使一部分神经元的输出为0,这样就造成了网络的稀疏性,并且减少了参数的相互依存关系,缓解了过拟合问题的发生。

这里有个问题,前面提到,激活函数要用非线性的,是为了使网络结构有更强的表达的能力。那这里使用ReLU本质上却是个线性的分段函数,是怎么进行非线性变换的。

这里把神经网络看着一个巨大的变换矩阵\(M\),其输入为所有训练样本组成的矩阵\(A\),输出为矩阵\(B\)。

\[B = M \cdot A
\]

这里的\(M\)是一个线性变换的话,则所有的训练样本\(A\)进行了线性变换输出为\(B\)。

那么对于ReLU来说,由于其是分段的,0的部分可以看着神经元没有激活,不同的神经元激活或者不激活,其神经玩过组成的变换矩阵是不一样的。

设有两个训练样本 \(a_1,a_2\),其训练时神经网络组成的变换矩阵为\(M_1,M_2\)。 由于\(M_1\)变换对应的神经网络中激活神经元和\(M_2\)是不一样的,这样\(M_1,M_2\)实际上是两个不同的线性变换。也就是说,每个训练样本使用的线性变换矩阵\(M_i\)是不一样的,在整个训练样本空间来说,其经历的是非线性变换。

简单来说,不同训练样本中的同样的特征,在经过神经网络学习时,流经的神经元是不一样的(激活函数值为0的神经元不会被激活)。这样,最终的输出实际上是输入样本的非线性变换。

单个训练样本是线性变换,但是每个训练样本的线性变换是不一样的,这样整个训练样本集来说,就是非线性的变换。

数据增强

神经网络由于训练的参数多,表能能力强,所以需要比较多的数据量,不然很容易过拟合。当训练数据有限时,可以通过一些变换从已有的训练数据集中生成一些新的数据,以快速地扩充训练数据。对于图像数据集来说,可以对图像进行一些形变操作:

  • 翻转
  • 随机裁剪
  • 平移,颜色光照的变换
  • ...

AlexNet中对数据做了以下操作:

  1. 随机裁剪,对\(256\times256\)的图片进行随机裁剪到\(227 \times 227\),然后进行水平翻转。
  2. 测试的时候,对左上、右上、左下、右下、中间分别做了5次裁剪,然后翻转,共10个裁剪,之后对结果求平均。
  3. 对RGB空间做PCA(主成分分析),然后对主成分做一个(0, 0.1)的高斯扰动,也就是对颜色、光照作变换,结果使错误率又下降了1%。

层叠池化

在LeNet中池化是不重叠的,即池化的窗口的大小和步长是相等的,如下

在AlexNet中使用的池化(Pooling)却是可重叠的,也就是说,在池化的时候,每次移动的步长小于池化的窗口长度。AlexNet池化的大小为3×3的正方形,每次池化移动步长为2,这样就会出现重叠。重叠池化可以避免过拟合,这个策略贡献了0.3%的Top-5错误率。与非重叠方案\(s = 2,z = 2\)相比,输出的维度是相等的,并且能在一定程度上抑制过拟合。

局部相应归一化

ReLU具有让人满意的特性,它不需要通过输入归一化来防止饱和。如果至少一些训练样本对ReLU产生了正输入,那么那个神经元上将发生学习。然而,我们仍然发现接下来的局部响应归一化有助于泛化。\(a_{x,y}^i\)表示神经元激活,通过在\((x, y)\)位置应用核\(i\),然后应用ReLU非线性来计算,响应归一化激活\(b^i_{x,y}\)通过下式给定:

\[b^i_{x,y} = a_{x,y}^i / \big( k + \alpha \sum _{j = max(0, i-n / 2)} ^{min(N-1, i+n / 2)} (a_{x,y}^j)^2 \big)^\beta
\]

其中,\(N\)是卷积核的个数,也就是生成的FeatureMap的个数;\(k,\alpha,\beta,n\)是超参数,论文中使用的值是\(k = 2 , n =5 ,\alpha = 10^{-4},\beta = 0.75\)

输出\(b^i_{x,y}\)和输入\(a_{x,y}^j\)的上标表示的是当前值所在的通道,也即是叠加的方向是沿着通道进行。将要归一化的值\(a_{x,y}^i\)所在附近通道相同位置的值的平方累加起来\(\sum _{j = max(0, i-n / 2)} ^{min(N-1, i+n / 2)} (a_{x,y}^j)^2\)

Dropout

这个是比较常用的抑制过拟合的方法了。

引入Dropout主要是为了防止过拟合。在神经网络中Dropout通过修改神经网络本身结构来实现,对于某一层的神经元,通过定义的概率将神经元置为0,这个神经元就不参与前向和后向传播,就如同在网络中被删除了一样,同时保持输入层与输出层神经元的个数不变,然后按照神经网络的学习方法进行参数更新。在下一次迭代中,又重新随机删除一些神经元(置为0),直至训练结束。

Dropout应该算是AlexNet中一个很大的创新,现在神经网络中的必备结构之一。Dropout也可以看成是一种模型组合,每次生成的网络结构都不一样,通过组合多个模型的方式能够有效地减少过拟合,Dropout只需要两倍的训练时间即可实现模型组合(类似取平均)的效果,非常高效。

如下图:

Alex网络结构

上图中的输入是\(224\times224\),不过经过计算\((224 - 11) / 4 = 54.75\)并不是论文中的\(55 \times 55\),而使用\(227 \times 227\)作为输入,则\((227 - 11) / 4 = 55\)

网络包含8个带权重的层;前5层是卷积层,剩下的3层是全连接层。最后一层全连接层的输出是1000维softmax的输入,softmax会产生1000类标签的分布网络包含8个带权重的层;前5层是卷积层,剩下的3层是全连接层。最后一层全连接层的输出是1000维softmax的输入,softmax会产生1000类标签的分布。

  • 卷积层C1

    该层的处理流程是: 卷积-->ReLU-->池化-->归一化。

    • 卷积,输入是\(227\times227\),使用96个\(11 \times 11 \times 3\)的卷积核,得到的FeatureMap为\(55 \times 55 \times 96\)。
    • ReLU,将卷积层输出的FeatureMap输入到ReLU函数中。
    • 池化,使用\(3 \times 3\)步长为2的池化单元(重叠池化,步长小于池化单元的宽度),输出为\(27 \times 27 \times 96\)(\((55 - 3) / 2 + 1 = 27\))
    • 局部响应归一化,使用\(k = 2 , n =5 ,\alpha = 10^{-4},\beta = 0.75\)进行局部归一化,输出的仍然为\(27 \times 27 \times 96\),输出分为两组,每组的大小为\(27 \times 27 \times 48\)
  • 卷积层C2

    该层的处理流程是:卷积-->ReLU-->池化-->归一化

    • 卷积,输入是2组\(27 \times 27 \times 48\)。使用2组,每组128个尺寸为\(5 \times 5 \times 48\)的卷积核,并作了边缘填充padding=2,卷积的步长为1. 则输出的FeatureMap为2组,每组的大小为\(27 \times 27 \ times 128\). (\((27 + 2 * 2 - 5) / 1 + 1 = 27\))
    • ReLU,将卷积层输出的FeatureMap输入到ReLU函数中
    • 池化运算的尺寸为\(3\times3\),步长为2,池化后图像的尺寸为\((27-3)/2+1=13\),输出为\(13 \times 13 \times 256\)
    • 局部响应归一化,使用\(k = 2 , n =5 ,\alpha = 10^{-4},\beta = 0.75\)进行局部归一化,输出的仍然为\(13 \times 13 \times 256\),输出分为2组,每组的大小为\(13 \times 13 \times 128\)
  • 卷积层C3

    该层的处理流程是: 卷积-->ReLU

    • 卷积,输入是\(13 \times 13 \times 256\),使用2组共384尺寸为\(3 \times 3 \times 256\)的卷积核,做了边缘填充padding=1,卷积的步长为1.则输出的FeatureMap为\(13 \times 13 \ times 384\)
    • ReLU,将卷积层输出的FeatureMap输入到ReLU函数中
  • 卷积层C4

    该层的处理流程是: 卷积-->ReLU

    该层和C3类似。

    • 卷积,输入是\(13 \times 13 \times 384\),分为两组,每组为\(13 \times 13 \times192\).使用2组,每组192个尺寸为\(3 \times 3 \times 192\)的卷积核,做了边缘填充padding=1,卷积的步长为1.则输出的FeatureMap为\(13 \times 13 \ times 384\),分为两组,每组为\(13 \times 13 \times192\)
    • ReLU,将卷积层输出的FeatureMap输入到ReLU函数中
  • 卷积层C5

    该层处理流程为:卷积-->ReLU-->池化

    • 卷积,输入为\(13 \times 13 \times 384\),分为两组,每组为\(13 \times 13 \times192\)。使用2组,每组为128尺寸为\(3 \times 3 \times 192\)的卷积核,做了边缘填充padding=1,卷积的步长为1.则输出的FeatureMap为\(13 \times 13 \times 256\)
    • ReLU,将卷积层输出的FeatureMap输入到ReLU函数中
    • 池化,池化运算的尺寸为3×3,步长为2,池化后图像的尺寸为 \((13-3)/2+1=6\),即池化后的输出为\(6 \times 6 \times 256\)
  • 全连接层FC6

    该层的流程为:(卷积)全连接 -->ReLU -->Dropout

    • 卷积->全连接: 输入为\(6 \times 6 \times 256\),该层有4096个卷积核,每个卷积核的大小为\(6 \times 6 \times 256\)。由于卷积核的尺寸刚好与待处理特征图(输入)的尺寸相同,即卷积核中的每个系数只与特征图(输入)尺寸的一个像素值相乘,一一对应,因此,该层被称为全连接层。由于卷积核与特征图的尺寸相同,卷积运算后只有一个值,因此,卷积后的像素层尺寸为\(4096\times1\times1\),即有4096个神经元。
    • ReLU,这4096个运算结果通过ReLU激活函数生成4096个值
    • Dropout,抑制过拟合,随机的断开某些神经元的连接或者是不激活某些神经元
  • 全连接层FC7

    流程为:全连接-->ReLU-->Dropout

    • 全连接,输入为4096的向量
    • ReLU,这4096个运算结果通过ReLU激活函数生成4096个值
    • Dropout,抑制过拟合,随机的断开某些神经元的连接或者是不激活某些神经元
  • 输出层

    第七层输出的4096个数据与第八层的1000个神经元进行全连接,经过训练后输出1000个float型的值,这就是预测结果。

AlexNet参数数量

卷积层的参数 = 卷积核的数量 * 卷积核 + 偏置

  • C1: 96个\(11 \times 11 \times 3\)的卷积核,$96 \times 11 \times 11 \times 3 + 96=34848 $
  • C2: 2组,每组128个\(5 \times 5 \times 48\)的卷积核,\((128 \times 5 \times 5 \times 48 + 128)\times 2 = 307456\)
  • C3: 384个\(3 \times 3 \times 256\)的卷积核,\(3 \times 3 \times 256 \times 384 + 384 = 885120\)
  • C4: 2组,每组192个\(3 \times 3 \times 192\)的卷积核,\((3 \times 3 \times 192 \times 192 + 192)\times 2= 663936\)
  • C5: 2组,每组128个\(3 \times 3 \times 192\)的卷积核,\((3 \times 3 \times 192 \times 128 + 128) \times 2 = 442624\)
  • FC6: 4096个\(6 \times 6 \times 256\)的卷积核,\(6 \times 6 \times 256 \times 4096 + 4096 = 37752832\)
  • FC7: \(4096 * 4096 + 4096 = 16781312\)
  • output: \(4096 * 1000 = 4096000\)

卷积层 C2,C4,C5中的卷积核只和位于同一GPU的上一层的FeatureMap相连。从上面可以看出,参数大多数集中在全连接层,在卷积层由于权值共享,权值参数较少。

Keras实现

由于AlexNet是使用两块显卡进行训练的,其网络结构的实际是分组进行的。并且,在C2,C4,C5上其卷积核只和上一层的同一个GPU上的卷积核相连。 对于单显卡来说,并不适用,本文基于Keras的实现,忽略其关于双显卡的的结构,并且将局部归一化操作换成了BN。其网络结构如下:

Keras代码

class AlexNet:
@staticmethod
def build(width,height,depth,classes,reg=0.0002):
model = Sequential()
inputShape = (height,width,depth)
chanDim = -1 if K.image_data_format() == "channels_first":
inputShape = (depth,height,width)
chanDim = 1 model.add(Conv2D(96,(11,11),strides=(4,4),input_shape=inputShape,padding="same",kernel_regularizer=l2(reg)))
model.add(Activation("relu"))
model.add(BatchNormalization(axis=chanDim))
model.add(MaxPooling2D(pool_size=(3,3),strides=(2,2)))
model.add(Dropout(0.25)) model.add(Conv2D(256,(5,5),padding="same",kernel_regularizer=l2(reg)))
model.add(Activation("relu"))
model.add(BatchNormalization(axis=chanDim))
model.add(MaxPooling2D(pool_size=(3,3),strides=(2,2)))
model.add(Dropout(0.25)) model.add(Conv2D(384,(3,3),padding="same",kernel_regularizer=l2(reg)))
model.add(Activation("relu"))
model.add(BatchNormalization(axis=chanDim))
model.add(Conv2D(384,(3,3),padding="same",kernel_regularizer=l2(reg)))
model.add(Activation("relu"))
model.add(BatchNormalization(axis=chanDim))
model.add(Conv2D(256,(3,3),padding="same",kernel_regularizer=l2(reg)))
model.add(MaxPooling2D(pool_size=(3,3),strides=(2,2)))
model.add(Dropout(0.25)) model.add(Flatten())
model.add(Dense(4096,kernel_regularizer=l2(reg)))
model.add(Activation("relu"))
model.add(BatchNormalization())
model.add(Dropout(0.25)) model.add(Dense(4096,kernel_regularizer=l2(reg)))
model.add(Activation("relu"))
model.add(BatchNormalization())
model.add(Dropout(0.25)) model.add(Dense(classes,kernel_regularizer=l2(reg)))
model.add(Activation("softmax")) return model

更多测测试代码,可以从我的github上找到。

卷积神经网络之AlexNet的更多相关文章

  1. 第十六节,卷积神经网络之AlexNet网络实现(六)

    上一节内容已经详细介绍了AlexNet的网络结构.这节主要通过Tensorflow来实现AlexNet. 这里做测试我们使用的是CIFAR-10数据集介绍数据集,关于该数据集的具体信息可以通过以下链接 ...

  2. 第十五节,卷积神经网络之AlexNet网络详解(五)

    原文 ImageNet Classification with Deep ConvolutionalNeural Networks 下载地址:http://papers.nips.cc/paper/4 ...

  3. 卷积神经网络之AlexNet网络模型学习

    ImageNet Classification with Deep Convolutional Neural Networks 论文理解  在ImageNet LSVRC-2010上首次使用大型深度卷 ...

  4. TensorFlow实战:Chapter-4(CNN-2-经典卷积神经网络(AlexNet、VGGNet))

    转载自:http://blog.csdn.net/u011974639/article/details/76146822 项目:https://www.cs.toronto.edu/~frossard ...

  5. 卷积神经网络之LeNet

    开局一张图,内容全靠编. 上图引用自 [卷积神经网络-进化史]从LeNet到AlexNet. 目前常用的卷积神经网络 深度学习现在是百花齐放,各种网络结构层出不穷,计划梳理下各个常用的卷积神经网络结构 ...

  6. TensorFlow实战之实现AlexNet经典卷积神经网络

    本文根据最近学习TensorFlow书籍网络文章的情况,特将一些学习心得做了总结,详情如下.如有不当之处,请各位大拿多多指点,在此谢过. 一.AlexNet模型及其基本原理阐述 1.关于AlexNet ...

  7. 经典卷积神经网络(LeNet、AlexNet、VGG、GoogleNet、ResNet)的实现(MXNet版本)

    卷积神经网络(Convolutional Neural Network, CNN)是一种前馈神经网络,它的人工神经元可以响应一部分覆盖范围内的周围单元,对于大型图像处理有出色表现. 其中 文章 详解卷 ...

  8. 深度学习——卷积神经网络 的经典网络(LeNet-5、AlexNet、ZFNet、VGG-16、GoogLeNet、ResNet)

    一.CNN卷积神经网络的经典网络综述 下面图片参照博客:http://blog.csdn.net/cyh_24/article/details/51440344 二.LeNet-5网络 输入尺寸:32 ...

  9. 卷积神经网络的一些经典网络(Lenet,AlexNet,VGG16,ResNet)

    LeNet – 5网络 网络结构为: 输入图像是:32x32x1的灰度图像 卷积核:5x5,stride=1 得到Conv1:28x28x6 池化层:2x2,stride=2 (池化之后再经过激活函数 ...

随机推荐

  1. Windows下Markdown软件的选择

    从开始Java学习这个系列的同时,我也开始改用Markdown而不是无比蛋疼的博客园默认编辑器来进行博客管理.但是Windows下想找一个比较好的Markdown编辑器蛮困难的,可以说专门的Markd ...

  2. 初入thinkphp

    花3天时间入门了php和thinkphp框架,紧接着就做了一个小后台,简单使用了thinkphp框架封装的一些类和函数. 现在来总结一下:             //登陆函数 public func ...

  3. 高性能网络通信框架 HP-Socket

      HP-Socket 详细介绍 HP-Socket 是一套通用的高性能 TCP/UDP/HTTP 通信框架,包含服务端组件.客户端组件和Agent组件,广泛适用于各种不同应用场景的 TCP/UDP/ ...

  4. IDEA安装教程

    1.下载安装程序A,链接:https://pan.baidu.com/s/1IAsGDbApfyNsHuS7_m0rdw 密码:fthp 2.下载一个配置程序B,下载安装之后,暂时不用管,之后会用到. ...

  5. hdu-2683 TCE-frep number system---完全数+二项展开式

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2683 题目大意: g(n)是n的因子和 两种操作: A a b 查询a b区间有多少个n满足上式. ...

  6. Quartz学习--二 Hello Quartz! 和源码分析

    Quartz学习--二  Hello Quartz! 和源码分析 三.  Hello Quartz! 我会跟着 第一章 6.2 的图来 进行同步代码编写 简单入门示例: 创建一个新的java普通工程 ...

  7. 用ECMAScript4 ( ActionScript3) 实现Unity的热更新 -- 使用FairyGUI (二)

    上次讲解了FairyGUI的最简单的热更新办法,并对其中一个Demo进行了修改并做成了热更新的方式. 这次我们来一个更加复杂一些的情况:Emoji. FairyGUI的   Example 04 - ...

  8. linux几种定时函数的使用

    Linux定时函数介绍: 在程序开发过程中,我们时不时要用到一些定时器,通常如果时间精度要求不高,可以使用sleep,uslepp函数让进程睡眠一段时间来实现定时, 前者单位为秒(s),后者为微妙(u ...

  9. SSM-SpringMVC-31:SpringMVC中利用hibernate-validator做后台校验

    ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 校验有三种:前台页面校验(例如js和h5),后台校验,数据库校验 但是一般能不用数据库校验就不用数据库校验,因 ...

  10. python自定义库文件路径

    各有各的小烦恼,各有的小期待 这是人家私事,不要大嘴巴 在Pycharm中import whois时,总是失败 原因是安装了python3.x相关操作过程,将环境变量path中关于Python的配置c ...