Tokenizer的魔法:如何通过特殊Token赋予大模型超能力
·
Tokenizer的魔法:如何通过特殊Token赋予大模型超能力
在自然语言处理领域,Tokenizer(分词器)是大模型理解人类语言的第一道门户。它负责将原始文本转换为模型能够理解的数字表示,而特殊Token在这个过程中扮演着关键角色。这些看似简单的标记符号,实际上能够显著扩展模型的功能边界,为各种NLP任务提供强大的定制化能力。
1. 特殊Token的核心概念与应用场景
特殊Token是预定义的特殊标记,它们在文本处理过程中具有特定的语义或功能。与普通词汇不同,这些Token通常不会被进一步分割,并且在模型处理过程中会触发特殊行为。
常见特殊Token类型包括:
- 结构控制类:
[CLS]、[SEP]、[PAD] - 功能扩展类:
[MASK]、[UNK] - 领域专用类:
[ENT_START]、[ENT_END] - 对话系统类:
<|User|>、<|Assistant|>
在BERT模型中,[CLS]Token用于分类任务的聚合表示,[SEP]用于分隔句子对。而在对话系统中,角色标记如<|User|>可以帮助模型区分不同说话者。
提示:特殊Token的设计应遵循"功能明确、语义清晰"原则,避免与现有词汇冲突。
特殊Token在多个场景中展现出强大能力:
实体识别案例:
sentence = "Two [ENT_START] cars [ENT_END] collided in [ENT_START] tunnel [ENT_END]"
tokens = tokenizer.tokenize(sentence)
# 输出:['two', '[ENT_START]', 'cars', '[ENT_END]', 'collided', 'in', '[ENT_START]', 'tunnel', '[ENT_END]']
对话系统案例:
dialog = "<|User|> Hello! <|Assistant|> Hi there! How can I help?"
2. 添加特殊Token的技术实现
为Tokenizer添加特殊Token主要有两种方法,它们在处理方式和适用场景上存在重要区别。
2.1 add_tokens与add_special_tokens对比
| 特性 | add_tokens() | add_special_tokens() |
|---|---|---|
| 标准化处理 | 会进行标准化(如小写化) | 保持原样 |
| 适用场景 | 普通词汇扩展 | 功能标记添加 |
| 访问方式 | 通过词汇表访问 | 有专用属性访问 |
| 初始化方式 | 随机初始化 | 随机初始化 |
| 典型用例 | 领域术语添加 | 结构标记添加 |
关键区别示例:
# 使用add_tokens添加
tokenizer.add_tokens(["[NEW_tok1]"])
print(tokenizer.tokenize('[NEW_tok1]')) # 输出:['[new_tok1]'] (被小写化)
# 使用add_special_tokens添加
tokenizer.add_special_tokens({"additional_special_tokens": ["[NEW_tok2]"]})
print(tokenizer.tokenize('[NEW_tok2]')) # 输出:['[NEW_tok2]'] (保持大写)
2.2 添加特殊Token的标准流程
- 初始化Tokenizer
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")
- 定义要添加的Token
special_tokens_dict = {
"additional_special_tokens": ["[ENT_START]", "[ENT_END]"]
}
- 添加Token到Tokenizer
num_added = tokenizer.add_special_tokens(special_tokens_dict)
print(f"Added {num_added} special tokens")
- 验证添加结果
print(tokenizer.special_tokens_map)
# 输出应包含新增的Token
3. 模型适配与Embedding初始化
仅仅修改Tokenizer是不够的,必须同步调整模型的Embedding层以适配新的词表大小。
3.1 调整模型Embedding层
from transformers import AutoModelForSequenceClassification
model = AutoModelForSequenceClassification.from_pretrained("bert-base-uncased")
old_embedding_size = model.get_input_embeddings().weight.size(0)
# 关键步骤:调整Embedding层大小
model.resize_token_embeddings(len(tokenizer))
new_embedding_size = model.get_input_embeddings().weight.size(0)
print(f"Embedding size changed from {old_embedding_size} to {new_embedding_size}")
3.2 Embedding初始化策略
新添加Token的Embedding默认随机初始化,但在实际应用中可能需要更精细的控制:
全零初始化:
with torch.no_grad():
model.embeddings.word_embeddings.weight[-num_added:, :] = torch.zeros(
[num_added, model.config.hidden_size], requires_grad=True)
语义相关初始化:
entity_id = tokenizer.convert_tokens_to_ids("entity")
entity_embedding = model.embeddings.word_embeddings.weight[entity_id]
with torch.no_grad():
for i in range(1, num_added+1):
model.embeddings.word_embeddings.weight[-i:, :] = entity_embedding.clone().detach()
注意:初始化后必须进行模型微调,否则新Token的Embedding将保持随机状态,无法发挥应有作用。
4. 高级应用与最佳实践
4.1 对话系统特殊Token设计
现代对话系统通常需要区分不同角色,这可以通过特殊Token实现:
dialog_tokens = {
"additional_special_tokens": [
"<|System|>", "<|User|>", "<|Assistant|>", "<|End|>"
]
}
tokenizer.add_special_tokens(dialog_tokens)
# 对话格式示例
dialog = "<|System|> Welcome! <|User|> Hello! <|Assistant|> Hi there!"
4.2 避免重复添加的检查机制
new_tokens = ["[ENT_START]", "[ENT_END]"]
# 方法1:列表推导式检查
new_tokens = [tok for tok in new_tokens if tok not in tokenizer.get_vocab()]
# 方法2:集合操作(更简洁)
new_tokens = list(set(new_tokens) - set(tokenizer.vocab.keys()))
if new_tokens:
tokenizer.add_special_tokens({"additional_special_tokens": new_tokens})
4.3 完整工作流程示例
from transformers import AutoTokenizer, AutoModelForSequenceClassification
import torch
# 1. 加载分词器和模型
model_name = "bert-base-uncased"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForSequenceClassification.from_pretrained(model_name)
# 2. 定义新Token
new_special_tokens = {
"additional_special_tokens": ["[REVIEW]", "[SUMMARY]", "[RATING]"]
}
# 3. 添加Token并调整模型
num_added = tokenizer.add_special_tokens(new_special_tokens)
model.resize_token_embeddings(len(tokenizer))
# 4. 初始化新Token的Embedding
review_id = tokenizer.convert_tokens_to_ids("review")
if review_id != tokenizer.unk_token_id: # 确保"review"在词表中
review_embedding = model.embeddings.word_embeddings.weight[review_id]
with torch.no_grad():
model.embeddings.word_embeddings.weight[-num_added:, :] = review_embedding.clone()
# 5. 保存定制化的分词器和模型
tokenizer.save_pretrained("./custom_tokenizer")
model.save_pretrained("./custom_model")
在实际项目中,特殊Token的添加和初始化策略需要根据具体任务需求和数据特点进行调整。例如,在少样本学习场景下,合理的Embedding初始化可以显著提升模型性能。
更多推荐
所有评论(0)