跳转到内容

研究代码的组织

研究代码不需要生产级质量,但需要:配置与代码分离、实验入口统一、结果自动记录、关键函数有测试。本章给出一个轻量的项目模板,以及何时该重构、何时该扔掉重写。

定位:研究代码不需要生产级质量

Section titled “定位:研究代码不需要生产级质量”

研究代码的生命周期是一次性的(一个项目、一轮实验),不需要生产级质量——过度设计(抽象层、通用框架、完美测试覆盖)会拖慢迭代,而迭代速度是研究的生命线(见实验设计)。

但它需要最低限度的纪律,否则两周后你自己都跑不起来了:

  • 配置与代码分离:实验的所有可变项(超参、路径、开关)在配置文件里,命令行只传配置路径。这是"每个实验可追溯"的前提(见可复现性);
  • 实验入口统一:run.py --config xxx 一个入口跑所有实验,禁止复制脚本改参数——复制的脚本会在一周内分叉成无法维护的十份;
  • 结果自动记录:指标、日志、配置快照在代码里自动落盘,靠人手抄的记录一定会丢;
  • 关键函数有测试:只测两类东西——数据加载与预处理、评测逻辑。评测代码的 bug 比训练代码的 bug 代价大一个数量级:它悄悄污染所有结论。模型前向传播可以靠小规模过拟合检查,评测逻辑必须单测。

notebook 用于探索,脚本用于实验。 Jupyter notebook 适合探索数据、画图、快速验证想法;但它有隐藏状态(cell 执行顺序),不可作为实验入口。探索成熟后,把 notebook 里的逻辑固化成脚本与函数——判断标准:这段逻辑第二次被用到时,就该离开 notebook。

  • 该重构的信号:改一个实验要动三处以上的文件;配置里出现了条件分支的逻辑;两个实验的公共代码开始漂移。小幅重构(提取公共函数、清理配置)值得马上做。
  • 该重写的信号:核心数据流已经与最初设计不符;"能跑"依赖一两个没人理解的补丁;新同学三天读不懂主流程。扔掉重写前,把可复用的部分(数据处理、评测)提出来——评测与数据加载代码值得带进下一个项目,训练逻辑通常不值得。
  • 配置文件驱动实验,命令行只传配置路径
  • 数据加载与评测代码值得写测试
  • notebook 用于探索,脚本用于实验