参考资料:
一、优化器
PyTorch常用的优化方法都封装在torch. optim里面,其设计很灵活,可以扩展为自定义的优化方法。所有的优化方法都是继承了基类optim.Optimizer,并实现了自己的优化步骤。最常用的优化算法就是梯度下降法及其各种变种,后续章节我们将介绍各种算法的原理,这类优化算法通过使用参数的梯度值更新参数。
说明使用优化器的一-般步骤为:
(1) 建立优化器实例
导入optim模块,实例化SGD优化器,这里使用动量参数momentum (该值一般在(0,1) 之间),是SGD的改进版,效果一般比不使用动量规则的要好.
import torch.optim as optim
optimizer = optim.SGD(model.parameters(), lr=lr, momentum=momentum)
以下步骤在训练模型的for循环中
(2)向前传播
把输入数据传入神经网络Net实例化对象model中,自动执行forward函数,得到out输出值,然后用out与标记label计算损失值loss.
out=model(img)
loss=criterion(out,label)
(3)清空梯度
缺省情况梯度是累加的,在梯反向传播前,先需要把梯度清零.
optimizer.zero_grad()
(4)反向传播
基于损失值,把梯度进行反向传播.
loss.backward()
(5)更新参数
基于当前梯度(存储在参数的.grad属性中)更新参数
optimizer.step()
二、动态修改学习率参数
修改参数的方式可以通过修改参数optimizer. params_ groups或新建optimizer。 新建optimizer比较简单,optimizer十分轻量级, 所以开销很小。但是新的优化器会初始化动量等状态信息,这对于使用动量的优化器(momentum参数的sgd)可能会造成收敛中的震荡。所以,这里直接采用修改参数optimizer.params_ groups。
optimizer.param_ groups
: 长度1的list,
optimizer.param_ groups[0]
: 长度为6的字典,包括权重参数、Ir、 momentum等参数。
len(optimizer.param_groups[0])#结果为6
动态修改学习率参数
for epoch in range(num_epoches):
# 动态修改参数学习率
if epoch%5 == 0:
optimizer.param_groups[0][lr] *= 0.1
print(optimizer.param_groups[O]['lr'])
for img, label in train_loader:####
三、优化器比较
PyTorch中的优化器很多,各种优化器一-般都有 其适应的场景,不过,像自适应优化器在深度学习中比较受欢迎,除了性能较好,鲁棒性、泛化能力也更强。这里通过一个简单实例进行说明。
1)导入需要的模块。
import torch
import torch.utils.data as Data
import torch.nn.functional as F
import matplotlib. pyplot as plt
%matplotlib inline
#超参数
LR = 0.01
BATCH_SIZE = 32
EPOCH= 12
2)生成数据。
#生成训练数据
# torch.unsqueeze()的作用是将一维变二 维,torch只能处理二 维的数据
x = torch.unsqueeze(torch.linspace(-1, 1, 1000), dim=1)
# 0.1 * torch.normal(x.size()增加噪点
y = x.pow(2) + 0.1 * torch.normal(torch.zeros(*x.size()))
torch_dataset = Data.TensorDataset(x,y)
#得 到一个代批量的生成器
loader = Data.DataLoader(dataset=torch_dataset,batch_size=BATCH_SIZE, shuffle=True)
3)构建神经网络。
class Net(torch.nn.Module):
# 初始化
def __init__(self):
super(Net, self).__init__()
self.hidden = torch.nn.Linear(1, 20)
self.predict = torch.nn.Linear(20, 1) # 前向传递
def forward(self, x):
x = F.relu(self.hidden(x))
x = self.predict(x)
return x
4)使用多种优化器。
net_SGD = Net()
net_Momentum = Net()
net_RMSProp = Net()
net_Adam = Net()
nets = [net_SGD, net_Momentum, net_RMSProp, net_Adam]
opt_SGD =torch.optim.SGD(net_SGD.parameters(), lr=LR)
opt_Momentum = torch.optim.SGD(net_Momentum.parameters(),lr=LR, momentum=0.9)
opt_RMSProp =torch.optim.RMSprop(net_RMSProp.parameters(), lr=LR, alpha=0.9)
opt_Adam = torch.optim.Adam(net_Adam.parameters(), lr=LR, betas=(0.9, 0.99))
optimizers = [opt_SGD, opt_Momentum, opt_RMSProp, opt_Adam]
5)训练模型。
loss_func = torch.nn.MSELoss()
loss_his= [[],[],[], []]
#记录损失
for epoch in range(EPOCH):
for step, (batch_x, batch_y) in enumerate(loader):
for net, opt,l_his in zip(nets,optimizers, loss_his):
output = net(batch_x) # get output for every net
loss = loss_func(output, batch_y) # compute loss for every net
opt.zero_grad() # clear gradients for next train
loss.backward() # backpropagation, compute gradients
opt.step() # apply gradients
l_his.append(loss.data.numpy()) # loss recoder
labels= ['SGD', 'Momentum', 'RMSprop', 'Adam']
- 可视化结果。
for i,l_loss in enumerate(loss_his):
plt.plot(l_his,label=labels[i])
plt.legend(loc="best")
plt.xlabel("Steps")
plt.ylabel("Loss")
plt.ylim((0,0.2))
plt.show()