在深度学习的训练中,我们依赖于权重系数来构建和调整模型。这些权重系数需要通过反向传播算法进行更新,以实现模型训练的目标。
权重的更新是基于梯度来计算的,而梯度的获取方式并非单一,它们由不同类型的优化器提供。这就是我们今天要深入探讨的优化器的角色。
首先为了后续符号的统一,我们先引入一个最为常见的损失函数: L = ∑ i = 1 m ( y i − f w , b ( x i ) ) 2 L= \sum_{i=1}^m(y_i - f_{w,b}(\bold{x}_i))^2 L=i=1∑m(yi−fw,b(xi))2这个损失函数是计算全体数据样本的损失函数,一般来说,只是随机采用一个样本 i i i 进行权重更新的话,则可以将损失函数写成: L ( i ) = ( y i − f w , b ( x i ) ) 2 L(i)= (y_i - f_{w,b}(\bold{x}_i))^2 L(i)=(yi−fw,b(xi))2如果要计算其基于 w j w_j wj 的偏导数,也就是梯度的话,我们可以得到 ∂ L ( i ) ∂ w j \frac{\partial{L(i)}}{\partial{w_j}} ∂wj∂L(i),考虑上时间 t t t 来表示更新前( t − 1 t-1 t−1)和更新后( t t t)的区别,可以写成: ∂ L ( i ) ∂ w t − 1 , j \frac{\partial{L(i)}}{\partial{w_{t-1,j}}} ∂wt−1,j∂L(i),因为梯度是根据前一个时刻的权重系数 w t − 1 , j w_{t-1,j} wt−1,j 计算的。
后续为了简化,我会写成 ∇ L ( w t − 1 , j ) i \nabla L(w_{t-1,j})_i ∇L(wt−1,j)i,来表示损失函数在 t − 1 t-1 t−1 时刻关于 w j w_j wj 的偏导数,也就是梯度。
按照我的理解,通过前一时刻( t − 1 t-1 t−1)的权重系数计算出来的梯度,应该是算是前一时刻的梯度?
但是 Pytorch 官方实现各种优化器的时候,都是这么表示梯度的: g t ← ∇ θ f t ( θ t − 1 ) g_t \leftarrow \nabla_{\theta}f_t(\theta_{t-1}) gt←∇θft(θt−1),这就意味着,Pytorch 官方定义,通过 t − 1 t-1 t−1 时刻的权重系数计算出来的事当前 t t t 时刻的梯度。
但是,我为了方便理解,将 t − 1 t-1 t−1 时刻权重计算得到的梯度表示为 t − 1 t-1 t−1 时刻的梯度,即 g t − 1 g_{t-1} gt−1,这样对我来说更好理解一些,但是暂时还不知道坏处是啥?如果有大佬可以告诉我是否可行,我感觉梯度因为是实时计算的,不需要更新的,标不标准时刻感觉都可以。
接下来就来到正题,介绍各个优化器的公式:
BGD (Batch Gradient Descent)
其实这种方式和基于全体样本的梯度计算方式比较类似,或者说是一样的。
将一个 Batch 的数据( m m m 个样本)都考虑进来,我们要更新 w j w_j wj 权重,就对其求 w j w_j wj 的偏导,然后可以得到 ∇ L ( w t , j ) i \nabla L(w_{t,j})_i ∇L(wt,j)i,但是因为这是 m m m 个样本的梯度求和,
所以我们需要求其平均梯度: g t − 1 , j = 1 m ⋅ ∑ i = 1 m ∇ L ( w t − 1 , j ) i g_{t-1, j} = \frac{1}{m}\cdot\sum_{i=1}^m\nabla L(w_{t-1,j})_i gt−1,j=m1⋅i=1∑m∇L(wt−1,j)i权重更新公式可以写成: w t , j = w t − 1 , j − η ⋅ g t − 1 , j w_{t,j}= w_{t-1, j}-\eta \cdot g_{t-1,j} wt,j=wt−1,j−η⋅gt−1,j因为我们所有的权重都是和 w j w_j wj 相关的,所以为了让公式更简洁一点,我们就不必显式的将 j j j 的下标标注出来了,后面的公式都采用一样的操作。
也就是我们的 BGD 的公式可以写成: g t − 1 = 1 m ⋅ ∑ i = 1 m ∇ L ( w t − 1 , j ) i g_{t-1} = \frac{1}{m}\cdot\sum_{i=1}^m\nabla L(w_{t-1,j})_i gt−1=m1⋅i=1∑m∇L(wt−1,j)i w t = w t − 1 − η ⋅ g t − 1 w_{t}= w_{t-1}-\eta \cdot g_{t-1} wt=wt−1−η⋅gt−1
MBGD (Mini-Batch Gradient Descent)
这种方式是 BGD 和 SGD 的一种折中处理方式,采用一个 mini batch.
简单举个例子,采用一个 batchsize 为 k k k 的小样本集,权重系数的更新公式可以写成下面的形式:
梯度和权重更新公式可以表示为: g t − 1 = 1 k ⋅ ∑ i i + k − 1 ∇ L ( w t − 1 , j ) i g_{t-1} = \frac{1}{k}\cdot\sum_{i}^{i+k-1} \nabla L(w_{t-1, j})_i gt−1=k1⋅i∑i+k−1∇L(wt−1,j)i w t = w t − 1 − η ⋅ g t − 1 w_{t} = w_{t-1} - \eta \cdot g_{t-1} wt=wt−1−η⋅gt−1除了梯度计算的样本数变少了,其他是完全一样的。
SGD (Stochastic Gradient Descent)
随机梯度下降,这个就不需要考虑全体样本了,因为全体样本毕竟还是耗时耗力,只要随机抽取一个样本 i i i 来计算梯度就可以了: g t − 1 = ∇ L ( w t − 1 , j ) i g_{t-1} = \nabla L(w_{t-1, j})_i gt−1=∇L(wt−1,j)i w t = w t − 1 − η ⋅ g t − 1 w_{t} = w_{t-1} - \eta \cdot g_{t-1} wt=wt−1−η⋅gt−1只这种情况是最简单的了。
SGDM (Stochastic Gradient Descent with Momentum)
在随机梯度下降的基础上,加上一阶动量。
梯度: g t − 1 = ∇ L ( w t − 1 , j ) i g_{t-1}=\nabla L(w_{t-1, j})_i gt−1=∇L(wt−1,j)i一阶动量系数更新: v t = λ ⋅ v t − 1 + ( 1 − λ ) ⋅ g t − 1 v_{t}= \lambda \cdot v_{t-1} + (1-\lambda)\cdot g_{t-1} vt=λ⋅vt−1+(1−λ)⋅gt−1权重系数更新: w t = w t − 1 − η ⋅ v t w_{t}= w_{t-1} - \eta \cdot v_{t} wt=wt−1−η⋅vt
Adagrad
这里的梯度可以写成 g t − 1 = ∇ L ( w t − 1 , j ) i g_{t-1}=\nabla L(w_{t-1, j})_i gt−1=∇L(wt−1,j)i权重系数更新: w t = w t − 1 − η ⋅ 1 ∑ i = 0 t − 1 g i 2 + ϵ ⋅ g t − 1 w_{t} = w_{t-1} - \eta \cdot \frac{1}{\sqrt{\sum_{i=0}^{t-1}g_i^2} +\epsilon} \cdot g_{t-1} wt=wt−1−η⋅∑i=0t−1gi2+ϵ1⋅gt−1注意:这里面求和的 i i i 并不是指样本 i i i,只是对之前所有时间 t − 1 t-1 t−1 求和的一个表示。
RMSProp
和 Adagrad 基本类似,只是加入了迭代衰减(二阶动量)
梯度: g t − 1 = ∇ L ( w t − 1 , j ) i g_{t-1} = \nabla L(w_{t-1,j})_i gt−1=∇L(wt−1,j)i二阶动量参数(其中 q 0 = g 0 2 q_0 = g_0^2 q0=g02 ): q t = α ⋅ q t − 1 + ( 1 − α ) ⋅ g t − 1 2 q_{t} = \alpha \cdot q_{t-1} + (1-\alpha)\cdot\ g_{t-1}^2 qt=α⋅qt−1+(1−α)⋅ gt−12权重系数: w t = w t − 1 − η ⋅ 1 q t + ϵ ⋅ g t − 1 w_{t} = w_{t-1} - \eta \cdot \frac{1}{\sqrt{q_t}+\epsilon} \cdot g_{t-1} wt=wt−1−η⋅qt+ϵ1⋅gt−1
Adam
这里我为 Adam 选择计算梯度的方式是随机小批量,也就是类似 MBGD 的方式,但是实际上,Adam 可以根据数据集的特点自己选择全量样本,随机样本或者随机小批量来进行梯度计算:
g
t
−
1
=
1
k
∑
i
i
+
k
−
1
∇
L
(
w
t
−
1
,
j
)
i
g_{t-1} = \frac{1}{k}\sum_i^{i+k-1}\nabla L(w_{t-1,j})_i
gt−1=k1i∑i+k−1∇L(wt−1,j)i累计平方梯度(二阶动量,和 RMSProp 类似):
q
t
=
α
⋅
q
t
−
1
+
(
1
−
α
)
⋅
g
t
−
1
2
q_{t} = \alpha \cdot q_{t-1} + (1-\alpha)\cdot g_{t-1}^2
qt=α⋅qt−1+(1−α)⋅gt−12累计梯度(一阶动量,和 SGDM 类似):
v
t
=
λ
⋅
v
t
−
1
+
(
1
−
λ
)
⋅
g
t
−
1
v_{t} = \lambda \cdot v_{t-1} + (1-\lambda)\cdot g_{t-1}
vt=λ⋅vt−1+(1−λ)⋅gt−1修正偏差:
v
~
t
=
v
t
1
−
λ
t
,
q
~
t
=
q
t
1
−
α
t
\tilde{v}_{t} = \frac{v_{t}}{1-\lambda^{t}}, \space\space\space\space\space\space \tilde{q}_t=\frac{q_{t}}{1-\alpha^{t}}
v~t=1−λtvt, q~t=1−αtqt这里的
λ
\lambda
λ 和
α
\alpha
α 都是初始设定的固定参数,这里的上标
t
t
t 是求时间
t
t
t 次方。
权重系数更新的公式为: w t = w t − 1 − η ⋅ 1 q ~ t + ϵ ⋅ v ~ t w_{t} = w_{t-1} - \eta \cdot \frac{1}{\sqrt{\tilde{q}_{t}}+\epsilon}\cdot \tilde{v}_{t} wt=wt−1−η⋅q~t+ϵ1⋅v~t这里的 ϵ \epsilon ϵ 是一个非常小的值,为了是防止分母为 0。