首页 > 代码库 > 深度学习补充和总结
深度学习补充和总结
一、损失函数
深度学习中,常用的损失函数为均方误差和交叉熵,分别对应回归和分类问题,其实深度学习的损失函数和机器学习的损失函数差不多,是一致的,均方误差就相当于最小二乘,交叉熵其实是一种特殊的对数损失函数形式,这里不再赘述。
二、激活函数
是深度学习特有的。
关于激活函数,首先要搞清楚的问题是,激活函数是什么,有什么用?不用激活函数可不可以?答案是不可以。激活函数的主要作用是提供网络的非线性建模能力。如果没有激活函数,那么该网络仅能够表达线性映射,此时即便有再多的隐藏层,其整个网络跟单层神经网络也是等价的。因此也可以认为,只有加入了激活函数之后,深度神经网络才具备了分层的非线性映射学习能力。 那么激活函数应该具有什么样的性质呢?
非线性: 当激活函数是线性的时候,一个两层的神经网络就可以逼近基本上所有的函数了。但是,如果激活函数是恒等激活函数的时候(即f(x)=x),就不满足这个性质了,而且如果MLP使用的是恒等激活函数,那么其实整个网络跟单层神经网络是等价的。
可微性: 当优化方法是基于梯度的时候,这个性质是必须的。
单调性: 当激活函数是单调的时候,单层网络能够保证是凸函数。
f(x)≈x: 当激活函数满足这个性质的时候,如果参数的初始化是random的很小的值,那么神经网络的训练将会很高效;如果不满足这个性质,那么就需要很用心的去设置初始值。
输出值的范围: 当激活函数输出值是 有限 的时候,基于梯度的优化方法会更加 稳定,因为特征的表示受有限权值的影响更显著;当激活函数的输出是 无限 的时候,模型的训练会更加高效,不过在这种情况小,一般需要更小的learning rate.
这些性质,也正是我们使用激活函数的原因!
Activation Functions.
Sigmoid
Sigmoid 是常用的非线性的激活函数,它的数学形式如下: f(x)=11+e?x
正如前一节提到的,它能够把输入的连续实值“压缩”到0和1之间。
特别的,如果是非常大的负数,那么输出就是0;如果是非常大的正数,输出就是1.
sigmoid 函数曾经被使用的很多,不过近年来,用它的人越来越少了。主要是因为它的一些 缺点:
Sigmoids saturate and kill gradients. (saturate 这个词怎么翻译?饱和?)sigmoid 有一个非常致命的缺点,当输入非常大或者非常小的时候(saturation),这些神经元的梯度是接近于0的,从图中可以看出梯度的趋势。所以,你需要尤其注意参数的初始值来尽量避免saturation的情况。如果你的初始值很大的话,大部分神经元可能都会处在saturation的状态而把gradient kill掉,这会导致网络变的很难学习。
Sigmoid 的 output 不是0均值. 这是不可取的,因为这会导致后一层的神经元将得到上一层输出的非0均值的信号作为输入。
产生的一个结果就是:如果数据进入神经元的时候是正的(e.g. x>0 elementwise in f=wTx+b),那么 w 计算出的梯度也会始终都是正的。
当然了,如果你是按batch去训练,那么那个batch可能得到不同的信号,所以这个问题还是可以缓解一下的。因此,非0均值这个问题虽然会产生一些不好的影响,不过跟上面提到的 kill gradients 问题相比还是要好很多的。
tanh
tanh 是上图中的右图,可以看出,tanh 跟sigmoid还是很像的,实际上,tanh 是sigmoid的变形:
tanh(x)=2sigmoid(2x)?1
与 sigmoid 不同的是,tanh 是0均值的。因此,实际应用中,tanh 会比 sigmoid 更好(毕竟去粗取精了嘛)。
ReLU
近年来,ReLU 变的越来越受欢迎。它的数学表达式如下:
f(x)=max(0,x)
很显然,从图左可以看出,输入信号<0时,输出都是0,>0 的情况下,输出等于输入。w 是二维的情况下,使用ReLU之后的效果如下:
ReLU 的优点:
Krizhevsky et al. 发现使用 ReLU 得到的SGD的收敛速度会比 sigmoid/tanh 快很多(看右图)。有人说这是因为它是linear,而且 non-saturating
相比于 sigmoid/tanh,ReLU 只需要一个阈值就可以得到激活值,而不用去算一大堆复杂的运算。
ReLU 的缺点: 当然 ReLU 也有缺点,就是训练的时候很”脆弱”,很容易就”die”了. 什么意思呢?
举个例子:一个非常大的梯度流过一个 ReLU 神经元,更新过参数之后,这个神经元再也不会对任何数据有激活现象了。
如果这个情况发生了,那么这个神经元的梯度就永远都会是0.
实际操作中,如果你的learning rate 很大,那么很有可能你网络中的40%的神经元都”dead”了。
当然,如果你设置了一个合适的较小的learning rate,这个问题发生的情况其实也不会太频繁。
Leaky-ReLU、P-ReLU、R-ReLU
Leaky ReLUs: 就是用来解决这个 “dying ReLU” 的问题的。与 ReLU 不同的是:
f(x)=αx,(x<0)
f(x)=x,(x>=0)
这里的 α 是一个很小的常数。这样,即修正了数据分布,又保留了一些负轴的值,使得负轴信息不会全部丢失。
关于Leaky ReLU 的效果,众说纷纭,没有清晰的定论。有些人做了实验发现 Leaky ReLU 表现的很好;有些实验则证明并不是这样。
Parametric ReLU: 对于 Leaky ReLU 中的α,通常都是通过先验知识人工赋值的。
然而可以观察到,损失函数对α的导数我们是可以求得的,可不可以将它作为一个参数进行训练呢?
Kaiming He的论文《Delving Deep into Rectifiers: Surpassing Human-Level Performance on ImageNet Classification》指出,不仅可以训练,而且效果更好。
公式非常简单,反向传播至未激活前的神经元的公式就不写了,很容易就能得到。对α的导数如下:
δyiδα=0,(ifyi>0),else=yi
原文说使用了Parametric ReLU后,最终效果比不用提高了1.03%.
Randomized ReLU:
Randomized Leaky ReLU 是 leaky ReLU 的random 版本 (α 是random的).
它首次试在 kaggle 的NDSB 比赛中被提出的。
核心思想就是,在训练过程中,α 是从一个高斯分布 U(l,u) 中 随机出来的,然后再测试过程中进行修正(有点像dropout的用法)。
数学表示如下:
在测试阶段,把训练过程中所有的 αij 取个平均值。NDSB 冠军的 α 是从 U(3,8) 中随机出来的。那么,在测试阶段,激活函数就是就是:
yij=xijl+u2
看看 cifar-100 中的实验结果:
Maxout
Maxout出现在ICML2013上,作者Goodfellow将maxout和dropout结合后,号称在MNIST, CIFAR-10, CIFAR-100, SVHN这4个数据上都取得了start-of-art的识别率。
Maxout 公式如下:
fi(x)=maxj∈[1,k]zij
假设 w 是2维,那么有:
f(x)=max(wT1x+b1,wT2x+b2)
可以注意到,ReLU 和 Leaky ReLU 都是它的一个变形(比如,w1,b1=0 的时候,就是 ReLU).
Maxout的拟合能力是非常强的,它可以拟合任意的的凸函数。作者从数学的角度上也证明了这个结论,即只需2个maxout节点就可以拟合任意的凸函数了(相减),前提是”隐隐含层”节点的个数可以任意多.
所以,Maxout 具有 ReLU 的优点(如:计算简单,不会 saturation),同时又没有 ReLU 的一些缺点 (如:容易 go die)。不过呢,还是有一些缺点的嘛:就是把参数double了。
还有其他一些激活函数,请看下表:
How to choose a activation function?
怎么选择激活函数呢?
我觉得这种问题不可能有定论的吧,只能说是个人建议。
如果你使用 ReLU,那么一定要小心设置 learning rate,而且要注意不要让你的网络出现很多 “dead” 神经元,如果这个问题不好解决,那么可以试试 Leaky ReLU、PReLU 或者 Maxout.
三、优化算法
深度学习的优化算法跟机器学习也大体一样,但出现一些专门用于神经网络的优化算法,现在一一介绍。
主要是一阶的梯度法,包括SGD, Momentum, Nesterov Momentum, AdaGrad, RMSProp, Adam。 其中SGD,Momentum,Nesterov Momentum是手动指定学习速率的,而后面的AdaGrad, RMSProp, Adam,就能够自动调节学习速率.
二阶的方法目前还不太常用。
BGD
即batch gradient descent. 在训练中,每一步迭代都使用训练集的所有内容. 也就是说,利用现有参数对训练集中的每一个输入生成一个估计输出yi^,然后跟实际输出yi比较,统计所有误差,求平均以后得到平均误差,以此来作为更新参数的依据.
具体实现:
需要:学习速率 ?, 初始参数 θ
每步迭代过程:
1. 提取训练集中的所有内容{x1,…,xn},以及相关的输出yi
2. 计算梯度和误差并更新参数:
优点:
由于每一步都利用了训练集中的所有数据,因此当损失函数达到最小值以后,能够保证此时计算出的梯度为0,换句话说,就是能够收敛.因此,使用BGD时不需要逐渐减小学习速率?k
缺点:
由于每一步都要使用所有数据,因此随着数据集的增大,运行速度会越来越慢.
SGD
SGD全名 stochastic gradient descent, 即随机梯度下降。不过这里的SGD其实跟MBGD(minibatch gradient descent)是一个意思,即随机抽取一批样本,以此为根据来更新参数.
具体实现:
需要:学习速率 ?, 初始参数 θ
每步迭代过程:
1. 从训练集中的随机抽取一批容量为m的样本{x1,…,xm},以及相关的输出yi
2. 计算梯度和误差并更新参数:
优点:
训练速度快,对于很大的数据集,也能够以较快的速度收敛.
缺点:
由于是抽取,因此不可避免的,得到的梯度肯定有误差.因此学习速率需要逐渐减小.否则模型无法收敛
因为误差,所以每一次迭代的梯度受抽样的影响比较大,也就是说梯度含有比较大的噪声,不能很好的反映真实梯度.
学习速率该如何调整:
那么这样一来,?如何衰减就成了问题.如果要保证SGD收敛,应该满足如下两个要求:
而在实际操作中,一般是进行线性衰减:
其中?0是初始学习率, ?τ是最后一次迭代的学习率. τ自然代表迭代次数.一般来说,?τ 设为?0的1%比较合适.而τ一般设为让训练集中的每个数据都输入模型上百次比较合适.那么初始学习率?0怎么设置呢?书上说,你先用固定的学习速率迭代100次,找出效果最好的学习速率,然后?0设为比它大一点就可以了.
Momentum
上面的SGD有个问题,就是每次迭代计算的梯度含有比较大的噪音. 而Momentum方法可以比较好的缓解这个问题,尤其是在面对小而连续的梯度但是含有很多噪声的时候,可以很好的加速学习.Momentum借用了物理中的动量概念,即前几次的梯度也会参与运算.为了表示动量,引入了一个新的变量v(velocity).v是之前的梯度的累加,但是每回合都有一定的衰减.
具体实现:
需要:学习速率 ?, 初始参数 θ, 初始速率v, 动量衰减参数α
每步迭代过程:
1. 从训练集中的随机抽取一批容量为m的样本{x1,…,xm},以及相关的输出yi
2. 计算梯度和误差,并更新速度v和参数θ:
其中参数α表示每回合速率v的衰减程度.同时也可以推断得到,如果每次迭代得到的梯度都是g,那么最后得到的v的稳定值为
也就是说,Momentum最好情况下能够将学习速率加速11?α倍.一般α的取值有0.5,0.9,0.99这几种.当然,也可以让α的值随着时间而变化,一开始小点,后来再加大.不过这样一来,又会引进新的参数.
特点:
前后梯度方向一致时,能够加速学习
前后梯度方向不一致时,能够抑制震荡
Nesterov Momentum
这是对之前的Momentum的一种改进,大概思路就是,先对参数进行估计,然后使用估计后的参数来计算误差
具体实现:
需要:学习速率 ?, 初始参数 θ, 初始速率v, 动量衰减参数α
每步迭代过程:
1. 从训练集中的随机抽取一批容量为m的样本{x1,…,xm},以及相关的输出yi
2. 计算梯度和误差,并更新速度v和参数θ:
注意在估算g^的时候,参数变成了θ+αv而不是之前的θ
AdaGrad
AdaGrad可以自动变更学习速率,只是需要设定一个全局的学习速率?,但是这并非是实际学习速率,实际的速率是与以往参数的模之和的开方成反比的.也许说起来有点绕口,不过用公式来表示就直白的多:
其中δ是一个很小的常亮,大概在10?7,防止出现除以0的情况.
具体实现:
需要:全局学习速率 ?, 初始参数 θ, 数值稳定量δ
中间变量: 梯度累计量r(初始化为0)
每步迭代过程:
1. 从训练集中的随机抽取一批容量为m的样本{x1,…,xm},以及相关的输出yi
2. 计算梯度和误差,更新r,再根据r和梯度计算参数更新量
优点:
能够实现学习率的自动更改。如果这次梯度大,那么学习速率衰减的就快一些;如果这次梯度小,那么学习速率衰减的就满一些。
缺点:
任然要设置一个变量?
经验表明,在普通算法中也许效果不错,但在深度学习中,深度过深时会造成训练提前结束。
RMSProp
RMSProp通过引入一个衰减系数,让r每回合都衰减一定比例,类似于Momentum中的做法。
具体实现:
需要:全局学习速率 ?, 初始参数 θ, 数值稳定量δ,衰减速率ρ
中间变量: 梯度累计量r(初始化为0)
每步迭代过程:
1. 从训练集中的随机抽取一批容量为m的样本{x1,…,xm},以及相关的输出yi
2. 计算梯度和误差,更新r,再根据r和梯度计算参数更新量
优点:
相比于AdaGrad,这种方法很好的解决了深度学习中过早结束的问题
适合处理非平稳目标,对于RNN效果很好
缺点:
又引入了新的超参,衰减系数ρ
依然依赖于全局学习速率
RMSProp with Nesterov Momentum
当然,也有将RMSProp和Nesterov Momentum结合起来的
具体实现:
需要:全局学习速率 ?, 初始参数 θ, 初始速率v,动量衰减系数α, 梯度累计量衰减速率ρ
中间变量: 梯度累计量r(初始化为0)
每步迭代过程:
1. 从训练集中的随机抽取一批容量为m的样本{x1,…,xm},以及相关的输出yi
2. 计算梯度和误差,更新r,再根据r和梯度计算参数更新量
Adam
Adam(Adaptive Moment Estimation)本质上是带有动量项的RMSprop,它利用梯度的一阶矩估计和二阶矩估计动态调整每个参数的学习率。Adam的优点主要在于经过偏置校正后,每一次迭代学习率都有个确定范围,使得参数比较平稳。
具体实现:
需要:步进值 ?, 初始参数 θ, 数值稳定量δ,一阶动量衰减系数ρ1, 二阶动量衰减系数ρ2
其中几个取值一般为:δ=10?8,ρ1=0.9,ρ2=0.999
中间变量:一阶动量s,二阶动量r,都初始化为0
每步迭代过程:
1. 从训练集中的随机抽取一批容量为m的样本{x1,…,xm},以及相关的输出yi
2. 计算梯度和误差,更新r和s,再根据r和s以及梯度计算参数更新量
深度学习补充和总结