Optimizer(BGD,SGD,MBGD,Momentum,NAG,Adagrad,Adadelta,RMSprop,Adam)详解

一、optimizer 算法介绍

1、Batch Gradient Descent(BGD)

BGD采用整个训练集的数据来计算 cost function 来进行参数更新。
θ = θ − α ⋅ ∇ θ J ( θ ) \theta = \theta - \alpha \cdot \nabla_{\theta}J(\theta) θ=θαθJ(θ)

for i in range(iteration):    
	"""
	这是从我写的DNN模型中抽取的部分代码,只需关注 L_model_forward() 和
	L_model_backward() 中的参数 X_all_data, y_all_data
	"""
	A, caches = self.L_model_forward(X_all_data, parameters, activation_list)
	grads = self.L_model_backward(y_all_data, parameters, caches, activation_list)
	parameters = self.update_parameters(parameters, grads, learning_rate)

缺点:
该优化方法在一次梯度更新过程中,需要对整个数据集求梯度,所以当数据集很大时,计算量会非常大,梯度更新的速度也会变很慢。


2、Stochastic Gradient Descent(SGD)

(SGD)随机梯度下降法,每次更新时只用到了一份样本,梯度更新的速度明显加快,并且可以随时扩增样本。
θ = θ − α ⋅ ∇ θ J ( θ ; ( x i , y i ) ) \theta = \theta - \alpha \cdot \nabla_{\theta}J(\theta;(x_i,y_i)) θ=θαθJ(θ;(xi,yi))

for i in range(iteration):    
	permutation = np.random.permutation(X_all_data.shape[1])
	
	for j in permutation:         # 分别用每个样本点进行更新
		A, caches = self.L_model_forward(X_all_data[:, j], parameters, activation_list)
		grads = self.L_model_backward(y_all_data[:, j], parameters, caches, activation_list)
		parameters = self.update_parameters(parameters, grads, learning_rate)

在这里插入图片描述
对于随机梯度下降法,可能只需要迭代很少的几次数据,就可以使模型收敛。并且当函数非凸时,BGD收敛到局部极小值点后就无法更新了,但是SGD因为取的样本点是随机的,所以可能会跳到更好的局部极小值点继续更新。
缺点:

  1. SGD 因为更新比较频繁,会造成 cost function 有严重的震荡。
  2. 通过上述代码可以看到,SGD的更新建立了两个嵌套循环,没有使用numpy中优化的矩阵运算,所以整体速度会比较慢。

3、Mini-Batch Gradient Descent(MBGD)

MBGD是BGD和SGD的中和版本,每次使用一小部分样本进行更新,这样可以减小参数更新过程中的震荡,使收敛更加稳定,另一方面遍历一次全数据集就可以进行多次更新,减少收敛的迭代次数,还能使用Numpy中的矩阵优化加快运算速度。
θ = θ − α ⋅ ∇ θ J ( θ ; ( x b a t c h _ i , y b a t c h _ i ) ) \theta = \theta - \alpha \cdot \nabla_{\theta}J(\theta;(x_{batch\_i},y_{batch\_i})) θ=θαθJ(θ;(xbatch_i,ybatch_i))

for i in range(iteration):    
	for (X_batch, y_batch) in get_batches(X_all_data, y_all_data, batch_size):
		A, caches = self.L_model_forward(X_batch, parameters, activation_list)
		grads = self.L_model_backward(y_batch, parameters, caches, activation_list)
		parameters = self.update_parameters(parameters, grads, learning_rate)

4、Momentum

在更新参数的过程中,如果曲面不同方向的梯度值不同,一般的梯度下降法总是无法找到最佳的更新路径,这时可以使用 momentum 来进行改进,就是在梯度下降过程中给其添加一个惯性,让其有保持原先更新方向的趋势。
在这里插入图片描述
算法流程
在当前的 mini-batch 中,计算 dw, db:
v d w = β v d w ( 此 处 为 上 一 个 v d w ) + ( 1 − β ) d w v d b = β v d b ( 此 处 为 上 一 个 v d b ) + ( 1 − β ) d b w = w − α v d w b = b − α v d b v_{dw}=\beta v_{dw}(此处为上一个v_{dw}) + (1-\beta)dw\\ v_{db}=\beta v_{db}(此处为上一个v_{db}) + (1-\beta)db\\ w = w-\alpha v_{dw}\\ b = b-\alpha v_{db} vdw=βvdw(vdw)+(1β)dwvdb=βvdb(vdb)+(1β)dbw=wαvdwb=bαvdb
偏差修正
由于在计算前几个平均值的时候, v 0 = 0 v_0=0 v0=0的影响比较大,可能会使得求得的前几个均值 v 1 , v 2 , . . . v_1,v_2,... v1,v2,...的值偏小,所以需要对偏差进行修正。修正的方法如下:
v t = v t 1 − β t v_t=\frac {v_t}{1-\beta^t} vt=1βtvt
随着 t 值的增大, 1 − β t 1-\beta^t 1βt 的值趋向于1,所以偏差修正的影响越来越小。在上述算法中,有两个超参数 α , β \alpha,\beta α,β β \beta β的值通常取0.9。在动量梯度下降法中,一般不考虑偏差修正。
动量梯度下降算法的解释
在碗形的 cost function 中,指向最低点的路径更新才是有效的,而垂直该方向的路径更新是无效的,在动量梯度下降法中,由于求平均值的作用,无效的路径更新由于符号相反,会相互抵消,留下的是近似的有效的更新路径。


5、Nesterov Accelerated Gradient(NAG)

梯度更新规则
NAG是对Momentum的改进,可以理解为先对参数进行估计,然后使用估计后的参数来计算误差。即用 θ − γ v t − 1 \theta-\gamma v_{t-1} θγvt1来近似当做参数下一步会变成的值,则在计算梯度时,不是在当前位置,而是在未来的位置上。用一张图来形象的对比下momentum和nesterov momentum的区别(图片来自:一篇写的很好的博客):
在这里插入图片描述
参数更新步骤如下:
v t + 1 = β v t − α ∇ θ J ( θ t + β v t ; ( x b a t c h _ i , y b a t c h _ i ) ) θ t + 1 = θ t + v t + 1 \begin{aligned} &v_{t+1} = \beta v_t - \alpha\nabla_{\theta}J(\theta_t+\beta v_t;(x_{batch\_i},y_{batch\_i}))\\ &\theta_{t+1} =\theta_t + v_{t+1} \end{aligned} vt+1=βvtαθJ(θt+βvt;(xbatch_i,ybatch_i))θt+1=θt+vt+1
缺点:
通过观察上述方法,我们会发现这个算法中有一步需要计算 ∇ θ J ( θ t + β v t ; ( x b a t c h _ i , y b a t c h _ i ) ) \nabla_{\theta}J(\theta_t+\beta v_t;(x_{batch\_i},y_{batch\_i})) θJ(θt+βvt;(xbatch_i,ybatch_i)),这就意味着需要重新走一次前向传播和反向传播,这会导致整个计算步骤比Momentum慢至少一倍。因此在实际中一般不会直接这么用,而是采用如下变形版本。
θ = θ + β 2 v − ( 1 + β ) α ∗ g r a d \theta = \theta + \beta^2v-(1+\beta)\alpha*grad θ=θ+β2v(1+β)αgrad
上述公式可以写成Keras风格:
V d W = β V d W − α d W V d b = β V d b − α d b W = W + β V d W − α d W b = b + β V d b − α d b \begin{aligned} &V_{dW} &=& \beta V_{dW} - \alpha dW\\ &V_{db} &=& \beta V_{db} - \alpha db\\ &W &= & W + \beta V_{dW}-\alpha dW\\ &b &=& b + \beta V_{db} - \alpha db \end{aligned} VdWVdbWb====βVdWαdWβVdbαdbW+βVdWαdWb+βVdbαdb


6、Adagrad(Adaptive gradient algorithom)

通常,我们在每一次更新参数时,对于所有的参数使用的都是相同的学习率 α \alpha α。而AdaGrad算法的思想是:每一次更新参数时,对不同的参数使用不同的学习率。简而言之,Adagrad有如下特点:

  1. 每一次迭代,学习率不同
  2. 对于每一个参数,学习率不同

G t = G t − 1 + g r a d t 2 θ t + 1 = θ t − α G t + ϵ ⋅ g r a d t 一 般 α 取 0.01 G_t = G_{t-1}+grad_t^2\\ \theta_{t+1} = \theta_t - \frac {\alpha}{\sqrt {G_t}+\epsilon}\cdot grad_t\\ 一般\alpha 取0.01 Gt=Gt1+gradt2θt+1=θtGt +ϵαgradtα0.01
优点:
对于梯度较大的参数, G t G_t Gt相对较大,则学习率 α G t + ϵ \frac {\alpha}{\sqrt {G_t}+\epsilon} Gt +ϵα较小;对于梯度较小的参数,则刚好相反。这样就可以使得参数在平缓的地方下降的稍微快些,不至于徘徊不前。
缺点:
由于在计算 G t G_t Gt时是累加梯度的平方,这会导致最后 G t G_t Gt较大,从而导致 α G t + ϵ → 0 \frac {\alpha}{\sqrt {G_t}+\epsilon} \to 0 Gt +ϵα0,梯度消失。


7、Adadelta

Adadelta是对Adagrad的改进版本,为了克服Adagrad的两个缺点:

  1. 学习率的持续下降,最终导致梯度消失
  2. 需要手动设置学习率 α \alpha α

为了解决第一个问题,Adadelta采用指数加权平均的方式,只累加前 w 个窗口的梯度的平方:
E [ g 2 ] t = β E [ g 2 ] t − 1 + ( 1 − β ) g t 2 E[g^2]_t = \beta E[g^2]_{t-1}+(1-\beta)g_t^2 E[g2]t=βE[g2]t1+(1β)gt2
β \beta β取0.9,就相当于累加了前10个梯度的平方。
为了解决第二个问题,Adadelta中不再需要设置 α \alpha α。参数更新的具体算法如下:
在这里插入图片描述
其中 ϵ \epsilon ϵ的作用是防止分母为0,通常取 1 0 − 6 10^{-6} 106


8、RMSprop

RMSprop 是 Geoff Hinton 提出的一种自适应学习率方法。和Adadelta一样,RMSprop使用指数加权平均(指数衰减平均)只保留过去给定窗口大小的梯度,使其能够在找到凸碗状结构后快速收敛。
S d w = β 2 S d w + ( 1 − β 2 ) ( d w ) 2 S d b = β 2 S d b + ( 1 − β 2 ) ( d b ) 2 w = w − α d w S d w + ε b = b − α d b S d b + ε 其 中 ε 是 很 小 的 一 个 数 , 为 了 防 止 分 母 为 0 S_{dw}=\beta_2 S_{dw}+(1-\beta_2)(dw)^2\\ S_{db}=\beta_2 S_{db}+(1-\beta_2)(db)^2\\ w=w-\alpha \frac {dw}{\sqrt {S_{dw}} + \varepsilon}\\ b=b-\alpha \frac {db}{\sqrt {S_{db}} + \varepsilon}\\ 其中\varepsilon是很小的一个数,为了防止分母为0 Sdw=β2Sdw+(1β2)(dw)2Sdb=β2Sdb+(1β2)(db)2w=wαSdw +εdwb=bαSdb +εdbε
在实际使用过程中,RMSprop已被证明是一种有效且实用的深度神经网络优化算法。目前它是深度学习人员经常采用的优化算法之一。keras文档中关于RMSprop写到:This optimizer is usually a good choice for recurrent neural networks.


9、Adam(Adaptive Moment Estimation)

Adam实际上是把momentum和RMSprop结合起来的一种算法,是最常用的一种算法,被广泛用于各种结构的神经网络。算法流程如下:
在这里插入图片描述

二、算法选择

实践表明,RMSprop,Adadelta和Adam表现的相当鲁棒,而且Adam算法是目前使用最多的,而且公认效果最好的。

[1]Ruder S . An overview of gradient descent optimization algorithms[J]. 2016.

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在多分类任务实验中,可以使用以下代码实现momentumrmsprop和adam优化器: 1. Momentum优化器: ```python import torch import torch.nn as nn import torch.optim as optim # 定义模型 model = YourModel() # 定义损失函数和优化器 criterion = nn.CrossEntropyLoss() optimizer = optim.SGD(model.parameters(), lr=0.1, momentum=0.9) # 在训练过程中使用优化器 for inputs, labels in dataloader: # 正向传播 outputs = model(inputs) loss = criterion(outputs, labels) # 反向传播和优化 optimizer.zero_grad() loss.backward() optimizer.step() ``` 2. RMSprop优化器: ```python import torch import torch.nn as nn import torch.optim as optim # 定义模型 model = YourModel() # 定义损失函数和优化器 criterion = nn.CrossEntropyLoss() optimizer = optim.RMSprop(model.parameters(), lr=0.001, alpha=0.99) # 在训练过程中使用优化器 for inputs, labels in dataloader: # 正向传播 outputs = model(inputs) loss = criterion(outputs, labels) # 反向传播和优化 optimizer.zero_grad() loss.backward() optimizer.step() ``` 3. Adam优化器: ```python import torch import torch.nn as nn import torch.optim as optim # 定义模型 model = YourModel() # 定义损失函数和优化器 criterion = nn.CrossEntropyLoss() optimizer = optim.Adam(model.parameters(), lr=0.001) # 在训练过程中使用优化器 for inputs, labels in dataloader: # 正向传播 outputs = model(inputs) loss = criterion(outputs, labels) # 反向传播和优化 optimizer.zero_grad() loss.backward() optimizer.step() ``` 以上代码展示了如何使用PyTorch库中的SGDRMSprop和Adam优化器来进行多分类任务的训练。请确保将`YourModel`替换为您实际使用的模型,并根据实际情况调整学习率(lr)和其他超参数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值