学习率对梯度下降的影响分析
梯度下降的优化算法-动量算法MOmentum 梯度计算公式: s_t=βs_t−1 + (1−β)g_t 参数更新公式: w_t= …
梯度下降的优化算法-动量算法MOmentum
梯度计算公式:
s_t=βs_t−1 + (1−β)g_t
参数更新公式:
w_t=w_t−1 − ηs_t
s_t是当前时刻指数加权平均梯度值
s_t-1是历史指数加权平均梯度值
g_t是当前时刻的梯度值
β 是调节权重系数,通常取 0.9 或 0.99
η是学习率
w_t是当前时刻模型权重参数

import torch
import torch.nn as nn
#todo:St = β * St-1 +(1-β) * Gt
def dm01_momentum():
#1:初始化权重参数
w = torch.tensor([1.0],requires_grad=True,dtype=torch.float)
#2:定义损失函数
criterion = ((w**2)/2.0).sum()
#3:定义优化器
#参1:优化的参数 参2:学习率 参3:动量参数
optimizer = torch.optim.SGD([w],lr=0.01,momentum=0.9) #细节:momentum=0时,只考虑本次梯度
#4:计算梯度值:梯度清零+反向传播+参数更新
optimizer.zero_grad()
criterion.backward()
optimizer.step()
print(f'w:{w},w.grad:{w.grad}')
#5:重复步骤,第二次,更新权重参数
criterion = ((w**2)/2.0).sum()
optimizer.zero_grad()
criterion.backward()
optimizer.step()
print(f'w:{w},w.grad:{w.grad}')
if __name__ == '__main__':
dm01_momentum()

梯度下降的优化方法——adaGrad

def dm02_adagrad():
# 1:初始化权重参数
w = torch.tensor([1.0], requires_grad=True, dtype=torch.float)
# 2:定义损失函数
criterion = ((w**2) / 2.0).sum()
# 3:定义优化器
# 参1:优化的参数 参2:学习率 参3:动量参数
#思路1:基于SGD,加入参数momentum就是动量法
# optimizer = torch.optim.SGD([w], lr=0.01, momentum=0.9) # 细节:momentum=0时,只考虑本次梯度
#思路2:基于Adagrad(自适应学习率)
optimizer = torch.optim.Adagrad(params=[w], lr=0.01)
# 4:计算梯度值:梯度清零+反向传播+参数更新
optimizer.zero_grad()
criterion.backward()
optimizer.step()
print(f"w:{w},w.grad:{w.grad}")
# 5:重复步骤,第二次,更新权重参数
criterion = ((w**2) / 2.0).sum()
optimizer.zero_grad()
criterion.backward()
optimizer.step()
print(f"w:{w},w.grad:{w.grad}")
梯度下降的优化方法RMSProp

def dm03_rmsprop():
# 1:初始化权重参数
w = torch.tensor([1.0], requires_grad=True, dtype=torch.float)
# 2:定义损失函数
criterion = ((w**2) / 2.0).sum()
# 3:定义优化器
# 参1:优化的参数 参2:学习率 参3:动量参数
#思路1:基于SGD,加入参数momentum就是动量法
# optimizer = torch.optim.SGD([w], lr=0.01, momentum=0.9) # 细节:momentum=0时,只考虑本次梯度
#思路2:基于Adagrad(自适应学习率)
# optimizer = torch.optim.Adagrad(params=[w], lr=0.01)
#思路3:基于RMSprop(自适应学习率)
optimizer = torch.optim.RMSprop(params=[w], lr=0.01,alpha=0.99)
# 4:计算梯度值:梯度清零+反向传播+参数更新
optimizer.zero_grad()
criterion.backward()
optimizer.step()
print(f"w:{w},w.grad:{w.grad}")
# 5:重复步骤,第二次,更新权重参数
criterion = ((w**2) / 2.0).sum()
optimizer.zero_grad()
criterion.backward()
optimizer.step()
print(f"w:{w},w.grad:{w.grad}")
三种算法的比较

总结:momentum更新梯度,adagrad和RMSprop更新学习率
梯度下降的优化方法Adam


momentum和adam用的最多
学习率衰减优化方法
学习率对梯度的影响
import torch
import matplotlib.pyplot as plt
x看成是权重,y看成是loss,下面通过代码来理解学习率的作用
def func(x_t):
return torch.pow(2*x_t, 2) # y = 4 x ^2
采用较小的学习率,梯度下降的速度慢
采用较大的学习率,梯度下降太快越过了最小值点,导致不收敛,甚至震荡
def dm01():
x = torch.tensor([2.], requires_grad=True)
# 记录loss迭代次数,画曲线
iter_rec, loss_rec, x_rec = list(), list(), list()
# 实验学习率: 0.01 0.02 0.03 0.1 0.2 0.3 0.4
# lr = 0.1 # 正常的梯度下降
# lr = 0.125 # 当学习率设置0.125 一下子求出一个最优解
# x=0 y=0 在x=0处梯度等于0 x的值x=x-lr*x.grad就不用更新了
# 后续再多少次迭代 都固定在最优点
lr = 0.2 # x从2.0一下子跨过0点,到了左侧负数区域
# lr = 0.3 # 梯度越来越大 梯度爆炸
max_iteration = 4
for i in range(max_iteration):
y = func(x) # 得出loss值
y.backward() # 计算x的梯度
print("Iter:{}, X:{:8}, X.grad:{:8}, loss:{:10}".format(
i, x.detach().numpy()[0], x.grad.detach().numpy()[0], y.item()))
x_rec.append(x.item()) # 梯度下降点 列表
# 更新参数
x.data.sub_(lr * x.grad) # x = x - x.grad
x.grad.zero_()
iter_rec.append(i) # 迭代次数 列表
loss_rec.append(y.item()) # 损失值 列表,这里将y改为y.item()以获取标量值
# 迭代次数-损失值 关系图
plt.subplot(121).plot(iter_rec, loss_rec, '-ro')
plt.grid()
plt.xlabel("Iteration X")
plt.ylabel("Loss value Y")
# 函数曲线-下降轨迹 显示图
x_t = torch.linspace(-3, 3, 100)
y = func(x_t)
plt.subplot(122).plot(x_t.detach().numpy(), y.detach().numpy(), label="y = 4*x^2")
y_rec = [func(torch.tensor(i)).item() for i in x_rec]
print('x_rec--->', x_rec)
print('y_rec--->', y_rec)
# 指定线的颜色和样式(-ro:红色圆圈,b-:蓝色实线等)
plt.subplot(122).plot(x_rec, y_rec, '-ro')
plt.grid()
plt.legend()
plt.show()
dm01()
运行效果图如下:
可以看出:采用较小的学习率,梯度下降的速度慢;采用较大的学习率,梯度下降太快越过了最小值点,导致震荡,甚至不收敛(梯度爆炸)。

等间隔学习率衰减

import torch
import matplotlib.pyplot as plt
from torch import optim
def dm01():
lr = 0.1
epochs = 200
iteration = 10
y_ture = torch.tensor([0])
x = torch.tensor([1.0],dtype=torch.float32)
w = torch.tensor([1.0],dtype=torch.float32,requires_grad=True)
optimizer = optim.SGD([w],lr=lr,momentum=0.9)
scheduler = optim.lr_scheduler.StepLR(optimizer,step_size=50,gamma=0.5)
lr_list,epoch_list = [],[]
for epoch in range(epochs):
epoch_list.append(epoch)
lr_list.append(scheduler.get_last_lr())
for batch in range(iteration):
y_pred = w*x
loss = (y_pred - y_ture)**2
optimizer.zero_grad()
loss.backward()
optimizer.step()
scheduler.step()
print(f'lr_list:{lr_list}')
plt.plot(epoch_list,lr_list)
plt.xlabel('epoch')
plt.ylabel('lr')
# plt.legend()
plt.show()
if __name__ == '__main__':
dm01()

指定间隔学习率衰减
只需修改一行代码
# scheduler = optim.lr_scheduler.StepLR(optimizer,step_size=50,gamma=0.5)
scheduler = optim.lr_scheduler.MultiStepLR(optimizer,milestones=[50,125,160],gamma=0.5)

指数间隔学习率衰减

也是修改一行代码即可
# scheduler = optim.lr_scheduler.StepLR(optimizer,step_size=50,gamma=0.5)
# scheduler = optim.lr_scheduler.MultiStepLR(optimizer,milestones=[50,125,160],gamma=0.5)
scheduler = optim.lr_scheduler.ExponentialLR(optimizer,gamma=0.95)

正则化-dropout
隐藏层失活

def dm01():
t1 = torch.randint(0,10,(1,4)).float()
# print(t1)
linear1 = nn.Linear(4,5)
l1 = linear1(t1)
print(f'l1:{l1}')
output = torch.relu(l1)
print(f'output:{output}')
dropout = nn.Dropout(p=0.5)
d1 = dropout(output)
print(f'随机失活后的数据:{d1}')

正则化-批量归一化

一般在计算机视觉领域应用较多
import torch
import torch.nn as nn
def dm01():
input_2d = torch.randn(size=(1,2,3,4))
bn2d = nn.BatchNorm2d(num_features=2,eps=1e-5,momentum=0.1,affine=True)
output2d = bn2d(input_2d)
print(f'output2d:{output2d}')
def dm02():
input_1d = torch.randn(size=(2,2))
print(f'input_1d:{input_1d}')
linear1 = nn.linear(in_features=2,out_features=4)
l1 = linear1(input_1d)
print(f'l1:{l1}')
bn1d=nn.batchnorm1d(num_features=2)
output_1d = bn1d(l1)
print(f'output_1d:{output_1d}')
if __name__ == '__main__':
# dm01()
dm02()
