首页 › S 模型训练 › S1 基础概念与第一个实验 › 03

S1-03 · 梯度与 autograd:反向传播在算什么

入门阶段约 240 分钟阶段:S1 基础概念与第一个实验

阶段:S1-基础概念与第一个实验 | 预计耗时:45 分钟 | 前置:S1-00 训练是什么(手算 3 步梯度下降) 代码:本篇代码要你自己敲成 model-learn/s1_autograd_toy.py(15 行)

学习目标

  1. 理解 requires_grad / .backward() / .grad 三个机制:PyTorch 怎么自动算梯度
  2. 用代码验证你在 S1-00 的手算——两边数字一致,反向传播对你就不神秘了
  3. 亲手制造"忘记清梯度"的事故,理解训练循环里 zero_grad() 为什么必须存在

核心知识

1. autograd 的三件套

  • w = torch.tensor([0.0], requires_grad=True):打开"记录梯度"开关(参数才有,数据没有)
  • loss.backward():沿计算图反向走一遍,把每个开了开关的张量的梯度填进 .grad
  • w.grad.zero_():.grad 是累加的,不清零就会越加越大

2. 反向传播没有新东西

它只是"微积分链式法则的自动化"。你手算 loss=(w−2)² 的梯度是 2(w−2),backward() 算出的一模一样——模型再大,本质也是这一件事,只是链条长了几十万节。

3. 为什么更新参数要包在 torch.no_grad() 里

参数更新本身也是张量运算,如果不关记录,计算图会越缠越长、内存爆掉。训练循环里这和 zero_grad() 一样是标配。

实验任务

任务 1:敲出脚本并预测输出(15 分钟)

# s1_autograd_toy.py —— 用 15 行代码看见"反向传播"
# 目标:让参数 w 逼近 2(模型 y = w * x,数据 x=1,真实答案 y=2)
import torch

w = torch.tensor([0.0], requires_grad=True)   # 参数:记录梯度
x = torch.tensor([1.0])
y_true = torch.tensor([2.0])
lr = 0.1

for step in range(3):
    loss = (w * x - y_true) ** 2        # 前向:算损失
    loss.backward()                     # 反向:自动算出 2*(w-2)
    print(f"第{step+1}步  w={w.item():.4f}  loss={loss.item():.4f}  grad={w.grad.item():.4f}")
    with torch.no_grad():               # 更新时不记录梯度
        w -= lr * w.grad
    w.grad.zero_()                      # 清梯度

运行后与 S1-00 的手算表逐行核对(w 应该是 0 → 0.4 → 0.72)。

任务 2:制造事故——删掉清梯度那行(15 分钟)

注释掉 w.grad.zero_(),再跑。观察 grad 列:第 2 步不再是 −3.2 而是 −7.2(−4 和 −3.2 累加),w 很快冲过 2 开始震荡。 这就是训练脚本忘写 zero_grad() 的典型症状——你以后一眼能认出来。

任务 3:把步数加到 20(10 分钟)

把 range(3) 改成 range(20),看 w 和 loss 怎么一步步贴近 2 和 0。把最后 5 行输出抄进观察记录表(S1-02),解读:梯度为什么会自己变小?

验收标准

衔接下一阶段

你已从"概念"和"机制"两端理解了训练核心 → 完成 S1-01 的 3 个改动实验后,进入 S2-01 数据处理:数据怎么流进这个循环。

小测验(2 题)

答完立即判分,错题给解析;得分存本地。实验与实操题不上网测:回对话找老师验收。