如何向bert-base-uncased分词器添加[EOT]类自定义特殊标记?
问题原因
你使用的bert-base-uncased是小写预训练模型,对应的分词器默认会将所有输入字符转为小写后再做分词。你通过add_tokens添加的是大写的[EOT]标记,但实际输入文本里的[EOT]会被先转成[eot],和你添加的标记无法匹配,就会被拆分为[、e、##ot、]多个子词。
正确添加自定义特殊标记的方法
不要用普通的add_tokens方法添加特殊标记,改用add_special_tokens方法,该方法添加的标记会被分词器优先匹配,不会被做大小写转换、子词拆分处理,修改后的代码如下:
from transformers import AutoTokenizer, AutoModelForSequenceClassification tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased") model = AutoModelForSequenceClassification.from_pretrained("bert-base-uncased") # 新增特殊标记 special_tokens_dict = {'additional_special_tokens': ['[EOT]']} num_added_toks = tokenizer.add_special_tokens(special_tokens_dict) # 调整模型嵌入层尺寸 model.resize_token_embeddings(len(tokenizer)) text_to_encode = '''QUERY: I want to ask a question. [EOT] ANSWER: Sure, ask away. [EOT] QUERY: How is the weather today? [EOT] ANSWER: It is nice and sunny. [EOT] QUERY: Okay, nice to know. [EOT] ANSWER: Would you like to know anything else?''' enc = tokenizer.encode_plus( text_to_encode, max_length=128, add_special_tokens=True, return_token_type_ids=False, return_attention_mask=False, )['input_ids'] print(tokenizer.convert_ids_to_tokens(enc))
运行后就可以看到[EOT]会被识别为独立标记,不会被拆分。
是否可以用[SEP]替代自定义标记
更推荐直接用原生[SEP]标记分隔对话轮次,理由如下:
[SEP]在BERT预训练阶段就被用来分隔不同文本片段,本身就具备“文本边界”的语义,不需要额外训练就能发挥作用,在小数据集上效果远好于随机初始化的自定义特殊标记- 不需要修改分词器和模型嵌入层,实现更简单,不存在适配问题
- 这也是对话分类、对话状态追踪等常见对话任务的通用处理方式,工业界和学术界都有大量实践验证
只有当你的数据集规模足够大(百万级以上对话样本),且你需要明确区分“单轮对话结束”和“整段对话结束”两种边界时,才需要额外新增自定义[EOT]标记。
内容的提问来源于stack exchange,提问作者sid8491
相关产品推荐
相关产品推荐

