PyTorch 简介和示例

2025-02-17  本文已影响0人  河码匠

一、基本概念

1. 张量(Tensor)

张量 是 PyTorch 中用来存储数据的基本单位,它可以看作是一个多维的列表
你可以把它看成是一个容器,用来存放数字,并且可以进行很多数学计算。

这些张量可以在计算时进行加、减、乘、除等操作。它们的大小(例如行数、列数)和形状也是可以调整的。

2. 计算图(Computation Graph)

计算图 是指在进行计算时,PyTorch 会把你做的每一步操作记录下来。

3. 自动微分(Autograd)

自动微分 自动地帮助你计算每个操作的变化。这对于训练神经网络非常重要,因为它可以自动计算出每个操作如何影响最终结果,从而更新模型的参数。

4. 优化器(Optimizer)

优化器 是用来调整机器模型中参数的工具。在训练模型时,我们会不断调整这些参数,使得模型的预测越来越准确。优化器根据每个参数的“误差”来决定如何调整这些参数,类似于每次练习时改进动作。

5. 神经网络(Neural Networks)

神经网络 是一个模拟人脑神经元的计算模型,它通过层层处理输入数据来生成输出。在 PyTorch 中,你可以使用 torch.nn 模块来构建神经网络。

6. 数据加载(Data Loading)

当你进行深度学习训练时,往往需要处理大量的数据。为了高效地使用这些数据,PyTorch 提供了数据加载器(DataLoader),它可以帮助你从文件中读取数据,并将数据分成小批次送入模型进行训练。

二、示例

1. 下载训练数据,测试数据的的信息

import torch
# nn 神经网络模块
from torch import nn
# 批量加载数据的工具。帮助你将数据集按批次(batch)分成小块,并且可以自动化地进行数据的随机打乱、批次分配以及并行加载等操作
from torch.utils.data import DataLoader
# datasets 提供了常见的图像数据集接口,方便我们直接下载和使用数据集
from torchvision import datasets
# 转换器,它用于将图像转换为 PyTorch 张量
from torchvision.transforms import ToTensor

# FashionMNIST: 图像数据集
# train:
#       True  下载训练数据
#       False 下载测试数据
# ToTensor():  将数据转化为 PyTorch 张量格式
training_data = datasets.FashionMNIST(
    root="data",
    train=True,
    download=True,
    transform=ToTensor(),
)

test_data = datasets.FashionMNIST(
    root="data",
    train=False,
    download=True,
    transform=ToTensor(),
)


batch_size = 64

# 将数据加载成小批次(每批次大小为 batch_size,即 64)
train_dataloader = DataLoader(training_data, batch_size=batch_size)
test_dataloader = DataLoader(test_data, batch_size=batch_size)


#  X 是每个批次的数据输入,通常是特征数据(features),在图像分类任务中,它通常是图像数据。
#  y 是每个批次的数据标签,通常是对应于输入数据的目标值(labels)。例如,在图像分类任务中,y 可能是每张图像对应的类别标签。
for X, y in test_dataloader:

    #  N 是批次大小(batch size),也就是在每次循环中,X 包含了 64 个样本(因为 batch_size=64)。
    #  C 是通道数(channels)。如果是彩色图像,C 可能是 3(表示 RGB 三个颜色通道);如果是灰度图像,C 可能是 1。
    #  H 是图像的高度(height),即图像的垂直尺寸。
    #  W 是图像的宽度(width),即图像的水平尺寸。
    print(f"Shape of X [N, C, H, W]: {X.shape}")

    # y 的形状会依据任务的不同有所不同。
    #     如果是分类任务,y 可能是每张图像的类别索引(例如,一个数字表示图像的类别)。
    #     对于回归任务,y 可能是连续值。
    # y.shape 会显示 y 的形状,y.dtype 会显示标签的类型。
    print(f"Shape of y: {y.shape} {y.dtype}")
    break

2. 创建模型

# 检查是否有加速器(GPU 或其他硬件加速设备)
if torch.accelerator.is_available():
    # 当前加速器的类型(如 cuda 表示 GPU)
    device = torch.accelerator.current_accelerator().type
else:
    device = "cpu"
print(f"Using {device} device")


# 定义神经网络
class NeuralNetwork(nn.Module):
    def __init__(self):
        super().__init__()
        # 用 nn.Flatten() 将输入的二维图像(28x28)展平成一维数组。每张图像的像素数是 28 * 28 = 784
        self.flatten = nn.Flatten()

        #  一个 nn.Sequential 容器,顺序地包含了多个层:
        self.linear_relu_stack = nn.Sequential(

            #  nn.Linear(28*28, 512):一个全连接层,将 784 个输入映射到 512 个神经元。
            nn.Linear(28*28, 512),

            #  nn.ReLU():激活函数,增加非线性性。
            nn.ReLU(),

            #  nn.Linear(512, 512):另一个全连接层,输入和输出都是 512。
            nn.Linear(512, 512),

            #  nn.ReLU():激活函数。
            nn.ReLU(),

            #  nn.Linear(512, 10):最终输出层,映射到 10 个神经元,代表 10 个分类(例如,MNIST 数据集中的 10 个数字类别)。
            nn.Linear(512, 10)
        )
    # 定义了数据如何通过网络流动
    # 也就是输入数据从输入层到输出层的传递过程,也就是数据如何在网络中的各个层之间进行运算和变换
    def forward(self, x):
        # 输入数据展平
        x = self.flatten(x)
        # 数据通过定义的层堆进行前向传播,输出 logits(原始的网络输出)
        logits = self.linear_relu_stack(x)
        return logits

model = NeuralNetwork().to(device)
print(model)

返回内容

NeuralNetwork(
  (flatten): Flatten(start_dim=1, end_dim=-1)
  (linear_relu_stack): Sequential(
    (0): Linear(in_features=784, out_features=512, bias=True)
    (1): ReLU()
    (2): Linear(in_features=512, out_features=512, bias=True)
    (3): ReLU()
    (4): Linear(in_features=512, out_features=10, bias=True)
  )
)

说明:

1. (flatten): Flatten(start_dim=1, end_dim=-1)
2. (linear_relu_stack): Sequential(...)

linear_relu_stack 是一个包含多个层的顺序容器(Sequential)。

每一层按照顺序排列,依次执行计算:

3. 模型优化和训练


# 损失函数(loss function)
# CrossEntropyLoss。是一个常用于分类任务的损失函数
# 交叉熵损失函数(Cross-Entropy Loss):
#           它衡量的是模型预测的概率分布与真实标签之间的差异。
#           在分类任务中,模型的输出通常是一个概率分布(例如,模型输出每个类别的得分),而标签是实际的类别。
#           接收模型的输出(通常是 logits,即未经激活的原始输出)和实际的标签,并计算损失值。通常用作多类别分类任务中的损失函数
loss_fn = nn.CrossEntropyLoss()

# 优化器(optimizer): 是训练神经网络时用于调整参数(权重和偏置)的算法。目标是通过最小化损失函数,逐步提高模型的预测准确性。
# SGD(Stochastic Gradient Descent,随机梯度下降):
#     它通过计算损失函数相对于模型参数的梯度,并沿着梯度的反方向更新参数,从而使损失最小化。
# model.parameters():
#     这部分返回模型中所有需要训练的参数(即权重和偏置)。
# lr=1e-3:
#    学习率(learning rate),控制每次参数更新的步长。
#    1e-3 表示学习率是 0.001。较小的学习率通常意味着训练过程较慢,但可能更稳定;
#    较大的学习率可能使训练过程更快,但可能导致不稳定
optimizer = torch.optim.SGD(model.parameters(), lr=1e-3)


# 训练函数 train,用于训练神经网络模型。
# 作用是遍历数据集,计算损失,进行反向传播并优化模型参数
#
# 参数说明:
#     dataloader:数据加载器,用于按批次加载训练数据。
#     model:神经网络模型。
#     loss_fn:损失函数,用于计算预测结果与真实标签之间的差异。
#     optimizer:优化器,用于更新模型的参数。
def train(dataloader, model, loss_fn, optimizer):
    # 获取数据集的大小
    size = len(dataloader.dataset)
    # 将模型设置为训练模式
    model.train()
    # 遍历数据加载器中的每个批次(batch 批次号),X 是输入数据(通常是图像),y 是对应的标签(通常是图像类别)
    for batch, (X, y) in enumerate(dataloader):
        # 将数据移动到设备(如GPU)
        X, y = X.to(device), y.to(device)

        # 通过将输入 X 传入模型来获取模型的预测结果
        pred = model(X)
        # 计算预测值与真实标签之间的损失
        loss = loss_fn(pred, y)

        # 计算损失函数相对于模型参数的梯度
        loss.backward()
        # 更新模型的参数
        # 根据计算出的梯度和优化算法(如 SGD、Adam 等),优化器会调整模型的参数以减少损失
        optimizer.step()
        # 清除模型的梯度,以便下次计算时不会叠加上次计算的梯度
        # 每次反向传播后必须清零梯度,否则会导致梯度累积
        optimizer.zero_grad()

        #  打印训练进度
        if batch % 100 == 0:
            loss, current = loss.item(), (batch + 1) * len(X)
            print(f"loss: {loss:>7f}  [{current:>5d}/{size:>5d}]")


# test,用于评估训练后的模型在测试数据集上的表现
#
# 参数说明:
#        dataloader:数据加载器,用于按批次加载测试数据。
#        model:训练好的神经网络模型。
#        loss_fn:损失函数,用于计算模型在测试集上的误差。
def test(dataloader, model, loss_fn):
    # 测试数据集的总样本数
    size = len(dataloader.dataset)

    # 数据加载器中批次的数量,用来计算平均损失
    num_batches = len(dataloader)

    # 设置模型为评估模式
    model.eval()

    # 初始化测试损失和正确预测数
    # test_loss 用于累积每个批次的损失值,最终用于计算平均损失。
    # correct 用于累积模型在测试集上正确预测的数量,最终计算准确率。
    test_loss, correct = 0, 0

    # 上下文管理器,告诉 PyTorch 在这个代码块中不计算梯度
    with torch.no_grad():
        # 遍历测试数据集的批次
        # X 是输入数据,y 是对应的标签
        for X, y in dataloader:

            # 将数据移动到设备(如GPU)
            X, y = X.to(device), y.to(device)

            # 模型预测。通过将输入数据 X 传入模型,得到预测值 pred
            pred = model(X)

            # 累积损失。
            # loss_fn(pred, y) 计算当前批次的损失值(即预测与真实标签之间的差异)。
            # .item() 会将损失的张量转换为数值,并将其加到 test_loss 中,累计每个批次的损失
            test_loss += loss_fn(pred, y).item()

            # 计算正确预测的数量
            #  pred.argmax(1) 获取每个样本的最大得分对应的类别索引(即预测的类别)。
            #  (pred.argmax(1) == y) 是一个布尔张量,表示预测类别是否与实际类别相同。
            #  .type(torch.float) 将布尔值转换为浮点数(True 为 1,False 为 0)。
            #  .sum() 计算该批次中所有正确预测的样本数量。
            #  .item() 将结果转换为数值,并将其加到 correct 中。
            correct += (pred.argmax(1) == y).type(torch.float).sum().item()

    # 计算平均损失值
    test_loss /= num_batches

    # 计算模型在测试集上的准确率,size 是测试集的样本数量
    correct /= size
    print(f"测试误差: \n 准确率: {(100*correct):>0.1f}%, 平均损失: {test_loss:>8f} \n")


# 训练的轮数
epochs = 5
for t in range(epochs):
    print(f"第 {t+1} 次\n-------------------------------")
    # 每一轮循环中,调用 train() 函数对模型进行训练
    #
    # 参数说明:
    #     train_dataloader 训练数据加载器
    #     model 模型
    #     loss_fn 损失函数
    #     optimizer 优化器
    train(train_dataloader, model, loss_fn, optimizer)
    # 每轮训练后,使用 test() 函数评估模型的性能,
    #
    # 参数说明:
    #     test_dataloader 测试数据加载器
    #     model 模型
    #     loss_fn 损失函数
    test(test_dataloader, model, loss_fn)

print("结束!")

4. 保存模型

torch.save(model.state_dict(), "model.pth")
print("保存路径:model.pth")

5. 加载模型

# 初始化模型并将其移至指定设备
# device:cpu cuda之类
model = NeuralNetwork().to(device)

# 加载保存的模型参数
model.load_state_dict(torch.load("model.pth", weights_only=True))
上一篇 下一篇

猜你喜欢

热点阅读