基于Pytorch的不同优化算法(Adagrad、RMSProp、AdaDelta、Adam四种)在 MNIST 数据集上的性能比较与可视化

442 阅读2分钟

本文主要介绍了Adagrad、RMSProp、AdaDelta、Adam四种经典的深度学习的优化算法。在基于 PyTorch 的 MNIST数字图像数据集分类模型训练与评估的简单练习-CSDN博客一文中展示了深度学习的简单框架,在其基础上通过修改优化器便能得到不同优化方法的结果。下面将只展示修改的优化器部分。

一、Adagrad方法

该方法通过初始化一个变量ss为0,然后每次将该参数的梯度平方求和累加到这个变量ss上,然后更新参数设置学习率为

QQ_1722422437740.png

其中ϵ\epsilon是为了防止ss为0时,导致学习率为无穷大而设置的一个很小的正数,通常设置为101010^{-10}

该方法核心是在梯度一直特别大时,学习率就会特别小,从而防止震荡。当梯度一直特别小时,学习率就会变大,从而快速更新参数。

但是该方法存在一些问题,比如,ss是损失值平方的累加,会越来越大,导致后期学习率会很小,导致还没收敛,学习率就特别低,使得进程十分缓慢。 优化器设置如下:

optimizer = torch.optim.Adagrad(net.parameters(), lr=0.01)

如果我们想自己实现优化函数,代码如下所示:

def sgd_adagrad(parameters, sqrs, learn_rate):
    eps = 1e-10
    for param, sqr in zip(parameters, sqrs):
        sqr[:] = sqr + param.grad.data ** 2
        change = learn_rate / torch.sqrt(sqr + eps) * param.grad.data
        param.data = param.data - change

其中sqrs需要初始化为与参数大小相同的张量。

二、RMSProp方法

该方法仍然使用到了损失值平方累加,但在处理上与Adagrad方法不同。 该方法在损失值平方累加上还添加了一个指数加权移动平均来计算ss,如下所示:

si=αsi1+(1α)g2s_i=\alpha s_{i-1}+(1-\alpha) g^2

其中α\alpha就是添加的权重,而gg是当前参数的梯度值。最终学习率就与上面的Adagrad方法一样了。

ηs+ϵ\frac{\eta}{\sqrt{s+\epsilon}}

拥有α\alpha这个参数后,在每次更新参数时,对于梯度较大的方向,其学习率会相对较小,从而避免了学习过程中的大幅震荡;对于梯度较小的方向,学习率相对较大,能够更快地收敛到最优值。同时这个系数也使得到了训练后期ss不会打太,使得其依然能找到比较优秀的结果。

优化器设置如下:

optimizer = torch.optim.RMSprop(net.parameters(), 0.001, 0.9)

若自己实现优化器,代码如下:

def rmsprop(parameters, sqrs, lr, alpha):
    eps = 1e-10
    for param, sqr in zip(parameters, sqrs):
        sqr[:] = alpha * sqr + (1 - alpha) * param.grad.data ** 2
        div = lr / torch.sqrt(sqr + eps) * param.grad.data
        param.data = param.data - div

其中sqrs需要初始化为与参数大小相同的张量,alpha通常设置为0.9。

三、AdaDelta方法

该方法算是Adagrad方法的延伸,与RMSProp方法一样,都是为了解决在Adagrad方法中学习率不断减小的问题。

该方法同RMSProp一样,先使用移动平均来计算

si=αsi1+(1α)g2s_i=\alpha s_{i-1}+(1-\alpha) g^2

此处的α\alphagg同RMSProp方法的一样,分别是移动平均系数与当前参数梯度。然后计算参数更新的变化量,如下:

g=Δθ+ϵs+ϵgg'=\frac{\sqrt{\Delta\theta+\epsilon}}{\sqrt{s+\epsilon}}g

Δθ\Delta\theta)初始值设置为0的张量,更新Δθ\Delta\theta与上述更新ss的方式相同。

Δθ=αΔθ+(1α)g2\Delta\theta=\alpha\Delta\theta+(1-\alpha)g'^2

最终参数更新如下。

θ=θg\theta=\theta-g'

优化器设置如下

optimizer = torch.optim.Adadelta(net.parameters(), rho=0.9)

若自己实现优化器,代码如下:

ef adadelta(parameters, sqrs, deltas, alpha):
    eps = 1e-6
    for param, sqr, delta in zip(parameters, sqrs, deltas):
        sqr[:] = alpha * sqr + (1 - alpha) * param.grad.data ** 2
        cur_delta = torch.sqrt(delta + eps) / torch.sqrt(sqr + eps) * param.grad.data
        delta[:] = alpha * delta + (1 - alpha) * cur_delta ** 2
        param.data = param.data - cur_delta

其中sqrs、deltas均为初始为0的张量,alpha是平均移动系数。

四、Adam方法

该方法结合了动量法与RMSProp法,首先他将vvss都设置为0的张量,然后通过迭代计算他们的更新值。

v=β1v+(1β1)gs=β2s+(1β2)g2v=\beta_{1}v+(1-\beta_{1})g\\s=\beta_{2}s+(1-\beta_{2})g^{2}

在该方法中为了减少s与v初始化为0张量对加权平均移动的影响,每次都会对vvss做以下操作。

v^=v1β1ts^=s1β2t\hat{v}=\frac{v}{1-\beta_{1}^{t}}\\\hat{s}=\frac{s}{1-\beta_{2}^{t}}

这里t是训练的次数,当β1\beta_{1}β2\beta_{2}位于0到1之间时,当训练的次数足够多时,β1t\beta_1^{t}β2t\beta_2^{t}就越趋近于0,则不会影响vvss了。算法作者建议将β1\beta_1β2\beta_2分别设置成0.9和0.999。然后将计算的到的v^\hat{v}s^\hat{s}用于计算更新参数的变化之。

g=ηv^s^+ϵg^{\prime}=\frac{\eta\hat{v}}{\sqrt{\hat{s}+\epsilon}}

最后进行参数更新。

θi=θi1g\theta_i=\theta_{i-1}-g'

该优化算法结合动量法与RMSProp各自的优点,同时具有较好的参数更新稳定性。 优化器设置如下:

optimizer = torch.optim.Adam(net.parameters(), lr=0.001)

若自己实现优化器,代码如下:

def adam(parameters, vs, sqrs, lr, t, beta1=0.9, beta2=0.999):
    eps = 1e-8
    for param, v, sqr in zip(parameters, vs, sqrs):
        v[:] = beta1 * v + (1 - beta1) * param.grad.data
        sqr[:] = beta2 * sqr + (1 - beta2) * param.grad.data ** 2
        v_hat = v / (1 - beta1 ** t)
        s_hat = sqr / (1 - beta2 ** t)
        param.data = param.data - lr * v_hat / torch.sqrt(s_hat + eps)

其中vs和sqrs为初始化为0的张量,t为训练的次数。

五、对比

使用上述四种方法训练相同的数据,通过matplotlab可视化以及控制台输出得到如下结果。

***********adagrad************  
epoch:1,Train Loss:0.41554  
epoch:2,Train Loss:0.26491  
epoch:3,Train Loss:0.22543  
epoch:4,Train Loss:0.20005  
epoch:5,Train Loss:0.18108  
所用时间为:19.04406  
***********RMSProp************  
epoch:1,Train Loss:0.37212  
epoch:2,Train Loss:0.16852  
epoch:3,Train Loss:0.12333  
epoch:4,Train Loss:0.10148  
epoch:5,Train Loss:0.08937  
所用时间为:21.77974s  
***********adadelt************  
epoch:1,Train Loss:0.36424  
epoch:2,Train Loss:0.15955  
epoch:3,Train Loss:0.12493  
epoch:4,Train Loss:0.10394  
epoch:5,Train Loss:0.08919  
所用时间为:20.12976  
*************Adam*************  
epoch:1,Train Loss:0.35856  
epoch:2,Train Loss:0.17507  
epoch:3,Train Loss:0.12567  
epoch:4,Train Loss:0.10140  
epoch:5,Train Loss:0.08493  
所用时间为:23.16603

image.png