1. 为什么需要损失函数和训练循环?¶
在机器学习中,模型的目标是“学习”数据中的规律,而损失函数(Loss Function)和训练循环(Training Loop)是实现这一目标的核心工具。
- 损失函数:衡量模型预测结果与真实标签的差距,相当于给模型“打分”。差距越小,分数越高,模型越“优秀”。
- 训练循环:通过调整模型参数,不断减小损失的过程。就像学生做题时根据错题(损失)修正答案(参数),最终让分数(模型精度)提高。
2. 损失函数:模型的“差距度量”¶
2.1 什么是损失函数?¶
损失函数是一个数学公式,输入模型的预测值(如分类的概率、回归的数值)和真实标签,输出一个非负的“差距值”。Pytorch提供了多种预定义损失函数,针对不同任务(分类/回归)设计。
2.2 常用损失函数(新手必学)¶
- MSE损失(均方误差):适用于回归任务(预测连续值,如房价、温度)。
- 公式:\(L = \frac{1}{n}\sum_{i=1}^{n}(y_{pred,i} - y_{true,i})^2\)
- Pytorch调用:
loss_fn = torch.nn.MSELoss() -
例子:预测房价时,MSE衡量“预测房价”与“真实房价”的平均平方差。
-
CrossEntropy损失(交叉熵):适用于分类任务(预测离散类别,如“猫/狗”“0-9数字”)。
- 公式:\(L = -\frac{1}{n}\sum_{i=1}^{n}\sum_{c=1}^{C}y_{true,i,c} \log(y_{pred,i,c})\)
- Pytorch调用:
loss_fn = torch.nn.CrossEntropyLoss() - 注意:输入需是模型输出的“原始分数”(logits,未经过softmax),目标标签是类别索引(如0、1、2)。
3. 训练循环:模型如何“学习”?¶
训练循环是模型通过调整参数减小损失的具体步骤,核心分为4步:前向传播→计算损失→反向传播→参数更新。
3.1 训练循环核心步骤¶
-
前向传播(Forward Pass):将输入数据送入模型,得到预测结果(y_pred)。
- 代码:y_pred = model(x)(x是输入数据,model是定义的模型) -
计算损失(Compute Loss):用损失函数对比y_pred和真实标签(y_true),得到损失值。
- 代码:loss = loss_fn(y_pred, y_true) -
反向传播(Backward Pass):计算损失对模型参数的梯度(即“哪里需要改”)。
- 代码:loss.backward()(Pytorch自动计算梯度,无需手动推导) -
参数更新(Update Parameters):通过优化器(如SGD、Adam)根据梯度调整模型参数。
- 代码:optimizer.step()(优化器会根据梯度更新参数,如optimizer = torch.optim.Adam(model.parameters(), lr=0.01))
4. 完整训练流程示例(以线性回归为例)¶
下面用一个简单的线性回归任务(预测房价)演示训练循环,数据和模型都极度简化。
4.1 准备数据¶
假设我们有100个样本,每个样本是1个特征(如房屋面积),真实关系为:y = 2x + 3(真实斜率=2,截距=3),并加入随机噪声模拟真实数据。
import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
# 生成模拟数据
np.random.seed(42) # 固定随机种子便于复现
x = np.random.randn(100, 1) # 100个样本,1个特征
y = 2 * x + 3 + 0.1 * np.random.randn(100, 1) # 真实关系+噪声
# 转为Pytorch张量
x = torch.from_numpy(x).float()
y = torch.from_numpy(y).float()
4.2 定义模型(简单线性层)¶
用一个线性层模拟房价预测:输入1个特征,输出1个预测值。
class LinearRegression(nn.Module):
def __init__(self):
super(LinearRegression, self).__init__()
self.linear = nn.Linear(1, 1) # 输入维度1,输出维度1(即 y = w*x + b)
def forward(self, x):
return self.linear(x) # 前向传播:返回预测值
model = LinearRegression()
4.3 初始化损失函数和优化器¶
- 损失函数:回归任务用MSE。
- 优化器:用Adam优化器,学习率
lr=0.01(控制参数更新幅度)。
loss_fn = nn.MSELoss() # 均方误差损失
optimizer = optim.Adam(model.parameters(), lr=0.01) # Adam优化器
4.4 训练循环(核心!)¶
遍历多个epoch(整个数据集),每次迭代完成“前向→损失→反向→更新”:
epochs = 1000 # 训练轮数:每个epoch遍历全部数据
for epoch in range(epochs):
# 1. 前向传播:计算预测值
y_pred = model(x)
# 2. 计算损失:预测值 vs 真实值
loss = loss_fn(y_pred, y)
# 3. 反向传播前必须清零梯度(否则梯度会累积)
optimizer.zero_grad()
# 4. 反向传播:计算梯度
loss.backward()
# 5. 参数更新:根据梯度调整模型参数
optimizer.step()
# 打印进度(每100轮输出一次)
if (epoch + 1) % 100 == 0:
print(f'Epoch [{epoch+1}/{epochs}], Loss: {loss.item():.4f}')
4.5 训练结果验证¶
训练后,模型参数(w和b)会接近真实值2和3:
# 打印最终参数
print("模型参数 w:", model.linear.weight.item()) # 接近2
print("模型参数 b:", model.linear.bias.item()) # 接近3
5. 关键细节与注意事项¶
- 梯度清零:
optimizer.zero_grad()必须在loss.backward()前调用,否则梯度会累加,导致训练失控。 - 模型模式:训练时用
model.train()(启用Dropout等),推理时用model.eval()(关闭Dropout,保证结果稳定)。 - 优化器选择:
- SGD(随机梯度下降):基础版,适合简单模型;
- Adam:更高效,默认参数即可,适合大多数场景(推荐新手优先用)。
- batch_size:若数据量大,可通过
DataLoader分批训练(如batch_size=32),加快训练速度。
6. 总结¶
损失函数是模型的“纠错尺子”,训练循环是模型“自我修正”的过程。通过调整参数最小化损失,模型就能从数据中学习到规律。
- 回归任务(连续值)→ 用MSE损失;
- 分类任务(离散类别)→ 用CrossEntropy损失;
- 训练循环核心:前向→损失→反向→更新。
掌握这些基础后,你可以尝试更复杂的模型(如CNN、RNN)或更复杂的任务(图像分类、文本生成),Pytorch的强大之处在于这些基础组件的可复用性。加油!