导读
看到这个问题的时候,可能你会很直观的认为是等价的
,其实等不等价这个应该取决于在更新参数时所选择的优化算法
。
因为无论是缩放loss
还是learning rate
最终的影响都是对更新参数时偏移量(
Δ
\Delta
Δ)的影响,而不同的优化算法会导致这个偏移量存在差别,下面我们来讨论一下不同优化算法之间的差别。
SGD
梯度下降优化算法,也是最常见的一种优化算法,公式如下:
θ
=
θ
−
η
∗
Δ
θ
J
(
θ
)
\theta = \theta - \eta * \Delta_{\theta}J(\theta)
θ=θ−η∗ΔθJ(θ)
- η \eta η:学习率
- Δ θ J ( θ ) \Delta_{\theta}J(\theta) ΔθJ(θ):loss对参数的一阶偏导,所以当我们对loss的尺度进行缩放的时候实际最终都会反应到梯度上面
结论
:通过上面的公式不难看出,当loss乘以s时其实就等价于偏导
Δ
θ
J
(
θ
)
\Delta_{\theta}J(\theta)
ΔθJ(θ)数乘以s,也就等价与学习率
η
\eta
η乘以s。所以对于SGD而言,loss乘以s等价于learning rate乘以s
。下面我们可以用代码来证明一下
import torch
from torch import nn
#保证每次产生的随机数(输入和输出都相同)
torch.manual_seed(28)
class ExampleModel(nn.Module):
"""定义一个简单的神经网络
"""
def __init__(self):
super(ExampleModel, self).__init__()
self.linear_model = nn.Sequential(
nn.Linear(10,10),
nn.ReLU(),
nn.Linear(10,1),
nn.Sigmoid()
)
def forward(self,x):
return self.linear_model(x**3+x**2+x)
def print_weight_info(input,label,model,opt,loss_scale):
"""输出网络的参数信息
:param input: 输入
:param label: 输出
:param model: 模型
:param opt: 优化器
:param loss_scale: loss变化的尺度
:return:
"""
output = model(input)
loss = (label - output) * loss_scale
opt.zero_grad()
loss.backward()
opt.step()
print(model.linear_model[0].weight)
model = ExampleModel()
input1 = torch.rand(1,10)
label1 = torch.rand(1,)
lr = 0.01
lr_sgd_opt = torch.optim.SGD(model.parameters(),lr=lr)
#lr设置为0.01,loss的尺度扩大10倍
print_weight_info(input1,label1,model,lr_sgd_opt,10)
#lr设置为0.01*10扩大10倍,loss的尺度不做处理
#lr_scale_sgd_opt = torch.optim.SGD(model.parameters(),lr=lr*10)
#print_weight_info(input1,label1,model,lr_scale_sgd_opt,1)
Momentum SGD
Momentum SGD
是基于SGD
的基础上做了修改,为了解决海森矩阵的不良条件数
和随机梯度的方差问题
导致训练模型时进入到局部极小值问题而改进的。Momentum SGD
梯度的更新过程如下所示:
θ
=
θ
−
v
t
v
t
=
γ
∗
v
t
−
1
+
η
∗
Δ
θ
J
(
θ
)
\begin{aligned} \theta &= \theta - v_t \\ v_t &= \gamma * v_{t-1} + \eta * \Delta_{\theta}J(\theta) \end{aligned}
θvt=θ−vt=γ∗vt−1+η∗ΔθJ(θ)
- γ \gamma γ:动量参数,一般取0.5、0.9和0.99
- v t v_t vt :t时刻的梯度
结论
:通过上面的公式不难看出,对于Momentum SGD
来说和SGD
一样,loss乘以s等价于learning rate乘以s
。证明代码如下:
import torch
from torch import nn
#保证每次产生的随机数(输入和输出都相同)
torch.manual_seed(28)
class ExampleModel(nn.Module):
"""定义一个简单的神经网络
"""
def __init__(self):
super(ExampleModel, self).__init__()
self.linear_model = nn.Sequential(
nn.Linear(10,10),
nn.ReLU(),
nn.Linear(10,1),
nn.Sigmoid()
)
def forward(self,x):
return self.linear_model(x**3+x**2+x)
def print_weight_info(input,label,model,opt,loss_scale):
"""输出网络的参数信息
:param input: 输入
:param label: 输出
:param model: 模型
:param opt: 优化器
:param loss_scale: loss变化的尺度
:return:
"""
output = model(input)
loss = (label - output) * loss_scale
opt.zero_grad()
loss.backward()
opt.step()
print(model.linear_model[0].weight)
model = ExampleModel()
input1 = torch.rand(1,10)
label1 = torch.rand(1,)
lr = 0.01
#设置momentum SGD的动量为0.9
momentum = 0.9
lr_mom_sgd_opt = torch.optim.SGD(model.parameters(),lr=lr,momentum=momentum)
#lr设置为0.01,loss的尺度扩大10倍
print_weight_info(input1,label1,model,lr_mom_sgd_opt,10)
#lr设置为0.01*10扩大10倍,loss的尺度不做处理
# lr_mom_sgd_opt = torch.optim.SGD(model.parameters(),lr=lr*10,momentum=momentum)
# print_weight_info(input1,label1,model,lr_mom_sgd_opt,1)
Adagrad
Adagrad
能够自适应的调整不同参数的学习率,根据参数的历史所有梯度平方值总和的平方根来调整学习率的缩放比例,使得稀疏的特征得到大的学习率更新,对于非稀疏的特征得到较小的学习更新
,所以该算法适合处理稀疏特征的数据。参数的更新公式如下:
g
t
,
i
=
Δ
θ
J
(
θ
i
)
θ
t
+
1
,
i
=
θ
t
,
i
−
η
G
t
,
i
i
+
ϵ
∗
g
t
,
i
\begin{aligned} g_{t,i} &= \Delta_{\theta}J(\theta_i) \\ \theta_{t+1,i} &= \theta_{t,i} - \frac{\eta}{\sqrt{G_{t,ii} + \epsilon}} * g_{t,i} \end{aligned}
gt,iθt+1,i=ΔθJ(θi)=θt,i−Gt,ii+ϵη∗gt,i
- g t , i g_{t,i} gt,i: t t t时刻参数 θ i \theta_{i} θi的梯度
- θ t \theta_{t} θt: t t t时刻参数 θ \theta θ的值
- G t , i i G_{t,ii} Gt,ii: G t G_{t} Gt是一个对角矩阵,第 i i i行元素 e i i e_{ii} eii表示的是过去到现在第 i i i个参数 θ i \theta_i θi的梯度的平方和
- ϵ \epsilon ϵ:通常取 e − 8 e^{-8} e−8,用来避免分母为零的情况
接下来我们来讨论,对loss和learning rate乘以s对参数
θ
\theta
θ的更新会有什么影响,先讨论对loss乘以s
θ
t
+
1
,
i
=
θ
t
,
i
−
η
G
t
,
i
i
∗
s
2
+
ϵ
∗
g
t
,
i
∗
s
=
θ
t
,
i
−
η
G
t
,
i
i
+
ϵ
/
s
∗
g
t
,
i
\theta_{t+1,i} = \theta_{t,i} - \frac{\eta}{\sqrt{G_{t,ii} * s^2} + \epsilon} * g_{t,i} * s = \theta_{t,i} - \frac{\eta}{\sqrt{G_{t,ii}} + \epsilon / s} * g_{t,i}
θt+1,i=θt,i−Gt,ii∗s2+ϵη∗gt,i∗s=θt,i−Gt,ii+ϵ/sη∗gt,i
因为
ϵ
\epsilon
ϵ是极小值,所以我们可以忽略它的影响。通过上式就能够说明,当使用Adagrad
优化算法时,乘以s对于参数的更新没有影响。而对于learning rate而言,它会使得参数更新的更快(s大于1)或更慢(s小于1),所以使用Adagrad优化算法的时候,loss乘以s不等价于learning rate乘以s
证明的代码如下:
input1 = torch.rand(1,10)
label1 = torch.rand(1,)
lr = 0.01
# lr_opt = torch.optim.Adagrad(model.parameters(),lr=lr)
#lr设置为0.01,loss的尺度不变
# print_weight_info(input1,label1,model,lr_opt,1)
#loss的尺度扩大10倍
# print_weight_info(input1,label1,model,lr_opt,10)
#lr设置为0.01*10扩大10倍,loss的尺度不做处理
lr_opt = torch.optim.Adagrad(model.parameters(),lr=lr*10)
print_weight_info(input1,label1,model,lr_opt,1)
RMSProp
RMSProp
针对梯度平方和累积的越来越大的问题,而采用了历史梯度平方衰减平均值来代替梯度的平方和。动态的梯度平均值
E
[
g
2
]
t
E[g^2]_t
E[g2]t取决于当前时刻以及上一时刻的平均值,计算公式如下
E
[
g
2
]
t
=
γ
∗
E
[
g
2
]
t
−
1
+
(
1
−
γ
)
∗
g
t
2
θ
t
+
1
=
θ
t
−
η
E
[
g
2
]
t
+
δ
∗
g
t
,
i
\begin{aligned} E[g^2]_t &= \gamma * E[g^2]_{t-1} + (1-\gamma) * g_t^2 \\ \theta_{t+1} &= \theta_t - \frac{\eta}{\sqrt{E[g^2]_t}+\delta} * g_{t,i} \end{aligned}
E[g2]tθt+1=γ∗E[g2]t−1+(1−γ)∗gt2=θt−E[g2]t+δη∗gt,i
不难看出RMSProp
其实和Adagrad
的计算公式差不多,所以对于RMSProp
而言loss乘以s不等价于learning rate乘以s
。
Adam
Adam
:Adaptive Momnet Estimation,与Adagrad
和RMSProp
的区别在于计算历史梯度衰减的方法不同。Adam没有使用梯度的平方衰减,而是采用了类似于动量的梯度衰减,计算公式如下:
v
t
=
β
1
v
t
−
1
+
(
1
−
β
1
)
g
t
u
t
=
β
2
u
t
−
1
+
(
1
−
β
2
)
g
t
2
v
t
~
=
v
t
1
−
β
1
t
u
t
~
=
u
t
1
−
β
2
t
θ
t
+
1
=
θ
t
−
η
u
t
~
+
ϵ
v
t
~
\begin{aligned} v_t &= \beta_{1}v_{t-1} + (1-\beta_1)g_t \\ u_t &= \beta_{2}u_{t-1} + (1 - \beta_2)g_t^2\\ \widetilde{v_t} &= \frac{v_t}{1-\beta_1^t}\\ \widetilde{u_t} &= \frac{u_t}{1- \beta_2^t} \\ \theta_{t+1} &= \theta_t - \frac{\eta}{\sqrt{\widetilde{u_t}}+\epsilon}\widetilde{v_t} \end{aligned}
vtutvt
ut
θt+1=β1vt−1+(1−β1)gt=β2ut−1+(1−β2)gt2=1−β1tvt=1−β2tut=θt−ut
+ϵηvt
v
t
v_t
vt:梯度的一阶估计
u
t
u_t
ut:梯度的二阶估计
v
t
~
\widetilde{v_t}
vt
:梯度一阶估计的偏差修正
u
t
~
\widetilde{u_t}
ut
:梯度二阶估计的偏差修正
β
1
\beta_1
β1通常取0.9,
β
2
\beta_2
β2通常取0.999
转换一下公式可以发现,对于Adam
来说,loss乘以s不等价于learning rate乘以s
。
总结
我们通过理论公式的推导以及实践的代码证明,最终发现对loss或learning rate乘以缩放尺度参数s是否等价
,主要取决于优化器的选择。对于SGD
和Moment SGD
来说,loss乘以s等价于learning rate乘以s
,而对于Adagrad
、RMSProp
和Adam
来说loss乘以s不等价于learning rate乘以s
。
注意
:上面在讨论loss与learning rate乘以s之间的关系时,我们并不考虑weight decay
的影响。