事情本身不复杂,线索都在日志里。加载自己训练的 tokenizer 后发现中文几乎每个字一个 token,同样长度的文本 token 数是原来的三倍。
第一反应是「自定义词表合并时丢了中文子词」,验证下来不成立。
排查方向其实有限,先把可能性排一排。词表是用英文语料训练的,中文覆盖极差。另一种情况是分词前没有做规范化,全角半角混用。
另外,tokenizer 配置里的 pre_tokenizer 规则过强。
第一件事是看几个中文句子的切分结果
python -c "print(tokenizer.tokenize('人工智能技术发展很快'))"
接着统计中文 token 平均长度
python -c "print(sum(len(tokenizer.tokenize(s)) for s in zh)/len(zh))"
再往下换用中文覆盖更好的基座词表
python -c "print(len(AutoTokenizer.from_pretrained('Qwen/Qwen2.5-7B-Instruct')))"
必要时扩充词表并重新训练嵌入
python add_tokens.py --tokens zh_vocab.txt --model ./base
怎么算真的好了,看的是同一批现象。中文平均 token 长度降到接近两个字一个,同样文本的 token 数明显减少,训练与推理成本随之下降。
容易忽略的是,扩充词表后必须重新训练新增的嵌入向量,直接冻结会让新词变成随机向量,效果比不扩充还差。改动前把原配置备份一份,出问题能马上回滚,这比任何技巧都实用。