从0训练LLM · 现代大模型体系 阅读 + 实验 ≈ 30 分钟 页内实验 ×2
C7 数据:从哪来、怎么洗、怎么配 第 1 课

直接把网页爬下来就能训练吗?

爬取与规则过滤
原始网页和我们自己的原始语料一样脏:样板、声明、硬换行。先把正文还原出来,再在自己的数据上逐条跑规则——同一条 C4 规则,顺序一换,整本书留下的字从 17% 变成 94%;英文规则原样套在中文上,整本书一段不剩。
❓

本课一问:C6 算出 Llama 3 8B 要喂 15T 个 token。最直接的来源是整个互联网——直接把网页爬下来就拿去训练,可以吗?

这一课先不碰:同一段话重复出现怎么办(第 2 课)、「合法但没营养」的文本怎么筛(第 3 课)、各类数据按什么比例混(第 4 课)。

从已有出发

前六章一直在处理流水线的中段:文字怎么切成 token、token 怎么变向量、向量怎么过注意力和 FFN、参数怎么更新、要训多大。流水线最左端那一格「文字」,一直被当成理所当然的输入。

从已有出发 · 累计数据流 点已学环节看形状与参数
解码层

这一章就是在回答那一格从哪来。数据本身也是一条流水线,本课只看它的前四个环节:

从已有出发 · 数据管线 本课其他环节点环节看它做什么、真实数字

先感受一下量级。我们项目的语料是整部《三國志演義》,用项目分词器切出来一共 560,001 个 token(训练集 501,615 + 验证集 58,386)。Llama 3 8B 训了 15T token,相当于把这部书重复约 2.68 × 10⁷ 遍。书、百科这类「干净」文本远远不够,大头只能来自网页。

先自己设计:原始文件直接拿来用

我们手上就有一份和网页一样脏的原始文件:项目语料的原样 pg23950.txt。它有 1,863,656 字节,带 21,682 个 Windows 换行符、782 字节的英文头部声明和 18,551 字节的英文尾部许可证,正文每 38 个字硬换一行,共 17,584 行。

最朴素的清洗是:直接拿它跑一条最常用的规则——C4 数据集的「只留以句末标点结尾的行」(C4 原版的标点是 . ! ? “,这里先替我们换成中文的 。!?」』”…):

  1. ① 朴素方案
  2. ② 它在哪失败
  3. ③ 改进方案
朴素方案原始文件直接逐行跑句末标点规则

在 17,584 行原始硬换行行上逐行判断:以中文句末标点结尾的留下,其余删掉。

  • 留下 4,299 行,占 24.45%;按字数算只留下 17.02%。
  • 如果照搬 C4 原版的英文句末标点 . ! ? “,一行都不剩:0 行。

网页的「硬换行」叫样板:导航栏、cookie 提示、分享按钮、推荐列表、页脚。Common Crawl 的每个快照同时提供两种格式:WARC 是原始 HTML,WET 是它自带的纯文本版。FineWeb 发现 WET 留下了太多样板和菜单文字,改用 trafilatura 从 WARC 里抽正文;在同样 28B token 的消融里,抽取后的数据训出的模型明显更好 。下面两个实验把这两件事都放到你手里:

概念 + 真算 · 网页 → 正文;我们的原始文件 → 段落

教学构造的小说网站网页(正文是《三國志演義》第一回的真实首段)。浏览器当场用 DOMParser 解析下面这份 HTML。

看 HTML 源码(1,223 个字符)
    🎯

    试三件事:① 在「网页」标签下切换两种抽取,读出样板占去标签结果的百分比——这就是 WET 式纯文本的问题;② 看「正文抽取」删掉每个块的理由:按所在区块、按链接占比、按长度,三类理由各对应一条常见启发式;③ 切到「我们的原始文件」,在「不还原」和「先拼回段落」之间来回点,整本书的留存率在 17.02% 和 94.27% 之间跳。

    改进一:把「有人觉得值得看」当过滤器

    GPT-2 的做法绕开了直接用 Common Crawl:作者只抓取 Reddit 上得到至少 3 karma 的外链,把「有人点过赞」当成质量的代理。4,500 万个链接,抽取正文、去重和启发式清洗后,得到约 800 万篇文档、40 GB 文本,叫 WebText;为了避免和测试集重叠,还删掉了所有维基百科页面 。

    它的问题是量:40 GB 文本离 15T token 差几个数量级,而且只覆盖被 Reddit 用户分享过的那一小部分网页。GPT-3 把这个思路反过来用:拿 WebText、维基和书当「好样本」训一个分类器,去 Common Crawl 里捞长得像它们的网页——这是第 3 课的起点。

    改进二:只看长相的规则

    量要大,就只能从全网快照出发,再用便宜的规则删掉明显的垃圾。两套最常被引用的规则:

    这些规则全部是在英文网页上设计、在英文网页上调阈值的。套到我们的书上会怎样?下面的求值器把两套规则逐条跑在三段真实原文、三段标明「教学构造」的网页文本和你输入的文本上;最下面是整本书 3,697 段的结果。

    算法模拟器 · 规则逐条求值(文档 × 规则,格内是实测值)
    🎯

    试三件事:① 在英文原版下读整本书那张表:「50–100,000 个词」一条就删掉 3,697 段——中文不用空格,按空白切出来每段最多 2 个「词」;② 切到「本课中文改写」,在「文言虚词表」和「现代虚词表」之间切换,看删除率怎么从 15.5% 跳到 46.1%(整本书「的」只出现 149 次,「之」7,833 次);③ 把最少字数拖到 0 再拖回 50,看被删的是谁:回目、诗、章末套话——再点「按回」,同样的规则按整回求值,几乎全部通过。

    它在哪失败

    规则本身很便宜,也确实有用:FineWeb 的基础过滤(URL 黑名单、fastText 英文识别、MassiveText 的质量与重复规则)在 96 个快照上留下约 36T token,训出的模型比不过滤的明显更好。但上面的实验暴露了三个问题,前两个是我们在自己语料上实测的,第三个来自 FineWeb 的消融:

    1. 规则绑着语言和文体。英文原版在整本书上一段不留;改成中文后,虚词表的选择又能让删除率差约 3 倍——现代汉语的高频虚词在文言小说里几乎不出现。
    2. 规则绑着求值单位。同一条句末标点规则,在硬换行的行上删掉 83% 的字,在段落上只删 6%;同一条「≥ 50 字」规则,按段删 8.8%,按回几乎不删。FineWeb 抽 WARC 而不用 WET,本质上也是在修正「单位」。
    3. 规则越严不等于越好。C4 的句末标点规则单独用时对 HellaSwag 提升最大,但删掉约 30% 的 token;FineWeb 最后没有用它,只用了其余的 C4 规则(合计删约 7%) 。

    FineWeb 给出的改进是用数据挑阈值:把同一个快照分别做「独立去重」和「全局去重」,当成一份高质量、一份低质量数据(第 2 课会讲为什么全局去重的那份更差),统计 50 多个指标,看哪些指标的分布在两份数据之间差得最多,再在低质量数据更密集的区间下刀。16 个候选里留下 3 条:以标点结尾的行占比 ≤ 0.12 就删(删 10.14% 的 token,C4 那条是 30%)、重复行字符占比 ≥ 0.1 就删(删 12.47%,MassiveText 原阈值是 0.2)、短于 30 字的行占比 ≥ 0.67 就删(删 3.73%);三条合用删约 22%,综合得分涨约 1 个点,并且超过了 C4 。

    ⚠

    常见误解一:「规则是通用的,抄来就能用。」Gopher 与 C4 的阈值是在英文网页上定的。原样套在中文上,「按空白数词」这一步就让整本书全军覆没;改成中文后,虚词表、长度门槛、句末标点集合全都要在你自己的数据上重新求值。

    常见误解二:「规则越严,数据越干净,模型越好。」C4 的句末标点规则删掉约 30% 的 token,FineWeb 用一条只删 10% 的替代规则反而更好。删掉的不全是垃圾,也有正常内容。

    常见误解三:「清洗步骤的先后无所谓。」同一条规则,在还原段落之前跑,整本书留下 17.02% 的字;之后跑,留下 94.27%。抽取与还原必须在任何逐行规则之前。

    🔍 「含字母的词 ≥ 80%」为什么全过?

    这条规则本来是为了删掉满是数字、符号的页面。它在实现里通常写成「这个词里有没有任何一个字符是字母」,而 Unicode 把汉字归在字母类(Lo)。所以一段中文按空白切成一个「词」,这个词里当然有字母——规则全部通过,但原因和设计者想的完全不同。这是「规则在别的语言上碰巧过」的例子:通过不代表它在检查你以为它在检查的东西。Python 的 str.isalpha() 与 JavaScript 的 /\p{L}/u 都把汉字当字母;gen_c07_corpus.py 与本课组件用的是同一口径。

    🔍 我们这部「干净」的书里有没有脏字符?

    有。整本书里有 17 处 ASCII 杂字符:大部分是用英文句点打的省略号「…」,还有两处看起来像录入错误的字母——「未知可去否?d憲英曰」「皇后曰:c內廷耳目頗多」,d 和 c 大概本该是「」」和「「」。「不含 ASCII 字母」这条规则会为了一个误植的字母删掉整段;更好的处理是修字,而不是删段。网页数据量太大,只能删;精选语料量小,值得修。

    放回演进图里

    规则过滤是预训练数据演进的第二代;它的前一代是 GPT-2 那种「让人当过滤器」。整张图在章首页,这里只看本课所在的位置:

    预训练数据的演进:每一代都被上一代的某个真数字逼出来
    1. 起点 有多少用多少:原始网页直接进训练 Common Crawl 原始快照
      解决了量几乎无限:Common Crawl 定期抓取全网,FineWeb 用了 96 个快照。
      卡在WET 纯文本里样板和菜单太多(FineWeb §3.2);我们的原始文件不还原硬换行就跑 C4 句末规则,整本书只剩 17.02% 的字。
    2. 第一代 让人当过滤器:只取被点过赞的链接 GPT-2 WebText,2019
      解决了Reddit 上至少 3 karma 的外链,4,500 万个链接,清洗后约 800 万文档、40 GB。
      卡在量太小:C6 算出的需求是十几 T token;而且只覆盖被分享过的那一小部分网页。
    3. 第二代 只看长相的规则过滤 C4 2019 · Gopher 2021 你在这里
      解决了句末标点、词数、平均词长、停用词、重复行……便宜,能在全网快照上跑。
      卡在绑语言、绑求值单位:英文原版在整本《三國志演義》3,697 段上通过 0 段;C4 句末标点规则删掉约 30% 的 token,FineWeb 最后没用它。
    4. 第二代 近重复去重:MinHash + 分桶 Broder 1997 → Lee 2021 → FineWeb 2024
      解决了C4 里一句话重复 61,036 次;去重后模型复述训练文本的频率降到 1/10。MinHash 把两两比较变成查桶。
      卡在去得越狠未必越好:跨 96 个快照全局去重只剩 4T,训不出更好的模型;每快照独立去重留 20T,才追平 RefinedWeb。
    5. 第三代 让模型给数据打分 CCNet 2019 · GPT-3 2020 → FineWeb-Edu、DCLM 2024
      解决了判断「有没有营养」:FineWeb-Edu 让 Llama-3-70B 标 46 万页、蒸馏成分类器,MMLU 33% → 37%。
      卡在参考语料的困惑度偏向「像参考」:我们模型写的胡话困惑度 93.417,低于真原文 273.209;阈值 3 删掉 92%,长程训练不够用。
    6. 第四代 配比:从手工权重到代理模型搜索 The Pile 2020 → DoReMi 2023
      解决了DoReMi 用 280M 代理模型搜域权重,8B 模型下游平均 +6.5 个点,达到基线快 2.6 倍。
      卡在权重一变就要重复:按 DoReMi 的权重花完 The Pile 的有效体量,YouTube 字幕要走约 16.9 遍(按字节近似 token,只看量级)。
    7. 第五代 数据墙:重复与合成 Muennighoff 2023 · WRAP 2024 · Phi-4 2024
      解决了重复 4 遍以内几乎等于新数据;改写真实网页(WRAP)预训练约快 3 倍;Phi-4 约 10T token 里合成占 40%。
      卡在让模型只吃自己生成的数据,分布的尾巴一代代消失:在三国演义真实字频上重采样,只出现 1 次的字每一代有约 36.8% 的概率丢掉,丢了就回不来。
    8. 第六代 按时机投放:退火 → mid-training MiniCPM、Llama 3 2024 → OLMo 2、Qwen3、GLM-5
      解决了最好的数据放到学习率衰减段(C5 的 WSD)加量;再发展成独立阶段,顺便拉长上下文。
      卡在同名不同方:Qwen3 的高质量阶段占 13.9%,Llama 3 的退火只占 2.6e-6;收益与学习率调度缠在一起,很难单独归因。
    数字口径:我们语料上的数字由 gen_c07_corpus.py 在《三國志演義》上实算(c07-*.json);FineWeb、GPT-2 数字出自本地 PDF;DoReMi、Muennighoff、WRAP、Phi-4、Qwen3、Llama 3 出自原文(核实记录见设计卡);「约 16.9 遍」「36.8%」「13.9%」在构建时现算。

    证据三问

    问本课的回答
    ① 它解决什么问题?从海量原始网页里,便宜地删掉样板、乱码、非目标语言和明显的垃圾,留下可以训练的正文
    ② 数学上为什么可能有效?没有数学保证。规则是对「好文本长什么样」的经验描述
    ③ 实验上为什么最后选了它?靠一条条消融:FineWeb 每加一步都比上一步好,也因为消融删掉了 C4 的句末标点规则 ;我们的实测只说明「规则在中文书上怎么失效」,不能证明哪条规则让模型更好

    一句话

    📌

    规则只看文本的长相:先把网页还原成正文,再在你自己的数据上逐条求值——英文规则原样套在中文上,会把最好的文本删光。

    🚦

    先停在这里:记住「先抽取还原、后跑规则;规则要在自己的数据上求值」。
    再深一层:打开 FineWeb 长文的「Developing additional heuristic filters」一节,对照本课的求值器,看它是怎么用两份数据的直方图挑出 0.12 这个阈值的。

    下一个缺口

    规则留下来的文本里,同一段话可能出现成千上万次,会怎样? → 第 2 课:同一段话在语料里出现几万次,会怎样?

    先记下一个线索:FineWeb 挑阈值时用的「低质量数据」,是同一个快照做了全局去重之后的版本。去重怎么会让数据变差?第 2 课兑现。

    你可能会问