环境配置与数据准备
本节中,我们将演示如何安装 XTuner。 推荐使用 Python-3.10 的 conda 虚拟环境安装 XTuner。
步骤 0. 使用 conda 先构建一个 Python-3.10 的虚拟环境
cd ~ #git clone 本repo git clone https://github.com/InternLM/Tutorial.git -b camp4 mkdir -p /root/finetune && cd /root/finetune conda create -n xtuner-env python=3.10 -y conda activate xtuner-env
1. cd ~
- 解释: 这个命令将当前工作目录更改为用户的主目录(在Linux系统中通常是
/root
对于root用户或/home/username
对于普通用户)。这一步确保了接下来的操作将在主目录下进行。
2. git clone https://github.com/InternLM/Tutorial.git -b camp4
- 解释: 使用
git clone
命令从GitHub上复制指定的仓库到本地计算机。这里是从GitHub - InternLM/Tutorial: LLM&VLM Tutorial地址克隆仓库,并且通过-b camp4
参数指定了要检出的分支为camp4
。这意味着只会下载camp4
这个特定分支的内容。
3. mkdir -p /root/finetune && cd /root/finetune
- 解释:
mkdir -p /root/finetune
: 创建一个新的目录/root/finetune
。如果该目录已经存在,则不会报错也不会覆盖现有目录(这就是-p
选项的作用)。&&
: 在shell命令中,&&
用于连接两个命令,只有当第一个命令成功执行后才会执行第二个命令。cd /root/finetune
: 将当前工作目录切换到刚刚创建的/root/finetune
目录。
4. conda create -n xtuner-env python=3.10 -y
- 解释: 使用Conda创建一个新的虚拟环境,名为
xtuner-env
,并指定Python版本为3.10。-y
选项自动确认所有提示,默认同意安装过程中提出的所有问题。
5. conda activate xtuner-env
- 解释: 激活之前创建的名为
xtuner-env
的Conda虚拟环境。激活环境后,所有后续的Python命令都将使用这个环境中配置的Python版本和包。
综上所述,这段脚本的主要目的是:
- 克隆特定的GitHub仓库。
- 在
/root
下创建一个新的目录finetune
,用于存放与微调相关的文件或数据。 - 创建并激活一个专门的Python虚拟环境
xtuner-env
,其中配置了Python 3.10版本,适合于特定项目的需求,比如微调语言模型等任务。这种做法有助于隔离项目的依赖关系,避免不同项目之间的库冲突。
步骤 1. 安装 XTuner
此处推荐用我 freeze 的 requirements.txt,更多的安装方法请回到前面看 XTuner 文档
cd /root/Tutorial/docs/L1/XTuner pip install -r requirements.txt
验证安装
为了验证 XTuner 是否安装正确,我们将使用命令打印配置文件。
打印配置文件: 在命令行中使用 xtuner list-cfg
验证是否能打印配置文件列表。
xtuner list-cfg
输出没有报错则为此结果
注意:上面的这个安装步骤是书生文档中的,如果直接用会有问题,如下图所示,所以我们应该按照我下面给的这个步骤来做,这个步骤来自XTuner的安装文档
安装
本节中,我们将演示如何安装 XTuner。
最佳实践
我们推荐用户参照我们的最佳实践安装 XTuner。 推荐使用 Python-3.10 的 conda 虚拟环境安装 XTuner。
步骤 0. 使用 conda 先构建一个 Python-3.10 的虚拟环境
$ conda create --name xtuner-env python=3.10 -y $ conda activate xtuner-env
步骤 1. 安装 XTuner
方案a: 通过 pip 直接安装
$ pip install -U 'xtuner[deepspeed]'
方案b: 从源码安装(我用的这个)
$ git clone https://github.com/InternLM/xtuner.git $ cd xtuner $ pip install -e '.[deepspeed]'#这一步特别慢,耐心等待
备注
“-e” 表示在可编辑模式下安装项目,因此对代码所做的任何本地修改都会生效
验证
为了验证 XTuner 是否安装正确,我们将使用命令打印配置文件。
打印配置文件: 在命令行中使用 xtuner list-cfg
验证是否能打印配置文件列表。
$ xtuner list-cfg #也需要等待一下结果
输出内容为 XTuner 支持微调的模型
修改提供的数据
步骤 0. 创建一个新的文件夹用于存储微调数据
mkdir -p /root/finetune/data && cd /root/finetune/data cp -r /root/Tutorial/data/assistant_Tuner.jsonl /root/finetune/data
在这我遇到一个这样的问题然后我强制删除,重新克隆了一下,问题解决,注意位置
rm -rf Tutorial
git clone https://github.com/InternLM/Tutorial.git -b camp4
注意: 使用 rm -rf
命令会永久删除指定目录及其所有内容,请确保你不再需要该目录下的任何数据。
此时 `finetune` 文件夹下应该有如下结构
步骤 1. 创建修改脚本
我们写一个脚本生成修改我们需要的微调训练数据,在当前目录下创建一个 change_script.py
文件,内容如下:
# 创建 `change_script.py` 文件 touch /root/finetune/data/change_script.py
打开该change_script.py
文件后将下面的内容复制进去。
import json import argparse from tqdm import tqdm def process_line(line, old_text, new_text): # 解析 JSON 行 data = json.loads(line) # 递归函数来处理嵌套的字典和列表 def replace_text(obj): if isinstance(obj, dict): return {k: replace_text(v) for k, v in obj.items()} elif isinstance(obj, list): return [replace_text(item) for item in obj] elif isinstance(obj, str): return obj.replace(old_text, new_text) else: return obj # 处理整个 JSON 对象 processed_data = replace_text(data) # 将处理后的对象转回 JSON 字符串 return json.dumps(processed_data, ensure_ascii=False) def main(input_file, output_file, old_text, new_text): with open(input_file, 'r', encoding='utf-8') as infile, \ open(output_file, 'w', encoding='utf-8') as outfile: # 计算总行数用于进度条 total_lines = sum(1 for _ in infile) infile.seek(0) # 重置文件指针到开头 # 使用 tqdm 创建进度条 for line in tqdm(infile, total=total_lines, desc="Processing"): processed_line = process_line(line.strip(), old_text, new_text) outfile.write(processed_line + '\n') if __name__ == "__main__": parser = argparse.ArgumentParser(description="Replace text in a JSONL file.") parser.add_argument("input_file", help="Input JSONL file to process") parser.add_argument("output_file", help="Output file for processed JSONL") parser.add_argument("--old_text", default="尖米", help="Text to be replaced") parser.add_argument("--new_text", default="闻星", help="Text to replace with") args = parser.parse_args() main(args.input_file, args.output_file, args.old_text, args.new_text)
然后修改如下: 打开 change_script.py
,修改 --new_text
中 default="闻星"
为你的名字。
if __name__ == "__main__": parser = argparse.ArgumentParser(description="Replace text in a JSONL file.") parser.add_argument("input_file", help="Input JSONL file to process") parser.add_argument("output_file", help="Output file for processed JSONL") parser.add_argument("--old_text", default="尖米", help="Text to be replaced") - parser.add_argument("--new_text", default="闻星", help="Text to replace with") + parser.add_argument("--new_text", default="你的名字", help="Text to replace with") args = parser.parse_args()
#修改完成后保存一下,不然算作没有修改 运行没有反应
步骤 2. 执行脚本
# usage:python change_script.py {input_file.jsonl} {output_file.jsonl} cd ~/finetune/data python change_script.py ./assistant_Tuner.jsonl ./assistant_Tuner_change.jsonl#注意一定要保存一,不然相当于没有修改,运行这句程序就没有反应
-
python change_script.py ./assistant_Tuner.jsonl ./assistant_Tuner_change.jsonl
:- 使用Python执行
change_script.py
脚本。 ./assistant_Tuner.jsonl
是作为输入文件的路径,它应该是一个JSON Lines格式的文件,通常每行包含一个有效的JSON对象。./assistant_Tuner_change.jsonl
是输出文件的路径,经过change_script.py
脚本处理后的数据将会写入此文件。
- 使用Python执行
assistant_Tuner_change.jsonl
是修改后符合 XTuner 格式的训练数据。
此时 data 文件夹下应该有如下结构
步骤 3. 查看数据
cat assistant_Tuner_change.jsonl | head -n 3
-
cat assistant_Tuner_change.jsonl
cat
是一个标准的Unix命令,用来显示文件的内容。当你使用cat
加上一个文件名作为参数时,它会输出该文件的所有内容到标准输出(通常是终端屏幕)。- 在这里,
assistant_Tuner_change.jsonl
是你想要查看内容的目标文件。.jsonl
表示这是一个JSON Lines格式的文件,意味着每行都是独立的、有效的JSON对象。
-
|
(管道符号)- 管道符 (
|
) 用于将一个命令的输出作为另一个命令的输入。在这个例子中,cat
命令的输出(即assistant_Tuner_change.jsonl
文件的内容)被传递给下一个命令head
。
- 管道符 (
-
head -n 3
head
是一个用于显示文件开头部分的命令,默认情况下它会显示文件的前10行。-n 3
参数指定了要显示的行数,在这里是前3行。因此,结合前面的cat
命令和管道符,整个命令的作用是仅显示assistant_Tuner_change.jsonl
文件的前3行内容。
此处结果太长不再展示,主要是检查自己要修改的名字是否在数据中。
训练启动
步骤 0. 复制模型
在InternStudio开发机中的已经提供了微调模型,可以直接软链接即可。
本模型位于/root/share/new_models/Shanghai_AI_Laboratory/internlm2_5-7b-chat
mkdir /root/finetune/models ln -s /root/share/new_models/Shanghai_AI_Laboratory/internlm2_5-7b-chat /root/finetune/models/internlm2_5-7b-chat
步骤 1. 修改 Config
获取官方写好的 config
# cd {path/to/finetune} cd /root/finetune mkdir ./config cd config xtuner copy-cfg internlm2_5_chat_7b_qlora_alpaca_e3 ./
修改以下几行
####################################################################### # PART 1 Settings # ####################################################################### - pretrained_model_name_or_path = 'internlm/internlm2_5-7b-chat' + pretrained_model_name_or_path = '/root/finetune/models/internlm2_5-7b-chat' - alpaca_en_path = 'tatsu-lab/alpaca' + alpaca_en_path = '/root/finetune/data/assistant_Tuner_change.jsonl' evaluation_inputs = [ - '请给我介绍五个上海的景点', 'Please tell me five scenic spots in Shanghai' + '请介绍一下你自己', 'Please introduce yourself' ] ####################################################################### # PART 3 Dataset & Dataloader # ####################################################################### alpaca_en = dict( type=process_hf_dataset, - dataset=dict(type=load_dataset, path=alpaca_en_path), + dataset=dict(type=load_dataset, path='json', data_files=dict(train=alpaca_en_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, use_varlen_attn=use_varlen_attn)
除此之外,我们还可以对一些重要的参数进行调整,包括学习率(lr)、训练的轮数(max_epochs)等等。
本教程已经将改好的 config 放在了 ~/Tutorial/configs/internlm2_5_chat_7b_qlora_alpaca_e3_copy.py
同学们可以直接使用(前置步骤路径一致的情况下)
步骤 2. 启动微调
完成了所有的准备工作后,我们就可以正式的开始我们下一阶段的旅程:XTuner 启动~!
当我们准备好了所有内容,我们只需要将使用 xtuner train
命令令即可开始训练。
xtuner train
命令用于启动模型微调进程。该命令需要一个参数:CONFIG
用于指定微调配置文件。这里我们使用修改好的配置文件internlm2_5_chat_7b_qlora_alpaca_e3_copy.py
。
训练过程中产生的所有文件,包括日志、配置文件、检查点文件、微调后的模型等,默认保存在work_dirs
目录下,我们也可以通过添加--work-dir
指定特定的文件保存位置。--deepspeed
则为使用 deepspeed, deepspeed 可以节约显存。
运行命令进行微调
cd /root/finetune conda activate xtuner-env xtuner train ./config/internlm2_5_chat_7b_qlora_alpaca_e3_copy.py --deepspeed deepspeed_zero2 --work-dir ./work_dirs/assistTuner#会报下面的错 pip install protobuf就好了,需要等挺久的
下面是正确的运行结果(800轮,训练完成后会保存pth,在进行后面的步骤)
步骤 3. 权重转换
模型转换的本质其实就是将原本使用 Pytorch 训练出来的模型权重文件转换为目前通用的 HuggingFace 格式文件,那么我们可以通过以下命令来实现一键转换。
我们可以使用 xtuner convert pth_to_hf
命令来进行模型格式转换。
xtuner convert pth_to_hf
命令用于进行模型格式转换。该命令需要三个参数:CONFIG
表示微调的配置文件,PATH_TO_PTH_MODEL
表示微调的模型权重文件路径,即要转换的模型权重,SAVE_PATH_TO_HF_MODEL
表示转换后的 HuggingFace 格式文件的保存路径。
除此之外,我们其实还可以在转换的命令中添加几个额外的参数,包括:
参数名 | 解释 |
---|---|
--fp32 | 代表以fp32的精度开启,假如不输入则默认为fp16 |
--max-shard-size {GB} | 代表每个权重文件最大的大小(默认为2GB) |
cd /root/finetune/work_dirs/assistTuner conda activate xtuner-env # 先获取最后保存的一个pth文件 pth_file=`ls -t /root/finetune/work_dirs/assistTuner/*.pth | head -n 1 | sed 's/:$//'` export MKL_SERVICE_FORCE_INTEL=1 export MKL_THREADING_LAYER=GNU xtuner convert pth_to_hf ./internlm2_5_chat_7b_qlora_alpaca_e3_copy.py ${pth_file} ./hf
模型格式转换完成后,我们的目录结构应该是这样子的。
目录结构
转换完成后,可以看到模型被转换为 HuggingFace 中常用的 .bin 格式文件,这就代表着文件成功被转化为 HuggingFace 格式了。
此时,hf 文件夹即为我们平时所理解的所谓 “LoRA 模型文件”
可以简单理解:LoRA 模型文件 = Adapter
步骤 4. 模型合并
对于 LoRA 或者 QLoRA 微调出来的模型其实并不是一个完整的模型,而是一个额外的层(Adapter),训练完的这个层最终还是要与原模型进行合并才能被正常的使用。
对于全量微调的模型(full)其实是不需要进行整合这一步的,因为全量微调修改的是原模型的权重而非微调一个新的 Adapter ,因此是不需要进行模型整合的。
在 XTuner 中提供了一键合并的命令 xtuner convert merge
,在使用前我们需要准备好三个路径,包括原模型的路径、训练好的 Adapter 层的(模型格式转换后的)路径以及最终保存的路径。
xtuner convert merge
命令用于合并模型。该命令需要三个参数:LLM
表示原模型路径,ADAPTER
表示 Adapter 层的路径,SAVE_PATH
表示合并后的模型最终的保存路径。
在模型合并这一步还有其他很多的可选参数,包括:
参数名 | 解释 |
---|---|
--max-shard-size {GB} | 代表每个权重文件最大的大小(默认为2GB) |
--device {device_name} | 这里指的就是device的名称,可选择的有cuda、cpu和auto,默认为cuda即使用gpu进行运算 |
--is-clip | 这个参数主要用于确定模型是不是CLIP模型,假如是的话就要加上,不是就不需要添加 |
cd /root/finetune/work_dirs/assistTuner conda activate xtuner-env export MKL_SERVICE_FORCE_INTEL=1 export MKL_THREADING_LAYER=GNU xtuner convert merge /root/finetune/models/internlm2_5-7b-chat ./hf ./merged --max-shard-size 2GB
模型合并完成后,我们的目录结构应该是这样子的。
在模型合并完成后,我们就可以看到最终的模型和原模型文件夹非常相似,包括了分词器、权重文件、配置信息等等。
模型 WebUI 对话
微调完成后,我们可以再次运行 xtuner_streamlit_demo.py
脚本来观察微调后的对话效果,不过在运行之前,我们需要将脚本中的模型路径修改为微调后的模型的路径。
cd ~/Tutorial/tools/L1_XTuner_code
xtuner_streamlit_demo.py这个文件中
# 直接修改脚本文件第18行
- model_name_or_path = "Shanghai_AI_Laboratory/internlm2_5-7b-chat"
+ model_name_or_path = "/root/finetune/work_dirs/assistTuner/merged"
然后,我们可以直接启动应用。
conda activate xtuner-env pip install streamlit==1.31.0 streamlit run /root/Tutorial/tools/L1_XTuner_code/xtuner_streamlit_demo.py
运行后,确保端口映射正常,如果映射已断开则需要重新做一次端口映射。
ssh -CNg -L 8501:127.0.0.1:8501 root@ssh.intern-ai.org.cn -p *****#这一步我没有用