A-A+

Chinese-LLaMA-Alpaca 扩充词表python代码及说明

2023年04月20日 14:54 学习笔记 暂无评论 共2904字 (阅读1,117 views次)

【注意:此文章为博主原创文章!转载需注意,请带原文链接,至少也要是txt格式!】

准备工作:词表扩充

由于原版LLaMA对中文的支持非常有限,本项目在原版LLaMA的基础上进一步扩充了中文词表。

  • 在通用中文语料上训练了基于sentencepiece的20K中文词表并与原版LLaMA模型的32K词表进行合并
  • 排除重复的token后,得到的最终中文LLaMA词表大小为49953
  • 需要注意的是,在fine-tune阶段Alpaca比LLaMA多一个pad token,所以中文Alpaca的词表大小为49954

更多关于中文词表扩充的动机,可参考FAQ

如果欲了解扩充词表的具体方法,或者使用自己的词表对LLaMA tokenizer进行扩充,我们提供了代码merge_tokenizers.py供参考。 该脚本运行方式如下:
python merge_tokenizers.py \
--llama_tokenizer_dir llama_tokenizer_dir \
--chinese_sp_model_file chinese_sp_model_file

其中

  • llama_tokenizer_dir:指向存放原版LLaMA tokenizer的目录
  • chinese_sp_model_file:指向用sentencepiece训练的中文词表文件

我们所使用的在中文通用语料上训练的20K中文词表也一并放出,可以在scripts/chinese_sp.model下载。

 

其中merge_tokenizers.py的代码介绍为如下:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import os # 导入 os 库
os.environ["PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION"]="python" # 设置环境变量
from transformers import LlamaTokenizer # 从 transformers 库中导入 LlamaTokenizer 类
from sentencepiece import sentencepiece_model_pb2 as sp_pb2_model # 从 sentencepiece 库中导入 sentencepiece_model_pb2 模块并重命名为 sp_pb2_model
import sentencepiece as spm # 导入 sentencepiece 库并重命名为 spm
import argparse # 导入 argparse 库
parser = argparse.ArgumentParser() # 创建一个 ArgumentParser 对象
parser.add_argument('--llama_tokenizer_dir', default=None, type=str, required=True) # 添加一个命令行参数
parser.add_argument('--chinese_sp_model_file', default='./chinese_sp.model', type=str) # 添加另一个命令行参数
args = parser.parse_args() # 解析命令行参数
 
llama_tokenizer_dir = args.llama_tokenizer_dir # 获取命令行参数的值
chinese_sp_model_file = args.chinese_sp_model_file # 获取命令行参数的值
 
# load
llama_tokenizer = LlamaTokenizer.from_pretrained(llama_tokenizer_dir) # 加载 LLaMA 分词器
chinese_sp_model = spm.SentencePieceProcessor() # 创建一个 SentencePieceProcessor 对象
chinese_sp_model.Load(chinese_sp_model_file) # 加载中文 SentencePiece 分词器
 
llama_spm = sp_pb2_model.ModelProto() # 创建一个 ModelProto 对象
llama_spm.ParseFromString(llama_tokenizer.sp_model.serialized_model_proto()) # 从 LLaMA 分词器中获取序列化模型并解析它
chinese_spm = sp_pb2_model.ModelProto() # 创建另一个 ModelProto 对象
chinese_spm.ParseFromString(chinese_sp_model.serialized_model_proto()) # 从中文 SentencePiece 分词器中获取序列化模型并解析它
 
# print number of tokens
print(len(llama_tokenizer),len(chinese_sp_model)) # 打印两个分词器的 token 数量
print(llama_tokenizer.all_special_tokens) # 打印 LLaMA 分词器的特殊 token
print(llama_tokenizer.all_special_ids) # 打印 LLaMA 分词器的特殊 token 的 ID
print(llama_tokenizer.special_tokens_map) # 打印 LLaMA 分词器的特殊 token 映射
 
## Add Chinese tokens to LLaMA tokenizer
llama_spm_tokens_set=set(p.piece for p in llama_spm.pieces) # 获取 LLaMA 分词器中所有 token 的集合
print(len(llama_spm_tokens_set)) 
print(f"Before:{len(llama_spm_tokens_set)}") 
for p in chinese_spm.pieces: 
    piece = p.piece 
    if piece not in llama_spm_tokens_set: 
        new_p = sp_pb2_model.ModelProto().SentencePiece() 
        new_p.piece = piece 
        new_p.score = 0 
        llama_spm.pieces.append(new_p) 
print(f"New model pieces: {len(llama_spm.pieces)}") 
 
## Save
output_sp_dir = 'merged_tokenizer_sp' 
output_hf_dir = 'merged_tokenizer_hf' # the path to save Chinese-LLaMA tokenizer 
os.makedirs(output_sp_dir,exist_ok=True) 
with open(output_sp_dir+'/chinese_llama.model', 'wb') as f: 
    f.write(llama_spm.SerializeToString()) 
tokenizer = LlamaTokenizer(vocab_file=output_sp_dir+'/chinese_llama.model') 
 
tokenizer.save_pretrained(output_hf_dir)

布施恩德可便相知重

微信扫一扫打赏

支付宝扫一扫打赏

×

给我留言