【AI - nlp】Tokenizer简介及常见编码方式
Tokenizer:自然语言处理的核心桥梁
一、什么是Tokenizer?
Tokenizer(分词器)是自然语言处理(NLP)中最基础、最关键的组件之一,它的核心作用是将人类可读的文本(字符串)转换为模型可以处理的数字序列(通常是整数ID)。这一过程包含两个关键步骤:
- 分词(Tokenization):将文本拆分成更小的单元(称为
token
) - 编码(Encoding):将每个
token
映射为一个唯一的整数ID
二、Tokenizer的核心工作原理
1. 分词方式与算法
Tokenizer的分词方式决定了文本如何被拆分,目前主流的分词算法包括:
分词方式 | 特点 | 适用场景 | 代表模型 |
---|---|---|---|
Word-level | 基于空格分词 | 英语等空格分隔语言 | 早期NLP模型 |
Character-level | 按字符分词 | 适合处理未登录词 | 早期RNN模型 |
Subword-level | 按子词分词(如BPE、WordPiece) | 主流方案,平衡词汇表大小与OOV问题 | BERT, GPT, RoBERTa |
Byte-level | 按字节分词 | 多语言支持 | GPT-2/3 |
2. Subword分词算法详解
(1) Byte Pair Encoding (BPE)
- 工作原理:
- 从字符级开始(如英文的26个字母、标点符号)
- 统计训练语料中词频
- 迭代合并出现频率最高的相邻字符对
- 重复此过程直到达到预设词表大小
- 示例:
"unhappiness"
→["un", "happi", "ness"]
(2) WordPiece
- 工作原理:
- 类似BPE,但基于概率选择合并
- 优先合并能提高语言模型概率的词对
- 适用于中文等没有明显空格分隔的语言
- 示例:
"自然语言处理"
→["自", "然", "语", "言", "处", "理"]
(3) Unigram
- 工作原理:
- 从大词汇表开始
- 逐步剔除低概率token
- 基于最大似然估计选择最优分词
- 优势:能处理更复杂的语言结构
三、Tokenizer在深度学习模型中的应用
1. BERT模型中的Tokenizer
BERT(Bidirectional Encoder Representations from Transformers)模型的Tokenizer有以下关键特征:
自动添加特殊标记:
[CLS]
(ID=101):分类任务的起点,模型最终输出的特征向量来源[SEP]
(ID=102):句子结束标记,单句任务也必须存在[PAD]
(ID=0):填充标记,用于批量处理时对齐序列长度
输入格式:
[CLS] + 文本 + [SEP]
2. GPT模型中的Tokenizer
GPT(Generative Pre-trained Transformer)模型的Tokenizer特点:
- 无
[SEP]
标记:GPT是自回归模型,不需要句子分隔符 - 前导空格处理:许多单词的token包含前导空格
- 大小写敏感:对大小写敏感(如"Hello"和"hello"是不同token)
四、Tokenizer的输出结构
当使用Hugging Face的Tokenizer处理文本时,返回的通常是一个包含多个字段的字典:
{'input_ids': [101, 704, 1226, 119, 4396, 2017, 2110, 117, 102],'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0],'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1]
}
各字段详细说明:
字段 | 说明 | 作用 |
---|---|---|
input_ids | 每个token对应的ID序列 | 模型的主要输入 |
token_type_ids | 标记不同句子(0表示第一句,1表示第二句) | 用于句子对任务(如问答) |
attention_mask | 标记真实token(1)和填充token(0) | 告诉模型哪些部分是有效输入 |
五、Tokenizer的使用场景
1. 文本分类任务
from transformers import AutoTokenizertokenizer = AutoTokenizer.from_pretrained("bert-base-chinese")
text = "这部电影太棒了!"encoded = tokenizer(text,padding=True,truncation=True,max_length=32,return_tensors="pt"
)
2. 序列标注任务(如NER)
from transformers import AutoTokenizertokenizer = AutoTokenizer.from_pretrained("bert-base-chinese")
text = "北京是中国的首都"encoded = tokenizer(text,is_split_into_words=True, # 用于标注任务,已分词return_offsets_mapping=True # 返回token偏移量
)
3. 生成任务(如文本生成)
from transformers import AutoTokenizertokenizer = AutoTokenizer.from_pretrained("gpt2")
text = "你好,世界"input_ids = tokenizer.encode(text, return_tensors="pt")
六、Tokenizer在语音处理中的应用
除了文本处理,Tokenizer也应用于语音处理领域,如S3Tokenizer项目:
- S3Tokenizer:基于SenseVoice-Large模型的语音标记提取器
- 功能:将语音信号编码为具有强语义关系的标记
- 应用场景:
- 语音合成:生成自然流畅的语音
- 语音识别:增强语音信号的语义信息
- 语音编码:提取关键特征,降低数据维度
七、Tokenizer的性能与优化
1. 速度优化
- 分布式推理:如S3Tokenizer项目通过分布式处理,相比原推理管道速度提升了约790倍
- 批处理:支持高吞吐量的批量推理
2. 语言支持
- 多语言支持:如SentencePiece可以统一处理中英文混合文本
- 中文处理:使用中文预训练Tokenizer(如
bert-base-chinese
)可显著提升中文分词效果
八、常见问题与解决方案
问题 | 原因 | 解决方案 |
---|---|---|
出现大量[UNK] | 未使用正确的Tokenizer,或文本包含生僻字 | 使用匹配的预训练Tokenizer,或添加自定义词汇 |
长文本被截断 | 未设置max_length 或truncation | 设置max_length 和truncation=True |
批量输入长度不一致 | 未使用padding=True | 设置padding=True 自动对齐长度 |
无法正确识别中文 | 使用英文Tokenizer处理中文 | 使用中文预训练Tokenizer |
九、Tokenizer的重要性
- 模型性能基础:分词方式直接影响模型对语义的理解能力
- OOV问题处理:Subword方法能有效处理未登录词(如"自然语言处理"→
["自","然","语","言","处","理"]
) - 多语言支持:如SentencePiece可统一处理多种语言
- 输入标准化:通过
max_length
和truncation
控制输入长度
十、总结
Tokenizer是NLP模型的"翻译官",它将人类语言翻译成模型可理解的数字形式。随着NLP技术的发展,Tokenizer也在不断演进,从早期的Word-level分词发展到现在的Subword-level分词(如BPE、WordPiece),使模型能够更高效地处理各种语言和任务。
在实际应用中,选择合适的Tokenizer并正确配置其参数,是NLP模型成功的关键第一步。无论是文本分类、命名实体识别、机器翻译还是语音处理,Tokenizer都是整个处理流程中不可或缺的环节。
提示:在使用Hugging Face的
transformers
库时,只需加载与模型匹配的Tokenizer,如AutoTokenizer.from_pretrained("bert-base-chinese")
,它会自动处理所有分词和特殊标记的添加,无需手动操作。
Tokenizer常见方式概览
一、四种常见方式概览
方法 | 输入类型 | 是否支持批量 | 返回内容 | 推荐场景 |
---|---|---|---|---|
tokenizer.encode(text) | 单个字符串 | ❌ 不支持批量 | 只返回 input_ids | 快速测试单句 |
tokenizer.encode_plus(text) | 单个字符串 | ❌ 不支持批量 | 返回 input_ids , attention_mask , token_type_ids 等字典 | 单样本预处理 |
tokenizer(batch_text_list) 或 __call__ | 列表/批量文本 | ✅ 支持批量 | 返回张量或列表的字典(推荐新方式) | 批量处理(现代写法) |
tokenizer.batch_encode_plus(...) | 列表/批量文本 | ✅ 支持批量 | 同上,功能更全(旧但兼容性好) | 批量处理(兼容老版本) |
结论先行:
官方更推荐直接调用tokenizer(...)
(即__call__
),它已取代batch_encode_plus
成为标准做法。
二、逐个详解
1. tokenizer.encode(text)
encoded = tokenizer.encode("Hello world")
# 输出: [101, 7592, 2088, 102] ← CLS + "hello" + "world" + SEP
- 作用:对单个文本进行编码,只返回
input_ids
(token ID 列表) - 不返回:
attention_mask
、token_type_ids
等其他字段 - 不能处理批数据
- 无填充、无截断控制
缺点明显:信息不完整,不适合训练模型使用。
适用场景:快速查看某个句子的 token IDs。
2. tokenizer.encode_plus(text)
encoded = tokenizer.encode_plus("Hello world",add_special_tokens=True,max_length=10,padding='max_length',truncation=True,return_attention_mask=True,return_tensors=None # 默认返回 list
)
# 输出: {'input_ids': [...], 'attention_mask': [...], 'token_type_ids': [...]}
- 作用:对单个文本进行完整编码
- 返回完整字段:
input_ids
attention_mask
token_type_ids
(用于句子对任务)- 可控
padding
/truncation
- 仍然只能处理一个文本
不能用于
DataLoader
的collate_fn
,因为你要处理的是一个 batch!
适用场景:处理单条样本,比如做推理时。
3. tokenizer.batch_encode_plus(...)
texts = ["I love NLP", "BERT is great"]
encoded = tokenizer.batch_encode_plus(texts,add_special_tokens=True,padding='max_length',max_length=10,truncation=True,return_attention_mask=True,return_tensors=None # 可设为 'pt' 返回 PyTorch 张量
)
# 输出: {'input_ids': [[...], [...]], 'attention_mask': [[...], [...]], ...}
- ✅ 支持批量输入(list of strings)
- ✅ 返回所有必要字段(
input_ids
,attention_mask
等) - ✅ 支持统一
padding
和truncation
- ✅ 完美适用于
DataLoader
的collate_fn
💡 注意:虽然
batch_encode_plus
功能强大,但它是一个“历史遗留”接口,现在已被整合进__call__
。
4. tokenizer(...)
直接调用(官方推荐新方式)
这是目前 Hugging Face 官方最推荐的方式,本质上是调用了分词器的 __call__
方法:
texts = ["I love NLP", "BERT is great"]
encoded = tokenizer(texts,add_special_tokens=True,padding='max_length',max_length=10,truncation=True,return_attention_mask=True,return_tensors='pt' # 直接返回 PyTorch 张量!
)
# 输出: {'input_ids': tensor([[...], [...]]), 'attention_mask': tensor([[...], [...]])}
- ✅ 功能与
batch_encode_plus
完全一致 - ✅ 更简洁,API 更现代
- ✅ 支持
return_tensors='pt'
直接输出torch.Tensor
- ✅ 已成为 Transformers 库的标准用法
官方文档示例现在基本都用这种方式。
为什么代码里用 batch_encode_plus
是合理的?
尽管 batch_encode_plus
正在被逐步替代,但在以下情况下依然合理:
原因 | 说明 |
---|---|
✅ 兼容老版本 Transformers | 如果你用的是较老版本(<4.x),__call__ 可能不支持某些参数 |
✅ 显式语义清晰 | batch_encode_plus 名字明确表示“批量+增强编码”,便于理解 |
✅ 项目稳定性 | 已上线项目无需重构,只要功能正确即可 |
三、总结对比表
特性 | encode | encode_plus | batch_encode_plus | tokenizer(...) |
---|---|---|---|---|
输入单文本 | ✅ | ✅ | ✅ | ✅ |
输入批文本 | ❌ | ❌ | ✅ | ✅ |
返回 input_ids | ✅ | ✅ | ✅ | ✅ |
返回 attention_mask | ❌ | ✅ | ✅ | ✅ |
支持 padding | ❌ | ✅ | ✅ | ✅ |
支持 truncation | ❌ | ✅ | ✅ | ✅ |
支持 return_tensors='pt' | ❌ | ⚠️部分 | ⚠️部分 | ✅(推荐) |
是否推荐用于 DataLoader | ❌ | ❌ | ✅(兼容) | ✅✅✅(首选) |