当前位置:首页 > 资讯 > 正文

[玩转AIGC]LLaMA2训练中文文章撰写神器(数据准备,数据处理,模型训练,模型推理)

好久没更新这个专栏的文章了,今天抽空写了一篇。————2023.12.28

摘要:文体包括新闻,法律文书,公告,广告等,每种文体的书写风格不一样,如果拥有自己的数据集,想针对特定文体来训练一个内容生成的工具,来帮助自己写点文章,如果没接触过AIGC,可能一开始会觉得无所入手,那么希望本文能够帮助到你。本文将基于llama2来教大家如何训练一个内容生成工具,即训练属于自己的AIGC(Artificial Intelligence Generated Content)。 这里需要训练两个模型,一个是tokenizer,一个是llama2模型,我们一个一个来。

看这篇文章之前可以看下以下两篇文章:

  • [玩转AIGC]sentencepiece训练一个Tokenizer(标记器)
  • [玩转AIGC]如何训练LLaMA2(模型训练、推理、代码讲解,并附可直接运行的kaggle连接) 第一篇是关于如何训练llama2的Tokenizer模型 第二篇是关于如何训练llama2的content generation模型,里面包括了对llama2的代码解析

相关github: tokenizer: GitHub - google/sentencepiece: Unsupervised text tokenizer for Neural Network-based text generation. llama2.c: GitHub - karpathy/llama2.c: Inference Llama 2 in one file of pure C

如果没有显卡,可使用kaggle,kaggle的P100 gpu 足矣

可直接运行的kaggle:llama2-c-chinese

加载中文数据集:

数据来源: https://github.com/eatmop/MNBVC https://huggingface.co/datasets/liwu/MNBVC

简单的加载方式:

 

由于law_judgement数据集太大了,要下载很久,所以可以下载小一点的数据集,比如news_peoples_daily

[玩转AIGC]LLaMA2训练中文文章撰写神器(数据准备,数据处理,模型训练,模型推理) 改为news_peoples_daily数据集

 

需要把下载的数据集进行处理,才能用来训练。

下载后的数据集如下: [玩转AIGC]LLaMA2训练中文文章撰写神器(数据准备,数据处理,模型训练,模型推理) 获取到的中文数据集需要转换成对应的格式

首先我们借用训练英文时的数据集(TinyStories_all_data),来看下训练llama2时的数据格式,如下(我们取一条数据集出来看看)

 

训练时,读取了"story"里面的内容进行训练,因此我们需要将news_peoples_daily的格式进行转换,news_peoples_daily的json格式如下:

有用的部分也就是[”段落”][”内容”],但可以看到文章是被分为多段了,所以要把这些段落整合到一起,作为一篇新闻,然后再把它放到”story”的字段下:

 

文章每一段的内容也就是用下面的结构体表示

 

1)先将一篇篇文本拼凑到一起(只是简单的拼凑一起,用于训练tokenizer)

 

代码如下:

 

2)将数据集进行合并

由于有多个json文本文件,然后也保存了多个txt文件,所以将这些txt文件合并为一个文件,保存为"data/mergedatas.txt”:

 

合并后的数据集"data/mergedatas.txt”,就可以用来训练tokenizer了,训练过程参考下面的文章:

[玩转AIGC]sentencepiece训练一个Tokenizer(标记器)

我们还需要对数据集进行处理,使得其符合train.py的输入数据格式,也就是转为带key为"story"的json数据,保存为txt文件:

 

转换后如下:

[{“story”: “### 对外友协举行酒会 庆祝蒙古人民革命六十二周年 1983-07-07 第4版() 专栏: 对外友协举行酒会 庆祝蒙古人民革命六十二周年 新华社北京7月5日电 为庆祝蒙古人民革命六十二周年,对外友协今天下午在这里举行酒会。 应邀出席酒会的有蒙古人民共和国驻中国大使彭茨克·沙格达尔苏伦,以及大使馆外交官员。 对外友协副会长陆璀主持了酒会。酒会结束后放映了中国彩色故事片《快乐的单身汉》。 ”}, {“story”: “### 今日兄弟报纸要目 1983-07-08 第4版() 专栏:今日兄弟报纸要目 今日兄弟报纸要目 《天津日报》△国务院委托水电部在天津召开的引滦工程管理工作会议提出,不但要把引滦工程建设成为第一流的工程,而且要努力创造第一流的管理水平 《经济日报》△一些地区和单位措施不力,心存观望,关停计划外烟厂进展迟缓 △社论:执行国务院决定不能打折扣 《四川日报》△四川省政府决定计划外烟厂一律关停 《湖北日报》△武汉钢铁公司主动清查乱涨价问题,从7月1日起停止加收计划外协作钢材“管理费” 《文汇报》△进一步加强关于统一祖国方针政策的宣传教育,《上海市对台宣传展览》昨日开幕 《报》△北京部队某炮团坚持原则,退回12名不符合规定的汽车驾驶员 《人民铁道》△特约评论员文章:杜绝野蛮装卸的根本措施在于加强基础工作 《南方日报》△广东省地质局水文一队在雷州半岛地表以下500米深度内查明有“地下海”,地下水资源总量每日为1,471万吨 《陕西日报》△平利县农民积极发展香菇生产,全县有1,100多户和外贸公司签订合同 《解放日报》△上海造船工业今年上半年创历史最好水平,已完成船舶20艘,计17.7万多吨位,其中出口船11艘,共15.6万多吨位,总产值4亿多 《北京日报》北京市政府通知:严格控制企业职工加班加点,制止滥发加班加点工资 ”}]

总之:这里我们准备了2种数据,一种用于训练tokenizer,一种用于训练llama2模型,并分别简单介绍了数据结构

训练操作可以参考博文:[玩转AIGC]sentencepiece训练一个Tokenizer(标记器)

 

训练完成后可以查看相关词汇

查看词汇个数:

打开训练好的文件tokenizer.vocab,就可以看到个数,可看到一共是8000

[玩转AIGC]LLaMA2训练中文文章撰写神器(数据准备,数据处理,模型训练,模型推理)

将tokenizer转为C++可读的bin,运行:

 

可看到:

tokenizer.bin

在进行train之前,先对训练集进行处理,即使用训练好的tokenizer进行编码:

先修改tinystories.py的pretokenize()方法里面的数据集路径:

 

必要时修改主路径:

 

然后运行:

 

1)vocab_size

训练之前需要对一些参数进行修改,这一步很重要:

首先要改词汇量大小,前面我们查到词汇量是8000 [玩转AIGC]LLaMA2训练中文文章撰写神器(数据准备,数据处理,模型训练,模型推理)

vocab_size设置为总文字数的个数,可以看到原代码为32000,所以这里将32000改为8000,否则在运行https://blog.csdn.net/qq_27149279/article/details/run model.bin的时候,会在下面画框那句return了,因为数组越界。

注意:run.c里面的config是从train出来的model.bin读取的,也就是里面的checkpoint

[玩转AIGC]LLaMA2训练中文文章撰写神器(数据准备,数据处理,模型训练,模型推理) 如果训练时忘记改了,那就直接在run.c里面直接把config.vocab_size改过来即可,上面划线部分就是直接把32000改为8000

2)max_seq_len与batch size

max_seq_len:推理生成的句子长度,会直接影响生成的故事长度,默认为256,能人为在run.c里面去修改长度(但是长度最好不超过训练时的max_seq_len,否则运行run.c时运行到越界了会报错),在run.c里面的变量为steps,训练时max_seq_len不能太大,要不然会报显存不足,训练时候会看到提示: [玩转AIGC]LLaMA2训练中文文章撰写神器(数据准备,数据处理,模型训练,模型推理) 代码里面默认为64256,也就是batch size为64,max_seq_len为256,这边我为了增长推理输出的句子长度(max_seq_len),把训练时的batch_size减少了,要不然内存要不足了,也就是改为161024

3)token

run.c中int token = 1,表示从头开始生成,设置为0会不知道从哪开始,随便生成的,也就是开头不知道从哪开始,所以建议token采用默认值,也就是token=1

训练之前需修改数据集加载的路径

先来看看训练时数据集是怎么加载的: 先来看看训练时数据集是怎么加载的:

 

可以看到调用了Task.iter_batches,Task是在tinystories.py里面定义的,来看看tinystories.py里面的Task:

 

可看到调用了PretokDataset,仔细看PretokDataset,发现了数据集路径,修改即可,也就是修改PretokDataset下的"news_peoples_daily"

 

修改好之后训练模型:

 

1)直接可跑的代码:

下载数据集之后放在data目录,依次运行:

1、python3 news_peoples_daily.py 2、python3 mergedatas.py 3、python3 processTrainDataSets.py 4、python3 tinystories.py pretokenize 5、python3 train.py

[玩转AIGC]LLaMA2训练中文文章撰写神器(数据准备,数据处理,模型训练,模型推理) 2)只保留训练的代码

放在kaggle里面的代码,需要创建data/news_peoples_daily文件,然后把编码好的数据集.bin文件放到里面,直接训练训练即可:

[玩转AIGC]LLaMA2训练中文文章撰写神器(数据准备,数据处理,模型训练,模型推理)

训练之后,在out里我们可以得到两个模型: [玩转AIGC]LLaMA2训练中文文章撰写神器(数据准备,数据处理,模型训练,模型推理) model.bin模型是可以用来进行C代码推理的

1) python 读取bin模型

 

2)python读取pt模型并转为bin

1>逐层手写转换(占用内存少)

loadModelPt.py

 

2>参考llama2.py的转换(占用内存大一些)

github:https://github.com/tairov/llama2.py/tree/master

需对原来的代码做小修改,改为从.pt读取参数,然后也要修改输入:

修改后的代码为:

export_meta_llama_bin.py

如果你想改输入输出的路径,那么要修改代码export_meta_llama_bin.py里面的:

 

然后直接运行:

 

1)代码与模型

代码与模型在run.zip里面 [玩转AIGC]LLaMA2训练中文文章撰写神器(数据准备,数据处理,模型训练,模型推理) 可以看到主要为上图框中的4个文件,其中.bin文件均为模型文件,一个是文本编码模型,一个是llama模型

2)编译运行

进行编译

 

运行推理

 

int token = 0时生成的内容,开头随便生成

[玩转AIGC]LLaMA2训练中文文章撰写神器(数据准备,数据处理,模型训练,模型推理) int token = 1,=从头生成,且max_seq_len=1024

[玩转AIGC]LLaMA2训练中文文章撰写神器(数据准备,数据处理,模型训练,模型推理)

 

修改:

去掉下面两句(读取tokenizer.bin时):

 

bpe_encode也需要做修改(添加中文支持):

参考:https://github.com/chenyangMl/llama2.c-zh/blob/main/run.c

 

运行:

 
 

[玩转AIGC]LLaMA2训练中文文章撰写神器(数据准备,数据处理,模型训练,模型推理)

 

AVX2指的是使用 AVX2 指令集的内嵌函数(intrinsics)来执行矩阵乘法(matmul)操作,当然也包含了原始的矩阵乘法方法

将tokenizer.model拷贝到代码根目录下,运行:

 

导出的模型:tokenizer.bin

可见比master分支下的模型还要大一些,内容更丰富

跟1、可自定义参数运行(运行master旧tokenizer.bin模型) 一样,但是只需要修改bpe_encode 使得代码能够兼容中文,不一样的地方是不需要修改tokenizer.bin模型的读取,也就是不需要去掉

 

不同的地方在export

master的export

 

feature/avx2的export

 

把写入文件那里摘出来:

 

多写了max_token_length,与score:

f.write(struct.pack(“fI”, score, len(bytes)))改为f.write(struct.pack(“I”, len(bytes)))

把**f.write(struct.pack(“I”, max_token_length))**去掉,两者就一样了

 
 

对于大部分常见的中文字符,UTF-8 编码使用 3 个字节来表示。每个字节都有 8 位,因此一个中文字符在 UTF-8 编码中所占用的总位数是 3 × 8 = 24 位。

比如用下面的输入,带了prompt

 

输入的prompt为“中国特色社会主义”,会通过bpe_encode这个函数进行处理,结合分数来处理,

训练的tokenizer的词汇表,我们可以看到:

[玩转AIGC]LLaMA2训练中文文章撰写神器(数据准备,数据处理,模型训练,模型推理) 两个组合就是:

在tokenizer词汇表里面能找到的就是以下的词汇: [玩转AIGC]LLaMA2训练中文文章撰写神器(数据准备,数据处理,模型训练,模型推理) 可见中国是分数得分最高的,因此第一轮的:

best_score = -6.41448; best_id = 48; best_idx = 0;

把“中”,“国”,组合为“中国”,因此tokens变为以下的 [玩转AIGC]LLaMA2训练中文文章撰写神器(数据准备,数据处理,模型训练,模型推理) 接着再进行组合,那么就是

 

再来查看tokenizer词汇表 [玩转AIGC]LLaMA2训练中文文章撰写神器(数据准备,数据处理,模型训练,模型推理) 得分最高的是社会,将“社”,“会”,两个词组合到一起,因此输入的tokens变为: [玩转AIGC]LLaMA2训练中文文章撰写神器(数据准备,数据处理,模型训练,模型推理) 将tokens两两前后合并,得到:

 

查看tokenizer词汇表 [玩转AIGC]LLaMA2训练中文文章撰写神器(数据准备,数据处理,模型训练,模型推理)

得到主义得分最低,因此tokens就变为: [玩转AIGC]LLaMA2训练中文文章撰写神器(数据准备,数据处理,模型训练,模型推理) 然后再进行两两前后组合:

 

查看tokenizer词汇表 [玩转AIGC]LLaMA2训练中文文章撰写神器(数据准备,数据处理,模型训练,模型推理) 因此,tokens变为: [玩转AIGC]LLaMA2训练中文文章撰写神器(数据准备,数据处理,模型训练,模型推理) 最后再进行组合:

 

在tokenizer词汇表里面已经找不到相应词汇了,此时就结束while(1)的死循环

上面可以看到最后的tokens就变成了:

tokens[0] = 中国 tokens[1] = 特色 tokens[2] = 社会主义

也就是说原本为:“中”,“国”,“特”,“色”,“社”,“会”,“主”,“义”,经过bpe_encode的处理,就变成了“中国”,“特色”,“社会主义”,原本看起来没关系的独个词汇,变成有关联

最终得到的tokens就赋值给了prompt_tokens,即变为:[48, 2953, 274],然后再补一些padding,使得输入shape一致。

**steps:**不是表示词汇个数,而是生成的token个数,有个token包含了多个词汇,有的token是标点符号,比如:“社会主义”,“,”

注:很多没细看,以后有空再补充

 

https://github.com/google/sentencepiece/blob/9cf136582d9cce492ba5a0cfb775f9e777fe07ea/python/add_new_vocab.ipynb

 
 

打印new_token会得到下面的内容

 

采用UTF-8编码的,可恢复为:

 

打出来是“诽”

输出所加载模型的所有token:

 

最新文章