改善深层神经网络——吴恩达深度学习课程笔记(二)

2020-07-20 11:48:30 浏览数 (1)

文章总览图

改进网络结构

常用的对网络结构的改进包括正则化和标准化,正则化可以解决深度网络的过拟合问题,标准化可以加快学习过程。为了缓解较深的网络由于指数效应导致的梯度爆炸和梯度消失问题,需要合理地设置网络权重参数初始值。此外对于多分类问题,通常在最后一个神经元使用softmax分类器。

1,正则化方法

L2正则化:

L2正则化在损失函数加入网络权重参数平方和,从而使得网络权重倾向于取更小的值。

dropout正则化:

dropout正则化通过以一定的概率随机设置某些隐藏层节点输出值为0,相当于给网络增加了一些干扰。通常对节点个数越多的隐藏层,需要设置越大的dropout概率,对输入层一般全部保留。dropout正则化方法是计算机视觉领域中的常规做法。

数据扩增:

Early Stopping :

2,标准化方法

输入标准化:

对输入数据通过Min-Max或Z-Score等标准化等方法可以将不同特征缩放到相当的变化范围,可以使得等值面更“圆”,从而加快梯度下降学习进程。

Batch Norm标准化:

我们不仅可以对输入层节点的值进行标准化缩放,对于各个隐藏层节点,我们也能够在计算激活函数值之前进行某种标准化处理,这就是Batch Norm标准化。它相当于在神经元的线性组合和非线性映射2步操作之间增加了1步平移缩放操作,变成了3步操作。

进行Batch Norm标准化时,我们先将对上一层神经元的输出a线性组合得到的z值作标准化处理,即平移和缩放成0均值和单位标准差,然后再对标准化后的结果使用γ和β两个参数进一步进行线性变换。由于对z作了去均值处理,因此其截距b的作用被消除了。和不作Batch Norm标准化时只有W和b两组参数相比,现在我们有W和γ,和β三组参数。这三组参数都是需要使用梯度下降进行学习的。

由于Batch Norm标准化处理总是能够将激活函数的输入缩放到β均值和γ标准差,从而能够不受输入数据整体分布发生漂移情况的影响,不同层之间可以进行相对独立的学习,从而增强了网络的适应能力。

此外,当使用mini-batch梯度下降法进行学习时,采用Batch Norm标准化还会取得轻微的正则化效果。其原理和dropout类似,由于不同的batch对均值和标准差的估计会有所差异,因此相当于对网络施加了一定的噪声干扰。

3,梯度爆炸和梯度消失

对于层数很深的网络,由于指数增长或指数衰减效应,容易出现梯度爆炸和梯度消失的现象。通过选择合适的初始权重能够缓解该现象。一般会取值让各个节点值的初始方差为1。

4,梯度检验

如果是人工方法实现的神经网络反向传播,可以使用数值逼近方法计算梯度,与求导计算的梯度进行对比,以检验反向传播过程是否正确。对于使用tensorflow等框架实现的神经网络,一般无需梯度检验。

5,softmax回归

对于回归问题,通常神经网络的最后一层设置为线性回归层,其激活函数为等值激活函数,采用平方损失函数。对于二分类问题,神经网络的最后一层通常设置为logistic回归层,其激活函数为sigmoid激活函数,采用交叉熵损失函数。而对于多分类问题,通常设置最后一层为softmax回归层,它是logistic回归的扩展,具有多个输出值用来表示样本分别属于多个不同类别的概率,其损失函数也具有交叉熵形式。

优化学习算法

梯度下降法是求解函数最小值的非常简单的数值迭代方法,但有时候效率偏低。针对梯度下降法可以有多方面的改进,以提升学习效率,减少迭代次数。

1,mini-batch算法(小批量梯度下降)

当样本数量很大时,对全部样本一次性进行损失函数的计算和执行梯度下降会导致较大的内存开销,可能很长的时间都不能够执行完成一次梯度下降,从而影响效率。mini-batch算法每次只使用部分样本计算损失函数和执行梯度下降,只需要很短的时间就可以看到损失函数下降的效果,整体性能会有较大的提升。

普通的使用全部样本进行训练的算法叫做batch梯度下降。在mini-batch梯度下降算法中,batch大小常取32,64,128,256,512这样的值,具体取决于机器性能。

如果batch大小取为1,则叫做随机梯度下降 stochastic gradient descend (SGD)算法。通常batch大小越大,损失函数下降曲线会越稳定。

2,momentum算法 (动量算法)

梯度下降算法在趋近最小值的过程中,如果等值面像一个"椭圆",学习率选取较大,可能会走弯曲的路线。动量算法通过使用梯度的指数加权平均数来代替梯度,从而抑制梯度的折返。

3,RMSprop算法 (均方根传播算法)

RMSprop算法是另一种抑制梯度折返的方法,其主要思想是对梯度除以梯度的均方根,由于平方后恒为正,折返方向的均方根将会显著大于正常前进方向的均方根,从而能够抑制梯度折返。

4,Adam算法(自适应矩估计算法)

Adam算法是深度学习领域实践当中使用最普遍的优化算法。它可以看成是momentum算法和RMSprop算法的结合。值的注意的是,它对动量和均方根都作了偏差修正。

5,learning rate decay(学习率衰减)

学习率衰减通过在迭代过程中不断降低学习率来减少最优值附近的波动。这种策略可以叠加到梯度下降,Adam算法等优化算法上。

6,局部最优问题

尽管我们使用梯度下降法来求解神经网络目标函数的最小值。但实际上神经网络的目标函数并不是关于网络权重参数的一个凸函数,也就是说它可能存在着许多局部最小值。当我们选取不同的初始值,我们可能会落入到不同的局部最小值。例如,如果我们在初始化网络权重时不是随机初始化网络权重而是全部初始化成相同的值,那么我们得到的最终结果也将是对称的网络权重。这就说明我们最终求得的神经网络的权重是初始值依赖的。

但实际上,如果我们用不同的方式随机地初始化网络权重,经过训练后,我们几乎总是能够得到等价的网络权重,即不同的初始值得到的网络可能有同一层节点之间顺序的调换,但它们的计算结果是等价的,最终求得的最小目标函数值也是相当的。这是为什么呢?主要原因是神经网络的目标函数是一个高维函数,我们在低维空间的直觉并不适用。对于一个二维空间的函数,我们可能会觉得很容易遇到局部最大和局部最小值。但是对于一个高维空间的函数,出现鞍点的概率远高于局部最大和局部最小值的概率。

例如一个有100个参数的高维空间函数,如果我们要求其局部最小值,那么我们要找到函数对其100个参数的一阶偏导数全部等于0的点。但是对于这些点,只有函数还满足对这100个参数的二阶偏导数全部大于等于0,这些点才是局部最小值,这个概率约等于0.5的100次方,只要有一个参数的二阶偏导小于0,那么这个点就成为了鞍点。所以,对于神经网络的目标函数,尽管它不是一个凸函数,但我们遇见局部最小值和局部最大值的的概率很小很小,所以我们使用梯度下降等迭代算法依然能够非常有效地求得其全局最小值。我们不必过分担心落入局部最小值,而应该更加关注在鞍点附近学习速率降低的现象。

超参数调试

1,参数的重要顺序

学习率最重要,其次是momentum算法的β参数,隐藏层神经元的个数,以及mini-batch的大小,第三重要的是网络的层数和学习率衰减的参数。如果使用Adam算法,那么设置β1=0.9,β2=0.99就可以了,几乎不需要调整Adam算法的相应参数。

2,参数的候选值分布

对于不同的参数,由于模型对它们的敏感性不同,应当设置不同的参数候选值分布。节点个数n[l]和层数layers的参数候选值可以平均分布,学习率参数α则应当指数分布,而动量算法的参数β的候选值则应当合适选取使得1/(1-β)呈指数分布。

3,随机搜索vs网格搜索

当我们的模型具有多个超参数时,如果要同时对这些超参数进行调优,由于很多时候某些参数会比其它参数更加重要,为了让更重要的参数能够多选取一些可能的取值,随机搜索超参数组合的策略通常会优于网格搜索策略。

4,Coarse to fine

为了更加有效地搜索超参数组合,由粗到细不断缩小搜索范围是一种常用的策略。对于随机搜索策略,可以把包含了上一轮前几个最优的超参数组合的更小的超参数组合取值范围作为下一轮随机搜索的范围。

5,Pandas vs Caviar

在超参数调优中,有两种不同的方法论。一种可以称之为Pandas方法论,另一种则可以称之为Cavia方法论。当我们计算资源有限时,我们可能只能同时训练一个模型,然后一天两天不断地去优化其超参数,就好像熊猫的繁殖策略,它们只有很少的幼崽,然后每一个都细心呵护。但如果我们有很多的计算资源,我们则更应该采取鱼子酱策略,我们可以同时并行地训练很多不同超参数组合的模型,然后根据一定的标准,从里面选出表现最好的,就好像鱼类的繁殖策略,它们会同时孵化大量鱼苗,然后几乎不加以照顾任其自生自灭,虽然很多最后都夭折了,但只要有一些能够生存下来,整个族群就可以繁衍。

深度学习框架

1,常用的学习框架

虽然徒手构建神经网络也许可以帮助我们更好地理解深度学习的一些原理细节,但是在实际工作中,基于现有的深度学习框架来搭建神经网络则更为高效可行。

目前主流的开源深度学习框架包括谷歌主导的TensorFlow,脸书主导的Torch,微软主导的CNTK,亚马逊支持的MXNet,以及以TensorFlow和Theano,CNTK等框架为后端可用于快速实现深度学习原型的高级库Keras。

以下为七大主流深度学习框架优势对比(CNTK在2.0之后引入了对Keras的支持)。

从上述对比表格可以看出,TensorFlow在学习材料丰富性、对CNN的建模能力和整体架构设计上都是最出色的,Torch在速度方面胜过TensorFlow,CNTK在RNN的支持方面比TensorFlow更为强大,依然是自然语言处理领域的重要工具,而MXNet拥有最强大的的多核GPU扩展支持。

综上,对于新手来说,深度学习框架优先学习TensorFlow,然后等TensorFlow掌握到一定程度,很快就能够学会更加高级的Keras接口以快速搭建神经网络原型。如果对自然语言处理方向感兴趣,可以学习一下CNTK。此外,如果有兴趣还可以选择学习一下PyTorch。

2,TensorFlow基础

请允许我引用官网上的这段话来介绍TensorFlow。

TensorFlow™ 是一个采用数据流图(data flow graphs),用于数值计算的开源软件库。节点(Nodes)在图中表示数学操作,图中的线(edges)则表示在节点间相互联系的多维数据数组,即张量(tensor)。它灵活的架构让你可以在多种平台上展开计算,例如台式计算机中的一个或多个CPU(或GPU),服务器,移动设备等等。TensorFlow 最初由Google大脑小组(隶属于Google机器智能研究机构)的研究员和工程师们开发出来,用于机器学习和深度神经网络方面的研究,但这个系统的通用性使其也可广泛用于其他计算领域

程序 = 数据结构 算法

TensorFlow的数据结构为张量(Tensor)。张量即多维数组,TensorFlow中的Tensor对象和Python的numpy库的ndarray对象可以无缝对接。

TensorFlow的算法表达形式为计算图。计算图为单向图,计算图由节点和线组成,节点表示操作符,操作符有0个或多个输入以及0个或多个输出。线表示计算间的依赖,线可以是实线或虚线。实线表示有数据传递,虚线通常可以表示先后依赖关系。

使用TensorFlow的一般流程通常如下:

1,用一组Operator定义计算图。

2,使用Session执行计算图。

3,在TensorBoard中查看计算图。(可选)

下面为示范代码:计算 e = 3*5 (3 5)

代码语言:javascript复制
import numpy as np
import tensorflow as tf 

# 定义计算图
graph = tf.Graph()
with graph.as_default(): 
    a = tf.constant(0,name = 'input_a')
    b = tf.constant(0,name = 'input_b')
    c = tf.multiply(a,b,name = 'mul_c')
    d = tf.add(a,b,name = 'add_d')
    e = tf.add(c,d,name = 'add_e')

# 执行计算图
with tf.Session(graph = graph) as sess:
    output = sess.run(fetches = e,feed_dict = {a:3,b:5})
    print(output)
    # 指定计算图写入文件的路径
    writer = tf.summary.FileWriter('./my_graph',sess.graph)

打开cmd命令行,用cd指令切换到当前路径后,输入如下命令:

tensorboard --logdir='my_graph'

成功运行tensorboard后,根据提示在浏览器窗口输入如下地址即可进入tensorboard界面查看我们创建的美丽的数据流图。

http://localhost:6006

0 人点赞