【神经网络】09 - 优化器 torch.optim

发布于:2024-05-09 ⋅ 阅读:(23) ⋅ 点赞:(0)

09 - 优化器 torch.optim

概念

优化器是用于更新和管理模型参数以改进模型性能的一种工具。在机器学习和深度学习中,优化器的主要任务是通过调整模型的参数来最小化或最大化特定的目标函数。在许多情况下,这个目标函数是一个损失函数,我们的目标是将其最小化。

在 PyTorch 中,torch.optim 是一个包含了各种优化算法的模块,用于帮助开发者在训练神经网络时更方便地更新和管理模型参数。

当我们训练神经网络时,我们的目标是找到一组模型参数,可以最小化或最大化某个损失函数或者目标函数。优化算法或者优化器(Optimizer)是用于实现这个过程的工具。

torch.optim 中包括了很多常用的优化算法,如随机梯度下降(SGD)、Adam、Adagrad、RMSprop等。这些优化器通常都会实现一个 step() 方法来更新模型的参数。

一些常用的优化器:

  • 随机梯度下降(SGD):SGD是最基础和最经常使用的优化器之一。它通过计算每一个训练样本或训练批次的损失函数的梯度,并沿着梯度的反方向更新模型参数以最小化损失。
  • Momentum:融入动量的随机梯度下降,意味着在更新参数时,不仅考虑当前的梯度,还会考虑前一次的梯度方向,因此具有“保持动量”并更快速地收敛到最小值的效果。
  • Adagrad, RMSprop, Adam:这些是更高级的优化器,它们可以自动调节学习率——每个参数都有自己的学习率。有的优化器(如Adam)甚至综合了动量和自适应学习率的优点。

关键的通用参数:

  1. params(必须):是一个可迭代的对象,通常你会传入模型的参数,通常可以通过 model.parameters() 获取。这个参数告诉优化器应该更新哪些张量。
为什么 model.parameters() 可以获取 params?

GPT4的回答:

在 PyTorch 中,model.parameters() 方法被用来获取模型中所有可训练的参数。这些参数,例如权重和偏置,是在训练过程中通过优化算法进行更新的值。

首先,我们需要明白,在 PyTorch 中,模型(通常是 nn.Module 的子类)是由一系列的层构成的,而每一层又有它自己的参数。例如,线性层 nn.Linear 有权重和偏置作为参数,卷积层 nn.Conv2d 也有权重和偏置。

在定义模型时,这些层通常被定义为模型的属性。因此,当你调用 model.parameters() 时,PyTorch 会去遍历每一层,并收集所有的参数。

在优化器中,我们需要告诉优化器,应该对哪些张量进行优化(即应用梯度更新)。model.parameters() 提供了一种简便的方式来收集所有这些张量,而无需手动指定。

具体来说,model.parameters() 返回一个生成器,生成包含模型所有参数(权重和偏置)的张量,这些参数就是我们希望优化器能够更新的值。

  1. lr(必须):学习率,它决定了参数更新的步长。学习率太小可能导致训练过程慢而无法收敛,太大可能导致收敛不稳定。

示例

import torch
import torchvision
from torch import nn
from torch.nn import Sequential, Conv2d, MaxPool2d, Flatten, Linear
from torch.utils.data import DataLoader

dataset = torchvision.datasets.CIFAR10(root="./dataset", train=True, download=True,
                                       transform=torchvision.transforms.ToTensor())

dataloader = DataLoader(dataset, batch_size=32)


class MyNet(nn.Module):
    def __init__(self):
        # nn.Module.__init__(self)
        super(MyNet, self).__init__()
        self.model1 = Sequential(
            Conv2d(3, 32, 5, padding=2),
            MaxPool2d(2),
            Conv2d(32, 32, 5, padding=2),
            MaxPool2d(2),
            Conv2d(32, 64, 5, padding=2),
            MaxPool2d(2),
            Flatten(),
            Linear(1024, 64),
            Linear(64, 10)
        )

    def forward(self, x):
        x = self.model1(x)
        return x

# 定义损失函数为交叉熵损失,它通常用于分类任务
loss = nn.CrossEntropyLoss()
net = MyNet()
# 定义优化器为随机梯度下降(SGD),学习率设置为0.01。
# 优化器会更新传入的 net.parameters() 中的参数
optimizer = torch.optim.SGD(net.parameters(), lr=0.01)
for data in dataloader:
    imgs, targets = data
    outputs = net(imgs)
    # 计算此次预测的损失值,预测结果outputs与真实targets的交叉熵损失。
    res_loss = loss(outputs, targets)
    # 清零之前反向传播过程中累积的梯度
    optimizer.zero_grad()
    # 对损失进行反向传播,计算每个参数的梯度
    res_loss.backward()
    # 根据计算得到的梯度更新网络参数,更新步骤由前面定义的优化器optimizer完成
    optimizer.step()

该训练循环在每一个大小为32的批次(batch)上进行了完整的前向传播(获取预测和损失)、反向传播(计算梯度)以及更新权重的操作。这个过程会持续进行,直到遍历完 dataloader 中所有的数据。

这个过程完成一次被称为一个训练周期(epoch)。如果要进行多个训练周期(epoch),可以将这个训练循环放在一个外部循环中,每个训练周期都遍历一次所有的数据。