本文为稀土技能社区首发签约文章,30天内禁止转载,30天后未获授权禁止转载,侵权必究!

跟着 ChatGPT 的现象级走红,引领了AI大模型年代的变革,然后导致 AI 算力日益紧缺。与此同时,中美贸易战以及美国对华进行AI芯片相关的制裁导致 AI 算力的国产化适配势在必行。之前叙述了依据昇腾910运用ChatGLM-6B进行模型推理,本文将叙述针对ChatGLM-6B大模型在昇腾910加速卡上面进行模型练习,为了文章具有更好的阅览体验,详细代码放置在GitHub:llm-action。

环境建立

  • 操作系统版本/架构:EulerOS release 2.0 (SP8)/aarch64
  • NPU:8卡 910 ProB 32G
  • Python:3.7
  • NPU 驱动:23.0.rc1,下载
  • NPU 固件:6.3.0.1.241,下载
  • CANN 东西包:6.3.RC1.alpha003,下载
  • MindSpore:2.0.0-rc1,下载
  • MindFormers:dev ( commit id: 6f2b0b8 )

运转环境与依据昇腾910运用ChatGLM-6B进行模型推理共同,这儿就不再赘述了。

数据预备及数据格局转化

下面以ADGEN(广告生成) 数据集为例来介绍微调的详细运用。

ADGEN 数据集为依据输入(content)生成一段广告词(summary),详细格局如下所示:

{
    "content": "类型#上衣*版型#宽松*版型#显瘦*图案#线条*衣样式#衬衫*衣袖型#泡泡袖*衣样式#抽绳",
    "summary": "这件衬衫的样式非常的宽松,妥当的线条可以很好的隐藏身材上的小缺陷,穿在身上有着很好的显瘦效果。领口装修了一个心爱的抽绳,美丽的绳结展现出了十足的特性,合作时尚的泡泡袖型,尽显女人甜美心爱的气息。"
}

请从官网下载 ADGEN 数据集或经过此链接下载,并将其解压到AdvertiseGen目录。

tar -zxvf AdvertiseGen.tar.gz

查看数据集巨细:

> wc -l AdvertiseGen/*
> 1070 AdvertiseGen/dev.json
> 114599 AdvertiseGen/train.json
> 115669 total

运用mindformers/tools/dataset_preprocess/glm/adgen_dataset.py脚本将数据集处理成mindrecord格局。

履行指令生成练习数据集:

cd mindformers/tools/dataset_preprocess/glm
python adgen_dataset.py \
    --input_file /root/workspace/data/AdvertiseGen/train.json \
    --vocab_file /root/workspace/model/checkpoint_download/glm/ice_text.model\
    --output_file /root/workspace/data/AdvertiseGen-ms/train_0604_128.mindrecord \
    --max_source_length 64 \
    --max_target_length 64 \
    --mode train

运转进程:

100%|##########################################################################| 114599/114599 [11:25<00:00, 167.17it/s]
2023-06-20 14:26:59,086 - mindformers - INFO - Wrote 114599 total instances

履行指令生成评价数据集:

cd mindformers/tools/dataset_preprocess/glm
python adgen_dataset.py \
    --input_file /root/workspace/data/AdvertiseGen/dev.json \
    --vocab_file /root/workspace/model/checkpoint_download/glm/ice_text.model \
    --output_file /root/workspace/data/AdvertiseGen-ms/eval_0604_256.mindrecord \
    --max_source_length 256 \
    --max_target_length 256 \
    --mode eval

运转进程:

100%|##############################################################################| 1070/1070 [00:01<00:00, 772.11it/s]
2023-06-20 14:17:20,492 - mindformers - INFO - Wrote 1070 total instances    

转化后的文件如下所示:

> tree AdvertiseGen-ms/
AdvertiseGen-ms/
├── eval_0711_256.mindrecord
├── eval_0711_256.mindrecord.db
├── train_0604_128.mindrecord
└── train_0604_128.mindrecord.db

其间,*.mindrecord为数据文件,*.mindrecord.db为索引文件。

弥补阐明

一个MindRecord文件由数据文件和索引文件组成:

  • 数据文件:包括文件头、标量数据页、块数据页,用于存储用户归一化后的练习数据,且单个MindRecord文件主张小于20G,用户可将大数据集进行分片存储为多个MindRecord文件。
  • 索引文件:包括依据标量数据(如:图画Label、图画文件名等)生成的索引信息,用于便利的检索、计算数据集信息。

大模型国产化适配3-基于昇腾910使用ChatGLM-6B进行模型训练

数据文件首要由以下几个要害部分组成:

  • 文件头:文件头首要用来存储文件头巨细、标量数据页巨细、块数据页巨细、Schema信息、索引字段、计算信息、文件分区信息、标量数据与块数据对应关系等,是MindRecord文件的元信息。
  • 标量数据页:标量数据页首要用来存储整型、字符串、浮点型数据,如:图画的Label、图画的文件名、图画的长宽等信息,即适合用标量来存储的信息会保存在这儿。
  • 块数据页:块数据页首要用来存储二进制串、Numpy数组等数据,如:二进制图画文件自身、文本转化成的字典等。

模型预备及模型格局转化

模型预备及模型格局转化请参阅依据昇腾910运用ChatGLM-6B进行模型推理,这儿也不再赘述。

代码预备

模型练习的代码直接运用安装mindformers的代码即可,因为版本迭代很快,为了防止代码不兼容的情况,主张坚持同样的commit id。

git clone https://gitee.com/mindspore/mindformers.git
cd mindformers/
git checkout 6f2b0b8

网络装备

当进行分布式练习时,需求经过昇腾软件中的HCCN Tool东西装备device的网卡IP,用于多个device间通讯以完结网络模型参数的同步更新。

关于装备的要求如下:

  • AI Server中的第0/4,1/5,2/6,3/7号网卡需处于同一网段,第0/1/2/3号网卡在不同网段,第4/5/6/7号网卡在不同网段。
  • 关于集群场景,各AI Server对应的位置的device需处于同一网段,例如:AI Server1和AI Server2的0号网卡需处于同一网段,AI Server1 和 AI Server2 的1号网卡需处于同一网段。IP地址需求依据实际情况修正。

先检查/etc/下是否有hccn.conf装备文件,若不存在,需先履行如下指令进行设置:

hccn_tool -i 0 -ip -s address 192.168.100.101 netmask 255.255.255.0
hccn_tool -i 1 -ip -s address 192.168.101.101 netmask 255.255.255.0
hccn_tool -i 2 -ip -s address 192.168.102.101 netmask 255.255.255.0
hccn_tool -i 3 -ip -s address 192.168.103.101 netmask 255.255.255.0
hccn_tool -i 4 -ip -s address 192.168.100.100 netmask 255.255.255.0
hccn_tool -i 5 -ip -s address 192.168.101.100 netmask 255.255.255.0
hccn_tool -i 6 -ip -s address 192.168.102.100 netmask 255.255.255.0
hccn_tool -i 7 -ip -s address 192.168.103.100 netmask 255.255.255.0

参数阐明:

  • -i0:指定设备ID。
  • -netdetect:指定网络检测目标IP属性。
  • -saddress:表明设置属性为IP地址。192.168.100.101表明服务器的设备0的ip地址。

查看/etc/hccn.conf文件:

> cat /etc/hccn.conf
address_0=192.168.100.101
netmask_0=255.255.255.0
...
address_7=192.168.103.100
netmask_7=255.255.255.0

软件、模型、数据、代码以及网络环境预备好之后,接下来进行模型练习。

模型练习

下面分别对模型全量微调以及LoRA微调进行讲解。

全量微调

首要,生成用于Ascend芯片分布式通讯的芯片资源信息装备文件(RANK_TABLE_FILE)。Ascend HCCL 的 RANK_TABLE_FILE 文件供给Ascend分布式练习作业的集群信息。下面生成8卡的rank_table_file文件。

> python ./mindformers/tools/hccl_tools.py --device_num "[0,8)"
start ./mindformers/tools/hccl_tools.py
visible_devices:['0', '1', '2', '3', '4', '5', '6', '7']
server_id:192.168.1.196
device_num_list: [0, 1, 2, 3, 4, 5, 6, 7]
rank_id:0, device_id:0, device_ip:192.168.100.101
...
rank_id:7, device_id:7, device_ip:192.168.103.100
Completed: hccl file was save in : /root/workspace/code/mindformers/hccl_8p_01234567_192.168.1.196.json

修正装备文件(configs/glm/run_glm_6b_finetune.yaml),设置模型权重途径、练习和评价数据集途径等,现在运用张量并行为8进行练习。

load_checkpoint: '/root/workspace/model/chatglm-convert/ms_glm_6b.ckpt'
train_dataset: &train_dataset
  data_loader:
    type: MindDataset
    dataset_dir: "/root/workspace/data/AdvertiseGen-ms/train_0604_128.mindrecord"
    shuffle: True
eval_dataset: &eval_dataset
  data_loader:
    type: MindDataset
    dataset_dir: "/root/workspace/data/AdvertiseGen-ms/eval_0604_256.mindrecord"
    shuffle: True
parallel_config:
  data_parallel: 1
  model_parallel: 8
  pipeline_stage: 1
  expert_parallel: 1

发动模型练习前,可以经过设置多卡间等待时间(HCCL_CONNECT_TIMEOUT)来防止长期没收到其他卡的消息而失败的问题,默以为300(秒)。

export HCCL_CONNECT_TIMEOUT=1200

scripts目录下发动全量微调练习任务:

# cd /root/workspace/code/mindformers/scripts
# Usage Help: bash run_distribute.sh [RANK_TABLE_FILE] [CONFIG_PATH] [DEVICE_RANGE] [RUN_STATUS]
> bash run_distribute.sh /root/workspace/code/mindformers/hccl_8p_01234567_192.168.1.196.json ../configs/glm/run_glm_6b_finetune.yaml '[0,8]' finetune
start training for rank 0, device 0
...
start training for rank 7, device 7

参数阐明

  • RANK_TABLE_FILE: hccl_tools.py生成的分布式json文件。
  • CONFIG_PATH: 装备文件。
  • DEVICE_RANGE: 单机分布式卡的范围,如:[0,8]为8卡分布式,不包括8自身。
  • RUN_STATUS: 任务运转状况,支持要害:train、eval、finetune、predict。

模型练习发动成功,输出目录的结构如下所示。

output/
├── checkpoint
├── log
└── strategy

其间,checkpoint文件夹放置权重文件,log文件夹方式日志文件,strategy文件夹放置模型切分战略文件。

部分练习日志如下所示:

...
[INFO] 2023-07-11 10:38:43,568 [/root/workspace/code/mindformers/scripts/mf_parallel1/mindformers/trainer/base_trainer.py:550] training_process: .........Build Running Wrapper From Config For Train..........
[INFO] 2023-07-11 10:38:43,568 [/root/workspace/code/mindformers/scripts/mf_parallel1/mindformers/trainer/base_trainer.py:391] create_model_wrapper: .........Build Model Wrapper for Train From Config..........
[INFO] 2023-07-11 10:38:43,582 [/root/workspace/code/mindformers/scripts/mf_parallel1/mindformers/trainer/base_trainer.py:562] training_process: .........Starting Init Train Model..........
[INFO] 2023-07-11 10:38:43,583 [/root/workspace/code/mindformers/scripts/mf_parallel1/mindformers/trainer/base_trainer.py:581] training_process: .........Build Callbacks For Train..........
[INFO] 2023-07-11 10:38:43,583 [/root/workspace/code/mindformers/scripts/mf_parallel1/mindformers/trainer/base_trainer.py:400] create_callbacks: .........Build Callbacks for Train From Config..........
[INFO] 2023-07-11 10:38:43,584 [/root/workspace/code/mindformers/scripts/mf_parallel1/mindformers/core/callback/callback.py:340] __init__: Integrated_save is changed to False when using auto_parallel.
[INFO] 2023-07-11 10:38:43,585 [/root/workspace/code/mindformers/scripts/mf_parallel1/mindformers/trainer/base_trainer.py:609] training_process: .........Starting Training Model..........
[INFO] 2023-07-11 10:38:43,585 [/root/workspace/code/mindformers/scripts/mf_parallel1/mindformers/trainer/base_trainer.py:610] training_process: .........Model Compiling, Please Wait a Moment...........
[INFO] 2023-07-11 10:47:36,427 [/root/workspace/code/mindformers/scripts/mf_parallel1/mindformers/core/callback/callback.py:269] print_output_info: Epoch:[  1/  1], step:[    4/  125], loss:[2.244/2.244], time:507844.205 ms, lr:[0.], overflow cond: True, loss_scale: 268435460.0
[INFO] 2023-07-11 10:47:37,342 [/root/workspace/code/mindformers/scripts/mf_parallel1/mindformers/core/callback/callback.py:146] epoch_end: Per sink_size step time: 533756.177 ms, per step time: 133439.044 ms, avg loss: 2.244
[INFO] 2023-07-11 10:47:44,861 [/root/workspace/code/mindformers/scripts/mf_parallel1/mindformers/core/callback/callback.py:269] print_output_info: Epoch:[  1/  1], step:[    8/  125], loss:[2.499/2.499], time:7480.938 ms, lr:[0.], overflow cond: True, loss_scale: 16777216.0
[INFO] 2023-07-11 10:47:44,874 [/root/workspace/code/mindformers/scripts/mf_parallel1/mindformers/core/callback/callback.py:146] epoch_end: Per sink_size step time: 7518.224 ms, per step time: 1879.556 ms, avg loss: 2.499
...
[INFO] 2023-07-11 10:48:35,199 [/root/workspace/code/mindformers/scripts/mf_parallel1/mindformers/core/callback/callback.py:146] epoch_end: Per sink_size step time: 1958.791 ms, per step time: 489.698 ms, avg loss: 2.091
[INFO] 2023-07-11 10:48:37,162 [/root/workspace/code/mindformers/scripts/mf_parallel1/mindformers/core/callback/callback.py:269] print_output_info: Epoch:[  1/  1], step:[  116/  125], loss:[2.220/2.220], time:1951.612 ms, lr:[2.4499998e-06], overflow cond: False, loss_scale: 16384.0
[INFO] 2023-07-11 10:48:37,163 [/root/workspace/code/mindformers/scripts/mf_parallel1/mindformers/core/callback/callback.py:146] epoch_end: Per sink_size step time: 1963.915 ms, per step time: 490.979 ms, avg loss: 2.220
[INFO] 2023-07-11 10:48:39,125 [/root/workspace/code/mindformers/scripts/mf_parallel1/mindformers/core/callback/callback.py:269] print_output_info: Epoch:[  1/  1], step:[  120/  125], loss:[2.092/2.092], time:1953.753 ms, lr:[2.5499999e-06], overflow cond: False, loss_scale: 16384.0
[INFO] 2023-07-11 10:48:39,126 [/root/workspace/code/mindformers/scripts/mf_parallel1/mindformers/core/callback/callback.py:146] epoch_end: Per sink_size step time: 1962.049 ms, per step time: 490.512 ms, avg loss: 2.092
[INFO] 2023-07-11 10:48:41,083 [/root/workspace/code/mindformers/scripts/mf_parallel1/mindformers/core/callback/callback.py:269] print_output_info: Epoch:[  1/  1], step:[  124/  125], loss:[2.346/2.346], time:1949.995 ms, lr:[2.65e-06], overflow cond: False, loss_scale: 16384.0
[INFO] 2023-07-11 10:48:41,084 [/root/workspace/code/mindformers/scripts/mf_parallel1/mindformers/core/callback/callback.py:146] epoch_end: Per sink_size step time: 1958.268 ms, per step time: 489.567 ms, avg loss: 2.346
[INFO] 2023-07-11 10:49:26,307 [/root/workspace/code/mindformers/scripts/mf_parallel1/mindformers/trainer/base_trainer.py:616] training_process: .........Training Over!.............

LoRA 简述

针对大模型来说,模型全量微调需求消耗很多的内存;除此之外,模型全量微调还会损失多样性,存在灾难性忘记的问题,因而,催生了各种高效微调技能。而LoRA,无疑是如今最盛行的高效微调办法之一。

LoRA(论文:LoRA: LOW-RANK ADAPTATION OF LARGE LANGUAGE MODELS),该办法的核心思维就是经过低秩分解来模仿参数的改变量,然后以极小的参数量来完结大模型的直接练习。

在涉及到矩阵相乘的模块,在原始的PLM周围添加一个新的通路,经过前后两个矩阵A,B相乘,第一个矩阵A担任降维,第二个矩阵B担任升维,中间层维度为r,然后来模仿所谓的本征秩(intrinsic rank)。

大模型国产化适配3-基于昇腾910使用ChatGLM-6B进行模型训练

更加详细的介绍可参阅之前的文章:大模型参数高效微调技能原理综述(五)-LoRA、AdaLoRA、QLoRA。

LoRA 微调

首要,生成用于Ascend芯片分布式通讯的芯片资源信息装备文件,因为仅运用LoRA进行参数高效微调,所需内存削减,此处用4卡张量并行即可练习,因而,这儿仅生成运用4卡的rank_table_file文件。

> python ./mindformers/tools/hccl_tools.py --device_num "[0,4)"
start ./mindformers/tools/hccl_tools.py
visible_devices:['0', '1', '2', '3', '4', '5', '6', '7']
server_id:192.168.1.196
device_num_list: [0, 1, 2, 3]
rank_id:0, device_id:0, device_ip:192.168.100.101
rank_id:1, device_id:1, device_ip:192.168.101.101
rank_id:2, device_id:2, device_ip:192.168.102.101
rank_id:3, device_id:3, device_ip:192.168.103.101
Completed: hccl file was save in : /root/workspace/code/mindformers/hccl_4p_0123_192.168.1.196.json

修正装备文件(configs/glm/run_glm_6b_lora.yaml),设置模型权重途径、练习和评价数据集途径等,详细装备同全量微调类似,现在运用张量并行为4进行练习。

load_checkpoint: "/root/workspace/model/chatglm-convert/ms_glm_6b.ckpt"
train_dataset: &train_dataset
  data_loader:
    type: MindDataset
    dataset_dir: "/root/workspace/data/AdvertiseGen-ms/train_0604_128.mindrecord"
    shuffle: True
eval_dataset: &eval_dataset
  data_loader:
    type: MindDataset
    dataset_dir: "/root/workspace/data/AdvertiseGen-ms/eval_0604_256.mindrecord"
    shuffle: True
parallel_config:
  data_parallel: 1
  model_parallel: 4
  pipeline_stage: 1
  expert_parallel: 1

scripts目录下发动LoRA微调练习任务:

# cd /root/workspace/code/mindformers/scripts
# Usage Help: bash run_distribute.sh [RANK_TABLE_FILE] [CONFIG_PATH] [DEVICE_RANGE] [RUN_STATUS]
> bash run_distribute.sh /root/workspace/code/mindformers/hccl_4p_0123_192.168.1.196.json ../configs/glm/run_glm_6b_lora.yaml '[0,4]' finetune

详细的参数同全量微调共同。

不管是全量微调,仍是LoRA微调,假如运用多卡模型并行进行练习,模型练习完结之后,需求先兼并模型权重文件。

模型权重兼并

微调所得到的模型权重文件为依据模型切分战略切分后的权重,我们需求手动将切分后的权重兼并为一个文件,以用于评价和推理。

全量微调权重兼并

首要,获取模型切分战略文件,在履行全量参数微调时,模型完结编译后,将会在模型输出权重途径下strategy子目录生成类似名为ckpt_strategy*.ckpt的切分战略文件,找到对应的文件途径。

接下来,履行以下脚本(merge_ckpt.py),将8份模型文件合成一份。MindSpore供给了依据切分战略转化模型权重切分的接口(mindspore.transform_checkpoint_by_rank)。

python3 merge_ckpt.py --src_postfix=31_4 \
--src_checkpoints_dir=/root/workspace/output/fullft_output \
--src_strategy_file=/root/workspace/output/fullft_output/strategy/ckpt_strategy_rank_0.ckpt \
--dst_checkpoints_dir=/root/workspace/output/fullft_merge_checkpoint/

参数阐明:

  • src_postfix: 练习最新生成模型文件中数字,用于兼并文件时索引。
  • src_checkpoints_dir: 练习生成的模型文件途径。
  • src_strategy_file: 模型切分战略文件。
  • dst_checkpoints_dir: 模型文件兼并后文件夹途径。

兼并之后的权重文件如下所示:

> tree -h /root/workspace/output/fullft_merge_checkpoint
/root/workspace/output/fullft_merge_checkpoint
├── [  13G]  filtered_transformed.ckpt
└── [  63G]  transformed.ckpt

LoRA微调权重兼并

需求留意的是,在运用LoRA进行参数微调时,生成的切分战略文件将不包括被冻住的权重,导致权重文件兼并失败;此刻,需将mindformers/models/glm/glm.py文件中有关LoRA冻住权重的代码注释后,从头运转微调脚本,获取到正确的切分战略文件后中止练习进程;相关代码如下

@MindFormerRegister.register(MindFormerModuleType.MODELS)
class GLMForPreTrainingWithLora(GLMForPreTraining):
  def __init__(self, config: GLMConfig = None, pet=None, **kwargs):
    _ = kwargs
    super().__init__(config)
    # get Pet tuning model.
    self.pet = pet
    self.pet.pet_config.reg_rules = r'.*query_key_value*'
    self.transformer = LoraAdapter.get_pet_model(self.transformer, self.pet.pet_config)
    # freeze pretrained model
    PetAdapter.freeze_pretrained_model(self, self.pet.pet_type)     # 注释此行以生成新的战略文件

LoRA微调的权重兼并与全量微调权重兼并类似,详细指令如下:

python3 merge_ckpt_lora.py --src_postfix=31_4 \
--src_checkpoints_dir=/root/workspace/output/lora_output \
--src_strategy_file=/root/workspace/code/mindformers/output/strategy/ckpt_strategy_rank_0.ckpt \
--dst_checkpoints_dir=/root/workspace/output/lora_merge_checkpoint_v2/

兼并之后的模型权重文件如下所示:

> tree -h /root/workspace/output/lora_merge_checkpoint_v2/
/root/workspace/output/lora_merge_checkpoint_v2/
├── [  14G]  filtered_transformed.ckpt
└── [  14G]  transformed.ckpt

模型权重兼并之后,接下来进行模型评价。

模型评价

全量微调模型评价

履行以下脚本(run_mindformer.py)进行模型评价:

python run_mindformer.py \
--config ./configs/glm/run_glm_6b_infer.yaml \
--run_mode eval \
--load_checkpoint /root/workspace/output/fullft_merge_checkpoint/filtered_transformed.ckpt \
--eval_dataset_dir /root/workspace/data/AdvertiseGen-ms/eval_0604_256.mindrecord \
--device_id 7

参数阐明:

  • config: 指定用于评价的装备文件名称,此处为configs/glm/run_glm_6b_infer.yaml
  • run_mode: 指定履行形式,此为eval,表明为评价形式
  • load_checkpoint: 指定要加载的checkpoint途径,替换为权重兼并之后的真实途径。
  • eval_dataset_dir: 评价数据集的途径。
  • device_id: 指定要运用的设备编号。

评价完结后会打印评价目标bleu-4rouge-1rouge-2rouge-l。详细如下所示:

rouge-1: 25.986109999999993 
rouge-2: 4.22121 
rouge-l: 21.202881999999995 
bleu-4:  4.540767999999999 

留意:

因为默许评价目标为生成完整文本后与预期文本做比较,评价速度将受限于模型巨细与文本生成速度,评价流程可能较为缓慢。

LoRA微调模型评价

LoRA微调模型评价同全量微调模型评价办法共同,详细指令如下。

python run_mindformer.py \
--config ./configs/glm/run_glm_6b_lora_infer.yaml \
--run_mode eval \
--load_checkpoint /root/workspace/output/lora_merge_checkpoint_v2/filtered_transformed.ckpt \
--eval_dataset_dir /root/workspace/data/AdvertiseGen-ms/eval_0711_256.mindrecord \
--device_id 0

结语

本文首要叙述了针对华为昇腾910加速卡依据ChatGLM-6B进行模型练习(全量微调以及LoRA微调)、权重兼并以及模型评价。

假如觉得我的文章可以可以给您带来帮助,期待您的点赞保藏加重视~~