LLaMA Tokenizer Expansion

LLaMA 词表扩充小记

LLaMA 词表扩充

LLaMA tokenizer 是一个 byte-level BPE(BBPE) 模型

BPE 的参数使用 sentencepiece 库训练得到

对于 LLaMA 词表的扩充 可以使用同样的库进行新数据上的参数训练 然后手动合并去重

词表扩充原因和用途

LLaMA 词表仅有32K 而且主要在拉丁和西里尔数据上进行训练 对于其他语言编码效率低

虽然从 byte-level 的实现逻辑上来讲 模型本身可以支持任意字符 但会存在编码效率、字符限制和生成效率等问题

在扩充词表后在进行预训练 可以得到更好的效果#304

基于sentencepiece的 LLaMA 词表扩充

sentencepiece的API支持多个tokenizer模型的合并 所以可以根据自己的数据训练一个词表模型之后 合并词表

训练新的词表模型

1
2
3
4
5
6
7
8
import sentencepiece as spm
spm.SentencePieceTrainer.Train(
    input='YOUR_FILE_HERE',
    model_prefix='MODEL_NAME', # -> MODEL_NAME.model MODEL_NAME.vocab
    vocab_size=1000,
    model_type="bpe",
    byte_fallback=True, # 对没见过的词进行 byte-level 处理
)

合并词表代码可见 merge_tokenizers.py

合并词表后 词表大小和模型输出的Embedding大小不一致 所以需要调整 LLaMA Embedding 的大小 代码如下

不调整的报错信息: Assertion srcIndex < srcSelectDimSize failed....RuntimeError: CUDA error: device-side assert triggered

1
2
3
4
5
6
7
8
9
# https://github.com/ymcui/Chinese-LLaMA-Alpaca/blob/main/scripts/inference_hf.py#LL70-L77
model_vocab_size = base_model.get_input_embeddings().weight.size(0)
tokenzier_vocab_size = len(tokenizer)
print(f"Vocab of the base model: {model_vocab_size}")
print(f"Vocab of the tokenizer: {tokenzier_vocab_size}")
if model_vocab_size!=tokenzier_vocab_size:
    assert tokenzier_vocab_size > model_vocab_size
    print("Resize model embeddings to fit tokenizer")
    base_model.resize_token_embeddings(tokenzier_vocab_size)

references

参考项目: https://github.com/ymcui/Chinese-LLaMA-Alpaca/

相关的issue

  • 词表合并问题#128
  • 词表扩充 + 预训练代码#150
  • Vocabulary expansion pre-training code for Chinese language#161

另外的相关库: LianjiaTech/BELLE

扩充词表的相关代码: merge_tokenizers.py

扩充BERT词表的方法: https://medium.com/@pierre_guillou/nlp-how-to-add-a-domain-specific-vocabulary-new-tokens-to-a-subword-tokenizer-already-trained-33ab15613a41

Built with Hugo
主题 StackJimmy 设计