深度模型的优化
优化的问题:寻找一组参数,能够显著的降低损失函数。损失函数通常包括整个数据集上的性能评估和额外的正则化
学习和纯粹的优化的不同
深度学习的优化算法和和传统的优话算法有几个方面的不同:
- 在深度学习/机器学习的优化过程中,我们关注某些性能度量P,但是它可能是不可求解的,所以,我们是间接的优化P。我们希望通过降低代价函数 $J(\theta)$来提高P
- 而纯优化是最小化目标J本身。
经验风险最小化
最小化平均训练误差的训练过程是经验风险最小化的过程。
代理损失函数
我们真正关心的损失函数(比如分类误差)并不能高效的优化(因为不是凸函数)。例如,在二元分类中,我们真正关心的是0-1损失函数,
$$ l(y,y^)=∑_{i=1}^mχ(yi≠y^i) $$
但是,这个损失函数无法进行优化。
这种情况下,我们会选择使用代理损失函数,将原来的优化问题转化为一个近似的优化问题,而且近似的优化问题更容易求解。
提前终止
批量算法和小批量算法
假设样本之间独立,那么n个样本的均值的标准差是$\sigma / \sqrt{n}$,其中$\sigma$是样本值的真是方差,分母为$\sqrt{n}$表示更多的样本来估计梯度的方法的回报是小于线性的。
计算量的问题。
所以,我么会采用随机采样少量样本作为一个batch,然后计算平均值。
使用整个训练集的优化算法成为批量或者确定性
深度学习采用的是小批量或者小批量随机d的方法,通常简称为*随机(stochastic)方法
小批量带下通常由以下因素决定:
- 大批量会得到更加准确的梯度,但是回报是小于线性的
- 极小的批量无法充分利用多核的架构
- 批量大小和内存占用成正比
- 硬件对于特征的数(比如2的指数)的运行时间更小
- 小批量在学习过程中增加了噪音的影响,一定程度上起到了正则化的方法
不同的优化算法从不同的小批量中获取到不同的信息,一般而言,基于梯度的更新g相对鲁棒,在较小的批量就能成功,比如100.
基于Hessian矩阵的二阶更新方法则通常需要更大的批量。
小批量是随机抽取的这点很重要,因为样本的无偏估计要求样本之间是独立的。通常的做法是将训练样本shuffle。
神经网络中的挑战
病态问题
病态体现在随机梯度”卡“在某个位置,此时即使很小的更新步长也大大增加代价函数。
局部极小值
对于非凸的问题,如深度学习,有可能存在多个局部极小值。
但是,大多数局部极小值都具有很小的代价函数,我们能不能找到全局最小点并不重要。
高原、鞍点和其他平坦区域
对于高纬度非凸函数,局部极小值实际上都远小于另一种梯度为0的点:鞍点。
在鞍点出,Hessian矩阵同时有正负特征值。
Hessian在极小值处只有正特征值。
悬崖和梯度爆炸哦
遇到梯度极大的悬崖结构,梯度更新很大将可能导致权值远离最优点
解决方法:梯度截断的方法。
长期依赖
主要出现在序列模型中,由于变深的结构使得模型丧失了学习到先前信息的能力,让优化变得困难。
在多个事件步上讲输入重复和权值W相乘,将会导致结果丢弃了x中与权值W的主特征向量正交的成分。
基本算法
随机梯度下降
按照数据生成分布抽取m个独立同分布的赝本,九三他们的梯度均值,就可以得到梯度的无偏估计
在实践中,我们有必要随着时间推移逐渐降低学习率。
动量
动量算法主要是用在加速训练,忒儿是处理高曲率,小但一致的梯度,或者是有噪音的梯度。
动量算法积累了之前的梯度指数级衰减的移动平均,并且在这个方向上继续移动。
学习的效果图:
学习的算法是:
Neserov动量
对动量的方法进行了一次修正。在Nesterov动量中,梯度计算是在施加当前动量之后。可以解释为在标准动量方法中增加了一个矫正因子。
算法如下:
其实,在随机梯度的情况下,nesterov并没没有改进收敛。
参数初始化策略
初始化的策略会影响到深度学习模型的收敛情况。
初始化参数需要在不同单元间”破坏对称性“。如果两个在同一层的神经元的参数相同,那么学习算法将会使参数以相同的方向更新。
我们几乎总是初始化模型的权重为高斯或者均匀分布的值,二者的选择似乎不会有很大的区别。
更大的初始化权值具有更强的破坏对称性的作用,有助于避免冗余的单元。同时也有助于增强梯度传播的信号强度。但是,如果初始化权重太大,那么可能在前向传播或者反向传播中产生梯度爆炸的值。
同时,较大的权重也会容易使得激活函数饱和,导致饱和的单元的梯度完全消失。
如何继续初始化?
参考链接:https://zhuanlan.zhihu.com/p/25931903
当我们对参数进行随机初始化时候,如果初始化的参数很小,得到的激活值会很快接近于0((Tanh),同时,梯度在进行反向传播的时候会累乘每一层的权值,权值过小,会导致梯度变得很小,参数无法更新。
此外,如果初始化的参数很大,则每一层的输出都非常大,经过激活函数之后的输出集中在-1和1上,此事,激活函数是出于饱和的情况,导数接近于0.在进行反向传播的时候,会导致梯度消失。
Xavier initialization
1 | w = Variable(np.random.randn(node_in, node_out)) / np.sqrt(node_in) |
这种方法对于tanh激活函数有效,但是对于ReLU激活函数,还是会出现输出值趋近于0的情况。
He initialization
He initialization的思想是:在ReLU网络中,假定每一层有一半的神经元被激活,另一半为0,所以,要保持variance不变,只需要在Xavier的基础上再除以2:
1 | w = Variable(np.random.randn(node_in, node_out) / np.sqrt(node_in / 2)) |
推荐在ReLu网络中使用
BatchNormalization
对输出进行重新的normlization。
自适应是学习算法
自适应的学习算法是通过累积二阶动量的信息(梯度的平方和),然后将学习率处于二阶动量的根号。通过这种方法,可以让具有损失最大偏导的参数的学习率下降快,而具有小偏导的参数的学习率具有相对较小的下降
Adagrad
1 | # Assume the gradient dx and parameter vector x |
RMSProp
在Adagrad的基础上,对二阶动量进行了指数加权衰减。使得在找到凸碗状结构后能够快速收敛1
2cache = decay_rate * cache + (1 - decay_rate) * dx**2
x += - learning_rate * dx / (np.sqrt(cache) + eps)
Adam
增加了一阶的动量
1 | # t is your iteration counter going from 1 to infinity |
二阶近似方法
牛顿法
牛顿法是基于二阶的泰勒级数展开得到的。其忽略了高阶的导数。
然后以就可以得到牛顿参数的更新规则:
对于非二次的表面,只要Hessian矩阵保持正定,牛顿法就能够进行迭代使用。这意味着一个两步迭代的过程。
在深度学习中,目标函数表面通常具有非凸的特点,如鞍点,这个时候如果Hessian矩阵的特征值不全是正的,牛顿法实际上会朝着错误的方向进行更新。这种情况可以通过正则化Hessian避免。
常用的正则化方法是在Hessian矩阵的对角线上增加常数$\alpha$
这个时候,更新的公式就变成了:
优化技巧和元算法
batch normalization
他不是一个优化算法,而是一个自适应的重新参数化的方法,试图解决训练非常深的模型的困难。
在实践中,我们同时更新参数的所有层。某一层的参数的更新的假设是其他层的参数没有变化,而实际上,其他层的参数也是在发生变化的。这个就是Internal Covariate Shift”
BatchNormalization提出一种几乎可以重新参数化所有深度网络的优雅方法,通过重新参数化显著减少了多层之间的协调更新问题。
为何可以解决梯度消失问题:
在BN中,是通过将activation规范为均值和方差一致的手段使得原本会减小的activation的scale变大。
坐标下降
在某些情况下,可以将一个优化的问题分解成几个部分,可以更快的解决这个问题。如果我们对于某个单一变量$x_i$最小化f(x),然后相对于另外一个变量$x_j$更新,反复循环所有变量,可以保证到达极小值。这种方法是坐标下降方法。
监督预训练
在直接训练目标模型求解目标问题之前,训练简单的模型求解简化问题的方法统称为预训练。
贪心算法是将问题分解为许多部分,独立的在每个部分求解最优值。贪心算法虽然不能保证得到最优值,但是比求解最优联合解的算法高效的多。
贪心算法后面可以紧接着一个精调(find-tuning)阶段,搜索最优解。
贪心监督预训练方法
每个阶段包括一个仅涉及最终神经网络的子集层的监督学习训练的任务。这种方法可以更好地指导深层次网络的中间层学习。