Skip to content

第 1 讲 文本预处理与分词

对应 Lecture 01 slideslecture-01-tokenization。本讲的目标是理解“字符怎样变成整数序列”以及词表选择带来的统计与计算权衡。

1. NLP 的任务、发展与困难

自然语言具有歧义、上下文依赖、隐含知识、长距离依赖和不断变化的用法。NLP 关心让计算机理解或生成语言,常见任务包括分类、序列标注、机器翻译、问答、摘要与生成。现代 LLM 把大量任务统一成条件序列建模:给定上下文 x,建模输出 y 的概率 pθ(yx)

完整数据流通常是:

text
原始字节 → Unicode 字符 → 规范化 → 预分词 → 子词算法 → token id → embedding

任何一步不一致,都会造成训练与推理分布偏移。

从符号规则到预训练模型

NLP 的技术路线大致经历了三个阶段:

  1. 符号主义阶段(约 1947—1969):依靠人工词典、语法规则和逻辑表示,机器翻译与图灵测试等问题在这一时期被正式提出。规则可解释,但覆盖真实语言现象的成本很高。
  2. 统计学习阶段(约 1970—2017):语料库与概率模型成为核心,HMM、最大熵、SVM、n-gram、LSTM、word2vec、Seq2Seq 和注意力依次把任务转化为“从数据估计参数”。
  3. Transformer 与大模型阶段(2017 至今):自注意力支持大规模并行预训练,ELMo、BERT、GPT 等模型把分类、翻译、问答和生成统一为预训练表示或条件生成问题。

它们不是替代关系:规则仍适合边界清楚、必须审计的模式;统计特征适合数据有限的基线;大模型擅长开放语境,但也需要检索、验证和安全约束。

为什么自然语言难处理

  • 句法歧义:同一词序可能对应不同的成分结构。
  • 语义歧义:一个词可能有多个词义,指代也依赖上下文。
  • 语用歧义:真实意图受说话人、场景和常识影响,字面意义并不充分。
  • 非规范表达:拼写错误、缩写、表情、方言、代码混排和缺失标点会不断产生新形式。
  • 形式与推理不一致:模型生成语法流畅的文本,不等于其事实、因果或数学推理正确。

由此,预处理的目标是在保留任务信息的前提下,建立稳定、可复现的离散表示。

2. 文本规范化

Unicode 与规范化

“看起来相同”的字符可能有不同码点序列,例如重音字符可由单一码点或“字母 + 组合附加符”表示。常见规范化形式:

  • NFC:先分解再尽量合成,常用于保留自然书写形式。
  • NFD:规范分解。
  • NFKC/NFKD:兼容分解,会把全角、上标或连字等兼容字符折叠,信息损失更大。

规范化策略必须与任务匹配。搜索系统可能希望统一全半角;代码模型则不能随便改变空格、大小写和符号。

正则表达式与清洗

正则适合局部、明确的模式,如 URL、邮箱、重复空白和标点边界。常用结构包括:

  • [abc] 匹配集合中的一个字符,[A-Z] 表示范围,[^0-9] 表示否定字符类;
  • a|b 表示二选一,. 表示任意字符(是否含换行由模式决定);
  • ?*+ 分别表示零或一次、零或多次、一次或多次,{m,n} 指定次数范围;
  • (...) 用于分组或捕获,元字符要用反斜杠转义。

例如 [A-Za-z]+(?:'[A-Za-z]+)? 可以匹配普通英文单词及带一个撇号的形式。它仍只是任务相关的近似:连字符、人名、Unicode 字母和多重撇号都需要另行规定。不要用过度清洗“美化”语料;大小写、换行、表情、标签和拼写变体都可能承载语义。

WARNING

训练前清洗与线上推理必须复用同一条流水线。否则模型看到的 token 分布不同,指标会显著下降。

3. 最小编辑距离:文本对齐的基础工具

分词之前,课程先用最小编辑距离(Minimum Edit Distance, MED)说明如何把语言问题写成动态规划。给定源串 x1:m 与目标串 y1:n,允许插入、删除与替换。令 D(i,j) 表示把前缀 x1:i 变为 y1:j 的最小代价,则

D(i,j)=min{D(i1,j)+cdel,D(i,j1)+cins,D(i1,j1)+csub(xi,yj).

边界为 D(i,0)=icdelD(0,j)=jcins。若字符相同,替换代价通常为 0;否则可设为 1,也可让替换代价为 2,以体现“一次删除加一次插入”。填表复杂度为 O(mn),空间也为 O(mn);只求距离时可滚动数组降到 O(min(m,n))

从右下角回溯最优路径可以恢复字符对齐,这比单个距离更有解释力:拼写纠错需要知道改了哪里,语音识别的 WER 需要分别统计 substitution、deletion 与 insertion:

WER=S+D+IN.

MED 与 tokenizer 的关系在于:二者都要求把原始字符串转成离散符号并规定边界。Unicode 规范化、大小写折叠或预分词策略一旦变化,距离和切分都会变化。

例如在插入、删除代价为 1、非相同字符替换代价为 2 时,intentionexecution 的最小代价为 8。不同代价函数会改变最优对齐,所以报告编辑距离时必须同时说明操作集合与代价。MED 的“状态、递推、回溯”也会在 Viterbi 解码和 CKY 句法分析中反复出现。

4. Heaps' Law:语料越大,词表仍会增长

设语料共有 N 个 token,观察到的不同词型数量为 |V(N)|。Heaps' Law 用经验幂律描述二者关系:

|V(N)|=KNβ,

其中 K 与语料、语言及分词规则有关,常见量级为 10—100;β 通常约为 0.4—0.6。因为 0<β<1,词表增长是次线性的,但不会在有限语料后真正停止:新名字、拼写变体和专业术语仍会出现。

由此可得词型—词例比

|V(N)|N=KNβ1,

它会随语料增大而下降。Heaps' Law 解释了纯“按词建表”的根本困难:继续扩大训练数据会不断引入长尾词,而固定词表只能在 OOV、巨大输出层和更细粒度切分之间取舍。

5. 为什么不直接按词或字符切分

粒度优点缺点
字符/字节几乎没有 OOV,词表小序列很长,语义单位被拆散
单词序列短、语义直观词形变化和新词导致 OOV,词表巨大
子词在词表大小、序列长度和泛化间折中切分依赖语料,边界未必符合语言学直觉

子词分词的核心思想是:高频片段保留为整体,低频词拆成可复用的小片段。中文、代码、多语种和专有名词尤其需要关注 byte fallback 与词表覆盖。

6. BPE

Byte Pair Encoding 从最细粒度符号开始,反复合并语料中最频繁的相邻符号对:

  1. 初始化词表为字符或字节集合,并记录每个词的符号序列与频次。
  2. 统计所有相邻 pair 的加权频次。
  3. 选择频次最高的 pair (a,b),创建新符号 ab
  4. 在全语料替换该 pair,记录 merge rule。
  5. 达到目标词表大小或合并次数后停止。

训练复杂度的关键在于避免每轮全量重算 pair;实际实现会维护 pair 到出现位置/词频的索引,并只更新受合并影响的邻域。

编码新文本时必须按训练得到的 merge 次序应用规则,而不是重新选局部最高频 pair。若以字节为基础,任意 Unicode 字符都能回退为字节序列,代价是罕见文本 token 数变多。

一个最小合并例子

假设语料词频为 low:5, lower:2, newest:6, widest:3,初始把每个词写成字符序列并添加词尾标记。相邻 pair 的计数必须乘词频;若 (e,s) 频次最高,就先合并为 es,随后只重新统计受该合并影响的邻域。最终得到的是“初始符号表 + 有序 merge rules”。

编码 lowest 时,先按初始符号切开,再严格按全局 merge rule 的优先级合并;训练频次不会在编码阶段重新计算。这个区别是 BPE 作业中最常见的错误来源。

7. WordPiece 与 Unigram

WordPiece

WordPiece 也逐步构造词表,但合并标准通常关注 pair 相对于组成部分频率的收益,可直观写成:

score(a,b)f(ab)f(a)f(b).

它倾向合并“共同出现强、单独出现弱”的片段。BERT 系模型常使用 WordPiece,并以 ## 标记非词首子词。

Unigram Language Model

Unigram 从较大的候选子词集合出发,为每个子词赋概率。一个字符串 x 的一种切分 s=(t1,,tm) 的概率为

p(s)=i=1mp(ti).

训练交替估计 token 概率并删除损失最小的候选;编码可用 Viterbi 找最大概率切分,也可对子词切分采样,形成 subword regularization。

SentencePiece 是框架而非第四种合并准则

SentencePiece 直接在原始 Unicode 字符串上训练,常用 BPE 或 Unigram 作为内部算法。它把空格编码为显式符号(常见显示为 ),避免依赖语言特定的预分词器,适合中文、日文和多语模型。训练时可配置字符覆盖率、规范化规则、byte fallback 与特殊 token;这些配置都属于模型的一部分,不能只保存词表文件。

方法构造方向主要打分常见特点
BPE从小词表向上合并pair 频次确定、快速、工程成熟
WordPiece从小词表向上合并似然增益的近似常与预分词及 ## 约定结合
Unigram从大候选集向下剪枝语料似然损失可保留多种切分并采样
SentencePiece训练与编码框架BPE 或 Unigram可直接处理原始文本与多语空格

8. 词表设计的系统权衡

设词表大小为 V、平均序列长度为 T(V)、隐藏维度为 d。更大的词表通常缩短序列,但增加 embedding 与输出层参数,约为 O(Vd);注意力计算随长度约为 O(T2d)。因此不存在对所有语言、领域和算力都最优的固定 V

评估 tokenizer 不应只看压缩率,还要看:

  • fertility:每个词平均拆成多少 token;
  • 不同语言之间的 token 成本公平性;
  • 数字、代码、空白和专业术语的稳定性;
  • 词表利用率、未知字符回退和可逆解码;
  • 对恶意插入空格、同形异码字符和特殊 Unicode 序列的鲁棒性;
  • 下游任务表现与总训练/推理 FLOPs。

readings 中的“词表 scaling law”进一步提醒:词表变大同时改变序列长度、embedding 参数、softmax 成本和每种语言的 token 预算。英文上合适的词表不一定适合中文或代码;多语模型若只优化总体压缩率,可能让低资源语言被拆得更碎,推理价格也随之更高。

9. 训练与推理必须共享同一协议

一个 tokenizer 不只是 token → id 映射,而是下面这组协议的组合:

text
normalizer + pre-tokenizer + model(BPE/Unigram/...)
+ post-processor + special-token map + decoder

预训练时若使用 BOS text EOS,SFT 又套用 chat template,推理时就必须复现同样的角色标记与空格规则。特殊 token 要么被预先保留、禁止普通合并,要么在 post-processing 中插入。新增 token 后还要扩展模型输入 embedding 和输出投影;只修改 tokenizer 文件会产生越界 id 或随机未训练向量。

10. 实现检查点

一个可验证的 BPE 实现至少应满足:

  • 合并频次相同的 pair 时有确定性 tie-break;
  • 统计频次时考虑词在语料中的出现次数;
  • 特殊 token 不参与普通合并;
  • decode(encode(text)) 在约定规范化后可逆;
  • 保存词表、merge rules、normalizer、pre-tokenizer 和特殊 token 配置。

延伸阅读