FA_CNN卷积神经网络七---优化器PyTorch

FA :Formulas and Algorithm,CNN:Convolutional Neural Network

1. 优化器

在神经网络训练过程中,优化器(Optimizer)扮演着至关重要的角色。它的核心作用是根据损失函数计算出的梯度,对网络参数进行调整,从而逐步降低整体误差。

1.1 损失函数与反向传播

当我们调用损失函数的 backward() 方法时,就会触发反向传播机制,自动计算出我们需要调节的梯度。随后,优化器便可以利用这些梯度对参数进行调整,达到整体误差降低的目的。

1.2 梯度清零

在每次参数更新之前,必须将梯度清零。如果梯度不清零,会导致梯度累加,从而影响参数更新的准确性。这是训练过程中最容易忽略却又极其重要的细节。

2. 神经网络优化一轮

下面我们通过一个完整的示例,演示如何对神经网络进行一轮优化。这里我们使用 CIFAR10 数据集,构建一个简单的卷积神经网络,并采用随机梯度下降(SGD)优化器。

python 复制代码
import torch
import torchvision
from torch import nn 
from torch.nn import Conv2d, MaxPool2d, Flatten, Linear, Sequential
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter

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

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 = self.model1(x)
        return x

loss = nn.CrossEntropyLoss()  # 交叉熵损失函数
tudui = Tudui()
optim = torch.optim.SGD(tudui.parameters(), lr=0.01)  # 随机梯度下降优化器

for data in dataloader:
    imgs, targets = data
    outputs = tudui(imgs)
    result_loss = loss(outputs, targets)  # 计算实际输出与目标输出的差距
    optim.zero_grad()  # 梯度清零
    result_loss.backward()  # 反向传播,计算损失函数的梯度
    optim.step()  # 根据梯度,对网络的参数进行调优
    print(result_loss)  # 对数据只看了一遍,只看了一轮,所以loss下降不大

2.1 运行结果分析

运行上述代码,可以看到每一批数据的损失值都在 2.3 左右波动,下降幅度并不明显。这是因为我们只对数据看了一遍(即只训练了一轮),模型尚未充分学习到数据的特征。

复制代码
tensor(2.2978, grad_fn=<NllLossBackward0>)
tensor(2.2988, grad_fn=<NllLossBackward0>)
tensor(2.3163, grad_fn=<NllLossBackward0>)
tensor(2.3253, grad_fn=<NllLossBackward0>)
...

3. 神经网络优化多轮

单轮训练显然不够,我们需要让模型多次遍历整个数据集。下面我们引入 epoch 的概念,对数据集进行多轮训练,并统计每一轮的累计损失。

python 复制代码
import torch
import torchvision
from torch import nn 
from torch.nn import Conv2d, MaxPool2d, Flatten, Linear, Sequential
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter

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

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 = self.model1(x)
        return x

loss = nn.CrossEntropyLoss()  # 交叉熵损失函数
tudui = Tudui()
optim = torch.optim.SGD(tudui.parameters(), lr=0.01)  # 随机梯度下降优化器

for epoch in range(20):
    running_loss = 0.0
    for data in dataloader:
        imgs, targets = data
        outputs = tudui(imgs)
        result_loss = loss(outputs, targets)  # 计算实际输出与目标输出的差距
        optim.zero_grad()  # 梯度清零
        result_loss.backward()  # 反向传播,计算损失函数的梯度
        optim.step()  # 根据梯度,对网络的参数进行调优
        running_loss = running_loss + result_loss
    print(running_loss)  # 对这一轮所有误差的总和

3.1 运行结果分析

从输出结果可以清晰地看到,随着训练轮次的增加,每一轮的累计损失在稳步下降:

复制代码
tensor(358.1069, grad_fn=<AddBackward0>)
tensor(353.8411, grad_fn=<AddBackward0>)
tensor(337.3790, grad_fn=<AddBackward0>)
tensor(317.3237, grad_fn=<AddBackward0>)
tensor(307.6762, grad_fn=<AddBackward0>)
tensor(298.2425, grad_fn=<AddBackward0>)
tensor(289.7010, grad_fn=<AddBackward0>)
tensor(282.7116, grad_fn=<AddBackward0>)
tensor(275.8972, grad_fn=<AddBackward0>)
tensor(269.5961, grad_fn=<AddBackward0>)
tensor(263.8480, grad_fn=<AddBackward0>)
tensor(258.5006, grad_fn=<AddBackward0>)
tensor(253.4671, grad_fn=<AddBackward0>)
tensor(248.7994, grad_fn=<AddBackward0>)
tensor(244.4917, grad_fn=<AddBackward0>)
tensor(240.5728, grad_fn=<AddBackward0>)
tensor(236.9719, grad_fn=<AddBackward0>)
tensor(233.6264, grad_fn=<AddBackward0>)
tensor(230.4298, grad_fn=<AddBackward0>)
tensor(227.3427, grad_fn=<AddBackward0>)

这说明多轮训练能够有效帮助模型学习数据特征,逐步降低损失。

4. 神经网络学习率优化

在训练过程中,学习率的大小直接影响模型的收敛速度和最终效果。PyTorch 提供了 torch.optim.lr_scheduler 模块,可以在训练过程中动态调整学习率。

下面我们使用 StepLR 调度器,每经过 step_size 个 epoch,将学习率乘以 gamma 进行衰减。

python 复制代码
import torch
import torchvision
from torch import nn 
from torch.nn import Conv2d, MaxPool2d, Flatten, Linear, Sequential
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter

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

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 = self.model1(x)
        return x

loss = nn.CrossEntropyLoss()  # 交叉熵损失函数
tudui = Tudui()
optim = torch.optim.SGD(tudui.parameters(), lr=0.01)  # 随机梯度下降优化器
scheduler = torch.optim.lr_scheduler.StepLR(optim, step_size=5, gamma=0.1)  # 每过 step_size 更新一次优化器,学习率变为原来的 0.1 倍

for epoch in range(20):
    running_loss = 0.0
    for data in dataloader:
        imgs, targets = data
        outputs = tudui(imgs)
        result_loss = loss(outputs, targets)  # 计算实际输出与目标输出的差距
        optim.zero_grad()  # 梯度清零
        result_loss.backward()  # 反向传播,计算损失函数的梯度
        optim.step()  # 根据梯度,对网络的参数进行调优
        scheduler.step()  # 学习率太小了,所以20个轮次后,相当于没走多少
        running_loss = running_loss + result_loss
    print(running_loss)  # 对这一轮所有误差的总和

4.1 运行结果分析

观察输出可以发现,损失值几乎没有下降,始终维持在 359 左右:

复制代码
tensor(359.4722, grad_fn=<AddBackward0>)
tensor(359.4630, grad_fn=<AddBackward0>)
tensor(359.4630, grad_fn=<AddBackward0>)
...

这是因为我们在每个 batch 之后 都调用了 scheduler.step(),导致学习率被过早、过快地衰减到极小值。学习率太小,模型几乎无法更新参数,20 个轮次后相当于没走多少步。

4.2 正确用法

StepLR 的 step() 方法应该在每个 epoch 结束后 调用一次,而不是在每个 batch 之后。正确的写法是将 scheduler.step() 放在内层循环之外:

python 复制代码
for epoch in range(20):
    running_loss = 0.0
    for data in dataloader:
        imgs, targets = data
        outputs = tudui(imgs)
        result_loss = loss(outputs, targets)
        optim.zero_grad()
        result_loss.backward()
        optim.step()
        running_loss = running_loss + result_loss
    scheduler.step()  # 每个 epoch 结束后更新一次学习率
    print(running_loss)

5. 总结

通过本文的实战演练,我们掌握了以下核心要点:

  • 优化器:利用反向传播计算出的梯度对参数进行调整,逐步降低损失。
  • 梯度清零 :每次参数更新前必须调用 optim.zero_grad(),防止梯度累加。
  • 多轮训练 :通过 epoch 循环让模型多次遍历数据集,损失会稳步下降。
  • 学习率调度 :lr_scheduler 可以动态调整学习率,但要注意 step() 的调用时机------应在每个 epoch 结束后调用,而非每个 batch 之后。

希望本文能帮助你更好地理解 PyTorch 中神经网络优化的完整流程。欢迎在评论区交流你的训练心得!

相关推荐
智能直播2 小时前
RK3518:1.5G 内存 + 8G 存储,如何跑起硬件编解码、Web、AI 识别、绿幕特效
前端·人工智能·5g
大模型真好玩2 小时前
初试短视频生成:豆包将我梦中的场景画出来了~
人工智能·agent·deepseek
梦想出海-Phoebe3 小时前
AI Agent能实现自主复制吗?Anthropic研究揭示模型部署与IoT设备安全问题
人工智能·物联网·安全
指针向南3 小时前
PDF转长图用什么?3种方法实测(2026)
图像处理·人工智能·计算机视觉·pdf
郝学胜-神的一滴3 小时前
AI 编程智能体 09:零门槛调用教程
人工智能·数据分析·自动化·numpy·pandas·量化投资
商业看点解说3 小时前
支持私有化部署的 AI 助手有哪些?把“私有化“拆成四层,排除一类常被错放的产品
大数据·人工智能
清华kenny3 小时前
安徽晓得养HIS系统适合哪类健康机构升级使用
大数据·人工智能·安徽晓得养
kyriewen3 小时前
我抽查了 6 万个 Skills:前排没几个真货
人工智能·程序员·ai编程
掘金酱3 小时前
【10.24 特别活动】AI 时代,程序员的新饭碗在哪里?
前端·人工智能·后端