坚持写博客,分享自己的在学习、工作中的所得
- 给自己做备忘
- 对知识点记录、总结,加深理解
- 给有需要的人一些帮助,少踩一个坑,多走几步路
尽量以合适的方式排版,图文兼有
如果写的有误,或者有不理解的,均可在评论区留言
如果内容对你有帮助,欢迎点赞 收藏 ⭐留言 。
虽然平台并不会有任何奖励,但是我会很开心,可以让我保持写博客的热情
torch.optim是一个实现各种优化算法的包。已经支持大部分常用的方法
要使用torch.optim必须构造一个优化器对象,该对象将保存当前状态并根据计算出的梯度更新参数。
为了构造一个优化器,你必须给它一个包含参数(都应该是Variable s)的可迭代对象来进行优化。然后,您可以指定优化器特定的选项,如学习率、权重衰减等。
注意:如果你需要通过.cuda()将模型移动到GPU,请在为它构建优化器之前这样做。在.cuda()之后的模型参数与调用之前的参数是不同的对象。
通常,在构造和使用优化器时,应该确保优化参数位于一致的位置。
例如:
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)
optimizer = optim.Adam([var1, var2], lr=0.0001)
在上面的optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)
,构造优化器是为整个模型的参数设置相同的学习率;
当需要为每一层指定不同学习率时可以使用optimizer = optim.Adam([var1, var2], lr=0.0001)
,其中var1
,var2
应该定义为dict,并且应该包含一个params
键
optim.Adam([
{'params': model.base.parameters()},
{'params': model.classifier.parameters(), 'lr': 1e-3}
], lr=1e-2)
model.base的参数将使用的默认学习率1e-2, model.classifier的参数将使用 的学习率1e-3
所有优化器都实现了一个step()更新参数的方法。
一旦使用backward()计算出梯度,就可以调用该函数。
loss.backward()
optimizer.step()
torch.optim.Optimizer(params, defaults)是所以优化器的基类
Optimizer基类实现了以下主要方法:
Optimizer.add_param_group(param_group)
:向优化器的param_groups添加一个参数组。这在微调预训练网络时非常有用,把冻结层被设置为可训练,并在训练过程中添加到优化器中。param_group是一个dict
Optimizer.load_state_dict(state_dict)
:加载optimizer state。state_dict是一个dict,应该是调用Optimizer.state_dict()
的返回值
Optimizer.state_dict()
:以字典的形式返回优化器的状态。
Optimizer.step()
:执行单个优化步骤,更新参数。
Optimizer.zero_grad(set_to_none=False)
:将梯度设为0。set_to_none:将梯度值设置为None,而不是设置为0。这通常会有更低的内存占用,并可以适度地提高性能。然而,它改变了某些行为。例如:1。当用户试图访问梯度并对其执行手动操作时,None属性与全0的张量表现不同。2. 如果用户调用zero_grad(set_to_none=True)然后反向传播,则对于没有接收到梯度的参数,.grad保证为None。3.如果梯度为0或None, torch.optim优化器会有不同的行为(在一种情况下,它以0的梯度执行步骤,而在另一种情况下,它完全跳过步骤)。
torch.optim.SGD(params, lr=<required parameter>, momentum=0, dampening=0, weight_decay=0, nesterov=False)
torch.optim.Adam(params, lr=0.001, betas=(0.9, 0.999), eps=1e-08, weight_decay=0, amsgrad=False)
https://pytorch.org/docs/stable/optim.html#algorithms
torch.optim.Lr_scheduler
提供了几种基于epoch数调整学习率的方法。
学习率调度应该在优化器更新之后应用
model = [Parameter(torch.randn(2, 2, requires_grad=True))]
optimizer = SGD(model, 0.1)
scheduler = ExponentialLR(optimizer, gamma=0.9)
for epoch in range(20):
for input, target in dataset:
optimizer.zero_grad()
output = model(input)
loss = loss_fn(output, target)
loss.backward()
optimizer.step()
scheduler.step()
可以使用以下模板来引用调度程序算法:
scheduler = ...
for epoch in range(100):
train(...)
validate(...)
scheduler.step()
注意:在PyTorch 1.1.0之前,学习率调度程序应该在优化器更新之前调用;1.1.0以一种BC-breaking的方式改变了这种行为。如果您在优化器更新(调用optimizer.step())之前使用学习率调度程序(调用scheduler.step()),这将跳过学习率调度程序的第一个值。如果您在升级到PyTorch 1.1.0之后无法复制结果,请检查是否在错误的时间调用了scheduler.step()。
可参考动态调整学习率,更换不同学习率策略。
以下代码在jupter中运行
import torch
import torchvision
from torchvision.datasets import CIFAR10
from torchvision import transforms
from torch import optim
import torch.nn as nn
import torch.nn.functional as F
import numpy as np
import matplotlib.pyplot as plt
检测设备
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
print(device)
数据下载并处理
transform = transforms.Compose(
[transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
batch_size = 4
trainset = CIFAR10(root='./CIFAR10', train=True,
download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=batch_size,
shuffle=True, num_workers=2)
testset = CIFAR10(root='./CIFAR10', train=False,
download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=batch_size,
shuffle=False, num_workers=2)
classes = ('plane', 'car', 'bird', 'cat',
'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
定义网络
class Net(nn.Module):
def __init__(self):
super().__init__()
self.conv1 = nn.Conv2d(3, 6, 5)
self.pool = nn.MaxPool2d(2, 2)
self.conv2 = nn.Conv2d(6, 16, 5)
self.fc1 = nn.Linear(16 * 5 * 5, 120)
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84, 10)
def forward(self, x):
x = self.pool(F.relu(self.conv1(x)))
x = self.pool(F.relu(self.conv2(x)))
x = torch.flatten(x, 1)
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
net = Net()
net.to(device)
定义优化器并训练
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
scheduler = optim.lr_scheduler.ExponentialLR(optimizer, gamma=0.9)
lrs = []
steps = []
for epoch in range(20):
running_loss = 0.0
for i, data in enumerate(trainloader, 0):
inputs, labels = data[0].to(device), data[1].to(device)
# zero the parameter gradients
optimizer.zero_grad()
# forward + backward + optimize
outputs = net(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
running_loss += loss.item()
if i % 2000 == 1999: # print every 2000 mini-batches
print('[%d, %5d] loss: %.3f' %
(epoch + 1, i + 1, running_loss / 2000))
running_loss = 0.0
steps.append(epoch)
lrs.append(scheduler.get_last_lr()[0])
scheduler.step()
print('Finished Training')
可视化学习率
plt.plot(steps, lrs)
plt.xlabel("epoch")
plt.ylabel("lr")
plt.title("learning rate's curve changes as epoch goes on!")
plt.show()
参考:https://pytorch.org/docs/stable/optim.html
如果内容对你有帮助,或者觉得写的不错
️欢迎点赞 收藏 ⭐留言
有问题,请在评论区留言