06-工程实践 进阶 预计 20 分钟

实验管理与可复现性

实验管理把「跑一次训练」升级为「可复现、可对比、可回溯的科学流程」:固定全部随机性来源、配置与代码同版本管理、指标与曲线自动记录、最优检查点与其出生配置绑定保存。

一句话定义

实验管理把「跑一次训练」升级为「可复现、可对比、可回溯的科学流程」:固定全部随机性来源、配置与代码同版本管理、指标与曲线自动记录、最优检查点与其出生配置绑定保存。

直觉

没有实验管理的调参像「没有实验记录本的化学家」:做出好结果却说不清是哪一步的功劳,一周后自己都复现不了;有管理的实验像带编号的试剂瓶——任何一瓶结果都能追溯到完整的配方与流程。

为什么重要

深度学习结果的噪声水平(种子间差异常达 ±0.3~1%)与超参敏感度,使「不可复现的好结果」一文不值:没法对比、没法改进、没法交付。kp-027 的单变量原则必须落在本节的记录体系上才可执行;kp-021 的项目里程碑检查也依赖「同一基线可重跑」。

前置知识

  • kp-016(训练循环——被管理的对象)、kp-027(单变量实验纪律)。

核心概念

  • 随机性来源清单:权重初始化、数据增强、DataLoader shuffle、CUDA 算子、(序列任务)采样。
  • 种子(seed):torch/numpy/random/DataLoader 四处都要固定,缺一处就漂。
  • 配置即文档(config):超参数据集中在单一字典/yaml,训练产物与其绑定。
  • 日志(logging):每 epoch 记录 train/val 损失与指标、学习率、梯度范数,落盘为结构化文件。
  • 检查点(checkpoint):model.state_dict + 优化器状态 + epoch + 配置的打包保存。
  • 确定性 vs 速度:torch.use_deterministic_algorithms(True) 会显著拖慢训练,实践上常折中(记录种子而非强制逐位一致)。

原理与机制

可复现性的机制在于「消灭隐式状态」:训练过程的状态 = 代码 × 配置 × 数据 × 随机流,前三者用版本管理(git/数据快照)与配置文件钉死,随机流用种子钉死。四处种子的原理:Python 内置 random 与 numpy 各有独立生成器管增强与打乱;PyTorch 的 CPU 与 CUDA 生成器相互独立;DataLoader 的 worker 进程还会再分叉生成器——所以完整固定需要 seed一切 + worker_init_fn + generator 三件套。哪怕全部钉死,GPU 浮点运算的归约顺序仍可能非确定(原子加法),这就是「确定性模式」存在的理由与代价——工程折中是「统计可复现」:固定种子 + 2~3 个种子重复,报告均值±标准差,比单次逐位复现更科学也更便宜。实验记录的最小完备集:一次实验 = {git commit、config 快照、数据版本、随机种子、每 epoch 指标、最终 checkpoint、一句话结论};对比实验的唯一纪律继承 kp-027 的单变量原则。工具谱系:轻量方案用「CSV/JSONL + matplotlib」即可满足本库项目;重型方案(wandb/mlflow/tensorboard)提供面板与对比视图,本库不绑定任何一种(保持零依赖),但记录字段的设计完全通用。

公式或模型

本节不适用——理由:本节为工程流程规范,不含新数学;种子固定的代码清单即其「公式」。

图示

一次实验的完备档案(最小完备集):

exp-021-baseline/
 ├─ config.json        ← 学习率/批大小/增强/种子/epoch……(快照,勿改)
 ├─ git-hash.txt       ← 代码版本
 ├─ metrics.jsonl      ← {epoch, train_loss, val_loss, val_acc, lr, grad_norm}×N
 ├─ best.pt            ← 最优检查点(含 model/optimizer 状态与 epoch)
 └─ notes.md           ← 一句话结论 + 与上一实验的唯一差异

直观类比

配置快照与 git-hash 像「菜谱拍照 + 拍下厨房照片」:三个月后任何人(包括三个月后的你)都能按图复原同一道菜。

实例或案例

kp-016 训练循环的实验化改造(新增部分):

import random, numpy as np, torch, json, time

def set_seed(s=42):
    random.seed(s); np.random.seed(s); torch.manual_seed(s)
    torch.cuda.manual_seed_all(s)          # ① 四处种子
    torch.backends.cudnn.deterministic = True   # ② 折中的确定性
    torch.backends.cudnn.benchmark = False

cfg = dict(lr=1e-3, batch=128, epochs=5, seed=42, dropout=0.2)
set_seed(cfg['seed'])
run_dir = f"runs/{time.strftime('%m%d-%H%M')}-lr{cfg['lr']}"
# 每 epoch: 向 metrics.jsonl 追加一行 json;结束: 保存 config.json + best.pt

对照实验模板:baseline 与 +dropout 两个 run 目录并排,metrics.jsonl 双曲线一画即知结论——kp-021 的「增强开关对照」就是这样执行的。种子间差异实验:同一 config 跑 seed 42/43/44,观察 val_acc 的 ±0.3% 漂移,亲身体会「单次结果不可尽信」。

常见误区

  • 只固定 torch.manual_seed:增强与 shuffle 仍在漂,两次运行曲线不同还以为是 GPU 玄学。
  • 「结果好就当场跑」:不落盘的日志在进程结束后蒸发,过拟合掉的 0.5% 永远说不清来源。
  • checkpoint 只存模型权重:恢复训练或分析优化器动量状态时缺件,应整包保存。
  • 用测试集「顺便看看」当记录习惯:每次查看都在消耗测试集的法律效力(kp-015 的闸门纪律)。

与其他知识点的关系

本节为 kp-027 的单变量实验提供载体、为 kp-021 的里程碑检查提供工具;种子固定是 kp-012/015 中随机性的总开关;「配置与数据版本化」在大规模训练中的升级形态(数据版本控制、分布式检查点)属于 kp-029 的延伸话题。

自测题

  1. 列出深度学习训练中至少四个需要固定种子的随机性来源。

答案要点:权重初始化、数据增强、DataLoader shuffle(含 worker)、CUDA 算子随机性。

  1. 「统计可复现」为什么优于「逐位确定性」?

答案要点:GPU 确定性模式显著拖慢训练;而科学结论本应以多种子均值±方差报告,统计口径更实用。

  1. 一个最小完备的实验档案应包含哪些文件?

答案要点:config 快照、git-hash、逐 epoch 指标流、最优检查点(含优化器状态)、结论笔记。

延伸阅读

  • Pineau 等《Improving Reproducibility in Machine Learning Research»(JMLR 2021,可复现性检查表运动)。
  • Karpathy《A Recipe for Training Neural Networks» 中「 obsess over reproducibility 」一节(与 kp-027 共读)。

学习状态

状态保存在浏览器本地,用于首页与路径页的进度统计。