一、基本概念
1. 张量(Tensor)
张量 是 PyTorch 中用来存储数据的基本单位,它可以看作是一个多维的列表。
你可以把它看成是一个容器,用来存放数字,并且可以进行很多数学计算。
-
标量(Scalar):一个单独的数字,又称为零维张量。
例如:x = torch.tensor(5),这里5是一个数字。 -
向量(Vector):一组数字,可以理解为一个列表。
例如:x = torch.tensor([1, 2, 3]),这就表示了包含 1、2 和 3 三个数字的列表。 -
矩阵(Matrix):一个由多个数字组成的二维表格,像一个表格或一张纸上的数字排列。
例如:x = torch.tensor([[1, 2], [3, 4]]),这表示一个 2 行 2 列的表格。 -
高维张量:可以理解为包含多个矩阵的数据结构。
例如:x = torch.tensor([[[1, 2], [3, 4]], [[5, 6], [7, 8]]]),这是一个包含 2 个矩阵的数据结构。
这些张量可以在计算时进行加、减、乘、除等操作。它们的大小(例如行数、列数)和形状也是可以调整的。
2. 计算图(Computation Graph)
计算图 是指在进行计算时,PyTorch 会把你做的每一步操作记录下来。
-
例子:可以想象成你在看着菜谱做饭,切菜、热锅、放油、放入蔬菜、翻炒、加盐、调料、出锅。把这个做饭过程比作一个计算过程,每一步都是一个操作。而计算图就是记录这个做饭过程的一个步骤图。每一步操作(如“切菜”)就是计算图中的一个节点。每个节点都有它的输入(如“切好的菜”),和它产生的输出(如“炒熟的菜”)。
-
动态图:计算图在你运行时动态生成。这意味着每次你执行计算时,PyTorch 会根据你给出的步骤自动创建新的计算图。
3. 自动微分(Autograd)
自动微分 自动地帮助你计算每个操作的变化。这对于训练神经网络非常重要,因为它可以自动计算出每个操作如何影响最终结果,从而更新模型的参数。
- 例子:假设你有一个目标(比如想让机器预测某个数字),然后你使用机器进行计算得到一个结果,最后会得到一个“误差”值。通过自动微分,PyTorch 会计算出这个误差如何影响机器的每个部分,然后根据这些计算来调整机器的参数,直到它做得更好。
4. 优化器(Optimizer)
优化器 是用来调整机器模型中参数的工具。在训练模型时,我们会不断调整这些参数,使得模型的预测越来越准确。优化器根据每个参数的“误差”来决定如何调整这些参数,类似于每次练习时改进动作。
- 例子:假设你在学习骑自行车,开始时可能会不太稳定,但是你根据每次骑行后的“反馈”调整自己的动作,直到可以稳定骑行。优化器就是这个过程的“反馈机制”。
5. 神经网络(Neural Networks)
神经网络 是一个模拟人脑神经元的计算模型,它通过层层处理输入数据来生成输出。在 PyTorch 中,你可以使用 torch.nn 模块来构建神经网络。
- 例子:想象你正在玩一个“是/否”问题游戏,每一次回答都会根据你的输入(例如:“它是红色的吗?”)来改变下一步的决策过程。神经网络就像这样的决策过程,每一层的处理都会根据前面的输入进行调整。
6. 数据加载(Data Loading)
当你进行深度学习训练时,往往需要处理大量的数据。为了高效地使用这些数据,PyTorch 提供了数据加载器(DataLoader),它可以帮助你从文件中读取数据,并将数据分成小批次送入模型进行训练。
- 例子:如果你有 1000 本书,你并不会一次性读完所有的书,而是会分成每次读 10 本。这种分批处理方式就像数据加载器,它将所有数据分成小块,以便训练时逐步输入。
二、示例
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)
-
flatten层是将输入的数据从多维数组展平成一维数组。
start_dim=1表示从第一个维度(即图像的高度或宽度)开始展平
end_dim=-1表示直到最后一个维度 - 对于 MNIST 图像数据集(28x28 像素的图像),每个图像是一个二维数组(28, 28)。
flatten会将其展平为一个一维的数组,形状变为(784,)(28*28=784)。 - 作用:将输入的图像展平为一个一维向量,准备输入到全连接层。
2. (linear_relu_stack): Sequential(...)
linear_relu_stack 是一个包含多个层的顺序容器(Sequential)。
每一层按照顺序排列,依次执行计算:
-
第一个层:
(0): Linear(in_features=784, out_features=512, bias=True)-
Linear表示一个全连接层,它执行线性变换y = Wx + b。 -
in_features=784:输入特征数为 784(展平后的图像像素数量)。 -
out_features=512:输出特征数为 512,即输出的向量长度是 512。 -
bias=True:表示在计算中会加上偏置项。
-
-
第二个层:
(1): ReLU()-
ReLU是一个激活函数(Rectified Linear Unit),用于引入非线性,帮助神经网络捕捉复杂的模式。 -
ReLU的作用是对输入值进行非线性变换,使得所有负数变为 0,正数保持不变。
-
-
第三个层:
(2): Linear(in_features=512, out_features=512, bias=True)- 这是另一个全连接层,输入特征数为 512,输出特征数为 512。
- 同样使用偏置项。
-
第四个层:
(3): ReLU()- 这是另一个 ReLU 激活函数层,对输出进行非线性变换。
-
第五个层:
(4): Linear(in_features=512, out_features=10, bias=True)- 最后一个全连接层,输入特征数为 512,输出特征数为 10。
- 输出的 10 个值对应分类任务中的 10 个类别(例如,MNIST 数据集中 10 个数字)。
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))











网友评论