微调的效果上限,在写第一行训练代码之前就定了:数据长什么样,模型就学成什么样。 这一节讲三件事——数据从哪来、标注口径怎么定、转成模板之后 token 涨了多少。 最后那件事最容易被忽略:一段两百字的系统提示配五千条数据,就要在 token 预算里出现五千次。
上一章把模型跑起来了,这一章开始改它。改之前先得有材料。 17 课 编程原理 讲的是程序怎么处理数据, 这一节讲的是给人看的数据怎么变成给模型看的数据——中间隔着一层模板,也隔着一层口径。
一、数据从哪来:三条路,各有各的脏
第一条是自有业务数据:工单、客服记录、审批意见、成稿的方案。 这类最贴业务,但量最少、最脏,还牵扯脱敏——客户名字、电话、报价都得先替换掉。 第二条是公开数据集改写。 量大,但文风不对:拿别人的问答训出来的模型,说的是别人的话,业务里的行话一句也不会。 第三条是让强模型造。 最快,一天能造几千条,风险是「自己教自己」——基座不会的东西,造出来的数据也不会, 训完只是把错误说得更流利。
比较稳的做法是这么配:先用几百条真数据把口径定死,再用强模型按这个口径扩量,最后人工抽检百分之十。 几百条真数据的作用不是训练,是定标准。
二、标注:口径比标注员重要
先写手册,再动手。 手册要能回答「遇到某种情况怎么办」,不能只写「回答要简洁」——什么叫简洁,得给例子,得给边界。 判断手册够不够用,有个便宜的办法:让两个标注员各标一百条,比对一致率。 低于八成,说明手册有问题,不是标注员不认真。这时候该改手册,不是换人。 边界案例单独收一册。这些例子以后调提示、调评测、判断模型退化都要用,是整份数据里最值钱的部分。
还有一条:允许标「不确定」。硬猜出来的样本在训练里跟正确样本拿一样的权重, 它会主动教模型一些错的东西;标成不确定的样本可以后面再议。 答案的写法比答案的内容更影响结果。写成「结论 + 依据」两段,模型学得快; 写成一段散文,模型学会的是「说一段话」,而不是「先给结论」。
三、三种格式,最后都要拼成一条字符串
Alpaca 格式最简:instruction、input、output 三个字段,适合单轮任务。
ShareGPT 格式能存整段对话:conversations 是个列表,每项带 from 和 value,
from 取值是 human 与 gpt。多轮数据一般用它。
Llama 2 原生格式是一条纯文本:<s>[INST] 指令 [/INST] 回答 </s>,
带系统提示时把 <<SYS>> 那段塞在第一条 [INST] 里。只有这种能直接喂给模型。
前两种是「存」的格式,第三种是「喂」的格式,中间那一步转换最容易出错:多一个空格、少一个 </s>,
模型学到的边界就错位,表现是「回答完不收尾,继续说」。
模板会把 token 撑大。演示里五条数据正文 236 字,拼完 587 token,平均 2.49 倍。
这个倍数直接乘在你的显存和训练时长上。
四、训练之前先体检
五项必查:长度分布、空答案、答案复述提问、重复条目、测试集污染。 长度要看两头的极端值。太长的会被截断,而截断常常把答案切掉一半——模型于是学到「话说一半就停」。 复述是最隐蔽的一种坏数据:答案跟提问高度重合,比如问「图纸改了吗」,答「图纸改了」。 这类样本训下去,模型学会的是复读。
重复和污染要分开看。同一条出现十次,等于给这条加了十倍权重; 测试题混进训练集,评测分数会好看得不像真的,而且你很难发现。
五、动手 Demo:同一批数据三种格式,模板吃掉多少 token
这一节造五条业务问答(亮化工程现场那类),先列出来看,再写成三种格式,然后真的拼成 Llama 2 模板, 数 token。 分词器用的是本课自带的字符级替身,不是真的 sentencepiece——所以绝对数会比真机大, 但膨胀的比例是可信的。
SYS_PROMPT = u'你是一个工程助理,回答先给结论,再给依据,不超过六十个字。'
# 拼成 Llama 2 原生模板
s = u'<s>[INST] <<SYS>>\n%s\n<</SYS>>\n\n%s [/INST] %s </s>' % (SYS_PROMPT, q, a)
n = tokens(s) # 字符级分词替身
print(len(q) + len(a), n, n / float(len(q) + len(a)))
# 多轮:每轮一对 [INST] … [/INST] … </s>
parts = []
for q, a in conv:
parts.append(u'[INST] %s [/INST] %s </s>' % (q, a))
s = u'<s>' + u''.join(parts)
实跑输出:
--------------------------------------------------------------------
同一批数据三种格式,模板吃掉多少 token
--------------------------------------------------------------------
① 先看数据长什么样
--------------------------------------------------------------------
| 序 | 指令 | 回答 |
|:---:|---|---|
| 1 | 把「图纸已更新,请查收」改得更正… | 图纸已完成更新,请查收。 |
| 2 | 这三条待办按紧急程度排一下:报价… | 结论:验收最急,其次报价单,最后图纸… |
| 3 | 用一句话说明为什么这个月进度落后 | 结论:材料到场晚了两周。理由:供应商… |
| 4 | 把这段会议记录提炼成三条结论 | 一、三月报价按新成本重算。二、验收推… |
| 5 | 客户问为什么价格涨了,怎么回 | 结论:因为主要材料涨了 12%。建议… |
这一节用五条样例演示,真机上通常是几千到几万条。字段就两个:问和答。
! 注意每条的答案都带「结论」两个字——这不是文风,是格式约束。
指令微调最直接的作用就是把输出样式固定下来。
② 三种常见格式
--------------------------------------------------------------------
| 格式 | 形状 | 适合 |
|---|---|---|
| Alpaca | {"instruction": ..., "input": "", "output": ...} | 单轮,字段最简 |
| ShareGPT | {"conversations": [{"from": "human", "value": ...}, ...]} | 多轮,能存整段对话 |
| Llama 2 原生 | <s>[INST] 指令 [/INST] 回答 </s> | 拼成一条纯文本,训练时直接用 |
三种格式里只有第三种能直接喂给模型——前两种都要先转成模板字符串。
③ 转成 Llama 2 的模板
--------------------------------------------------------------------
| 序 | 正文字数 | 模板后 token | 膨胀比 |
|:---:|---:|---:|---:|
| 1 | 29 | 91 | 3.14 |
| 2 | 66 | 142 | 2.15 |
| 3 | 45 | 117 | 2.60 |
| 4 | 49 | 122 | 2.49 |
| 5 | 47 | 115 | 2.45 |
五条合计 587 token,正文 236 字,平均膨胀 2.49 倍。
膨胀来自三处:系统提示每条都要带一遍、[INST] 这类标记、以及中文本身一字一 token。
! 系统提示重复是最亏的——如果有五千条数据,那段话就要进 token 预算五千次。
所以长系统提示在大数据集上是要花钱的。
④ 多轮怎么拼
--------------------------------------------------------------------
三轮拼成一条:155 个字符,141 token。
每一轮都以 </s> 收尾,下一轮重新开 [INST]——这个结构告诉模型「该我说完了」。
! 多轮最容易错的地方是:只把最后一轮算损失。
真机上要把前面几轮也放进上下文,但只有助手说的话进损失——这就是第 1.4 节讲的屏蔽。
⑤ 数据要先体检
--------------------------------------------------------------------
| 检查项 | 值 |
|---|---:|
| 条数 | 5 |
| 最短 / 最长 | 91 / 142 token |
| 平均 | 117 token |
| 超过 512 的 | 0 |
| 答案为空 | 0 |
这几项体检要在训练前跑:太长的截断、太短的手工看、空的直接删。
! 最贵的一类错误是「答案其实是提问的复述」——这种数据训下去,模型会学会复读。
先看①那张表:五条数据字段只有两个,问和答。
但每条的答案都以「结论:
」开头——这不是文风,是格式约束。指令微调最直接的作用就是把输出样式固定下来。
②那张表是三种格式的对照。要点在最后一行:只有 Llama 2 原生格式能直接喂给模型,前两种都得先转。
所以「用什么格式存」和「用什么格式训」是两件事。
③是这一节的主表。五条数据正文 236 字,拼成模板 587 token,平均膨胀 2.49 倍。
膨胀来自三处:系统提示每条重复一遍、[INST] 这类标记、字符级分词本身不省。
系统提示重复是最亏的那一项。
五千条数据,那段话就进预算五千次——长系统提示在大数据集上是要花钱的,这笔钱按 token 计,
不是按字数计。
④的多轮拼法值得记住:每一轮都以 </s> 收尾,下一轮重新开 [INST]。
这个结构告诉模型「该我说完了」。少一个 </s>,模型就不知道边界在哪。
⑤是训练前该跑的体检。
这五项里最贵的一类错是「答案其实是提问的复述」——它不会报错,也不会让损失异常,
只会让模型慢慢学会复读。
30 秒实验
- 把
SYS_PROMPT整段删掉,重跑第③段。膨胀比会掉到多少? 再算一笔:五千条数据下,这个差别是多少 token? - 把第④段的三轮对话改成五轮,看 token 怎么涨。想一想:多轮数据的长度是线性涨,还是更快?
- 把第⑤段的截断阈值从 512 改成 128,看有几条被截。被截的那几条,答案还在不在? 这就是「长度体检」要提前做的原因。
常见误区
- 以为数据越多越好。 五百条口径一致的数据,胜过五万条口径混乱的。模型学的是模式, 口径乱的样本教给它的是「随便写」。
- 让标注员自由发挥。 没有手册就没有一致性,没有一致性就没有可学的模式,训出来的模型会时而给结论、时而写作文, 而且你查不出是哪条数据带坏的。
- 拿测试集调参。分数一路涨,上线一路掉,这是最常见也最难自查的一种自欺。 训练集、验证集、测试集要在动手前就切好,切完不许动。
自测三问(点开对答案)
1. 为什么说系统提示重复是「最亏的」一项? —— 因为它对每条数据都要占一遍 token,而且内容完全一样——信息量是零,成本是满的。 五千条数据就是五千遍。把系统提示压短,等于免费省掉一部分训练成本。 2. 多轮对话为什么只把助手说的话算进损失? —— 因为模型要做的是「接着往下说」,用户说的话是输入条件,不是它该学会生成的内容。 如果连用户那几段也算损失,模型会学会自己跟自己对话。 3. 模板膨胀 2.49 倍,这个数对训练有什么实际影响? —— 显存和时长都按 token 数算,所以大约按这个倍数放大。 同一批数据,去掉冗余的系统提示、缩短标记,训练成本能明显下来,而模型学到的内容没变。数据备齐了,下一节把它喂进去——先解决「怎么把十几 GB 的权重装进显存」这件事。
- ☐ (本篇完,下一篇 3.2 Llama 2 大模型加载)
相关笔记
- 40 课 图解机器学习:训练集、验证集与过拟合
- 38 课 AI 训练师手册:标注规范与数据质检
- 预训练及微调:损失只在答案段上算
- 🦙 Llama 大模型实践 · 索引