TT Lab
开始
学习 学习路径 课程

上周那个模型更好,可没人找得到

谁也找不到上周那个模型

在 TT Lab 中继续学习

目标

把一次训练做成“运行(run)”这个记录单位,把参数、指标、代码和数据指纹留在账本里,使以后能把那次运行重新复现。最后,用真实的日志确认没有留下记录的运行是如何消失的。

为什么重要

把模型做好,和把那个模型重新做出来,是两件不同的事。训练同时依赖随机数种子、数据版本和预处理代码,其中只要有一样没有写下来,两个月后就不会再得到同样的数字。实验跟踪工具所做的,不是漂亮的图表,而是 强制把足以让一次训练重新立起来的事实写下来。这里要亲自设计这个最小集合——亲手填一遍工具自动填好的那些格子,以后看到那些格子空着的账本,就能立刻察觉。

步骤

  1. 实验定义——先写下要最大化什么。
  2. 把第一次运行以一行写进账本。
  3. 改变参数,把运行增加到 4 个以上。
  4. 给所有运行加上代码和数据指纹。
  5. 用目标指标,从账本里重新挑出最佳运行。
  6. 只凭记录复现那次运行。
  7. 调查没有留下记录就消失的运行。
  8. 把账本导出成能独立成立的一包。

参考

先写下什么算做得好

把实验定义保存到 /root/mlops/experiment.json。name 是 churn-baseline,objective_metric 是 valid_accuracy,direction 是 max,owner 是负责人姓名(2 个字符以上),dataset 是 /opt/fixtures/mlops/train.csv。

如果在选定指标之前就开始实验,以后就会挑对自己有利的数字。先把要最大化什么定死。

把第一次运行以一行写进账本

运行一次 /opt/fixtures/mlops/train_model.py,把结果以一行 JSON 记到 /root/mlops/runs.jsonl。一行中包含 run_id、params(lr、epochs、seed)、metrics(valid_accuracy、train_accuracy)、data(train、valid 路径)、started_at。指标原样抄写运行输出。

训练器会向标准输出打印一个 JSON 对象。不要用手去抄那些值,而是在 Python 里接收下来写进账本,这样就不会在抄写时出错。

再跑四次,做到可以比较

用不同的 lr、epochs、seed 组合增加运行,在 /root/mlops/runs.jsonl 里留下 4 个以上。run_id 每次运行必须不同,同样的参数组合不能写两次。每一行的指标都必须与用这些参数重新运行时得到的值相同。

把参数列表放在代码里循环,五行就一次做出来了。评分器会用每一行的参数重新运行训练器,并核对指标。

给代码和数据打上指纹

在 /root/mlops/runs.jsonl 的所有行里加入 code_sha256 和 data_sha256。code_sha256 是 /opt/fixtures/mlops/train_model.py 的、data_sha256 是 /opt/fixtures/mlops/train.csv 的 SHA-256 十六进制字符串。

即使参数相同,只要训练代码或数据变了,就是不同的实验。用 hashlib.sha256 对文件字节做哈希。

从账本里重新挑出最好的运行

读取 /root/mlops/experiment.json 的目标指标和方向,从 /root/mlops/runs.jsonl 中挑出最好的运行,把 run_id、metric、value、selected_by 保存到 /root/mlops/best.json。并列时,选账本中先出现的运行。

不要用眼睛挑,要用代码挑。如果由人来挑,下周再挑一次就会得出不同的答案。

只凭记录把那次运行复现出来

从 /root/mlops/runs.jsonl 中读取 /root/mlops/best.json 所挑选的运行的参数,重新运行训练器,把结果以 run_id、params、valid_accuracy、matches、code_sha256、data_sha256 保存到 /root/mlops/reproduce.json。matches 在与账本的值相同时为布尔值 true。

复现靠的不是“记忆”,而是“记录”。只使用账本里写的参数,字符串 "true" 不是布尔值。

调查没有留下记录就消失的运行

/opt/fixtures/mlops/ghost_run.log 是上周有人运行的一次运行的日志片段。把 ghost_metric(日志中写的值)、best_recorded_metric(/root/mlops/runs.jsonl 的最高值)、gap(两者之差,四舍五入到小数点后第四位)、reproducible、missing_fields(仅凭日志无法得知的运行记录字段,按字典序)、recovery_plan(40 个字符以上)保存到 /root/mlops/incident.json。

从日志里能读出来的只有一个指标。数一数运行记录应具备的字段中哪些是空的,就能看出为什么无法复现。

会话结束之前把账本带出去

把 runs.jsonl、experiment.json、best.json 复制到 /root/mlops/export/ 下,并把 experiment、run_count、best_run_id、files 保存到 /root/mlops/export/manifest.json。files 的每一项包含 path(只有文件名,不带目录)、sha256、bytes,best_run_id 必须是从所装入的账本里重新计算得到的值。

实验 Pod 没有卷,会话一结束 /root 就消失了。这一包必须能独立成立——只有账本而没有目标,以后就无法解释。