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 训练循环核心步骤
  1. 前向传播(Forward Pass):将输入数据送入模型,得到预测结果(y_pred)。
    - 代码:y_pred = model(x)(x是输入数据,model是定义的模型)

  2. 计算损失(Compute Loss):用损失函数对比y_pred和真实标签(y_true),得到损失值。
    - 代码:loss = loss_fn(y_pred, y_true)

  3. 反向传播(Backward Pass):计算损失对模型参数的梯度(即“哪里需要改”)。
    - 代码:loss.backward()(Pytorch自动计算梯度,无需手动推导)

  4. 参数更新(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的强大之处在于这些基础组件的可复用性。加油!

小夜