深度学习:优化算法

1 梯度下降

为什么梯度下降算法可以优化目标函数?
考虑一类连续可微实值函数f:RR
利用泰勒展开,我们可以得到

f(x+ϵ)=f(x)+ϵf(x)+O(ϵ2).

f(xηf(x))=f(x)ηf2(x)+O(η2f2(x)).

f(xηf(x))f(x).

这意味着,如果我们使用

xxηf(x)

来迭代x,函数f(x)的值可能会下降。

因此,在梯度下降中,我们首先选择初始值x和常数η>0
然后使用它们连续迭代x,直到停止条件达成。
例如,当梯度|f(x)|的幅度足够小或迭代次数达到某个值时。

📣

  • 学习率的大小很重要:学习率太大会使模型发散,学习率太小会没有进展。

  • 梯度下降会可能陷入局部极小值,而得不到全局最小值。

  • 在高维模型中,调整学习率是很复杂的。

  • 预处理有助于调节比例。

2 随机梯度下降

随机梯度下降(SGD)可降低每次迭代时的计算代价。在随机梯度下降的每次迭代中,我们对数据样本随机均匀采样一个索引i,其中i{1,,n},并计算梯度fi(x)以更新x

xxηfi(x),

其中η是学习率。每次迭代的计算代价从梯度下降的O(n)降至常数O(1)。此外,我们要强调,随机梯度fi(x)是对完整梯度f(x)的无偏估计,因为

Eifi(x)=1ni=1nfi(x)=f(x).

这意味着,平均而言,随机梯度是对梯度的良好估计。

3 小批量随机梯度下降

基于梯度的学习方法中遇到了两个极端情况:

  • 梯度下降中使用完整数据集来计算梯度并更新参数,
  • 随机梯度下降中一次处理一个训练样本来取得进展。

二者各有利弊:每当数据非常相似时,梯度下降并不是非常“数据高效”。
而由于CPU和GPU无法充分利用向量化,随机梯度下降并不特别“计算高效”。

这暗示了两者之间可能有折中方案,这便涉及到小批量随机梯度下降(minibatch gradient descent)。

每当我们执行wwηtgt时,消耗巨大。其中

gt=wf(xt,w).

我们将梯度gt替换为一个小批量而不是单个观测值

gt=w1|Bt|iBtf(xi,w).

尽管在处理的样本数方面,随机梯度下降的收敛速度快于梯度下降,但与梯度下降相比,它需要更多的时间来达到同样的损失,因为逐个样本来计算梯度并不那么有效。 小批量随机梯度下降能够平衡收敛速度和计算效率。 大小为10的小批量比随机梯度下降更有效; 大小为100的小批量在运行时间上甚至优于梯度下降。

  • 在小批量随机梯度下降中,我们处理通过训练数据的随机排列获得的批量数据(即每个观测值只处理一次,但按随机顺序)。
  • 在训练期间降低学习率有助于训练。
  • 一般来说,小批量随机梯度下降比随机梯度下降和梯度下降的速度快,收敛风险较小。

4 动量法

gt,t1=w1|Bt|iBtf(xi,wt1)=1|Bt|iBthi,t1.

泄漏平均值(leaky average)取代梯度计算:

vt=βvt1+gt,t1

其中β(0,1)
这有效地将瞬时梯度替换为多个“过去”梯度的平均值。
v被称为动量(momentum),
它累加了过去的梯度。即

vt=β2vt2+βgt1,t2+gt,t1=,=τ=0t1βτgtτ,tτ1.

5 AdaGrad算法

算法原理:

gt=wl(yt,f(xt,w)),st=st1+gt2,wt=wt1ηst+ϵgt.

def init_adagrad_states(feature_dim):
    s_w = np.zeros((feature_dim, 1))
    s_b = np.zeros(1)
    return (s_w, s_b)

def adagrad(params, states, hyperparams):
    eps = 1e-6
    for p, s in zip(params, states):
        s[:] += np.square(p.grad)
        p[:] -= hyperparams['lr'] * p.grad / np.sqrt(s + eps)
  • AdaGrad算法会在单个坐标层面动态降低学习率。
  • AdaGrad算法利用梯度的大小作为调整进度速率的手段:用较小的学习率来补偿带有较大梯度的坐标。
  • 在深度学习问题中,由于内存和计算限制,计算准确的二阶导数通常是不可行的。梯度可以作为一个有效的代理。
  • 如果优化问题的结构相当不均匀,AdaGrad算法可以帮助缓解扭曲。
  • AdaGrad算法对于稀疏特征特别有效,在此情况下由于不常出现的问题,学习率需要更慢地降低。

6 RMSprop

算法原理:

stγst1+(1γ)gt2,xtxt1ηst+ϵgt.

常数ϵ>0通常设置为106,以确保我们不会因除以零或步长过大而受到影响。
鉴于这种扩展,我们现在可以自由控制学习率η,而不考虑基于每个坐标应用的缩放。
就泄漏平均值而言,我们可以采用与之前在动量法中适用的相同推理。
扩展st定义可获得

st=(1γ)gt2+γst1=(1γ)(gt2+γgt12+γ2gt2+,).

def rmsprop_2d(x1, x2, s1, s2):
    g1, g2, eps = 0.2 * x1, 4 * x2, 1e-6
    s1 = gamma * s1 + (1 - gamma) * g1 ** 2
    s2 = gamma * s2 + (1 - gamma) * g2 ** 2
    x1 -= eta / math.sqrt(s1 + eps) * g1
    x2 -= eta / math.sqrt(s2 + eps) * g2
    return x1, x2, s1, s2

def f_2d(x1, x2):
    return 0.1 * x1 ** 2 + 2 * x2 ** 2

eta, gamma = 0.4, 0.9
def init_rmsprop_states(feature_dim):
    s_w = np.zeros((feature_dim, 1))
    s_b = np.zeros(1)
    return (s_w, s_b)

def rmsprop(params, states, hyperparams):
    gamma, eps = hyperparams['gamma'], 1e-6
    for p, s in zip(params, states):
        s[:] = gamma * s + (1 - gamma) * np.square(p.grad)
        p[:] -= hyperparams['lr'] * p.grad / np.sqrt(s + eps)

  • RMSProp算法与Adagrad算法非常相似,因为两者都使用梯度的平方来缩放系数。
  • RMSProp算法与动量法都使用泄漏平均值。但是,RMSProp算法使用该技术来调整按系数顺序的预处理器。
  • 在实验中,学习率需要由实验者调度。
  • 系数γ决定了在调整每坐标比例时历史记录的时长。

7 Adadelta

算法原理:

st=ρst1+(1ρ)gt2.

使用重新缩放的梯度gt执行更新,即

xt=xt1gt.

那么,调整后的梯度gt是什么?我们可以按如下方式计算它:

gt=Δxt1+ϵst+ϵgt,

其中Δxt1是重新缩放梯度的平方gt的泄漏平均值。我们将Δx0初始化为0,然后在每个步骤中使用gt更新它,即

Δxt=ρΔxt1+(1ρ)gt2,

ϵ(例如105这样的小值)是为了保持数字稳定性而加入的。

%matplotlib inline
from mxnet import np, npx
from d2l import mxnet as d2l

npx.set_np()

def init_adadelta_states(feature_dim):
    s_w, s_b = np.zeros((feature_dim, 1)), np.zeros(1)
    delta_w, delta_b = np.zeros((feature_dim, 1)), np.zeros(1)
    return ((s_w, delta_w), (s_b, delta_b))

def adadelta(params, states, hyperparams):
    rho, eps = hyperparams['rho'], 1e-5
    for p, (s, delta) in zip(params, states):
        # In-placeupdatesvia[:]
        s[:] = rho * s + (1 - rho) * np.square(p.grad)
        g = (np.sqrt(delta + eps) / np.sqrt(s + eps)) * p.grad
        p[:] -= g
        delta[:] = rho * delta + (1 - rho) * g * g
data_iter, feature_dim = d2l.get_data_ch11(batch_size=10)
d2l.train_ch11(adadelta, init_adadelta_states(feature_dim),
               {'rho': 0.9}, data_iter, feature_dim);

  • Adadelta没有学习率参数。相反,它使用参数本身的变化率来调整学习率。
  • Adadelta需要两个状态变量来存储梯度的二阶导数和参数的变化。
  • Adadelta使用泄漏的平均值来保持对适当统计数据的运行估计。

8 Adam

Adam算法的关键组成部分之一是:它使用指数加权移动平均值来估算梯度的动量和二次矩,即它使用状态变量

vtβ1vt1+(1β1)gt,stβ2st1+(1β2)gt2.

这里β1β2是非负加权参数。
常将它们设置为β1=0.9β2=0.999
也就是说,方差估计的移动远远慢于动量估计的移动。
注意,如果我们初始化v0=s0=0,就会获得一个相当大的初始偏差。
我们可以通过使用i=0tβi=1βt1β来解决这个问题。
相应地,标准化状态变量由下式获得

v^t=vt1β1t and s^t=st1β2t.

有了正确的估计,我们现在可以写出更新方程。
首先,我们以非常类似于RMSProp算法的方式重新缩放梯度以获得

gt=ηv^ts^t+ϵ.

与RMSProp不同,我们的更新使用动量v^t而不是梯度本身。
此外,由于使用1s^t+ϵ而不是1s^t+ϵ进行缩放,两者会略有差异。
前者在实践中效果略好一些,因此与RMSProp算法有所区分。
通常,我们选择ϵ=106,这是为了在数值稳定性和逼真度之间取得良好的平衡。

最后,我们简单更新:

xtxt1gt.

%matplotlib inline
from mxnet import np, npx
from d2l import mxnet as d2l

npx.set_np()

def init_adam_states(feature_dim):
    v_w, v_b = np.zeros((feature_dim, 1)), np.zeros(1)
    s_w, s_b = np.zeros((feature_dim, 1)), np.zeros(1)
    return ((v_w, s_w), (v_b, s_b))

def adam(params, states, hyperparams):
    beta1, beta2, eps = 0.9, 0.999, 1e-6
    for p, (v, s) in zip(params, states):
        v[:] = beta1 * v + (1 - beta1) * p.grad
        s[:] = beta2 * s + (1 - beta2) * np.square(p.grad)
        v_bias_corr = v / (1 - beta1 ** hyperparams['t'])
        s_bias_corr = s / (1 - beta2 ** hyperparams['t'])
        p[:] -= hyperparams['lr'] * v_bias_corr / (np.sqrt(s_bias_corr) + eps)
    hyperparams['t'] += 1
data_iter, feature_dim = d2l.get_data_ch11(batch_size=10)
d2l.train_ch11(adam, init_adam_states(feature_dim),
               {'lr': 0.01, 't': 1}, data_iter, feature_dim);

  • Adam算法将许多优化算法的功能结合到了相当强大的更新规则中。
  • Adam算法在RMSProp算法基础上创建的,还在小批量的随机梯度上使用EWMA。
  • 在估计动量和二次矩时,Adam算法使用偏差校正来调整缓慢的启动速度。
  • 对于具有显著差异的梯度,我们可能会遇到收敛性问题。我们可以通过使用更大的小批量或者切换到改进的估计值st来修正它们。

参考文献

《动手学深度学习》

posted @   朝南烟  阅读(188)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
历史上的今天:
2020-09-16 第一次个人编程作业
body { color: #000; background-color: #e6e6e6; font-family: "Helvetica Neue",Helvetica,Verdana,Arial,sans-serif; font-size: 12px; min-height: 101%; background: url(https://images.cnblogs.com/cnblogs_com/caolanying/1841633/o_2009041…ly1geq8oc9owbj21hc0u0th5.jpg) fixed; } #home { margin: 0 auto; opacity: 0.8; width: 65%; min-width: 1080px; background-color: #fff; padding: 30px; margin-top: 50px; margin-bottom: 50px; box-shadow: 0 2px 6px rgba(100, 100, 100, 0.3); }
点击右上角即可分享
微信分享提示