🥎分词
type
status
date
slug
summary
category
tags
icon
password
AI summary
Blocked by
Blocking
Category
一、为什么要分词
考虑一个简单的句子
Hello world,不分词直接拆成字符:H、e、l、l、o、空格、w、o、r、l、d共11个字符:- 语义完全丢失
- 一个复杂的句子或片段拆分出来的字母序列非常长
考虑直接空格分词:
- 中文没有空格,多语言不支持
Token和Tokenization语义相近,但词表里是两个毫不相关的词,再来一个Tokenizer就不认识了
- 词表巨大(OOV)
概括一下:
- 语言的开放性:语种、语法、专业词汇、人名、地名、网络梗、……
- 模型的泛化能力:理解词与词的关系,提高学习效率
- 计算效率:Transformer的自注意力机制计算复杂度为O(N^2)
在语义、泛化能力、效率之间达到平衡:$$\text{有效性} \propto \frac{\text{语义保持}}{( \text{词表大小} + \text{序列长度} )}$$
二、BPE(Byte Pair Encoding)
把最常见的字节对合并为一个新符号以减少长度
步骤:
- 把训练语料的每个词看作由字符组成的序列,通常在每个词尾加一个特殊结束符(比如
</w>)以保存词边界信息。
- 统计整个语料中所有相邻符号对(pair,例如
('l','o')或('o','w'))的出现频率。
- 找到出现频率最高的符号对,把它们合并成一个新符号(比如把
'l'+'o'合并成'lo')。
- 在语料中用新符号替换所有该对出现位置。
- 重复步骤 2–4,直到达到预定的合并次数或词表大小。
训练结果是一系列“合并操作(merge ops)”或最终词表。用于推理时,对新词按同样策略进行合并(贪心地应用已学合并),得到子词序列。
举个🌰:
- 给定一组语料:
- </w>作为结尾保留边界,初始化
- 统计初始相邻对频率
- low</w>:(l,o) (o,w) (w, </w>)
- lower</w>:(l,o) (o,w) (w,e) (e,r) (r, </w>)
- lowest</w>:(l,o) (o,w) (w,e) (e,s) (s, t) (t, </w>)
频率表:
pair | 计数 |
(l,o) | 3 |
(o,w) | 3 |
(w,e) | 2 |
(w,</w>) | 1 |
(e,r) | 1 |
(r,</w>) | 1 |
(e,s) | 1 |
(s,t) | 1 |
(t,</w>) | 1 |
频率最高的是(l,o) (o,w),先合并(l,o),也可以定义不同的优先级选取不同的结果
- 合并(l,o) -> lo
- 更新频率表
pair | 计数 |
(lo,w) | 3 |
(w, e) | 2 |
(w,</w>) | 1 |
(e,r) | 1 |
(e,s) | 1 |
(s,t) | 1 |
(t,</w>) | 1 |
(r,</w>) | 1 |
频率最高的是(lo,w)
- 再合并(lo, w) -> low
pair | 计数 |
(low, e) | 2 |
(low, </w>) | 1 |
(e,r) | 1 |
(e,s) | 1 |
(s,t) | 1 |
(t,</w>) | 1 |
(r,</w>) | 1 |
除主项之外,其余项的频率都是1,没有再继续合并的必要,算法终止
- 最终合并结果:
编码一个输入:lower
初始:
l o w e r </w>贪心匹配:
- l + o -> lo =>
lo w e r </w>
- lo + w -> low =>
low e r </w>
- low + e -> lowe =>
lowe r </w>
最终tokens:
三、WordPiece
评价函数
基于BPE,在如何选择新的字词上做概率计算,每次选择加入词表的子词,都是为了最大化训练语料在当前词表下的似然(或最大减少负对数似然),说人话就是:优先合并那些组合在一起后,看起来更像一个整体的、有意义的 Token的字符对,而不是仅仅是高频的随机组合,进而减小token数量
数学表达:$$\text{Score}(\text{A}, \text{B}) = \log\left( \frac{P(\text{A}, \text{B})}{P(\text{A}) \cdot P(\text{B})} \right)$$
其中,P(*)是 Token 在训练语料中出现的概率
- P(A)·P(B) : 表示如果A和B是两个独立事件(即它们随机相邻),它们同时出现的概率。
- P(A,B): 表示A和B 实际相邻出现的概率(作为整体)
那么如果Score越大,说明 $$P(\text{A}, \text{B}){}$$比 $$P(\text{A}) \cdot P(\text{B})$$大得多,就说明A和B相邻不是一个偶然事件,以整体的形式出现更有意义
再举例🌰
- 还是这组语料
初始词表为:
{ l, o, w, e, r, s, t, </w> }- 统计相邻对
- (l,o): 3
- (o,w): 3
- (w,e): 2
- 其它都是 1
如果把
lo(l+o)作为新 token,会对训练语料的似然增益有多大贡献?同理评估ow(o+w)、we,这里选择(l,o) → lo,因为英语里lo的组合更具语义,胜过ow组合- 再评估
- (lo, w): 3
- (w, e): 2
- 其余 1
(lo,w) → low在三个单词中都能减少token数量,显著提升似然- 再次评估
- (low, e): 2
- others 1
得到词表:
{ l, o, w, e, r, s, t, </w>, lo, low, lowe }编码一个输入:lowest
按最新词表用 longest-match-first:
- 从左到右,先试最长匹配:
lowe存在 → 输出lowe
- 余下
s t </w>,st</w>不在表;尝试s→ 存在 → 输出s
- 剩
t </w>→ 输出t</w>或t+</w>取决实现
最终得到tokens:
问题:
- 多语言怎么办?
- 没空格怎么办?
四、SentencePiece
基本思想:大词表优化
- 给定一组候选 token,生成初始的候选词表
- 不断移除不重要的 token
- 最后剩下最能表达语料的 token
特殊处理:把空格映射为
_,这样能对所有语言生效最后举例🌰
预处理后:
- 初始大词表
- 对语料分词,以“_我爱学习”为例
同理,列出每段语料可能的分词情况
- 计算每个token对语料的贡献得分
- 定性分析
token | 使用频率(想象即可) |
▁我 | 很高 |
爱 | 很高 |
学习 | 高 |
北京 | 高 |
你 | 一般 |
我 | 偶尔(因为多数用了“▁我”) |
▁我爱学习 | 几乎不用 |
▁我爱北京 | 几乎不用 |
▁我爱你 | 几乎不用 |
- 实际的定量计算是一套关于后验概率和概率期望值的复杂计算
- 去除贡献得分低的token
- 重复步骤2-4,重新分词,计算新token的贡献得分
token | 被使用次数 |
▁我 | 很高 |
爱 | 很高 |
学习 | 高 |
北京 | 高 |
你 | 中 |
北 | 少 |
京 | 少 |
- 得到最终词表
总结
- 分词的原因:语义、泛化能力、效率之间达到平衡
- 三种分词算法:BPE、WordPiece、SentencePiece
特性 / 算法 | BPE(Byte Pair Encoding) | WordPiece | SentencePiece(Unigram/BPE) |
核心思想 | 频繁 token 对合并 | 最大似然概率合并(基于语言模型) | 用概率模型选最优 token 序列 |
输入处理 | 只能处理空格分好词的文本 | 同 BPE(依赖空格) | 不依赖空格,直接基于字符序列 |
空格处理方式 | 需要预先空格分词 | 需要预先空格分词 | 将空格视为「▁」符号,直接处理原始文本 |
词表构建方式 | 贪心:频率最高的 pair | 贪心 + 概率:最大化 likelihood | 基于概率模型:删除低贡献 token |
优点 | 简单、高效 | 拆分结果更自然 | 最灵活,最通用,不依赖空格 |
缺点 | 不考虑上下文概率 | 仍需空格分词 | 训练复杂度高一点 |
典型应用 | GPT、LLaMA 早期模型 | BERT | GPT-4、T5、现代模型 |
Prev
vLLM 初体验
Next
k8s informer 架构
Loading...