拿到一个开源或托管的预训练模型,想让它懂你的业务,第一步往往不是打开训练脚本,而是决定「动哪里」。很多人一上手就全量重训,卡烧完效果还不如提示词;也有人只改了学习率就以为在微调。这篇按判断顺序拆成几段:先分清冻结、适配器和全量改动的代价,再看数据与显存怎么定规模,最后给一套验收与回退的动作清单。数字类的部分都指到站内页面现查。
先定改哪一层:冻结、适配器还是全量
决定微调改哪一层,先别急着看工具,先回答一个问题:你的任务离预训练模型见过的分布有多远。离得近,动的层就少;离得远,才往上加。判断错了,要么白花算力,要么把基座能力带偏。
| 任务特征 | 建议改动层 | 原因 |
|---|---|---|
| 只是输出风格、格式、话术差异 | 冻结主干 + 轻量适配层 | 主干已有能力,只需引导输出形态 |
| 要学新领域词汇、术语体系 | 适配层加深,或部分解冻上层 | 新词表映射需要更多可调参数 |
| 要学完整推理链、多步决策 | 解冻更多层或全量 | 推理模式藏在深层,旁路不够用 |
| 要换分词器或改输出头结构 | 不在适配器范围 | 结构变了,旁路权重无法承载 |
适配器类方法(LoRA 这一类)改的是旁路权重,主干不动。好处很直接:训练显存小、单任务产出体积小、一份基座可以挂多个任务。代价在部署侧——推理时多一层合并或挂载,服务链路要跟着调,延迟和显存峰值都得重新测。训练省下来的钱,可能花在推理链路上。
全量微调不等于更认真。它会同时改掉基座原有的能力,小数据下更容易把通用能力带偏,而且每个下游任务要存一份完整权重,运维成本按任务数线性上涨。只有当任务确实需要深层改动、且你手上有足够数据兜住基座能力时,全量才划算。什么情况下不适用:如果你要的是换掉分词器或改输出头结构,适配器那套就不成立,得走继续预训练或改结构的路线。
- 先看任务离分布多远把任务拆成“风格差异”和“新知识新推理”两类,如果只有前者,从冻结主干加适配层试起。
- 再确认服务商支持范围到站内的模型与服务商资料库核对,看目标基座支持哪些微调方式、是否支持适配器挂载,别等训练完才发现部署不了。
- 估部署链路成本适配器方案要把合并或挂载那一步算进推理延迟和显存,测一遍真实请求再决定。
- 评估运维放大效应如果下游任务会持续增加,算一算全量方案下每任务一份权重的存储与切换成本,和适配器方案对比。
再定数据规模与显存:别用感觉拍数
数据规模这件事最容易犯的错,就是先想「我要准备多少条」,再去找数据。顺序反了。应该先看质量分布:同一件事,你的数据里有多少种写法,覆盖了哪些边角情况,标注口径是不是一套。分布看清楚了,条数才有意义。
| 先问的问题 | 怎么看 | 不合格的信号 |
|---|---|---|
| 同一意图有几种表达 | 抽样 20 条,按语义归类 | 同义句式反复堆,覆盖面窄 |
| 标注是否一致 | 两人独立标同一批,比对分歧 | 分歧集中在边界样本上 |
| 难例占比多少 | 标出模型现有版本会答错的 | 全是简单样本,指标虚高 |
| 留出集来源 | 和训练集是否出自同一批模板 | 同一模板切分,算作弊 |
- 第一步 定任务类型先判断你做的是分类、抽取、改写还是对话风格对齐。不同类型对条数的敏感度差别很大,去站内的微调数据集相关页面,按你这类任务找经验区间,别照搬别的任务的数字。
- 第二步 切分留出集留出集必须来自真实分布,不能是训练集同一批模板换几个词。做法是:按来源、时间或渠道切,而不是随机切。切完检查两边关键词分布是否明显不同。
- 第三步 估显存按三步走:先定基座规模,再定量化方式与优化器状态占多少,最后定序列长度和批大小。到 /models/deploy 用站内的测算口径过一遍,看单卡能不能装下。
- 第四步 决定训练方式如果全参装不下,先考虑参数高效方法,再考虑降序列长度或批大小。注意调参空间和显存是绑在一起的,不要一边想大 batch 一边想省显存。
- 同一件事的写法覆盖,比总条数更能决定泛化;覆盖窄,条数再多也是重复。
- 标注一致性靠抽查,不靠感觉;分歧率高的类别,先修标注再谈训练。
- 留出集要能代表线上会遇到的输入,包括那些你不太想看到的脏数据。
- 显存估算要留余量,实际占用常比纸面测算高,具体差多少去 /models/deploy 的测算页面核对。
- 训练方式的选择顺序是:能全参就全参,装不下再上参数高效,最后才动序列长度和批大小。
训练这步:盯住三个会翻车的点
训练这步真正容易翻车的地方不多,但每一个都够你白烧一整天卡。下面这三个点建议按顺序盯:学习率和轮数、通用能力有没有被练废、结果能不能复刻。三者里任何一个失控,后面调出来的好东西都是运气。
| 翻车点 | 典型症状 | 先做的事 |
|---|---|---|
| 学习率与轮数 | 训练损失还在降,留出集反而变差 | 用小步数试探,看两条曲线是否同向 |
| 灾难性遗忘 | 原来的通用问答、改写、抽取明显退步 | 跑一组固定问题做前后对比 |
| 可复现性 | 同一份数据换个人跑不出同样结果 | 固定种子、记录数据版本与完整配置 |
学习率与轮数:先试探,别一上来就冲
小数据配大学习率是最常见的带跑模型方式:样本少,梯度更新次数却不少,模型很容易把这几百条背下来。做法是先跑一个很小的步数做试探,同时看训练损失和留出集表现。两条一起往下走,说明还在学规律,可以再加;训练损失降、留出集开始往上拐,就该停在这一档,别继续加轮数。判断标准是「同向下降」而不是「训练损失够低」。
- 先定小步数试探用很小的步数跑一轮,只看趋势不看最终值,目的是拿到两条曲线的前半段。
- 对比两条曲线训练损失和留出集指标同向下降就继续加步数;出现分叉立刻回退到分叉前的配置。
- 确认留出集来源干净留出集必须和训练集没有重叠、没有同源改写,否则曲线好看也是假的。
- 再上正式训练把试探出来的合理区间作为正式训练的起点,中途按固定间隔存检查点。
灾难性遗忘:拿一组固定问题做前后对比
微调之后模型在你关心的任务上变好了,但它原本会做的通用任务可能退化了,比如概括、改写、结构化抽取、简单推理。这件事不能靠感觉,要准备一组固定的通用问题,在微调前后各跑一次,逐条比对。退化明显的话,两个方向可选:一是掺入一部分通用数据一起训,二是调整损失让模型不要偏离原分布太远。具体用哪种,取决于你手上的数据量和算力预算。
- 固定问题集要覆盖概括、改写、抽取、简单推理这几类通用能力,条目不要临时换
- 前后各跑一次并保存原始输出,避免只凭印象判断
- 退化集中出现在某几类任务上时,优先补对应类型的通用数据
- 如果业务本身只关心单一任务、且能接受通用能力下降,可以放宽这条
可复现:调出好结果只是第一步
随机种子、数据版本、训练配置如果没记录,调出来的好结果就是一次性的。团队里换个人、换台机器重跑,得到的是另一个模型,之前所有对比结论作废。所以训练一开始就把种子固定住,把数据处理的版本、切分方式、超参和代码提交都存下来,和模型检查点放在一起。这样别人拿到记录能复跑,你自己过两周也能复跑。
- 随机种子
- 固定它,才能让数据打乱和初始化在同一套条件下重来
- 数据版本
- 数据清洗和切分规则变了,等于换了训练集,必须记下来
- 配置快照
- 超参、代码提交、环境一起存,和检查点放同一目录
排查顺序颠倒,等于白烧卡时
出问题时最容易犯的错是先怀疑基座选错了。实际上数据泄漏、学习率不合适这两件事的发生概率远高于基座问题,而且改起来快、代价小。建议的排查顺序是先查数据是否有泄漏或分布问题,再调学习率和轮数,最后才考虑换基座。按这个顺序走,多数问题在前两步就能定位;反过来先换基座重训,一轮下来时间和算力都花掉了,问题可能还在原地。
训练出问题,先怀疑数据和超参,最后才怀疑基座——顺序对了,卡时才不白烧。下一步把留出集切分规则、种子记录格式和固定通用问题集先落成模板,再开始正式训练;具体工具和流程模板可以到站内工具目录与指南中心对照使用。→
验收与上线:先定回退条件再谈效果
微调项目最常见的翻车方式,是效果还没定论就先想着上线。更稳的顺序是反过来:先把「什么情况必须退回去」写清楚,再谈效果好不好。回退条件不是技术团队的自我怀疑,而是给业务方的一个安全承诺——出了问题有明确的动作和时间点,而不是上线后临时开会决定要不要停。
| 验收维度 | 看什么 | 什么情况下这一项不适用 |
|---|---|---|
| 单一自动指标 | 只能作为筛选信号,不能作为通过与否的唯一依据 | 任务本身有客观唯一答案、且评测集与线上分布一致时可以放宽 |
| 业务关键样例 | 人工逐条过,重点看边界输入和不该被改动的行为 | 纯生成类、无固定正确答案的任务,改成人工打分或偏好对比 |
| 不该改的行为 | 原来正常的能力有没有被顺手改坏 | 新任务与原有能力完全不共享输入时,这一项权重降低 |
| 合并后一致性 | 合并推理和适配器推理跑同一批输入,结果是否一致 | 只保留适配器不合并部署时,改为检验加载路径是否稳定 |
人工过样例别铺太开。挑十到三十条就够,覆盖三类:正常输入、踩边界的输入、以及你压根不希望模型动它的输入。第三类最容易被忽略,也最容易出事——原来答得好好的问题,被微调带偏了,业务方第一个发现。每条样例记录「期望表现」和「实际表现」,别只写「感觉还行」。
- 跑合并前后的一致性对比用同一批输入,分别在合并前(适配器加载推理)和合并后(权重已合回主干)各跑一遍,逐条比对输出。差异超过预期的条目要逐条定位,别整体看个大概就放过。
- 确认合并与部署链路能走通在测试环境把完整流程走一遍:权重合回、模型导出、加载、起服务、打请求。重点确认线上加载的到底是合并后的主干,还是漏带了适配器。
- 写好回退脚本并演练一次回退动作要有现成脚本,比如切回原基座、切回提示词方案、回滚到上一版权重。上线前真的执行一次,确认几分钟内能切回去,而不是等到出事才现找命令。
- 把成本和周期对齐站内口径预算和排期别用记忆里的数字,去站内页面按当时的报价和方案口径核算,把训练、评测、部署、回退演练的时间都算进去。
成本和周期这两件事,最忌讳拍脑袋。训练要多久、评测要多久、部署和回退演练占多少人力,这些口径会随方案变。做预算时到 /compute/finetune 看当时的算力报价,到 /stacks/fine-tuning 看当时的方案口径,两边对上了再写进排期,别拿印象里的数字去和业务方承诺。
下一步把回退条件、关键样例清单和合并一致性比对表落成一份上线检查单,再走一遍部署流程。相关的算力报价与方案口径,到站内对应页面按当时的数字核对。→常见问题
微调一定比提示词和 RAG 效果好吗?
不一定。任务只是要求输出格式、角色语气,提示词往往够用;知识随时更新的事实问答,RAG 更省事。微调的优势在稳定改变模型的输出行为与风格,让同一类输入每次都对。三条路的分界可以对照 /stacks/vector-dbs 与站内微调服务目录一起判断,别默认微调是升级版。
只有几百条数据,还有必要微调吗?
看任务是否高度同质。几百条高度一致的样本,用参数高效方法做风格与格式对齐是有意义的;要让模型学会一个它完全没见过的领域,这点量通常不够,先去补数据或改用检索。具体规模判断按任务类型到 /training 查经验区间,再决定投入。
微调完的模型怎么部署,和原模型冲突吗?
适配器类方法产出的是增量权重,部署时要么运行时挂载,要么先合并回主干再按普通模型加载,两条路推理结果要对比一致。合并后的权重要单独存版本,别直接覆盖原基座。合并到部署的完整流程和常见坑,站内已有专文讲透,这里只提醒先定版本命名规则再动手。