11. 实验纪律(从 §5 换来的人话版)
2.6k 字 ·
源文件 PROJECT.md 第 2002 行起 ·
discipline ruler optim
- 先跑自检,再跑实验。 自检不过 = 不许开始。
- 一次只动一个变量。
- 判读标准事先写下来,不要看到结果再解释。
- 多个种子(≥3),报成功率。单次运行不下结论。
- 诚实标注可信度。 5 折 CV ≠ 训练集内准确率。
- 检查结果是否逐位重复 —— 那是训练已死的信号。
- 检查标签分布 —— 常数预测的上界常常就是"好成绩"。
- 判据是"能力的有无",不是准确率的小数点(§1)。
- 自主动力学要消融验证 —— 固定它,行为必须变化,否则它只是装饰。
- 每个门禁都要做负向验证 —— 从没失败过的检查没有说服力。
- ★ 任何"某能力不行"的结论,必须在多个
lr下确认。lr是一个"必要性维度"(exp06:lr=1e-2 全失败;exp14:100ms 在 lr=3e-3 失败、lr=1e-3 成功到 98%)。只在一个lr上测,分不清 "能力不足"和"学习率不对"。这条的代价是一次过早结论(§6.14)。 - 看趋势,别只看终点 —— 用实时面板(§6.15)看"何时开始学",
因为"8000 迭代仍 50%"和"3000 迭代到 98%"可能只差一个
lr。 - ★ 比较两个架构之前,必须先证明基线能学。
exp28第一版跑出"18 个配置 0 个收敛",差点被解读成单元问题。 真因是我没复现已知胜出配置——读出结构、batch、delay、调度器四条全错。 没有门禁时,"0 个收敛"既可能是单元问题也可能是配置问题,两者无法区分。 → 任何 A/B 之前先跑一次已知胜出配置,不收敛就直接退出,不解读。 (这就是 §8.1"先过可学性阶梯,再谈比较"的现场版本。) - ★ 判据必须能失败。 如果一个实验没有失败模式,它不在测任何东西。
例:不训练、直接比零输入下的"有效秩"——换掉映射后状态几乎必然探索更大
区域,
eff_rank必然上升。它必然"成功",而成功的理由与要检验的假设 之间没有逻辑联系。这类实验会给出变好的数字和为零的信息量。 → 判据要建在训练后的指标上(训练过的比较才可以失败)。 - 指标要有校准锚点。 报一个新指标时,必须同时报它的天花板与地板 (例:噪声应 ≫1、线性衰减 0.99^t 应 =0.049、完美保持应 =1.000)。 没有锚点,"retention = 0.31" 这个数字无法解释 —— §5 第 25 条就是这么来的。
- ★ 判据必须是"任务相关"的,不能是"状态看起来"。
本会话连续三套抽象指标(有效秩 / retention / 随机初态探针)全部失败,
而它们一致指向"状态已死"时,任务相关的探针显示内容保持 100%(§5 第 27 条)。
→ 正确形式:把模型冻结,只训线性分类器从
h_t预测任务标签, 看它在关键时刻的可读出性(§6.13 方法)。 → 抽象指标不是不能用,而是只能当辅助,不能当判据。 - ★ 比较训练配方之前,先确认基线在同一个配方下能复现。
exp13(带clip_grad_norm_(1.0)+eta_min=lr×0.05)在lr=1e-3下 主任务准确率是 76.6 / 60.4 / 90.7,而exp28(无 clip、eta_min=0) 在同一个 lr 下是 99.2 / 96.6 / 94.7。同 lr、同结构、差 20–30pp。 → 训练细节(梯度裁剪、lr 下限)是未受控变量,它们的影响可能大于我们 正在比较的那些变量。任何 A/B 之前先把训练配方固定并复现。 - ★★ 种子数必须按失败率算,不能一律写 "≥3"。
本会话实测:
u64/b64的 5 种子末刻可读出性是75.2 / 98.7 / 89.0 / **50.6** / 75.0—— 有一个种子整轮失败。 于是 3 种子给出 87.6%(通过判据),5 种子给出 77.7%(不通过)。 → 若真实失败率p,则n个种子全部成功的概率是(1−p)^n:p=0.2, n=3→ 51%(一半概率漏掉!);n=5→ 33%;n=11→ 8.6% → 要有 90% 把握看到至少一次失败,需要n ≥ ln(0.1)/ln(1−p) ≈ 11(p=0.2)。 规则:跑之前先声明"我要检测多小的失败率",据此定种子数。 一律写 "≥3" 会让约 20% 的失败率有一半概率被漏掉 —— 我们刚刚亲身示范了。 - ★★ 做对照实验的脚本,必须和被测脚本跑在同一个设备上,并打印设备。
本条是一次错误结论的存档。
diag_seed_failure忘了.to(device), 于是它在 CPU 上跑,而exp13在 GPU 上跑:seed=4 / u32/b64的base条件 —— GPU 给 0.507,CPU 给 0.931。 我据此写了"同进程内连续跑多种子会泄漏状态"这个结论,方向完全错了(§5 第 29 条)。 → 规则:①对照脚本必须--device可指定且默认与主实验一致; ②输出里必须打印实际设备;③跨设备的结果不可直接比较。 → 附带教训:一个"数字看着合理、判读很自信"的结果,也可能测的是另一个东西。