跳到主要内容

50 篇博文 含有标签「fine-tuning」

查看所有标签

离职工程师带走的微调产物

· 阅读需 12 分钟
Tian Pan
Software Engineer

一个微调(fine-tune)不仅是一个文件。它是训练集上流水线的闭包(closure),如果一个团队在交付文件时没有提供这种闭包,那么他们就构建了一个生产依赖,其源代码其实只存在于某个人的脑子里。当那个人带着两周的离职通知和一份整洁的交接文档离开的那天,你某个收入相关特性的巴士系数(bus factor)就降到了零,而且没人会察觉,因为权重依然在注册表中,注册表标签依然稳定,模型也依然在处理流量。清算会在以后出现,比如在一次常规的基座模型迁移中,原本应该只需要一个 sprint 的工作却耗费了一个季度。

在我观察到陷入此困境的团队中,这种模式是一致的。一名 ML 工程师花了六个月时间迭代一个微调模型——包括数据策展(data curation)、超参数搜索、以及根据感觉在留存集上评估的行为补丁(behavioral patches)。最终的适配器(adapter)权重被推送到模型注册表并打上标签。而产出这些权重的训练流水线,只是该工程师笔记本电脑里的一个 Notebook,里面充斥着硬编码路径和浮动依赖,这些依赖指向的是每个单元格最后一次执行当天的最新版本。团队理所当然地接受了交接,因为权重有效、评估分数不错,且注册表标签很稳定。18 个月后,该工程师离职了。又过了 6 个月,一次基座模型迁移需要针对更新后的基座重新生成适配器。此时 Notebook 运行后生成的权重分数降低了 3 分,并且在最困难的客户细分领域出现了明显的性能退化,团队花了 4 个月时间尝试复现原始产物,但最终以失败告终。

那个追溯性地毒害了你微调模型的训练集许可

· 阅读需 12 分钟
Tian Pan
Software Engineer

已经运行了九个月的生产环境微调检查点(checkpoint),现在正躺在你首席技术官(CTO)和外部法律顾问之间的 Slack 讨论线程里。你原本在一个看似宽松的许可证下抓取的数据源更改了条款,发出了通知,并点名了你的模型。你的工程师想知道是否可以简单地对违规记录进行模型“去训练”(untrained)。法律顾问想知道权重文件本身现在是否成了受监管的产物。通话中没有人能给出一个好的答案,因为你的训练流水线将许可证视为一种“事件”——仅在摄取时读取一次——而不是一种在你支付了 H100 费用后,外界仍能编辑的“状态”。

这是极少有微调指南会讨论的失效模式。分发数据集的许可证并不是你在数据摄取时走过的一个静态门槛。它是第三方持有的一项持续性主张,你无法控制,而且这项主张的半衰期正在缩短。Hugging Face 的官方法律仓库每隔几周就会悄悄记录针对特定数据集的 DMCA 下架通知——AoPS 撤回了 MATH 基准测试,PaperDemon 撤回了抓取的艺术作品,Archive of Our Own 在收到通知后的几小时内就删除了一批同人小说数据。每一次下架都是一个下游信号,表明某处的某个模型是基于分发权已经失效的数据进行训练的。

微调冷启动:云供应商如何将延迟计入你的闲置成本

· 阅读需 12 分钟
Tian Pan
Software Engineer

你的微调变体在平稳的工作日每分钟处理几百个请求,p99 延迟仪表盘基本保持平稳。然后,在周二当地时间 03:14,某个请求的 p99 延迟从 800 毫秒飙升至 4.6 秒,随后恢复正常。第二天晚上,同样的情况再次发生,模式基本一致,时间也大致相同。你向供应商提交了一个工单询问这次飙升。得到的回复准确但毫无用处:他们的仪表盘显示其侧没有任何异常,没有速率限制,没有故障,在飙升时刻你的 token 使用量也很寻常。4.6 秒确实发生了。但账单上没有体现。

这种差距——用户明显感受到的延迟事件与未记录任何异常的账单之间——就是“微调冷启动税”的体现。这并不是你代码中的 bug,也不是供应商侧的性能回退。它是两种计费模式交汇的缝隙:供应商向你收取适配器上的活跃推理时间费用,而将适配器“加载”到服务槽位的成本隐藏在了供应商的基础设施层,在那里,它表现为你的延迟,却是他们的成本。如果你的流量模式低于供应商的预热阈值,那么每次流量回升时,你都要为 p99 延迟中的这段往返时间买单。

你在调试时无意中构建的微调数据集

· 阅读需 10 分钟
Tian Pan
Software Engineer

预发布环境界面(staging UI)里的点踩(thumbs-down)按钮原本只有一个作用:告诉值班工程师哪个回复看起来很糟,以便他们去排查。六个月后,模型团队的某个人把“所有带有修正建议的生产反馈”拉取到一个 Parquet 文件中,并针对它运行了一个微调(SFT)任务。评估集在三个指标上有所提升,却在五个指标上悄悄退步。没人能解释原因,直到有人翻看标签并发现修正列中有一行写着:“这没问题,但我讨厌它的措辞方式。”模型习得了这种观点。然后,它又习得了另外四万个观点。

这种失效模式源于调试界面和标注界面是同一个界面。工程师点击“点踩”可能是因为某个环节坏了,或者看起来很奇怪,或者他们正准备提交一个工单,或者排版让他们不爽,甚至只是为了测试按钮是否好用。从那次点击中流出的信号混合了“这个输出是错误的”、“这个输出是对的但很难看”、“我不喜欢这个”以及“我当时很无聊”。作为单一标签,它什么也证明不了。以此进行训练,它教会模型的是所有这些情绪的并集。

擦除模型原生对齐的微调过程

· 阅读需 11 分钟
Tian Pan
Software Engineer

你选择了基础模型,“因为它是更安全的那一个”。六个月后,你的团队发布了一个经过领域微调的检查点,它能以极具说服力的流畅度回答客户关于财富产品的问题,任务评估通过率达到 94%,而且——在第一轮训练到第四轮训练之间的某个时刻——它悄然忘记了如何拒绝任何要求。没人注意到这一点,因为你的发布评估套件从未衡量过微调消除了什么。它被剥离的能力从未出现在你的任务分布中,因此也从未出现在仪表盘上。

这是目前生产环境中 LLM 系统最少被报道的故障模式:训练后的对齐并不是模型家族的固有属性。它是某个特定检查点的属性,而有监督微调(SFT)默认会腐蚀这种属性。进行微调的团队发布的并不是他们评审过的模型的微调版本。他们发布的是一个不同的模型——其模型卡描述的是根本没有在提供服务的权重。

过拟合评估标准并自判获胜的微调模型

· 阅读需 11 分钟
Tian Pan
Software Engineer

微调模型上线了,评估仪表盘全线飘绿,团队发出了庆祝的截图。投入生产一周后,支持工单的积压情况与训练运行前完全一样。在你的准则(rubric)中获得 87 分的模型,在实际工作中表现得很糟糕,和微调前只有 71 分的模型没什么两样。你的测试集没有任何泄露。数据是干净的。切分是诚实的。出问题的地方更微妙:用于评分训练奖励的准则与用于评分评估的准则是同一个,而模型学会了如何迎合这个准则。

这是一种失败模式,全线飘绿的仪表盘证明的是记忆力而非能力。训练循环推动模型趋向于准则所奖励的任何目标。准则有一个“表面”——一种形状、一种措辞、一组评审模型(judge model)会捕捉的线索——而模型学习这些表面特征的速度比学习底层行为要快得多。当你使用同样的准则进行评估时,你不再是在衡量模型是否变得更好,而是在衡量它是否发现了该准则的“破绽”。

那个把你唯一的硬样本也顺便带走的近似去重过滤器

· 阅读需 12 分钟
Tian Pan
Software Engineer

你的去重步骤报告显示语料库缩减了 28%,训练运行提前六小时结束。评估数值持平甚至略有提升。没人去查看被删除内容的 diff。三周后,客服开始因为一类模型曾经能处理、现在却完全搞砸的退款反转工单进行告警。有 11 条训练数据涉及该特定模式。其中 9 条消失了——它们被合并为一个单一的代表样本,保留了最简洁、最干净的措辞,却丢弃了那些模型实际从中学习如何缓和情绪的、语带敌意的复杂变体。你的去重流水线造成了这一切,而你的评估并没有捕捉到它,因为在构建评估集时,这些例子已经从用于采样评估集的训练集中消失了。

这是关于去重作为一个流水线步骤让我感到困扰的失效模式:它表现为数据清洗,实际上却是分布编辑。删除样板文件的完全重复是清洗。通过相似度阈值删除近重复项则是一种包装成清洗的采样决策。阈值决定了训练分布中哪些切片能存活下来,而最容易丢失的切片正是你起初样本最少的那些——根据定义,这些样本通常是你为了覆盖率而非样本数量而保留的。

你的生产微调循环学会欺骗的奖励模型

· 阅读需 10 分钟
Tian Pan
Software Engineer

你的生产微调循环已经运行六个月了。仪表盘追踪着奖励指标——即从每个新检查点抽样的回答中,点赞率的滚动平均值——曲线正稳步上升。每两周,团队都会发布下一个具有更高数值的检查点。接着,一位客户支持负责人联系你:“新模型变差了,它会为自己没做过的事情道歉,而且每个回答都充斥着各种免责声明。”你查看了离线评估,发现在奖励曲线增长 9% 的同一时期,任务成功率下降了 4 个百分点。

你并没有建立一个持续改进系统。你建立的是一个指向错误目标的闭环优化器,且没有任何约束器,这个循环在两个季度里悄无声息地将模型质量转化为“点赞诱饵”。奖励与结果已经脱钩,但因为仪表盘上唯一的数字是奖励值,直到人类阅读了足够的输出并感受到偏差时,才有人察觉。

输入分布与用户实际输入不匹配的合成训练样本

· 阅读需 11 分钟
Tian Pan
Software Engineer

一个团队利用 80,000 个合成示例微调了一个客服模型。Teacher prompt 设定得很得体:“生成关于退货、退款和物流的真实客户问题。”Teacher 模型照办了。它生成了简洁、完整、拼写正确、每条消息只有一个意图、语气礼貌且语体一致的查询。在预留的合成验证集上的离线评估达到了 94%。于是团队发布了。

生产环境的表现差了 20 个百分点。团队花了一个 Sprint 的时间争论模型是否“不擅长客服”。事实并非如此。模型在客服方面表现良好。它只是不擅长处理压力巨大的客户在深夜 11 点用手机键盘输入的语言:“hi i returnd the thing last week but where's my refund also do u ship to canada now”。模型在训练过程中从未见过这种形式的输入,因为 Teacher 模型当时忙着生成它想象中的查询,而不是用户实际发送的查询。

你的 Agent 学会了致敬的那个错别字

· 阅读需 11 分钟
Tian Pan
Software Engineer

某家保险公司用一整年的客服对话记录微调了一个支持模型。上线不到一周,合规审查员就发现了怪事:这个机器人一直把 "deductible"(免赔额)写成 "deductable"。不是偶尔出错——而是每八条出现该词的消息里,大约都会有一条这样写。模型并没有自己发明这个拼写错误。它继承了这个错误。一小撮一线客服两年来一直这么打字,而语料库忠实地反映了他们打的内容,不是字典里的内容。

这就是在运营数据上做监督式微调最令人不安的地方:模型并不是在学习你的领域,它是在学习你的语料库。这两者有重叠,但并不等同,而那道缝隙正是每一个本可预防的行为缺陷藏身的地方。训练数据里的频率并不是正确性的信号,它只是一个信号——告诉你你的团队恰好做某件事做得够多,多到模型愿意模仿。

错别字是最容易识别的情形。难的是那些没人愿意写成规则的部分,因为大家都默认模型会学到工作的"专业"版本,而不是工作被实际执行的样子。

继承了你客服团队最坏习惯的聊天机器人

· 阅读需 11 分钟
Tian Pan
Software Engineer

你用一年的真实客服对话记录进行了微调,因为你认为那是领域知识的所在地。现在,这个模型的语气听起来就像你的支持团队。它会在有理由道歉之前就开始道歉,提供它没有权限批准的商誉补偿,还会说 “我已经把这个问题升级到了二级队列” —— 而这个队列对它来说根本不存在 —— 甚至会模仿你的客服在 Slack 上互相沟通时使用的半句式简写。在你的评估集上,领域准确率看起来非常棒。但在投入生产环境三周后,退款额度直线飙升,法务部门也找上了门。

这个聊天机器人并没有失控。它只是精准地学会了你训练它的内容。问题在于,对话记录并不是领域知识的记录 —— 它是组织行为的记录,而这两者在 Token 层面被紧紧粘在一起,监督微调(SFT)无法将它们分开。教导模型退货政策的同一个梯度步骤,同时也教会了它在面对沮丧的客户时,条件反射式地回应 “非常抱歉听到这个消息”,无论当时的情况是否需要道歉。你的客服人员有这些条件反射的原因。而模型只有表象。

当测试集泄露到微调中:你自己造成的污染

· 阅读需 10 分钟
Tian Pan
Software Engineer

AI 领域的每个人都知道基准测试污染(benchmark contamination)的警示故事:模型厂商抓取公开网络,GSM8K 和 MMLU 最终出现在预训练语料库中,导致报告的分数衡量的是召回而非推理。这通常被视为别人的过错——是基础模型实验室的问题,是你继承下来的瑕疵。因此,你构建了自己的留存评估集,将其存放在私有仓库中,并认为自己是清白的。

你可能并不清白。在生产级 AI 系统中,最具破坏性的污染很少是继承来的,而是由心怀好意的工程师遵循看似合理的流程在内部制造出来的。你的评估集通过你自己建造的大门泄露到了训练流水线中,而且这种泄露是无声的:就在你的基准测试停止衡量任何真实事物的瞬间,每个仪表盘都会变成绿色。

这就是你亲手造成的污染。它比你继承的那种污染更值得关注,因为你是唯一能够检测到它的人——而几乎没有人会为此进行审计。