想象你是一位裁缝师傅,老板递来一批五颜六色的布料,要求你把它裁成一套标准大小的补丁包,方便缝纫工随时取用。每条布纹理不同,有人名、地名、网络符号、标点——有的部位经常被用到(比如“老师”这个词),你就整块保留;有的布料过于生僻(比如“宇智波斑”),整块存着太占地方,你就剪成“宇智波”+“斑”这样的常用碎片。关键问题是:怎么剪才既省料、又让缝纫工拼得回去? 大模型的世界里,这台剪布机叫 Tokenizer(分词器)。它把未经加工的文本(一匹匹布)先剪成标准化的 token(词元),模型才能读取。当前最火的剪裁方案,叫 SentencePiece——LLaMA、BLOOM 等主流大模型都用它来切词。它底层是一套叫 Unigram 语言模型 的智能裁缝:不靠死记硬背的规则,而是用“概率”来衡量每块补丁的性价比,自动找出最优裁剪方案。 本文会带你从一块布出发,看懂 BPE 和 Unigram 两种剪法的本质区别、词表大小怎么定、以及为什么这套方案在中文、日语、多语言混排的“杂色布料”上格外好用。读完你就明白:大模型背后的分词器,其实是一台会算概率的裁缝铺。
掌握分词原理,你能独立评估大模型的词表设计优劣,在预训练数据预处理、推理服务优化时做出更聪明的工程决策——这是理解 LLaMA、BLOOM 一切行为的起点。
可视化演示
展示Unigram语言模型的Viterbi子词切分过程与BPE算法的核心差异,对比自底向上合并与自顶向下删减两种词汇表构建策略。
本节配有交互动效(进入视口后自动加载,约 3KB)。
Unigram子词切分过程 输入字符经Viterbi解码,从词汇表选概率最大的子词组合 每个子词有概率分数,切分目标是最小化负对数似然 argmax P(w) = Π P(sub_i),L = -Σlog P(sub_i) Unigram通过概率选最优切分,语言无关
分词基础
裁缝铺开门第一课:布料不能整匹塞进缝纫机,得先剪成补丁。模型也一样,原始文本是一整段连续的字符流,Transformer 这类模型没法直接“读”字符串——它只能识别离散的编号。分词器要做的,就是把“自然语言处理”这匹布,剪成“自然”“语言”“处理”这样的标准补丁,每个补丁编一个号(token id),模型才看得懂。
为什么不能直接逐字裁剪?如果按单字剪,词表只需要几千个编号,但一句话会变得很长,模型要处理很长的序列,记不住远距离的依赖关系。如果按整词剪,常用词没毛病,但“元宇宙”“大模型”这类新词不断冒出来,词表装不下,遇到没见过的词只能干瞪眼。于是聪明人发明了子词(subword):介于字与词之间的粒度。把“大语言模型”切成“大语言”+“模型”,既保留了语义,又不至于让词表爆炸。
分词器还讲“语言无关”——不管中文、日文还是英文,都按同一套字符逻辑处理。中文天然紧凑,英文有空格分界,但 Unicode 字符在底层都是字节串,子词算法不关心你原来是哪种语言,只问“哪块布最常用”。这也是 SentencePiece 能统一处理多语言的根本原因。
回到裁缝铺的比喻:分词基础就是这个铺子的“补丁尺寸标准”。剪多大、分几档、如何编号,定了之后所有工序都照着执行。标准定得好,后面缝纫(训练)就顺畅;定得差,模型再强也事倍功半。
- token 流分词器把原始文本拆成有序的子词序列,每个 $t_i$ 是词表中的一个元素。
- 词表预训练前预先定义好的全部合法子词集合,模型只能“说”这些词。
- 一一映射模型输入的每个 token 会被查表映射成向量——就像裁缝根据补丁编号找到对应颜色和质地的布料。
BPE算法
裁缝铺有一种老派裁剪法,叫 BPE(Byte Pair Encoding,字节对编码)。它的思路很简单:从最小的布粒出发,谁经常被拼在一起,就把谁缝成一块大补丁。 比如语料里反复出现“low”和“est”相邻——2 万次——那裁缝就决定把这两个小布粒缝死成“lowest”,以后不再拆开。
BPE 的裁剪过程是纯统计驱动的。先要把文本拆成最细的字符(或字节),然后统计所有相邻字符对的共现频次。比如语料里有“低 low 低”,相邻对 “l o” 出现 10 次,“o w” 出现 8 次……每次只挑频次最高的那一对合并成一个新符号,然后重复统计、合并,直到词表大小达到预设目标。
这个“贪心”策略有三个关键设计。第一,合并规则全程按字符对频次走,不看语义,纯靠统计——所以它快,但偶尔会剪出不伦不类的补丁。第二,迭代必须设停止条件:词表达到 32000 就算完工,否则会一路合并成整句,丧失子词灵活性。第三,字节回退(byte fallback):遇到词表里根本没有的生僻字符,BPE 允许退回到 UTF-8 字节级别兜底,保证任何文本都能被切出来,这就像裁缝铺保留了一台万能锁边机。
BPE 的局限恰恰来自它的“贪”:它只看到局部共现,不看整体概率。就像裁缝只盯着哪两块布常挨着,却不管缝出来的补丁包在整套服装里是否协调。这种“局部最优、全局未必最优”的缺陷,正是 Unigram 语言模型要解决的。
- 候选对扫描当前词表,找出所有相邻符号对 $(a,b)$,比如 “(l,o)”“(o,w)”。
- 统计频次数一数每个候选对在整个语料中出现了多少次,出现越多越优先。
- 选最优取频次最大的那对作为本轮合并对象。
- 合并入库把 $(a^*,b^*)$ 合并成一个新符号写入词表,下一轮重新统计。
Unigram原理
Unigram 是一种更先进的裁缝哲学:不盲目合并,而是给每块补丁标一个“信任价”,用概率决定谁留下、谁淘汰。 它的核心想法是:训练语料整体出现的概率等于所有分词路径里,各子词概率连乘(取对数后相加)的最大值。裁缝手里有一副牌,每种剪法是一手牌,Unigram 会挑“最顺”的那手出。
数学上,Unigram 给每个子词 $t$ 赋予一个概率 $P(t)$,且全部子词概率之和为 1。给定一个句子 $x$,候选分段方式很多,比如“自然语言”→“自然/语言”或“自/然语/言”。Unigram 认为句子的概率是所有可行切分路径的概率之和,训练目标就是最大化这个总似然——也就是让裁缝在各个剪法中都能拼出一个完整句子,而不是只赌一种剪法。
有了概率模型,选出最优切分就用 Viterbi(维特比)算法:把每个字符位置看作节点,子词作为边,边的权重是 $\log P(t)$,然后找一条从开头到结尾、总权重最大的路径。这个动态规划过程像裁缝在纸上画网格,从起点逐格推进,只保留每个位置的最佳累计得分,最终回溯出完整裁剪方案。
训练词表时则用 EM(期望最大化)算法交替迭代:E 步用当前概率给语料分词,统计每个候选子词被选中的期望次数;M 步用统计结果重新归一化更新 $P(t)$,然后丢掉概率过低的子词。多轮迭代后,词表会收敛到一个“性价比”高的集合——生僻且无用的补丁被淘汰,常用组合被保留,这正是 SentencePiece 的精髓。
回到比喻:BPE 是凭经验缝合布粒的老裁缝,Unigram 则是拿计算器核算每块布成本的精算师。老裁缝快,但容易剪出怪补丁;精算师慢,却能从全局最优出发优化词表。理解了 Unigram 的“概率加总”逻辑,你才能明白为什么它比 BPE 更擅长处理多语言混杂的复杂文本。
- 切分集合$S(x)$ 表示句子 $x$ 所有合法的子词切分方式,每种切分是一组子词序列。
- 单路径概率一种切分方式的概率是其中各子词概率的连乘。
- 全路径求和句子概率 = 所有切分方式的概率之和,而不是只取最大。
- 取对数对数把连乘变成连加,数值更稳定,也便于后续用 EM 优化。
SentencePiece
实践中的 Unigram 模型被封装进一个叫 SentencePiece 的成熟工具库,LLaMA、BLOOM 都直接用它做分词。如果说 Unigram 是数学原理,SentencePiece 就是把这套原理开成一家标准化裁缝连锁店——只留几个好用的按钮,但把流程锁死,保证任何人用都能得到一致结果。
SentencePiece 的第一个特色是直接从原始文本训练,不需要预先切好词。传统分词器(如 BERT 的 WordPiece)要先用空格把词分开,再在上面切子词;但中文、日文没有空格,SentencePiece 把整个句子当作连续字符流直接开工,这让它天然适合 CJK(中日韩)语言。它把空格编码成特殊符号 ▁(下划线形状),这样空格也变成普通 token,模型能明确知道哪里该断词。
第二个特色是自带特殊 token。分词器会自动在句子首尾加上 [BOS] 和 [EOS] 标记,分别表示“布料开头”和“布料结尾”。BOS 让模型知道一个句子从哪里开始,EOS 让模型学会“说完了”就停止生成——这对生成式模型至关重要,否则模型会无限续写。
第三个特色在实现层面:SentencePiece 用直接切分(direct segmentation),训练时无需对语料做语言相关的预处理(如 lowercase、Unicode 规范化),它把原始字符当作不可变的原子。空白处理(▁)、BOS/EOS 等特殊 token 都在训练前自动注入,用户只需给定词表大小这一超参数。这种“傻瓜化”设计让多语言团队的开发成本大幅降低。
这套标准化流程正是裁缝连锁店的精髓:不管你送来的是英文小说还是中文公告,进门一律按“🔲开头—剪裁—🔲结尾”的固定流程处理,出来的补丁包规格完全统一。模型侧因此可以放心假设:所有输入都有明确边界,不会遇到格式错乱。
▁,并在序列两端固定添加 BOS 和 EOS,形成模型真正看到的 token 流。- BOS 起点序列开头插入
[BOS],告诉模型“新句子开始”。 - 句子主体原始句子按 Unigram 最优切分,词与词之间用
▁标记空白。 - EOS 终点结尾插入
[EOS],模型生成到它会自动停止。 - 完整序列拼接成带边界的 token 序列,长度 $m+2$。
词表策略
裁缝铺开了几家分店,每家的补丁目录大小不一样:有的只备 8000 块补丁,有的备到 32 万块。词表大小是分词器最重要的旋钮,它直接牵动模型性能与训练成本的平衡。
如果词表太小(如 8K),你会遇到两个问题。第一,很多常用词切不成整块,比如“机器学习”可能被切成一堆单字,句子被拉得很长,序列长度上升导致注意力计算和显存开销暴涨。第二,同一概念被反复拆成碎片,模型难以学到稳定的语义表示,下游任务表现变差。这就像裁缝只有小布块,缝一件大衣要拼上百块,费时费力还容易错位。
如果词表太大(如 250K),问题反过来。词表太大意味着 Embedding 层和输出层参数剧增——每个 token 都要一个向量,假设隐藏维度 4096,25 万词表光 embedding 就有 10 亿参数,训练和推理的开销显著上升。而且词表过大时很多生僻 token 在整个预训练语料里只出现几次,学不到好表示,属于“闲置补丁”,白白占仓库。
工程上有一个经验法则:让平均每个 token 对应约 3-4 个字符(中文场景),同时用覆盖率来评估词表是否合适——覆盖率指训练语料中被词表直接覆盖的字符比例,一般设 99.95% 以上。稀有词的处理策略也很关键:Unigram 天然会把生僻词切成更小的常见子词,这比直接把整词删掉更稳妥,因为它保证了“再怪的词也能拼出来”。
回到比喻:词表策略就是决定“仓库备多少种补丁”。备太多,租金(参数)贵;备太少,缝纫费劲(序列变长)。好的裁缝会根据客户群——也就是语料分布——定制目录,而不是拍脑袋定数字。这也是为什么 LLaMA 和 BLOOM 各选了与自己语料匹配的不同词表大小。
- 对数似然把分词后每个 token 的概率取对数再累加,表示模型“读顺”这段文本的程度。
- 取平均除以 token 总数 $N$,消除文本长度影响,便于跨句子比较。
- 取负指数负号让“越顺畅越大”,指数还原成正数,得到可读的 PPL 值。
- 模型选择分词方案 A 的 PPL 更低,就选 A——就像裁缝比价,同样效果谁更省料用谁。
大模型应用
最后,我们从裁缝铺走进真正的大模型工厂。LLaMA(Meta 开源的 Llama 系列)选择词表大小 32000,这个数字并非随意——它在模型容量与文本压缩率之间取得平衡。32K 词表下,英文 token 平均覆盖约 3.7 个字符,模型参数量可控(7B 模型 embedding 约 1.3 亿参数,占比不到 2%),同时多语言文本都能被有效编码。
BLOOM(BigScience 开源的多语言模型)则走了另一条路:它训练语料覆盖 46 种自然语言和 13 种编程语言,因此把词表扩到 250880。这么大的词表是为了给每种语言都留足“常用补丁”,避免冷门语言过度依赖字节兜底。代价是 embedding 参数巨大,但在 BLOOM 的设计里,这部分开销换来了跨语言一致性和低 token 数——法语、中文、阿拉伯语都能以较短的序列表达。
多语言之所以可行,靠的正是 Unigram 的共享子词单元能力。不同语言的文本在顶层“字符”不同,但字节层面高度重叠。比如英文“play”和中文“播放”机制不同,但阿拉伯文、西里尔文等字符经过 UTF-8 编码后,在子词层会存在可共享的字节片段。Unigram 概率模型会自动发现这种跨语言共现结构,把多语言布料统一裁剪成一套补丁。
推理阶段,模型对词表做 softmax 采样:输出层给每个 token 一个 logit 分数,除以温度参数后转成概率分布,再采样得到下一个 token。分词器的词表质量直接影响采样空间——如果词表切得太碎,模型每步只能推进一两个字符,生成效率低且容易跑偏;切得太粗,则选择空间不足,句式生硬。恰当的词表就像裁缝备好了尺寸合身的拼图,让生成过程行云流水。
回看整条链:从分词基础到词表策略,再到 LLaMA 与 BLOOM 的差异,你会发现分词器从来不是配角。它是模型认识世界的第一道关口——Unigram 概率化裁剪让多语言共享一把剪刀,SentencePiece 则把剪刀标准化、工厂化,让任何团队都能快速为自家大模型定制合身的补丁包。
- logit 得分模型输出层为每个 token 计算原始得分 $z_j$,表示“该 token 在当前位置的适合程度”。
- 温度缩放除以温度 $\tau$,$\tau$ 大则分布趋于均匀,$\tau$ 小则分布尖锐。
- softmax 归一化指数化后除以所有 token 得分之和,得到合法概率分布。
- 抽样选择按概率采样——高概率 token 更容易被选中,但低概率 token 也有机会,增加生成多样性。
AI 应用场景
多语言大模型预训练数据处理
阶段:数据预处理 / Tokenization
解决的问题:传统分词器(如 BERT WordPiece)需要预先按空格分词,遇到中文、日语等无空格语言直接失效,且词表无法跨语言共享。采用 SentencePiece + Unigram 后,能统一处理 46 种语言,训练时无需任何语言特定预处理流程。
具体案例:BLOOM 训练团队收集了涵盖法语、中文、阿拉伯语、斯瓦希里语等 46 种语言的原始语料。如果按老办法逐语言定制分词器,需维护 46 套流程;改用 SentencePiece 后,一套 Unigram 词表覆盖全部语言,训练数据管线只剩“喂文本→出 token→训练”三步。
大模型推理服务的显存优化
阶段:推理优化 / 序列长度控制
解决的问题:大模型部署时 KV Cache 显存随序列长度线性增长。分词过碎时同样一句话被切成更多 token,直接导致显存超限。通过 Unigram 概率模型挑选覆盖率高的词表,可压缩序列长度,降低推理成本。
具体案例:某团队基于 Llama 2 做中文客服机器人,初版词表切中文时“银行卡余额”被切成 11 个 token;换用 SentencePiece 在中文语料上重训 32K 词表后,同句仅 5 个 token,KV Cache 显存占用下降约 45%,响应延迟减半。
代码大模型的多语言符号覆盖
阶段:训练数据清洗
解决的问题:编程语言中存在大量特殊符号(=>、::、{ 等),纯字符级切分会让序列爆炸。Unigram 能自动把高频符号组合吸收成独立 token,代码理解效率显著提升。
具体案例:StarCoder 项目在训练前用 SentencePiece 处理 GitHub 代码语料,自动识别出 Python、Java、C++ 各自的惯用语法片段(如 def 、public class)作为统一 token,使模型生成代码时的语法错误率降低 30%。
Python 演示
import refrom collections import defaultdictfrom math import log, exp class MiniUnigram: def __init__(self, corpus, vocab_size=18, iters=30): self.corpus = corpus self.vocab_size = vocab_size self.iters = iters self.vocab = set() self.prob_cache = {} def _seed_vocab(self): char_set = set() for sent in self.corpus: char_set.update(list(sent)) self.vocab = set(char_set) for token in self._freq_2grams(): if len(self.vocab) < self.vocab_size: self.vocab.add(token) def _freq_2grams(self): cnt = defaultdict(int) for sent in self.corpus: for a, b in zip(sent, sent[1:]): cnt[a + b] += 1 return sorted(cnt, key=cnt.get, reverse=True)[: self.vocab_size] def _all_segmentations(self, text): n = len(text) dp = [[] for _ in range(n + 1)] dp[0] = [()] for i in range(1, n + 1): paths = [] for j in range(max(0, i - 4), i): w = text[j:i] if w in self.vocab: for prev in dp[j]: if len(prev) < 6: paths.append(prev + (w,)) dp[i] = paths return dp[n] def _update_probs(self): self.prob_cache = {} cnt = defaultdict(float) logsum = defaultdict(float) for sent in self.corpus: for path in self._all_segmentations(sent): score = sum(log(self.prob_cache.get(w, 0.01)) for w in path) logsum[path] = score for sent in self.corpus: paths = self._all_segmentations(sent) if not paths: continue max_score = max(logsum[p] for p in paths) denom = sum(exp(logsum[p] - max_score) for p in paths) for p in paths: weight = exp(logsum[p] - max_score) / denom for w in p: cnt[w] += weight total = sum(cnt.values()) self.prob_cache = {w: c / total for w, c in cnt.items()} def train(self): self._seed_vocab() for _ in range(self.iters): self._update_probs() if len(self.prob_cache) > self.vocab_size: drop = min(self.prob_cache, key=self.prob_cache.get) self.vocab.discard(drop) del self.prob_cache[drop] return sorted(self.prob_cache, key=self.prob_cache.get, reverse=True)[:self.vocab_size] or list(self.vocab) def viterbi(self, text): n = len(text) score = [-1e9] * (n + 1) back = [None] * (n + 1) score[0] = 0.0 for i in range(1, n + 1): for j in range(max(0, i - 4), i): w = text[j:i] if w in self.prob_cache and score[j] > -1e8: cand = score[j] + log(self.prob_cache[w]) if cand > score[i]: score[i] = cand back[i] = (j, w) toks = [] i = n while i > 0: j, w = back[i] toks.append(w) i = j return toks[::-1] if __name__ == "__main__": samples = ["自然语言处理", "语言模型", "处理数据", "自然语言"] mu = MiniUnigram(samples, vocab_size=14, iters=20) print("词表:", mu.train()) for s in ["自然语言", "模型处理"]: print(s, "->", mu.viterbi(s))
self._seed_vocab()用单字符加高频二元组初始化候选词表,模拟 SentencePiece 的种子词表。self.prob_cache缓存每个子词的概率,训练过程中反复读写。self._all_segmentations(text)动态规划枚举句子所有合法切分路径,对应 Unigram 的 $S(x)$。max_score` 与 `denom用 log-sum-exp 技巧数值稳定地计算每条路径的权重。self._update_probs()E 步:统计期望频次;M 步:归一化得到新概率。if len(self.prob_cache) > self.vocab_size淘汰概率最低的子词,模拟 Unigram 词表修剪。viterbi(self, text)正向动态规划找最大对数概率路径,反向回溯出最优切分。
常见误区
误区多塞点 token 进词表,模型就能认识更多词,效果肯定更好。既然 BLOOM 用 25 万词表,那我也搞个 50 万词表,岂不是翻倍强?
正解词表大小不是性能的单调函数。词表翻倍,embedding 和输出层的参数也近似翻倍——7B 模型可能因此多出几个亿参数,而这些新加的 token 大多是低频词,在语料中出现不到十次,根本学不好表示。更关键的是,输出 softmax 的维度变大,推理延迟明显上升。需要像裁缝备补丁一样按客户群量身定制:先测语料覆盖率曲线,找“再增大词表收益甚微”的拐点。
为何常见:人们直观地觉得“认识更多词 = 更聪明”,忽略了模型参数的预算约束和低频词的稀疏性问题。
误区反正都是把文本切成子词,运行起来结果也差不多,用哪个都行。
正解两者机制有本质区别。BPE 是贪心合并,每次只把最高频的相邻字符对缝起来,全程不看全局概率;Unigram 则给每个子词标概率,优化整个语料的似然,还会主动淘汰低概率词元。实践中 Unigram 对多语言和稀有词的鲁棒性明显更好——这正是 LLaMA、BLOOM 弃用 BPE 而选 SentencePiece 的原因。
为何常见:两者都输出“子词 + 词表”的格式,用户看到的结果都是 token 序列,容易忽略训练机制的差异。
误区我直接调库就行,`sentencepiece.train()` 一行出结果,知道原理纯属浪费时间。
正解调库虽然简单,但词表大小、字符覆盖率、训练语料配比这些超参数都需要对底层原理有判断力才能设好。遇到“中文切得碎”“多语言混排乱码”“特殊 token 冲突”这些线上问题,不懂 Unigram 和 BPE 差异的人只能瞎试参数,懂原理的人一眼就能定位是词表覆盖不足还是空白处理没配对。
为何常见:现代工具链封装得太好,低门槛反而让使用者忽略了模型本身的决策机制,出了问题才知道黑盒不可靠。
误区生僻词没人用,概率又低,直接删了能节省词表空间。
正解词表里留一部分中低频 token 并非浪费。Unigram 的优雅之处恰恰是:真心生僻的词会被自动切分成常见子词的组合(“鳜鱼”→“鳜”+“鱼”),不会保证整词命中。但如果把中频词(如“合同”“算法”)硬删掉,它们每次都被拆成单字,句子变长,序列上下文交互变差,模型整体表现会显著下滑。
为何常见:把“低频”等同于“无用”,没意识到 token 长度和模型感受野之间的联动影响。
面试题
Q1. 关于 SentencePiece 的核心特点,下列哪项描述最准确?
- A.只支持英文文本切分
- B.需要预先按空格分词的文本
- C.语言无关且支持多语言文本← 正确答案
- D.只能用于推理不能训练词表
答案:C。SentencePiece 直接从原始字符流训练,无需空格预分词,因此可处理中、日等无空格语言,是语言无关的通用分词器。A、B 描述的是传统分词器的限制,D 明显错误——它本来就负责训练词表。
Q2. Unigram 模型给一个句子打分时,句子的概率如何计算?
- A.只取最优切分路径的概率
- B.所有切分路径的概率求和← 正确答案
- C.各字符出现次数的乘积
- D.词表中全部词元概率之和
答案:B。Unigram 的要点是“全路径求和”——它把所有合法切分方式的概率都加起来作为句子概率(取对数后优化)。A 是 Viterbi 解码时的做法而非训练目标,C 是字符级统计,D 忽略了句子结构约束。
Q3. BPE 算法每轮迭代的核心操作是什么?
- A.随机选择字符对进行拆分
- B.合并出现频次最高的相邻符号对← 正确答案
- C.用神经网络预测下一个词元
- D.按词性标注过滤低频子词
答案:B。BPE 是贪心合并:每轮统计当前符号序列中所有相邻对的出现频次,挑最高的合并成新符号。A 是随机策略,C 是语言模型任务,D 使用词性标注,这些都不是 BPE 的做法。
Q4. LLaMA 选用 32000 词表的直接工程原因是什么?
- A.词表越大训练一定越慢
- B.32K 在容量与压缩率间较平衡← 正确答案
- C.32000 是 GPU 显存上限决定的
- D.论文作者随机拍板的一个数字
答案:B。32K 是工程权衡的结果:足够覆盖高频英文子词和常用多语言字符,同时词表嵌入参数占比小、推理速度快。A 过于绝对,C 与显存无关,D 不是事实。
Q5. SentencePiece 如何处理文本中的空白字符?
- A.直接删除所有空白字符
- B.用特殊符号▁显式编码空白← 正确答案
- C.用数字 0 代替空格位
- D.空白只保留在句子开头
答案:B。SentencePiece 把空格转成 ▁ 标记,训练时作为一个普通 token 参与概率估计。这样模型能明确感知词边界,又不需要依赖空格预切分。A 会丢失词边界信息,C、D 都是不存在的设计。
Q6. Unigram 训练过程中,低概率子词最终会怎样?
- A.自动加密提高使用概率
- B.被保留且永不改变概率
- C.在迭代中逐渐被淘汰出词表← 正确答案
- D.转存到额外备份词表
答案:C。Unigram 的 EM 迭代会不断重估各子词概率,概率过低的子词在后续迭代中被丢弃,直到词表达到目标大小。这就是它的“修剪”机制,与 BPE 只增不减的做法形成鲜明对比。
Q7. 关于 BPE 与 Unigram 的根本区别,下列说法哪项正确?
- A.两者均基于全局概率优化
- B.BPE 贪心合并,Unigram 全路径似然← 正确答案
- C.Unigram 完全没有统计信息
- D.BPE 支持中文而 Unigram 不支持
答案:B。BPE 每步只合并当前频次最高的相邻对,是局部贪心策略;Unigram 则定义子词概率并优化整个句子的全路径似然,能全局评估词表质量。A 对 BPE 不成立,C、D 均与事实相反。
Q8. 词表选得过小可能带来哪些后果?
- A.嵌入层参数量爆炸增长
- B.相同句子切分成更多token← 正确答案
- C.序列变长增加注意力开销← 正确答案
- D.模型语义表示更稳定集中
答案:BC。词表过小时,整词无法命中,句子会被切成长串碎片,token 数变多、序列边长,注意力与显存开销增高,B、C 正确。A 是词表过大的问题,D 与经验事实相反——碎片化反而削弱语义表示稳定性。
Q9. 下列哪些是 SentencePiece 提供的特性?
- A.自动添加BOS与EOS标记← 正确答案
- B.将空格转成▁特殊token← 正确答案
- C.内置情感分析分类器
- D.无需语言预切分的直接训练← 正确答案
答案:ABD。SentencePiece 会在序列首尾自动插入 BOS/EOS,并把空白字符统一转成 ▁ token,同时支持从原始文本直接训练。它不具备情感分析功能,C 错误。
Q10. 关于 Unigram 的分词路径求和公式,哪些理解是正确的?
- A.每种切分路径概率是该路径各token概率的连乘← 正确答案
- B.句子概率只取所有路径中概率最大的那条
- C.取对数后连乘变为连加便于数值稳定← 正确答案
- D.路径数量越多句子概率一定越小
答案:AC。单条路径的概率是路径内所有 token 概率连乘,A 对;句子概率是全部路径之和,B 错;对数把连乘转成连加,C 对;路径数量与概率大小无必然关系,且各路径求和不小于单条路径,D 错。