本篇文章是书生浦语大模型微调实战系列第四篇。
一个大语言模型微调工具箱。由 MMRazor 和 MMDeploy 联合开发。
有一个超大的玩具,现在你想改造这个超大的玩具。对整个玩具进行全面的改动会非常昂贵。
※ 因此,你找到了一种叫 LoRA 的方法:只对玩具中的某些零件进行改动,而不是对整个玩具进行全面改动。
※ 而 QLoRA 是 LoRA 的一种改进:如果你手里只有一把生锈的螺丝刀,也能改造你的玩具。
快速入门炼丹炉
Ubuntu + Anaconda + CUDA/CUDNN + 8GB nvidia显卡
# 如果你是在 InternStudio 平台,则从本地 clone 一个已有 pytorch 2.0.1 的环境:
conda create --name xtuner0.1.9 --clone=/root/share/conda_envs/internlm-base
# 如果你是在其他平台:
conda create --name xtuner0.1.9 python=3.10 -y
# 激活环境
conda activate xtuner0.1.9
# 进入家目录 (~的意思是 “当前用户的home路径”)
cd ~
# 创建版本文件夹并进入,以跟随本教程
mkdir xtuner019 && cd xtuner019
# 拉取 0.1.9 的版本源码
git clone -b v0.1.9 https://github.com/InternLM/xtuner
# 无法访问github的用户请从 gitee 拉取:
# git clone -b v0.1.9 https://gitee.com/Internlm/xtuner
# 进入源码目录
cd xtuner
# 从源码安装 XTuner
pip install -e '.[all]'
准备在 oasst1 数据集上微调 internlm-7b-chat
# 创建一个微调 oasst1 数据集的工作路径,进入
mkdir ~/ft-oasst1 && cd ~/ft-oasst1
XTuner 提供多个开箱即用的配置文件,用户可以通过下列命令查看:
# 列出所有内置配置
xtuner list-cfg
==========================CONFIGS===========================
baichuan2_13b_base_qlora_alpaca_e3
...
baichuan2_7b_base_qlora_alpaca_e3
...
baichuan_13b_base_qlora_alpaca_e3
...
baichuan_7b_qlora_alpaca_e3
...
chatglm2_6b_qlora_alpaca_e3
...
chatglm3_6b_base_qlora_alpaca_e3
...
deepspeed_zero1
...
internlm_20b_qlora_alpaca_e3
...
internlm_7b_full_alpaca_e3
...
internlm_chat_20b_qlora_alpaca_e3
...
internlm_chat_7b_qlora_alpaca_e3
...
llama2_70b_int8_lora_open_platypus_e1
...
llama2_7b_chat_qlora_alpaca_e3
...
llama2_7b_qlora_alpaca_e3
...
llama_7b_qlora_alpaca_e3
...
mistral_7b_qlora_skypile_pretrain_e1
qwen_7b_chat_qlora_alpaca_e3
...
qwen_7b_qlora_alpaca_e3
...
starcoder_qlora_stack_exchange_example
yi_34b_qlora_alpaca_enzh_e3
yi_6b_qlora_alpaca_enzh_e3
zephyr_7b_beta_qlora_alpaca_e3
=============================================================
拷贝一个配置文件到当前目录: xtuner copy-cfg ${CONFIG_NAME} ${SAVE_PATH}
cd ~/ft-oasst1
xtuner copy-cfg internlm_chat_7b_qlora_oasst1_e3 .
配置文件名的解释: xtuner copy-cfg internlm_chat_7b_qlora_oasst1_e3 .
模型名 | internlm_chat_7b |
---|---|
使用算法 | qlora |
数据集 | oasst1 |
把数据集跑几次 | 跑3次:e3 (epoch 3 ) |
*无 chat比如 internlm-7b
代表是基座(base)模型
不用 xtuner 默认的从 huggingface 拉取模型
,而是提前从 OpenXLab ModelScope 下载模型到本地
# 创建一个目录,放模型文件,防止散落一地
mkdir ~/ft-oasst1/internlm-chat-7b
# 装一下拉取模型文件要用的库
pip install modelscope
# 从 modelscope 下载下载模型文件
cd ~/ft-oasst1
apt install git git-lfs -y
git lfs install
git lfs clone https://modelscope.cn/Shanghai_AI_Laboratory/internlm-chat-7b.git -b v1.0.3
https://huggingface.co/datasets/timdettmers/openassistant-guanaco/tree/main
cd ~/ft-oasst1
# ...-guanaco 后面有个空格和英文句号啊
cp -r /root/share/temp/datasets/openassistant-guanaco .
|-- internlm-chat-7b
| |-- README.md
| |-- config.json
| |-- configuration.json
| |-- configuration_internlm.py
| |-- generation_config.json
| |-- modeling_internlm.py
| |-- pytorch_model-00001-of-00008.bin
| |-- pytorch_model-00002-of-00008.bin
| |-- pytorch_model-00003-of-00008.bin
| |-- pytorch_model-00004-of-00008.bin
| |-- pytorch_model-00005-of-00008.bin
| |-- pytorch_model-00006-of-00008.bin
| |-- pytorch_model-00007-of-00008.bin
| |-- pytorch_model-00008-of-00008.bin
| |-- pytorch_model.bin.index.json
| |-- special_tokens_map.json
| |-- tokenization_internlm.py
| |-- tokenizer.model
| `-- tokenizer_config.json
|-- internlm_chat_7b_qlora_oasst1_e3_copy.py
`-- openassistant-guanaco
|-- openassistant_best_replies_eval.jsonl
`-- openassistant_best_replies_train.jsonl
修改其中的模型和数据集为 本地路径
cd ~/ft-oasst1
vim internlm_chat_7b_qlora_oasst1_e3_copy.py
减号代表要删除的行,加号代表要增加的行。
# 修改模型为本地路径
- pretrained_model_name_or_path = 'internlm/internlm-chat-7b'
+ pretrained_model_name_or_path = './internlm-chat-7b'
# 修改训练数据集为本地路径
- data_path = 'timdettmers/openassistant-guanaco'
+ data_path = './openassistant-guanaco'
常用超参
参数名 | 解释 |
---|---|
data_path | 数据路径或 HuggingFace 仓库名 |
max_length | 单条数据最大 Token 数,超过则截断 |
pack_to_max_length | 是否将多条短数据拼接到 max_length,提高 GPU 利用率 |
accumulative_counts | 梯度累积,每多少次 backward 更新一次参数 |
evaluation_inputs | 训练过程中,会根据给定的问题进行推理,便于观测训练状态 |
evaluation_freq | Evaluation 的评测间隔 iter 数 |
...... | ...... |
训练:xtuner train ${CONFIG_NAME_OR_PATH},也可以增加 deepspeed 进行训练加速:
xtuner train ${CONFIG_NAME_OR_PATH} --deepspeed deepspeed_zero2
例如,我们可以利用 QLoRA 算法在 oasst1 数据集上微调 InternLM-7B:
# 单卡
## 用刚才改好的config文件训练
xtuner train ./internlm_chat_7b_qlora_oasst1_e3_copy.py
# 多卡
NPROC_PER_NODE=${GPU_NUM} xtuner train ./internlm_chat_7b_qlora_oasst1_e3_copy.py
# 若要开启 deepspeed 加速,增加 --deepspeed deepspeed_zero2 即可
微调得到的 PTH 模型文件和其他杂七杂八的文件都默认在当前的
./work_dirs
中。
炼丹两个多小时......跑完训练后,当前路径应该长这样:
|-- internlm-chat-7b
|-- internlm_chat_7b_qlora_oasst1_e3_copy.py
|-- openassistant-guanaco
| |-- openassistant_best_replies_eval.jsonl
| `-- openassistant_best_replies_train.jsonl
`-- work_dirs
`-- internlm_chat_7b_qlora_oasst1_e3_copy
|-- 20231101_152923
| |-- 20231101_152923.log
| `-- vis_data
| |-- 20231101_152923.json
| |-- config.py
| `-- scalars.json
|-- epoch_1.pth
|-- epoch_2.pth
|-- epoch_3.pth
|-- internlm_chat_7b_qlora_oasst1_e3_copy.py
`-- last_checkpoint
即:生成 Adapter 文件夹
xtuner convert pth_to_hf ${CONFIG_NAME_OR_PATH} ${PTH_file_dir} ${SAVE_PATH}
在本示例中,为:
mkdir hf
export MKL_SERVICE_FORCE_INTEL=1
xtuner convert pth_to_hf ./internlm_chat_7b_qlora_oasst1_e3_copy.py ./work_dirs/internlm_chat_7b_qlora_oasst1_e3_copy/epoch_3.pth ./hf
|-- internlm-chat-7b
|-- internlm_chat_7b_qlora_oasst1_e3_copy.py
|-- openassistant-guanaco
| |-- openassistant_best_replies_eval.jsonl
| `-- openassistant_best_replies_train.jsonl
|-- hf
| |-- README.md
| |-- adapter_config.json
| |-- adapter_model.bin
| `-- xtuner_config.py
`-- work_dirs
`-- internlm_chat_7b_qlora_oasst1_e3_copy
|-- 20231101_152923
| |-- 20231101_152923.log
| `-- vis_data
| |-- 20231101_152923.json
| |-- config.py
| `-- scalars.json
|-- epoch_1.pth
|-- epoch_2.pth
|-- epoch_3.pth
|-- internlm_chat_7b_qlora_oasst1_e3_copy.py
`-- last_checkpoint
hf 文件夹即为我们平时所理解的所谓 “LoRA 模型文件”,LoRA 模型文件 = Adapter
使用 InternStudio 的同学换至少
A100*1
的机器
# 加载 Adapter 模型对话
xtuner chat ./internlm-chat-7b --adapter ./hf --prompt-template internlm_chat
# 与原模型对话(Float 16)
# xtuner chat ./internlm-chat-7b --prompt-template internlm_chat
# 与原模型对话(4 bit)
# xtuner chat ./internlm-chat-7b --bits 4 --prompt-template internlm_chat
效果:
xtuner chat
的启动参数
启动参数 | 功能 |
---|---|
--prompt-template | 指定对话模板 |
--system | 指定SYSTEM文本 |
--system-template | 指定SYSTEM模板 |
--bits | LLM位数 |
--bot-name | bot名称 |
--with-plugins | 指定要使用的插件 |
--no-streamer | 是否启用流式传输 |
--lagent | 是否使用lagent |
--command-stop-word | 命令停止词 |
--answer-stop-word | 回答停止词 |
--offload-folder | 存放模型权重的文件夹(或者已经卸载模型权重的文件夹) |
--max-new-tokens | 生成文本中允许的最大 token 数量 |
--temperature | 温度值 |
--top-k | 保留用于顶k筛选的最高概率词汇标记数 |
--top-p | 如果设置为小于1的浮点数,仅保留概率相加高于 top_p 的最小一组最有可能的标记 |
--seed | 用于可重现文本生成的随机种子 |
自定义微调
基于 InternLM-chat-7B 模型,用 MedQA 数据集进行微调,将其往医学问答
领域对齐。
问题 | 答案 |
---|---|
What are ketorolac eye drops?(什么是酮咯酸滴眼液?) | Ophthalmic ketorolac is used to treat itchy eyes caused by allergies. It also is used to treat swelling and redness (inflammation) that can occur after cataract surgery. Ketorolac is in a class of medications called nonsteroidal anti-inflammatory drugs (NSAIDs). It works by stopping the release of substances that cause allergy symptoms and inflammation. |
What medicines raise blood sugar? (什么药物会升高血糖?) | Some medicines for conditions other than diabetes can raise your blood sugar level. This is a concern when you have diabetes. Make sure every doctor you see knows about all of the medicines, vitamins, or herbal supplements you take. This means anything you take with or without a prescription. Examples include: Barbiturates. Thiazide diuretics. Corticosteroids. Birth control pills (oral contraceptives) and progesterone. Catecholamines. Decongestants that contain beta-adrenergic agents, such as pseudoephedrine. The B vitamin niacin. The risk of high blood sugar from niacin lowers after you have taken it for a few months. The antipsychotic medicine olanzapine (Zyprexa). |
以 Medication QA 数据集为例
原格式:(.xlsx)
问题 | 药物类型 | 问题类型 | 回答 | 主题 | URL |
---|---|---|---|---|---|
aaa | bbb | ccc | ddd | eee | fff |
3.2.1 将数据转为 XTuner 的数据格式
[{
"conversation":[
{
"system": "xxx",
"input": "xxx",
"output": "xxx"
}
]
},
{
"conversation":[
{
"system": "xxx",
"input": "xxx",
"output": "xxx"
}
]
}]
将 .xlsx
中的 问题 和 回答 两列 提取出来,再放入 .jsonL
文件的每个 conversation 的 input 和 output 中。
这一步的 python 脚本可以请 ChatGPT 来完成。
Write a python file for me. using openpyxl. input file name is MedQA2019.xlsx
Step1: The input file is .xlsx. Exact the column A and column D in the sheet named "DrugQA" .
Step2: Put each value in column A into each "input" of each "conversation". Put each value in column D into each "output" of each "conversation".
Step3: The output file is .jsonL. It looks like:
[{
"conversation":[
{
"system": "xxx",
"input": "xxx",
"output": "xxx"
}
]
},
{
"conversation":[
{
"system": "xxx",
"input": "xxx",
"output": "xxx"
}
]
}]
Step4: All "system" value changes to "You are a professional, highly experienced doctor professor. You always provide accurate, comprehensive, and detailed answers based on the patients' questions."
执行 python 脚本,获得格式化后的数据集:
python xlsx2jsonl.py
格式化后的数据集长这样:
my .jsonL file looks like:
[{
"conversation":[
{
"system": "xxx",
"input": "xxx",
"output": "xxx"
}
]
},
{
"conversation":[
{
"system": "xxx",
"input": "xxx",
"output": "xxx"
}
]
}]
Step1, read the .jsonL file.
Step2, count the amount of the "conversation" elements.
Step3, randomly split all "conversation" elements by 7:3. Targeted structure is same as the input.
Step4, save the 7/10 part as train.jsonl. save the 3/10 part as test.jsonl
此时,我们重新建一个文件夹来玩“微调自定义数据集”
mkdir ~/ft-medqa && cd ~/ft-medqa
把前面下载好的internlm-chat-7b模型文件夹拷贝过来。
cp -r ~/ft-oasst1/internlm-chat-7b .
把自定义数据集.jsonL
传到服务器上。
# 复制配置文件到当前目录
xtuner copy-cfg internlm_chat_7b_qlora_oasst1_e3 .
# 改个文件名
mv internlm_chat_7b_qlora_oasst1_e3_copy.py internlm_chat_7b_qlora_medqa2019_e3.py
# 修改配置文件内容
vim internlm_chat_7b_qlora_medqa2019_e3.py
# 修改import部分
- from xtuner.dataset.map_fns import oasst1_map_fn, template_map_fn_factory
+ from xtuner.dataset.map_fns import template_map_fn_factory
# 修改模型为本地路径
- pretrained_model_name_or_path = 'internlm/internlm-chat-7b'
+ pretrained_model_name_or_path = './internlm-chat-7b'
# 修改训练数据为 MedQA2019-structured-train.jsonl 路径
- data_path = 'timdettmers/openassistant-guanaco'
+ data_path = './MedQA2019/MedQA2019-structured-train.jsonl'
# 修改 train_dataset 对象
train_dataset = dict(
type=process_hf_dataset,
- dataset=dict(type=load_dataset, path=data_path),
+ dataset=dict(type=load_dataset, path='json', data_files=dict(train=data_path)),
tokenizer=tokenizer,
max_length=max_length,
- dataset_map_fn=alpaca_map_fn,
+ dataset_map_fn=None,
template_map_fn=dict(
type=template_map_fn_factory, template=prompt_template),
remove_unused_columns=True,
shuffle_before_pack=True,
pack_to_max_length=pack_to_max_length)
xtuner train internlm_chat_7b_qlora_medqa2019_e3.py
用 MS-Agent 数据集赋予 LLM Agent 能力
MSAgent 数据集每条样本包含一个对话列表(conversations),其里面包含了 system、user、assistant 三种字段。其中:
xtuner 是从国内的 ModelScope 平台下载 MS-Agent 数据集,因此不用提前手动下载数据集文件。
# 准备工作
mkdir ~/ft-msagent && cd ~/ft-msagent
cp -r ~/ft-oasst1/internlm-chat-7b .
# 查看配置文件
xtuner list-cfg | grep msagent
# 复制配置文件到当前目录
xtuner copy-cfg internlm_7b_qlora_msagent_react_e3_gpu8 .
# 修改配置文件中的模型为本地路径
vim ./internlm_7b_qlora_msagent_react_e3_gpu8_copy.py
- pretrained_model_name_or_path = 'internlm/internlm-chat-7b'
+ pretrained_model_name_or_path = './internlm-chat-7b'
xtuner train ./internlm_7b_qlora_msagent_react_e3_gpu8_copy.py --deepspeed deepspeed_zero2
msagent 的训练非常费时,目录应该长这样:
有了这个在 msagent 上训练得到的Adapter,模型现在已经有 agent 能力了!就可以加 --lagent 以调用来自 lagent 的代理功能了!
开始 chat 之前,还要加个 serper 的环境变量:
去 serper.dev 免费注册一个账号,生成自己的 api key。
添加 serper api key 到环境变量:
export SERPER_API_KEY=abcdefg
xtuner + agent,启动!
xtuner chat ./internlm-chat-7b --adapter internlm-7b-qlora-msagent-react --lagent
今天的分享到此为止,谢谢大家!
PS:炼丹真累。