← Learning

Lab 2 — 激活函数与 ReLU 非线性

DOM-08 深度学习 · 2026-07-25 · torch 2.5.1 + CUDA · source

实验概述

用 PyTorch 从零搭建一个带隐藏层的小型神经网络,拟合送货距离(英里)与时间(分钟)之间的非线性关系。核心是引入 ReLU 激活函数,让模型获得非线性拟合能力。

模型:Linear(1,3) → ReLU → Linear(3,1),共 10 个参数

数据:39 组(距离 1.0~20.0 英里,时间 6.96~92.98 分钟)

归一化:z-score(距离和时间各算各的)

训练:SGD lr=0.01,3000 epochs,manual_seed(27)

核心代码

模型定义与训练循环:

torch.manual_seed(27)
model = nn.Sequential(
    nn.Linear(1, 3),   # 隐藏层:1 输入 → 3 神经元
    nn.ReLU(),         # 激活函数:负数归零,正数不变
    nn.Linear(3, 1),   # 输出层:3 → 1
)
loss_function = nn.MSELoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)

for epoch in range(3000):
    optimizer.zero_grad()
    outputs = model(distances_norm)
    loss = loss_function(outputs, times_norm)
    loss.backward()
    optimizer.step()

反归一化预测(从归一化值还原到真实分钟数):

predicted_time_norm = model(new_distance_norm)
predicted_time_actual = (predicted_time_norm * times_std) + times_mean

训练过程

6 个关键帧(epoch 1 / 50 / 200 / 600 / 1500 / 3000),展示模型如何从随机初始化逐步拟合数据:

训练关键帧:6 个 epoch 的拟合变化
训练关键帧(归一化尺度)

Loss 曲线(对数尺度),3000 轮训练的收敛过程:

Loss 曲线:3000 epochs 的 MSE 收敛
Training Loss (MSE, normalized) — 对数尺度

最终拟合(真实单位:英里 vs 分钟):

最终拟合:非线性模型 vs 真实数据
Final Non-Linear Model Fit

结果

归一化最终 loss (MSE):0.003144

真实单位 RMSE:1.566 分钟

5.1 英里预测:38.7 分钟 → use a car

学到的参数(10 个):隐藏层 weight [0.912, -1.279, -0.719] / bias [-0.604, -0.420, 0.543];输出层 weight [0.240, -0.949, -0.787] / bias 0.806。

关键理解

矩阵乘加偏置 = 机器人运动学仿射变换。Linear 层的本质就是 p' = W·p + b,和机器人运动学里的 p' = R·p + d 同构——权重矩阵 W 对应旋转 R,偏置 b 对应平移 d。这个类比让"全连接层在做什么"瞬间具体了。

ReLU 的几何意义。ReLU 把负数归零,相当于在空间里"折叠"——单个 ReLU 神经元是一个分段线性函数(斜率在 0 处突变)。3 个 ReLU 神经元组合起来,就能拟合曲线。

归一化不是可选项。如果不做 z-score 归一化,距离(1~20)和时间(7~93)的尺度差异会让 loss 地形极度狭长,SGD 几乎学不动。归一化后 loss 地形接近圆形,梯度下降才能高效收敛。

错误复盘

一个关键错误:最初误判 seed=27 是"差拟合"——根因是用 Python random 而非 torch.manual_seed 生成初始权重,导致结果对不上。改用严格 manual_seed(27) 后确认是好种子(RMSE 1.57)。教训:PyTorch 的随机性必须用 PyTorch 自己的 RNG 控制,混用 Python random 会产生不可复现的结果。