第一次接触NLP技术时,看到"Token"这个词总感觉云里雾里。直到有天看邻居家小孩切西瓜,突然就明白了——Token本质上就是AI处理文本时的"最小处理单元",就像我们吃西瓜前要先切成块一样。
想象你面前有个完整的西瓜(一段文本),直接啃肯定不方便。这时候你会怎么做?当然是先切成适合入口的小块(Token)。不同人切法可能不同:有人喜欢切大块(单词级Token),有人偏好小块(字符级Token)。AI处理文本也是这个道理,只不过它的"刀法"更讲究。
在自然语言处理领域,Tokenization(分词)是最基础的预处理步骤。以英文句子"Let's eat!"为例:
关键认知:Token不是固定不变的物理单位,而是根据模型需求动态划分的逻辑单元。就像切西瓜,最终目的是为了方便"食用"(模型处理)。
Token的粒度选择直接影响模型表现,主要分为四个层级:
| 粒度类型 | 示例(英文) | 示例(中文) | 适用场景 |
|---|---|---|---|
| 字符级 | ['h','e','l','l','o'] | ['你','好'] | 拼写检查、语音识别 |
| 子词级 | ['un','happy'] | ['人工','智能'] | 主流Transformer模型 |
| 单词级 | ['hello','world'] | ['人工智能'] | 传统NLP任务 |
| 短语级 | ['new','york'] | ['机器学习'] | 特定领域任务 |
中文分词尤其考验Tokenizer设计。比如"机器学习"可以切分为:
原始Token需要转换为数值才能被AI处理,主流编码方式有:
One-Hot编码:词表大小维度的稀疏向量
Embedding编码:通过神经网络学习稠密向量
python复制# HuggingFace的Token转ID示例
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("bert-base-chinese")
input_ids = tokenizer.encode("你好世界", return_tensors="pt")
print(input_ids) # 输出类似 tensor([[101, 123, 456, 789, 102]])
由于Transformer的自注意力机制本身没有位置概念,必须通过额外手段注入位置信息:
实验发现:移除位置编码后,模型对"猫追狗"和"狗追猫"的输出将变得完全一致。
Byte Pair Encoding(BPE)是当前最流行的分词算法,其核心是:
以"low lower newest"为例:
code复制初始:l o w l o w e r n e w e s t
第1轮:合并"lo"→ lo w lo w e r n e w e s t
第2轮:合并"low"→ low low e r n e w e s t
第3轮:合并"ne"→ low low e r ne w e s t
...
最终可能得到:"low" "lower" "new" "est"
两种改进型BPE算法的对比:
| 特性 | WordPiece | SentencePiece |
|---|---|---|
| 开发者 | ||
| 典型模型 | BERT | T5、XLNet |
| 处理空格 | 视为分隔符 | 作为普通字符 |
| 特殊符号 | 显式添加 | 自动学习 |
| 中文支持 | 需要预分词 | 直接处理原始文本 |
中文处理示例:
配置Tokenizer时需要特别注意:
vocab_size:词表大小
unk_token:未知词标记
special_tokens:特殊标记
max_length:最大长度
truncation:截断策略
当文本超过模型最大长度限制时:
python复制# 动态截断示例
inputs = tokenizer(
text,
truncation=True,
max_length=256,
stride=128, # 滑动窗口步长
return_overflowing_tokens=True
)
高效处理长文档的三种方法:
处理中英混合文本时的注意事项:
错误示例:
"深度学习deep learning" → ["深","度","学","习","deep","learning"]
正确做法:
"深度学习 deep learning" → ["深度学习","deep","learning"]
让通用Tokenizer适应专业领域:
python复制# 添加新Token示例
tokenizer.add_tokens(["<医学CT>", "<基因序列>"])
model.resize_token_embeddings(len(tokenizer))
医疗领域改进案例:
现象:相同文本突然产生更多Token
可能原因:
诊断命令:
python复制text = "你的输入文本"
tokens = tokenizer.tokenize(text)
print(f"Token数量: {len(tokens)}")
print(f"Token列表: {tokens}")
当遇到罕见汉字时:
python复制ord(char) > 0xFFFF # 补充字符
python复制def custom_tokenizer(text):
return [char if char in tokenizer.vocab
else f"[UNK:{ord(char)}]"
for char in text]
提升Token处理速度的方法:
python复制from concurrent.futures import ThreadPoolExecutor
with ThreadPoolExecutor() as executor:
results = list(executor.map(tokenizer, texts))
实测对比(处理10万条文本):
传统Tokenizer的局限性:
新兴解决方案:
跨模态模型的Token设计趋势:
示例:GPT-4V的图像处理流程:
解决长上下文窗口的内存瓶颈:
在7B参数模型上的实测效果: