alexnet_alexnet pytorch - CSDN
alexnet 订阅
AlexNet是2012年ImageNet竞赛冠军获得者Hinton和他的学生Alex Krizhevsky设计的。也是在那年之后,更多的更深的神经网络被提出,比如优秀的vgg,GoogLeNet。 这对于传统的机器学习分类算法而言,已经相当的出色。 展开全文
AlexNet是2012年ImageNet竞赛冠军获得者Hinton和他的学生Alex Krizhevsky设计的。也是在那年之后,更多的更深的神经网络被提出,比如优秀的vgg,GoogLeNet。 这对于传统的机器学习分类算法而言,已经相当的出色。
信息
提出者
Hinton及其学生
类    型
神经网络
外文名
AlexNet
提出时间
2012
AlexNet模型简介
AlexNet中包含了几个比较新的技术点,也首次在CNN中成功应用了ReLU、Dropout和LRN等Trick。同时AlexNet也使用了GPU进行运算加速。AlexNet将LeNet的思想发扬光大,把CNN的基本原理应用到了很深很宽的网络中。AlexNet主要使用到的新技术点如下:(1)成功使用ReLU作为CNN的激活函数,并验证其效果在较深的网络超过了Sigmoid,成功解决了Sigmoid在网络较深时的梯度弥散问题。虽然ReLU激活函数在很久之前就被提出了,但是直到AlexNet的出现才将其发扬光大。(2)训练时使用Dropout随机忽略一部分神经元,以避免模型过拟合。Dropout虽有单独的论文论述,但是AlexNet将其实用化,通过实践证实了它的效果。在AlexNet中主要是最后几个全连接层使用了Dropout。(3)在CNN中使用重叠的最大池化。此前CNN中普遍使用平均池化,AlexNet全部使用最大池化,避免平均池化的模糊化效果。并且AlexNet中提出让步长比池化核的尺寸小,这样池化层的输出之间会有重叠和覆盖,提升了特征的丰富性。(4)提出了LRN层,对局部神经元的活动创建竞争机制,使得其中响应比较大的值变得相对更大,并抑制其他反馈较小的神经元,增强了模型的泛化能力。(5)使用CUDA加速深度卷积网络的训练,利用GPU强大的并行计算能力,处理神经网络训练时大量的矩阵运算。AlexNet使用了两块GTX 580 GPU进行训练,单个GTX 580只有3GB显存,这限制了可训练的网络的最大规模。因此作者将AlexNet分布在两个GPU上,在每个GPU的显存中储存一半的神经元的参数。因为GPU之间通信方便,可以互相访问显存,而不需要通过主机内存,所以同时使用多块GPU也是非常高效的。同时,AlexNet的设计让GPU之间的通信只在网络的某些层进行,控制了通信的性能损耗。 (6)数据增强,随机地从256*256的原始图像中截取224*224大小的区域(以及水平翻转的镜像),相当于增加了2*(256-224)^2=2048倍的数据量。如果没有数据增强,仅靠原始的数据量,参数众多的CNN会陷入过拟合中,使用了数据增强后可以大大减轻过拟合,提升泛化能力。进行预测时,则是取图片的四个角加中间共5个位置,并进行左右翻转,一共获得10张图片,对他们进行预测并对10次结果求均值。同时,AlexNet论文中提到了会对图像的RGB数据进行PCA处理,并对主成分做一个标准差为0.1的高斯扰动,增加一些噪声,这个Trick可以让错误率再下降1%。 [1]  AlexNet结构图(3张)
收起全文
精华内容
参与话题
  • AlexNet网络介绍

    千次阅读 2018-03-04 20:59:18
    本文转自红黑联盟https://www.2cto.com/kf/201608/533035.html1LeNet-51.1局限性早在1989年,Yann LeCun (现纽约大学教授)和他的同事们就发表了卷积神经网络(Convolution NeuralNetworks, 简称CNN)的工作。...

    本文转自红黑联盟https://www.2cto.com/kf/201608/533035.html

    1LeNet-5

    1.1局限性

    早在1989年,Yann LeCun (现纽约大学教授)和他的同事们就发表了卷积神经网络(Convolution NeuralNetworks, 简称CNN)的工作。在很长时间里,CNN虽然在小规模的问题上,如手写数字,取得过当时世界最好结果,但一直没有取得巨大成功。这主要原因是,CNN在大规模图像上效果不好,比如像素很多的自然图片内容理解,所以没有得到计算机视觉领域的足够重视。

    这个惊人的结果为什么在之前没有发生? 原因当然包括算法的提升,比如dropout等防止过拟合技术,但最重要的是,GPU带来的计算能力提升和更多的训练数据。

     

    1.2理解

    \

    (1)为什么F6神经元是84维 ?

    \

    原文是用于手写字识别,手写字范围为0-9共有10个字符,因此输出OUTPUT层的节点共10个,可以把每个字符格式化为12*7的图像,如上图,共有84个像元,像元的参数成分(即像素值)可以设为1和-1,此时C5到F6是通过sigmod函数计算的,因此F6节点的值范围为-1到1,因此可以根据F6节点的值\和格式化图像\(参数向量)的值距离,来判断输入图像的类别,即通过径向基函数:

    \

    输入离参数向量越远,RBF输出的越大。

    所有训练参数和连接个数:

    \

     

    2AlexNet

    本深度学习网络是Alex和Hinton参加ILSVRC2012比赛的卷积网络论文,本网络结构也是开启ImageNet数据集更大,更深CNN的开山之作,本文对CNN的一些改进成为以后CNN网络通用的结构;在一些报告中被称为Alex-net,之后在Imagenet上取得更好结果的ZF-net,SPP-net,VGG等网络,都是在其基础上修改得到。

    原论文:ImageNet Classification with Deep ConvolutionalNeural Networks

    2.1结构介绍

    2.1.1ReLU非线性

    模拟神经元输出的标准函数一般是:tanh(x)或者sigmoid(x)函数,由于此类函数在x非常大或者非常小时,函数输出基本不变,所以此类函数成为饱和函数;f(x)=max(0,x),扭曲线性函数,是一种非线性的非饱和函数。在训练时间上,非饱和函数比饱和函数训练更快。而且这种扭曲线性函数,不但保留了非线性的表达能力,而且由于其具有线性性质(正值部分),相比tanh和sigmoid函数在误差反向传递时,不会有由于非线性引起的梯度弥散形象(顶层误差较大,由于逐层递减误差传递,引起低层误差很小,导致深度网络地层权值更新量很小,导致深度网络局部最优)。ReLU的这些性质可以让我们训练更深的网络。

     

    ReLu相关知识:http://www.mamicode.com/info-detail-873243.html

    2.1.2在多个GPU上训练

    单个GTX 580 GPU只有3GB内存,这限制了可以在其上训练的网络的最大规模。事实证明,120万个训练样本才足以训练网络,这网络太大了,不适合在一个GPU上训练。因此我们将网络分布在两个GPU上。目前的GPU特别适合跨GPU并行化,因为它们能够直接从另一个GPU的内存中读出和写入,不需要通过主机内存。我们采用的并行方案基本上是在每个GPU中放置一半核(或神经元),还有一个额外的技巧:GPU间的通讯只在某些层进行。这就是说,例如,第3层的核需要从第2层中所有核映射输入。然而,第4层的核只需要从第3层中位于同一GPU的那些核映射输入。选择连接模式是一个交叉验证的问题,但是这让我们可以精确地调整通信量,直到它的计算量在可接受的部分。

    2.1.3局部响应归一化

    ReLU具有所希望的特性,它们不需要输入归一化来防止它们达到饱和。如果至少有一些训练样例对ReLU产生了正输入,学习就将发生在那个神经元。可是,我们仍然发现下列局部归一化方案有助于一般化。用\表示点\处通过应用核 计算出的神经元激活度,然后应用ReLU非线性,响应归一化活性\由下式给出

    \

    其中求和覆盖了n个“相邻的”位于相同空间位置的核映射,N是该层中的核总数。核映射的顺序当然是任意的,且在训练开始前就确定。受到在真实神经元中发现的类型启发,这种响应归一化实现了一种侧向抑制,在使用不同核计算神经元输出的过程中创造对大激活度的竞争。常数k,n,α和β是超参数,它们的值要用验证集来确定;我们使用\。我们在某些层应用ReLU归一化后再应用这种归一化(见3.5节)。
    该方案与Jarrett等人的局部对比度归一化方案具有一些相似之处[11],但我们的方案更正确的命名为“亮度归一化”,因为我们不减去平均活跃度。响应归一化将我们的top-1与top-5误差率分别减少了1.4%与1.2%。我们也验证了该方案在CIFAR-10数据集上的有效性:四层CNN不带归一化时的测试误差率是13%,带归一化时是11%。

    2.1.4重叠Pooling

    CNN中的Pooling层总结了同一核映射中邻近神经元组的输出。传统上,通过邻接pooling单元总结的邻近关系不重叠(例如,[17,11,4])。更准确地说,一个pooling层可以被认为是由间隔s像素的pooling单元网格组成,每个网格总结出一个z×z大小的邻近关系,都位于pooling单元的中心位置。若设s=z,我们得到传统的局部pooling,正如常用于CNN中的那样。若设s<z,则得到有重叠pool。整个网络结构中,s=2,z=3,即pool区域的大小为3*3,间隔为2,即相邻两个pool,会重叠一个像素,这种方法使top-1和top-5错误率分别减少0.4%和0.3%,与s=2,z=2相比,它们池化结果有相同的维度,并且重叠pool在训练过程中不容易产生过拟合。< p="">

    2.1.5减少过拟合

    我们的神经网络结构有6000万个参数。虽然ILSVRC的1000个类别,使得每个训练样本在图像到标签的映射上强加了10比特约束,事实上学习如此多的参数而不带相当大的过拟合,这些类别是不够的。下面,我们描述减少过拟合的两种主要方法。

    <1>数据扩充

    对于图像数据来说,减少过拟合问题,最早使用的同时也是最常用的方法就是,在保持数据标签不变的情况下增大数据集。这里我们使用了两种不同的方法,它们都只需要很少的计算量,因此变换后的图像并不需要存储在硬盘中,而只需要存放在内存中即可。在我们的实现中,转换图像是由CPU上的Python代码生成的,与此同时,在GPU上训练先前产生的图像,因此这些数据扩展方案是计算自由的。

    (1)图像平移和翻转

    我们从256×256的图像中提取随机的224×224的碎片(还有它们的水平反射),并在这些提取的碎片上训练我们的网络(这就是图2中输入图像是224×224×3维的原因)。这使得我们的训练集规模扩大了2048倍(32*32*2=2048),但是由此产生的训练样例一定高度地相互依赖。如果没有这个方案,我们的网络会有大量的过拟合,这将迫使我们使用小得多的网络。在测试时,该网络通过提取五个224×224的碎片(四个边角碎片和中心碎片)连同它们的水平反射(因此总共是十个碎片)做出了预测,并在这十个碎片上来平均该网络的softmax层做出的预测。

     

    (2)调整RGB像素值

    具体来说,我们在遍及整个ImageNet训练集的RGB像素值集合中执行PCA。对于每个训练图像,我们成倍增加已有主成分,比例大小为对应特征值乘以一个从均值为0,标准差为0.1的高斯分布中提取的随机变量。这样一来,对于每个RGB图像像素\,我们增加下面这项:\

    其中\\分别是RGB像素值的3×3协方差矩阵的第i个特征向量与特征值,是\前面提到的随机变量。每个\对于特定训练图像的全部像素只提取一次,直到那个图像再次被用于训练,在那时它被重新提取。这个方案大致抓住了自然图像的一个重要属性,即,光照强度与颜色是变化的,而对象识别是不变的。该方案将top-1误差率减少了1%以上。

     

    <2>Dropout

    结合许多不同模型的预测是一种非常成功的减少测试误差的方式[1,3],但它先前训练花了好几天时间,似乎对于大型神经网络来说太过昂贵。然而,有一个非常有效的模型组合版本,它在训练中只花费两倍于单模型的时间。最近推出的叫做“dropout”的技术[10],它做的就是以0.5的概率将每个隐层神经元的输出设置为零。以这种方式“dropped out”的神经元既不参与前向传播,也不参与反向传播。所以每次提出一个输入,该神经网络就尝试一个不同的结构,但是所有这些结构之间共享权重。因为神经元不能依赖于其他特定神经元而存在,所以这种技术降低了神经元复杂的互适应关系。正因如此,要被迫学习更为鲁棒的特征,这些特征在结合其他神经元的一些不同随机子集时有用。在测试时,我们将所有神经元的输出都仅仅只乘以0.5,对于获取指数级dropout网络产生的预测分布的几何平均值,这是一个合理的近似方法。
    前两个全连接层使用dropout。如果没有dropout,我们的网络会表现出大量的过拟合。dropout使收敛所需的迭代次数大致增加了一倍。

    理解:每次选择一半的节点进行连接构成网络,只在被选中参与连接的节点上进行正向和反向传播,如下图,左侧是全连接形式,右边是一半节点构成的网络:

    \

    为什么有助于防止过拟合呢?可以简单地这样解释,运用了dropout的训练过程,相当于训练了很多个只有半数隐层单元的神经网络(后面简称为“半数网络”),每一个这样的半数网络,都可以给出一个分类结果,这些结果有的是正确的,有的是错误的。随着训练的进行,大部分半数网络都可以给出正确的分类结果,那么少数的错误分类结果就不会对最终结果造成大的影响。

    Dropout相关知识:http://www.mamicode.com/info-detail-517504.html

    2.2总体结构

    2.2.1总体介绍

    \

     

    该网络包括八个带权层;前五层是卷积层,剩下三层是全连接层。最后一个全连接层的输出被送到一个1000-way的softmax层,其产生一个覆盖1000类标签的分布。我们的网络使得多分类的Logistic回归目标最大化,这相当于最大化了预测分布下训练样本中正确标签的对数概率平均值。

    第二、第四和第五个卷积层的核只连接到前一个卷积层也位于同一GPU中的那些核映射上(见图2)。第三个卷积层的核被连接到第二个卷积层中的所有核映射上。全连接层中的神经元被连接到前一层中所有的神经元上。响应归一化层跟在第一、第二个卷积层后面。最大Pooling层,跟在响应归一化层以及第五个卷积层之后。ReLU非线性应用于每个卷积层及全连接层的输出。
    第一个卷积层利用96个大小为11×11×3、步长为4个像素(这是同一核映射中邻近神经元的感受野中心之间的距离)的核,来对大小为224×224×3的输入图像进行滤波。第二个卷积层需要将第一个卷积层的(响应归一化及池化的)输出作为自己的输入,且利用256个大小为5×5×48的核对其进行滤波(注:48对应第一层得到的48个map,即第一层的所有map卷积生成第二层的一个map图)。第三、第四和第五个卷积层彼此相连,没有任何介于中间的pooling层与归一化层。第三个卷积层有384个大小为3×3×256的核被连接到第二个卷积层的(归一化的、池化的)输出。第四个卷积层拥有384个大小为3×3×192的核,第五个卷积层拥有256个大小为3×3×192的核。全连接层都各有4096个神经元。

    2.2.2各层运算、维度和参数

    \

    \

     

    \

     

    \

     

    \

    \

    \

    \

    \

    \

     

     

     

    2.3学习过程

    我们使用随机梯度下降法和一批大小为128、动力为0.9、权重衰减为0.0005的样例来训练我们的网络。我们发现,这少量的权重衰减对于模型学习是重要的。换句话说,这里的权重衰减不仅仅是一个正则化矩阵:它减少了模型的训练误差。对于权重w的更新规则为
    \
    其中i是迭代指数,v是动力变量,ε是学习率,\是目标关于w、对\求值的导数在第i批样例上的平均值。
    我们用一个均值为0、标准差为0.01的高斯分布初始化了每一层的权重。我们用常数1初始化了第二、第四和第五个卷积层以及全连接隐层的神经元偏差。该初始化通过提供带正输入的ReLU来加速学习的初级阶段。我们在其余层用常数0初始化神经元偏差。
    对于所有层都使用了相等的学习率,这是在整个训练过程中手动调整的。我们遵循的启发式是,当验证误差率在当前学习率下不再提高时,就将学习率除以10。学习率初始化为0.01,在终止前降低三次。作者训练该网络时大致将这120万张图像的训练集循环了90次,在两个NVIDIA GTX 580 3GB GPU上花了五到六天。

    展开全文
  • 深度学习AlexNet模型详细分析

    万次阅读 多人点赞 2017-05-16 21:34:35
    Alex在2012年提出的alexnet网络结构模型引爆了神经网络的应用热潮,并赢得了2012届图像识别大赛的冠军,使得CNN成为在图像分类上的核心算法模型。 接下来本文对该网络配置结构中各个层进行详细的解读(训练阶段):...

    Alex2012提出的alexnet网络结构模型引爆了神经网络的应用热潮并赢得了2012届图像识别大赛的冠军,使得CNN成为在图像分类上的核心算法模型

    接下来本文对该网络配置结构中各个层进行详细的解读(训练阶段):

    注:下述关于卷积核的尺寸来自于Alex2012年发表的经典论文。


     

    1. conv1阶段DFDdata flow diagram):

     

    第一层输入数据为原始的227*227*3的图像,这个图像被11*11*3的卷积核进行卷积运算,卷积核对原始图像的每次卷积都生成一个新的像素。卷积核沿原始图像的x轴方向和y轴方向两个方向移动,移动的步长是4个像素。因此,卷积核在移动的过程中会生成(227-11)/4+1=55个像素(227个像素减去11,正好是54,即生成54个像素,再加上被减去的11也对应生成一个像素),行和列的55*55个像素形成对原始图像卷积之后的像素层。共有96个卷积核,会生成55*55*96个卷积后的像素层。96个卷积核分成2组,每组48个卷积核。对应生成255*55*48的卷积后的像素层数据。这些像素层经过relu1单元的处理,生成激活像素层,尺寸仍为255*55*48的像素层数据。

    这些像素层经过pool运算(池化运算)的处理,池化运算的尺度为3*3,运算的步长为2,则池化后图像的尺寸为(55-3)/2+1=27。 即池化后像素的规模为27*27*96;然后经过归一化处理,归一化运算的尺度为5*5;第一卷积层运算结束后形成的像素层的规模为27*27*96。分别对应96个卷积核所运算形成。这96层像素层分为2组,每组48个像素层,每组在一个独立的GPU上进行运算。

    反向传播时,每个卷积核对应一个偏差值。即第一层的96个卷积核对应上层输入的96个偏差值。

    2. conv2阶段DFDdata flow diagram):

     

    第二层输入数据为第一层输出的27*27*96的像素层,为便于后续处理,每幅像素层的左右两边和上下两边都要填充2个像素;27*27*96的像素数据分成27*27*48的两组像素数据,两组数据分别再两个不同的GPU中进行运算。每组像素数据被5*5*48的卷积核进行卷积运算,卷积核对每组数据的每次卷积都生成一个新的像素。卷积核沿原始图像的x轴方向和y轴方向两个方向移动,移动的步长是1个像素。因此,卷积核在移动的过程中会生成(27-5+2*2)/1+1=27个像素。(27个像素减去5,正好是22,在加上上下、左右各填充的2个像素,即生成26个像素,再加上被减去的5也对应生成一个像素),行和列的27*27个像素形成对原始图像卷积之后的像素层。共有2565*5*48卷积核;这256个卷积核分成两组,每组针对一个GPU中的27*27*48的像素进行卷积运算。会生成两组27*27*128个卷积后的像素层。这些像素层经过relu2单元的处理,生成激活像素层,尺寸仍为两组27*27*128的像素层。

    这些像素层经过pool运算(池化运算)的处理,池化运算的尺度为3*3,运算的步长为2,则池化后图像的尺寸为(57-3)/2+1=13。 即池化后像素的规模为213*13*128的像素层;然后经过归一化处理,归一化运算的尺度为5*5;第二卷积层运算结束后形成的像素层的规模为213*13*128的像素层。分别对应2128个卷积核所运算形成。每组在一个GPU上进行运算。即共256个卷积核,共2GPU进行运算。

    反向传播时,每个卷积核对应一个偏差值。即第一层的96个卷积核对应上层输入的256个偏差值。

     

    3. conv3阶段DFDdata flow diagram):

     

    第三层输入数据为第二层输出的213*13*128的像素层;为便于后续处理,每幅像素层的左右两边和上下两边都要填充1个像素;2组像素层数据都被送至2个不同的GPU中进行运算。每个GPU中都有192个卷积核,每个卷积核的尺寸是3*3*256。因此,每个GPU中的卷积核都能对213*13*128的像素层的所有数据进行卷积运算。卷积核对每组数据的每次卷积都生成一个新的像素。卷积核沿像素层数据的x轴方向和y轴方向两个方向移动,移动的步长是1个像素。因此,运算后的卷积核的尺寸为(13-3+1*2)/1+1=1313个像素减去3,正好是10,在加上上下、左右各填充的1个像素,即生成12个像素,再加上被减去的3也对应生成一个像素),每个GPU中共13*13*192个卷积核。2GPU中共13*13*384个卷积后的像素层。这些像素层经过relu3单元的处理,生成激活像素层,尺寸仍为213*13*192像素层,共13*13*384个像素层。

     

    4. conv4阶段DFDdata flow diagram):

     

    第四层输入数据为第三层输出的213*13*192的像素层;为便于后续处理,每幅像素层的左右两边和上下两边都要填充1个像素;2组像素层数据都被送至2个不同的GPU中进行运算。每个GPU中都有192个卷积核,每个卷积核的尺寸是3*3*192。因此,每个GPU中的卷积核能对113*13*192的像素层的数据进行卷积运算。卷积核对每组数据的每次卷积都生成一个新的像素。卷积核沿像素层数据的x轴方向和y轴方向两个方向移动,移动的步长是1个像素。因此,运算后的卷积核的尺寸为(13-3+1*2)/1+1=1313个像素减去3,正好是10,在加上上下、左右各填充的1个像素,即生成12个像素,再加上被减去的3也对应生成一个像素),每个GPU中共13*13*192个卷积核。2GPU中共13*13*384个卷积后的像素层。这些像素层经过relu4单元的处理,生成激活像素层,尺寸仍为213*13*192像素层,共13*13*384个像素层。

     

    5. conv5阶段DFDdata flow diagram):

     

    第五层输入数据为第四层输出的213*13*192的像素层;为便于后续处理,每幅像素层的左右两边和上下两边都要填充1个像素;2组像素层数据都被送至2个不同的GPU中进行运算。每个GPU中都有128个卷积核,每个卷积核的尺寸是3*3*192。因此,每个GPU中的卷积核能对113*13*192的像素层的数据进行卷积运算。卷积核对每组数据的每次卷积都生成一个新的像素。卷积核沿像素层数据的x轴方向和y轴方向两个方向移动,移动的步长是1个像素。因此,运算后的卷积核的尺寸为(13-3+1*2)/1+1=1313个像素减去3,正好是10,在加上上下、左右各填充的1个像素,即生成12个像素,再加上被减去的3也对应生成一个像素),每个GPU中共13*13*128个卷积核。2GPU中共13*13*256个卷积后的像素层。这些像素层经过relu5单元的处理,生成激活像素层,尺寸仍为213*13*128像素层,共13*13*256个像素层。

    213*13*128像素层分别在2个不同GPU中进行池化(pool)运算处理。池化运算的尺度为3*3,运算的步长为2,则池化后图像的尺寸为(13-3)/2+1=6。 即池化后像素的规模为两组6*6*128的像素层数据,共6*6*256规模的像素层数据。

     

    6. fc6阶段DFDdata flow diagram):

     

    第六层输入数据的尺寸是6*6*256,采用6*6*256尺寸的滤波器对第层的输入数据进行卷积运算;每个6*6*256尺寸的滤波器对第层的输入数据进行卷积运算生成一个运算结果,通过一个神经元输出这个运算结果;共有40966*6*256尺寸的滤波器输入数据进行卷积运算,通过4096个神经元输出运算结果;这4096运算结果通过relu激活函数生成4096并通过drop运算后输出4096本层的输出结果值。

         由于第六层的运算过程中,采用的滤波器的尺寸(6*6*256)待处理的feature map的尺寸(6*6*256)相同即滤波器中的每个系数只与feature map中的一个像素相乘而其它卷积层,每个滤波器的系数都会与多个feature map像素值相乘;因此第六层称为全连接层。

    第五层输出的6*6*256规模的像素层数据与第六层的4096个神经元进行全连接,然后经由relu6进行处理后生成4096个数据,再经过dropout6处理后输出4096个数据。

     

    7. fc7阶段DFDdata flow diagram):

     

    第六层输出的4096个数据与第七层的4096个神经元进行全连接,然后经由relu7进行处理后生成4096个数据,再经过dropout7处理后输出4096个数据。

     

    8. fc8阶段DFDdata flow diagram):

     

    第七层输出的4096个数据与第八层的1000个神经元进行全连接,经过训练后输出被训练的数值。

     

    Alexnet网络中各个层发挥的作用如下表所述:

     

    在学习过程中我们使用随机梯度下降法和一批大小为128、动力为0.9、权重衰减为0.0005的样例来训练我们的网络。我们发现,这少量的权重衰减对于模型学习是重要的。换句话说,这里的权重衰减不仅仅是一个正则化矩阵:它减少了模型的训练误差。对于权重w的更新规则为:


    其中i是迭代指数,v是动力变量,ε是学习率,是目标关于w、对求值的导数在第i批样例上的平均值。我们用一个均值为0、标准差为0.01的高斯分布初始化了每一层的权重。我们用常数1初始化了第二、第四和第五个卷积层以及全连接隐层的神经元偏差。该初始化通过提供带正输入的ReLU来加速学习的初级阶段。我们在其余层用常数0初始化神经元偏差。
        对于所有层都使用了相等的学习率,这是在整个训练过程中手动调整的。我们遵循的启发式是,当验证误差率在当前学习率下不再提高时,就将学习率除以10。学习率初始化为0.01,在终止前降低三次。作者训练该网络时大致将这120万张图像的训练集循环了90次,在两个NVIDIA GTX 580 3GB GPU上花了五到六天。

     

    各种layeroperation更多解释可以参考http://caffe.berkeleyvision.org/tutorial/layers.html

    从计算该模型的数据流过程中,该模型参数大概5kw+

    caffe开源的model样例中,它也给出了alexnet的复现,具体网络配置文件如下https://github.com/BVLC/caffe/blob/master/models/bvlc_reference_caffenet/train_val.prototxt

     

    caffe的输出中也有包含这块的内容日志,详情如下:

    1. I0721 10:38:15.326920  4692 net.cpp:125] Top shape: 256 3 227 227 (39574272) output data of layer 0

    2. I0721 10:38:15.326971  4692 net.cpp:125] Top shape: 256 1 1 1 (256)  

    3. I0721 10:38:15.326982  4692 net.cpp:156] data does not need backward computation.  

    4. I0721 10:38:15.327003  4692 net.cpp:74] Creating Layer conv1  

    5. I0721 10:38:15.327011  4692 net.cpp:84] conv1 <- data  

    6. I0721 10:38:15.327033  4692 net.cpp:110] conv1 -> conv1  

    7. I0721 10:38:16.721956  4692 net.cpp:125] Top shape: 256 96 55 55 (74342400)  

    8. I0721 10:38:16.722030  4692 net.cpp:151] conv1 needs backward computation.  

    9. I0721 10:38:16.722059  4692 net.cpp:74] Creating Layer relu1  

    10. I0721 10:38:16.722070  4692 net.cpp:84] relu1 <- conv1  

    11. I0721 10:38:16.722082  4692 net.cpp:98] relu1 -> conv1 (in-place)  

    12. I0721 10:38:16.722096  4692 net.cpp:125] Top shape: 256 96 55 55 (74342400)  

    13. I0721 10:38:16.722105  4692 net.cpp:151] relu1 needs backward computation.  

    14. I0721 10:38:16.722116  4692 net.cpp:74] Creating Layer pool1  

    15. I0721 10:38:16.722125  4692 net.cpp:84] pool1 <- conv1  

    16. I0721 10:38:16.722133  4692 net.cpp:110] pool1 -> pool1  

    17. I0721 10:38:16.722167  4692 net.cpp:125] Top shape: 256 96 27 27 (17915904)  

    18. I0721 10:38:16.722187  4692 net.cpp:151] pool1 needs backward computation.  

    19. I0721 10:38:16.722205  4692 net.cpp:74] Creating Layer norm1  

    20. I0721 10:38:16.722221  4692 net.cpp:84] norm1 <- pool1  

    21. I0721 10:38:16.722234  4692 net.cpp:110] norm1 -> norm1  

    22. I0721 10:38:16.722251  4692 net.cpp:125] Top shape: 256 96 27 27 (17915904)output data of layer 1

    23. I0721 10:38:16.722260  4692 net.cpp:151] norm1 needs backward computation.  

    24. I0721 10:38:16.722272  4692 net.cpp:74] Creating Layer conv2  

    25. I0721 10:38:16.722280  4692 net.cpp:84] conv2 <- norm1  

    26. I0721 10:38:16.722290  4692 net.cpp:110] conv2 -> conv2  

    27. I0721 10:38:16.725225  4692 net.cpp:125] Top shape: 256 256 27 27 (47775744)  

    28. I0721 10:38:16.725242  4692 net.cpp:151] conv2 needs backward computation.  

    29. I0721 10:38:16.725253  4692 net.cpp:74] Creating Layer relu2  

    30. I0721 10:38:16.725261  4692 net.cpp:84] relu2 <- conv2  

    31. I0721 10:38:16.725270  4692 net.cpp:98] relu2 -> conv2 (in-place)  

    32. I0721 10:38:16.725280  4692 net.cpp:125] Top shape: 256 256 27 27 (47775744)  

    33. I0721 10:38:16.725288  4692 net.cpp:151] relu2 needs backward computation.  

    34. I0721 10:38:16.725298  4692 net.cpp:74] Creating Layer pool2  

    35. I0721 10:38:16.725307  4692 net.cpp:84] pool2 <- conv2  

    36. I0721 10:38:16.725317  4692 net.cpp:110] pool2 -> pool2  

    37. I0721 10:38:16.725329  4692 net.cpp:125] Top shape: 256 256 13 13 (11075584)  

    38. I0721 10:38:16.725338  4692 net.cpp:151] pool2 needs backward computation.  

    39. I0721 10:38:16.725358  4692 net.cpp:74] Creating Layer norm2  

    40. I0721 10:38:16.725368  4692 net.cpp:84] norm2 <- pool2  

    41. I0721 10:38:16.725378  4692 net.cpp:110] norm2 -> norm2  

    42. I0721 10:38:16.725389  4692 net.cpp:125] Top shape: 256 256 13 13 (11075584)output data of layer 2

    43. I0721 10:38:16.725399  4692 net.cpp:151] norm2 needs backward computation.  

    44. I0721 10:38:16.725409  4692 net.cpp:74] Creating Layer conv3  

    45. I0721 10:38:16.725419  4692 net.cpp:84] conv3 <- norm2  

    46. I0721 10:38:16.725427  4692 net.cpp:110] conv3 -> conv3  

    47. I0721 10:38:16.735193  4692 net.cpp:125] Top shape: 256 384 13 13 (16613376)  

    48. I0721 10:38:16.735213  4692 net.cpp:151] conv3 needs backward computation.  

    49. I0721 10:38:16.735224  4692 net.cpp:74] Creating Layer relu3  

    50. I0721 10:38:16.735234  4692 net.cpp:84] relu3 <- conv3  

    51. I0721 10:38:16.735242  4692 net.cpp:98] relu3 -> conv3 (in-place)  

    52. I0721 10:38:16.735250  4692 net.cpp:125] Top shape: 256 384 13 13 (16613376)output data of layer 3

    53. I0721 10:38:16.735258  4692 net.cpp:151] relu3 needs backward computation.  

    54. I0721 10:38:16.735302  4692 net.cpp:74] Creating Layer conv4  

    55. I0721 10:38:16.735312  4692 net.cpp:84] conv4 <- conv3  

    56. I0721 10:38:16.735321  4692 net.cpp:110] conv4 -> conv4  

    57. I0721 10:38:16.743952  4692 net.cpp:125] Top shape: 256 384 13 13 (16613376)  

    58. I0721 10:38:16.743988  4692 net.cpp:151] conv4 needs backward computation.  

    59. I0721 10:38:16.744000  4692 net.cpp:74] Creating Layer relu4  

    60. I0721 10:38:16.744010  4692 net.cpp:84] relu4 <- conv4  

    61. I0721 10:38:16.744020  4692 net.cpp:98] relu4 -> conv4 (in-place)  

    62. I0721 10:38:16.744030  4692 net.cpp:125] Top shape: 256 384 13 13 (16613376)output data of layer 4

    63. I0721 10:38:16.744038  4692 net.cpp:151] relu4 needs backward computation.  

    64. I0721 10:38:16.744050  4692 net.cpp:74] Creating Layer conv5  

    65. I0721 10:38:16.744057  4692 net.cpp:84] conv5 <- conv4  

    66. I0721 10:38:16.744067  4692 net.cpp:110] conv5 -> conv5  

    67. I0721 10:38:16.748935  4692 net.cpp:125] Top shape: 256 256 13 13 (11075584)  

    68. I0721 10:38:16.748955  4692 net.cpp:151] conv5 needs backward computation.  

    69. I0721 10:38:16.748965  4692 net.cpp:74] Creating Layer relu5  

    70. I0721 10:38:16.748975  4692 net.cpp:84] relu5 <- conv5  

    71. I0721 10:38:16.748983  4692 net.cpp:98] relu5 -> conv5 (in-place)  

    72. I0721 10:38:16.748998  4692 net.cpp:125] Top shape: 256 256 13 13 (11075584)  

    73. I0721 10:38:16.749011  4692 net.cpp:151] relu5 needs backward computation.  

    74. I0721 10:38:16.749022  4692 net.cpp:74] Creating Layer pool5  

    75. I0721 10:38:16.749030  4692 net.cpp:84] pool5 <- conv5  

    76. I0721 10:38:16.749039  4692 net.cpp:110] pool5 -> pool5  

    77. I0721 10:38:16.749050  4692 net.cpp:125] Top shape: 256 256 6 6 (2359296)output data of layer 5

    78. I0721 10:38:16.749058  4692 net.cpp:151] pool5 needs backward computation.  

    79. I0721 10:38:16.749074  4692 net.cpp:74] Creating Layer fc6  

    80. I0721 10:38:16.749083  4692 net.cpp:84] fc6 <- pool5  

    81. I0721 10:38:16.749091  4692 net.cpp:110] fc6 -> fc6  

    82. I0721 10:38:17.160079  4692 net.cpp:125] Top shape: 256 4096 1 1 (1048576)  

    83. I0721 10:38:17.160148  4692 net.cpp:151] fc6 needs backward computation.  

    84. I0721 10:38:17.160166  4692 net.cpp:74] Creating Layer relu6  

    85. I0721 10:38:17.160177  4692 net.cpp:84] relu6 <- fc6  

    86. I0721 10:38:17.160190  4692 net.cpp:98] relu6 -> fc6 (in-place)  

    87. I0721 10:38:17.160202  4692 net.cpp:125] Top shape: 256 4096 1 1 (1048576)  

    88. I0721 10:38:17.160212  4692 net.cpp:151] relu6 needs backward computation.  

    89. I0721 10:38:17.160222  4692 net.cpp:74] Creating Layer drop6  

    90. I0721 10:38:17.160230  4692 net.cpp:84] drop6 <- fc6  

    91. I0721 10:38:17.160238  4692 net.cpp:98] drop6 -> fc6 (in-place)  

    92. I0721 10:38:17.160258  4692 net.cpp:125] Top shape: 256 4096 1 1 (1048576)output data of layer 6

    93. I0721 10:38:17.160265  4692 net.cpp:151] drop6 needs backward computation.  

    94. I0721 10:38:17.160277  4692 net.cpp:74] Creating Layer fc7  

    95. I0721 10:38:17.160286  4692 net.cpp:84] fc7 <- fc6  

    96. I0721 10:38:17.160295  4692 net.cpp:110] fc7 -> fc7  

    97. I0721 10:38:17.342094  4692 net.cpp:125] Top shape: 256 4096 1 1 (1048576)  

    98. I0721 10:38:17.342157  4692 net.cpp:151] fc7 needs backward computation.  

    99. I0721 10:38:17.342175  4692 net.cpp:74] Creating Layer relu7  

    100. I0721 10:38:17.342185  4692 net.cpp:84] relu7 <- fc7  

    101. I0721 10:38:17.342198  4692 net.cpp:98] relu7 -> fc7 (in-place)  

    102. I0721 10:38:17.342208  4692 net.cpp:125] Top shape: 256 4096 1 1 (1048576)  

    103. I0721 10:38:17.342217  4692 net.cpp:151] relu7 needs backward computation.  

    104. I0721 10:38:17.342228  4692 net.cpp:74] Creating Layer drop7  

    105. I0721 10:38:17.342236  4692 net.cpp:84] drop7 <- fc7  

    106. I0721 10:38:17.342245  4692 net.cpp:98] drop7 -> fc7 (in-place)  

    107. I0721 10:38:17.342254  4692 net.cpp:125] Top shape: 256 4096 1 1 (1048576)output data of layer 7

    108. I0721 10:38:17.342262  4692 net.cpp:151] drop7 needs backward computation.  

    109. I0721 10:38:17.342274  4692 net.cpp:74] Creating Layer fc8  

    110. I0721 10:38:17.342283  4692 net.cpp:84] fc8 <- fc7  

    111. I0721 10:38:17.342291  4692 net.cpp:110] fc8 -> fc8  

    112. I0721 10:38:17.343199  4692 net.cpp:125] Top shape: 256 22 1 1 (5632)  

    113. I0721 10:38:17.343214  4692 net.cpp:151] fc8 needs backward computation.  

    114. I0721 10:38:17.343231  4692 net.cpp:74] Creating Layer loss  

    115. I0721 10:38:17.343240  4692 net.cpp:84] loss <- fc8  

    116. I0721 10:38:17.343250  4692 net.cpp:84] loss <- label  

    117. I0721 10:38:17.343264  4692 net.cpp:151] loss needs backward computation.  

    118. I0721 10:38:17.343305  4692 net.cpp:173] Collecting Learning Rate and Weight Decay.  

    119. I0721 10:38:17.343327  4692 net.cpp:166] Network initialization done.  

    120. I0721 10:38:17.343335  4692 net.cpp:167] Memory required for Data 1073760256 

    展开全文
  • 【深度学习】AlexNet原理解析及实现

    万次阅读 多人点赞 2018-06-26 20:07:43
    【深度学习】AlexNet原理解析及实现 Alex提出的alexnet网络结构模型,在imagenet2012图像分类challenge上赢得了冠军。 要研究CNN类型DL网络模型在图像分类上的应用,就逃不开研究alexnet,这是CNN在图像分类上的...

    【深度学习】AlexNet原理解析及实现

        Alex提出的alexnet网络结构模型,在imagenet2012图像分类challenge上赢得了冠军。

        要研究CNN类型DL网络模型在图像分类上的应用,就逃不开研究alexnet,这是CNN在图像分类上的经典模型。

    一、Alexnet结构

    alexNet为8层深度网络,其中5层卷积层和3层全连接层,不计LRN层和池化层。如下图所示:

        

                                                                图 Alexnet结构

    详解各层训练参数的计算:

    前五层:卷积层


    后三层:全连接层

                        

    整体计算图:

      

    二、结构分析

            AlexNet每层的超参数如下图所示,其中输入尺寸为227*227,第一个卷积使用较大的核尺寸11*11,步长为4,有96个卷积核;紧接着一层LRN层;然后是最大池化层,核为3*3,步长为2。这之后的卷积层的核尺寸都比较小,5*5或3*3,并且步长为1,即扫描全图所有像素;而最大池化层依然为3*3,步长为2.

            我们可以发现,前几个卷积层的计算量很大,但参数量很小,只占Alexnet总参数的很小一部分。这就是卷积层的优点!通过较小的参数量来提取有效的特征。

            要注意,论文中指出,如果去掉任何一个卷积层,都会使网络的分类性能大幅下降。

                

    三、AlexNet的新技术点

        AlexNet的新技术点(即大牛论文的contribution),如下:

    (1)ReLU作为激活函数。

        ReLU为非饱和函数,论文中验证其效果在较深的网络超过了SIgmoid,成功解决了SIgmoid在网络较深时的梯度弥散问题

    (2)Dropout避免模型过拟合

        在训练时使用Dropout随机忽略一部分神经元,以避免模型过拟合。在alexnet的最后几个全连接层中使用了Dropout。

    (3)重叠的最大池化

        之前的CNN中普遍使用平均池化,而Alexnet全部使用最大池化,避免平均池化的模糊化效果。并且,池化的步长小于核尺寸,这样使得池化层的输出之间会有重叠和覆盖提升了特征的丰富性

    (4)提出LRN层

        提出LRN层,对局部神经元的活动创建竞争机制,使得响应较大的值变得相对更大,并抑制其他反馈较小的神经元,增强了模型的泛化能力。

    (5)GPU加速

    (6)数据增强

        随机从256*256的原始图像中截取224*224大小的区域(以及水平翻转的镜像),相当于增强了(256-224)*(256-224)*2=2048倍的数据量。使用了数据增强后,减轻过拟合,提升泛化能力。避免因为原始数据量的大小使得参数众多的CNN陷入过拟合中。

    四、AlexNet的搭建

        利用tensorflow实现ALexNet,环境为:win10+anaconda+python3+CPU(本人仅利用CPU,未使用GPU加速,所以最终模型训练速度较慢)。

        利用tensorboard可视化ALexNet结构为:

                

    (1)首先看一下卷积层的搭建:带有LRN和池化层的卷积层

        with tf.name_scope('conv1') as scope:
            """
            images:227*227*3
            kernel: 11*11 *64
            stride:4*4
            padding:name      
            
            #通过with tf.name_scope('conv1') as scope可以将scope内生成的Variable自动命名为conv1/xxx
            便于区分不同卷积层的组建
            
            input: images[227*227*3]
            middle: conv1[55*55*96]
            output: pool1 [27*27*96]
            
            """
            kernel=tf.Variable(tf.truncated_normal([11,11,3,96],
                               dtype=tf.float32,stddev=0.1),name="weights")
            conv=tf.nn.conv2d(images,kernel,[1,4,4,1],padding='SAME')
            biases=tf.Variable(tf.constant(0.0, shape=[96],  dtype=tf.float32),
                               trainable=True,name="biases")
            bias=tf.nn.bias_add(conv,biases) # w*x+b
            conv1=tf.nn.relu(bias,name=scope) # reLu
            print_architecture(conv1)
            parameters +=[kernel,biases]
    
            #添加LRN层和max_pool层
            """
            LRN会让前馈、反馈的速度大大降低(下降1/3),但最终效果不明显,所以只有ALEXNET用LRN,其他模型都放弃了
            """
            lrn1=tf.nn.lrn(conv1,depth_radius=4,bias=1,alpha=0.001/9,beta=0.75,name="lrn1")
            pool1=tf.nn.max_pool(lrn1,ksize=[1,3,3,1],strides=[1,2,2,1],
                                 padding="VALID",name="pool1")
            print_architecture(pool1)
    
    (2)卷积层的搭建:不带有LRN和池化层的卷积层
     with tf.name_scope('conv3') as scope:
            """
            input: pool2[13*13*256]
            output: conv3 [13*13*384]
    
            """
            kernel = tf.Variable(tf.truncated_normal([3, 3, 256, 384],
                                                     dtype=tf.float32, stddev=0.1), name="weights")
            conv = tf.nn.conv2d(pool2, kernel, [1, 1, 1, 1], padding='SAME')
            biases = tf.Variable(tf.constant(0.0, shape=[384], dtype=tf.float32),
                                 trainable=True, name="biases")
            bias = tf.nn.bias_add(conv, biases)  # w*x+b
            conv3 = tf.nn.relu(bias, name=scope)  # reLu
            parameters += [kernel, biases]
            print_architecture(conv3)

    3)全连接层的搭建

    #全连接层6
        with tf.name_scope('fc6') as scope:
            """
            input:pool5 [6*6*256]
            output:fc6 [4096]
            """
            kernel = tf.Variable(tf.truncated_normal([6*6*256,4096],
                                                     dtype=tf.float32, stddev=0.1), name="weights")
            biases = tf.Variable(tf.constant(0.0, shape=[4096], dtype=tf.float32),
                                 trainable=True, name="biases")
            # 输入数据变换
            flat = tf.reshape(pool5, [-1, 6*6*256] )  # 整形成m*n,列n为7*7*64
            # 进行全连接操作
            fc = tf.nn.relu(tf.matmul(flat, kernel) + biases,name='fc6')
            # 防止过拟合  nn.dropout
            fc6 = tf.nn.dropout(fc, keep_prob)
            parameters += [kernel, biases]
            print_architecture(fc6)

    (4)训练测试:

        因未下载ImageNet数据集(太大),只是简单的测试了一下alexnet的性能。使用的是随机生成的图片来作为训练数据。

    def time_compute(session,target,info_string):
        num_step_burn_in=10  #预热轮数,头几轮迭代有显存加载、cache命中等问题可以因此跳过
        total_duration=0.0   #总时间
        total_duration_squared=0.0
        for i in range(num_batch+num_step_burn_in):
            start_time=time.time()
            _ = session.run(target)
            duration= time.time() -start_time
            if i>= num_step_burn_in:
                if i%10==0: #每迭代10次显示一次duration
                    print("%s: step %d,duration=%.5f "% (datetime.now(),i-num_step_burn_in,duration))
                total_duration += duration
                total_duration_squared += duration *duration
        time_mean=total_duration /num_batch
        time_variance=total_duration_squared / num_batch - time_mean*time_mean
        time_stddev=math.sqrt(time_variance)
        #迭代完成,输出
        print("%s: %s across %d steps,%.3f +/- %.3f sec per batch "%
                  (datetime.now(),info_string,num_batch,time_mean,time_stddev))
    
    def main():
        with tf.Graph().as_default():
            """仅使用随机图片数据 测试前馈和反馈计算的耗时"""
            image_size =224
            images=tf.Variable(tf.random_normal([batch_size,image_size,image_size,3],
                                         dtype=tf.float32,stddev=0.1 ) )
            fc8,parameters=inference(images)
    
            init=tf.global_variables_initializer()
            sess=tf.Session()
            sess.run(init)
    
            """
            AlexNet forward 计算的测评
            传入的target:fc8(即最后一层的输出)
            优化目标:loss
            使用tf.gradients求相对于loss的所有模型参数的梯度
            
            
            AlexNet Backward 计算的测评
            target:grad
             
            """
            time_compute(sess,target=fc8,info_string="Forward")
    
            obj=tf.nn.l2_loss(fc8)
            grad=tf.gradients(obj,parameters)
            time_compute(sess,grad,"Forward-backward")

    (5)测试结果:

        结构输出   (注意,32是我设置的batch_size,即训练的图片数量为32)

                    

        前向预测用时:


        后向训练(学习)用时:


        可以看出后向训练用时比前向推理用时长很多,大概是5倍。


    【附录】完整代码

    # -*- coding:utf-8 -*-
    """
    @author:Lisa
    @file:alexNet.py
    @function:实现Alexnet深度模型
    @note:learn from《tensorflow实战》
    @time:2018/6/24 0024下午 5:26
    """
    
    import tensorflow as tf
    import time
    import math
    from datetime import datetime
    
    batch_size=32
    num_batch=100
    keep_prob=0.5
    
    
    def print_architecture(t):
        """print the architecture information of the network,include name and size"""
        print(t.op.name," ",t.get_shape().as_list())
    
    
    def inference(images):
        """ 构建网络 :5个conv+3个FC"""
        parameters=[]  #储存参数
    
        with tf.name_scope('conv1') as scope:
            """
            images:227*227*3
            kernel: 11*11 *64
            stride:4*4
            padding:name      
            
            #通过with tf.name_scope('conv1') as scope可以将scope内生成的Variable自动命名为conv1/xxx
            便于区分不同卷积层的组建
            
            input: images[227*227*3]
            middle: conv1[55*55*96]
            output: pool1 [27*27*96]
            
            """
            kernel=tf.Variable(tf.truncated_normal([11,11,3,96],
                               dtype=tf.float32,stddev=0.1),name="weights")
            conv=tf.nn.conv2d(images,kernel,[1,4,4,1],padding='SAME')
            biases=tf.Variable(tf.constant(0.0, shape=[96],  dtype=tf.float32),
                               trainable=True,name="biases")
            bias=tf.nn.bias_add(conv,biases) # w*x+b
            conv1=tf.nn.relu(bias,name=scope) # reLu
            print_architecture(conv1)
            parameters +=[kernel,biases]
    
            #添加LRN层和max_pool层
            """
            LRN会让前馈、反馈的速度大大降低(下降1/3),但最终效果不明显,所以只有ALEXNET用LRN,其他模型都放弃了
            """
            lrn1=tf.nn.lrn(conv1,depth_radius=4,bias=1,alpha=0.001/9,beta=0.75,name="lrn1")
            pool1=tf.nn.max_pool(lrn1,ksize=[1,3,3,1],strides=[1,2,2,1],
                                 padding="VALID",name="pool1")
            print_architecture(pool1)
    
        with tf.name_scope('conv2') as scope:
            """
            input: pool1[27*27*96]
            middle: conv2[27*27*256]
            output: pool2 [13*13*256]
    
            """
            kernel = tf.Variable(tf.truncated_normal([5, 5, 96, 256],
                                                     dtype=tf.float32, stddev=0.1), name="weights")
            conv = tf.nn.conv2d(pool1, kernel, [1, 1, 1, 1], padding='SAME')
            biases = tf.Variable(tf.constant(0.0, shape=[256], dtype=tf.float32),
                                 trainable=True, name="biases")
            bias = tf.nn.bias_add(conv, biases)  # w*x+b
            conv2 = tf.nn.relu(bias, name=scope)  # reLu
            parameters += [kernel, biases]
            # 添加LRN层和max_pool层
            """
            LRN会让前馈、反馈的速度大大降低(下降1/3),但最终效果不明显,所以只有ALEXNET用LRN,其他模型都放弃了
            """
            lrn2 = tf.nn.lrn(conv2, depth_radius=4, bias=1, alpha=0.001 / 9, beta=0.75, name="lrn1")
            pool2 = tf.nn.max_pool(lrn2, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1],
                                   padding="VALID", name="pool2")
            print_architecture(pool2)
    
        with tf.name_scope('conv3') as scope:
            """
            input: pool2[13*13*256]
            output: conv3 [13*13*384]
    
            """
            kernel = tf.Variable(tf.truncated_normal([3, 3, 256, 384],
                                                     dtype=tf.float32, stddev=0.1), name="weights")
            conv = tf.nn.conv2d(pool2, kernel, [1, 1, 1, 1], padding='SAME')
            biases = tf.Variable(tf.constant(0.0, shape=[384], dtype=tf.float32),
                                 trainable=True, name="biases")
            bias = tf.nn.bias_add(conv, biases)  # w*x+b
            conv3 = tf.nn.relu(bias, name=scope)  # reLu
            parameters += [kernel, biases]
            print_architecture(conv3)
    
        with tf.name_scope('conv4') as scope:
            """
            input: conv3[13*13*384]
            output: conv4 [13*13*384]
    
            """
            kernel = tf.Variable(tf.truncated_normal([3, 3, 384, 384],
                                                     dtype=tf.float32, stddev=0.1), name="weights")
            conv = tf.nn.conv2d(conv3, kernel, [1, 1, 1, 1], padding='SAME')
            biases = tf.Variable(tf.constant(0.0, shape=[384], dtype=tf.float32),
                                 trainable=True, name="biases")
            bias = tf.nn.bias_add(conv, biases)  # w*x+b
            conv4 = tf.nn.relu(bias, name=scope)  # reLu
            parameters += [kernel, biases]
            print_architecture(conv4)
    
        with tf.name_scope('conv5') as scope:
            """
            input: conv4[13*13*384]
            output: conv5 [6*6*256]
    
            """
            kernel = tf.Variable(tf.truncated_normal([3, 3, 384, 256],
                                                     dtype=tf.float32, stddev=0.1), name="weights")
            conv = tf.nn.conv2d(conv4, kernel, [1, 1, 1, 1], padding='SAME')
            biases = tf.Variable(tf.constant(0.0, shape=[256], dtype=tf.float32),
                                 trainable=True, name="biases")
            bias = tf.nn.bias_add(conv, biases)  # w*x+b
            conv5 = tf.nn.relu(bias, name=scope)  # reLu
            pool5 = tf.nn.max_pool(conv5, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1],
                                   padding="VALID", name="pool5")
            parameters += [kernel, biases]
            print_architecture(pool5)
    
        #全连接层6
        with tf.name_scope('fc6') as scope:
            """
            input:pool5 [6*6*256]
            output:fc6 [4096]
            """
            kernel = tf.Variable(tf.truncated_normal([6*6*256,4096],
                                                     dtype=tf.float32, stddev=0.1), name="weights")
            biases = tf.Variable(tf.constant(0.0, shape=[4096], dtype=tf.float32),
                                 trainable=True, name="biases")
            # 输入数据变换
            flat = tf.reshape(pool5, [-1, 6*6*256] )  # 整形成m*n,列n为7*7*64
            # 进行全连接操作
            fc = tf.nn.relu(tf.matmul(flat, kernel) + biases,name='fc6')
            # 防止过拟合  nn.dropout
            fc6 = tf.nn.dropout(fc, keep_prob)
            parameters += [kernel, biases]
            print_architecture(fc6)
    
        # 全连接层7
        with tf.name_scope('fc7') as scope:
            """
            input:fc6 [4096]
            output:fc7 [4096]
            """
            kernel = tf.Variable(tf.truncated_normal([4096, 4096],
                                                     dtype=tf.float32, stddev=0.1), name="weights")
            biases = tf.Variable(tf.constant(0.0, shape=[4096], dtype=tf.float32),
                                 trainable=True, name="biases")
            # 进行全连接操作
            fc = tf.nn.relu(tf.matmul(fc6, kernel) + biases, name='fc7')
            # 防止过拟合  nn.dropout
            fc7 = tf.nn.dropout(fc, keep_prob)
            parameters += [kernel, biases]
            print_architecture(fc7)
    
        # 全连接层8
        with tf.name_scope('fc8') as scope:
            """
            input:fc7 [4096]
            output:fc8 [1000]
            """
            kernel = tf.Variable(tf.truncated_normal([4096, 1000],
                                                     dtype=tf.float32, stddev=0.1), name="weights")
            biases = tf.Variable(tf.constant(0.0, shape=[1000], dtype=tf.float32),
                                 trainable=True, name="biases")
            # 进行全连接操作
            fc8 = tf.nn.xw_plus_b(fc7, kernel, biases, name='fc8')
            parameters += [kernel, biases]
            print_architecture(fc8)
    
        return fc8,parameters
    
    def time_compute(session,target,info_string):
        num_step_burn_in=10  #预热轮数,头几轮迭代有显存加载、cache命中等问题可以因此跳过
        total_duration=0.0   #总时间
        total_duration_squared=0.0
        for i in range(num_batch+num_step_burn_in):
            start_time=time.time()
            _ = session.run(target)
            duration= time.time() -start_time
            if i>= num_step_burn_in:
                if i%10==0: #每迭代10次显示一次duration
                    print("%s: step %d,duration=%.5f "% (datetime.now(),i-num_step_burn_in,duration))
                total_duration += duration
                total_duration_squared += duration *duration
        time_mean=total_duration /num_batch
        time_variance=total_duration_squared / num_batch - time_mean*time_mean
        time_stddev=math.sqrt(time_variance)
        #迭代完成,输出
        print("%s: %s across %d steps,%.3f +/- %.3f sec per batch "%
                  (datetime.now(),info_string,num_batch,time_mean,time_stddev))
    
    def main():
        with tf.Graph().as_default():
            """仅使用随机图片数据 测试前馈和反馈计算的耗时"""
            image_size =224
            images=tf.Variable(tf.random_normal([batch_size,image_size,image_size,3],
                                         dtype=tf.float32,stddev=0.1 ) )
            fc8,parameters=inference(images)
    
            init=tf.global_variables_initializer()
            sess=tf.Session()
            sess.run(init)
    
            """
            AlexNet forward 计算的测评
            传入的target:fc8(即最后一层的输出)
            优化目标:loss
            使用tf.gradients求相对于loss的所有模型参数的梯度
            
            
            AlexNet Backward 计算的测评
            target:grad
             
            """
            time_compute(sess,target=fc8,info_string="Forward")
    
            obj=tf.nn.l2_loss(fc8)
            grad=tf.gradients(obj,parameters)
            time_compute(sess,grad,"Forward-backward")
    
    
    if __name__=="__main__":
        main()
    
    
    ------------------------------------------------------         END      ----------------------------------------------------------

    参考:

    《tensorflow实战》黄文坚(本文内容及代码大多源于此书,感谢!)

    大牛论文《ImageNet Classification with Deep Convolutional Neural Networks Alex Krizhevsky

    [caffe]深度学习之图像分类模型AlexNet解读  https://blog.csdn.net/sunbaigui/article/details/39938097(参数分析很详细)



    展开全文
  • 深入理解AlexNet网络

    万次阅读 多人点赞 2020-04-13 15:22:12
    AlexNet 论文:《ImageNet Classification with Deep Convolutional Neural Networks》 第一个典型的CNN是LeNet5网络结构,但是第一个引起大家注意的网络却是AlexNet,也就是文章《ImageNet Classification ...

    AlexNet

    论文:《ImageNet Classification with Deep Convolutional Neural Networks》

    第一个典型的CNN是LeNet5网络结构,但是第一个引起大家注意的网络却是AlexNet,也就是文章《ImageNet Classification with Deep Convolutional Neural Networks》介绍的网络结构。这篇文章的网络是在2012年的ImageNet竞赛中取得冠军的一个模型整理后发表的文章。作者是多伦多大学的Alex Krizhevsky等人。Alex Krizhevsky其实是Hinton的学生,这个团队领导者是Hinton,那么Hinton是谁呢?这就要好好说说了,网上流行说 Hinton, LeCun和Bengio是神经网络领域三巨头,LeCun就是LeNet5作者(Yann LeCun),昨天的文章就提到了这个人。而今天的主角虽然不是Hinton,但却和他有关系,这篇的论文第一作者是Alex,所以网络结构称为AlexNet。这篇论文很有意思,因为我读完这篇论文之后,没有遇到比较难以理解的地方,遇到的都是之前学过的概念,比如Relu,dropout。之前学的时候只知道Relu是怎么一回事,今天才知道它真正的来源。这篇文章在2012年发表,文章中的模型参加的竞赛是ImageNet LSVRC-2010,该ImageNet数据集有1.2 million幅高分辨率图像,总共有1000个类别。测试集分为top-1和top-5,并且分别拿到了37.5%和17%的error rates。这样的结果在当时已经超过了之前的工艺水平。AlexNet网络结构在整体上类似于LeNet,都是先卷积然后在全连接。但在细节上有很大不同。AlexNet更为复杂。AlexNet有60 million个参数和65000个 神经元,五层卷积,三层全连接网络,最终的输出层是1000通道的softmax。AlexNet利用了两块GPU进行计算,大大提高了运算效率,并且在ILSVRC-2012竞赛中获得了top-5测试的15.3%error rate, 获得第二名的方法error rate 是 26.2%,可以说差距是非常的大了,足以说明这个网络在当时给学术界和工业界带来的冲击之大。

    一些背景

    在计算机视觉领域object detection & recognition 通常用机器学习的方法来解决。为了提高识别的效果,我们可以通过收集更多的可训练的数据来让模型的泛化性能提高。目前,在以一万为单位的数量级层面的数据(称为简单的识别任务)已经获得了非常好的性能,例如:MNIST 手写数字识别任务,最好的性能已经达到了<0.3%的误差。但是现实中的物体存在相当多的变化属性,所以学习识别它们需要更多的数据。事实上,小的图像训练数据有很多的缺点,无论以我们的直觉想还是理论证明都是有依据的,理论上论文《Why is real-world visual object recognition hard?》给出了研究方法。随着互联网技术的发展,以及智能手机的普及图像数据获取可以说越来越容易。所以就有组织去收集这些现实中事物的图像并进行标记和分割。例如:LabelMe(Labelme: a database and web-based tool for image annotation. ),包含了成百上千的全分割图像。 ImageNet(ImageNet: A Large-Scale Hierarchical Image Database. I),包含15 million 标记的高分辨率图像,包含超过了22000种现实中的事物。

    文章中说该模型有5层卷积,去掉任意一层都会使结果不好,所以这个网络的深度似乎是很重要的,这样的话难免引起我们的思考,记得不知道哪位大神在一篇论文中证明了,神经网络可以模拟任意多项式,只要神经元数量足够多,并且和深度关系不大。但这里的实验却表示深度会对网络的性能有影响。

    文章中还提到了,他们用5-6天训练了这个模型,并且限制了网络的大小,因为现有的硬件智能允许那么大的内存,用更好的设备还可以获得更好的效果。

    网络结构

    AlexNet 的网络结构是这样的,为啥我感觉这样表示的网络很丑呀,哈哈。

    感觉这个网络很复杂呀,需要怎么理解好呢?首先这幅图分为上下两个部分的网络,论文中提到这两部分网络是分别对应两个GPU,只有到了特定的网络层后才需要两块GPU进行交互,这种设置完全是利用两块GPU来提高运算的效率,其实在网络结构上差异不是很大。为了更方便的理解,我们假设现在只有一块GPU或者我们用CPU进行运算,我们从这个稍微简化点的方向区分析这个网络结构。网络总共的层数为8层,5层卷积,3层全连接层。

    第一层:卷积层1,输入为 224×224×3224 \times 224 \times 3的图像,卷积核的数量为96,论文中两片GPU分别计算48个核; 卷积核的大小为 11×11×311 \times 11 \times 3; stride = 4, stride表示的是步长, pad = 0, 表示不扩充边缘;
    卷积后的图形大小是怎样的呢?
    wide = (224 + 2 * padding - kernel_size) / stride + 1 = 54
    height = (224 + 2 * padding - kernel_size) / stride + 1 = 54
    dimention = 96
    然后进行 (Local Response Normalized), 后面跟着池化pool_size = (3, 3), stride = 2, pad = 0 最终获得第一层卷积的feature map
    最终第一层卷积的输出为

    第二层:卷积层2, 输入为上一层卷积的feature map, 卷积的个数为256个,论文中的两个GPU分别有128个卷积核。卷积核的大小为:5×5×485 \times 5 \times 48; pad = 2, stride = 1; 然后做 LRN, 最后 max_pooling, pool_size = (3, 3), stride = 2;

    第三层:卷积3, 输入为第二层的输出,卷积核个数为384, kernel_size = (3×3×2563 \times 3 \times 256), padding = 1, 第三层没有做LRN和Pool

    第四层:卷积4, 输入为第三层的输出,卷积核个数为384, kernel_size = (3×33 \times 3), padding = 1, 和第三层一样,没有LRN和Pool

    第五层:卷积5, 输入为第四层的输出,卷积核个数为256, kernel_size = (3×33 \times 3), padding = 1。然后直接进行max_pooling, pool_size = (3, 3), stride = 2;

    第6,7,8层是全连接层,每一层的神经元的个数为4096,最终输出softmax为1000,因为上面介绍过,ImageNet这个比赛的分类个数为1000。全连接层中使用了RELU和Dropout。

    上面的结构是假设在一块GPU上面的,和论文的两块GPU有差别,但是为了方便理解,还是采用越简单的结构越好。

    ReLU Nonlinearity(Rectified Linear Unit)

    标准的L-P神经元的输出一般使用tanh 或 sigmoid作为激活函数, tanh(x)=sinhxcoshx=exexex+extanh(x) = \frac{sinhx}{coshx} = \frac{e^x - e^{-x}}{e^x + e^{-x}}, sigmoid: f(x)=11+exf(x) = \frac{1}{1 + e^{-x}}。但是这些饱和的非线性函数在计算梯度的时候都要比非饱和的现行函数f(x)=max(0,x)f(x) = max(0, x)慢很多,在这里称为 Rectified Linear Units(ReLUs)。在深度学习中使用ReLUs要比等价的tanh快很多。


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

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

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

    b(x,y)i=a(x,y)i(k+αj=max(0,in/2)min(N1,i+n/2)(a(x,y)j)2)βb^{i}_{(x, y)} = \frac{a^{i}_{(x, y)}}{(k + \alpha \sum\limits_{j = max(0, i - n / 2)}^{min(N-1, i+n / 2)}(a^j_{(x, y)})^2)^{\beta}}

    这个公式什么意思呢?a(x,y)ia^i_{(x, y)}代表的是ReLU在第i个kernel的(x, y)位置的输出,n表示的是a(x,y)ia^i_{(x, y)}d的邻居个数,N表示该kernel的总数量。b(x,y)ib^i_{(x,y)}表示的是LRN的结果。ReLU输出的结果和它周围一定范围的邻居做一个局部的归一化,怎么理解呢?我觉得这里有点类似域我们的最大最小归一化,假设有一个向量X=[x1,x2,...,xn]X = [x_1,x_2, ... ,x_n]
    那么将所有的数归一化到0-1之间的归一化规则是:xi=xixminxmaxxminx_i = \frac{x_i - x_{min}}{x_{max} - x_{min}}
    上面那个公式有着类似的功能,只不过稍微复杂一些,首先运算略微复杂,其次还有一些其他的参数α,β,k\alpha, \beta, k

    我们看上图,每一个矩形表示的一个卷积核生成的feature map。所有的pixel已经经过了ReLU激活函数,现在我们都要对具体的pixel进行局部的归一化。假设绿色箭头指向的是第i个个kernel对应的map,其余的四个蓝色箭头是它周围的邻居kernel层对应的map,假设矩形中间的绿色的pixel的位置为(x, y),那么我需要提取出来进行局部归一化的数据就是周围邻居kernel对应的map的(x, y)位置的pixel的值。也就是上面式子中的a(x,y)ja^j_{(x, y)}。然后把这些邻居pixel的值平方再加和。乘以一个系数α\alpha再加上一个常数k,然后β\beta次幂,就是分母,分子就是第i个kernel对应的map的(x, y)位置的pixel值。这样理解之后我感觉就不是那么复杂了。

    关键是参数α,β,k\alpha, \beta, k如何确定,论文中说在验证集中确定,最终确定的结果为:
    k=2,n=5,α=104,β=0.75k=2, n=5, \alpha=10^{-4}, \beta = 0.75

    Overlapping Pooling(覆盖的池化操作)

    一般的池化层因为没有重叠,所以pool_size 和 stride一般是相等的,例如8×88\times 8的一个图像,如果池化层的尺寸是2×22 \times 2,那么经过池化后的操作得到的图像是 4×44 \times 4大小,这种设置叫做不覆盖的池化操作,如果 stride < pool_size, 那么就会产生覆盖的池化操作,这种有点类似于convolutional化的操作,这样可以得到更准确的结果。在top-1,和top-5中使用覆盖的池化操作分别将error rate降低了0.4%和0.3%。论文中说,在训练模型过程中,覆盖的池化层更不容易过拟合。

    Overall Architecture

    用caffe 自带的绘图工具(caffe/python/draw_net.py) 和caffe/models/bvlc_alexnet/目录下面的train_val.prototxt绘制的网络结构图如下图


    这张图也是单个GPU的网络结构,不是两个GPU的网络结构。

    防止过拟合的方法

    神经网络的一个比较严重的问题就是过拟合问题,论文中采用的数据扩充和Dropout的方法处理过拟合问题。

    Data Augmentation(数据扩张,就是对原始数据做一些变化)

    数据扩充是防止过拟合的最简单的方法,只需要对原始的数据进行合适的变换,就会得到更多有差异的数据集,防止过拟合。

    Dropout

    Dropout背后有很多有意思的东西,但是在这里我们不需要了解太深,只需要知道Dropout是在全连接层中去掉了一些神经节点,达到防止过拟合的目的,我们可以看上面的图在第六层和第七层都设置了Dropout。关于DropOut的理解,推荐一篇文章

    Reference

    1. AlexNet 原始论文
    2. caffe AlexNet
    3. dropout 理解
    4. 机器学习进阶笔记之三|深入理解Alexnet
    展开全文
  • AlexNet详细解读

    万次阅读 多人点赞 2018-05-19 15:50:03
    目前在自学计算机视觉与深度学习方向的论文,今天给大家带来的是很经典的一篇文章 :《ImageNet ...AlexNet的篇文章当中,我们可以主要从五个方面去讲,重点介绍总体结构和减少过度拟合。1. ReLU Nonline...
  • 从LeNet到AlexNet

    千次阅读 2019-07-27 20:15:03
    CNN卷积神经网络的经典网络综述 一切的开始( LeNet) 1、Input (32*32) 2、C1, C3, C5 (卷积层) 3、S2, S4 (pooling层) 4、F6 (全连接层) 5、Output (输出层) 详细参数: 1、INPUT层-输入层 ...6、C...
  • AlexNet

    2020-03-26 09:24:08
    这篇论文的作者包括Alex Krizhevsky,Ilya Sutskever 和Geoffrey E. Hinton,三人均来自于多伦多大学计算机科学院,其中,前两者都是Hinton的学生,Hinton就不多说了,和Yoshua Bengio以及Yann LeCun共同获得了2018...
  • 使用AlexNet训练自己的数据集

    万次阅读 热门讨论 2019-07-02 15:58:12
    前言: 前两篇分别介绍两个图像识别的模型,第一个是mnist手写体图像识别,第二个是在第一个代码...具体的就介绍AlexNet、VGG19、ResNet_152 、InceptionV4 、DenseNet这五个模型,并且测试一下这些模型在卫星图像...
  • [论文阅读]中文版-AlexNet

    千次阅读 2019-06-17 15:50:43
    论文地址 :AlexNet 时间:2019年6月16日11:05:09 难度:一般 编号:2 进度:2/2 23/52 方向:深度学习,计算机视觉 类型:经典网络 相关: 值得阅读:[我看AlexNet-Author: Zongwei Zhou | 周纵苇 ]...
  • Matlab2017 安装alexnet

    千次阅读 热门讨论 2017-11-05 11:40:27
    下载 https://cn.mathworks.com/matlabcentral/fileexchange/59133-neural-network-toolbox-tm--model-for-alexnet-network 下载下来这个东东: alexnet.mlpkginstall,放到matlab的某个目录下, 双击 ale
  • AlexNet中的参数数量

    千次阅读 2018-03-22 16:28:41
    参考:https://vimsky.com/article/3664.html
  • AlexNet(Pytorch实现)

    千次阅读 2018-12-16 16:33:58
    github博客传送门 博客园传送门 论文在此: ImageNet Classification with Deep Convolutional Neural Networks 网络结构图: ...class AlexNet(nn.Module): def __init__(self, num_classes=1000)...
  • caffe中的 AlexNet,LeNet,CaffeNet

    千次阅读 2016-05-18 23:47:43
    AlexNet LeNet caffenet CaffeNetConv
  • AlexNet 参数计算

    千次阅读 2018-10-11 08:41:37
    FeatureMap大小计算公式: No Padding: 长=(Input长-过滤器长+1)/步长,上取整 宽=(Input宽-过滤器宽+1)/步长,上取整 Padding: 长=Input长/步长,上取整 ...宽=Input宽/步长,上取整 ...参数数量:11113...
  • Alexnet输入大小调整的经验

    万次阅读 热门讨论 2017-03-04 22:07:03
    Alexnet是在2012的ImageNet图像分类竞赛中亮相的,top-5错误率比上一年的冠军下降了十个百分点,而且远远超过当年的第二名。一下子打破了之前深度学习的冷门期。AlexNet 优势在于:网络增大(5个卷积层+3个全连接层+...
  • 关于Deep learning 中AlexNet工具箱安装问题

    千次阅读 热门讨论 2018-01-31 10:58:09
    matlab 运行 AlexNet 0. alexnet 工具箱下载 下载地址:Neural Network Toolbox(TM) Model for AlexNet Network 需要先注册(十分简单),登陆,下载;下载完成之后,windows
  • Alexnet 网络结构和原理介绍

    千次阅读 2018-01-04 14:53:43
    一、Alexnet网络结构图* 二、Alexnet网络结构详细解读* 之前做过一个相关的ppt,下图是其中的一页,介绍的也比较详细,可以参考:Alexnet网络是由八层网络组成的,包括5层卷积层和3层全连接层,下面是详细的介绍: ...
  • AlexNet模型及迁移学习

    千次阅读 2018-08-12 17:28:44
    一、CNN卷积神经网络结构的演化   二、AlexNet 网络结构 ... 例如采用在计算机视觉挑战赛通过ImageNet数据(源数据)集训练出来的AlexNet 模型迁移应用到另一个新的数据集(目标数据集)重新进...
  • PyTorch实现的AlexNet

    千次阅读 2019-09-26 23:05:21
    PyTorch实现的AlexNet import torch import torch.nn as nn import torchvision class AlexNet(nn.Module): def __init__(self,num_classes=1000): super(AlexNet,self).__init__() self.feature_...
  • ALEXNET 论文总结

    千次阅读 2016-07-08 08:54:35
    AlexNet 论文总结
1 2 3 4 5 ... 20
收藏数 22,280
精华内容 8,912
关键字:

alexnet