求助:如何加载用tokenizers训练的WordLevel分词器?Bert/Bart加载失败
我用WordLevel编码方法构建了自定义词表,训练代码已成功运行,模型保存到my_word2_token文件夹下的vocab.json。训练代码如下:
import pandas as pd from tokenizers import decoders, models, normalizers, pre_tokenizers, processors, trainers, Tokenizer from transformers import BertTokenizerFast from tokenizers.pre_tokenizers import Whitespace import os tokenizer = Tokenizer(models.WordLevel()) tokenizer.normalizer = normalizers.BertNormalizer(lowercase=True) tokenizer.pre_tokenizer = pre_tokenizers.BertPreTokenizer() special_tokens = ["[UNK]", "[PAD]", "[CLS]", "[SEP]", "[MASK]"] trainer = trainers.WordLevelTrainer(vocab_size=1400, special_tokens=special_tokens) tokenizer.train(files=["./data/material.txt"], trainer=trainer) # 最终得到该语料的Tonkernize,查看下词汇大小 print("Trained vocab size: {}".format(tokenizer.get_vocab_size())) # 保存训练的tokenizer tokenizer.model.save('./my_word2_token/')
但加载时遇到两个问题:
- 使用
BertTokenizer分词结果全为[UNK] - 使用
BartTokenizer报错:
ValueError: Calling BartTokenizer.from_pretrained() with the path to a single file or url is not supported for this tokenizer. Use a model identifier or the path to a directory instead.
需求是使用WordLevel编码而非BPE编码进行分词,需要解决加载问题。
1. 正确保存和加载自定义WordLevel Tokenizer(适配Hugging Face Transformers)
你当前只保存了tokenizer的模型部分(vocab.json),但Hugging Face的BertTokenizer/BartTokenizer需要完整的tokenizer配置(比如预处理规则、特殊token映射等)。正确的做法是将训练好的tokenizers库的Tokenizer转换为BertTokenizerFast(它原生支持自定义WordLevel模型),再保存完整配置:
修改保存代码
在训练完成后,添加以下代码:
# 将tokenizers的Tokenizer转换为BertTokenizerFast fast_tokenizer = BertTokenizerFast(tokenizer_object=tokenizer) # 保存完整的tokenizer到目录 fast_tokenizer.save_pretrained('./my_word2_token/')
这会在my_word2_token目录下生成三个关键文件:vocab.json、tokenizer_config.json、special_tokens_map.json,包含了分词所需的所有规则和映射。
加载方式
之后用BertTokenizerFast加载整个目录即可:
from transformers import BertTokenizerFast tokenizer = BertTokenizerFast.from_pretrained('./my_word2_token/') # 测试分词 test_text = "你的测试文本内容" print(tokenizer.tokenize(test_text))
这样就能避免全[UNK]的问题,因为加载后的tokenizer复用了训练时的所有预处理规则、特殊token配置,分词逻辑完全一致。
2. 关于BartTokenizer的问题
BartTokenizer默认基于BPE编码,且它的初始化依赖特定的模型目录结构和配置,不支持直接加载自定义WordLevel词表。如果一定要结合Bart模型架构使用WordLevel分词,建议:
- 用上述方法训练并保存
BertTokenizerFast(WordLevel) - 在加载Bart模型时,指定该tokenizer并调整嵌入层:
from transformers import BartForConditionalGeneration, BertTokenizerFast tokenizer = BertTokenizerFast.from_pretrained('./my_word2_token/') model = BartForConditionalGeneration.from_pretrained('facebook/bart-base') # 匹配自定义词表大小 model.config.vocab_size = tokenizer.vocab_size model.resize_token_embeddings(len(tokenizer))
注意:这种方式下,Bart的预训练权重是基于BPE的,替换词表后必须重新微调模型,否则效果会极差。如果只是需要WordLevel分词,优先使用BertTokenizerFast更直接高效。
3. 原加载方式全[UNK]的原因
你之前用BertTokenizer加载单个vocab.json时全[UNK],核心原因是:
BertTokenizer默认的预处理规则(大小写转换、预分词方式)和你训练WordLevel tokenizer时的规则不匹配- 没有加载特殊token的映射配置,导致tokenizer无法识别训练时定义的特殊token,进而打乱了整体分词逻辑
只有保存完整的tokenizer配置,才能保证加载后的分词逻辑和训练时完全一致。
内容的提问来源于stack exchange,提问作者VictorZhu

