目录

 

 

1.概述 1

1.1 项目背景 1

客户端 3

Distributed Master 3

Worker Service 5

Kernel Implements 6

技术栈 7

一、 神经网络的实现过程 8

二、 前向传播 8

三、后向传播 10

四、搭建神经网络的过程 11

神经网络优化 12

1、 神经元模型: 12

2、激活函数 13

3、神经网络的复杂度 13

4、神经网络的层数 13

5、神经网络待优化的参数 14

神经网络优化问题 14

1、损失函数(loss 14

2、学习率 16

3、滑动平均(影子) 18

4、正则化 19

第一项是预测结果与标准答案的差距,第二项是正则化计算结果。 19

1.2 研究现状 20

AlexNet 21

更深一点的网络:VGGNet 22

再深一点的网络:GoogLeNet Inception 模块 23

使用一个捷径来跳跃:ResNet 24

将捷径扩展到极致:DenseNet 25

深度学习未来将如何发展 26

从有监督学习到无监督学习 26

对抗学习 27

加快进展 27

1.3 项目计划 29

2.1 数据集介绍 29

2.2 数据可视化 30

1、导入相应要用到的python包: 30

2、读取相应路径下的文件 30

3、读取每个水果的子文件里面的水果图片的名字。 30

4a、定义一个保存所有训练集图片名称的列表 31

5a、逐个读取每个水果类的子文件夹名称 33

2.3深度学习的训练目标 35

3.1 读取图像数据 36

i、对r列表进行升序排序 37

3.2 图像数据预处理 39

1)逐个子文件夹文件依次读取。 39

2)将彩色的图片转变为灰度图 39

3)接着再将灰度图片转变成64*64的大小 39

4)依次将每个子文件夹里面处理过的灰度图片保存到one列表 39

5)最后将每个子文件处理后的图片数据保存的trainData列表里 39

4.1深度学习网络结构 43

4.2 卷积、池化及参数定义 44

4.3 训练过程及结果 48

4.4 参数调整及优化 50

1、 使用命令读取可视化文件 64

2、 输入最后的http://acer:6006,使用Google浏览器打开 64

1导入相应的python 70

2神经网络的搭建以及迁移学习的测试 70

1、 神经网络的学习率太大,导致欠拟合 77

2、 搭建的神经网络的层次太多,导致过拟合 77

3、 图片的深度设置太小,导致欠拟合 77

4、 图片的深度设置太大,导致过拟合 77

5、 图片预处理时,裁剪得太多,导致图片许多关键的特征丢失 77

6、 神经网络学习循环的次数太少,也会导致准确率低 77

7、 神经网络优化器选定不当,导致准确率低 77

8、 图片的标签与图片没有对应上 78

9、 加载训练数据时,没有事先乱序处理 78

10、 乱序时,图片数据与标签没有做相对应的变化 78

11、 降低图片的通道数也会导致准确率低 78

 

 

1.概述

1.1 项目背景

      深度学习的概念源于人工神经网络的研究。含多隐层的多层感知器就是一种深度学习结构。深度学习通过组合低层特征形成更加抽象的高层表示属性类别或特征,以发现数据的分布式特征表示。深度学习是机器学习中一种基于对数据进行表征学习的方法。观测值(例如一幅图像)可以使用多种方式来表示,如每个像素强度值的向量,或者更抽象地表示成一系列边、特定形状的区域等。而使用某些特定的表示方法更容易从实例中学习任务(例如,人脸识别或面部表情识别)。深度学习的好处是用非监督式或半监督式的特征学习和分层特征提取高效算法来替代手工获取特征。深度学习是机器学习研究中的一个新的领域,其动机在于建立、模拟人脑进行分析学习的神经网络,它模仿人脑的机制来解释数据,例如图像,声音和文本。同机器学习方法一样,深度机器学习方法也有监督学习与无监督学习之分.不同的学习框架下建立的学习模型很是不同.例如,卷积神经网络Convolutional neural networks,简称CNNs)就是一种深度的监督学习下的机器学习模型,而深度置信网(Deep Belief Nets,简称DBNs)就是一种无监督学习下的机器学习模型。

    神经网络深度学习常使用到的一种框架是TensorFlow,本项目主要也是基于此技术框架完成的,下面是对TensorFlow框架的详细介绍。

TensorFlow基于数据流图,用于大规模分布式数值计算的开源框架。节点表示某种抽象的计算,边表示节点之间相互联系的张量。TensorFlow的系统结构以C API为界,将整个系统分为「前端」和「后端」两个子系统:前端系统:提供编程模型,负责构造计算图;后端系统:提供运行时环境,负责执行计算图。Client是前端系统的主要组成部分,它是一个支持多语言的编程环境。它提供基于计算图的编程模型,方便用户构造各种复杂的计算图,实现各种形式的模型设计。Client通过Session为桥梁,连接TensorFlow后端的「运行时」,并启动计算图的执行过程。在分布式的运行时环境中,Distributed Master根据Session.runFetching参数,从计算图中反向遍历,找到所依赖的「最小子图」。然后,Distributed Master负责将该「子图」再次分裂为多个「子图片段」,以便在不同的进程和设备上运行这些「子图片段」。最后,Distributed Master将这些「子图片段」派发给Work Service;随后Work Service启动「子图片段」的执行过程。对于每以个任务,TensorFlow都将启动一个Worker ServiceWorker Service将按照计算图中节点之间的依赖关系,根据当前的可用的硬件环境(GPU/CPU),调用OPKernel实现完成OP的运算(一种典型的多态实现技术)。另外,Worker Service还要负责将OP运算的结果发送到其他的Work Service;或者接受来自其他Worker Service发送给它的OP运算的结果。KernelOP在某种硬件设备的特定实现,它负责执行OP的运算。

 

如上图所示,假设存在两个任务:/job:ps/task:0: 负责模型参数的存储和更新/job:worker/task:0: 负责模型的训练或推理

客户端

Client基于TensorFlow的编程接口,构造计算图。目前,TensorFlow主流支持Python和C++的编程接口,并对其他编程语言接口的支持日益完善。此时,TensorFlow并未执行任何计算。直至建立Session会话,并以Session为桥梁,建立Client与后端运行时的通道,将Protobuf格式的GraphDef发送至Distributed Master。也就是说,当Client对OP结果进行求值时,将触发Distributed Master的计算图的执行过程。如下图所示,Client构建了一个简单计算图。它首先将w与x进行矩阵相乘,再与截距b按位相加,最后更新至s。

Distributed Master

在分布式的运行时环境中,Distributed Master根据Session.runFetching参数,从计算图中反向遍历,找到所依赖的最小子图。然后Distributed Master负责将该子图再次分裂为多个「子图片段」,以便在不同的进程和设备上运行这些「子图片段」。最后,Distributed Master将这些图片段派发给Work Service。随后Work Service启动「本地子图」的执行过程。Distributed Master将会缓存「子图片段」,以便后续执行过程重复使用这些「子图片段」,避免重复计算。

如上图所示,Distributed Master开始执行计算子图。在执行之前,Distributed Master会实施一系列优化技术,例如「公共表达式消除」,「常量折叠」等。随后,Distributed Master负责任务集的协同,执行优化后的计算子图。

如上图所示,存在一种合理的「子图片段」划分算法。Distributed Master将模型参数相关的OP进行分组,并放置在PS任务上。其他OP则划分为另外一组,放置在Worker任务上执行。

如上图所示,如果计算图的边被任务节点分割,Distributed Master将负责将该边进行分裂,在两个分布式任务之间插入SENDRECV节点,实现数据的传递。随后,Distributed Master将「子图片段」派发给相应的任务中执行,在Worker Service成为「本地子图」,它负责执行该子图的上的OP

Worker Service

对于每个任务,都将存在相应的Worker Service,它主要负责如下3个方面的职责:处理来自Master的请求;调度OPKernel实现,执行本地子图;协同任务之间的数据通信。

Worker Service派发OP到本地设备,执行Kernel的特定实现。它将尽最大可能地利用多CPU/GPU的处理能力,并发地执行Kernel实现。

另外,TensorFlow根据设备类型,对于设备间的SEND/RECV节点进行特化实现:使用cudaMemcpyAsyncAPI实现本地CPUGPU设备的数据传输;

对于本地的GPU之间则使用端到端的DMA,避免了跨host CPU昂贵的拷贝过程。

对于任务之间的数据传递,TensorFlow支持多协议,主要包括:gRPC over TCPRDMA over Converged Ethernet

Kernel Implements

TensorFlow的运行时包含200多个标准的OP,包括数值计算,多维数组操作,控制流,状态管理等。每一个OP根据设备类型都会存在一个优化了的Kernel实现。在运行时,运行时根据本地设备的类型,为OP选择特定的Kernel实现,完成该OP的计算。

其中,大多数Kernel基于Eigen::Tensor实现。Eigen::Tensor是一个使用C++模板技术,为多核CPU/GPU生成高效的并发代码。但是,TensorFlow也可以灵活地直接使用cuDNN实现更高效的Kernel。此外,TensorFlow实现了矢量化技术,使得在移动设备,及其满足高吞吐量,以数据为中心的应用需求,实现更高效的推理。如果对于复合OP的子计算过程很难表示,或执行效率低下,TensorFlow甚至支持更高效的Kernle实现的注册,其扩展性表现相当优越。

技术栈

最后,按照TensorFlow的软件层次,通过一张表格罗列TensorFlow的技术栈,以便更清晰地对上述内容做一个简单回顾。

一、神经网络的实现过程

1、准备数据集,提取特征,作为输入喂给神经网络
  2、搭建神经网络结构,从输入到输出
  3、大量特征数据喂给 NN,迭代优化 NN 参数
  4、使用训练好的模型预测和分类 

二、前向传播

前向传播就是搭建模型的计算过程,可以针对一组输入给出相应的输出。

举例:假如生产一批零件, 体积为 x1, 重量为 x2, 体积和重量就是我们选择的特征,把它们喂入神经网络, 当体积和重量这组数据走过神经网络后会得到一个输出。假如输入的特征值是:体积 0.7 ,重量 0.5 ,下图是搭建的神经网络框架图

由搭建的神经网络可得, 隐藏层节点 a11=x1* w11+x2*w21=0.14+0.15=0.29, 同理算得节点 a12=0.32a13=0.38,最终计算得到输出层 Y=-0.015, 这便实现了前向传播过程。

接下来推导图中的代码实现过程。

第一层:

(1)x是输入为1*2的矩阵:用x表示输入,是一个12列的矩阵,表示一次输入一组特征,这组特征包含了体积和重量两个元素。

(2)W前节点编号,后节点编号(层数)为待优化的参数:前面两个节点,后面三个节点。所以w应该是个两行三列的矩阵。表示为

注意:神经网络共有几层是指计算层, 输入不算作计算层,所以 上图中a 为第一层网络,a 是一个一行三列矩阵。

第二层:

(1)参数要满足前面三个节点,后面一个节点,所以W2)是三行一列矩阵。表示为

把每层输入乘以线上的权重w,这样就可以用矩阵乘法输出y了。

    三、后向传播

      反向传播:训练模型参数,以减小loss值为目的,使用优化方法,使得 NN 模型在训练数据上的损失函数最小。

损失函数(loss): 计算得到的预测值 y 与已知答案 y_ 的差距。损失函数的计算有很多方法,均方误差( MSE) 是比较常用的方法之一。 

均方误差 MSE: 求前向传播计算结果与已知答案之差的平方再求平均。数学公式为:

tensorflow函数表示为:loss_mse = tf.reduce_mean(tf.square(y_ - y))

反向传播训练方法: 以减小 loss 值为优化目标。一般有梯度下降、 momentum 优化器、 adam 优化器等优化方法。这三种优化方法用 tensorflow 的函数可以表示为:

train_step=tf.train.GradientDescentOptimizer(learning_rate).minimize(loss)

train_step=tf.train.MomentumOptimizer(learning_rate, momentum).minimize(loss)

train_step=tf.train.AdamOptimizer(learning_rate).minimize(loss) 三种优化方法的区别:

学习率:决定每次参数更新的幅度。

优化器中都需要一个叫做学习率的参数,使用时,如果学习率选择过大会出现震荡不收敛的情况(步子跨的太大),如果学习率选择过小,会出现收敛速度慢的情况。可以选个比较小的值填入,比如 0.010.001

四、搭建神经网络的过程

1)导入模块,生成模拟数据集

Import

常量定义

生成数据集

2)前向传播:定义输入、参数和输出

x=              y_=

w1=            w2=

a=              y=

3)后向传播:定义损失函数、反向传播方法

    loss=

 train_step=

 4)生成会话,训练STEPS

 with tf.Session as sess:

init_op = tf.global_variables_initializer()

sess.run(init_op)

STEPS =

for i in range(STEPS):

start = 

end = 

sess.run(train_step, feed_dict={ })

神经网络优化

1、神经元模型:

之前的神经元结构都采用线上的权重w直接乘以输入数据x,用数学表达式即,但这样的结构不够完善。完善的结构需要加上偏置,并加上激励函数。用数学公式表示为:。其中f为激励函数。神经网络就是由以这样的神经元为基本单位构成的。

2、激活函数

引入非线性激活因素,提高模型的表达力。

3、神经网络的复杂度

可以用神经网络的层数和神经网络待优化的参数个数来表示

4、神经网络的层数

层数=n个隐藏层 + 1个输出层  

注意:一般不计入输入层

5、神经网络待优化的参数

神经网络所有参数wb的个数

举例:下图为神经网络示意图

在该神经网络中,包含1个输入层、1个隐藏层和1个输出层,该神经网络的层数为2层。(不计入输入层)

在该神经网络中,参数的个数是所有参数w的个数加上所有参数b的总数,第一层参数用三行四列的二阶张量表示(即12个线上的权重w)再加上4个偏置b;第二层参数是四行两列的二阶张量(即8个线上的权重w)再加上2个偏置b。总参数=3*4+4+4*2+2=26

神经网络优化问题

1、损失函数(loss

用来表示预测值(y)与已知答案(y_)的差距。在训练神经网络时,通过不断改变神经网络中所有参数,使损失函数不断减小,从而训练出更高准确率的神经网络模型。

常用的损失函数有:

1)均方误差(mse

均方误差就是n个样本的预测值y与已知答案y_之差的平方和,再求平均值。数学公式为,在Tensorflow中表示为 tf.reduce_mean(tf.square(y-y_))

2)自定义

上面的模型中,损失函数采用的是MSE,但根据事实情况我们知道,销量预测问题不是简单的成本和利润相等问题。如果预测多了,卖不出去,损失的是成本,反之预测少了,损失的是利润,现实情况往往利润和成本是不相等的。因此,需要使用符合该问题的自定义损失函数。自定义损失函数数学公式为:loss = Σnf(y_,y)

到本问题中可以定义成分段函数:

 

tf的函数表示为:loss = tf.reduce_sum(tf.where(tf.greater(y,y_),cost(y-y_),PROFIT(y_-y))) 

3)交叉熵(Cross Entropy)

表示两个概率分布之间的距离,交叉熵越大,说明两个概率分布距离越远,两个概率分布越相异;交叉熵越小,说明两个概率分布距离越近,两个概率分布越相似。交叉熵计算公式为:H(y_,y)=-Σy_ * log10 y

tf中表示为:ce = -tf.reduce_mean(y_ * tf.log(tf.clip_by_value(y,1e-12,1.0)))  # 确保y<1e-12为1e-2,y>1为1

举一个数学的例子,比如标准答案y_=(1,0)。y1=(0.6,0.4 )  y2=(0.8,0.2),哪个更接近标准答案呢。

tf中,一般让模型的输出经过softmax函数,进而获得输出分类的概率分布,再与标准答案对比,求得交叉熵,得到损失函数,并且有专门的函数。

 ce = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=y, labels=tf.argmax(y_, 1))

cem = tf.reduce_mean(ce)

这也就代替了ce = -tf.reduce_mean(y_ * tf.log(tf.clip_by_value(y,1e-12,1.0)))    这句函数。

2、学习率

学习率过大,会导致待优化参数在最小值附近波动,不收敛;学习率过小,导致训练次数增大,收敛缓慢。

(1)随机梯度下降算法更新参数

首先随机梯度下降方法更新参数的公式为:wn+1=wn - learning_rate *   (▽表示损失函数关于参数的偏导)

     如果参数初值为5,学习率为0.2,则参数更新情况为:

 

能看的出来,如果损失函数使用随机梯度下降优化器,loss的最小值应该是0,此时参数w-1

2)指数衰减学习率

指数衰减学习率就是指学习率会随着训练轮数变化而实现动态更新,它不再是一个定值。计算公式为:learning_rate = learning_rate_base *   learning_rate_decay global_step/learning_rate_step,这里面的概念:

learning_rate_base:学习率基数,一般认为和学习率初始值相等

learning_rate_decay:学习率衰减率,范围是(01

global_step:运行了几轮batch_size

learning_rate_step:多少论更新一次学习率=总样本数/batch_size

tensorflow中,我们用这样的函数来表示:

首先要有一个值指向当前的训练轮数,这是一个不可训练参数,作为一个“线索”global_step = tf.Variable(0,trainable=False)

再来就是一个学习率的函数:learning_rate = tf.train.exponential_decay(LEARNING_RATE_BASE,global_step, LEARNING_RATE_STEP, LEARNING_RATE_DECAY,staircase=True/False)# 其他的参数已经在上面提到过,最后一个参数staircase,当设置为True时,表示global_step/learning_rate_step取整数,学习率阶梯型衰减;若为False,学习率是一条平滑下降的曲线。

3、滑动平均(影子)

滑动平均值(也有人称为影子值),记录了一段时间内模型中所有的参数w和b各自的平均值。使用影子值可以增强模型的泛化能力。就感觉是给参数加了影子,参数变化,影子缓慢跟随。

影子 = 衰减率*影子 + (1-衰减率)*参数

其中,影子初值 = 参数初值;衰减率 = min{moving_average_decay , (1+轮数)/(10+轮数) }

例如,moving_average_decay赋值为0.99,参数w设置为0,影子值为0

(1) 开始时,训练轮数为0,参数更新为1,则w的影子值为:

影子 = min(0.99,1/10)*0+(1-min(0.99,1/10))*1=0.9

 (2)    当训练轮数为100时,参数w更新为10,则w的影子值为:

影子 = min(0.99,101/110)*0.9+(1min(0.99,101/110)*10 = 0.826+0.818=1.644

(3)    当训练轮数为100时,参数w更新为1.644,则w的影子值为:

影子 = min(0.99,101/110)*1.644+(1– min(0.99,101/110)*10 = 2.328

(4) 当训练轮数为100时,参数w更新为2.328,则w的影子值为:

影子 = 2.956

tensorflow函数可以表示为以下内容:

ema = tf.train.ExponentialMovingAverage(MOVING_AVERAGE_DECAYglobal_step)   

 ema_op = ema.apply(tf.trainable_variables()) 

with tf.control_dependencies([train_step, ema_op]):

 train_op = tf.no_op(name='train')

4、正则化

正则化是解决神经网络过拟合的有效方法。

过拟合:神经网络模型在训练集上准确率高,在测试集进行预测或分类时准确率吧较低,说明模型的泛化能力差。

正则化:在损失函数中给每个参数w加上权重,引入模型复杂度指标,从而抑制模型噪声,减小过拟合。

根据正则化的定义,可以得出新的损失函数值:

 loss = loss(y-y_) + regularizer* loss(w)

第一项是预测结果与标准答案的差距,第二项是正则化计算结果。

正则化有两种计算方法:(1)L1正则化:lossL1 = i |wi|,tf函数表示为:loss(w) = tf.contrib.layers.l1_regularizer(regularizer)(w)(2)L2正则化:lossL2 = i  |wi|2 ,  tf函数表示为:loss(w) = tf.contrib.layers.l2_regularizer(regularizer)(w)

正则化实现用tensorflow可以表示为:

 tf.add_to_collection('losses', tf.contrib.layers.l2_regularizer(regularizer)(w)

 loss = cem + tf.add_n(tf.get_collection('losses')) # cem即交叉熵损失函数的值

 

 

 

1.2 研究现状

神经网络有大量的参数,经常发生过拟合问题,即往往在训练集上准确率很高,而在测试集上效果差。这部分归因于当时的训练数据集规模都较小。而且计算资源有限,即便是训练一个较小的网络也需要很长的时间。总体而言,神经网络与其它模型相比并未在识别的准确率上体现出明显的优势,而且难于训练。因此更多的学者开始采用诸如支持向量机、Boosting、最近邻等分类器。这些分类器可以用具有一个或两个隐含层的神经网络模拟,因此被称作浅层机器学习模型。它们不再模拟大脑的认知机理;相反,针对不同的任务设计不同的系统,并采用不同的手工设计的特征。例如语音识别采用高斯混合模型和隐马尔可夫模型,物体识别采用SIFT特征,人脸识别采用LBP特征,行人检测采用HOG特征。

2006年,Geoffrey Hinton提出了深度学习,之后深度学习在诸多领域取得了巨大成功,受到广泛关注。神经网络能够重新焕发青春的原因有几个方面。首先是大数据的出现在很大程度上缓解了训练过拟合的问题。例如ImageNet[2]训练集拥有上百万有标注的图像。计算机硬件的飞速发展提供了强大的计算能力,使得训练大规模神经网络成为可能。一片GPU可以集成上千个核。此外神经网络的模型设计和训练方法都取得了长足的进步。例如,为了改进神经网络的训练,学者提出了非监督和逐层的预训练。它使得在利用反向传播对网络进行全局优化之前,网络参数能达到一个好的起始点,从而训练完成时能达到一个较好的局部极小点。

深度学习在计算机视觉领域最具影响力的突破发生在2012年,Hinton的研究小组采用深度学习赢得了ImageNet[2]图像分类的比赛[3]ImageNet是当今计算机视觉领域最具影响力的比赛之一。它的训练和测试样本都来自于互联网图片。训练样本超过百万,任务是将测试样本分成1000类。自2009年,包括工业界在内的很多计算机视觉小组都参加了每年一度的比赛,各个小组的方法逐渐趋同。在2012年的比赛中,排名24位的小组都采用的是传统的计算机视觉方法,手工设计的特征,他们准确率的差别不超过1%Hinton的研究小组是首次参加比赛,深度学习比第二名超出了10%以上。这个结果在计算机视觉领域产生了极大的震动,掀起了深度学习的热潮。

2012 年,一篇来自多伦多大学的文章引起了所有人的注意。这篇文章就是《ImageNet Classification with Deep Convolutional Networks》,发布在 NIPS 上。这篇文章随后成为了该领域最具影响力的论文,并且在 ImageNet 挑战赛上降低了 50% 的错误率,这是一个史无前例的进展。这篇文章建议使用深度卷积神经网络 (CNN) 来进行图像分类。相比于今天使用的各种卷积神经网络,它相对来说比较简单。这篇文章的主要贡献是:

第一次成功地将深度神经网络应用在大规模图像分类问题上。这其中的一部分原因是 ImageNet 中有 大量带有标注 的数据,同时,使用了两个 GPU 并行计算。

1使用 ReLU 作为 非线性激活函数,相比于 tanh 函数,ReLU 在获得更好的性能的同时还能减少训练时间。如今,ReLU 已经逐渐成为深度网络的默认激活函数。

2使用数据增强技术,包括图像平移 (image translation)、水平翻转 (horizontal reflections) 和均值减法 (mean subtraction)。这些技术在如今的很多计算机视觉任务中都被广泛使用。

3使用 随机失活(dropout) 来防止模型对训练数据 过拟合。

4提出 连续卷积、池化层及全连接层 的网络结构,这一结构至今仍然是许多顶尖网络的基础。

总的来说,AlexNet 是一项里程碑式的工作,它提供了使用 CNN 完成计算机视觉任务的基准和基本技术。

论文《Very Deep Convolutional Neural Networks for Large-Scale Image Recognition》于 2014 年问世,文中的 VGGNet 进一步扩展了包含许多卷积层和 ReLu 的深度网络。它们的核心思想是,你并不需要很多新奇的技巧来获得很高的准确率,大量的 3x3 卷积核和非线性网络就可以做到这一点!这篇论文的主要贡献是:

1使用了尺寸只有 3x3 的滤波器代替 AlexNet 11x11 的滤波器。他们认为,两个连续的 3x3 卷积和一个 5x5 的卷积核具有相同的接受域(receptive field)或者视场 (即可观测到的像素数量);类似地,三个连续的 3x3 卷积核相当于一个 7x7 的卷积核。这样做的好处是,使用较小的滤波器尺寸就可以获得与更大的滤波器相同的效果。而较小的滤波器具有的一个好处是减少了参数的数量,其次是在每个卷积层之间使用 ReLU 函数可以在网络中引入更多的非线性,使决策函数更具有判别性。

2随着每层输入量的空间尺寸减小(由于池化层的作用),它的深度在逐渐增加。原因是随着空间信息的减小(通过最大池化降采样),图像被编码为更具有判别性的特征来提高分类任务的准确率。因此特征图 (feature map) 的数量随着深度而增加,以便将这些特征图用在分类任务中。

3它介绍了一种新的数据增强方式:抖动 (scale jittering)

4使用 Caffe 工具包搭建模型,从此深度学习库变得越来越流行。

再深一点的网络:GoogLeNet Inception 模块

在文章《Going Deeper with Convolutions》中,GoogLeNet 框架首次真正解决了 计算资源 的问题,并提出了 多尺度处理 方法。当我们不断加深分类网络的深度,我们面临着需要使用大量内存的困境。另外,之前已经发展出了很多不同尺寸的滤波器:从 1x1 11x11,如何选择使用哪种滤波器?Inception 模块和 GoogLeNet 解决了这些问题,具体贡献如下:

1通过在每个 3x3 5x5 卷积之前使用 1x1 卷积,Inception 模块有效地减少了每层特征图的数量,从而减少了计算量和内存损耗!

2Inception 模块具有并行的 1x13x3 5x5 卷积操作。这背后的想法是让网络通过训练来决定哪些信息应当被学习和使用。它还可以进行多尺度处理:模型可以分别通过较小的卷积核和更大的卷积核获得局部特征与抽象特征。

3GoogLeNet 首次引入这样的想法:CNN 的每一层并不总是要依次叠加。本文的作者表示,在追求更深层的网络结构的同时,增加网络宽度当然也可以获得更好的性能。

使用一个捷径来跳跃:ResNet

自从 2015 年《Deep Residual Learning for Image Recognition》首次发布,ResNet 在众多计算机视觉任务的精确度上获得了巨大的提升。ResNet ImageNet 挑战赛上首次超越人类表现,并且残差学习 (residual learning) 如今被普遍应用于很多性能最好的网络:

1证明单纯的堆积网络层使网络更深,这不见得总是好的,实际上这样有可能导致网络性能更差。

2为了解决上面提到的这个问题,他们引入了跨越式连接的残差学习。这个想法通过使用跨越式连接作为一种捷径,网络的深层可以使用前面层的特征。这样使得特征信息可以更好地通过网络传播。同样,训练时梯度也能够更高效地反向传播。

3第一个超深的网络,通常使用 100-200 层。

将捷径扩展到极致:DenseNet

在文章《Densely Connnected Convolutional Networks》中提出的 DenseNet 将快捷连接发展到了极致。DenseNet 扩展了 ResNet 中快捷连接的想法,但比其具有更稠密的连接:

1DenseNet 将每一层与其它层通过前馈方式连接。这样网络的每一层可以使用前面所有层的特征图作为输入,并且它的特征图将会被后面所有层使用。

2使用了串联的方式而不是类似于 ResNet 中直接相加的方式,原始特征因此可以直接通过这些层。

3 ResNet 取得了更好的效果。DenseNet 有效地抑制了梯度消失的问题,增强了特征传播,鼓励特征再利用,大幅减少了参数量。

以上就是过去几年中图像分类任务发展中的一些重要框架。令人激动的是,这些已取得的重大突破与进展已经被用于解决很多实际应用,但是仍然存在一个问题……

深度学习未来将如何发展

尽管深度学习已经取得了很多重大的进展,但是我们仍需保持谦虚的态度,力求让它变得更好。深度学习在图像分类问题中仍然存在很多挑战,如果我们想要获得更进一步的发展,如何解决这些挑战是至关重要的。这里我将回顾一些我认为重要的研究人员正在积极尝试解决的问题:

从有监督学习到无监督学习

如今,大部分图像分类任务使用的深度学习方法都是有监督的,即我们需要大量的标注数据来进行训练,这些数据是单调的,而且难以获得。比如 ImageNet 挑战赛有 130 万张训练样本,但是只有 1000 个不同的种类,并且需要人工获取和标注所有的图像,这是非常费时费力的工作。

很多时候,当公司想要将一个图像分类网络应用到他们自己的具体应用中,他们需要使用迁移学习的思想来微调在 ImageNet 上预训练过的网络。为了微调网络,他们还需要收集自己的数据并进行标注,这仍然是乏味且费时的过程。

研究人员目前正在积极努力地解决这个问题,并取得了一些进展。越来越多的工作开始转向这个方面,比如快速有效地迁移学习,半监督学习和小样本学习。我们可能无法直接进入无监督学习,但是这些方法的研究是朝着正确方向迈出的重要一步。

对抗学习

生成对抗网络 (GAN) 的流行带来了图像分类的一个新挑战:对抗图像。对抗图像的类别对人类来说是显而易见的,但是深度网络却不能正确地识别。比如上面的图像,只是加入了轻微的失真 (表观上的),深度网络就将它从熊猫分到了长臂猿。

这张图像在人类看来这仍然是一只熊猫,但是由于某些原因导致深度网络进行了错误的分类。这在实际应用的时候是非常危险的:试想一下如果自动驾驶汽车没有识别出行人而直接开过去会怎样?导致这一问题的部分原因可能是由于我们对网络内部的原理和机制没有充分的理解,但是无论如何,研究人员正在积极地投身于解决这个具有挑战性的问题当中。

加快进展

深度学习方面的很多进步是由硬件(尤其是 GPU)的改进所驱动的,GPU 可以高速地处理并行计算程序。由于使用矩阵操作,深度网络需要大量的乘加运算,而 GPU 非常擅长这些运算。这对于深度学习的发展来说非常棒,但是并不是所有地方都有 GPU 可以用!

许多顶尖的网络,包括上面已经讨论过的网络,都只能在高端 GPU 上正常运行。移动设备是一个巨大的市场,如何让深度神经网络也能服务于这个市场是关键一步。此外,随着网络越来越深,它们往往需要更多的内存,这也限制了更多的设备来运行网络。

实际上,这方面的研究最近已经有了很大的提升,逐渐流行的 MobileNets 是一种可以直接在移动端运行深度网络的框架。它使用另一种卷积方式来减少内存消耗和推理时间。