🧠 第五章 模型微调:让AI训练效果达到预期
📄 一句话概括

200 条数据里 9 条末条不是 assistant,格式合格 191 条(95.5%),训练/验证分到 171/20。 五步走完, 真正的时间分布是 校验 20%、统计 10%、训练 40%、评估 20%、登记 10%—— 训练那 40% 是机器在跑,前面两步才是人真正要花心思的地方。

📝 本节和前面几节的关系

前两节讲清了微调是什么、该不该用。这一节讲怎么下手:用什么工具、按什么顺序、每一步产出什么。

一、工具分三层,先选层再选产品

第一层:托管平台。 上传一份 jsonl、点几下、等它训完,给你一个模型名。 OpenAI Platform、各家云厂商的微调服务都在这一层。 优点是省事,缺点是不能改损失函数、不能换结构。 第二层:开源框架。 LoRA、QLoRA 那一套,配一份 yaml、跑一条命令, 能在单卡上微调 7B 到 13B 的模型。优点是便宜、可控,缺点是要懂一点训练。 第三层:自己写训练循环。 用 PyTorch 或 JAX 从 dataloader 写起。 这一层几乎只在研究和特殊需求时才用——绝大多数业务不需要。 选层的判断很简单: 需求能用「一份数据 + 一个标准接口」表达清楚,就走第一层;需要私有部署或成本敏感,走第二层; 两层都满足不了,再考虑第三层。 下面 Demo 用的是第三层的极简版(numpy 手写 softmax 回归), 因为沙箱里没有 GPU、没有 transformers。但五步流程在三层里是一模一样的——这才是要看的东西。

二、五步流程,每步都有产出物

第一步:格式校验。 每条样本是不是 messages 数组、首条是不是 system、末条是不是 assistant、 有没有空回答。产出是一份「坏样本清单」。 第二步:划分。 通常 9:1 或 8:2 分训练集和验证集。 产出是两个文件——没有验证集,后面所有评估都是自欺欺人。 第三步:统计。 条数、长度分布、估算 token 总量。产出是一份数据说明书,也顺带算出训练费。 第四步:训练。 真跑,挂机等。产出是权重或模型名,以及训练日志。 第五步:评估。 不只看验证损失,还要抽一批样本人工读。 产出是「能不能上线」的判断,以及一份登记表。 这五步里,只有第四步是机器在跑。前两步的产出物如果在半年后找不到,第二次微调就要从头再来一遍。

三、时间分布:训练只占四成

经验值大致是这样:

步骤 时间占比 是不是人盯着
① 数据格式校验 20% 要,而且最容易出事
② 划分与统计 10% 要,产出数据说明书
③ 训练 40% 不用,挂机等
④ 评估 20% 要,看样例不只看数字
⑤ 保存与登记 10% 要,决定下次能不能复用
训练那 40% 是机器在跑,人可以走开;前面那 30% 才是人真正要花的心思。这一点和很多人的直觉相反——
大家以为微调的难点在「训」,其实难点在「喂什么进去」。
还有一条:第三步的统计结果要存档。因为它同时是「数据说明书」和「训练费的依据」。
下次有人说「再训一版」,你可以直接报数:同样的数据、同样的轮数,多少钱。

四、两个最容易出事的环节

跳过第一步。 Demo 里 200 条数据有 9 条末条不是 assistant,占了 4.5%。 这 9 条如果直接进训练集,模型会学到「回答完之后再问一句」——因为数据里就是这么写的。 这类错误的可怕之处是它不会报错。格式合法、JSON 能解析、损失照样下降,只是模型学歪了。 没有验证集。 只有训练损失的时候,你无法区分「模型学会了」和「模型记住了」。 这两件事在训练集上的表现完全一样(损失都趋近于 0)。 所以最低配的流程也要有:一份校验脚本 + 一份留出的验证集。这两样加起来不到一天的工作量, 能挡掉后面九成的返工。

五、动手 Demo:五步走完:200 条里 9 条末条不是 assistant

造 200 条客服对话样本(system + user + assistant 三条消息), 其中每隔 23 条塞一条「末条是 user」的错样本。 按五步顺序跑:格式校验 → 9:1 划分 → 长度统计 → 训练 → 评估。 训练用的是「按长度分两类」这个占位任务,只为演示流程。

ok, bad_role = [], 0
for ln in open(path, encoding='utf-8'):        # 第一步:校验
    m = json.loads(ln).get('messages')
    if not isinstance(m, list) or m[-1].get('role') != 'assistant':
        bad_role += 1
        continue
    ok.append(m)

idx = np.arange(len(ok)); rg.shuffle(idx)      # 第二步:划分
cut = int(len(ok) * 0.9)
tr = [ok[i] for i in idx[:cut]]

L = np.array(lens)                             # 第三步:统计
print(L.min(), np.median(L), L.max(), L.sum() * 1.5)

W, b = train_soft(Xtr, ytr, 2, ep=300, lr=0.3) # 第四步:训练
print(acc_of(W, b, Xtr, ytr), acc_of(W, b, Xva, yva))   # 第五步

实跑输出:

--------------------------------------------------------------------
微调流程:五步里最花时间的不是训练,是前两步
--------------------------------------------------------------------
  总条数                   200
  格式合格                 191(95.5%)
  末条不是 assistant       9 条
  轮次过多                 0 条
  训练/验证               171/20
  样本长度 最小            50 字
  样本长度 中位            89 字
  样本长度 最大            117 字
  估算训练 token           约 2.4 万
  训练集准确率             0.9825
  验证集准确率             1.0000

  五步走完,看两件事:
  **第一步就刷掉了 4.5% 的数据**(末条不是 assistant 的有 9 条)。
  如果跳过校验直接训,这些样本会让模型学成「回答完再问一句」。
  **第五步的验证集准确率是 1.0000,训练集是 0.9825。**这里的任务是「按长度分两类」,纯属占位——
  真正要看的是**有没有验证集**这件事本身。只有训练损失的微调,等于闭着眼睛调参数。

  五步的时间分布,经验值大致是:
  ① 数据格式校验           20%(最容易被跳过,也最容易出事)
  ② 划分与统计             10%
  ③ 训练                   40%(挂机等)
  ④ 评估                   20%(看样例,不只看数字)
  ⑤ 保存与登记             10%
  **训练那 40% 是机器在跑,人可以走开;前面那 30% 才是人真正要花的心思。**

第一步的输出很干脆: 200 条里 9 条末条不是 assistant,格式合格 191 条。9 除以 200 是 4.5%—— 这个比例在真实项目里算很干净的,手工拼的数据集经常有 15% 以上要刷掉。 这里挑的错法(回答完之后又追加一句用户提问)是最常见的一种。 它的后果是模型学到「答完再问」,上线后你会发现它老是反问用户。 而损失曲线完全正常——这就是最难查的那类问题。 第二步分了 171/20。验证集只有 20 条,其实偏少,准确率跳一格就是 5 个百分点。 真实项目建议至少留 200 条做验证,否则你分不清「涨了 3 个点」是真涨还是抖动。 第三、四、五步的数字都不用细看:长度 50 到 117 字,训练集 0.9825、验证集 1.0000。 这里的任务是个占位(按长度把样本分成两类),它当然好学。 要看的是「有没有验证集」这件事本身。 诚实说明:长度分布是按「短问答」的样子造的,token 估算用的是每字 1.5 个 token 的经验值。 真实数据里长度分布通常长尾很重,最大值往往是中位数的五到十倍。

30 秒实验

  1. 把 9:1 改成 5:5,看验证集扩到 96 条后准确率变成多少。验证集越小,数字越好看也越不可信。
  2. 把每隔 23 条改成每隔 5 条(错样本变多),看格式合格率掉到多少。 这就是「脏数据」在流程第一步的样子。
  3. 给第三步加一项「长度最大值」,再拿最大值除以中位数。 这个比值超过 5,就说明数据里有超长样本要单独处理。

常见误区

  1. 「先把数据喂进去训,有问题再说」。格式错误不报错,只让模型学歪。 第一步校验是唯一能拦住它的地方。
  2. 「看训练损失就够了」。训练损失趋近 0 可能只是记住了,必须有留出的验证集才能区分。
  3. 「工具越高级越好」。 托管平台能解决 90% 的业务需求,上开源框架往往是为了私有部署或省钱,不是为了效果。
自测三问(点开对答案) 1. 微调工具的三层分别是什么?各适合谁? —— 托管平台(省事,业务方)、开源框架(便宜可控,要私有部署的团队)、 自己写训练循环(研究和特殊需求)。 2. 为什么说「训练只占四成时间」? —— 因为训练是机器在跑,人可以走开; 校验、统计、评估、登记都要人做,而且哪一步偷懒,后面都要返工。 3. 只有训练损失会有什么问题? —— 无法区分「学会了」和「记住了」——两者在训练集上的表现都是损失趋近 0。必须有留出的验证集。

流程清楚了,接下来的问题更现实:这个需求到底该不该微调?下一节给一张五项打分的决策表。

相关笔记