基于SWIFT和Qwen1.5-14B-Chat进行大模型LoRA微调测试
环境准备
基础环境
- 操作系统:Ubuntu 18.04.5 LTS (GNU/Linux 3.10.0-1127.el7.x86_64 x86_64)
- Anaconda3:Anaconda3-2023.03-1-Linux-x86_64
- 根据服务器网络情况配置好conda源和pip源,此处使用的是超算山河源
- 服务器硬件配置:CPU 96核;GPU 8×NVIDIA A100 40GB
环境安装
通过源代码安装SWIFT:
创建一个新的conda环境:
conda create --name swift python=3.8
激活刚刚创建的conda环境:
conda activate swift
下载SWIFT源码:
git clone https://github.com/modelscope/swift.git
切换到SWIFT路径:
cd /yldm0226/swift
安装SWIFT:
pip install -e .[llm]
非必要步骤:检查服务器cuda版本是否与当前安装的pytorch对应,详见:搭建一个大模型API服务
数据集准备
对于数据集,我们均采用json或jsonl的格式。
在做大模型SFT(Supervised Fine-Tuning)时,可以准备两种数据:
- 单轮问答
- 多轮对话
对于单轮问答数据,其格式可以为:
{"query": "11111", "response": "22222"}
对于多轮对话数据,其格式可以为:
{"query": "eeeee", "response": "fffff", "history": []}
{"query": "EEEEE", "response": "FFFFF", "history": [["AAAAA", "BBBBB"], ["CCCCC", "DDDDD"]]}
同时,也可以用以下两种格式的数据:
{"conversations": [{"from": "user", "value": "11111"}, {"from": "assistant", "value": "22222"}]}
{"conversations": [{"from": "user", "value": "aaaaa"}, {"from": "assistant", "value": "bbbbb"}, {"from": "user", "value": "ccccc"}, {"from": "assistant", "value": "ddddd"}]}
{"conversations": [{"from": "user", "value": "AAAAA"}, {"from": "assistant", "value": "BBBBB"}, {"from": "user", "value": "CCCCC"}, {"from": "assistant", "value": "DDDDD"}]}
{"messages": [{"role": "user", "content": "11111"}, {"role": "assistant", "content": "22222"}]}
{"messages": [{"role": "user", "content": "aaaaa"}, {"role": "assistant", "content": "bbbbb"}, {"role": "user", "content": "ccccc"}, {"role": "assistant", "content": "ddddd"}]}
{"messages": [{"role": "user", "content": "AAAAA"}, {"role": "assistant", "content": "BBBBB"}, {"role": "user", "content": "CCCCC"}, {"role": "assistant", "content": "DDDDD"}]}
在本文中,共使用了9个数据集,数据集的详细信息如下:
序号 | 数据集 | 简介 | 数据量 |
---|---|---|---|
1 | Chinese_medical_dialogue_six_department | 中文医疗问答数据集,包括男科、内科、妇产科、肿瘤科、儿科、外科六个科室的问题。 | 792K |
2 | HuatuoGPT2_sft_instruct_GPT4 | 华佗GPT(HuatuoGPT)第二版训练数据集。 | 50K |
3 | ChatMed_Consult-v0.3 | 中文医疗在线问诊数据集ChatMed_Consult_Dataset的50w+在线问诊+ChatGPT回复。 | 500K |
4 | ChatMed_TCM-v0.2 | 以开源的中医药知识图谱为基础,采用以实体为中心的自指令方法(entity-centric self-instruct),调用ChatGPT得到11w+的围绕中医药的指令数据。 | 110K |
5 | QiZhen_sft_20k | 包含20k训练数据(该数据集来自于启真医学知识库收集整理的真实医患知识问答数据以及在启真医学知识库的药品文本知识基础上,通过对半结构化数据设置特定的问题模板构造的指令数据)。 | 20K |
6 | Huatuo_Lite | Huatuo-Lite 是在Huatuo26M数据集的基础上经过多次提纯和重写而精炼优化的数据集。它包含了18万个高质量的医疗问答对,并具有医院科室和相关疾病两个额外的数据维度。 | 180K |
7 | ZhongJing_CMtMedQA | 仲景SFT训练集。 | 70K |
8 | DISC-Med-SFT_released | 包含了超过47万个衍生于现有的医疗数据集重新构建得到的样本。采用了目标导向的策略,通过对于精心选择的几个数据源进行重构来得到SFT数据集。这些数据的作用在于帮助模型学习医疗领域知识,将行为模式与人类偏好对齐,并对齐真实世界在线医疗对话的分布情况。 | 514K |
9 | SZY_TCM_QA | 私有数据集。 | 12K |
以下是加载后的数据集信息:
[INFO:swift] train_dataset: Dataset({
features: ['query', 'response', 'history'],
num_rows: 2223540
})
[INFO:swift] val_dataset: Dataset({
features: ['query', 'response', 'history'],
num_rows: 22460
})
数据总量为2,246,000,从中抽取出约1%作为验证集,其余的作为训练集。
通过max_lengt=4096进行过滤后的数据集信息如下:
[INFO:swift] Dataset Token Length: 224.276768±159.001432, min=25.000000, max=4089.000000, size=2223411
[INFO:swift] Dataset Token Length: 224.254464±157.600093, min=28.000000, max=3086.000000, size=22459
编写微调脚本
SWIFT框架提供了部分大模型的微调脚本,可以在我们下载的源码中的swift/examples/pytorch/llm/scripts路径中找到这些脚本。如果这些脚本能够满足我们大部分的微调需求,我们可以选择直接对这些脚本进行修改。如果找不到我们需要的脚本,需要我们根据swift/docs/source/LLM中的命令行参数文档自行编写训练脚本。
以下是对Qwen1.5-14B-Chat进行LoRA微调的一个训练脚本:
nproc_per_node=8
CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 \
NPROC_PER_NODE=$nproc_per_node \
MASTER_PORT=29500 \
swift sft \
--model_type qwen1half-14b-chat \
--model_id_or_path /yldm0226/models/Qwen1.5-14B-Chat \
--model_revision master \
--sft_type lora \
--tuner_backend swift \
--template_type qwen \
--dtype AUTO \
--output_dir /yldm0226/llm_sft_output \
--ddp_backend nccl \
--custom_train_dataset_path /yldm0226/data/1-Chinese_medical_dialogue_six_department.jsonl /yldm0226/data/2-HuatuoGPT2_sft_instruct_GPT4.jsonl /yldm0226/data/3-ChatMed_Consult-v0.3.jsonl /yldm0226/data/4-ChatMed_TCM-v0.2.jsonl /yldm0226/data/5-QiZhen_sft_20k.jsonl /yldm0226/data/6-Huatuo_Lite.jsonl /yldm0226/data/7-ZhongJing_CMtMedQA.jsonl /yldm0226/data/8-DISC-Med-SFT_released.jsonl /yldm0226/data/9-SZY_TCM_QA.jsonl \
--train_dataset_sample -1 \
--num_train_epochs 1 \
--max_length 4096 \
--check_dataset_strategy warning \
--lora_rank 8 \
--lora_alpha 32 \
--lora_dropout_p 0.05 \
--lora_target_modules ALL \
--gradient_checkpointing true \
--batch_size 1 \
--weight_decay 0.01 \
--learning_rate 1e-4 \
--gradient_accumulation_steps $(expr 64 / $nproc_per_node) \
--max_grad_norm 0.5 \
--warmup_ratio 0.03 \
--eval_steps 100 \
--save_steps 100 \
--save_total_limit 3 \
--logging_steps 10 \
--use_flash_attn false \
--deepspeed default-zero3 \
--save_only_model true
该脚本中的一些参数在基于SWIFT和Qwen1.5-14B-Chat进行大模型全参微调测试中已经解释过了,此处简单介绍一下与LoRA相关的几个参数,如果你想了解LoRA具体的原理,请阅读该论文LORA: LOW-RANK ADAPTATION OF LARGE LANGUAGE MODELS:
lora_rank
:微调中的秩大小。秩的值并不是越大越好,此处设置的8是LoRA原论文中测试的最优解,根据论文中的结果,1或者2这种很小的秩的表现也是很好的。
lora_alpha
:LoRA 微调中的缩放系数。
lora_dropout_p
:LoRA 微调中的 Dropout 系数。
lora_target_modules
:指定lora模块, 默认为['DEFAULT']
. 如果lora_target_modules传入'DEFAULT'
or 'AUTO'
, 则根据model_type
查找MODEL_MAPPING
中的lora_target_modules
(默认指定为qkv)。如果传入'ALL'
, 则将所有的Linear层(不含head)指定为lora模块。 如果传入'EMBEDDING'
, 则Embedding层指定为lora模块。 如果内存允许, 建议设置成'ALL'。 当然, 你也可以设置['ALL', 'EMBEDDING']
, 将所有的Linear和embedding层指定为lora模块。该参数只有当sft_type
指定为'lora'时才生效。
deepspeed
:用于指定deepspeed的配置文件的路径或者直接传入json格式的配置信息, 默认为None
, 即不开启deepspeed. deepspeed可以节约显存。 SWIFT书写了默认的ZeRO-2配置文件, ZeRO-3配置文件。你只需要指定'default-zero2', 就会使用默认zero2配置文件; 指定'default-zero3', 就会使用默认的zero3配置文件。
测试
以下是训练过程中的部分输出:
{'loss': 3.91967845, 'acc': 0.46053511, 'learning_rate': 0.0, 'epoch': 0.0, 'global_step': 1}
{'loss': 3.13938289, 'acc': 0.50242286, 'learning_rate': 3.313e-05, 'epoch': 0.0, 'global_step': 10}
{'loss': 2.02636986, 'acc': 0.56641636, 'learning_rate': 4.31e-05, 'epoch': 0.0, 'global_step': 20}
{'loss': 1.51573572, 'acc': 0.62124624, 'learning_rate': 4.894e-05, 'epoch': 0.0, 'global_step': 30}
{'loss': 1.37469482, 'acc': 0.65222416, 'learning_rate': 5.308e-05, 'epoch': 0.0, 'global_step': 40}
{'loss': 1.44527245, 'acc': 0.64013515, 'learning_rate': 5.629e-05, 'epoch': 0.0, 'global_step': 50}
{'loss': 1.36220665, 'acc': 0.65485716, 'learning_rate': 5.891e-05, 'epoch': 0.0, 'global_step': 60}
{'loss': 1.34706726, 'acc': 0.65729899, 'learning_rate': 6.113e-05, 'epoch': 0.0, 'global_step': 70}
{'loss': 1.3558219, 'acc': 0.65412712, 'learning_rate': 6.305e-05, 'epoch': 0.0, 'global_step': 80}
{'loss': 1.38924046, 'acc': 0.6498558, 'learning_rate': 6.475e-05, 'epoch': 0.0, 'global_step': 90}
{'loss': 1.31848869, 'acc': 0.66292844, 'learning_rate': 6.626e-05, 'epoch': 0.0, 'global_step': 100}
Train: 0%|▌ | 100/34740 [20:07<113:54:29, 11.84s/it]
Val: 22%|████████████████████████████████████████████ | 615/2808 [04:56<17:36, 2.07it/s]
训练一个epoch大约需要114小时;进行一次验证大约需要22分钟。(这里的时间只是一个大概值,在训练时,不同数据的处理速度不同,花费的总时间会一直变化)。文章来源:https://www.toymoban.com/news/detail-837691.html
相比于全参,LoRA的微调方式能够节约大量的显存,因此我们可以将nproc_per_node设置的大一些,以提高训练的速度。文章来源地址https://www.toymoban.com/news/detail-837691.html
到了这里,关于基于SWIFT和Qwen1.5-14B-Chat进行大模型LoRA微调测试的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!