跳转至

第 2 章 监督学习的最小闭环

学习式方法的第一个动作都是同一个:把"想要的行为"变成一组输入输出对,再用优化把参数调到让误差最小。这条闭环在监督学习里最干净——没有时间、没有探索,只有函数拟合。把它写清楚,后面强化学习的每处复杂度才有比较的基准。

1. 假设类与损失

监督学习选一个参数化的假设类 \(f_\theta:\mathcal X\to\mathcal Y\),用数据估计 \(\theta\)。假设类决定能表达什么:线性模型只表达线性关系,多层感知机表达连续映射,卷积网络利用平移结构,Transformer 利用注意力做变长依赖。机器人上常见的是后三者的组合——本体感受走多层感知机,图像走卷积或视觉主干,序列走注意力或循环结构。

损失函数不是随意挑的,它对应一个噪声模型。若目标是连续量且误差近似高斯,负对数似然化简为均方误差:

\[ \mathcal L_{\mathrm{MSE}}(\theta)=\frac1N\sum_{i=1}^{N}\lVert y_i-f_\theta(x_i)\rVert^2 \]

若目标是类别,负对数似然就是交叉熵:

\[ \mathcal L_{\mathrm{CE}}(\theta)=-\frac1N\sum_{i=1}^{N}\log p_\theta(y_i\mid x_i) \]

两条式子来自同一个原则:最小化负对数似然,等于最大化数据在模型下的概率。选损失就是选"误差长什么样"——MSE 假设误差对称且尾部轻,交叉熵假设输出是概率分布。机器人回归任务里还要注意量的几何:位置误差可以直接取欧氏距离,姿态误差要在旋转空间里量,直接对四元数四个分量取 MSE 会把"同一姿态的两种符号表示"当成两个不同答案(约定见 control-note 第 7 章「姿态与坐标表达」)。

2. 经验风险与优化

真正想最小化的是数据分布上的期望损失(风险),手上只有有限样本,于是最小化经验风险——训练集上的平均损失。批量梯度下降每步用全量数据算梯度,代价太大;随机梯度下降(stochastic gradient descent, SGD)每步只取一个小批量 \(B\):

\[ \theta\leftarrow\theta-\eta\,\nabla_\theta\mathcal L_B(\theta) \]

小批量梯度是全量梯度的有噪估计,噪声反而帮助跳出尖锐的局部结构。学习率 \(\eta\) 是整套训练里最敏感的超参:太大直接发散,太小则在预算内走不到。

自适应方法把每个参数的步长按历史梯度缩放。Adam 维护梯度的一阶矩与二阶矩估计,按 \(\hat m_t/(\sqrt{\hat v_t}+\epsilon)\) 归一化,对尺度差异大的参数(偏置与权重、不同量纲的输入)更宽容。它省掉了逐层调学习率的工作,代价是多出两个状态量与一组默认值——默认值对大多数任务够用,但换任务时仍应把它当作待验参数,而不是常量。

训练闭环的连接关系:

flowchart LR
    data["训练集<br/>输入 x、标签 y"] --> batch["小批量 B"]
    batch --> fwd["前向 f_θ(x)"]
    fwd --> loss["损失 L_B"]
    loss --> bwd["反向传播"]
    bwd --> opt["优化器<br/>SGD / Adam"]
    opt -->|"更新 θ"| fwd
    fwd --> val["验证集评估"]
    val -->|"泛化不升"| stop["早停 / 调参"]

3. 过拟合、正则与数据量

模型在训练集上误差持续下降、在验证集上先降后升,就是过拟合:模型记住了样本而非规律。诊断靠两条曲线的分叉,不靠单点数值。缓解手段各有代价:

  • L2 正则:在损失上加 \(\lambda\lVert\theta\rVert^2\),压小权重,等价于假设"参数不该太大"。实现最简单,但会与批归一化等尺度处理互相干扰。
  • Dropout:训练时随机置零一部分激活,迫使表示冗余;推理时要按保留概率缩放或使用对应的评估模式。
  • 数据增强:对输入做保持标签不变的变换(图像裁剪与色彩抖动、状态加小噪声)。增强方式必须匹配任务的不变性——把左右翻转用在"左右手装配"上就改变了标签。
  • 早停:验证指标不再改善就停止,用训练轮数当正则。

最有效的正则始终是数据量与多样性。机器人数据的稀缺是结构性的:一次真机示范要占用设备与人力,失败样本还带安全风险。常见做法是用大规模预训练表征降低对标注量的需求,再用小样本微调;这条路线把成本从前移到预训练,是否划算取决于下游任务的分布与预训练分布的接近程度(感知侧的做法见 camera-note 第 7 章「图像深度学习感知」)。

4. 划分、泄漏与指标

数据要分成训练、验证、测试三份:训练拟合参数,验证选超参与早停,测试只用一次、用来报告结论。机器人数据有个容易忽略的划分问题——同一回合的相邻帧高度相关。若按帧随机划分,验证集里会出现与训练集几乎一样的帧,指标虚高。正确做法是按回合分组划分:同一次示范的所有帧只能落在同一侧。

归一化统计量同样属于训练集:均值与方差只能在训练集上算,再原样用到验证、测试与部署。用全量数据算统计量是最常见的泄漏形式,它让指标好看一点,也让部署时的输入尺度与训练不一致。

指标要跟任务判据对齐:

任务类型 常用指标 判读要点
回归(位姿、力) RMSE、MAE、分位数误差 误差分布比均值更能说明尾部失败
分类(检测、分割) 精确率、召回率、F1、混淆矩阵 类别不平衡时准确率会骗人
机器人任务 阈值内成功率、平均完成步数 阈值与初始状态分布必须一起写明

成功率是最容易被含糊处理的指标:阈值取多少、初始状态怎么分布、评估多少次,三者不写清楚,数字之间不可比。第 10 章「训练工程、评测与迁移」会把口径补齐。

5. 张量形状与批维

实现层面最常见的错误不在算法,而在形状。约定一套固定顺序能省掉大量调试:批维放最前,其后按数据类型展开。

数据 形状 说明
状态向量 (B, obs_dim) 本体感受拼接后的定长向量
图像 (B, C, H, W) 通道在前,与 PyTorch 卷积约定一致
动作 (B, act_dim) 关节目标或末端增量
序列观测 (B, T, obs_dim) 帧堆叠或历史窗口,T 为长度
动作块 (B, K, act_dim) 一次预测 K 步,见第 8 章

观测与动作的归一化在训练与部署两侧必须用同一组统计量。把统计量随策略一起保存,是部署链路里最省事也最容易漏掉的一步:

# 数据归一化的最小实现:统计量只在训练集上估计,随策略一起保存
import torch

class Normalizer:
    def __init__(self, x: torch.Tensor, eps: float = 1e-6):
        self.mean = x.mean(dim=0)                 # (D,)
        self.std = x.std(dim=0).clamp_min(eps)    # (D,),防止常量维度除零

    def __call__(self, x: torch.Tensor) -> torch.Tensor:
        return (x - self.mean) / self.std

    def state_dict(self) -> dict:
        return {"mean": self.mean, "std": self.std}   # 与策略 checkpoint 同存

一个最小训练循环把上面的环节串起来:取批、前向、算损失、反向、更新,每若干步在验证集上评估。

model = PolicyNet(obs_dim, act_dim)
opt = torch.optim.Adam(model.parameters(), lr=3e-4)
for epoch in range(num_epochs):
    for x, y in train_loader:              # x: (B, obs_dim), y: (B, act_dim)
        pred = model(x)
        loss = torch.nn.functional.mse_loss(pred, y)
        opt.zero_grad()
        loss.backward()                    # 反向传播填充 .grad
        opt.step()                         # 按 Adam 规则更新参数
    if epoch % eval_every == 0:
        model.eval()                       # 关闭 dropout、固定归一化统计量
        with torch.no_grad():
            val_loss = evaluate(model, val_loader)
        model.train()

坑:model.train() 与 model.eval() 不只是开关梯度

Dropout 与批归一化在两种模式下的行为不同。评估时忘了 eval() 会得到偏乐观或偏悲观的指标;训练时忘了切回 train() 则会让后续训练退化。

6. 一个静态映射为何不够

监督学习假设"给定输入有唯一正确答案"。机器人的序贯决策不满足这条假设:

  • 动作改变下一状态。预测错一步,下一步的输入就偏离训练分布;误差沿回合累积,不会自己回到轨道。
  • 没有标注的最优动作。自由空间里到达同一个位姿可以有无数条轨迹,示范只给了其中一条;把示范当唯一标签,模型会把"另一条同样好的路"也算成错误。
  • 评价是延迟的。单个动作看不出好坏,好坏由整段回合的回报决定;这与逐帧标签的性质不同。

第一条是分布偏移问题,第 3 章「数据、表示与分布偏移」讲它的成因与判据;第二条与第三条是强化学习要解决的,第 4 章「马尔可夫决策过程与价值」给出形式。监督闭环本身没有失效,它变成更大闭环里的组件:感知头、价值网络、策略网络的最后一层都用它训练。

7. 要点

  • 损失函数对应噪声模型,MSE 与交叉熵都来自负对数似然;姿态误差要在旋转空间里量。
  • 学习率是最敏感的超参;Adam 的默认值是起点,不是结论。
  • 过拟合看两条曲线分叉;最有效的正则仍然是数据量与多样性,其次是 L2、Dropout、增强与早停。
  • 机器人数据要按回合分组划分,归一化统计量只在训练集上估计并随策略保存。
  • 指标要与任务判据对齐;成功率必须同时写明阈值、初始状态分布与评估次数。
  • 批维固定放最前;model.train() / model.eval() 影响 Dropout 与批归一化行为。
  • 静态映射不足以描述序贯决策:动作改变状态分布、最优动作不唯一、评价延迟——这三点引出后续两章。

参考文献与延伸阅读

  • Goodfellow, I., Bengio, Y., & Courville, A. Deep Learning. MIT Press, 2016. 书籍主页
  • Bishop, C. M. Pattern Recognition and Machine Learning. Springer, 2006. DOI
  • Kingma, D. P., & Ba, J. Adam: A Method for Stochastic Optimization. ICLR, 2015. arXiv
  • Srivastava, N., Hinton, G., Krizhevsky, A., Sutskever, I., & Salakhutdinov, R. Dropout: A Simple Way to Prevent Neural Networks from Overfitting. JMLR, 2014. JMLR
  • PyTorch. torch.nn 文档. 文档