Transformers Tokenizer 使用详解
一、基础用法
1.1 初始化 Tokenizer
python
from transformers import AutoTokenizer, BertTokenizer, GPT2Tokenizer
# 推荐方式:自动检测模型对应的 tokenizer
tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")
# 或指定具体 tokenizer 类
tokenizer = BertTokenizer.from_pretrained("bert-base-uncased")
tokenizer = GPT2Tokenizer.from_pretrained("gpt2")
1.2 基本编码解码
python
text = "Hello, how are you? I'm doing fine."
# 1. 编码为 token IDs
input_ids = tokenizer.encode(text)
print(input_ids) # [101, 7592, 1010, 2129, 2024, 2017, 1029, 102, 1045, 1005, 1049, 2515, 3836, 1012, 102]
# 2. 解码回文本
decoded = tokenizer.decode(input_ids)
print(decoded) # "[CLS] hello, how are you? [SEP] i'm doing fine. [SEP]"
# 3. 跳过特殊 token 解码
clean_decoded = tokenizer.decode(input_ids, skip_special_tokens=True)
print(clean_decoded) # "hello, how are you? i'm doing fine."
# 4. 分词(tokenize)
tokens = tokenizer.tokenize(text)
print(tokens) # ['hello', ',', 'how', 'are', 'you', '?', 'i', "'", 'm', 'doing', 'fine', '.']
二、核心参数详解
2.1 填充和截断参数
python
# 单文本处理
inputs = tokenizer(
text,
padding="max_length", # 填充到最大长度
max_length=20, # 最大长度
truncation=True, # 截断
return_tensors="pt" # 返回 PyTorch 张量
)
print(inputs["input_ids"].shape) # torch.Size([1, 20])
# 批量处理 - 不同策略
texts = ["Hello world", "This is a longer sentence", "Short"]
# 动态填充到批次内最长
batch1 = tokenizer(texts, padding=True, return_tensors="pt")
print(batch1["input_ids"].shape) # torch.Size([3, 最长序列长度])
# 填充到指定长度
batch2 = tokenizer(texts, padding="max_length", max_length=10, return_tensors="pt")
# 仅填充到模型最大长度
batch3 = tokenizer(texts, padding="longest", return_tensors="pt")
2.2 高级参数
python
# 完整参数示例
inputs = tokenizer(
text,
# 长度控制
max_length=512,
truncation=True,
padding="max_length",
# 返回格式
return_tensors="pt", # "tf" (TensorFlow), "np" (NumPy), None (列表)
return_token_type_ids=True, # 是否返回 token_type_ids
return_attention_mask=True, # 是否返回 attention_mask
return_overflowing_tokens=False, # 是否返回溢出的 token
return_special_tokens_mask=True, # 特殊 token 掩码
return_offsets_mapping=False, # token 到原始文本的偏移
return_length=False, # 返回序列长度
# 添加特殊 token
add_special_tokens=True, # 自动添加 [CLS], [SEP] 等
# 截断策略
stride=0, # 滑动窗口步长,配合 return_overflowing_tokens 使用
)
三、句子对处理
python
# 句子对任务(如文本分类、相似度计算)
question = "What is Transformers?"
context = "Transformers is a library by Hugging Face."
# 方法1:直接传入两个参数
inputs = tokenizer(question, context, padding=True, truncation=True)
# 方法2:使用 text_pair 参数
inputs = tokenizer(question, text_pair=context)
# 查看 token_type_ids(区分两个句子)
print(inputs["token_type_ids"])
# 输出:[0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
# 0 表示第一个句子,1 表示第二个句子
# 方法3:批量处理句子对
questions = ["Q1", "Q2"]
contexts = ["C1", "C2"]
batch_inputs = tokenizer(questions, contexts, padding=True)
四、处理长文本
4.1 滑动窗口截断
python
long_text = "..." # 很长的文本
# 使用滑动窗口处理长文本
inputs = tokenizer(
long_text,
truncation=True,
max_length=512,
stride=256, # 重叠长度
return_overflowing_tokens=True,
return_tensors="pt"
)
print(len(inputs["input_ids"])) # 多个片段
4.2 分块处理
python
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("gpt2")
def chunk_text(text, chunk_size=1000):
"""将长文本分块处理"""
tokens = tokenizer.encode(text)
chunks = []
for i in range(0, len(tokens), chunk_size):
chunk = tokens[i:i + chunk_size]
# 添加必要的特殊 token
chunks.append(chunk)
return chunks
# 处理长文本
long_text = "..." # 超长文本
chunks = chunk_text(long_text, chunk_size=512)
五、批量处理优化
python
# 批量处理时使用更高效的方式
texts = ["text1", "text2", "text3", ...] # 大量文本
# 方法1:直接批量处理(适合内存充足的情况)
batch_inputs = tokenizer(texts, padding=True, truncation=True)
# 方法2:分批处理(适合超大文本集)
batch_size = 32
all_inputs = {"input_ids": [], "attention_mask": []}
for i in range(0, len(texts), batch_size):
batch_texts = texts[i:i+batch_size]
batch_inputs = tokenizer(batch_texts, padding=True, truncation=True)
all_inputs["input_ids"].extend(batch_inputs["input_ids"])
all_inputs["attention_mask"].extend(batch_inputs["attention_mask"])
# 方法3:使用 Dataset 和 DataLoader
from torch.utils.data import DataLoader
class TextDataset:
def __init__(self, texts, tokenizer, max_length=512):
self.texts = texts
self.tokenizer = tokenizer
self.max_length = max_length
def __len__(self):
return len(self.texts)
def __getitem__(self, idx):
return self.tokenizer(
self.texts[idx],
max_length=self.max_length,
truncation=True,
padding="max_length",
return_tensors="pt"
)
dataset = TextDataset(texts, tokenizer)
dataloader = DataLoader(dataset, batch_size=32, collate_fn=lambda x: x)
六、特殊 token 处理
python
# 查看特殊 token
print(tokenizer.special_tokens_map)
# {'unk_token': '[UNK]', 'sep_token': '[SEP]', 'pad_token': '[PAD]', 'cls_token': '[CLS]', 'mask_token': '[MASK]'}
# 获取特殊 token 的 ID
cls_token_id = tokenizer.cls_token_id
sep_token_id = tokenizer.sep_token_id
pad_token_id = tokenizer.pad_token_id
# 添加自定义特殊 token
special_tokens_dict = {
'additional_special_tokens': ['[SPECIAL1]', '[SPECIAL2]']
}
num_added_toks = tokenizer.add_special_tokens(special_tokens_dict)
# 添加新词汇
new_tokens = ["new_word1", "new_word2"]
num_added_toks = tokenizer.add_tokens(new_tokens)
# 注意:添加新 token 后,需要调整模型的 embedding 层
model.resize_token_embeddings(len(tokenizer))
七、偏移映射(用于 NER 等任务)
python
# 获取 token 在原始文本中的位置
text = "Hello, how are you?"
inputs = tokenizer(
text,
return_offsets_mapping=True,
return_tensors="pt"
)
offsets = inputs["offset_mapping"][0]
tokens = tokenizer.convert_ids_to_tokens(inputs["input_ids"][0])
# 打印每个 token 的位置
for token, (start, end) in zip(tokens, offsets):
print(f"{token:10s} -> {text[start:end]}")
八、自定义配置
python
# 创建自定义 tokenizer 配置
from transformers import PreTrainedTokenizerFast
# 基于现有 tokenizer 创建
custom_tokenizer = PreTrainedTokenizerFast(
tokenizer_object=tokenizer,
unk_token="[UNK]",
pad_token="[PAD]",
cls_token="[CLS]",
sep_token="[SEP]",
mask_token="[MASK]",
padding_side="right", # 填充方向
truncation_side="right", # 截断方向
)
# 保存和加载自定义 tokenizer
custom_tokenizer.save_pretrained("./my_tokenizer")
loaded_tokenizer = AutoTokenizer.from_pretrained("./my_tokenizer")
九、性能优化技巧
python
# 1. 启用快速 tokenizer(如果可用)
tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased", use_fast=True)
# 2. 批量处理时预分配内存
batch_texts = ["text1"] * 1000
# 预计算最大长度
max_len = max(len(tokenizer.encode(t)) for t in batch_texts)
# 3. 使用缓存
tokenizer = AutoTokenizer.from_pretrained(
"bert-base-uncased",
cache_dir="./cache" # 缓存下载的模型
)
# 4. 并行处理(使用 multiprocessing)
from multiprocessing import Pool
import functools
def process_text(text, tokenizer):
return tokenizer(text, padding="max_length", max_length=512)
with Pool(4) as pool:
processed = pool.map(
functools.partial(process_text, tokenizer=tokenizer),
batch_texts
)
十、常见问题处理
python
# 1. 处理特殊字符
text = "Line 1\nLine 2\tTab"
# 自动处理换行符和制表符
inputs = tokenizer(text)
# 2. 处理表情符号和 Unicode
text = "Hello 😊 World 🌍"
inputs = tokenizer(text) # 大多数 tokenizer 能处理
# 3. 处理数字
text = "The price is 123.45 USD"
inputs = tokenizer(text)
# 4. 处理大小写(根据模型)
# bert-base-uncased: 全部小写
# bert-base-cased: 保留大小写
tokenizer_uncased = AutoTokenizer.from_pretrained("bert-base-uncased")
tokenizer_cased = AutoTokenizer.from_pretrained("bert-base-cased")
# 5. 处理 OOV(词汇表外)词汇
text = "supercalifragilisticexpialidocious"
inputs = tokenizer(text)
# 可能被分成子词或标记为 [UNK]
十一、调试信息
python
# 查看 tokenizer 信息
print(f"词汇表大小: {tokenizer.vocab_size}")
print(f"最大长度: {tokenizer.model_max_length}")
print(f"所有特殊 token: {tokenizer.all_special_tokens}")
print(f"所有特殊 token ID: {tokenizer.all_special_ids}")
# 详细查看编码过程
text = "Hello world!"
# 逐步查看
tokens = tokenizer.tokenize(text)
print(f"Tokens: {tokens}")
ids = tokenizer.convert_tokens_to_ids(tokens)
print(f"IDs: {ids}")
# 验证解码
decoded_tokens = tokenizer.convert_ids_to_tokens(ids)
print(f"Decoded tokens: {decoded_tokens}")
十二、实际应用示例
python
# 情感分析任务
def prepare_sentiment_data(texts, labels, tokenizer, max_length=128):
"""准备情感分析数据"""
encodings = tokenizer(
texts,
truncation=True,
padding=True,
max_length=max_length,
return_tensors="pt"
)
# 添加标签
encodings['labels'] = torch.tensor(labels)
return encodings
# NER 任务
def prepare_ner_data(texts, tags, tokenizer, max_length=256):
"""准备命名实体识别数据"""
tokenized_inputs = tokenizer(
texts,
truncation=True,
padding=True,
max_length=max_length,
is_split_into_words=True, # 文本已预先分词
return_tensors="pt"
)
# 对齐标签(考虑子词分词)
aligned_labels = []
for i, label in enumerate(tags):
word_ids = tokenized_inputs.word_ids(batch_index=i)
previous_word_idx = None
label_ids = []
for word_idx in word_ids:
if word_idx is None:
label_ids.append(-100) # 忽略特殊 token
elif word_idx != previous_word_idx:
label_ids.append(label[word_idx])
else:
# 子词,使用 -100 或相同的标签
label_ids.append(-100)
previous_word_idx = word_idx
aligned_labels.append(label_ids)
tokenized_inputs["labels"] = torch.tensor(aligned_labels)
return tokenized_inputs
通过掌握这些用法,你可以高效地使用 Transformers 的 Tokenizer 处理各种 NLP 任务。