Tokenization 分词
前言
2025-04-03 23:20:52 Thursday 参考博客 知乎博客
分词介绍
Tokenization 与 Embedding:文本如何变成向量?
一段文本输入给模型,转成 mebedding 会经过两个过程,
1. 分词(Tokenization)
目的:将原始文本拆分为模型可处理的离散单元(token),这些单元可能是单词、子词(subword)或字符。
输出:生成一个由 token 组成的序列,每个 token 对应一个唯一的整数 ID(
token_id)。例子:
- 输入文本:
"ChatGPT is powerful!" - 分词结果(以 OpenAI 的 tokenizer 为例):
["Chat", "G", "PT", " is", " powerful", "!"]→ 对应的token_id可能是[1234, 567, 890, 11, 2345, 7]。
- 输入文本:
2. Token 到 Embedding 的转换
步骤:
- Token ID 映射:每个
token_id作为索引,在模型的 Embedding 矩阵(一个大小为[vocab_size, embedding_dim]的查找表)中查找对应的行。 - 输出:得到该 token 的向量表示(embedding),维度为
embedding_dim(如 768、1024 等)。
- Token ID 映射:每个
关键点:
- Embedding 矩阵是模型训练时学习到的参数,每个
token_id对应一个固定的向量。 - 同一
token_id在不同模型中的 embedding 可能不同(因模型而异)。
- Embedding 矩阵是模型训练时学习到的参数,每个
3. 流程总结
原始文本 → Tokenization → [token_id1, token_id2, ...] → Embedding查找 → [embedding1, embedding2, ...]
分词的 3 种粒度
在自然语言处理(NLP)中,分词(Tokenization)的粒度决定了如何将文本拆分为基本单元,主要分为 3 种力度:
词级别(Word-level)
- 按空格/标点切分,每个词作为独立 token(如英文:"She is cute" →
["She","is","cute"])。 - 缺点:词汇表大,难以处理未登录词(OOV)。
- 按空格/标点切分,每个词作为独立 token(如英文:"She is cute" →
子词级别(Subword-level)
- 将词拆分为更小子单元(如 BPE 算法:"She is cute" →
["Sh", "e", "is","cu","te"])。 - 优点:平衡词汇量,解决 OOV 问题(主流模型如 BERT、GPT 均采用)。
- 将词拆分为更小子单元(如 BPE 算法:"She is cute" →
字符级别(Character-level)
- 按字符切分(如:"She is cute" →
["S","h","e","i","s","c","u","t","e"])。 - 优点:词汇表极小;缺点:序列过长,训练效率低。
- 按字符切分(如:"She is cute" →
提升分词效果的核心意义:
增强模型理解能力
- 更准确的分词(如合理拆分子词)能保留语义信息,帮助模型捕捉关键特征(例如将"unhappy"拆为
["un", "happy"]以理解否定含义)。
- 更准确的分词(如合理拆分子词)能保留语义信息,帮助模型捕捉关键特征(例如将"unhappy"拆为
解决未登录词(OOV)问题
- 优化分词策略(如子词切分)可减少生僻词、拼写变体的处理难度(如"ChatGPT"→
["Chat", "G", "PT"])。
- 优化分词策略(如子词切分)可减少生僻词、拼写变体的处理难度(如"ChatGPT"→
提升计算效率
- 平衡分词粒度(避免字符级过细或词级过粗)可缩短序列长度,降低计算开销。
一句话总结:更好的分词 = 更准的语义理解 + 更强的泛化能力 + 更高的计算效率。
分词算法
以下是几种常用的子词界别的分词方法
BPE(Byte Pair Encoding)
参考 BPE 图解算法
算法流程
初始化基础词表
- 将文本按字符级拆分(英文按字母,中文按单字),构成初始词表。
- 示例:句子
"low lower"→ 初始词表为{l, o, w, e, r},文本拆分为["l", "o", "w", " ", "l", "o", "w", "e", "r"]。
统计相邻符号对频率
- 遍历语料,统计所有相邻符号对的共现次数(如
("l", "o")、("w", " "))。 - 示例:在
"low lower"中,("l", "o")出现 2 次,("o", "w")出现 2 次,("w", "e")出现 1 次。
- 遍历语料,统计所有相邻符号对的共现次数(如
合并最高频符号对
- 选择频率最高的符号对,合并为新子词,更新词表。
- 示例:合并
("l", "o")为"lo",文本更新为["lo", "w", " ", "lo", "w", "e", "r"],词表新增"lo"。
迭代合并直至终止
- 重复步骤 2-3,直到达到预设的词表大小或无更高频符号对。
- 示例:下一步合并
("lo", "w")为"low",最终词表包含"low"、"er"等子词,剩余文本拆分为["low", " ", "low", "er"]。
缺点
随着合并的次数增加,词表大小通常先增加后减小。迭代次数太小,大部分还是字母,没什么意义;迭代次数多,又重新变回了原来那几个词。所以词表大小要取一个中间值。
WordPiece
WordPiece vs BPE 核心区别总结
1. 符号标记方式不同
BPE(原始版):
- 词表里只有普通子词,比如
"ing"、"happy" - 例子:
"playing"→ 拆成["play", "ing"]
- 词表里只有普通子词,比如
WordPiece(升级版):
- 词表里非词首的子词用
##标记,比如"##ing"、"##happy" - 例子:
"playing"→ 拆成["play", "##ing"](##ing表示它是词的一部分)
- 词表里非词首的子词用
2. 合并策略不同
BPE:
- 谁出现多就合并谁
- 例子:如果
"un"+"happy"出现 100 次,"un"+"h"出现 200 次 → 优先合并"un"+"h"变成"unh"
WordPiece:
- 谁组合后更像一个"合理词"就合并谁,具体计算公式这样:
- 例子:虽然
"un"+"h"出现 200 次,但"un"+"happy"的互信息分数更高 → 合并为"unhappy"(因为 100/(50 * 20) > 200/(50 * 500),假设 freq(un)=50, freq(happy)=20, freq(h)=500)
- 谁组合后更像一个"合理词"就合并谁,具体计算公式这样:
