22.优化器

优化器

当使用损失函数时,可以调用损失函数的 backward,得到反向传播,反向传播可以求出每个需要调节的参数对应的梯度,有了梯度就可以利用优化器,优化器根据梯度对参数进行调整,以达到整体误差降低的目的。

网站 : torch.optim — PyTorch 1.10 documentation

1.如何使用优化器?

(1)构造

# Example:
# SGD为构造优化器的算法,Stochastic Gradient Descent 随机梯度下降
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)  #模型参数、学习速率、特定优化器算法中需要设定的参数
optimizer = optim.Adam([var1, var2], lr=0.0001)

(2)调用优化器的step方法

利用之前得到的梯度对参数进行更新

for input, target in dataset:
    optimizer.zero_grad() #把上一步训练的每个参数的梯度清零
    output = model(input)
    loss = loss_fn(output, target)  # 输出跟真实的target计算loss
    loss.backward() #调用反向传播得到每个要更新参数的梯度
    optimizer.step() #每个参数根据上一步得到的梯度进行优化

算法

如Adadelta、Adagrad、Adam、RMSProp、SGD等等,不同算法前两个参数:params、lr 都是一致的,后面的参数不同

CLASS torch.optim.Adadelta(params, lr=1.0, rho=0.9, eps=1e-06, weight_decay=0)
# params为模型的参数、lr为学习速率(learning rate)
# 后续参数都是特定算法中需要设置的

学习速率不能太大(太大模型训练不稳定)也不能太小(太小模型训练慢),一般建议先采用较大学习速率,后采用较小学习速率

SGD为例

以 **SGD(随机梯度下降法)**为例进行说明:

import torch
import torchvision.datasets
from torch import nn
from torch.nn import Conv2d, MaxPool2d, Flatten, Linear, Sequential
from torch.utils.data import DataLoader
 
# 加载数据集并转为tensor数据类型
dataset = torchvision.datasets.CIFAR10("./dataset",train=False,transform=torchvision.transforms.ToTensor(),download=True)
# 加载数据集
dataloader = DataLoader(dataset,batch_size=1)
 
# 创建网络名叫Tudui
class Tudui(nn.Module):
    def __init__(self):
        super(Tudui, 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为input,forward前向传播
        x = self.model1(x)
        return x
 
# 计算loss
loss = nn.CrossEntropyLoss()
 
# 搭建网络
tudui = Tudui()
 
# 设置优化器
optim = torch.optim.SGD(tudui.parameters(),lr=0.01)  # SGD随机梯度下降法,我们上面搭建出来的模型就叫tudui,所以parameters就是tudui.parameters()
 
for data in dataloader:
    imgs,targets = data  # imgs为输入,放入神经网络中
    outputs = tudui(imgs)  # outputs为输入通过神经网络得到的输出,targets为实际输出
    result_loss = loss(outputs,targets)
    optim.zero_grad()  # 把网络模型中每一个可以调节的参数对应梯度设置为0
    result_loss.backward()  # backward反向传播求出每一个节点的梯度,是对result_loss,而不是对loss
    optim.step()  # 对每个参数进行调优

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

可以在以下地方打断点,debug:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

tudui ——> Protected Attributes ——> _modules ——> ‘model1’ ——> Protected Attributes ——> _modules ——> ‘0’ ——> weight ——> data 或 grad

通过每次按箭头所指的按钮(点一次运行一行),观察 data 和 grad 值的变化

  • 第一行 optim.zero_grad() 是让grad清零

  • 第三行 optim.step() 会通过grad更新data

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

完整代码

在 data 循环外又套一层 epoch 循环,一次 data 循环相当于对数据训练一次,加了 epoch 循环相当于对数据训练 20 次

import torch
import torchvision.datasets
from torch import nn
from torch.nn import Conv2d, MaxPool2d, Flatten, Linear, Sequential
from torch.utils.data import DataLoader
 
# 加载数据集并转为tensor数据类型
dataset = torchvision.datasets.CIFAR10("./dataset",train=False,transform=torchvision.transforms.ToTensor(),download=True)
dataloader = DataLoader(dataset,batch_size=1)
 
# 创建网络名叫Tudui
class Tudui(nn.Module):
    def __init__(self):
        super(Tudui, 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为input,forward前向传播
        x = self.model1(x)
        return x
 
# 计算loss
loss = nn.CrossEntropyLoss()
 
# 搭建网络
tudui = Tudui()
 
# 设置优化器
optim = torch.optim.SGD(tudui.parameters(),lr=0.01)  # SGD随机梯度下降法,我们上面搭建出来的模型就叫tudui,所以parameters就是tudui.parameters()
for epoch in range(20):
    running_loss = 0.0  # 在每一轮开始前将loss设置为0
    for data in dataloader:  # 该循环相当于只对数据进行了一轮学习
        imgs,targets = data  # imgs为输入,放入神经网络中
        outputs = tudui(imgs)  # outputs为输入通过神经网络得到的输出,targets为实际输出
        result_loss = loss(outputs,targets)
        optim.zero_grad()  # 把网络模型中每一个可以调节的参数对应梯度设置为0
        result_loss.backward()  # backward反向传播求出每一个节点的梯度,是对result_loss,而不是对loss
        optim.step()  # 对每个参数进行调优
        running_loss = running_loss + result_loss  # 每一轮所有loss的和
    print(running_loss)

部分运行结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

优化器对模型参数不断进行优化,每一轮的 loss 在不断减小

实际过程中模型在整个数据集上的训练次数(即最外层的循环)都是成百上千/万的,本例仅以 20 次为例。

print(running_loss)

部分运行结果:

[外链图片转存中...(img-lfoM0bJi-1724861918306)]

优化器对模型参数不断进行优化,每一轮的 loss 在不断减小

实际过程中模型在整个数据集上的训练次数(即最外层的循环)都是成百上千/万的,本例仅以 20 次为例。

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值