梯度下降法
以简单的一维梯度下降为例, 解释梯度下降算法可能降低目标函数值的原因。假设连续可导的函数 $f: \mathbb{R} \rightarrow \mathbb{R}$ 的输入和输出都是标量。给定绝对值足唱小 的数 $\epsilon$, 根据泰勒展开公式 ,得到以下的近似:
这里 $f^{\prime}(x)$ 是函数在 $x$ 处的梯度。一维函数的梯度是一个标量, 也称导数。接下来, 找到一个常数 $\eta>0,$ 使得 $\left|\eta f^{\prime}(x)\right|$ 足够小, 那么可以将 $\epsilon$ 替换为 $-\eta f^{\prime}(x)$ 并得到
如果导数 $f^{\prime}(x) \neq 0,$ 那么 $\eta f^{\prime}(x)^{2}>0,$ 所以
这意味着,如果通过
来迭代 $x,$ 函数 $f(x)$ 的值可能会降低。因此在梯度下降中,我们先选取一个初始值x和常数 $\eta>0,$ 然后不断通过上式来迭代 $x,$ 直到达到停止条件, 例如 $f^{\prime}(x)^{2}$ 的 值已足够小或迭代次数已达到某个值 $_{9}$
下面我们以目标函数 $f(x)=x^{2}$ 为例来看一看梯度下降是如何工作的。虽然我们知道最小化 $f(x)$ 的解为 $x=0,$ 这里依然使用这个简单函数来观察 $x$ 是如何被迭代 的。首先, 导入本节实验所需的包或模块。
eta=0.05 | eta=1.1 |
---|---|
多维梯度下降
再考虑一种更广义的情况:目标函数的输入为向量, 输出为标量。假设目标函数 $f: \mathbb{R}^{d} \rightarrow \mathbb{R}$ 的输入是一个 $d$ 维向量 $\boldsymbol{x}=\left[x_{1}, x_{2}, \ldots, x_{d}\right]^{\top}$ 。目标函数 $f(\boldsymbol{x})$ 有关 $x$ 的梯度是一个由 $d$ 个偏导数组成的向量:
为表示简洁, 我们用 $\nabla f(\boldsymbol{x})$ 代替 $\nabla_{x} f(\boldsymbol{x})_{\circ}$ 梯度中每个偏导数元素 $\partial f(\boldsymbol{x}) / \partial x_{i}$ 代表着 $f$ 在 $\boldsymbol{x}$ 有关输入 $x_{i}$ 的变化率。为了测量 $f$ 沿着单位向量 $u$ 方向上的变化率, 在多元微积分中, 我们定义 $f$ 在 $x$ 上沿着 $u$ 方向的方向导数为
依据方向导数性质,以上方向导数可以改写为
方向导数 $\mathrm{D}_{\boldsymbol{u}} f(\boldsymbol{x})$ 给出了 $f$ 在 $x$ 上沿着所有可能方向的变化率。为了最小化 $f$, 我们希望找到 $f$ 降低最快的方向。因此,我们可以通过单位向量 $u$ 来最小化方向导 数 $\mathrm{D}_{\boldsymbol{u}} f(\boldsymbol{x})_{\text { }}$。
由于$D_{\boldsymbol{u}} f(\boldsymbol{x})=|\nabla f(\boldsymbol{x})| \cdot|\boldsymbol{u}| \cdot \cos (\theta)=|\nabla f(\boldsymbol{x})| \cdot \cos (\theta),$ 其中 $\theta$ 为梯度 $\nabla f(\boldsymbol{x})$ 与单位向量 $u$ 之间的夹角, 当 $\theta=\pi$ 时, $\cos (\theta)$ 取得最小值-1。因此, 当 $\boldsymbol{u}$ 在梯度方向 $\nabla f(\boldsymbol{x})$ 的相反方向时, 方向导数 $\mathrm{D}_{\boldsymbol{u}} f(\boldsymbol{x})$ 被最小化。因此, 我们可能通过梯度下降法来不断降低目标函数 $f$ 的值:
其中$\eta$称为学习率。
随机梯度下降
在优化过程中,目标函数通常是训陈数据集中有关各个样本的损失函数的平均。设 $f_{i}(\boldsymbol{x})$ 是有关索引为 $i$ 的训练数据样本的损失函数, $n$ 是训练数据样本数, $\boldsymbol{x}$ 是模 的参数向量, 那么目标函数定义为
日标函数在 $x$ 处的梯度计算为
如果使用梯度下降, 每次自变量迭代的计算开销为 $\mathcal{O}(n),$ 它随着 $n$ 线性增长。因此, 当训切数据样本数很大时, 梯度下降每次迭代的计算开销很高。而随机梯度下降 (stochastic gradient descent, SGD) 减少了每次迭代的计算开销。在随机梯度下降的每次迭代中,我们随机均匀采样的一个样本索引 $i \in\{1, \ldots, n\},$ 并计算梯度 $\nabla f_{i}(\boldsymbol{x})$ 来迭代 $\boldsymbol{x}:$
里 $\eta$ 同样是学习率。可以看到, 每次迭代的计算开销从梯度下降的 $\mathcal{O}(n)$ 降到了常数 $\mathcal{O}(1)$ 。值得强调的是, 随机梯度 $\nabla f_{i}(\boldsymbol{x})$ 是对梯度 $\nabla f(\boldsymbol{x})$ 的无偏估计:
这意味着,随机梯度是对梯度的一个良好的估计。
多维梯度下降 | 随机梯度下降 |
---|---|
</div> |
梯度下降的问题
当目标函数在不同特征上梯度差别很大时,例如输入和输出分别为二维向量$x=[x_1,x_2]^T$,目标函数$f(x)=0.1x_1^2+2x_2^2$,当使用学习率为0.4时的迭代轨迹:
可以看出,目标函数在$x_2$轴方向比水平方向的斜率绝对值更大。这样梯度下降迭代自变量时在在$x_2$轴方向上的移动幅度比$x_1$轴方向要大。这样需要一个较小的学习率来避免在$x_2$轴方向上越过目标函数的最优解,然而,这样会造成在$x_1$轴方向上的移动变慢。试着稍微调大学习率(0.6)时的迭代轨迹:
动量法
动量法的提出就是为了解决梯度下降的上述问题。设时间步$t$的自变量为$x_t$,学习率为$\eta_t$。 在时间步$0$,动量法创建速度变量$v_0$,并将其元素初始化成$0$。在时间步$t>0$,动量法对每次迭代的步骤做如下修改:
其中,动量超参数$\gamma$满足$0≤\gamma≤1$。当$\gamma=0$时,动量法等价于小批量随机梯度下降。梯度下降在使用动量法后的迭代轨迹:
eta=0.4 | eta=0.6 |
---|---|
指数加权平均
给定超参数$0≤\gamma≤1$,当前时间步$t$的变量$y_t$是上一时间步$t−1$的变量$y_{t−1}$和当前时间步另一变量$x_t$的线性组合:
对$y_t$展开:
令$n=\frac{1}{1-\gamma}$,那么$(1-1/n)^n = \gamma^{1/(1-\gamma)}$。因为
所以当 $\gamma \rightarrow 1$ 时, $\gamma^{1 /(1-\gamma)}=\exp (-1),$ 如 $0.95^{20} \approx \exp (-1)$ 。如果把exp (-1) 当作一个比较小的数, 我们可以在近似中忽略所有含 $\gamma^{1 /(1-\gamma)}$ 和比 $\gamma^{1 /(1-\gamma)}$ 更高阶的系数的项。例如, 当 $\gamma=0.95$ 时,
常常将$y_t$看作是对最近$1/(1-\gamma)$个时间步的$x_t$值的加权平均。例如,当$\gamma=0.95$时,$y_t$可以被看作对最近$20$个时间步的$x_t$值的加权平均;当$\gamma=0.9$时,$y_t$可以看作是对最近$10$个时间步的$x_t$值的加权平均。
对动量法的速度变量做变形:
由指数加权移动平均的形式可得,速度变量$v_t$实际上对序列${\eta_{t-i}\boldsymbol{g}_{t-i}:i=0,…,1/(1-\gamma)-1}$做了指数加权移动平均。相比于小批量随机梯度下降,动量法在每个时间步的自变量更新量近似于将前者对应的最近$1/(1−\gamma)$个时间步的更新量做了指数加权移动平均后再除以$1−\gamma$。所以,在动量法中,自变量在各个方向上的移动幅度不仅取决于当前梯度,还取决于过去的各个梯度在各个方向上是否一致。
偏差修正 [vedio]
1 | def sgd_momentum(w, dw, config=None): |
Nesterov Momentum是动量法的一个略有不同的版本,它对凸函数具有更强的理论收敛性保证,并且在实践中它总体上比标准动量要好一些。
Nesterov动量更新的核心思想是:当前参数向量在某个位置$x$处时,动量法是以当前梯度与动量 之和作为更新方向,而Nesterov动量更新则是以未来的近似位置${x + mu * v}$视为“前瞻”。 该算法认为,计算“前瞻”处的梯度要比计算原始位置的梯度更有意义。
1 | x_ahead = x + mu * v |
1 | # 在实践中,人们更喜欢将更新表达为与SGD或之前的动量更新尽可能相似。即存储前一个版本的参数向量。 |
AdaGrad 算法
AdaGrad算法会使用一个小批量随机梯度 $g_{t}$ 按元素平方的累加变量 $s_{t \circ}$ 在时间步0, AdaGrad将 $s_{0}$ 中每个元素初始化为0。在时间步 $t,$ 首先将小批量随机梯度 $g_{t}$ 按 元素平方后累加到变量 $s_{t}:$
其中$\odot$是按元素相乘。接着,我们将目标函数自变量中每个元素的学习率通过按元素运算重新调整一下:
其中 $\eta$ 是学习率, $\epsilon$ 是为了维持数值稳定性而添加的常数, 如 $10^{-6}$ 。这里开方、除法和乘法的运算都是按元素运算的。这些按元素运算使得目标函数自变量中每个 元素都分别拥有自己的学习率。
eta=0.4 | eta=2 |
---|---|
需要强调的是,小批量随机梯度按元素平方的累加变量$s_t$出现在学习率的分母项中。因此,如果目标函数有关自变量中某个元素的偏导数一直都较大,那么该元素的学习率将下降较快;反之,如果目标函数有关自变量中某个元素的偏导数一直都较小,那么该元素的学习率将下降较慢。然而,由于$s_t$一直在累加按元素平方的梯度,自变量中每个元素的学习率在迭代过程中一直在降低(或不变)。所以,当学习率在迭代早期降得较快且当前解依然不佳时,AdaGrad算法在迭代后期由于学习率过小,可能较难找到一个有用的解。
RMSProp 算法
当学习率在迭代早期降得较快且当前解依然不佳时,AdaGrad算法在迭代后期由于学习率过小,可能较难找到一个有用的解。为了解决这一问题,RMSProp算法对AdaGrad算法做了一点小小的修改。
不同于AdaGrad算法里状态变量 $s_{t}$ 是截至时间步 $t$ 所有小批量随机梯度 $g_{t}$ 按元素平方和, RMSProp算法将这些梯 度按元素平方做指数加权移动平均。具体来说, 给定超参数 $0 \leq \gamma<1,$ rmsprop算法在时间步 $t>0$ 计算1,$>
和AdaGrad算法一样, RMSProp算法将目标函数自变量中每个元素的学习率通过按元素运算重新调整, 然后更新自变量
其中 $\eta$ 是学习率, $\epsilon$ 是为了维持数值稳定性而添加的常数, 如 $10^{-6}$ 。因为RMSProp算法的状态变量 $s_{t}$ 是对平方项 $g_{t} \odot g_{t}$ 的指数加权移动平均, 所以可以看作最近 $1 /(1-\gamma)$ 个时间步的小批量随机梯度平方项的加权平均。如此一来, 自变量每个元素的学习率在迭代过程中就不再一直降低 (或不变)。
1 | def rmsprop(w, dw, config=None): |
Adam 算法
$0 \leq \beta_{1}<1($ 算法作者建议设为0.9 $)$, 时间步 $t$ 的动量变量 $v_{t}$ 即小批量随机梯度 $g_{t}$ 的指数加权移动平均:
和RMSProp算法中一样, 给定超参数 $0 \leq \beta_{2}<1$ (算法作者建议设为0.999), 将小批量随机梯度按元素平方后的项 $\boldsymbol{g}_{t} \odot g_{t}$ 做指数加权移动平均得到 $s_{t}:$
由于我们将 $v_{0}$ 和 $s_{0}$ 中的元素都初始化为0, 在时间步 $t$ 我们得到 $v_{t}=\left(1-\beta_{1}\right) \sum_{i=1}^{t} \beta_{1}^{t-i} g_{i}$ 将过去各时间步小批量随机梯度的权值相加, 得到 $\left(1-\beta_{1}\right) \sum_{i=1}^{t} \beta_{1}^{t-i}=1-\beta_{1}^{t}$ 需要注意的是, 当t较小时,过去各时间步小批量随机梯度权值之和会较小。例如, 当 $\beta_{1}=0.9$ 时, $\boldsymbol{v}_{1}=0.1 \boldsymbol{g}_{1}$ 。为了消除这样
的影响,对于任意时间步 $t,$ 我们可以将 $v_{t}$ 再除以 $1-\beta_{1}^{t},$ 从而使过去各时间步小批量随机梯度权值之和为1。这也叫作偏差修正。在Adam算法中,我们对变量 $\boldsymbol{v}$ 和 $s_{t}$ 均作偏差修正:
其中 $\eta$ 是学习率, $\epsilon$ 是为了维持数值稳定性而添加的常数, 如 $10^{-8}$ 。和AdaGrad算法、RMSProp算法以及AdaDelta算法一样, 目标函数自变量中每个元素都分另 拥有白己的学习率。最后, 使用 $g_{t}^{\prime}$ 迭代白变量:
1 | def adam(w, dw, config=None): |
优化算法迭代轨迹
3D | 2D |
---|---|