Gradient descent (梯度下降)
来自维基百科,https://en.wikipedia.org/wiki/Gradient_descent
在数学中,梯度下降 gradient descent(也叫做最速下降 steepest descent)是一种一阶迭代优化算法,用于寻找可微函数的局部最小值。它的思路是,在当前点求出函数的梯度(或者近似梯度),然后向着梯度的反方向走一小步,因为这个方向是最陡的。然后不断地重复这个过程。相反地,朝着梯度的方向走,会把你带往函数的局部最大值,这个过程被称为梯度上升(gradient ascent)
梯度下降通常归功于柯西(Augustin-Louis Cauchy),它在1847年首次提出。- -《Cauchy and the Gradient Method》。
阿达马(Jacques Solomon Hadamard)在1907年独立提出了类似的方法。
库里(Haskell Curry)与1944年首先研究了它对非线性优化问题的收敛性 - - 《The Method of Steepest Descent for Non-linear Minimization Problems》。
描述
梯度下降基于这样一种观察:如果定义一个多变量函数 F ( x ) \pmb{F}(\textbf{x}) FFF(x) ,它在点 a \mathbf{a} a 的邻域是可微的,在点 a \mathbf{a} a 处求出函数 F \pmb{F} FFF 的梯度,如果向着梯度的反方向走: − ∇ F ( a ) -\nabla\pmb{F}(\textbf{a}) −∇FFF(a),则 F ( x ) \pmb{F}(\textbf{x}) FFF(x) 是下降得最快的。
由此可见,对于式子 a n + 1 = a n − γ ∇ F ( a n ) \textbf{a}_{n+1} = \textbf{a}_n - \gamma \nabla \pmb{F}(\textbf{a}_n) an+1=an−γ∇FFF(an),如果有足够小的学习率 (或者叫步长) γ ∈ R + \gamma \in \mathbb{R}_+ γ∈R+,那么就有 F ( a n + 1 ) ≤ F ( a n ) \pmb{F}(\textbf{a}_{n+1}) \leq \pmb{F}(\textbf{a}_n) FFF(an+1)≤FFF(an)。为什么是减去梯度呢,之前写的文章(https://blog.csdn.net/Yemiekai/article/details/119081873)有个例子里有个图片做了简单的解释。
考虑到上述观察,为了得到
F
\pmb{F}
FFF 的局部最小值,我们从一个猜测的初始值
x
0
\textbf{x}_0
x0 开始,考虑序列:
x
0
,
x
1
,
x
2
,
…
\textbf{x}_0,\textbf{x}_1,\textbf{x}_2,\dots
x0,x1,x2,… ,满足
x
n
+
1
=
x
n
−
γ
n
∇
F
(
x
n
)
,
n
≥
0
\textbf{x}_{n+1} = \textbf{x}_n - \gamma_n \nabla \pmb{F}(\textbf{x}_n), \; n \geq0
xn+1=xn−γn∇FFF(xn),n≥0
则我们会得到一个单调序列:
F
(
x
0
)
≥
F
(
x
1
)
≥
F
(
x
2
)
≥
⋯
,
\pmb{F}(\textbf{x}_0) \geq \pmb{F}(\textbf{x}_1) \geq \pmb{F}(\textbf{x}_2) \geq \cdots,
FFF(x0)≥FFF(x1)≥FFF(x2)≥⋯,
所以这个序列(
x
n
\textbf{x}_n
xn)会如期收敛到所需要的局部最小值。 注意步长
γ
\gamma
γ 的值可以在每次迭代中改变。
这个过程如上图所示,假设
F
\pmb{F}
FFF 被定义在一个平面上,它的形状就像一个碗状。蓝色的的曲线是等高线,即在同一条等高线上的
F
\pmb{F}
FFF 的值是相同恒定的。每个点上有一个红色的箭头,表示该点梯度相反的方向。每个点的梯度与穿过该点的等高线正交。可以看到梯度下降把我们带到了碗底,在那里能得到
F
\pmb{F}
FFF 的最小值。
例子
线性方程组的解、凸二次优化问题
(来自知乎:https://zhuanlan.zhihu.com/p/330267047)
设 A ∈ R n × n \pmb{A} \in \pmb{R}^{ \textbf{\textit{n}}\times \textbf{\textit{n}}} AAA∈RRRn×n 是实对称正定矩阵, b ∈ R n \textbf{\textit{b}} \in \textbf{\textit{R}}^{\textbf{\textit{n}}} b∈Rn,则求解凸二次优化问题: min f ( x ) = 1 2 x T A x − b T x \min f(x)=\dfrac{1}{2} \textbf{\textit{x}}^{\textbf{\textit{T}}} \pmb{A} \textbf{\textit{x}} - \textbf{\textit{b}}^{\textbf{\textit{T}}} \pmb{x} minf(x)=21xTAAAx−bTxxx等价于求解线性方程组 A x = b \pmb{A} \pmb{x} = \pmb{b} AAAxxx=bbb。
证明:
二次型二阶可导,极小值点处梯度为零,现对优化的目标函数求梯度。
二次型本质上具有:
f
(
x
)
=
1
2
x
T
A
x
−
b
T
x
=
1
2
∑
i
=
j
a
i
i
x
i
2
+
1
2
∑
i
≠
j
a
i
j
x
i
x
j
−
∑
i
b
i
x
i
\begin{aligned} f(x) &=\dfrac{1}{2} \textbf{\textit{x}}^{\textbf{\textit{T}}} \pmb{A} \textbf{\textit{x}} - \textbf{\textit{b}}^{\textbf{\textit{T}}} \pmb{x} \\[1.5em] &= \dfrac{1}{2}\sum_{i=j} \pmb{a}_{ii} \pmb{x}_i^2 + \dfrac{1}{2}\sum_{i\neq j}\pmb{a}_{ij} \pmb{x}_i \pmb{x}_j - \sum_{i} \pmb{b}_i \pmb{x}_i \end{aligned}
f(x)=21xTAAAx−bTxxx=21i=j∑aaaiixxxi2+21i=j∑aaaijxxxixxxj−i∑bbbixxxi
计算梯度的分量表达式: ∇ f ( x ) i = ∂ f ∂ x i = a i i x i + ∑ j ≠ i a i j x j − b i = ∑ j a i j x j − b i \begin{aligned} \nabla f(\pmb{x})_i &= \dfrac{\partial \pmb{f}}{ \partial \pmb{x}_i} \\[1.5em] &= \pmb{a}_{ii} \pmb{x}_{i} + \sum_{j\neq i} \pmb{a}_{ij} \pmb{x}_j -\pmb{b}_i \\[1.5em] &= \sum_{j} \pmb{a}_{ij} \pmb{x}_j - \pmb{b}_i \end{aligned} ∇f(xxx)i=∂xxxi∂fff=aaaiixxxi+j=i∑aaaijxxxj−bbbi=j∑aaaijxxxj−bbbi
合在一起写成矩阵形式:
∇
f
(
x
)
=
A
x
−
b
=
0
\nabla f(\pmb{x}) = \pmb{Ax} - \pmb{b} = 0
∇f(xxx)=AxAxAx−bbb=0
显然,凸二次优化问题的极值条件等价于该线性方程组。凸二次优化问题在建模中十分常见,这说明讨论线性方程组的求解方法具有普遍的实用价值。然而对于规模较大的问题,使用线性代数中的克莱姆法则暴力展开将导致时间开销巨大,而高斯消元法算法流程又较为复杂。这里用一种常见的数值分析方法,求得线性方程组的数值近似解。
最速梯度下降法:
称优化目标函数的梯度为残量(Residue),即是当前解对于线性方程组的不满足量:
r
(
x
)
=
A
x
−
b
\pmb{r}(\pmb{x}) = \pmb{Ax} - \pmb{b}
rrr(xxx)=AxAxAx−bbb
由于函数是凸函数,极值点一定存在。当前解处函数的梯度值表示了函数值上升最快的方向(梯度方向上方向导数最大)。那么沿着相反的方向每迭代一步就会更加靠近最优的极小值解。于是,我们定义迭代关系:
x
(
k
+
1
)
=
x
(
k
)
−
α
k
∇
f
(
x
(
k
)
)
=
x
(
k
)
−
α
k
(
A
x
(
k
)
−
b
)
\begin{aligned} \pmb{x}^{(k+1)} &= \pmb{x}^{(k)} - \alpha_k \nabla \pmb{f} (\pmb{x}^{(k)}) \\[1.5em] &= \pmb{x}^{(k)} - \alpha_k \left( \pmb{A} \pmb{x}^{(k)} - \pmb{b }\right)\\[1.5em] \end{aligned}
xxx(k+1)=xxx(k)−αk∇fff(xxx(k))=xxx(k)−αk(AAAxxx(k)−bbb)
其中 x ( k ) \pmb{x}^{(k)} xxx(k) 表示迭代第 k k k 轮的解, α k \alpha_k αk 表示每轮迭代的步长,即每一步下降多少的权重。步长应当随着 k k k 而变化,因为越靠近驻点的梯度会越小,接近于 0 0 0 的时候收敛。最后应当减小步长,不然在梯度附近会来回震荡,在最优解之间左右摇摆。
在最速下降法中,将
x
(
k
+
1
)
\pmb{x}^{(k+1)}
xxx(k+1) 作为自变量代回原函数,并看做
α
k
\alpha_k
αk 的函数,对其进行最小化:
min
h
(
α
)
=
f
(
x
(
k
+
1
)
)
=
f
(
x
(
k
)
−
α
k
(
A
x
(
k
)
−
b
)
)
\begin{aligned} \min h(\alpha) &= f \left( \pmb{x}^{(k+1)} \right) \\[1.5em] &= f \left( \pmb{x}^{(k)} - \alpha_k \left( \pmb{A} \pmb{x}^{(k)} - \pmb{b} \right) \right) \end{aligned}
minh(α)=f(xxx(k+1))=f(xxx(k)−αk(AAAxxx(k)−bbb))
同样的,驻点处梯度为零。根据链式求导法则:
最后一步由于
A
\pmb{A}
AAA 是正定矩阵,所以分母也是一个正定二次型,值不为零,可以直接除过来。由此,我们最终得到了解的迭代关系:
Stochastic Gradient descent (SGD,随机梯度下降)
它可以被当做是梯度下降的随机近似。
原本的梯度下降是把整个数据集的数据扔进去,算出一个梯度。
假如我们有
500
500
500 万个样本,那么我们每迈一步,就要算
500
500
500 万个样本的梯度,这样效率太低了。
而随机梯度下降是用随机选择的数据子集来计算梯度。尤其是在高维优化问题中,这减少了计算负担,实现更快的迭代以换取更低的收敛速度。
虽然单个样本或者一小批样本不能反映整体的趋势,甚至把你的求解带偏,损失会波动。但是长远来看,只要迭代次数足够多,最终还是收敛的。
本质上它还是梯度下降,只是每次计算用多少数据的问题。
有的人说
SGD
\text{SGD}
SGD 每次只用
1
1
1 个样本,有的人说是用
1
1
1 批(mini-batch)样本。
知道意思就行了,不要纠结到底用多少样本。
随机梯度下降的过程如下:
∙
\bullet
∙ 选择一个初始的参数向量
w
\pmb{w}
www 和学习率
η
\eta
η.
∙
\bullet
∙ 重复下面步骤,直至获得最小值:
∙
\bullet
∙ 把训练集打乱。
∙
\bullet
∙ 对于
i
=
1
,
2
,
…
,
n
,
i = 1, 2, \dots, n,
i=1,2,…,n, 做:
∙
\bullet
∙
w
:
=
w
−
η
∇
F
i
(
w
)
\pmb{w} := \pmb{w} - \eta \nabla \pmb{F}_i (\pmb{w})
www:=www−η∇FFFi(www)
Batch Gradient Descent (批梯度下降)
Mini Batch Gradient Descent (小批量梯度下降)
其实意思也一样,只是每一个 step 用多少样本的问题。
有的人说 Batch Gradient descent 是用整个样本,有的人说是用一批(此时等同于 Mini Batch Gradient Descent)。
Momentum Gradient descent (动量梯度下降)
它是随机梯度下降的一种改进。这种方法最早出现在 Rumelhart,Hinton 和 Williams 等人关于反向传播学习的论文中。《Learning representations by back-propagating errors》
这是一种带动量的随机梯度下降,它会在每次迭代中记住上一次的更新量
Δ
w
\Delta \pmb{w}
Δwww,然后与当前的梯度做一个线性组合,以决定最终参数更新多少:
Δ
w
:
=
α
Δ
w
−
η
∇
F
i
(
w
)
w
:
=
w
+
Δ
w
\begin{aligned} & \Delta \pmb{w} := \alpha \Delta \pmb{w} - \eta \nabla \pmb{F}_i (\pmb{w}) \\ & \pmb{w} :=\pmb{w} + \Delta \pmb{w} \end{aligned}
Δwww:=αΔwww−η∇FFFi(www)www:=www+Δwww 即
w
:
=
w
−
η
∇
F
i
(
w
)
+
α
Δ
w
\pmb{w} :=\pmb{w} - \eta \nabla \pmb{F}_i (\pmb{w}) + \alpha \Delta \pmb{w}
www:=www−η∇FFFi(www)+αΔwww
其中你要解决的最小化问题是
F
(
w
)
\pmb{F}(\pmb{w})
FFF(www) ,
w
\pmb{w}
www 是它的参数。
η
\eta
η 是步长(也叫学习率)。
α
\alpha
α 是指数衰减因子,
α
∈
(
0
,
1
)
\alpha \in (0,1)
α∈(0,1),决定你更新参数
w
\pmb{w}
www 时,当前梯度和以往的梯度各自占多少贡献。
Averaged Stochastic Gradient Descent (平均随机梯度下降)
由 Ruppert 和 Polyak 在1980 年代后期提出。《Acceleration of stochastic approximation by averaging》
它是一种普通的随机梯度下降,在当前迭代中用随机梯度下降更新参数,得到 w i \pmb{w}_i wwwi,记录下来。然后对过往时刻求平均: w ˉ = 1 t ∑ i = 1 t − 1 w i \bar{\pmb{w}} = \dfrac{1}{t} \sum^{t-1}_{i=1} \pmb{w}_i wwwˉ=t1i=1∑t−1wwwi
然后把当前网络参数换成这个平均后的 w ˉ \bar{\pmb{w}} wwwˉ,继续下一个迭代。
AdaGrad (Adaptive Gradient,自适应梯度)
g
τ
=
∇
F
i
(
w
)
\pmb{g}_{\tau} = \nabla \pmb{F}_i (\pmb{w})
gggτ=∇FFFi(www) 表示第
τ
\tau
τ 次 iteration 算出来的梯度。每个 iteration 的梯度都会保存起来。参数数量是
j
j
j,有
j
j
j 个梯度。
到了第
τ
\tau
τ 次迭代的时候,对过往每个时刻的
g
\pmb{g}
ggg 求平方,把所有时刻的平方的结果都加起来,用
G
j
,
j
=
∑
τ
=
1
t
g
τ
,
j
2
G_{j,j} = \sum\limits^t_{\tau = 1} g^2_{\tau, j}
Gj,j=τ=1∑tgτ,j2 表示。
然后开根号,
G
j
,
j
=
∑
τ
=
1
t
g
τ
,
j
2
\sqrt{G_{j,j}} = \sqrt{ \sum\limits^t_{\tau = 1} g^2_{\tau, j} }
Gj,j=τ=1∑tgτ,j2,学习率为
η
G
j
,
j
\dfrac{\eta}{\sqrt{G_{j,j}}}
Gj,jη。
为了防止分母为 0 0 0,有时候会加上一个很小的值 ϵ = 1 0 − 8 \epsilon = 10^{-8} ϵ=10−8。
最终的参数更新式子为: w j : = w j − η G j , j + ϵ g j w_j := w_j - \frac{\eta}{\sqrt{G_{j,j} + \epsilon } } g_j wj:=wj−Gj,j+ϵηgj
这说明什么?学习率除以一个东西,这个东西是过往梯度的积累。
也就是说,过往梯度越大,学习率就会越小。
SGD系列的都没有用到二阶动量。二阶动量的出现,才意味着“自适应学习率”优化算法时代的到来。SGD及其变种以同样的学习率更新每个参数,但深度神经网络往往包含大量的参数,这些参数并不是总会用得到。
∙
\bullet
∙ 对于经常更新的参数,我们已经积累了大量关于它的知识,不希望被单个样本影响太大,希望学习速率慢一些;
∙
\bullet
∙ 对于偶尔更新的参数,我们了解的信息太少,希望能从每个偶然出现的样本身上多学一些,即学习速率大一些。
因此,Adagrad 非常适用于稀疏数据。
Dean 等人发现 Adagrad 能够大幅提高 SGD 的鲁棒性,并在 Google 用其训练大规模神经网络,这其中就包括 在 YouTube 中学习识别猫。除此之外,Pennington 等人用 Adagrad 来训练 GloVe 词嵌入,因为罕见的词汇需要比常见词更大的更新。
参数更新越频繁,二阶动量越大,学习率就越小。有趣的是,如果去掉开方操作,算法性能会大幅下降。
RMSProp (Root Mean Square Propagation)
参考
https://zh.d2l.ai/chapter_optimization/rmsprop.html
https://keras.io/zh/optimizers/#rmsprop
https://paddlepedia.readthedocs.io/en/latest/tutorials/deep_learning/optimizers/rmsprop.html
上面 AdaGrad 那个 G j , j G_{j,j} Gj,j,原本等于 g 0 2 + g 1 2 + g 2 2 + ⋯ + g τ 2 g_0^2 + g_1^2 + g_2^2 + \cdots + g_{\tau}^2 g02+g12+g22+⋯+gτ2。
按照递归的方式可以写成: v τ = v τ − 1 + g τ 2 v_{\tau} = v_{\tau-1} + g_{\tau}^2 vτ=vτ−1+gτ2,其中( v τ − 1 = g 0 2 + ⋯ + g τ − 1 2 v_{\tau -1} = g_0^2 + \cdots + g_{\tau -1}^2 vτ−1=g02+⋯+gτ−12)
由于 AdaGrad 简单粗暴地累计过往的所有梯度,用于更新学习率。
这样做缺乏规范化,没有约束力。
RMSProp 对 AdaGrad 做了修改,以在非凸情况下表现更好,它改变梯度累积为指数加权的移动平均值,从而丢弃距离较远的历史梯度信息,关注最近的梯度信息。
现在用移动平均(或者说动量法)的方式来积累根号里面那个东西。在
t
t
t 时刻:
v
t
=
γ
v
t
−
1
+
(
1
−
γ
)
g
t
2
v_t = \gamma v_{t-1} + (1-\gamma) g_{t}^2
vt=γvt−1+(1−γ)gt2
其中
g
t
=
∇
F
i
(
w
)
g_t = \nabla F_i (w)
gt=∇Fi(w) 表示当前时刻的梯度。
然后就是和 Adagrad 一样:
w
:
=
w
−
η
v
t
+
ϵ
g
t
w:= w - \frac{\eta}{\sqrt{ v_t + \epsilon } } g_t
w:=w−vt+ϵηgt
这里作者推荐 γ \gamma γ 取 0.9 0.9 0.9,学习率 η \eta η 为 0.001 0.001 0.001。
Adam (Adaptive Moment Estimation)
它是 RMSProp 的升级版,也是 RMSProp 和 Momentum Gradient descent 的结合体。
把动量梯度下降的一阶动量和 RMSProp 的二阶动量都拿来了。
对于当前训练迭代次数 t t t,给定参数 w ( t ) w^{(t)} w(t) 和损失函数 L ( t ) L^{(t)} L(t),Adam 的更新过程如下:
m
w
(
t
+
1
)
←
β
1
m
w
(
t
)
+
(
1
−
β
1
)
∇
w
L
(
t
)
v
w
(
t
+
1
)
←
β
2
v
w
(
t
)
+
(
1
−
β
2
)
(
∇
w
L
(
t
)
)
2
m^{(t+1)}_{w} \leftarrow \beta_1 m^{(t)}_{w} + (1-\beta_1) \nabla_w L^{(t)} \\[1em] v^{(t+1)}_{w} \leftarrow \beta_2 v^{(t)}_{w} + (1-\beta_2) \left( \nabla_w L^{(t)} \right)^2 \\[1em]
mw(t+1)←β1mw(t)+(1−β1)∇wL(t)vw(t+1)←β2vw(t)+(1−β2)(∇wL(t))2以上分别表示一阶动量(可以说是均值,mean)和二阶动量(可以说是方差,variance)。
其中
β
1
\beta_1
β1 通常取
0.9
0.9
0.9,
β
2
\beta_2
β2 通常取
0.999
0.999
0.999。
初始时刻
m
m
m 和
v
v
v 可能为
0
0
0,代进去算出来下一时刻的
m
m
m 和
v
v
v 也接近
0
0
0 ,这样不好。
于是我们这样弄一下:
m
^
w
=
m
w
(
t
+
1
)
1
−
β
1
t
v
^
w
=
v
w
(
t
+
1
)
1
−
β
2
t
\hat{m}_w = \frac{ m^{(t+1)}_{w} }{ 1- \beta_1^{t} } \\[1em] \hat{v}_w = \frac{ v^{(t+1)}_{w} }{ 1- \beta_2^{t} } \\[1em]
m^w=1−β1tmw(t+1)v^w=1−β2tvw(t+1)最后:
w
t
+
1
←
w
(
t
)
−
η
m
^
w
v
^
w
+
ϵ
w^{t+1} \leftarrow w^{(t)} - \eta \frac{ \hat{m}_w }{ \sqrt{\hat{v}_w } + \epsilon }
wt+1←w(t)−ηv^w+ϵm^w
以上 5 5 5 条式子合起来就是 Adam 的步骤。
优点:
—— 通过一阶动量和二阶动量,有效控制学习率步长和梯度方向,防止梯度的振荡和在鞍点的静止。
—— 实现简单,计算高效,对内存需求少。
—— 参数的更新不受梯度的伸缩变换影响。
—— 超参数具有很好的解释性,且通常无需调整或仅需很少的微调。
—— 更新的步长能够被限制在大致的范围内(初始学习率)。
—— 能自然地实现步长退火过程(自动调整学习率)。
—— 很适合应用于大规模的数据及参数的场景。
—— 适用于不稳定目标函数。
—— 适用于梯度稀疏或梯度存在很大噪声的问题。
缺点:
—— 可能不收敛:二阶动量是固定时间窗口内的累积,随着时间窗口的变化,遇到的数据可能发生巨变,使得
v
t
v_t
vt 可能会时大时小,不是单调变化。这就可能在训练后期引起学习率的震荡,导致模型无法收敛。
—— 可能错过全局最优解:自适应学习率算法可能会对前期出现的特征过拟合,后期才出现的特征很难纠正前期的拟合效果。后期Adam的学习率太低,影响了有效的收敛。
—— 对于具有显著差异的梯度,我们可能会遇到收敛性问题。我们可以通过使用更大的小批量或者切换到改进的估计值
v
t
v_t
vt 来修正它们。