训练流程 🔧
学习目标
- 看懂并写出标准的 PyTorch 训练循环
- 明白
train()、eval()、zero_grad()、backward()、step()的顺序 - 能对一个小任务完成训练、验证和预测
- 形成可复用的训练模板
一、训练循环为什么重要?
深度学习代码里最值得反复练的,不是某一个层,而是训练循环。
因为不管你是做:
- 图像分类
- 文本分类
- 目标检测
- 大模型微调
训练主流程都逃不开这条线:
二、先记住标准模板
先不要急着背,先多看几遍:
for batch_x, batch_y in train_loader:
pred = model(batch_x)
loss = loss_fn(pred, batch_y)
optimizer.zero_grad()
loss.backward()
optimizer.step()
它其实只在做三件事:
- 算预测
- 算误差
- 按误差更新参数
三、一个完整可运行例子
运行环境
下面代码可以直接运行:
pip install torch
我们做一个二维回归任务。
输入两个特征,目标值满足近似关系 :
y ≈ 3*x1 + 2*x2 + 5
import torch
from torch import nn
from torch.utils.data import TensorDataset, DataLoader, random_split
torch.manual_seed(42)
# 1. 造一份可直接运行的模拟数据
X = torch.randn(200, 2)
noise = torch.randn(200, 1) * 0.3
y = 3 * X[:, [0]] + 2 * X[:, [1]] + 5 + noise
dataset = TensorDataset(X, y)
train_dataset, val_dataset = random_split(
dataset,
[160, 40],
generator=torch.Generator().manual_seed(42)
)
train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)
val_loader = DataLoader(val_dataset, batch_size=40, shuffle=False)
# 2. 定义模型
model = nn.Sequential(
nn.Linear(2, 8),
nn.ReLU(),
nn.Linear(8, 1)
)
# 3. 定义损失函数和优化器
loss_fn = nn.MSELoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.05)
# 4. 训练
for epoch in range(1, 101):
model.train()
train_loss_sum = 0.0
for batch_x, batch_y in train_loader:
pred = model(batch_x)
loss = loss_fn(pred, batch_y)
optimizer.zero_grad()
loss.backward()
optimizer.step()
train_loss_sum += loss.item() * len(batch_x)
train_loss = train_loss_sum / len(train_dataset)
# 5. 验证
model.eval()
with torch.no_grad():
val_loss_sum = 0.0
for batch_x, batch_y in val_loader:
pred = model(batch_x)
loss = loss_fn(pred, batch_y)
val_loss_sum += loss.item() * len(batch_x)
val_loss = val_loss_sum / len(val_dataset)
if epoch % 20 == 0 or epoch == 1:
print(f"epoch={epoch:3d}, train_loss={train_loss:.4f}, val_loss={val_loss:.4f}")
# 6. 测试预测
test_x = torch.tensor([[1.0, 2.0], [-1.0, 0.5], [0.0, 0.0]])
with torch.no_grad():
test_pred = model(test_x)
print("\n测试样本预测:")
for x_row, y_row in zip(test_x, test_pred):
print(f"x={x_row.tolist()} -> pred={round(y_row.item(), 2)}")
四、逐行拆解这段代码
1. model.train()
告诉模型进入训练模式。
如果模型里有 Dropout、BatchNorm 这样的层,它们会切换到训练行为。
2. pred = model(batch_x)
前向传播。
也就是“拿当前参数做一次预测”。
3. loss = loss_fn(pred, batch_y)
告诉模型:“你这次和真实答案差多少。”
4. optimizer.zero_grad()
清空旧梯度。
因为 PyTorch 默认会累计梯度。
5. loss.backward()
反向传播。
把损失对各参数的梯度算出来。
6. optimizer.step()
根据梯度真正更新参数。
五、为什么验证要用 eval() 和 no_grad()?
验证阶段的目标不是学习,而是检查模型表现。
所以我们一般会这样写:
model.eval()
with torch.no_grad():
...
原因有两个:
eval():让某些层切换成推理模式no_grad():不记录梯度,省内存、省时间
六、一个更适合记忆的“厨房版类比”
把训练看成开餐厅会很好记:
| 深度学习步骤 | 餐厅类比 |
|---|---|
batch_x | 一批顾客订单 |
model(batch_x) | 厨师按当前手法做菜 |
loss_fn | 顾客给评分 |
backward() | 找出是哪里做得不好 |
step() | 下次做菜时调整手法 |
训练就是反复营业、反复改进。
七、常见变体
1. 分类任务
回归常用 MSELoss(),分类更常见:
loss_fn = nn.CrossEntropyLoss()
2. 不同优化器
最常见的两个:
SGDAdam
初学阶段,Adam 往往更省心一些。
3. 统计指标
训练时除了 loss,还常常统计:
- 准确率
accuracy - 精确率
precision - 召回率
recall - F1