优化器
BGD
每次用整个批次的数据来计算梯度:
θ
=
θ
−
η
▽
θ
L
\theta = \theta -\eta \triangledown_\theta L
θ=θ−η▽θL
for i in range(nb_epochs):
params_grad = evaluate_gradient(loss_function, data, params)
params = params - learning_rate * params_grad
MBGD
MBGD 每一次利用一小批样本,即 n 个样本进行计算梯度更新值:
θ
=
θ
−
η
▽
θ
L
(
f
(
x
(
i
:
i
+
n
)
)
,
(
y
(
i
:
i
+
n
)
)
)
\theta = \theta -\eta \triangledown_\theta L(f(x^{(i:i+n)}),(y^{(i:i+n)}))
θ=θ−η▽θL(f(x(i:i+n)),(y(i:i+n)))
for i in range(epochs):
np.random.shuffle(data)
for batch in get_batches(data, batch_size=50):
params_grad = evaluate_gradient(loss_function, batch, params)
params = params - learning_rate * params_grad
SGD
每次随机选择一个样本,对
θ
\theta
θ进行更新:
θ
=
θ
−
η
▽
θ
L
(
f
(
x
i
)
,
y
i
)
\theta = \theta -\eta \triangledown_\theta L(f(x_i),y_i)
θ=θ−η▽θL(f(xi),yi)
for i in range(nb_epochs):
np.random.shuffle(data)
for example in data:
params_grad = evaluate_gradient(loss_function, example, params)
params = params - learning_rate * params_grad
从下面的优化器开始需要用到一阶动量和二阶动量的指数加权平均:
一阶动量的指数加权平均记为
m
t
m_t
mt
二阶动量的指数加权平均记为
v
t
v_t
vt
Momentum
让梯度在下降速度快的地方速度更快,相当于加上惯性,实现方式是参数不仅要减去当前梯度,还要减去历史梯度更新方向的指数加权平均:
g
t
=
▽
θ
L
m
t
=
γ
m
t
−
1
+
η
g
t
θ
=
θ
−
m
t
g_t=\triangledown_\theta L\\ m_t=\gamma m_{t-1}+\eta g_t\\ \theta = \theta - m_t
gt=▽θLmt=γmt−1+ηgtθ=θ−mt
NAG(Nesterov Accelerated Gradient)
与Momentum相似,只不过是在未来的位置上计算梯度
g
t
g_t
gt:
g
t
=
▽
θ
L
(
θ
−
γ
m
t
−
1
)
m
t
=
γ
m
t
−
1
+
η
g
t
θ
=
θ
−
m
t
g_t=\triangledown_\theta L(\theta-\gamma{m_{t-1}})\\ m_t=\gamma m_{t-1}+\eta g_t\\ \theta = \theta - m_t
gt=▽θL(θ−γmt−1)mt=γmt−1+ηgtθ=θ−mt
唯一的区别就是当前梯度是在减去了上一刻历史梯度的指数加权平均值之后进行计算的,这就是所谓的在未来位置上进行计算梯度。
上面的方法学习率不会根据训练的推进而改变
Adagrade
在参数空间更为平缓的方向,会取得更大的进步(因为平缓,所以历史梯度平方和较小,学习率下降的幅度较小,梯度更新的更快),并且能够使得陡峭的方向变得平缓,从而加快训练速度。
如图,假设两个参数w和b,明显梯度在b方向更陡峭,在w方向更平缓,绿色代码MBGD方法更新路线,该方法无论梯度平缓还是陡峭,学习率都不改变,红色代表Adagrade,梯度平缓时(w方向),更新的更快,梯度陡峭时(b方向),更新更慢:
Adagrad根据二阶动量的指数加权平均的倒数对学习率进行更新,学习率会随着二阶动量的积累逐渐变小:
g
t
=
▽
θ
L
v
t
=
v
t
−
1
+
g
t
⋅
g
t
△
θ
=
−
η
δ
+
v
t
g
t
θ
t
=
θ
t
−
1
+
△
θ
g_t=\triangledown_\theta L\\ v_t=v_{t-1}+g_t\cdot g_t\\ \triangle\theta = -\frac{\eta}{\delta+\sqrt{v_t}}g_t\\ \theta_t = \theta_{t-1} + \triangle \theta
gt=▽θLvt=vt−1+gt⋅gt△θ=−δ+vtηgtθt=θt−1+△θ
RMSProp
Adagrad随着梯度平方和的累积,使得学习率急速下降,所以引入RMSProp,作为改进版,唯一的区别就是
v
t
v_t
vt的计算:
g
t
=
▽
θ
L
v
t
=
ρ
v
t
−
1
+
(
1
−
ρ
)
g
t
⋅
g
t
△
θ
=
−
η
δ
+
v
t
g
t
θ
t
=
θ
t
−
1
+
△
θ
g_t=\triangledown_\theta L\\ v_t=\rho v_{t-1}+(1-\rho)g_t\cdot g_t\\ \triangle\theta = -\frac{\eta}{\delta+\sqrt{v_t}}g_t\\ \theta_t = \theta_{t-1} + \triangle \theta
gt=▽θLvt=ρvt−1+(1−ρ)gt⋅gt△θ=−δ+vtηgtθt=θt−1+△θ
RMSProp算法不是像AdaGrad算法那样暴力直接的累加平方梯度,而是加了一个衰减系数
ρ
\rho
ρ来控制历史信息的获取多少:
v
t
=
ρ
v
t
−
1
+
(
1
−
ρ
)
g
t
⋅
g
t
v_t=\rho v_{t-1}+(1-\rho)g_t\cdot g_t
vt=ρvt−1+(1−ρ)gt⋅gt
Adam
Adam是RMSProp和Momentum的结合:
首先计算一阶动量和二阶动量的指数加权平均值:
g
t
=
▽
θ
L
m
t
=
η
(
β
1
m
t
−
1
+
(
1
−
β
1
)
g
t
)
v
t
=
η
(
β
2
v
t
−
1
+
(
1
−
β
2
)
g
t
2
)
g_t=\triangledown_\theta L\\ m_t=\eta(\beta_1 m_{t-1}+(1-\beta_1) g_t)\\ v_t=\eta(\beta_2 v_{t-1}+(1-\beta_2) g_t^2)
gt=▽θLmt=η(β1mt−1+(1−β1)gt)vt=η(β2vt−1+(1−β2)gt2)
注意到,在迭代初始阶段,
m
t
m_t
mt和
v
t
v_t
vt 有一个向初值的偏移(过多的偏向了 0)。因此,可以对一阶和二阶动量做偏置校正 (bias correction):
m
^
t
=
m
t
1
−
β
1
\hat{m}_t=\frac{m_t}{1-\beta_1}
m^t=1−β1mt
v
^
t
=
v
t
1
−
β
2
\hat{v}_t=\frac{v_t}{1-\beta_2}
v^t=1−β2vt
用校正后的值更新参数:
θ
t
=
θ
t
−
1
−
1
δ
+
v
^
t
m
^
t
\theta_t = \theta_{t-1} -\frac{1}{\delta+\sqrt{\hat{v}_t}}\hat{m}_t
θt=θt−1−δ+v^t1m^t
参考
https://zhuanlan.zhihu.com/p/32626442
https://www.cnblogs.com/guoyaohua/p/8542554.html