Unigram 算法

概述

Unigram 是 SentencePiece 中常用的一种子词分词算法,和 BPE、WordPiece 的"从字符合并"方向相反:它先构建一个很大的候选词表,然后反复删除对语料似然影响最小的 token,直到词表缩小到目标大小。

它的核心是一个 Unigram 语言模型:假设每个 token 独立,一个词的概率等于其某种分词方式下所有 token 概率的乘积。

训练时用 EM 思想不断更新 token 概率,并用 Viterbi 算法找每个词概率最大的分词路径。

Unigram 的核心逻辑

与 BPE / WordPiece 的区别

算法 方向 合并/删除依据
BPE 从小到大合并 相邻对频率最高
WordPiece 从小到大合并 似然增益 P(xy)P(x)P(y)\frac{P(xy)}{P(x)P(y)}P(x)P(y)P(xy)
Unigram 从大到小删除 删除后语料 loss 增加最小

Unigram 的训练步骤:

  • 初始化一个大词表:比如所有字符 + 高频子串,或先用 BPE 生成一个较大词表。
  • E 步:用当前 token 概率,对语料中每个词找最优分词(Viterbi),统计 token 使用情况。
  • M 步:根据统计结果重新估计每个 token 的概率,使语料似然最大化。
  • 计算删除代价:对词表中每个 token,模拟删除它,重新分词并计算语料 loss 增量 ΔL。
  • 剪枝:删除 ΔL 最小的前 p% 个 token(如 10%)。
  • 重复,直到词表达到目标大小。单字符通常强制保留,保证任何词都能被分词。

数值例子:语料与初始词表

使用语料:

单词 频率
hug 10
pug 5
pun 12
bun 4
hugs 5

初始词表取所有出现的字符及部分高频子串:

text 复制代码
["h", "u", "g", "hu", "ug", "p", "pu", "n", "un", "b", "bu", "s", "hug", "gs", "ugs"]

统计每个 token 在语料中的总频率:

token 频率 计算来源
h 15 hug 10 + hugs 5
u 36 hug 10 + pug 5 + pun 12 + bun 4 + hugs 5
g 20 hug 10 + pug 5 + hugs 5
hu 15 hug 10 + hugs 5
ug 20 hug 10 + pug 5 + hugs 5
p 17 pug 5 + pun 12
pu 17 pug 5 + pun 12
n 16 pun 12 + bun 4
un 16 pun 12 + bun 4
b 4 bun 4
bu 4 bun 4
s 5 hugs 5
hug 15 hug 10 + hugs 5
gs 5 hugs 5
ugs 5 hugs 5

总频率:

15+36+20+15+20+17+17+16+16+4+4+5+15+5+5=210 15+36+20+15+20+17+17+16+16+4+4+5+15+5+5=210 15+36+20+15+20+17+17+16+16+4+4+5+15+5+5=210

因此每个 token 的概率是:

P(token)=freq(token)210 P(token) = \frac{\text{freq}(token)}{210} P(token)=210freq(token)

例如:

P(hug)=15210≈0.07143,P(ug)=20210≈0.09524 P(\text{hug}) = \frac{15}{210} \approx 0.07143, \quad P(\text{ug}) = \frac{20}{210} \approx 0.09524 P(hug)=21015≈0.07143,P(ug)=21020≈0.09524

对每个词找最优分词

Unigram 假设 token 独立,所以一种分词方式的概率是各 token 概率的乘积。我们枚举每个词的可能分词,选概率最大的。

"hug"

可能分词:

分词 概率
h u g 15210⋅36210⋅20210≈1.17×10−3\frac{15}{210} \cdot \frac{36}{210} \cdot \frac{20}{210} \approx 1.17 \times 10^{-3}21015⋅21036⋅21020≈1.17×10−3
hu g 15210⋅20210≈6.80×10−3\frac{15}{210} \cdot \frac{20}{210} \approx 6.80 \times 10^{-3}21015⋅21020≈6.80×10−3
h ug 15210⋅20210≈6.80×10−3\frac{15}{210} \cdot \frac{20}{210} \approx 6.80 \times 10^{-3}21015⋅21020≈6.80×10−3
hug 15210≈7.14×10−2\frac{15}{210} \approx 7.14 \times 10^{-2}21015≈7.14×10−2

最大是 hug ,概率:

P(hug)=15210=0.0714286 P(\text{hug}) = \frac{15}{210} = 0.0714286 P(hug)=21015=0.0714286

"pug"

分词 概率
p u g 17210⋅36210⋅20210≈1.32×10−3\frac{17}{210} \cdot \frac{36}{210} \cdot \frac{20}{210} \approx 1.32 \times 10^{-3}21017⋅21036⋅21020≈1.32×10−3
pu g 17210⋅20210≈7.71×10−3\frac{17}{210} \cdot \frac{20}{210} \approx 7.71 \times 10^{-3}21017⋅21020≈7.71×10−3
p ug 17210⋅20210≈7.71×10−3\frac{17}{210} \cdot \frac{20}{210} \approx 7.71 \times 10^{-3}21017⋅21020≈7.71×10−3

最大是 pu g 或 p ug,概率:

P(pug)=17210⋅20210=34044100≈0.0077098 P(\text{pug}) = \frac{17}{210} \cdot \frac{20}{210} = \frac{340}{44100} \approx 0.0077098 P(pug)=21017⋅21020=44100340≈0.0077098

"pun"

分词 概率
p u n 17210⋅36210⋅16210≈1.06×10−3\frac{17}{210} \cdot \frac{36}{210} \cdot \frac{16}{210} \approx 1.06 \times 10^{-3}21017⋅21036⋅21016≈1.06×10−3
pu n 17210⋅16210≈6.17×10−3\frac{17}{210} \cdot \frac{16}{210} \approx 6.17 \times 10^{-3}21017⋅21016≈6.17×10−3
p un 17210⋅16210≈6.17×10−3\frac{17}{210} \cdot \frac{16}{210} \approx 6.17 \times 10^{-3}21017⋅21016≈6.17×10−3

最大概率:

P(pun)=17210⋅16210=27244100≈0.0061678 P(\text{pun}) = \frac{17}{210} \cdot \frac{16}{210} = \frac{272}{44100} \approx 0.0061678 P(pun)=21017⋅21016=44100272≈0.0061678

"bun"

分词 概率
b u n 4210⋅36210⋅16210≈2.49×10−4\frac{4}{210} \cdot \frac{36}{210} \cdot \frac{16}{210} \approx 2.49 \times 10^{-4}2104⋅21036⋅21016≈2.49×10−4
bu n 4210⋅16210≈1.45×10−3\frac{4}{210} \cdot \frac{16}{210} \approx 1.45 \times 10^{-3}2104⋅21016≈1.45×10−3
b un 4210⋅16210≈1.45×10−3\frac{4}{210} \cdot \frac{16}{210} \approx 1.45 \times 10^{-3}2104⋅21016≈1.45×10−3

最大概率:

P(bun)=4210⋅16210=6444100≈0.0014512 P(\text{bun}) = \frac{4}{210} \cdot \frac{16}{210} = \frac{64}{44100} \approx 0.0014512 P(bun)=2104⋅21016=4410064≈0.0014512

"hugs"

分词 概率
hug s 15210⋅5210≈1.70×10−3\frac{15}{210} \cdot \frac{5}{210} \approx 1.70 \times 10^{-3}21015⋅2105≈1.70×10−3
hu gs 15210⋅5210≈1.70×10−3\frac{15}{210} \cdot \frac{5}{210} \approx 1.70 \times 10^{-3}21015⋅2105≈1.70×10−3
h ug s 15210⋅20210⋅5210≈1.62×10−4\frac{15}{210} \cdot \frac{20}{210} \cdot \frac{5}{210} \approx 1.62 \times 10^{-4}21015⋅21020⋅2105≈1.62×10−4

最大概率:

P(hugs)=15210⋅5210=7544100≈0.0017007 P(\text{hugs}) = \frac{15}{210} \cdot \frac{5}{210} = \frac{75}{44100} \approx 0.0017007 P(hugs)=21015⋅2105=4410075≈0.0017007

计算初始语料 Loss

Unigram 使用负对数似然:

Loss=−∑x∈Corpusfreq(x)⋅log⁡P(x) \text{Loss} = - \sum_{x \in \text{Corpus}} \text{freq}(x) \cdot \log P(x) Loss=−x∈Corpus∑freq(x)⋅logP(x)

其中 P(x) 是该词最优分词的概率。

代入:

单词 频率 最优概率 贡献
hug 10 0.0714286 10⋅(−log⁡0.0714286)=26.3910 \cdot (-\log 0.0714286) = 26.3910⋅(−log0.0714286)=26.39
pug 5 0.0077098 5⋅(−log⁡0.0077098)=24.335 \cdot (-\log 0.0077098) = 24.335⋅(−log0.0077098)=24.33
pun 12 0.0061678 12⋅(−log⁡0.0061678)=61.0612 \cdot (-\log 0.0061678) = 61.0612⋅(−log0.0061678)=61.06
bun 4 0.0014512 4⋅(−log⁡0.0014512)=26.144 \cdot (-\log 0.0014512) = 26.144⋅(−log0.0014512)=26.14
hugs 5 0.0017007 5⋅(−log⁡0.0017007)=31.885 \cdot (-\log 0.0017007) = 31.885⋅(−log0.0017007)=31.88

总 Loss:

26.39+24.33+61.06+26.14+31.88≈169.8

所以初始词表下的语料损失约为 169.8。

模拟删除 token,计算 Loss 增量

现在对词表中每个 token,假设删除它,看 loss 会增加多少。我们选几个有代表性的 token。

删除 "pu"

删除 "pu" 后,pug 和 pun 需要重新分词:

pug 原来:["pu", "g"],概率:

P(pu)P(g)=17210⋅20210 P(\text{pu})P(g) = \frac{17}{210} \cdot \frac{20}{210} P(pu)P(g)=21017⋅21020

删除 pu 后,可用 ["p", "ug"],概率:

P(p)P(ug)=17210⋅20210 P(p)P(ug) = \frac{17}{210} \cdot \frac{20}{210} P(p)P(ug)=21017⋅21020

完全相同。

pun 原来:["pu", "n"],概率:

P(pu)P(n)=17210⋅16210 P(\text{pu})P(n) = \frac{17}{210} \cdot \frac{16}{210} P(pu)P(n)=21017⋅21016

删除 pu 后,可用 ["p", "un"],概率:

P(p)P(un)=17210⋅16210 P(p)P(un) = \frac{17}{210} \cdot \frac{16}{210} P(p)P(un)=21017⋅21016

也完全相同。

因此删除 "pu" 后,所有词的最优概率不变,Loss 增量为:

ΔL(pu)=0 \Delta L(\text{pu}) = 0 ΔL(pu)=0

删除 "ug"

删除 "ug" 后:

  • pug 原来 "pu", "g" 仍可用,概率不变。
  • hugs 原来 "hug", "s" 仍可用,概率不变。
  • 其他词不依赖 "ug"。

所以:

ΔL(ug)=0 \Delta L(ug) = 0 ΔL(ug)=0

小结

  • 如果 ΔL(t)=0:删掉它,Loss 完全不变,说明这个 token 对模型没有贡献
  • 如果 ΔL(t)>0:删掉它,Loss 变大,说明它还有用。
  • ΔL(t) 越大,说明这个 token 越重要,越不应该删。

删除 "hug"

删除 "hug" 后,hug 和 hugs 会受影响。

"hug" 原来 ["hug"],概率:

P(hug)=15210=0.0714286 P(hug) = \frac{15}{210} = 0.0714286 P(hug)=21015=0.0714286

删除后最优变为 ["hu", "g"],概率:

P(hu)P(g)=15210⋅20210=30044100≈0.0068027 P(hu)P(g) = \frac{15}{210} \cdot \frac{20}{210} = \frac{300}{44100} \approx 0.0068027 P(hu)P(g)=21015⋅21020=44100300≈0.0068027

损失增加:

10⋅−log⁡(0.0068027)−(−log⁡(0.0714286))=10⋅log⁡0.07142860.0068027≈10⋅2.35=23.5 10 \cdot -\\log(0.0068027) - (-\\log(0.0714286)) = 10 \cdot \log \frac{0.0714286}{0.0068027} \approx 10 \cdot 2.35 = 23.5 10⋅−log(0.0068027)−(−log(0.0714286))=10⋅log0.00680270.0714286≈10⋅2.35=23.5

"hugs" 原来 ["hug", "s"],概率:

P(hug)P(s)=15210⋅5210 P(hug)P(s) = \frac{15}{210} \cdot \frac{5}{210} P(hug)P(s)=21015⋅2105

删除后可用 ["hu", "gs"],概率:

P(hu)P(gs)=15210⋅5210 P(hu)P(gs) = \frac{15}{210} \cdot \frac{5}{210} P(hu)P(gs)=21015⋅2105

概率不变,损失不增加。

所以:ΔL(hug)≈23.5\Delta L(hug) \approx 23.5ΔL(hug)≈23.5

因为 23.5 远大于 0,所以 "hug" 不会被删除。

Unigram 剪枝的规则是:每一轮删除 ΔL 最小的前 p% 个 token。

所以在这一轮剪枝中:

"pu" 和 "ug" 是最佳删除候选(ΔL = 0)

"hug" 是最不该删除的候选之一(ΔL = 23.5)

剪枝与词表更新

算法每轮会删除 ΔL\Delta LΔL 最小的前 p% 个 token。

例如设 p=10%,初始词表 15 个 token,则删除 1 个。

由于 "pu" 和 "ug" 的 ΔL=0,它们是最佳删除候选。

假设第一轮删除 "ug",则新词表频率总和变为:

210−20=190 210−20=190 210−20=190

更新后的概率重新归一化:

P(token)=freq(token)190 P(token) = \frac{freq(token)}{190} P(token)=190freq(token)

例如:P(hug)=15190≈0.07895P(hug) = \frac{15}{190} \approx 0.07895P(hug)=19015≈0.07895

然后重新运行 EM,更新分词和概率,再次计算每个 token 的删除代价,继续删除 ΔL 最小的 token。

如此反复,直到词表缩小到目标大小。

最终分词:Viterbi 找最大概率路径

训练完成后,对新词分词时,用 Viterbi 算法在词表构成的图中找概率最大的路径。

例如词表中有 h, u, g, hu, ug, hug 等,对单词 unhug 分词:

  • 从 u 开始,可能 u、un 等;
  • 到 n,最佳是 un;
  • 到 h,un + h;
  • 到 u,un + hu;
  • 到 g,un + hug。

最终得到:

text 复制代码
["un", "hug"]

这就是概率最大的分词路径。

总结

Unigram 算法可以概括为:

  1. 从大词表开始,而不是从小合并。

  2. 用 Unigram 语言模型定义词的概率:

    P(word)=max⁡segmentation∏t∈segP(t) P(word) = \max_{segmentation} \prod_{t \in seg} P(t) P(word)=segmentationmaxt∈seg∏P(t)

实际常用 Viterbi 找最大概率路径。

  1. 用 EM 更新 token 概率:E 步分词统计,M 步重估概率。

  2. 计算删除每个 token 的 loss 增量:

    ΔL(t)=Lnew−Lold \Delta L(t) = L_{new} - L_{old} ΔL(t)=Lnew−Lold

删除 ΔL 最小的 token。

  1. 重复剪枝,直到词表达到目标大小。

在上面的例子中,删除 "pu" 或 "ug" 不会增加语料 loss,因此它们会被优先删除;而删除 "hug" 会使 loss 增加约 23.5,因此会被保留。

通过这种"反向剪枝",Unigram 能自动保留对语料似然贡献最大的子词,最终得到一个紧凑且高效的分词词表。

相关推荐
小宋10211 小时前
Embedding 模型怎么无痛迁移:双写、回填、灰度切换与回滚实战
人工智能
Jazz_z1 小时前
如何用 C# 读取 Word 中的表格数据
开发语言·c#
yyk333241 小时前
PyTorch的CBOW词向量模型
深度学习
冯一川1 小时前
Python 实现与 Ollama 运行的模型对话
人工智能·python
pt10431 小时前
Cisco Splunk for AI Operations:AIOps企业实践
运维·人工智能·自动化
龙腾AI白云1 小时前
大模型的幻觉怎么治
人工智能·机器学习·知识图谱
车间溜盖子1 小时前
TE(TEC 半导体制冷片)Qc / Qh 冷热面基础定义
python
天赐范式1 小时前
天赐范式第168天:让子代开始从父代肩膀上演化——跨代β传递demo与完整代码
python·数字生命·天赐范式·动态运行时·跨代β传递·可继承性验证·digitallife
刘天远1 小时前
Agent系统接入编排:评分模型、状态机与Python门禁
数据库·人工智能·python