看到有很多人挺推崇:An overview of gradient descent optimization algorithms;特此放到最上面,你们有机会能够阅读一下;html
本文内容主要来源于Coursera吴恩达《优化深度神经网络》课程,另一些不一样优化算法之间的比较也会出如今其中,具体来源再也不单独说明,会在文末给出所有的参考文献;python
本主要主要介绍的优化算法有:算法
其实就是对梯度降低的优化算法,每一种优化算法会介绍其:基本原理、TensorFlow中的使用、不一样优化算法的优缺点总结;在最后会介绍调整学习率衰减的方式以及局部最优问题;segmentfault
[TOC]网络
若是样本数量不是过于庞大,通常使用batch的方式进行计算,即将整个样本集投入到深度神经网络进行梯度降低;而通常实际应用中,样本集的数量将会很大,如达到百万数量级,这种状况下若是继续使用batch的方式,训练的速度每每会很慢;app
所以,假如每次只对整个样本集中的部分样本执行梯度降低,这就有了Mini-batch gradient descent。机器学习
整个样本集$X=[x^1, x^2, \cdots, x^m] \in R^{n \times m}$;$Y=[y^1, y^2, \cdots, y^m] \in R^{1 \times m}$;函数
假设:oop
$m=5000000$;每个mini-batch含有1000个样本,即$X^{{t}} \in R^{n \times 1000},Y^{{t}} \in R^{1 \times 1000}, t=1, 2, \cdots, 5000$;学习
$x^i$表示第$i$个样本;$Z^{[l]}$表示网络第$l$层网络的线性输出;$X^{{t}}, Y^{{t}}$表示第$t$组mini-batch;
即在每个mini-batch上执行梯度降低,伪代码以下:
# 一个epoch for t = 1, ..., T{ Forward Propagation Compute Cost Function Backward Propagation }
其中,每一步详解:
(1)Forward Propagation
第一层网络非线性输出: $$ Z^{[1]} = W^{[1]}X^{{t}} + b^{[1]} $$
$$ A^{[1]} = g^{(1)}(Z^{[1]}) $$
第$l$层网络非线性输出: $$ A^{[l]} = g^{[l]}(Z^{[l]}) $$ (2)Compute Cost Function
计算代价函数: $$ J = \dfrac{1}{1000} \sum_{i=1}^{l}Loss(\hat{y}^i, y^i) + \dfrac{\lambda}{2 \times 1000} \sum_{l}||W^l||_F^2 $$ (3)Backward Propagation
更新权重和偏置: $$ W^{[l]} : = W^{[l]} - \alpha dW^{[l]} $$
$$ b^{[l]} : = b^{[l]} - \alpha db^{[l]} $$
通过T次for循环后,表示已经在整个样本集上训练了一次,即一个epoch;能够执行多个epoch;
对与Batch Gradient Descent来讲,一个epoch只进行了一次梯度降低;而对于Mini-batch Gradient Decent来讲,一个epoch进行T次梯度降低;
(1)左图表示通常神经网络中,使用Batch Gradient Descent,随着在整个样本集上迭代次数的增长,cost在不断的减少;
(2)右图表示使用Mini-batch Gradient Descent,随着在不一样的mini-batch上进行训练,cost总体趋势处于降低,但因为受到噪声的影响,会出现震荡;
(3)Mini-batch Gradient Descent中cost出现震荡的缘由时:不一样的mini-batch之间是存在差别的,可能其中某些mini-batch是好的子集,而某些子集中存在噪声,所以cost会出现震荡的状况;
总共有三种选择方式:(1)batch_size=m;(2)batch_size=1;(3)batch_size介于1和m之间;
(1)Batch Gradient Descent(batch_size = m)
当batch_size=m,就成了Batch Gradient Descent,只有包含一个子集,就是整个数据集;即$(X^{{1}}, Y^{{1}})=(X,Y)$;
(2)Stochastic Gradient Descent(batch_size=1)
当batch_size=m,就成了Stochastic Gradient Descent,共包含m个子集,每一个样本做为一个子集,即$(X^{{1}}, Y^{{1}})=(x^i,y^i)$;
(3)Mini-batch gradient descent(batch_size介于1和m之间)
上图表示三者之间梯度降低曲线:
a. 蓝色表示Batch Gradient Descent,会比较平稳的接近全局最小值;因为使用了所有数据集,每次前进的速度会比较慢;
b. 紫色表示Stochastic Gradient Descent,每次前进速度很快;但因为每次只使用了一个样本,会出现较大的震荡;并且,不会收敛到最小值,最终会在最小值附近来回波动
c. 绿色表示Mini-batch gradient descent,每次前进速度较快,且震荡较小,基本可以接近最小值;若是出如今最小值附近波动,能够减少学习率;
算法 | Stochastic Gradient Descent | Mini-batch gradient descent | Batch Gradient Descent |
---|---|---|---|
优势 | 适用于单个样本; | (1)可以快速学习;(2)向量化加速;(3)未在整个训练集上训练完,就能够执行后续工做; | |
缺点 | (1)丢失了向量化带来的加速;(2)效率低; | 单次迭代时间太长; |
如何为Mini-batch gradient descent选择batch size?
optimizer = tf.train.GradientDescentOptimizer(leraning_rate) train = optimizer.minimize(loss)
tf.train.GradientDescentOptimizer.__init__(self, learning_rate, use_locking=False, name="GradientDescent"): Args: learning_rate: A Tensor or a floating point value. The learning rate to use. # 学习率 use_locking: If True use locks for update operations. # name: Optional name prefix for the operations created when applying gradients. Defaults to "GradientDescent".
#coding=utf-8 import tensorflow as tf # Model parameters W = tf.Variable([.3], dtype=tf.float32) b = tf.Variable([-.3], dtype=tf.float32) # Model input and output x = tf.placeholder(tf.float32) y_pred = W * x + b y = tf.placeholder(tf.float32) # loss loss = tf.reduce_sum(tf.square(y_pred - y)) # sum of the squares # optimizer optimizer = tf.train.GradientDescentOptimizer(0.01) train = optimizer.minimize(loss) # training data x_train = [1, 2, 3, 4] y_train = [0, -1, -2, -3] # training loop init = tf.global_variables_initializer() sess = tf.Session() sess.run(init) # reset values to wrong for i in range(1000): sess.run(train, {x: x_train, y: y_train}) # evaluate training accuracy curr_W, curr_b, curr_loss = sess.run([W, b, loss], {x: x_train, y: y_train}) print("W: %s b: %s loss: %s" % (curr_W, curr_b, curr_loss))
指数加权平均(Exponentially weighted averages)是除梯度降低算法以外其余优化算法中重要的概念,所以,这里先介绍其概念。
这里再也不介绍如何引入指数加权平均的,具体参考:网易云课堂-吴恩达《优化深度神经网络》-第二周或红色石头Will-吴恩达《优化深度神经网络》课程笔记;
假设:$V_0 = 0$; $$ V_t = \beta V_{t-1} + (1 - \beta) \theta_t $$ 其中,$\theta_t$表示第$t$天的温度;$V_t$表示经过移动平均的方法对天天气温进行平滑处理后结果; $\beta$值决定了指数加权平均的天数,即$\dfrac{1}{1-\beta}$;$\beta$表示加权平均的天数越多,平均后的趋势越平缓,同时也会向右移动;
即,当$\beta=0.9$,则$\dfrac{1}{1-\beta}=10$,表示将前10天进行指数加权平均;
$$ V_t = \beta V_{t-1} + (1-\beta)\theta_{t} $$
$$ V_t = (1-\beta) \cdot \theta_{t} + (1-\beta) \cdot \beta \cdot \theta_{t-1} + (1-\beta) \cdot \beta^2 \cdot \theta_{t-2} + \cdots + (1-\beta)\cdot \beta^{t-1}\cdot \theta_1 + \beta^t\cdot V_0 $$
其中,$\theta_t, \theta_{t-1}, \cdots , \theta_1$表示原始数据集,即下图中的第一张图;
$(1-\beta), (1-\beta)\cdot \beta, \cdots, (1-\beta)\cdot \beta^{t-1}$相似指数曲线,以下图中第二张图;从右向左,呈指数降低;
$V_t$表示二者点乘,将原始数据值与衰减指数点乘,至关于作了指数衰减,离的越近,影响就越大;离的越远,影响就越小,衰减就越严重;
实际应用中,为了减小内存的使用,可使用以下语句实现指数加权平均:
$V_0=0$
Repeat{ $$ Get \quad next \quad \theta_t $$
$$ V_{\theta} := \beta V_{\theta} + (1-\beta)\theta_t $$
}
由于初始假设$V_0=0$,能够想到,在使用$V_t = \beta V_{t-1} + (1-\beta)\theta_t$计算的时候,前面的一些值将会受到很大的影响,会比正常值小一些,直到计算后面数据的时候,影响才会渐渐变小,趋于正常。
所以,修正这种问题的方式是偏移修正(bias correction),即对$V_t$做以下处理: $$ \dfrac{V_t}{1-\beta^t} $$ 在机器学习中,偏移修正不是必须的;
**动量梯度降低算法(Gradient descent with momentum)**的速度要快于标准的梯度降低算法;
具体作法是:在每次训练时,对梯度计算指数加权平均,而后使用获得的梯度值更新权重和偏置;
如上图蓝色折线所示,表示标准梯度降低算法;在梯度降低的过程当中,会出现震荡的状况,这是由于每一点的梯度只与当前梯度方向有关,所以会出现折线的效果;
如上图红色折线所示,表示使用momentum梯度降低算法;能够看到,在梯度降低的过程当中,不会出现剧烈的震荡,这是由于,每个点的梯度不只与当前梯度方向有关,还与以前的梯度方向有关;可以作到纵轴摆动变小,横轴方向运动更快;
On iteration t{
Compute dW, db on the current mini-batch
$V_{dW} = \beta V_{dW} + (1-\beta)dW$
$V_{db} = \beta V_{db} + (1-\beta)db$
更新权重和偏置
$W := W - \alpha V_{dW}, b := b - \alpha V_{db}$
}
其中,初始化时,$V_{dW}=0, V_{db}=0, \beta=0.9$;
# optimizer optimizer = tf.train.MomentumOptimizer(0.01, momentum) # \beta train = optimizer.minimize(loss)
tf.train.MomentumOptimizer.__init__(self, learning_rate, momentum, use_locking=False, name="Momentum", use_nesterov=False): Args: learning_rat: A `Tensor` or a floating point value. The learning rate. # 学习率 momentum: A `Tensor` or a floating point value. The momentum. # 就是指数加权平均中的超参数\alpha=0.9 use_locking: If `True` use locks for update operations. name: Optional name prefix for the operations created when applying gradients. Defaults to "Momentum". use_nesterov: If `True` use Nesterov Momentum. # 另外一种优化算法,由momentum改进而来,效果更好;来源于:http://jmlr.org/proceedings/papers/v28/sutskever13.pdf Return: optimizer
RMSprop(Root mean squared prop)是另一种优化梯度降低的算法,相似于Momentum Gradient descent,一样能够在纵轴上减少摆动,在横轴方向上运动更快;
On iteration t{
Compute dW, db on the current mini-batch
$S_{dW} = \beta S_{dW} + (1-\beta)(dW)^2$
$S_{db} = \beta S_{db} + (1-\beta)(db)^2$
更新权重和偏置
$W := W - \alpha \dfrac{dW}{\sqrt{S_W}+\epsilon}, b := b - \alpha \dfrac{db}{\sqrt{S_W}+\epsilon}$
}
其中,通常取$\epsilon=10^{-8}$,防止分母趋近于0;
# optimizer optimizer = tf.train.RMSPropOptimizer(0.01, decay, momentum) # decay不清楚具体什么做用??求解: train = optimizer.minimize(loss)
tf.train.RMSPropOptimizer.__init__(self, learning_rate, decay=0.9, momentum=0.0, epsilon=1e-10, use_locking=False, centered=False, name="RMSProp") Args: learning_rate: A Tensor or a floating point value. The learning rate. # 学习率 decay: Discounting factor for the history/coming gradient # ?? momentum: A scalar tensor. # \alpha epsilon: Small value to avoid zero denominator. # \epsilon 防止分母趋近于0 use_locking: If True use locks for update operation. centered: If True, gradients are normalized by the estimated variance of the gradient; if False, by the uncentered second moment. Setting this to True may help with training, but is slightly more expensive in terms of computation and memory. Defaults to False. name: Optional name prefix for the operations created when applying gradients. Defaults to "RMSProp".
Adam优化算法是结合了Gradient descent with momentum与RMSprop两种算法;被证实可以适用于不一样的神经网络;
初始化:$V_{dW}=0, S_{dW}=0, V_{db}=0, S_{db}=0$;
On iteration t {
Compute $dW, db$ on each mini-batch
$V_{dW} = \beta_1 V_{dW} + (1-\beta_1)dW$
$V_{db} = \beta_1 V_{db} + (1-\beta_1)db$
$S_{dW} = \beta_2 S_{dW} + (1-\beta_2)(dW)^2$
$S_{db} = \beta_2 S_{db} + (1-\beta_2)(db)^2$
$V_{dW}^{corrected}= \dfrac{V_{dW}}{1-\beta_1^t}, V_{db}^{corrected}= \dfrac{V_{db}}{1-\beta_1^t}$
$S_{dW}^{corrected}= \dfrac{S_{dW}}{1-\beta_2^t}, S_{db}^{corrected}= \dfrac{S_{db}}{1-\beta_2^t}$
$W := W - \alpha \dfrac{V_{dW}^{corrected}}{\sqrt{S_{dW}^{corrected}}+\epsilon} b := b - \alpha \dfrac{V_{db}^{corrected}}{\sqrt{S_{db}^{corrected}}+\epsilon}$
}
Adam算法中须要作误差修正;
超参数设置:$\beta_1 = 0.9, \beta_2=0.999, \epsilon = 10^{-8}$;通常只须要对学习率$\alpha$进行调试;
optimizer = tf.train.AdamOptimizer(learning_rate, beta1, beta2, epsilon) train = optimizer.minimize(loss)
tf.train.AdamOptimizer._init__(self, learning_rate=0.001, beta1=0.9, beta2=0.999, epsilon=1e-8, use_locking=False, name="Adam"): Args: learning_rate: A Tensor or a floating point value. The learning rate. # 学习率 beta1: A float value or a constant float tensor. The exponential decay rate for the 1st moment estimates. # \beta_1 beta2: A float value or a constant float tensor. The exponential decay rate for the 2nd moment estimates. # \beta_2 epsilon: A small constant for numerical stability. This epsilon is "epsilon hat" in the Kingma and Ba paper (in the formula just before Section 2.1), not the epsilon in Algorithm 1 of the paper. use_locking: If True use locks for update operations. name: Optional name for the operations created when applying gradients. Defaults to "Adam".
**思想:**基于整个训练集进行梯度降低,更新权重;
优势:
缺点:
**思想:**从训练集中随机选取一个样本计算梯度更新参数;
优势:
缺点:
**思想:**从整个样本集中选择batch_size个样本计算损失的梯度,更新权重;
优势:
缺点:
**思想:**基于以前梯度的方向以及当前batch的梯度方向进行更新;
优势:
**思想:**相似于动量梯度降低,引入了指数权重加权平均值;
**思想:**综合了Gradient Descent with Momentum与RMSprop两种优化算法;
优势:
缺点:
在神经网络训练的过程当中,适当减少学习率有利于提升训练速度,该类方法称为learning rate decay,即随着迭代次数的增长,学习率$\alpha$逐渐减少;
(1)第一种: $$ \alpha = \dfrac{1}{1+ decay_rate \times epoch_num}\cdot \alpha_0 $$ 其中,$decay_rate$衰减参数;$epoch_num$表示迭代次数;
(2)第二种: $$ \alpha = 0.95^{epoch_num} \cdot \alpha_0 $$ (3)第三种: $$ alpha = \dfrac{k}{\sqrt{epoch_num}}\cdot \alpha_0 \quad 或 \quad \dfrac{k}{\sqrt{t}}\cdot \alpha_0 $$ (4)第四种:
将$\alpha$设置为关于$t$的离散值,随着$t$的增长,$\alpha$呈阶梯式减小;
(5)第五种:
经过查看训练日志,手动调整学习率;
因为TensorFlow中提供的学习率设置方式有很多种,而本文主要是叙述梯度降低的优化算法,在此处介绍将会占用不小的篇幅,显得有些臃肿,所以,另总结一篇博文供本身学习;
在使用梯度降低算法减小cost function的时候,可能会获得局部最优解,而不是全局最优解;
咱们认为的局部最优可能以下图左边所示;但在神经网络中,局部最优的概念发生了变化;大部分梯度为零的“最优势“不是这些凹槽处,而是以下图右边的马鞍处,称为saddle point。
相似马鞍状的plateaus会下降神经网络的学习速度。plateaus是梯度接近于零的平缓区域,以下图所示,在plateaus上梯度很小,前进缓慢,达到saddle point须要很长时间;到达saddle point后,因为随机扰动,梯度可以进去降低;可是会在plateaus上花费不少时间;
动量梯度降低、RMSprop、Adam算法可以解决plateaus降低过慢的问题,提升训练速度;
结束!!!
博主我的网站:https://chenzhen.online