从 batch 张量出发,逐节拼出完整训练循环。
张量 tensor (1)
在前一篇的第5小节(例3)中,为了清晰地展示前向计算与后向求导的数学过程,计算全部采用标量(0维tensor)。实际上,PyTorch 使用矩阵(多维tensor)一次性处理一个 Batch,即 $B$ 个样本组成一个 $B \times N$ 的矩阵(其中 $N$ 是一个样本的特征数),前向计算从”逐样本循环”变成”一次矩阵运算”。回顾那个例子,2个样本(图1中红色的$\boldsymbol{x}^1$ 和 绿色的$\boldsymbol{x}^2$),每个样本2个特征,标量形式的计算图如下:

图1:DAG标量
改成向量形式(PyTorch真实情况):

图2:DAG向量
对账:图2中 $Y$ 的两行 $1.5362$ 和 $1.4915$ 即前一篇第 5.5 小节的 $\hat{y}^1$ 和 $\hat{y}^2$;再跑 backward,$w_{11}$ 的梯度是 $0.006731$ 与第 5.7 小节手算的一致。
用 nn.Module 搭网络 (2)
- 手写 20 个 torch.tensor(…, requires_grad=True) 的痛点
- nn.Linear + nn.Sigmoid 拼出 3-2-1 网络,参数自动收集进 parameters()
- 对账:state_dict() 里的 20 个数 = 第一篇 5.2 的初始值表
损失函数 (3)
- 第一篇手写 $\frac{1}{2}\sum(\hat{y}-y)^2$ → 换成 nn.MSELoss
- 系数辨析:MSELoss 默认是均值,与第一篇的 $\frac{1}{2}$ 和差一个常数倍——梯度同比例缩放,正好用第一篇的手算功底验证(0.00673 × 换算系数)
优化器 (4)
- 拿到 .grad 之后呢:$\boldsymbol{\theta}^{N+1} = \boldsymbol{\theta}^{N} - \eta \cdot \boldsymbol{\nabla}L$
- optim.SGD:zero_grad() → backward() → step() 三件套
- 回扣第一篇 3.2 的注(叶子 +=` 累加 → 必须zero_grad);学习率 η 直观演示(太大 loss 爆炸/太小不收敛)
数据加载 (5)
- Dataset / DataLoader:batch、shuffle
- 真实数据登场:从 tsar.data.hdd.1 读磁盘延迟数据(特征→标签的构造)
- 时间序列的特殊性:不能随机 shuffle,按时间切分
训练循环 (6)
- 五件套拼合:epoch × (zero_grad → forward → loss → backward → step)
- 观察 loss 曲线下降;第 1 个 epoch 的梯度与第一篇手算值对账(闭环验证)
- 推理模式:model.eval() / torch.no_grad()——回扣最小信息原则(不记图、不存 saved tensors,省显存)
保存与恢复 (7)
- state_dict() 落盘 / 加载 / 断点续训