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

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

拦住它,也记下它

在 TT Lab 中继续学习

一句话总结

重新训练可以自动进行,但晋级必须通过门禁;如果门禁拦住的东西被人强行推过去了,这件事也必须留在记录里。

为什么需要它

搭好重新训练的流水线之后,会出现一个诱惑:既然训练已经结束,干脆一路连到部署。大多数周里什么都不会发生。问题在于,什么都没发生 并不意味着成功。上游数据坏掉了一次的那周,流水线照样亮绿灯,更差的模型就悄悄地上了线。

谷歌整理的 MLOps 成熟度文档把这一点划分得很清楚。让训练流水线自动化(持续训练),与把它的产出放到线上(持续部署),是不同的阶段,而后者中必须夹有模型验证这一步(MLOps: Continuous delivery and automation pipelines in machine learning)。

工作原理

门禁其实就是几行比想象中简单的规则。难的不是定规则,而是 规则要读的数字是不是准备得足够可信。所以前面的那些模块才排在前面。

입력   champion 별칭이 가리키는 버전의 평가 지표
       challenger 별칭이 가리키는 버전의 평가 지표
       데이터 계약 검증 결과
규칙   challenger >= champion + margin  이고  계약 검증 통과
출력   promote | block  +  왜 그렇게 판단했는지

设置余量(margin)的原因是测量噪声。同样的数据,随机种子不同,准确率会在小数点后第三位晃动。余量为 0,光靠这点晃动就会换掉 champion,下周又换一次。这不是部署变频繁,而是 毫无意义地变频繁。

MLflow 在文档里举了一个例子,把这个判断的结果以版本标签的方式附上去。给等待验证的版本加上 validation_status: pending,给通过的版本加上 approved(MLflow Model Registry)。如果把门禁的判定以标签的形式留下来,就可以由自动化而不是人,依据这个条件来选择下一个步骤。

门禁所读的数字来自哪里,也要定好。如果每次都重新抽取评估划分,指标就会晃动,门禁就失去意义;反过来,如果一直只用固定的划分,过拟合到那个划分的模型就会通过门禁。所以通常以固定划分为基准,同时定期追加新的划分,两个数字一起看。

然后是回滚。前面模块里设置别名的原因,在这里得到了回收。回滚就是改变 champion 所指向的版本,这次变更在审计记录里就是一行。如果在记录里把之前的值(from)也写下来,那么从头重放就应当得到现在的状态,得不到,就说明某处有没被记录的变更。只凭这一条性质,“谁在什么时候改了什么”就成了检验,而不是猜测。

门禁的判定必须能让人读懂。如果只留下 block 这一个单词,下一个人就不知道为什么被拦住,会开始怀疑门禁,而被怀疑的门禁很快就会被关掉。所以在判定旁边,要用句子一并留下所比较的两个数字、余量,以及是在哪个条件上被卡住的。

在现场相遇的样子

建好门禁之后,必然会有绕过它的请求。演示就在明天,客户在等,说这次的肯定没问题。这时,与其把门禁关掉,不如设计成 可以无视,但必须把无视这件事留下来,这样更持久。如果想拦住无法拦住的东西,人们就会在门禁之外另开新路,那样连记录都不会留下。

第二种常见的情况,是门禁只看一个指标。只看整体准确率的话,在少数群体上大幅变差的模型也能通过。增加指标很容易,但每增加一个指标,都得定好“变差到什么程度就要拦住”,这需要达成共识。把这个共识写进代码里,才是门禁真正的价值。

第三是回滚之后的沉默。回滚做得很好,却没有人写下那个版本为什么不好,于是两个月后用相近的参数重复同样的错误。

第四是通过门禁之后的观察。晋级不是终点而是起点,需要留出一个窗口,用几天时间观察新的 champion 在线上实际表现如何。所以很多团队会先让挑战者只接一部分流量试一试,然后再移动别名。这时判断的依据也写在同一个地方——如果门禁看到的数字和观察期间看到的数字分散在不同的地方,那么在决定是否回滚的会议上,两个人拿出来的就会是不同的表。

下一项实验要做什么

搭建一个有版本和别名的小型注册表,把重新训练的结果注册为挑战者,并用代码做出带余量的晋级门禁。然后重现门禁拦住的晋级被人强行推过去的局面,回滚之后把审计记录从头重放,检验它与现在的状态是否吻合。最后把输入分布移动了多少用数字表示出来。