程序员求职经验分享与学习资料整理平台

网站首页 > 文章精选 正文

Pytorch学习-day8: 损失函数与优化器

balukai 2025-05-28 15:30:31 文章精选 13 ℃

学习目标

  1. 理解损失函数:学习什么是损失函数,为什么需要它,以及常见类型(如 MSE 和 CrossEntropy)。
  2. 理解优化器:了解优化器如何帮助模型学习,以及 SGD 和 Adam 的基本原理。
  3. 实践任务:为 Day 7 的 MLP 添加 MSE 损失函数和 SGD 优化器,训练 10 轮,观察模型如何改进预测。

术语解释

1. 损失函数 (Loss Function)

  • 是什么:损失函数是衡量模型预测结果与真实答案之间差距的指标。模型的目标是让这个“差距”尽可能小。
  • 类比:想象你在玩飞镖,目标是击中靶心(真实答案)。你的飞镖落在哪里(模型预测)与靶心的距离就是“损失”。损失越小,说明你越接近目标。
  • 常见类型MSE (Mean Squared Error, 均方误差):用于回归任务(预测连续值,如房价、温度)。它计算预测值与真实值差的平方平均值。 公式:MSE = (1/n) * Σ(预测值 - 真实值)^2 例子:预测房价是 100 万,真实是 120 万,差 20 万,平方后加权平均。 CrossEntropy (交叉熵损失):用于分类任务(预测类别,如猫狗分类)。它衡量预测概率分布与真实标签分布的差异。 例子:预测一张图片是猫的概率是 0.8,真实是猫,损失小;如果预测是狗,损失大。
  • 作用:告诉模型“错在哪里,错多少”,为优化提供方向。

2. 优化器 (Optimizer)

  • 是什么:优化器是调整模型参数(权重和偏置)的算法,让损失函数的值变小,模型预测更准确。
  • 类比:模型像一个在山谷里找最低点(最小损失)的人。优化器是“导航员”,告诉它每次走哪一步(调整参数)。
  • 常见类型SGD (Stochastic Gradient Descent, 随机梯度下降): 原理:根据损失函数的梯度(斜率),小步调整参数,朝损失下降的方向走。 类比:像下山时看脚下的坡度,慢慢走。 特点:简单,但可能需要较多步数,容易卡在“局部低点”。 Adam: 原理:结合动量法和自适应学习率,比 SGD 更“聪明”,能更快找到最低点。 类比:像个有经验的登山者,知道哪里陡、哪里平,步伐大小自动调整。 特点:收敛更快,适合复杂模型,但参数多。
  • 作用:通过反复调整模型参数,降低损失,让模型学到数据的规律。

示例:MLP + MSE + SGD

场景

假设你有一个简单的数据集:输入是 2 个数字(x1, x2),输出是它们的和(y = x1 + x2)。我们用一个 MLP 模型预测这个和,MSE 衡量预测误差,SGD 优化模型。

数据示例

  • 输入:[1.0, 2.0],真实输出:3.0
  • 输入:[0.5, 1.5],真实输出:2.0
  • 目标:模型学会预测任意输入的和。

代码

以下是完整的 PyTorch 代码,包含注释,帮助新手理解每一步。

python

Bash
import torch
import torch.nn as nn
import torch.optim as optim

# 定义 MLP 模型(Day 7 的假设结构)
class MLP(nn.Module):
      # 继承 PyTorch 的 Module 类
    def __init__(self, input_size=2, hidden_size=10, output_size=1):
        super(MLP, self).__init__()
        self.fc1 = nn.Linear(input_size, hidden_size)  # 第一层:输入到隐藏层
        self.relu = nn.ReLU()  # 激活函数,让模型学非线性关系
        self.fc2 = nn.Linear(hidden_size, output_size)  # 第二层:隐藏层到输出

    def forward(self, x):  # 前向传播
        x = self.fc1(x)
        x = self.relu(x)
        x = self.fc2(x)
        return x

# 设置超参数
input_size = 2  # 输入是 2 个数字
hidden_size = 10  # 隐藏层有 10 个神经元
output_size = 1  # 输出是 1 个数字(和)
learning_rate = 0.01  # 学习率,控制优化器步伐
epochs = 10  # 训练 10 轮
batch_size = 32  # 每批处理 32 个样本

# 生成示例数据
torch.manual_seed(42)  # 固定随机种子,结果可重复
X = torch.randn(100, input_size)  # 100 个样本,每个有 2 个特征
y = X.sum(dim=1, keepdim=True) + 0.1 * torch.randn(100, 1)  # 目标:特征和 + 噪声

# 初始化模型、损失函数、优化器
model = MLP(input_size, hidden_size, output_size)  # 创建模型
criterion = nn.MSELoss()  # MSE 损失函数
optimizer = optim.SGD(model.parameters(), lr=learning_rate)  # SGD 优化器

# 训练循环
model.train()  # 设置模型为训练模式
for epoch in range(epochs):
    total_loss = 0
    # 小批量训练
    for i in range(0, len(X), batch_size):
        # 取一批数据
        inputs = X[i:i+batch_size]
        targets = y[i:i+batch_size]

        # 前向传播
        outputs = model(inputs)  # 模型预测
        loss = criterion(outputs, targets)  # 计算 MSE 损失

        # 反向传播与优化
        optimizer.zero_grad()  # 清空上一步的梯度
        loss.backward()  # 计算当前梯度
        optimizer.step()  # 根据梯度更新参数

        total_loss += loss.item()  # 累加损失

    # 打印每轮平均损失
    avg_loss = total_loss / (len(X) // batch_size)
    print(f'Epoch [{epoch+1}/{epochs}], Loss: {avg_loss:.4f}')

# 测试模型
model.eval()  # 设置模型为评估模式
with torch.no_grad():  # 禁用梯度计算
    test_input = torch.tensor([[1.0, 2.0]])  # 测试输入
    prediction = model(test_input)  # 预测
    print(f'Test input: {test_input.tolist()}, Prediction: {prediction.tolist()}')

代码逐行解释

  1. 模型定义: MLP 类定义了一个两层神经网络:输入(2 个特征)→ 隐藏层(10 个神经元)→ 输出(1 个值)。 ReLU 激活函数让模型学到非线性关系(比如复杂的曲线)。 forward 方法描述数据如何通过网络。
  2. 数据生成: 创建 100 个随机样本,输入是 2 维(X),输出是输入的和加一点噪声(y)。 噪声模拟现实中的不完美数据。
  3. 损失函数: nn.MSELoss() 计算预测值和真实值的均方误差。 比如,预测 2.8,真实 3.0,误差是 (2.8 - 3.0)^2 = 0.04。
  4. 优化器: optim.SGD 使用梯度下降更新模型参数。 lr=0.01 控制每次调整的大小,太大可能跳过最低点,太小收敛慢。
  5. 训练过程: 每轮(epoch)遍历所有数据,分批(batch)处理。 前向传播:输入通过模型得到预测,计算损失。 反向传播:根据损失计算梯度(告诉参数怎么调整)。 优化:SGD 用梯度更新参数,减小损失。 打印平均损失,观察是否下降。
  6. 测试: 用 [1.0, 2.0] 测试,理想预测接近 3.0。 model.eval() 和 no_grad() 确保不计算梯度,节省内存。

预期输出

运行后,你会看到类似:

Bash
Epoch [1/10], Loss: 0.1234
Epoch [2/10], Loss: 0.0987
...
Epoch [10/10], Loss: 0.0123
Test input: [[1.0, 2.0]], Prediction: [[2.9876]]
  • 损失逐渐下降,说明模型在学习。
  • 预测值接近 3.0,说明模型学会了“求和”。

新手常见问题

  1. 为什么损失不下降? 学习率可能太高或太低,试试 0.001 或 0.1。 数据可能有问题,检查输入和目标是否匹配。 模型结构可能太简单,增加隐藏层或神经元。
  2. MSE 和 CrossEntropy 怎么选? 用 MSE 预测连续值(如温度、房价)。 用 CrossEntropy 预测类别(如猫、狗)。
  3. SGD 和 Adam 哪个好? SGD 简单,适合小数据集,但慢。 Adam 更快,适合复杂模型,但可能过拟合。
  4. 什么是梯度? 梯度是损失函数对参数的“斜率”,告诉优化器参数该往哪调(增大还是减小)。

资源建议

  • PyTorch 文档: MSELoss SGD
  • 视频教程: PyTorch 官方 YouTube 频道(如 Intro to PyTorch)。 Aladdin Persson 的 PyTorch 教程(YouTube)。
  • 实践: 试试用 CrossEntropy 做分类任务。 调整学习率、隐藏层大小,观察损失变化。

下一步

  • 试试 Adam 优化器:替换 optim.SGD 为 optim.Adam(model.parameters(), lr=0.001),比较收敛速度。
  • 加载真实数据集:如果有 CSV 或图像数据,我可以帮你写加载代码。
  • 可视化:用 Matplotlib 画损失曲线或预测结果。
最近发表
标签列表