从网页到训练文本:预训练数据清洗到底在做什么

成长演进

具备清晰骨架、初步数学推导或工程验证,持续补充论据与实测。

ℹ数字花园

🌿 什么是数字花园与思想演进?

遵循 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 语言处理实验

对假设项目,可以先单独记录“中文为主但有较多英文”的样本,抽查里面是技术文档还是无关目录,再决定分流或删除。繁体也应根据覆盖目标处理,不能仅因字形不同就判为低质量。

第五步 每条规则都要说清怎么算#

“重复太多就删掉”听起来很直观,但“太多”到底怎么算?看一个自拟例子:一篇文档有十行,其中五行都是同一句导航文字,另外五行各不相同。

第一次出现不算多余,之后又重复了四次。因此,按额外重复行数计算,比例是:

410=40%.\frac{4}{10}=40\%.

把它写成一般形式:非空行总数是 LL,不同的非空行有 UU 种,那么额外重复行比例为:

rline=L−UL.r_{\mathrm{line}}=\frac{L-U}{L}.

现在换个角度。假设五行导航每行只有两个字,另外五行正文每行一百字。重复多出来的字符只有 4×2=84\times2=8 个,总字符数是 5×2+5×100=5105\times2+5\times100=510,重复字符比例约为 1.6%。

同一篇文档,一个算法得出 40%,另一个算法得出约 1.6%。没有谁算错,是它们测量的东西不同。阈值只有与统计单位一起写出来才有意义。空文档则应单独处理,不能拿分母加一来掩盖问题。

其他规则也一样:

信号它能提醒你什么容易误伤什么
很短可能是空页或抓取失败简洁的 API 说明
链接多可能是导航或聚合页参考资料丰富的文档
重复片段多可能是广告堆词或循环文本格式重复但参数不同的代码
标点异常可能是损坏文本代码、公式、诗歌
非汉字比例高可能不属于目标语言中文技术教程

英文常按空格估计词数,中文不能照着 split() 就把整段文字当成一个词。统计用的是字符、分词结果还是模型 token,都要明确。

第六步 看删掉了什么,不只看删掉多少#

假设输入一百万条记录,抽取后留下八十万条,语言过滤后留下六十万条,规则过滤后留下四十八万条。

最后一步保留了上一步的 48/60=80%48/60=80\%,整个流程保留了原始输入的 48/100=48%48/100=48\%。这两个保留率回答不同问题。报告里只写“保留率 80%”,读者就可能误以为大部分原始数据都还在。

更重要的是按来源、语言、领域和长度拆开看。总体保留率 80%,可能是普通文章保留得很好,但技术文档几乎全被删了。对我们的项目,这样的规则就值得重查。

文档数也不能代替 token 数。删除很多短广告页,文档数量会大幅下降,训练内容长度却可能变化不大。

还要注意执行顺序。广告页可能既太短又重复过多,先执行哪条规则,就先被哪条删掉。只记录“第一条拒绝原因”,不能用来计算各规则互相独立的贡献。更好的记录是保存所有命中信号,再保存最终处理结果。

内容过滤也需要看上下文#

邮箱、姓名、账户信息等检测,可以用模式、实体识别和上下文规则。某个模式只能发现一部分情况,也可能把日期、版本号或产品编号误判成敏感内容。

因此,检测到一个片段以后,还要决定是替换片段、隔离整篇,还是排除整个来源。不要把局部检测结果直接当成整篇质量结论。追溯用的原始文本也不必全部公开,可放在受控存储中。

关键词过滤有同样的问题。讨论某个社会问题的文章可能包含被过滤的词,但讨论和鼓励不是同一回事。关于 C4 的研究发现,过滤对不同群体相关文本的影响并不相同。这是为什么清洗之后还要检查语料覆盖,而不只检查表面整洁。Dodge 等,EMNLP 2021

怎样比较一次清洗改动#

假设准备把旧抽取器换成新抽取器,先写下一个具体预测:新方法应该少留下导航,同时不增加代码块缺失。 这个预测比“新方法应该更干净”容易验证。

用同一组网页跑两套方法,检查四类样本:两者都保留、两者都拒绝、靠近阈值,以及两者决定不同的样本。最后一类最能解释改动。

人工检查时先不显示哪个是新方法,分别记录正文是否完整、代码是否保留、模板是否残留。如果只挑疑难样本,就单独报告这些样本;如果要推断整体误差,还需要有代表性的抽样和对应权重。

当数据层已经比较清楚,再固定模型、分词器、训练 token 与评测做训练对照。人工觉得更整齐,不等于模型一定学得更好。

比较结果能支持的结论
导航少了,代码也完整在这批审查页面上,抽取改动更符合目标
删除率提高新规则删得更多,还不能判断删得好不好
同训练条件下目标任务提高改动在这些训练与评测条件下有帮助
只有技术域提高,其他域下降需要讨论取舍,不能只报一个总分

DataTrove及其 FineWeb 示例可以用来学习怎样拆分读取、过滤和写出任务。对小项目,先把每一步的结果、拒绝原因和错误记录写清楚,再考虑扩大规模。读取失败应进入错误记录,不能伪装成“低质量已删除”。

本篇的例子和公式解释的是规则为什么会误伤;FineWeb、FineWeb2 和 C4 的结论来自各自研究设置。本地新规则是否有效,仍要通过上述比较来判断。

最后留两个问题:为什么同一篇文档的重复行比例和重复字符比例会差很多?如果中文技术内容大量被拒绝,你会先修改阈值,还是先看被拒绝的样本,为什么?

下一篇讨论更难的一步:干净的文本里,哪些更值得训练。

文章概念网络

从章节进入正文概念。实线表示所属层级,虚线连接跨章节重复出现的概念,不代表因果关系。

62 / 62 个节点 · 正文标记术语与关键词概念

从网页到训练文本:预训练数据清洗到底在做什么同一概念 / Shared concept同一概念 / Shared concept同一概念 / Shared concept同一概念 / Shared concept同一概念 / Shared concept同一概念 / Shared concept同一概念 / Shared concept同一概念 / Shared concept同一概念 / Shared concept同一概念 / Shared concept同一概念 / Shared concept同一概念 / Shared concept同一概念 / Shared concept同一概念 / Shared concept同一概念 / Shared concept从网页到训练文本:预训练数据清洗到底在做什么从网页到训练文本:预训练数据清洗到底在做什么数据清洗要做的,是尽量保住有用内容,同时去掉不需要的…数据清洗要做的,是尽量保住有用内容,同时去掉不需要的部分数据来源与选型数据来源与选型从一张具体网页看起从一张具体网页看起clean(text)clean(text)第一步 选对输入,才有机会修复内容第一步 选对输入,才有机会修复内容Common Crawl 格式说明Common Crawl 格式说明第二步 抽正文时,也要保留结构第二步 抽正文时,也要保留结构FineWeb 抽取实验FineWeb 抽取实验第三步 分清训练正文与去重副本第三步 分清训练正文与去重副本APIAPI0.0010.0010.010.01方便匹配的文本,不一定适合交给模型学习方便匹配的文本,不一定适合交给模型学习trainingtexttrainingtextmatchingtextmatchingtext第四步 不要把中英混排当成坏中文第四步 不要把中英混排当成坏中文FineWeb2 语言处理实验FineWeb2 语言处理实验第五步 每条规则都要说清怎么算第五步 每条规则都要说清怎么算1.6%1.6%split()split()第六步 看删掉了什么,不只看删掉多少第六步 看删掉了什么,不只看删掉多少内容过滤也需要看上下文内容过滤也需要看上下文Dodge 等,EMNLP 2021Dodge 等,EMNLP 2021怎样比较一次清洗改动怎样比较一次清洗改动新方法应该少留下导航,同时不增加代码块缺失新方法应该少留下导航,同时不增加代码块缺失DataTroveDataTroveFineWeb 示例FineWeb 示例干净的文本里,哪些更值得训练干净的文本里,哪些更值得训练技术技术HTMLHTML规范化规范化技术技术Common CrawlCommon CrawlParquetParquetJSONLJSONLHTMLHTMLFineWebFineWebHTMLHTML利用利用实验实验技术技术UnicodeUnicodeNFKCNFKCNFCNFC去重去重FineWebFineWeb技术技术memorymemoryCUDACUDA实验实验tokentoken分词分词技术技术tokentoken技术技术C4C4FineWebFineWeb技术技术tokentoken分词分词C4C4
从网页到训练文本:预训练数据清洗到底在做什么

从网页到训练文本:预训练数据清洗到底在做什么

回到原文 ↗
BIBTEX

引用本文

@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/}
}
🌐

本篇知识星丛与滑动侧栈

从网页到训练文本:预训练数据清洗到底在做什么 当前主轴

搜索

正在载入索引…