本文主要是介绍深度学习500问——Chapter13:优化算法(1),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
文章目录
13.1 如何解决训练样本少的问题
13.2 深度学习是否能胜任所有数据集
13.3 有没有可能找到比已知算法更好的算法
13.4 什么是共线性,如何判断和解决共线性问题
13.5 权值初始化方法有哪些
13.6 如何防止梯度下降陷入局部最优解
13.7 为什么需要激活函数
13.8 常见的损失函数有哪些
13.1 如何解决训练样本少的问题
目前大部分的深度学习模型仍然需要海量的数据支持。例如ImageNet数据就拥有1400多万的图片,而现实生产环境中,数据集通常较小,只有几万甚至几百个样本。这时候,如何在这种情况下应用深度学习呢?
(1)利用预训练模型进行迁移微调(fin-tuning),预训练模型通常在特征上拥有很好的语义表达。此时,只需将模型在小数据集上进行微调就能取得不错的效果。这也是目前大部分小数据集常用的训练方式。视觉领域内,通常会在ImageNet上训练完成的模型。自然语言处理领域,也有BERT模型等预训练模型可以使用。
(2)单样本或者少样本学习(one-shot,few-shot learning),这种方式适用于样本类别远远大于样本数量的情况等极端数据集。例如有1000个类别,每个类别只提供1-5个样本。少样本学习同样也需要借助预训练模型,但有别于微调的在于,微调通常仍然在学习不同类别的语义,而少样本学习通常需要学习样本之间的距离度量。例如孪生网络(Siamese Neural Networks)就是通过训练两个同种结构的网络来判别输入的两张图片是否属于同一类。上述两种是常用训练小样本数据集的方式。此外,也有些常用的手段,例如数据集增强、正则或者半监督学习等方式来解决小样本数据集的训练问题。
13.2 深度学习是否能胜任所有数据集
深度学习并不能胜任目前所有的数据环境,以下列举两种情况:
(1)深度学习能取得目前的成果,很大有一部分原因依赖于海量的数据集以及高性能密集计算硬件,因此,当数据集过小时,需要考虑与传统机器学习相比,是否在性能和硬件资源效率更具有优势。
(2)深度学习目前在视觉、自然语言处理等领域都有取得不错的成果,这些领域最大的特点就是具有局部相关性。例如图像中,人的耳朵位于两侧,鼻子位于两眼之间,文本中单词组成句子,这些都是具有局部相关性的,一旦被打乱则会破坏语义或者有不同的语义。所以当数据不具备这种相关性的时候,深度学习就很难取得效果。
13.3 有没有可能找到比已知算法更好的算法
在最优化理论发展中,有个没有免费午餐的定律,其主要含义在于,在不考虑具体背景和细节的情况下,任何算法和随机猜的效果期望是一样的。即,没有任何一种算法能优于其他一切算法,甚至不比随机猜好。深度学习作为机器学习领域的一个分支同样符合这个定律。所以,虽然目前深度学习取得了非常不错的成果,但是我们同样不能盲目崇拜。
优质算法本质上是在寻找和探索更符合数据集和问题的算法,这里数据集是算法的驱动力,而需要通过数据集解决的问题就是算法的核心,任何算法脱离了数据都会没有实际价值,任何算法的假设都不能脱离实际问题。因此,在实际应用中,面对不同的场景和不同的问题,可以从多个角度针对问题进行分析,寻找更优的算法。
13.4 什么是共线性,如何判断和解决共线性问题
对于回归算法,无论是一般回归还是逻辑回归,在使用多个变量进行预测分析时,都可能存在多变量相关的情况,这就是多重共线性。共线性的存在,使得特征之间存在冗余,导致过拟合。
常用判断是否存在共线性的方法有:
(1)相关性分析。当相关性系数高于0.8,表明存在多重共线性;但相关系数很低,并不能表示不存在多重共线性;
(2)方差膨胀因子VIF。当VIF大于5或10时。代表模型存在严重的共线性问题;
(3)条件系数检验。当条件数大于100、1000时吗,代表模型存在严重的共线性问题。
通常可通过PCA降维、逐步回归法和LASSO回归等方法消除共线性。
13.5 权值初始化方法有哪些
在深度学习模型中,从零开始训练时,权值的初始化有时候会对模型训练产生较大的影响。良好的初始化能让模型快速、有效的收敛,而糟糕的初始化会使得模型无法训练。
目前,大部分深度学习框架都提供了各类初始化方式,其中一般常用的会有如下几种:
1. 常数初始化(constant)
把权值或者偏置初始化为一个常数。例如设置为0,偏置初始化为0较为常见,权重很少会初始化为0。TensorFlow中也有 zeros_initializer、ones_initializer等特殊常数初始化函数。
2. 高斯初始化(gaussian)
给定一组均值和标准差,随机初始化的参数会满足给定均值和标准差的高斯分布。高斯初始化是很常用的初始化方式。特殊地,在TensorFlow中还有一种截断高斯分布初始化(truncated_normal_initializer),其主要为了将超过两个标准差的随机数重新随机,使得随机数更稳定。
3. 均匀分布初始化(uniform)
给定最大最小的上下限,参数会在该范围内以均匀分布方式进行初始化,常用上下限为(0,1)。
4. xavier初始化
在batchnorm还未出现之前,要训练较深的网络,防止梯度弥散,需要依赖非常好的初始化方式。xavier就是一种比较优秀的初始化方式,也是目前最常用的初始化方式之一。其目的是为了使得模型各层的激活值和梯度在传播过程中的方差保持一致。本质上xavier还是属于均匀分布初始化,但与上述的均匀分布初始化有所不同,xavier的上下限将在如下范围内进行均匀分布采样:
其中,n为所在层的输入维度,m为所在层的输出维度。
5. kaiming初始化(msra初始化)
kaiming初始化,在caffe中也叫msra初始化。kaiming初始化和xavier一样都是为了防止梯度弥散而使用的初始化方式。kaiming初始化的出现是因为xavier存在一个不成立的假设。xavier在推导中假设激活函数都是线性的,而在深度学习中常用的ReLu等都是非线性的激活函数。而kaiming初始化本质上是高斯分布初始化,与上述高斯分布初始化有所不同,其是个满足均值为0,方差为2/n的高斯分布:
其中,n为所在层的输入维度。
除了上述常见的初始化方式以外,不同深度学习框架下也会有不同的初始化方式,读者可自行查阅官方文档。
13.6 如何防止梯度下降陷入局部最优解
梯度下降法(GD)及其一些变种算法是目前深度学习里最常用于求解凸优化问题的优化算法。神经网络很可能存在很多局部最优解,而非全局最优解。为了防止陷入局部最优,通常会采用如下一些方法,当然,这并不能保证一定能找到全局最优解,或许能得到一个比目前更优的局部最优解也是不错的:
(1)stochastic GD / Mini-Batch GD
在GD算法中,每次的梯度都是从所有样本中累计获取的,这种情况最容易导致梯度方向过于稳定一致,且更新次数过少,容易陷入局部最优。而stochastic GD是GD的另一种极端更新方式,其每次都只使用一个样本进行参数更新,这样更新次数大大增加也就不容易陷入局部最优。但引出的一个问题在于其更新方向过多,导致不易于进一步优化。Mini-Batch GD便是两种极端的折中,即每次更新使用一小批样本进行参数更新。Mini-Batch GD是目前最常用的优化算法,严格意义上Mini-Batch GD也叫做stochastic GD,所以很多深度学习框架上都叫做SGD。
(2)动量
动量也是GD中常用的方式之一,SGD的更新方式虽然有效,但每次只依赖于当前批样本的梯度方向,这样的梯度方向依然很可能很随机。动量就是用来减少随机,增加稳定性。其思想是模仿物理学的动量方式,每次更新前加入部分上一次的梯度量,这样整个梯度方向就不容易过于随机。一些常见的情况时,如上次梯度过大,导致进入局部最小点时,下一次更新能很容易借助上次的大梯度跳出局部最小点。
(3)自适应学习率
无论是GD还是动量重点优化角度是梯度方向,而学习率则是用来直接控制梯度更新幅度的超参数。自适应学习率的优化方法有很多,例如Adagrad 和 RMSprop。两种自适应学习率的方式稍有差异,但主要思想都是基于历史的累计梯度去计算一个当前较优的学习率。
13.7 为什么需要激活函数
(1)非线性:即导数不是常数。这个条件是多层神经网络的基础,保证多层网络不退化成单层线性网络。这也是激活函数的意义所在。
(2)几乎处处可微:可微性保证了在优化中梯度的可计算性。传统的激活函数如sigmoid等满足处处可微。对于分段线性函数比如ReLU。只满足几乎处处可微(即仅在有限个点处不可微)。对于SGD算法来说,由于几乎不可能收敛到梯度接近零的位置,有限的不可微点对于优化结果不会有很大影响[1]。
(3)计算简单:非线性函数有很多。极端的说,一个多层神经网络也可以作为一个非线性函数,类似于Network In Network[2]中把它当做卷积操作的做法。但激活函数在神经网络前向的计算次数与神经元的个数成正比,因此简单的非线性函数自然更适合用作激活函数。这也是ReLU之流比其它使用Exp等操作的激活函数更受欢迎的其中一个原因。
(4)非饱和性(saturation):饱和指的是在某些区间梯度接近于零(即梯度消失),使得参数无法继续更新的问题。最经典的例子是Sigmoid,它的导数在x为比较大的正值和比较小的负值时都会接近于0。更极端的例子是阶跃函数,由于它在几乎所有位置的梯度都为0,因此处处饱和,无法作为激活函数。ReLU在 x>0 时导数恒为1。因此对于再大的正值也不会饱和。但同时对于 x<0 ,其梯度恒为0,这时候它也会出现饱和的现象(在这种情况下通常称为 dying ReLU)。Leaky ReLU[3]和PReLU[4]的提出正是为了解决这一问题。
(5)单调性(monotonic):即导数符号不变。这个性质大部分激活函数都有,除了诸如 sin、cos等。个人理解,单调性使得在激活函数处的梯度方向不会经常改变,从而让训练更容易收敛。
(6)输出范围有限:有限的输出范围使得网络对于一些比较大的输入也会比较稳定,这也是为什么早期的激活函数都以此类函数为主,如Sigmoid、TanH。但这导致了前面提到的梯度消失问题,而且强行让每一层的输出限制到固定范围会限制其表达能力。因此现在这类函数仅用于某些需要特定输出范围的场合,比如概率输出(此时loss函数中的log操作能够抵消其梯度消失的影响[1])、LSTM里的gate函数。
(7)接近恒等变换(identity):即约等于x。这样的好处是使得输出的幅值不会随着深度的增加而发生显著的增加,从而使网络更为稳定,同时梯度也能更容易地回传。这个与非线性是有点矛盾的,因此激活函数基本只是部分满足这个条件,比如Tanh只在原点附近有线性区(在原点为0且在原点的导数为1),而ReLU只在 x>0 时为线性。这个性质也让初始化参数范围的推导更为简单[5][4]。额外提一句,这种恒等变换的性质也被其他一些网络结构设计所借鉴,比如CNN中的ResNet[6]和RNN中的LSTM。
(8)参数少:大部分激活函数都是没有参数的。像PReLU带单个参数会略微增加网络的大小。还有一个例外是Maxout[7],尽管本身没有参数,但在同样输出通道数下k路Maxout需要的输入通道数是其它函数的k倍,这意味着神经元数目也需要变为k倍;但如果不考虑维持输出通道数的情况下,该激活函数又能将参数个数减少为原来的k倍。
(9)归一化(normalization):这个是最近才出来的概念,对应的激活函数是SELU[8],主要思想是使样本分布自动归一化到零均值、单位方差的分布,从而稳定训练。在这之前,这种归一化的思想也被用于网络结构的设计,比如Batch Normalization[9]。
13.8 常见的损失函数有哪些
机器学习通过对算法中的目标函数进行不断求解优化,得到最终想要的结果。分类和回归问题中,通常使用损失函数或代价函数作为目标函数。
损失函数用来评价预测值和真实值不一样的程度。通常损失函数越好,模型的性能也越好。
损失函数可分为经验风险损失和结构风险损失。经验风险损失是根据已知数据得到的损失。结构风险损失是为了防止模型过度拟合已知数据而加入的惩罚项。
下面介绍常用的损失函数:
(1)0-1损失函数
如果预测值和目标值相等,值为0,如果不相等,值为1:
一般的在实际使用中,相等的条件过于严格,可适当放宽条件:
(2)绝对值损失函数
和 0-1 损失函数相似,绝对值损失函数表示为:
(3)平方损失函数
这点可从最小二乘法和欧几里得距离角度理解。最小二乘法的原理是,最优拟合曲线应该使所有点到回归直线的距离和最小。
(4)log 对数损失函数
常见的逻辑回归使用的就是对数损失函数,有很多人认为逻辑回归的损失函数是平方损失,其实不然。逻辑回归它假设样本服从伯努利分布,进而求得满足该分布的似然函数,接着取对数求极值等。逻辑回归推导出的经验风险函数是最小化负的似然函数,从损失函数的角度看,就是log损失函数。
(5)指数损失函数
指数损失函数的标准形式为:
例如 AdaBoost 就是以指数损失函数为损失函数。
(6)Hinge 损失函数
Hinge损失函数的标准形式如下:
其中, y是预测值,范围是(-1,1),t为目标值,其为-1 或 1。
在线性支持向量机中,最优化问题可等价于:
其中, 是Hinge损失函数, 可看作为正则化项。
这篇关于深度学习500问——Chapter13:优化算法(1)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!