PyTorch与动态学习率应用-附有代码

坚持写博客,分享自己的在学习、工作中的所得

  1. 给自己做备忘
  2. 对知识点记录、总结,加深理解
  3. 给有需要的人一些帮助,少踩一个坑,多走几步路

尽量以合适的方式排版,图文兼有
如果写的有误,或者有不理解的,均可在评论区留言
如果内容对你有帮助,欢迎点赞 👍 收藏 ⭐留言 📝。
虽然平台并不会有任何奖励,但是我会很开心,可以让我保持写博客的热情


TORCH.OPTIM

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),其中var1var2应该定义为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

optimization step

所有优化器都实现了一个step()更新参数的方法。

一旦使用backward()计算出梯度,就可以调用该函数。

loss.backward()
optimizer.step()

基类torch.optim.Optimizer

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的梯度执行步骤,而在另一种情况下,它完全跳过步骤)。

算法

SGD
torch.optim.SGD(params, lr=<required parameter>, momentum=0, dampening=0, weight_decay=0, nesterov=False)
Adam
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


如果内容对你有帮助,或者觉得写的不错
🏳️‍🌈欢迎点赞 👍 收藏 ⭐留言 📝
有问题,请在评论区留言

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ayiya_Oese

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值