使用bert-base-uncased的encode_plus为何会将词语拆分为子词?
BERT子词拆分问题原因及解决方案
核心原因
bert-base-uncased使用WordPiece分词算法,内置30522个通用高频词的词汇表,设计逻辑就是将不在词汇表中的低频长词拆分为多个存在于词汇表的子词单元,子词前缀带##表示该片段属于前一个词的后缀部分,目的是从根本上解决OOV(未登录词)问题,同时减少整体词汇表大小。
你遇到的anecdotes、ambience被拆分,本质原因就是这两个词不属于bert-base-uncased的官方内置词汇表,而food、service、price属于高频词汇,内置在词汇表中所以会作为整词输出。
可行解决方案
如果需要实现你预期的整词拆分效果,可以选择以下两种方案:
- 方案1:补充自定义词汇到分词器
调用分词器的add_tokens方法手动添加你需要保留的整词,示例代码如下:
这种方案修改成本低,新增的词汇会被优先作为整词拆分,不会再被拆分为子词。# 加载分词器后新增自定义整词 tokenizer.add_tokens(['anecdotes', 'ambience']) # 如果后续要调用预训练模型,需要同步调整模型embedding层维度 # model.resize_token_embeddings(len(tokenizer)) - 方案2:标签对齐适配子词拆分
如果是做序列标注类任务需要对齐label_names,业内更常用的做法是不修改分词器和预训练权重,自己做标签映射:将同一个原词拆分出的所有子词对应同一个标签,推理时取第一个子词的预测结果或者所有子词预测结果的平均值即可,这种方案不会影响预训练模型的原有效果,稳定性更高。
内容的提问来源于stack exchange,提问作者teng wang
相关产品推荐
相关产品推荐

