[NLP] LLM---扩充词表LLama2-构建中文tokenization

使用SentencePiece的除了从0开始训练大模型的土豪和大公司外,大部分应该都是使用其为当前开源的大模型扩充词表,比如为LLama扩充通用中文词表(通用中文词表,或者 垂直领域词表)。那这部分工作有没有意义呢?或者说值不值得投入资源去做呢?先说自己的结论,有,以下两点的作用,第三点不确定:

1.提高模型的编解码的效率,在LLaMa原来的词表上,一个汉字平均1.45个token,扩充后的Chinese-LLaMa为0.65个token;那在垂直领域内呢?比如在LLaMa在继续扩充领域内词表,金融或者医疗等等,把“负债表”,“糖尿病”等领域词汇也加入词表里,那更加能提高其编解码的效率。

2.提高模型的上下文窗口长度,原LLaMa上下文长度是4096个token,不扩充词表前,按1.45来算就是最多只能输入2824个汉字,扩充后以0.65来算的话就是6301,垂直领域会更大。这点带来的好处是实打实的。

3.提高模型的效果?提高LLaMa在中文的表现?提高开源模型在垂直领域的表现?这一点上难以下结论,目前好像也没有确定的结论,自我感觉会有,但是不多,而且可能在垂直领域扩充词表后,垂直领域词太多过拟合影响通用领域效果,还有就是扩充完词表后还要经过一系列的后续处理和训练,可以控制变量的研究一下,但需要很多的资源哈哈。但是前两点的好处是实打实的,所以在有资源的情况下,扩充词表还是可以尝试的。

目前,大语言模型呈爆发式的增长,其中,基于llama家族的模型占据了半壁江山。而原始的llama模型对中文的支持不太友好,接下来本文将讲解如何去扩充vocab里面的词以对中文进行token化。

第一阶段的主要工作是通过扩展词表和 embedding 来提升 llama2 的中文能力。今天的工作是获得一个中文的bpe分词模型。

BPE模型对后期的 token 长度、token效果影响较大,而且我们希望训练的 llama2 模型具有通用价值,所以训练的数据应该尽可能多样。

  • liwu/MNBVC · Datasets at Hugging Face 是一个不错的数据集,多样性丰富。
  • https://github.com/aceimnorstuvwxz/toutiao-text-classfication-dataset 今日头条短文本
  • GitHub - shjwudp/shu: 中文书籍收录整理, Collection of Chinese Books 一些中文书籍
  • 维基百科

可以加入更多的数据

数据预处理

对斗破苍穹语料进行预处理,每一行为一句或多句话。

with open("data/《斗破苍穹》.txt", "r", encoding="utf-8") as fp:data = fp.read().strip().split("\n")
sentences = []for d in data:d = d.strip()if "===" in d or len(d) == 0 or d == "《斗破苍穹》来自:":continuesentences.append(d)with open("data/corpus.txt", "w", encoding="utf-8") as fp:fp.write("\n".join(sentences))

最终得到corpus.txt。

训练一个sentencepiece模型

首先,我们需要去构建中文的词库。一般的,目前比较主流的是使用sentencepiece训练中文词库。安装指令也很简单:pip install sentencepiece。然后,我们准备好语料,这里我们使用的语料是斗破苍穹小说。

直接看代码:

import sentencepiece as spm
spm.SentencePieceTrainer.train(input='data/corpus.txt',model_prefix='tokenizer',vocab_size=30000,user_defined_symbols=['foo', 'bar'],character_coverage=1.0,model_type="bpe",
)

这里讲下每个参数的作用:

  • input:指定输入文本文件的路径或者是一个目录,可以指定多个输入文件或目录。其中每一行可以是一句话或者多句话。
  • tokenizer:保存的模型的名称前缀。
  • vocab_size:设置的词表大小。
  • user_defined_symbols:用于指定用户自定义的符号。这些符号将会被视为单独的 Token,不会被拆分成子词。这个参数的作用是将一些用户定义的特殊符号作为一个整体加入到生成的词表中,以便于后续的模型使用。这里我们简单进行了测试。
  • model_type: 指定模型的类型,有三种可选参数:unigram, bpe, char. word。
  • character_coverage指定覆盖字符的数量,可以理解为限制字符集的大小。默认值为 1.0,即覆盖全部字符。
  • unk_id: 指定未登录词的 ID 号,即在词表中为未登录词分配一个整数 ID。默认值为 0。
  • bos_id: 指定句子开头符号的 ID 号,即在词表中为句子开头符号分配一个整数 ID。默认值为 1。
  • eos_id: 指定句子结束符号的 ID 号,即在词表中为句子结束符号分配一个整数 ID。默认值为 2。
  • pad_id: 指定填充符号的 ID 号,即在词表中为填充符号分配一个整数 ID。默认值为 -1,即不使用填充符号。

运行后会得到tokenizer.model和tokenizer.vocab两个文件。

我们来看看tokenizer.vocab里面是什么:

除了一些特殊符号外,还有我们自定义的foo和bar,其余的一些词是BPE训练得到,具体什么是BPE算法这里不作展开了。

合并LLama2词表和中文词表

import osos.environ["PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION"] = "python"
from transformers import LlamaTokenizer
from sentencepiece import sentencepiece_model_pb2 as sp_pb2_model
import sentencepiece as spmllama2_tokenizer_dir = "llama2_tokenizer/tokenizer.model"
llama2_tokenizer = LlamaTokenizer.from_pretrained(llama2_tokenizer_dir)chinese_sp_model = spm.SentencePieceProcessor()
chinese_sp_model_file = "tokenizer.model"
chinese_sp_model.Load(chinese_sp_model_file)llama2_spm = sp_pb2_model.ModelProto()
llama2_spm.ParseFromString(llama2_tokenizer.sp_model.serialized_model_proto())chinese_spm = sp_pb2_model.ModelProto()
chinese_spm.ParseFromString(chinese_sp_model.serialized_model_proto())# print number of tokens
print(len(llama2_tokenizer), len(chinese_sp_model))
print(llama2_tokenizer.all_special_tokens)
print(llama2_tokenizer.all_special_ids)
print(llama2_tokenizer.special_tokens_map)## Add Chinese tokens to LLaMA2 tokenizer
llama_spm_tokens_set = set(p.piece for p in llama2_spm.pieces)
print(len(llama_spm_tokens_set))
print(f"Before:{len(llama_spm_tokens_set)}")for p in chinese_spm.pieces:piece = p.pieceif piece not in llama_spm_tokens_set:new_p = sp_pb2_model.ModelProto().SentencePiece()new_p.piece = piecenew_p.score = 0llama2_spm.pieces.append(new_p)
print(f"New model pieces: {len(llama2_spm.pieces)}")## Save
output_sp_dir = 'llama2_chinese'
os.makedirs(output_sp_dir, exist_ok=True)
with open(output_sp_dir + '/chinese_llama2.model', 'wb') as f:f.write(llama2_spm.SerializeToString())
tokenizer = LlamaTokenizer(vocab_file=output_sp_dir + '/chinese_llama2.model')output_hf_dir = 'llama2_chinese'  #
os.makedirs(output_hf_dir, exist_ok=True)
tokenizer.save_pretrained(output_hf_dir)
print(f"Chinese-LLaMA tokenizer has been saved to {output_hf_dir}")# Test
llama_tokenizer = LlamaTokenizer.from_pretrained(llama2_tokenizer_dir)
chinese_llama_tokenizer = LlamaTokenizer.from_pretrained(output_hf_dir)
print(tokenizer.all_special_tokens)
print(tokenizer.all_special_ids)
print(tokenizer.special_tokens_map)
text = '''白日依山尽,黄河入海流。欲穷千里目,更上一层楼。
The primary use of LLaMA is research on large language models, including'''
print("Test text:\n", text)
print(f"Tokenized by LLaMA tokenizer:{llama_tokenizer.tokenize(text)}")
print(f"Tokenized by ChatGLM tokenizer:{chinese_llama_tokenizer.tokenize(text)}")

加入了我们定义的词表后确实能够正确的对中文进行分词了

核心部分是这一块:

for p in chinese_spm.pieces:piece = p.pieceif piece not in llama_spm_tokens_set:new_p = sp_pb2_model.ModelProto().SentencePiece()new_p.piece = piecenew_p.score = 0llama_spm.pieces.append(new_p)

也就是将原始词表中没有的新加入进去。

怎么使用修改后的词表

如果我们重新从头开始训练,那么其实使用起来很简单:

config = AutoConfig.from_pretrained(...)
tokenizer = LlamaTokenizer.from_pretrained(...)
model = LlamaForCausalLM.from_pretrained(..., config=config)
model_vocab_size = model.get_output_embeddings().weight.size(0)
model.resize_token_embeddings(len(tokenizer))

但是如果我们想要保留原始模型embedding的参数,那么我们可以这么做:

  • 1、找到新词表和旧词表id之间的映射关系。
  • 2、将模型里面新词表里面包含的旧词表用原始模型的embedding替换。
  • 3、如果新词在旧词表里面没有出现就进行相应的初始化再进行赋值。比如transformers库中的llama是这么进行初始化的:
 def _init_weights(self, module):std = self.config.initializer_rangeif isinstance(module, nn.Linear):module.weight.data.normal_(mean=0.0, std=std)if module.bias is not None:module.bias.data.zero_()elif isinstance(module, nn.Embedding):module.weight.data.normal_(mean=0.0, std=std)if module.padding_idx is not None:module.weight.data[module.padding_idx].zero_()

具体怎么做可以参考一下这个:https://github.com/yangjianxin1/LLMPruner

参考

https://github.com/ymcui/Chinese-LLaMA-Alpaca
https://github.com/yangjianxin1/LLMPruner
https://github.com/huggingface/transformers

LLM大模型之基于SentencePiece扩充LLaMa中文词表实践 - 知乎 (zhihu.com)

怎么让英文大语言模型支持中文?(一)构建中文tokenization - 知乎 (zhihu.com)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/131380.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

实验室电磁铁EM4的技术参数

锦正茂EM4电磁铁可以通过更换电磁铁极头在一定范围内改善磁场的大小和磁场的均匀度 ,并且可以通过调整极头间距改变磁场的大小,该种类型的电磁铁能够很好的与客户设计的磁场平台兼容。主要用于磁滞现象研究、磁化系数测量、霍尔效应研究、磁光实验、磁场…

WebSocket的优缺点

WebSocket的优缺点 1. WebSocket概念 1.1 WebSocket优点 低延迟全双工长期运行双向实时通信 1.2 什么是心跳机制 为了保持WebSocket稳定的长连接,在建立连接后,服务器和客户端之间需要通过心跳包来保持连接状态,以防止连接因长时间没有数据传输而被切断. 心跳包是一直特殊…

学会使用MySQL数据库(1)数据库相关背景了解

目录 什么是数据库 客户端-服务器(Client-Server) 数据库分类 MySQL服务器安装 内存和外存 什么是数据库 存储数据用文件就可以了,为什么还要弄个数据库? 文件保存数据有以下几个缺点: 文件的安全性问题文件不利于数据查询…

Spring框架中的Resource接口是什么,以及它在加载和访问资源时的关键作用

文章目录 什么是 Resource 接口?使用 Resource 加载资源使用 Resource 访问文件系统资源总结 🎈个人主页:程序员 小侯 🎐CSDN新晋作者 🎉欢迎 👍点赞✍评论⭐收藏 ✨收录专栏:Java框架 ✨文章内…

没出息的项目经理的5大表现

大家好,我是老原。 都说,30岁的项目经理凶猛如狼,40岁的项目经理狡猾如狐。 实际上,又有多少项目经理能做到这般。 有多少项目经理,兢兢业业工作个几年,最后还是守着一亩三分地,既没有升职加…

PMP认证可以用来干什么呢?

PMP(项目管理专业人士)认证是一项国际上广为认可的专业认证,具有以下几个重要用途和好处: 1. 提升职业竞争力: PMP认证是项目管理领域具有权威性和声誉的认证之一。持有PMP认证可以证明你具备了相关知识、技能和经验&#xff0c…

【LeetCode75】第五十四题 咒语和药水的成功对数

目录 题目: 示例: 分析: 代码: 题目: 示例: 分析: 题目给我们两个数组,要我们找出第一个数组中每个元素能和另一个数组的元素匹配的数量。匹配的条件是乘积大于特定的值。 那么…

[SSM]MyBatisPlus拓展

五、拓展篇 5.1逻辑删除 在电商网站中,我们会上架很多商品,这些商品下架以后,我们如果将这些商品从数据库中删除,那么在年底统计商品的时候,这个商品要统计的,所以这个商品信息我们是不能删除的。 如果商城…

LC1798. 你能构造出连续值的最大数目(JAVA)

LC1798. 你能构造出连续值的最大数目 题目描述贪心算法代码演示 题目描述 难度 - 中等 Leetcode - 1798. 你能构造出连续值的最大数目 给你一个长度为 n 的整数数组 coins ,它代表你拥有的 n 个硬币。第 i 个硬币的值为 coins[i] 。如果你从这些硬币中选出一部分硬币…

佛山融资融券(两融)开户利率最低能做到多少?5%!

佛山融资融券(两融)开户利率最低能做到多少?5%! 具体佛山融资融券(两融)开户利率最低能做到多少,需要根据不同的券商政策而定。不同的券商可能具有不同的优惠政策和开户条件,因此开户前应该仔细了解券商的政策和条件。 融资融券是投资者通过证券公司向…

STL stack 和 queue

文章目录 一、stack 类和 queue 类的模拟实现 stack 只允许在一端进行插入删除,是一个后进先出(LIFO)的结构,可以存储任意类型 queue 只允许在一端进行插入,另一端进行删除,是一个先进先出(FIFO)的结构,可以存储任意类…

2023年墨西哥 SP/BMV IPC 研究报告

第一章 指数概况 1.1 指数基本情况 墨西哥 S&P/BMV IPC 指数衡量在墨西哥证券交易所 (Bolsa Mexicana de Valores, BMV)上市,规模最大、流动性最高的股票表现。提供一个覆盖墨西哥股市的广泛、具有代表性且可轻易复制的指数。根据多元化要求,按市值…

SQL12 高级操作符练习(2)

描述 题目:现在运营想要找到学校为北大或GPA在3.7以上(不包括3.7)的用户进行调研,请你取出相关数据(使用OR实现) 示例:user_profile iddevice_idgenderageuniversitygpa12138male21北京大学3.423214male复旦大学4.03…

【c++每天一题】 字符串压缩

字符串压缩 时间限制:C/C 1000MS,其他语言 2000MS 内存限制:C/C 128MB,其他语言 256MB 难度:简单 分数:100 OI排行榜得分:12(0.1*分数2*难度) 描述 给定一个字符串,将连续相同的字符…

Docker实战:docker compose 搭建Rocketmq

1、配置文件准备 1.1、 新建目录:/home/docker/data/rocketmq/conf mkdir /home/docker/data/rocketmq/conf1.2、 在上面目录下新建文件broker.conf文件,内容如下 brokerClusterName DefaultCluster brokerName broker-a brokerId 0 deleteWhen 0…

LeetCode刷题笔记【31】:动态规划专题-3(整数拆分、不同的二叉搜索树)

文章目录 前置知识343. 整数拆分题目描述解题思路代码进一步优化 96.不同的二叉搜索树题目描述解题思路代码优化改进 总结 前置知识 参考前文 参考文章: LeetCode刷题笔记【29】:动态规划专题-1(斐波那契数、爬楼梯、使用最小花费爬楼梯&…

【Spring面试】六、@Autowired、@Configuration、第三方Bean的配置

文章目录 Q1、如何让自动注入没有找到依赖Bean时不报错?Q2、如何让自动注入找到多个依赖的Bean时不报错?Q3、Autowired注解有什么作用?Q4、Autowired和Resource之间的区别Q5、Autowired注解自动装配的过程是怎样的?Q6、Configurat…

idea 无法创建Javaweb项目也无法添加web模块

只有一个原因,就是使用的是社区版的idea,不是专业版的 如果想要idea创建动态的javaweb项目,还得去下载专业版 使用全新的专业版本,就有web模块了

冠达管理:“A股”上热搜,个股普跌!这一概念,逆市掀涨停潮

A股商场和港股商场今天上午再度低位震动,“A股”词条冲上微博热搜。 ​ A股商场方面,主要指数均跌落,创业板指创年内新低,TMT赛道团体走低,拖累商场人气。上午海峡西岸概念板块成为商场最大亮点之一,个股…

使用高斯混合模型进行聚类

一、说明 高斯混合模型 (GMM) 是一种基于概率密度估计的聚类分析技术。它假设数据点是由具有不同均值和方差的多个高斯分布的混合生成的。它可以在某些结果中提供有效的聚类结果。 二、Kmean算法有效性 K 均值聚类算法在每个聚类的中心周围放置一个圆形边…