一份 120 行的 JSONL,能用的只有 106 条(88.3%):7 条 JSON 解析失败、4 条缺字段、 3 条输出为空。 三类坏数据的修法完全不同——一份是文件坏了,一份是格式不对,一份是标注没做完。
上一节算清了「要多少」,这一节解决「从哪来」。但真正花时间的不是下载,是下载之后的体检。
一、公开数据集去哪找
Hugging Face Datasets:目前最大的模型数据集集散地,搜索、预览、直接按行取都能在网页上做。 做微调的首选。 魔搭 ModelScope 与阿里天池:国内访问快,中文数据集比国外平台多,竞赛类数据带完整说明。 Kaggle:表格类数据多,配套的讨论区质量高——很多人已经把「这份数据的坑在哪」写在讨论里了, 值得先读。 政府与行业开放数据平台:统计、气象、交通、法律文书这类,权威性最高,但要自己清洗, 格式往往不统一。 自己爬/自己攒:最后才是这一条。它最贵,也最容易踩合规的线。 选来源只看三件事:有没有许可证、有没有说明字段含义、有没有人用过。
二、拿到手的第一件事是体检,不是训练
一份公开数据集,看着有几万行,实际能用的常常只有八成多。 Demo 里造了一份 120 行的样本,按真实数据的毛病掺了三种坏行。 结果:能用 106 条、JSON 解析失败 7 条、缺字段 4 条、输出为空 3 条。比例是 88.3%, 这个数字在真实数据集里非常典型。 关键在于这三类坏数据的修法完全不同,混在一起处理就会做错: 解析失败是文件本身坏了——多半是导出时截断、编码不对、或者多了一层转义。 要重下或重新导出,不要在代码里打补丁。 缺字段是格式不统一——有的行少一个 key。可以补默认值,也可以直接丢。 但要知道丢了多少、丢的是哪一类。 输出为空是标注没做完。 这一类必须回炉,不能补——补一个空字符串进去,等于教模型「这个问题可以不回答」。
三、体检要看的四项
条数:总量,以及「能用」的比例。低于 80% 就要重新考虑这份数据的来源。 类别分布:每类多少条、占比多少。差三倍以上要做重采样。 长度分布:最短、中位、最长。 中位数比平均数可靠——一条超长样本能把平均数拉高,但它代表不了整体。 重复率:完全相同的行有多少、近似重复的有多少。公开数据集里「同一句话换个标点」的情况非常多。 这四项都是几行代码的事,但顺序不能反: 先看条数决定要不要继续,再看分布决定怎么处理。 反过来的话, 你会在一份只剩六成能用的数据上白忙半天。
四、许可证这件事不能跳过
公开不等于免费商用。 常见的几种:CC-BY(署名可用)、CC-BY-NC(禁止商用)、MIT/Apache(宽松)、 仅限研究(不能进产品)。 麻烦的是许可证常常不写在数据文件里,而在数据集主页的 README 或论文里。 把它抄下来存档,是省未来麻烦最便宜的一步。 还有一层是内容本身的合规:抓来的网页里可能含个人信息、受版权保护的长文。 这些不会因为「数据集标了开源」就变得能用。 所以真实项目里,数据来源和许可证要单独列表格,跟代码一起进版本管理。 出了事,那张表是唯一的凭据。
五、动手 Demo:120 行里能用 106 行:7 条坏 JSON、4 条缺字段、3 条空输出
造一份 120 行的指令微调数据(instruction/input/output/category), 按真实数据的常见毛病掺进三类坏行,然后写一个体检脚本:逐行解析、分类统计、算类别分布和长度分布。
ok, bad_json, miss, empty = [], 0, 0, 0
for ln in open(path, encoding=u'utf-8'):
ln = ln.strip()
if not ln:
continue
try:
d = json.loads(ln)
except ValueError:
bad_json += 1 # 文件坏了
continue
if u'instruction' not in d or u'output' not in d:
miss += 1 # 格式不对
continue
if not d[u'output'].strip():
empty += 1 # 标注没做完
continue
ok.append(d)
实跑输出:
--------------------------------------------------------------------
公开数据集:拿到手先体检,别急着往模型里喂
--------------------------------------------------------------------
文件 sft_sample.jsonl
体积 17.2 KB
行数 120
能用的 106 条(88.3%)
JSON 解析失败 7 条
缺字段 4 条
输出为空 3 条
三类坏数据,修法完全不同:
解析失败 文件本身坏了,要重下或重新导出
缺字段 格式不对,可以补默认值或丢弃
输出为空 标注没做完,必须回炉,不能补
再看类别分布和长度分布:
类别 条数 占比
--------------------
发票 35 33.0%
发货 36 34.0%
退换货 35 33.0%
输出长度 最小 20 字
输出长度 中位 20 字
输出长度 最大 21 字
**中位数比平均数可靠**:一条超长的样本能把平均数拉高,但它代表不了整体。
这份数据的类别是均匀的(模板造的)。真实数据集很少这么整齐。
**类别差三倍以上就要做重采样,否则模型会偏向多的那类。**
结果:106 条能用(88.3%)、7 条解析失败、4 条缺字段、3 条空输出。三类加起来 14 条,
正好把 120 减到 106。
这个 88.3% 不是巧合,是照着真实数据集的常见比例设的。
公开数据「下下来就能训」的情况基本不存在。
bad_json 那 7 条是截断的 JSON——现实里对应的是导出中断、编码不对、或者每行末尾多了个逗号。
这类错误不能靠 try 之后修补,要回去查导出环节。
miss 那 4 条少一个 key。这类可以补默认值,但要先想清楚:少的是 input 还是 output?
少 input 能补空串,少 output 就没法补。
empty 那 3 条最危险:格式全对,内容为空。如果只做 JSON 解析校验,
这三条会被当成好数据喂进去,教模型「这种问题可以答空」。
类别分布那一列是均匀的(因为模板造的),真实数据很少这么整齐。
类别差三倍以上就要做重采样,否则模型会偏向多的那类。
30 秒实验
- 把
output为空的那三行改成只有空格(' '),看脚本还能不能识别。strip()在这里是关键——不加它,空字符串和空白字符串会被当成两种东西。 - 加一项检查:完全重复的行有多少。把
instruction + output拼起来做集合,看去重后还剩几条。 公开数据集里这一项经常掉 10% 以上。 - 把类别分布改成 8:1:1(比如 96 条退换货、12 条发票、12 条发货),再跑一次体检, 看你能不能从统计里一眼看出来。
常见误区
- 「公开数据集直接用就行」。常见情况是能用的只有八成多,剩下的要么格式坏、要么标注不全。 先体检,再训练。
- 「三类坏数据一起丢掉就行」。修法不同:文件坏要重导出,缺字段可以补,空输出必须回炉。 混在一起处理,会把能救的也丢掉。
- 「开源就等于能商用」。许可证有好几种,CC-BY-NC 就是禁止商用的。 下载之前先看许可证,抄下来存档。
自测三问(点开对答案)
1. 为什么「输出为空」比「缺字段」更危险? —— 因为它的格式完全合法,只做 JSON 校验的话会被当成好数据。 喂进去等于教模型「这种问题可以答空」,而缺字段至少会报错。 2. 长度分布为什么要看中位数不看平均数? —— 一条超长样本就能把平均数拉得很高,但它代表不了整体。 中位数不受极端值影响,更能反映「大部分样本有多长」。 3. 拿到一份公开数据集,第一件事做什么? —— 体检:条数与可用率、类别分布、长度分布、重复率,再看许可证。**不是先跑一遍训练看效果。**公开数据不一定合你的业务。更多时候得自己造——下一节看模板生成的极限在哪。
- ☐ (本节完,下一节 3.1.3 生成高质量的模型微调数据集)