Samar-blog

导航

P23_ 优化器(一)

23.1打开官网:torch.optim

1.优化器的使用

(1)构造优化器

放入模型参数、学习速率

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

optimizer.zero_grad()一定要写

(3)优化器算法

params:参数,lr:学习速率(learning rate)

23.2代码实战:

1.复制nn_loss_network的代码

(1)前面:

加载数据集dataset,将其转成tensor数据类型,用dataloader进行加载,创建相应的网络,并计算出loss,再搭建了相应的网络:

现在:设置优化器

(2)随机梯度下降SGD

optim = torch.optim.SGD(dyl_seq.parameters(),lr = 0.01)

2.优化器SGD的使用

(1)输入代码
点击查看代码
import torch
import torchvision.transforms
from torch import nn
from torch.nn import Conv2d, MaxPool2d, Flatten, Linear, Sequential

#定义数据集
from torch.utils.data import DataLoader

dataset = torchvision.datasets.CIFAR10("./dataset",train=False,
                                       transform=torchvision.transforms.ToTensor(),download=True)
dataloader = DataLoader(dataset,batch_size=1)

#定义神经网络
class DYL_seq(nn.Module):
    def __init__(self):
        super(DYL_seq, self).__init__()
        self.model1 = Sequential(
            Conv2d(in_channels=3, out_channels=32, kernel_size=5, padding=2),
            MaxPool2d(kernel_size=2),
            Conv2d(32, 32, 5, padding=2),
            MaxPool2d(kernel_size=2),
            Conv2d(32, 64, 5, padding=2),
            MaxPool2d(kernel_size=2),
            Flatten(),
            Linear(1024, 64),
            Linear(64, 10)
        )

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

loss = nn.CrossEntropyLoss()

#创建网络
dyl_seq = DYL_seq()

#创建优化器
optim = torch.optim.SGD(dyl_seq.parameters(),lr = 0.01)

#从dataloader去取数据
for data in dataloader:
    imgs,targets = data
    #再把数据送到网络当中:
    outputs = dyl_seq(imgs)
    #计算出网络的输出和真实的target的差距
    result_loss = loss(outputs,targets)
    #梯度调为0
    optim.zero_grad()
    #反向传播:得到每一个可调节参数的对应的梯度
    result_loss.backward()
    #对每一个参数进行调优
    optim.step()
    print(result_loss)
(2)运行结果
点击查看代码
Files already downloaded and verified
tensor(2.2236, grad_fn=<NllLossBackward0>)
tensor(2.1527, grad_fn=<NllLossBackward0>)
tensor(2.0960, grad_fn=<NllLossBackward0>)
tensor(2.4661, grad_fn=<NllLossBackward0>)
tensor(2.3052, grad_fn=<NllLossBackward0>)
......

运行结果是在每个节点上的loss的变化,但是loss似乎并没有减小:

因为dataloader就是在网络模型对数据只看了一遍,现在看到的数据对于下次看到数据预测的影响不大

解决方法:
对数据进行多轮学习,在for循环外再套一层循环:epoch

3.多轮学习的设置

(1)外层嵌套轮次的for循环
点击查看代码
for epoch in range(20):
    running_loss = 0.0
    #从dataloader去取数据
    for data in dataloader:
        imgs,targets = data
        #再把数据送到网络当中:
        outputs = dyl_seq(imgs)
        #计算出网络的输出和真实的target的差距
        result_loss = loss(outputs,targets)
        #梯度调为0
        optim.zero_grad()
        #反向传播:得到每一个可调节参数的对应的梯度
        result_loss.backward()
        #对每一个参数进行调优
        optim.step()
        running_loss = running_loss + result_loss
    print(running_loss)
(2)整体流程
点击查看代码
对于每一个轮次 (Epoch):
  ①初始化总损失为 0。
  ②对于数据集中的每一个批次 (Batch):
    a. 取出一个批次的图片和标签。
    b. 将图片输入模型,得到模型的预测输出。(前向传播)
    c. 用损失函数计算预测输出和真实标签的差距。
    d. 清空上一次的梯度。
    e. 反向传播,计算出每个参数的梯度。
    f. 根据梯度,更新模型的所有参数。(优化器.step ())
    g. 将这个批次的损失累加到总损失上。
  ③一轮结束后:
    a. 打印出本轮的总损失。
(3)每一轮学习过程中

外层循环:控制训练的轮次

内层循环:遍历整个数据集

①for epoch in range(20):

模型会把整个 CIFAR-10 测试集看 20 遍

【因为只看一遍数据,模型学不会复杂的模式。它需要反复地观察、学习,才能不断调整内部的参数(权重和偏置),从而提高预测的准确率。】

②解包数据:imgs, targets = data

把 data 元组里的两个部分分开,分别赋值给 imgs 和 targets

其中:
imgs: PyTorch 的张量(Tensor),设置其形状是 [1, 3, 32, 32],即 “1 张 3 通道(RGB)的32x32 像素的图片”;
targets:这也是一个张量,形状是 [batch_size]。对于 CIFAR-10,它的值是一个 0 到 9 之间的整数,表示这张图片对应的类别(比如 0 是飞机,1 是汽车等);

③前向传播:outputs = dyl_seq(imgs)
④反向传播
点击查看代码
optim.zero_grad()       # 1. 清空之前的梯度
result_loss.backward()  # 2. 计算梯度
result_loss.backward:它会从损失函数的结果 result_loss 开始,自动计算出模型中每一个可训练参数(权重 W,偏置 b)对损失的梯度(d(Loss)/d(W), d(Loss)/d(b))。 【可以把梯度想象成一个 “指示信号”,它告诉我们:“要想让损失变小,这个参数应该往哪个方向调整,调整多少?”】
⑤参数更新:optim.step()
⑥累加损失:running_loss = running_loss + result_loss

在每一轮(epoch)开始时,我们把变量running_loss初始化为 0;对于每一个批次,我们都把这个批次的损失 result_loss 加到 running_loss 上;
这样,当整个 epoch 结束时,running_loss 就等于这个轮次中所有图片的损失之和。

打印它可以让我们直观地看到,随着训练轮次的增加,模型的总损失是不是在下降,从而判断训练是否有效。

(4)print打印结果
点击查看代码
Files already downloaded and verified
tensor(18790.3555, grad_fn=<AddBackward0>)
tensor(16177.8945, grad_fn=<AddBackward0>)
tensor(15394.5410, grad_fn=<AddBackward0>)
tensor(15897.9082, grad_fn=<AddBackward0>)
tensor(17882.6699, grad_fn=<AddBackward0>)
tensor(20084.4277, grad_fn=<AddBackward0>)
tensor(22518.1348, grad_fn=<AddBackward0>)
tensor(23672.5508, grad_fn=<AddBackward0>)
tensor(24243.7734, grad_fn=<AddBackward0>)
tensor(25187.7676, grad_fn=<AddBackward0>)
tensor(25525.9375, grad_fn=<AddBackward0>)
tensor(26094.1387, grad_fn=<AddBackward0>)
tensor(26918.0039, grad_fn=<AddBackward0>)
tensor(27612.7695, grad_fn=<AddBackward0>)
tensor(29427.4512, grad_fn=<AddBackward0>)
tensor(30726.7402, grad_fn=<AddBackward0>)
tensor(nan, grad_fn=<AddBackward0>)
tensor(nan, grad_fn=<AddBackward0>)
tensor(nan, grad_fn=<AddBackward0>)
tensor(nan, grad_fn=<AddBackward0>)

进程已结束,退出代码0

可见,核心问题是梯度爆炸
①前几轮:损失在下降,模型正常学习。
②中间轮次:损失开始回升并剧烈震荡,说明梯度已经开始不稳定。
③最后几轮:损失值变成 nan(Not a Number,不是一个数字),训练彻底崩溃。
④如何解决?
使用训练集进行训练:train=True;
增大 batch_size:例如 batch_size=64;
添加激活函数:在每个卷积层和全连接层后添加 nn.ReLU();
降低学习率:例如 lr=0.001;
使用动量(Momentum):momentum=0.9,帮助稳定训练;

posted on 2025-11-23 12:01  风居住的街道DYL  阅读(0)  评论(0)    收藏  举报