第四章:分词技术总览
分词(Tokenization)是将原始文本切分为若干具有独立语义的最小单元(即 token)的过程,是所有 NLP 任务的起点。
为什么需要分词?
计算机无法直接理解文本字符串。分词是将文本转换为数值表示的第一步:
原始文本:"我爱自然语言处理"
↓ 分词
Token 序列:["我", "爱", "自然语言处理"]
↓ 映射到词表
ID 序列:[2769, 4263, 8547]
↓ 嵌入层
向量序列:[[0.12, -0.34, ...], [0.56, 0.78, ...], [-0.11, 0.45, ...]]英文分词
按照分词粒度的大小,英文分词可分为三个层次:
词级分词(Word-Level)
词级分词是最传统、最直观的方式。在英文中,空格和标点是天然的分隔符。
text = "I love natural language processing"
tokens = text.split()
# ['I', 'love', 'natural', 'language', 'processing']优点:简单直观,语义清晰
缺点——OOV 问题:
词级分词容易出现 OOV(Out-Of-Vocabulary,未登录词)问题。当模型遇到词表中没有的词时,无法处理。
训练词表:["I", "love", "natural", "language", "processing", ...]
输入文本:"I love NLP and ChatGPT"
OOV 词: "NLP", "ChatGPT" → 被替换为 <UNK>随着网络新词、专有名词不断涌现,OOV 问题会越来越严重。
字符级分词(Character-Level)
以单个字符为最小单位:
text = "I love NLP"
tokens = list(text)
# ['I', ' ', 'l', 'o', 'v', 'e', ' ', 'N', 'L', 'P']优点:
- 词表极小(英文仅需 ~100 个字符)
- 几乎不存在 OOV 问题
缺点:
- 单个字符语义信息极弱
- 输入序列变得很长,增加计算成本
- 模型需要更长的上下文才能理解词义
子词级分词(Subword-Level)
子词级分词是介于词级和字符级之间的方法,也是现代 NLP 的主流选择。
它将词语切分为更小的子词单元:
"unhappiness" → ["un", "happi", "ness"]
"tokenization" → ["token", "ization"]
"ChatGPT" → ["Chat", "G", "PT"]核心优势:
| 特性 | 词级 | 字符级 | 子词级 |
|---|---|---|---|
| 词表大小 | 大(数万-数十万) | 极小(数百) | 适中(数千-数万) |
| OOV 问题 | 严重 | 无 | 基本无 |
| 语义信息 | 强 | 弱 | 中等 |
| 序列长度 | 短 | 极长 | 适中 |
为什么子词分词能解决 OOV?
即使一个完整的词没有出现在词表中,只要它可以被拆分为词表中存在的子词单元,就可以被模型识别和表示。
常见的子词分词算法包括:
- BPE(Byte Pair Encoding)
- WordPiece
- Unigram Language Model
我们将在下一章详细讲解这些算法。
中文分词
中文与英文的最大区别是:中文没有空格作为天然的词边界。
英文:I love natural language processing (空格分隔)
中文:我爱自然语言处理 (没有空格)因此中文分词是一个更具挑战性的问题。
字符级分词(中文)
将文本按单个汉字切分:
text = "我爱自然语言处理"
tokens = list(text)
# ['我', '爱', '自', '然', '语', '言', '处', '理']由于汉字本身通常具有独立语义,字符级分词在中文中比在英文中更"语义友好"。
这也是很多中文预训练模型(如 BERT 中文版)采用的方式。
词级分词(中文)
将文本按完整词语切分:
import jieba
text = "小明毕业于北京大学计算机系"
tokens = jieba.lcut(text)
# ['小明', '毕业', '于', '北京大学', '计算机系']优点:切分结果更贴近人类阅读习惯,语义更完整
缺点:
- 需要依赖词典或模型
- 分词结果可能存在歧义:"南京市长江大桥" → "南京市/长江大桥" 还是 "南京/市长/江大桥"?
子词级分词(中文)
虽然中文没有英文中的词根、前缀、后缀等子词结构,但 BPE 等算法仍可直接应用于中文。它们以汉字为基本单位,通过学习语料中高频的字组合来构建子词词表。
"自然语言处理" → ["自然", "语言", "处理"]
"深度学习" → ["深度", "学习"]
"大模型" → ["大", "模型"]当前主流的中文大模型(如通义千问、DeepSeek)均采用子词分词。
中文分词工具:jieba
jieba 是中文分词领域应用最广泛的开源工具。
安装
pip install jieba三种分词模式
精确模式(默认)
试图将句子最精确地切开,适合文本分析。
import jieba
text = "小明毕业于北京大学计算机系"
result = jieba.lcut(text)
print(result)
# ['小明', '毕业', '于', '北京大学', '计算机系']全模式
把句子中所有可以成词的词语都扫描出来,速度最快。
result = jieba.lcut(text, cut_all=True)
print(result)
# ['小', '明', '毕业', '于', '北京', '北京大学', '大学', '计算', '计算机', '计算机系', '算机', '系']搜索引擎模式
在精确模式基础上,对长词进一步切分,适合搜索引擎。
result = jieba.lcut_for_search(text)
print(result)
# ['小明', '毕业', '于', '北京', '大学', '北京大学', '计算', '算机', '计算机', '计算机系']三种模式对比
| 模式 | 方法 | 特点 | 适用场景 |
|---|---|---|---|
| 精确模式 | jieba.lcut() | 最精确,无冗余 | 文本分析 |
| 全模式 | jieba.lcut(cut_all=True) | 最全,有冗余 | 快速扫描 |
| 搜索引擎模式 | jieba.lcut_for_search() | 长词再切分 | 搜索引擎 |
自定义词典
jieba 支持用户自定义词典,用于增强特定领域词汇的识别能力。
词典格式:一个词占一行,格式为 词语 词频 词性标签(词频和词性可省略)
# dict.txt
云计算
云原生 5
大模型 10 n加载词典:
import jieba
jieba.load_userdict('dict.txt')
result = jieba.lcut("随着云计算技术的普及,越来越多企业开始采用云原生架构")
print(result)动态修改词典:
# 添加词语
jieba.add_word("大模型", freq=10, tag="n")
# 删除词语
jieba.del_word("自定义词")分词工具对比
| 工具 | 类型 | 适用语言 | 特点 |
|---|---|---|---|
| jieba | 基于词典/模型 | 中文 | 轻量、快速、广泛使用 |
| HanLP | 基于模型 | 多语言 | 功能全面、准确率高 |
| pkuseg | 基于模型 | 中文 | 北大开源、准确率高 |
| HuggingFace Tokenizer | 子词分词 | 多语言 | 与预训练模型配套 |
| SentencePiece | 子词分词 | 多语言 | 语言无关、不需预分词 |
| tiktoken | 子词分词 | 多语言 | OpenAI 的高效分词器 |
小结
| 分词方式 | 粒度 | 词表大小 | OOV | 语义 | 序列长度 |
|---|---|---|---|---|---|
| 词级 | 大 | 大 | 严重 | 强 | 短 |
| 字符级 | 小 | 小 | 无 | 弱 | 长 |
| 子词级 | 中 | 中 | 基本无 | 中 | 中 |
现代 NLP 模型普遍采用子词级分词,它在词表大小、OOV 处理和语义保留之间取得了最佳平衡。下一章我们将深入讲解 BPE、WordPiece 和 Unigram 等子词分词算法的原理。