2.2 来源与清洗:开源指令集的挑选


2.2 来源与清洗:开源指令集的挑选

本节摘要:最经济的取数路线是用现成的开源指令集。本节先给四把尺子——质量、规模、许可证、语言——再横向对比三个主流候选:OpenHermes 2.5(约 100 万条、多源混合、质量口碑好)、UltraChat(约 150 万轮多轮对话、由强模型生成)、SmolTalk(HuggingFace 为小模型 SFT 调配的混料,也是 nanochat 当前 master 的示例选择)。选定之后过一遍不可省略的清洗管线:格式校验(2.1 的契约)→ 精确去重 + 近似去重(MinHash 类)→ 规则质量过滤 → 长度截断,附可跑的管线代码。中心信条:开源数据"开箱即用"是指许可证,不是指质量。

学习目标

阅读完本节,你应当能够:

  1. 用四把尺子(质量/规模/许可证/语言)评估任一开源指令集。
  2. 说出 OpenHermes、UltraChat、SmolTalk 各自的特点与适用场景。
  3. 跑通"校验 → 去重 → 过滤 → 截断"四步清洗管线并解释每步的取舍。

一、四把尺子

尺子 问什么 为什么重要
质量 回答是否正确、格式是否统一、是否含机器翻译腔/残留水印 小模型没有"消化坏数据"的冗余容量,坏答案会被直接背下来
规模 条数够不够(SFT 通常数万~数十万条起) 太少学不会格式,太多重复则过拟合模板腔
许可证 数据集 license 是否允许训练与再分发 商用/再分发的前提,发布模型前必查
语言 中英占比与中文质量 英文为主的数据训出的模型中文手感差——第 8 章中文改造的核心动因

💡 质量优先于规模是 SFT 数据的主旋律:数万条高质量样本的效果通常好过百万条平庸混合(社区多份复现报告的一致结论,如 Tulu/LIMA 一系研究的核心发现——"少量高质量指令数据足以对齐",属学术共识级结论而非精确数字)。

二、三个主流候选对比

数据集 规模(数据集卡口径) 形态 特点 许可证(以数据集卡为准)
OpenHermes 2.5 ~100 万条 以单轮为主 多源混合、质量口碑好,社区 SFT 常客 开放(允许训练用途)
UltraChat ~150 万轮 多轮对话 强模型生成的多轮语料,练指代与角色恒定 开放研究用途
SmolTalk ~100 万条 混合(含工具/推理类子集) HuggingFace 为小模型 SFT 调配;nanochat 当前 master 的示例选择 开放(含子集,注意各源约束)

nanochat 与这三者的关系(两个时间层,均需以官方仓库 README 为准):发布帖时代(2025-10)SFT 数据由官方自备的一批问答对话构成;当前 master 的 SFT 示例数据换用了 SmolTalk。本书教学上不受绑定——三条数据里任一条(或混合)都能跑通第 3 章,方法完全一致。

选型速查:

  • 要单轮问答密度 → OpenHermes 系;
  • 要多轮对话能力 → UltraChat/SmolTalk 的多轮子集;
  • 模型本身很小(≤1B)→ 优先 SmolTalk 一类"为小模型调配"的混料;
  • 要中文 → 上述三者中文占比都有限,中文主力方案见 2.3 与第 8 章。

三、清洗管线:四步走

# clean_sft_data.py —— 开源指令集清洗管线(写法示意) import json import re import hashlib MAX_TOKENS = 2048 # 与 1.1 的长度预算对齐(p95 截断) def norm_key(content: str) -> str: """精确去重键:压空白后取哈希。""" return hashlib.md5(re.sub(r"\s+", "", content).encode()).hexdigest() def rule_filter(obj: dict) -> bool: """规则质量过滤:拦最常见的不合格样本。""" for m in obj["messages"]: c = m["content"] if len(c) < 2: # 空洞回答 return False if c.lower().startswith(("as an ai", "作为一个语言模型")): return False # 模型免责腔,小模型学了只会复读 if "http" in c and len(c) < 60: # 纯链接回答 return False # 回答与提问完全相同 = 自问自答脏样本 pairs = [(u, a) for u, a in zip(obj["messages"], obj["messages"][1:]) if u["role"] == "user" and a["role"] == "assistant"] return all(u["content"] != a["content"] for u, a in pairs) def char_budget(obj: dict) -> bool: """长度预算的粗筛(字符级,token 级在打包时精确截断)。""" return sum(len(m["content"]) for m in obj["messages"]) <= MAX_TOKENS * 3 def pipeline(src: str, dst: str) -> None: seen, kept = set(), 0 with open(src, encoding="utf-8") as f, open(dst, "w", encoding="utf-8") as out: for line in f: try: obj = json.loads(line) except json.JSONDecodeError: continue # step0:JSON 层直接丢 if not rule_filter(obj) or not char_budget(obj): continue # step2:规则过滤 key = norm_key(obj["messages"][-1]["content"]) # step1:按末轮回答精确去重 if key in seen: continue seen.add(key) out.write(json.dumps(obj, ensure_ascii=False) + "\n") # step3:截断在打包时做 kept += 1 print(f"清洗完成:保留 {kept} 条") if __name__ == "__main__": pipeline("data_sft/raw.jsonl", "data_sft/train.jsonl")

四步各自的取舍:

  1. 格式校验:2.1 的 check_messages.py,契约不过的样本直接出局。
  2. 精确去重:完全相同的回答只留一份。重复样本等于给该答案加权——模型会偏向复读它。
  3. 质量过滤:规则版拦明显坏样本(空洞、免责腔、纯链接)。规则过滤的精度有限,胜在零成本、可解释;要更高精度换模型打分("用小判别器给每条样本打分再阈值截留"),那是 2.3 蒸馏回环的过滤环节,同一套思路。
  4. 长度截断:按 1.1 的长度预算在 token 级截断(多轮对话可从头部丢轮次而不是从中间截断,保持消息完整性)。

⚠️ 近似去重(MinHash/SimHash 类)在十万条以上规模时值得加:精确哈希抓不到"改了几个字"的近重复。Python 里可用 datasketch 库的 MinHashLSH;本书 124M 实验的量级下,精确去重 + 规则过滤已够用。

四、量级参考与产出验收

清洗后的合理量级(示意参考,非硬指标):

模型规模 建议清洗后条数 训练轮数(第 3 章用)
124M 2 万~10 万条 2~3 个 epoch
1B+ 10 万~100 万条 1~2 个 epoch

产出验收两条:wc -l data_sft/train.jsonl 看条数落在上表区间;随机抽 20 条人眼看质量(人工抽检不可省略——所有自动指标都可能集体失灵,眼睛不会)。

本节要点回顾

  1. 四把尺子:质量 > 规模;许可证与语言是硬约束。
  2. OpenHermes(单轮密)/UltraChat(多轮)/SmolTalk(小模型混料,nanochat 现行示例)任选其一即可跑通本书流程。
  3. 清洗四步:校验 → 去重(重复=加权复读)→ 规则过滤 → 截断;量级 124M 配 2~10 万条,人工抽检收尾。

开源集覆盖不到的领域(比如中文垂直场景)怎么办?2.3 节换上自造数据的产线——让强模型替你写教材。


作者与出处
原作者: 灏天文库
整理: 灏天文库整理
本站整理收录,版权归原作者/开源协议所有;欢迎通过原文链接访问源仓库。
发布者: 作者: 灏天文库 转发
评论区 (0)
U