当前位置: 首页 > article >正文

2.1 pytorch官方demo(Lenet)_代码详解

 model.py

import torch.nn as nn
import torch.nn.functional as F


class LeNet(nn.Module):
    def __init__(self):
        super(LeNet, self).__init__()
        # 输入channel为:3,卷积核个数为:16,卷积核大小为:5*5
        self.conv1 = nn.Conv2d(3, 16, 5)#得到的结果为(16,28,28)
        # 池化核大小为:2,步距为:2
        self.pool1 = nn.MaxPool2d(2, 2)#得到的结果为(16,14,14)
        # 输入channel为:16,卷积核个数为:32,卷积核大小为:5*5
        self.conv2 = nn.Conv2d(16, 32, 5)#得到的结果为(32,10,10)
        # 池化核大小为:2,步距为:2
        self.pool2 = nn.MaxPool2d(2, 2)#得到的结果为(32,5,5)
        # 特征向量展平为一维向量,即数据节点个数为:32*5*5,输出节点个数为:120
        self.fc1 = nn.Linear(32*5*5, 120)
        self.fc2 = nn.Linear(120, 84)#84个输出节点
        self.fc3 = nn.Linear(84, 10)#10个输出节点(根据分类任务决定)

    def forward(self, x):
        x = F.relu(self.conv1(x))    # input(3, 32, 32) output(16, 28, 28)
        x = self.pool1(x)            # output(16, 14, 14)
        x = F.relu(self.conv2(x))    # output(32, 10, 10)
        x = self.pool2(x)            # output(32, 5, 5)
        # 使用view进行展平。-1: 表示自动计算该维度的大小(通常用于批量大小)
        x = x.view(-1, 32*5*5)       # output(32*5*5)
        x = F.relu(self.fc1(x))      # output(120)
        x = F.relu(self.fc2(x))      # output(84)
        x = self.fc3(x)              # output(10)
        return x

train.py

import torch
import torchvision
import torch.nn as nn
from model import LeNet
import torch.optim as optim
import torchvision.transforms as transforms
import matplotlib.pyplot as plt
import numpy as np


def main():
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    print("Using device:", device)
    # transforms.Compose它将多个预处理操作组合在一起,形成一个可调用的对象。
    # 当这个管道被应用于图像时,会按顺序执行其中定义的所有操作。
    # transforms.ToTensor()将PIL图片或NumPy数组转换为PyTorch张量,并将像素值从[0, 255]范围缩放到[0, 1]之间。
    # 具体行为:
    # 如果输入是RGB图片,每个像素值会除以255,转为浮点数。
    # 数据维度从 (H, W, C) (高度、宽度、通道)变为 (C, H, W)(通道、高度、宽度),这是PyTorch处理图像数据的标准格式。
    # transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
    # 对张量数据按通道标准化:
    # 每个通道的数据减去均值(0.5, 0.5, 0.5),再除以标准差(0.5, 0.5, 0.5)。
    # 将原本[0, 1]范围的值进一步映射到[-1, 1]范围。
    transform = transforms.Compose(
        [transforms.ToTensor(),
         transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])

    # 50000张训练图片
    # 第一次使用时要将download设置为True才会自动去下载数据集
    # train_set 是一个封装了所有训练数据和标签的对象,包括预处理方法
    train_set = torchvision.datasets.CIFAR10(root='./data', train=True,
                                             download=False, transform=transform)
    # train_loader 是一个帮助分批次加载 train_set 数据的工具,通过它可以方便地迭代读取数据和标签用于模型训练。
    train_loader = torch.utils.data.DataLoader(train_set, batch_size=64,
                                               shuffle=True, num_workers=4)

    # 10000张验证图片
    # 第一次使用时要将download设置为True才会自动去下载数据集
    val_set = torchvision.datasets.CIFAR10(root='./data', train=False,
                                           download=False, transform=transform)
    val_loader = torch.utils.data.DataLoader(val_set, batch_size=10000,
                                             shuffle=False, num_workers=4)
    # 将数据加载器 val_loader 转为迭代器。
    val_data_iter = iter(val_loader)
    # 取出迭代器的下一批数据:调用 next(),从 val_data_iter 中取出一批次的数据。
    # 由于 val_loader 的 batch_size=10000,所以这实际上取出的是验证集中的全部数据。
    val_image, val_label = next(val_data_iter)

    val_image, val_label = val_image.to(device), val_label.to(device)

    # 定义CIFAR-10数据集的10个类别。
    classes = ('plane', 'car', 'bird', 'cat',
               'deer', 'dog', 'frog', 'horse', 'ship', 'truck')



    # # Helper function for inline image display
    # def matplotlib_imshow(img, one_channel=False):
    #     if one_channel:
    #         img = img.mean(dim=0)
    #     img = img / 2 + 0.5     # unnormalize
    #     npimg = img.numpy()
    #     if one_channel:
    #         plt.imshow(npimg, cmap="Greys")
    #     else:
    #         plt.imshow(np.transpose(npimg, (1, 2, 0)))
    #
    # # Create a grid from the images and show them
    # img_grid = torchvision.utils.make_grid(val_image)
    # matplotlib_imshow(img_grid, one_channel=False)
    # print('  '.join(classes[val_label[j]] for j in range(4)))
    # plt.show()  # 显示图片

    # 实例化LeNet模型
    net = LeNet().to(device)
    # 使用交叉熵作为损失函数
    loss_function = nn.CrossEntropyLoss()
    # 使用Adam优化器更新模型的权重
    optimizer = optim.Adam(net.parameters(), lr=0.001)


    # 训练过程
    for epoch in range(5):  # 模型遍历训练数据集5次

        running_loss = 0.0
        for step, data in enumerate(train_loader, start=0):
            # get the inputs; data is a list of [inputs, labels]
            # 每次加载一个批次的训练数据,包括inputs和labels。
            inputs, labels = data[0].to(device), data[1].to(device)
            # zero the parameter gradients
            # 每次训练前清除梯度,避免梯度累积。
            optimizer.zero_grad()
            # forward + backward + optimize
            # 前向传播:将输入数据通过网络,得到模型的预测输出。
            outputs = net(inputs)
            # 计算当前批次的损失
            loss = loss_function(outputs, labels)
            # 反向传播
            loss.backward()
            # 根据Adam优化器规则,更新模型参数
            optimizer.step()

            # print statistics
            # 累积每个批次的损失值,用于计算平均训练损失
            running_loss += loss.item()
            if step % 500 == 499:    # print every 500 mini-batches
                # 禁用梯度计算,节省内存和计算资源。验证时不需要更新模型参数,只需要计算输出。
                with torch.no_grad():
                    # 使用验证数据进行前向传播,得到预测结果。
                    outputs = net(val_image)  # [batch, 10]
                    # 从模型输出中选择预测概率最大的类别,作为模型的预测结果。
                    predict_y = torch.max(outputs, dim=1)[1]
                    # 比较预测值 predict_y 和真实标签 val_label,计算正确预测的数量并求出验证集的准确率。
                    accuracy = torch.eq(predict_y, val_label).sum().item() / val_label.size(0)

                    # 打印当前轮次、批次、平均训练损失以及验证集准确率。
                    print('[%d, %5d] train_loss: %.3f  test_accuracy: %.3f' %
                          (epoch + 1, step + 1, running_loss / 500, accuracy))
                    running_loss = 0.0

    print('Finished Training')

    save_path = './Lenet.pth'
    torch.save(net.state_dict(), save_path)


if __name__ == '__main__':
    main()

 predict.py

import torch
import torchvision.transforms as transforms
from PIL import Image

from model import LeNet


def main():
    # Resize((32, 32)): 将图片缩放到 32×32 大小, LeNet 的输入要求。
    # ToTensor(): 将图片转换为 PyTorch 张量,值范围从 [0, 255] 转为 [0, 1]。
    # Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)): 按通道对图片进行标准化,结果范围从 [0, 1] 映射到 [-1, 1]。
    transform = transforms.Compose(
        [transforms.Resize((32, 32)),
         transforms.ToTensor(),
         transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])

    # CIFAR-10 数据集的标签类别,按顺序与模型的输出对应
    classes = ('plane', 'car', 'bird', 'cat',
               'deer', 'dog', 'frog', 'horse', 'ship', 'truck')

    # LeNet(): 创建模型实例。
    # torch.load('Lenet.pth'): 加载训练好的模型权重。
    # load_state_dict: 将加载的权重应用到模型中。
    net = LeNet()
    net.load_state_dict(torch.load('Lenet.pth'))

    # Image.open('1.jpg'): 使用 PIL 打开图片。
    # transform(im): 应用前面定义的预处理,将图片转为 [C, H, W] 格式的张量。
    # torch.unsqueeze(im, dim=0): 增加一个批次维度,将形状从 [C, H, W] 变为 [N, C, H, W],以符合模型输入格式。
    im = Image.open('1.jpg')
    im = transform(im)  # [C, H, W]
    im = torch.unsqueeze(im, dim=0)  # [N, C, H, W]

    # 禁用梯度计算,加速推理并节省显存。
    with torch.no_grad():
        # 使用模型对图片进行前向传播,得到输出张量 [N, num_classes]。
        outputs = net(im)
        # 获取每张图片预测的类别索引。
        predict = torch.max(outputs, dim=1)[1].numpy()
    # 根据类别索引找到对应的类别名称,并输出。
    print(classes[int(predict)])

if __name__ == '__main__':
    main()


http://www.kler.cn/a/408022.html

相关文章:

  • 二维绘图,地图(Openlayers/Leafletjs)
  • JavaEE 实现 登录+注册(采用注解方式链接数据库)
  • go语言示例代码
  • 微信小程序包之加农炮游戏
  • Spring Aop+自定义注解实践(待完善日志)
  • windows10下3DGS环境配置
  • Rust 力扣 - 2466. 统计构造好字符串的方案数
  • Redis的理解
  • cangjie (仓颉) vscode环境搭建
  • 2024年亚太杯数学建模竞赛赛题选题人数发布
  • Qt之QWidget相关
  • 7、深入剖析PyTorch nn.Module源码
  • 【入门篇】欧几里德最差序列——多语言求解版
  • 后端:事务
  • RabbitMQ2:介绍、安装、快速入门、数据隔离
  • 八、无刷电机电压电流温度采集
  • CSS布局学习1
  • Oracle SQL优化②——访问路径
  • 使用 Elastic AI Assistant for Search 和 Azure OpenAI 实现从 0 到 60 的转变
  • 2-测试bigcache做进程内缓存 --开源项目obtain_data测试