English interface selected · this article is currently written in Chinese.
从网页到训练文本:预训练数据清洗到底在做什么
English overview →具备清晰骨架、初步数学推导或工程验证,持续补充论据与实测。
数字花园
🌿 什么是数字花园与思想演进?
遵循 Maggie Appleton 与 Andy Matuschak 的常青笔记理念:这里不是按时间沉底的流水账,而是持续修剪打磨的知识生态。文章按成熟度经历:
- 🌱 萌芽 (Seedling): 发散灵感、读书摘录、开放猜想
- 🌿 演进 (Budding): 结构渐明、初步代码推导、积极修正
- 🌳 常青 (Evergreen): 逻辑闭环、持久经得起检验的基石
- 🔬 实验待证 (Speculative): 结合沙盒与仿真探针的理论探索
假设我们已经找到一批中文技术网页,准备拿来训练模型。网页在浏览器里看起来很正常:上面是导航,中间是文章,旁边是推荐,下方是评论。
可下载下来以后,它们混在了同一个文件里。模型不知道哪部分是正文,也不知道“下载客户端”已经在十万个网页里出现过。更麻烦的是,一次看似无害的“统一格式”,可能把代码缩进和表格结构一起删掉。
数据清洗要做的,是尽量保住有用内容,同时去掉不需要的部分。 不能只看处理后的文本是否整齐,还要看原文里的意思有没有被破坏。
这是第一卷第二篇,接着数据来源与选型,继续处理那个中文技术模型的假设项目。
从一张具体网页看起
下面是自写的教学网页,故意把正文、英文术语、代码和广告放在一起:
<nav>首页 / 推荐 / 登录 / 下载客户端</nav><article> <h1>为什么梯度累积不能减少参数内存</h1> <p>梯度累积改变每次更新使用的样本组织方式。</p> <p>Parameters、gradients 和 optimizer states 仍然需要存储。</p> <pre>if ready: optimizer.step()</pre></article><aside>相关阅读:点击领取优惠券</aside><footer>联系我们:editor@example.org</footer>先预测一下:如果只去掉 HTML 标签,会剩下什么?导航和广告仍然在。如果把所有空白变成一个空格,代码层级会消失。如果要求每一行大部分都是汉字,第二段技术说明可能被删掉。
这不是一条“清洗力度不够”的问题,而是几件事被混在了一起:
| 操作 | 通俗地说 | 这张网页里该做什么 |
|---|---|---|
| 正文抽取 | 找出主要内容 | 区分文章与导航、广告 |
| 文本规范化 | 统一确实不影响含义的格式 | 统一换行编码,保留代码缩进 |
| 过滤 | 决定是否保留 | 判断剩下的内容是否完整、有用 |
| 片段处理 | 处理局部特殊内容 | 按既定规则处理联系信息,不必一律扔掉整页 |
如果每一步都保存输入输出,就能知道正文在哪一步坏掉了。只写一个巨大的 clean(text),最后看到空字符串,很难判断是哪条规则造成的。
第一步 选对输入,才有机会修复内容
Common Crawl 的 WARC 保存抓取内容,WET 提供已提取的文本,WAT 提供元数据。选 WET 会省去自己解析 HTML 的工作;选 WARC 则可以自己更换抽取器。Common Crawl 格式说明
区别在于,你还能改到哪一步。假设上游已经把一张表抽成“12 24 36”,列名和行列关系都没了,下游再好的过滤器也无法知道这些数原本表示什么。
所以,只有清洗好的 JSONL 或 Parquet 也可以开始研究,但要把问题说准确:我们是在比较现有正文怎样筛选,不是在比较网页怎样抽取。
对假设项目,第一版可以从已处理文本开始,降低工程成本。若抽样发现代码段大量缺失,再考虑回到原始网页。不是所有项目都需要从抓取开始重做一遍。
第二步 抽正文时,也要保留结构
正文抽取器通常会利用 HTML 节点结构、文字密度、链接比例等线索,猜测主体内容在哪里。这些线索对新闻页可能很好用,对论坛、API 文档和表格页却未必合适。
FineWeb 比较过 WET 文本与从 WARC 使用 trafilatura 提取的文本,在其训练设置中,后者得到更好的下游表现。这个结果说明抽取值得单独比较,不说明任何页面都必须用同一个工具。FineWeb 抽取实验
先找一小组固定页面,逐个对照原文和输出,会比盲目处理百万页更容易发现问题。
| 页面类型 | 优先检查 |
|---|---|
| 技术博客 | 标题、正文和代码是否完整 |
| API 文档 | 参数名、参数解释是否仍能对应 |
| 表格说明 | 表头与数值是否还在同一关系中 |
| 论坛问答 | 问题、回答和引用是否混成一段 |
| 新闻或普通文章 | 导航和推荐是否混入正文 |
不要只看输出是否流畅。一篇漏掉“不适用于……”整段限制条件的文章,也可能读起来很顺。
抽得更多也不一定更好。把评论全保留,会增加文本,但也可能把不同人的观点接成同一段论述。评论是否保留,需要明确决定,不能交给工具默认值。
第三步 分清训练正文与去重副本
去重时,为了识别“表面不同、实际相同”的文章,我们可能想统一一些写法。比如把 API 和 api 都转成小写。
但训练代码时,大写和小写可能表示不同变量。把所有数字删掉,会让 0.001 和 0.01 没有区别。繁简转换也可能改变地域表达。方便匹配的文本,不一定适合交给模型学习。
一个好理解的做法是保留两种用途:
training_text是真正要训练的正文,只做经过审查的变换。matching_text是专门用于匹配重复的副本,可以采用另外一套明确规则。
再保留原文位置或受控原始缓存,方便回查。Unicode 的 NFC、NFKC 也要写清楚:两者并不等价,后者会合并更多兼容字符,不能把它们都笼统叫作“统一编码”。
每套规则都需要版本号。否则下一次指纹不同,无法知道是原文变了,还是清洗方式变了。
第四步 不要把中英混排当成坏中文
我们的目标是中文技术内容。这样的文章里,本来就会出现 CUDA、batch size、memory bandwidth,也会有代码和公式。
汉字比例可以作为信号,但不能替代内容判断。一篇正常教程和一页产品编号目录,都可能只有一半汉字;它们的用途显然不同。
语言识别模型同样会犯错。它给出 0.9 的分数,不自动意味着“有 90% 的概率判断正确”,还要看这个分数是否在相应语言与领域验证过。短文本和专业术语往往更难判断。
FineWeb2 专门研究了语言识别和阈值,并按语言与文字系统配置处理。它提示我们检查语言差异,但不提供一套适用于所有中文语料的万能阈值。FineWeb2 语言处理实验
对假设项目,可以先单独记录“中文为主但有较多英文”的样本,抽查里面是技术文档还是无关目录,再决定分流或删除。繁体也应根据覆盖目标处理,不能仅因字形不同就判为低质量。
第五步 每条规则都要说清怎么算
“重复太多就删掉”听起来很直观,但“太多”到底怎么算?看一个自拟例子:一篇文档有十行,其中五行都是同一句导航文字,另外五行各不相同。
第一次出现不算多余,之后又重复了四次。因此,按额外重复行数计算,比例是:
把它写成一般形式:非空行总数是 ,不同的非空行有 种,那么额外重复行比例为:
现在换个角度。假设五行导航每行只有两个字,另外五行正文每行一百字。重复多出来的字符只有 个,总字符数是 ,重复字符比例约为 1.6%。
同一篇文档,一个算法得出 40%,另一个算法得出约 1.6%。没有谁算错,是它们测量的东西不同。阈值只有与统计单位一起写出来才有意义。空文档则应单独处理,不能拿分母加一来掩盖问题。
其他规则也一样:
| 信号 | 它能提醒你什么 | 容易误伤什么 |
|---|---|---|
| 很短 | 可能是空页或抓取失败 | 简洁的 API 说明 |
| 链接多 | 可能是导航或聚合页 | 参考资料丰富的文档 |
| 重复片段多 | 可能是广告堆词或循环文本 | 格式重复但参数不同的代码 |
| 标点异常 | 可能是损坏文本 | 代码、公式、诗歌 |
| 非汉字比例高 | 可能不属于目标语言 | 中文技术教程 |
英文常按空格估计词数,中文不能照着 split() 就把整段文字当成一个词。统计用的是字符、分词结果还是模型 token,都要明确。
第六步 看删掉了什么,不只看删掉多少
假设输入一百万条记录,抽取后留下八十万条,语言过滤后留下六十万条,规则过滤后留下四十八万条。
最后一步保留了上一步的 ,整个流程保留了原始输入的 。这两个保留率回答不同问题。报告里只写“保留率 80%”,读者就可能误以为大部分原始数据都还在。
更重要的是按来源、语言、领域和长度拆开看。总体保留率 80%,可能是普通文章保留得很好,但技术文档几乎全被删了。对我们的项目,这样的规则就值得重查。
文档数也不能代替 token 数。删除很多短广告页,文档数量会大幅下降,训练内容长度却可能变化不大。
还要注意执行顺序。广告页可能既太短又重复过多,先执行哪条规则,就先被哪条删掉。只记录“第一条拒绝原因”,不能用来计算各规则互相独立的贡献。更好的记录是保存所有命中信号,再保存最终处理结果。
内容过滤也需要看上下文
邮箱、姓名、账户信息等检测,可以用模式、实体识别和上下文规则。某个模式只能发现一部分情况,也可能把日期、版本号或产品编号误判成敏感内容。
因此,检测到一个片段以后,还要决定是替换片段、隔离整篇,还是排除整个来源。不要把局部检测结果直接当成整篇质量结论。追溯用的原始文本也不必全部公开,可放在受控存储中。
关键词过滤有同样的问题。讨论某个社会问题的文章可能包含被过滤的词,但讨论和鼓励不是同一回事。关于 C4 的研究发现,过滤对不同群体相关文本的影响并不相同。这是为什么清洗之后还要检查语料覆盖,而不只检查表面整洁。Dodge 等,EMNLP 2021
怎样比较一次清洗改动
假设准备把旧抽取器换成新抽取器,先写下一个具体预测:新方法应该少留下导航,同时不增加代码块缺失。 这个预测比“新方法应该更干净”容易验证。
用同一组网页跑两套方法,检查四类样本:两者都保留、两者都拒绝、靠近阈值,以及两者决定不同的样本。最后一类最能解释改动。
人工检查时先不显示哪个是新方法,分别记录正文是否完整、代码是否保留、模板是否残留。如果只挑疑难样本,就单独报告这些样本;如果要推断整体误差,还需要有代表性的抽样和对应权重。
当数据层已经比较清楚,再固定模型、分词器、训练 token 与评测做训练对照。人工觉得更整齐,不等于模型一定学得更好。
| 比较结果 | 能支持的结论 |
|---|---|
| 导航少了,代码也完整 | 在这批审查页面上,抽取改动更符合目标 |
| 删除率提高 | 新规则删得更多,还不能判断删得好不好 |
| 同训练条件下目标任务提高 | 改动在这些训练与评测条件下有帮助 |
| 只有技术域提高,其他域下降 | 需要讨论取舍,不能只报一个总分 |
DataTrove及其 FineWeb 示例可以用来学习怎样拆分读取、过滤和写出任务。对小项目,先把每一步的结果、拒绝原因和错误记录写清楚,再考虑扩大规模。读取失败应进入错误记录,不能伪装成“低质量已删除”。
本篇的例子和公式解释的是规则为什么会误伤;FineWeb、FineWeb2 和 C4 的结论来自各自研究设置。本地新规则是否有效,仍要通过上述比较来判断。
最后留两个问题:为什么同一篇文档的重复行比例和重复字符比例会差很多?如果中文技术内容大量被拒绝,你会先修改阈值,还是先看被拒绝的样本,为什么?
下一篇讨论更难的一步:干净的文本里,哪些更值得训练。
文章概念网络
从章节进入正文概念。实线表示所属层级,虚线连接跨章节重复出现的概念,不代表因果关系。
62 / 62 个节点 · 正文标记术语与关键词概念
从网页到训练文本:预训练数据清洗到底在做什么
回到原文 ↗最后更新于 2026-10-20
引用本文
@article{2026-10-15-llm-training-data-02-cleaning,
author = {枫语},
title = {从网页到训练文本:预训练数据清洗到底在做什么},
journal = {枫语},
year = {2026},
month = {oct},
url = {https://meiluosi.github.io/posts/2026-10-15-llm-training-data-02-cleaning/}
}