pytorch train 模板
本文提供了一个完整、通用的 PyTorch 模型训练流程模板。它涵盖了从数据准备、模型构建、训练循环、测试评估到结果可视化的每一个关键步骤,是快速搭建深度学习项目的实用骨架。
🚀 整体流程一览
一个标准的 PyTorch 训练任务通常遵循以下流程。我们将通过一个具体的 CIFAR-10 图像分类任务来逐步解析代码。
graph TD
subgraph "准备阶段"
A["准备数据集 (CIFAR-10)"] --> B["创建 DataLoader"];
C["定义网络模型 (Tudui)"] --> D["定义损失函数 (CrossEntropy)"];
D --> E["定义优化器 (SGD)"];
end
subgraph "循环训练与评估 (Epochs)"
F["开始 Epoch 循环"];
F --> G["**训练模式** `model.train()`"];
G --> H["遍历 Train DataLoader"];
H --> I["前向传播 `output = model(input)`"];
I --> J["计算损失 `loss = loss_fn(output, target)`"];
J --> K["反向传播 `loss.backward()`"];
K --> L["更新参数 `optimizer.step()`"];
L --> M["记录训练 Loss (TensorBoard)"];
M --> N["**评估模式** `model.eval()`"];
N --> O["遍历 Test DataLoader (with `torch.no_grad()`)"];
O --> P["计算测试 Loss 和 Accuracy"];
P --> Q["记录测试结果 (TensorBoard)"];
Q --> R["保存模型 `torch.save()`"];
R --> F;
end
B --> H;
E --> L;
C --> I;
B --> O
A & C & E --> F
📝 代码详解
下面我们来分步解析实现这个流程的 Python 代码。
1. 导入库并准备数据
第一步是导入所有必要的库,并使用 torchvision.datasets
加载 CIFAR-10 数据集。
torchvision
: 提供了常用的数据集、模型和图像转换。Tensorboard SummaryWriter
: 用于可视化训练过程。DataLoader
: 用于批量加载数据。transforms.ToTensor
: 将 PIL Image 或 NumPyndarray
转换为FloatTensor
,并将像素值从[0, 255]
缩放到[0.0, 1.0]
。
1 | import torchvision |
2. 定义核心组件
接下来,我们创建模型实例、定义损失函数和优化器。
- 模型 (
Tudui
): 这是一个自定义的神经网络模型,其具体结构定义在model.py
文件中。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20import torch.nn as nn
class Tudui(nn.Module):
def __init__(self):
super(Tudui, self).__init__()
self.model = nn.Sequential(
nn.Conv2d(3, 32, 5, 1, 2),
nn.MaxPool2d(2),
nn.Conv2d(32, 32, 5, 1, 2),
nn.MaxPool2d(2),
nn.Conv2d(32, 64, 5, 1, 2),
nn.MaxPool2d(2),
nn.Flatten(),
nn.Linear(64*4*4, 64),
nn.Linear(64, 10)
)
def forward(self, x):
x = self.model(x)
return x - 损失函数 (
nn.CrossEntropyLoss
): 交叉熵损失函数,常用于多分类任务。它内部已经包含了 Softmax 操作。 - 优化器 (
torch.optim.SGD
): 随机梯度下降(Stochastic Gradient Descent)优化器,用于根据损失函数的梯度来更新模型的参数(权重和偏置)。lr
是学习率(learning rate)。
1 | # 创建网络模型 |
3. 设置训练参数与 TensorBoard
在开始训练之前,我们需要初始化一些计数器和超参数,并设置 TensorBoard 的 SummaryWriter
来记录训练数据。
total_train_step
/total_test_step
: 记录训练和测试的步数,作为 TensorBoard 的 x 轴。epoch
: 训练的总轮数。一轮(epoch)指完整地遍历一次整个训练数据集。SummaryWriter
: 创建一个写入器实例,它会将事件日志写入指定的目录(../logs_train
)。
1 | # 设置训练网络的一些参数 |
4. 训练与评估循环
这是整个脚本的核心。外层是 epoch 循环,内层包含一个训练步骤和一个评估步骤。
训练步骤
tudui.train()
: 将模型设置为训练模式。这会启用 Dropout 和 BatchNorm 等层。optimizer.zero_grad()
: 在计算新梯度之前,清除上一轮的旧梯度。loss.backward()
: 计算损失函数相对于模型参数的梯度(反向传播)。optimizer.step()
: 根据计算出的梯度更新模型参数。writer.add_scalar()
: 每 100 步记录一次训练损失。
评估步骤
tudui.eval()
: 将模型设置为评估模式。这会禁用 Dropout 和 BatchNorm 等层,确保评估结果的确定性。with torch.no_grad()
: 在此代码块内,所有计算都不会追踪梯度,从而节省内存和计算资源。- 计算准确率:
(outputs.argmax(1) == targets).sum()
计算一个批次中预测正确的样本数量。argmax(1)
找到概率最高的类别的索引。 - 记录结果: 在一轮 epoch 结束后,计算并打印在整个测试集上的总损失和正确率,并用 TensorBoard 记录。
1 | for i in range(epoch): |
💡 模型的两种保存方式
PyTorch 提供了两种主要的方式来保存模型,代码中展示了这两种方式:
- 保存整个模型对象 (
torch.save(model, PATH)
)
- 做法:
torch.save(tudui, "tudui_complete.pth")
- 优点: 非常简单,加载时也只需一行
model = torch.load("tudui_complete.pth")
。- 缺点: 这种方式使用了 Python 的
pickle
来序列化整个对象,它将模型的类定义、目录结构等都绑定在了一起。如果你的项目代码发生了变化(例如,重命名了模型类或存放模型的文件),加载时就可能会失败。可移植性较差。- 仅保存模型参数 (
torch.save(model.state_dict(), PATH)
) - (推荐)
- 做法:
torch.save(tudui.state_dict(), "tudui_params.pth")
- 优点: 只保存模型的“状态字典”(
state_dict
),即所有的权重和偏置。它不依赖于具体的类结构,非常轻量和灵活,是官方推荐的、更具 Python 风格的方式。- 缺点: 加载时需要先创建模型实例,然后再将参数加载进去:
1
2
3
4 # 需要先创建模型实例
model = Tudui()
# 再加载参数
model.load_state_dict(torch.load("tudui_params.pth"))结论:为了代码的健壮性和可移植性,强烈推荐使用第二种方法,即只保存和加载模型的
state_dict
。
为何需要
train()
和eval()
模式?模型的某些层(如
Dropout
和BatchNorm
)在训练和评估时的行为是不同的。 - 训练时 (train()
模式):Dropout
会随机失活一些神经元来防止过拟合;BatchNorm
会计算当前批次的均值和方差来归一化数据。 - 评估时 (eval()
模式):Dropout
会被禁用;BatchNorm
会使用在整个训练过程中学习到的全局均值和方差。切换模式能确保模型在正确的状态下进行训练和推理。
⚡️ 迁移到 GPU 训练
如果你的机器上有 NVIDIA 显卡并正确安装了 CUDA,那么将训练迁移到 GPU 上可以极大地加速计算。PyTorch 让这个过程变得非常简单,核心只有三步:定义设备、模型上设备、数据上设备。
1. 定义设备
在代码的准备阶段,首先定义一个 device
对象。下面的代码会自动检测 CUDA 是否可用,如果可用则选择 GPU,否则回退到 CPU。
1 | # 定义训练的设备 |
2. 将模型和损失函数移动到设备
创建完网络模型和损失函数后,调用 .to(device)
方法将它们发送到指定的设备上。
1 | # 创建网络模型 |
提示:优化器在初始化时已经注册了模型的参数。当模型被
.to(device)
移动后,优化器会自动感知到参数在 GPU 上,因此优化器本身不需要被移动。
3. 将数据移动到设备
最后,也是最关键的一步,是在训练和测试的循环中,将每一批次的数据也发送到同一个设备上。
1 | # 在训练/测试循环中 |
完成这三步修改后,你的训练代码就能在 GPU 上飞速运行了!
🔬 模型验证
训练完成后,我们可以加载保存好的模型,用它来对全新的、从未见过的数据进行预测。下面是一个完整的验证(或称推理,Inference)流程示例。
1. 准备环境和数据
首先,我们需要导入相关库,并准备一张待预测的图片。请注意,这张图片需要经过和训练时完全相同的预处理(transform
)。
1 | import torch |
2. 加载模型并进行预测
接下来,我们加载已经训练好的模型文件,并进行预测。
torch.load()
: 加载模型文件。map_location
: 这是一个非常重要的参数!如果你的模型是在 GPU 上训练保存的(.pth
文件中包含了 GPU 张量),而你现在想在只有 CPU 的机器上加载它,就必须指定map_location=torch.device('cpu')
,它会智能地将所有张量重新映射到 CPU 上。model.eval()
: 切换到评估模式,这和训练时的验证步骤一样重要。
1 | # 加载模型 |
通过这个流程,你就可以用训练好的模型来处理任何新的输入数据了。
📈 启动 TensorBoard
训练开始后,你可以在终端中运行以下命令来启动 TensorBoard 服务:
1 | tensorboard --logdir=../logs_train |
然后打开浏览器访问 http://localhost:6006
即可看到 train_loss
, test_loss
和 test_accuracy
的变化曲线。
📝 小结
这个模板展示了 PyTorch 训练一个模型的标准范式:
- 数据加载:使用
Dataset
和DataLoader
。 - 模型构建:定义网络、损失函数和优化器。
- 循环迭代:通过
for
循环进行多轮 (epoch) 训练。 - 训练模式:在每轮 epoch 开始时调用
model.train()
,进行前向传播、计算损失、反向传播和参数更新。 - 评估模式:调用
model.eval()
和with torch.no_grad()
,在测试集上评估模型性能。 - 可视化与保存:使用
TensorBoard
监控过程,使用torch.save
保存模型。
参考自 B站up 我是土堆,链接:https://www.bilibili.com/video/BV1hE411t7RN?spm_id_from=333.788.videopod.episodes&vd_source=a1e48cea1c1e1104579f0aefa6e00490&p=1