前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >XTuner 微调

XTuner 微调

原创
作者头像
用户10497140
修改2024-10-10 20:54:32
930
修改2024-10-10 20:54:32

创建一个虚拟环境。使用Anaconda创建一个名为xtuner03的虚拟环境,可以直接执行命令

代码语言:python
代码运行次数:0
复制
conda activate base
# 创建虚拟环境
conda create -n xtuner03 python=3.10 -y

# 激活虚拟环境(注意:后续的所有操作都需要在这个虚拟环境中进行)
conda activate xtuner03
# 安装一些必要的库
conda install pytorch==2.1.2 torchvision==0.16.2 torchaudio==2.1.2 pytorch-cuda=12.1 -c pytorch -c nvidia -y
# 安装其他依赖
pip install transformers==4.39.3
pip install streamlit==1.36.0

2.3 安装 XTuner

虚拟环境创建完成后,就可以安装 XTuner 了。首先,从 Github 上下载源码。

代码语言:python
代码运行次数:0
复制
# 创建一个目录,用来存放源代码
mkdir -p /root/InternLM/code

cd /root/InternLM/code

git clone -b v0.1.23  https://github.com/InternLM/XTuner /root/InternLM/code/XTuner

进入源码目录,执行安装。

代码语言:python
代码运行次数:0
复制
# 进入到源码目录
cd /root/InternLM/code/XTuner
conda activate xtuner03

# 执行安装
pip install -e '.[deepspeed]' -i https://mirrors.aliyun.com/pypi/simple/
# 解决pybind11>=2.12版本冲突
pip install NumPy==1.26.4   

验证一下安装结果。

代码语言:python
代码运行次数:0
复制
xtuner version

10/06 12:01:58 - mmengine - INFO - 0.1.23

通过 xtuner help 熟悉 XTuner 的用法

模型准备

InternLM 推出的 7B 模型来完成此次微调演示,可以通过 HuggingFace、OpenXLab 或者 Modelscope 进行模型的下载

代码语言:python
代码运行次数:0
复制
# 创建一个目录,用来存放微调的所有资料,后续的所有操作都在该路径中进行
mkdir -p /root/InternLM/XTuner

cd /root/InternLM/XTuner

mkdir -p Shanghai_AI_Laboratory

ln -s /root/share/new_models/Shanghai_AI_Laboratory/internlm2_5-20b-chat Shanghai_AI_Laboratory/internlm2_5-20b-chat

执行上述操作后,Shanghai_AI_Laboratory/internlm2-chat- 将直接成为一个符号链接,这个链接指向 /root/share/new_models/Shanghai_AI_Laboratory/internlm2-chat-1_8b 的位置。

这意味着,当我们访问 Shanghai_AI_Laboratory/internlm2-chat-1_8b 时,实际上就是在访问 /root/share/new_models/Shanghai_AI_Laboratory/internlm2-chat-1_8b 目录下的内容。通过这种方式,我们无需复制任何数据,就可以直接利用现有的模型文件进行后续的微调操作,从而节省存储空间并简化文件管理。

模型文件准备好后,我们可以使用tree命令来观察目录结构。

代码语言:python
代码运行次数:0
复制
apt-get install -y tree

tree -l

目录结构

代码语言:python
代码运行次数:0
复制
`-- Shanghai_AI_Laboratory
    `-- internlm2_5-20b-chat -> /root/share/new_models/Shanghai_AI_Laboratory/internlm2_5-20b-chat
        |-- README.md
        |-- config.json
        |-- configuration.json
        |-- configuration_internlm2.py
        |-- generation_config.json
        |-- model-00001-of-00021.safetensors
        |-- model-00002-of-00021.safetensors
        |-- model-00003-of-00021.safetensors
        |-- model-00004-of-00021.safetensors
        |-- model-00005-of-00021.safetensors
        |-- model-00006-of-00021.safetensors
        |-- model-00007-of-00021.safetensors
        |-- model-00008-of-00021.safetensors
        |-- model-00009-of-00021.safetensors
        |-- model-00010-of-00021.safetensors
        |-- model-00011-of-00021.safetensors
        |-- model-00012-of-00021.safetensors
        |-- model-00013-of-00021.safetensors
        |-- model-00014-of-00021.safetensors
        |-- model-00015-of-00021.safetensors
        |-- model-00016-of-00021.safetensors
        |-- model-00017-of-00021.safetensors
        |-- model-00018-of-00021.safetensors
        |-- model-00019-of-00021.safetensors
        |-- model-00020-of-00021.safetensors
        |-- model-00021-of-00021.safetensors
        |-- model.safetensors.index.json
        |-- modeling_internlm2.py
        |-- special_tokens_map.json
        |-- tokenization_internlm2.py
        |-- tokenization_internlm2_fast.py
        |-- tokenizer.model
        `-- tokenizer_config.json

2 directories, 33 files

在目录结构中可以看出,internlm2_5-20b-chat 是一个符号链接。

快速开始

这里我们用 internlm2_5-20b-chat 模型,通过 QLoRA 的方式来微调一个自己的小助手认知作为案例来进行演示。

指令跟随微调

代码语言:python
代码运行次数:0
复制
PATTERN: internlm2
-------------------------------
internlm2_1_8b_full_alpaca_e3
internlm2_1_8b_full_custom_pretrain_e1
internlm2_1_8b_qlora_alpaca_e3
internlm2_20b_full_custom_pretrain_e1
internlm2_20b_full_finetune_custom_dataset_e1
internlm2_20b_qlora_alpaca_e3
internlm2_20b_qlora_arxiv_gentitle_e3
internlm2_20b_qlora_code_alpaca_e3
internlm2_20b_qlora_colorist_e5
internlm2_20b_qlora_lawyer_e3
internlm2_20b_qlora_msagent_react_e3_gpu8
internlm2_20b_qlora_oasst1_512_e3
internlm2_20b_qlora_oasst1_e3
internlm2_20b_qlora_sql_e3
internlm2_5_chat_7b_full_finetune_custom_dataset_e1
internlm2_5_chat_7b_qlora_alpaca_e3
internlm2_5_chat_7b_qlora_oasst1_e3
internlm2_7b_full_custom_pretrain_e1
internlm2_7b_full_finetune_custom_dataset_e1
internlm2_7b_full_finetune_custom_dataset_e1_sequence_parallel_4
internlm2_7b_qlora_alpaca_e3
internlm2_7b_qlora_arxiv_gentitle_e3
internlm2_7b_qlora_code_alpaca_e3
internlm2_7b_qlora_colorist_e5
internlm2_7b_qlora_json_e3
internlm2_7b_qlora_lawyer_e3
internlm2_7b_qlora_msagent_react_e3_gpu8
internlm2_7b_qlora_oasst1_512_e3
internlm2_7b_qlora_oasst1_e3
internlm2_7b_qlora_sql_e3
internlm2_7b_w_internevo_dataset
internlm2_7b_w_tokenized_dataset
internlm2_7b_w_untokenized_dataset
internlm2_chat_1_8b_dpo_full
internlm2_chat_1_8b_dpo_full_varlenattn
internlm2_chat_1_8b_dpo_full_varlenattn_jsonl_dataset
internlm2_chat_1_8b_full_alpaca_e3
internlm2_chat_1_8b_orpo_full
internlm2_chat_1_8b_orpo_full_varlenattn
internlm2_chat_1_8b_orpo_full_varlenattn_jsonl_dataset
internlm2_chat_1_8b_qlora_alpaca_e3
internlm2_chat_1_8b_qlora_custom_sft_e1
internlm2_chat_1_8b_reward_full_ultrafeedback
internlm2_chat_1_8b_reward_full_varlenattn_jsonl_dataset
internlm2_chat_1_8b_reward_full_varlenattn_ultrafeedback
internlm2_chat_1_8b_reward_qlora_varlenattn_ultrafeedback
internlm2_chat_20b_full_finetune_custom_dataset_e1
internlm2_chat_20b_qlora_alpaca_e3
internlm2_chat_20b_qlora_code_alpaca_e3
internlm2_chat_20b_qlora_custom_sft_e1
internlm2_chat_20b_qlora_lawyer_e3
internlm2_chat_20b_qlora_oasst1_512_e3
internlm2_chat_20b_qlora_oasst1_e3
internlm2_chat_7b_dpo_qlora_varlenattn
internlm2_chat_7b_full_finetune_custom_dataset_e1
internlm2_chat_7b_orpo_qlora_varlenattn_ultrafeedback_e5
internlm2_chat_7b_qlora_alpaca_e3
internlm2_chat_7b_qlora_code_alpaca_e3
internlm2_chat_7b_qlora_custom_sft_e1
internlm2_chat_7b_qlora_lawyer_e3
internlm2_chat_7b_qlora_oasst1_512_e3
internlm2_chat_7b_qlora_oasst1_e3
internvl_v1_5_internlm2_26b_finetune
internvl_v1_5_internlm2_26b_lora_finetune
internvl_v1_5_internlm2_26b_qlora_finetune
internvl_v1_5_internlm2_2b_finetune
internvl_v1_5_internlm2_2b_lora_finetune
internvl_v1_5_internlm2_2b_qlora_finetune
internvl_v2_internlm2_26b_finetune
internvl_v2_internlm2_26b_lora_finetune
internvl_v2_internlm2_26b_qlora_finetune
internvl_v2_internlm2_2b_finetune
internvl_v2_internlm2_2b_lora_finetune
internvl_v2_internlm2_2b_qlora_finetune
internvl_v2_internlm2_5_8b_finetune
internvl_v2_internlm2_5_8b_lora_finetune
internvl_v2_internlm2_5_8b_qlora_finetune
llava_internlm2_chat_1_8b_clip_vit_large_p14_336_e1_gpu8_pretrain
llava_internlm2_chat_1_8b_qlora_clip_vit_large_p14_336_lora_e1_gpu8_finetune
llava_internlm2_chat_20b_clip_vit_large_p14_336_e1_gpu8_finetune
llava_internlm2_chat_20b_clip_vit_large_p14_336_e1_gpu8_pretrain
llava_internlm2_chat_20b_qlora_clip_vit_large_p14_336_lora_e1_gpu8_finetune
llava_internlm2_chat_7b_clip_vit_large_p14_336_e1_gpu8_finetune
llava_internlm2_chat_7b_clip_vit_large_p14_336_e1_gpu8_pretrain
llava_internlm2_chat_7b_qlora_clip_vit_large_p14_336_lora_e1_gpu8_finetune
=============================================================

由于没有我们的需求匹配的配置文件,这里就创建该配置文件。internlm2_5_chat_20b_qlora_alpaca_e3

根据 internlm2_5_chat_7b_qlora_alpaca_e3

代码语言:python
代码运行次数:0
复制
xtuner copy-cfg internlm2_5_chat_7b_qlora_alpaca_e3 .

修改为 internlm2_5_chat_20b_qlora_alpaca_e3_copy

代码语言:python
代码运行次数:0
复制
- pretrained_model_name_or_path = 'internlm/internlm2_5-7b-chat'
+ pretrained_model_name_or_path = '/root/InternLM/XTuner/Shanghai_AI_Laboratory/internlm2_5-20b-chat'

- alpaca_en_path = 'tatsu-lab/alpaca'
+ alpaca_en_path = 'datas/assistant.json'

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)

完成了所有的准备工作后,我们就可以正式的开始我们下一阶段的旅程:XTuner 启动~!

当我们准备好了所有内容,我们只需要将使用 xtuner train 命令令即可开始训练。

xtuner train 命令用于启动模型微调进程。该命令需要一个参数:CONFIG 用于指定微调配置文件。这里我们使用修改好的配置文件 internlm2_5_chat_20b_qlora_alpaca_e3_copy.py。 训练过程中产生的所有文件,包括日志、配置文件、检查点文件、微调后的模型等,默认保存在 work_dirs 目录下,我们也可以通过添加 --work-dir 指定特定的文件保存位置。

代码语言:javascript
复制
cd /root/InternLM/XTuner
conda activate xtuner03

xtuner train ./internlm2_5_chat_20b_qlora_alpaca_e3_copy.py             (50%)

在训练完后,我们的目录结构应该是这样子的。

代码语言:txt
复制
-- work_dirs
|   `-- internlm2_5_chat_20b_qlora_alpaca_e3_copy
|       |-- 20241006_151051
|       |   |-- 20241006_151051.log
|       |   `-- vis_data
|       |       `-- config.py
|       |-- 20241006_153349
|       |   |-- 20241006_153349.log
|       |   `-- vis_data
|       |       `-- config.py
|       |-- 20241006_154531
|       |   |-- 20241006_154531.log
|       |   `-- vis_data
|       |       |-- 20241006_154531.json
|       |       |-- config.py
|       |       |-- eval_outputs_iter_1499.txt
|       |       |-- eval_outputs_iter_1535.txt
|       |       |-- eval_outputs_iter_499.txt
|       |       |-- eval_outputs_iter_999.txt
|       |       `-- scalars.json
|       |-- internlm2_5_chat_20b_qlora_alpaca_e3_copy.py
|       |-- iter_1500.pth
|       |-- iter_1536.pth
|       `-- last_checkpoint
模型格式转换

模型转换的本质其实就是将原本使用 Pytorch 训练出来的模型权重文件转换为目前通用的 HuggingFace 格式文件,那么我们可以通过以下命令来实现一键转换。

我们可以使用 xtuner convert pth_to_hf 命令来进行模型格式转换。

xtuner convert pth_to_hf 命令用于进行模型格式转换。该命令需要三个参数:CONFIG 表示微调的配置文件, PATH_TO_PTH_MODEL 表示微调的模型权重文件路径,即要转换的模型权重, SAVE_PATH_TO_HF_MODEL 表示转换后的 HuggingFace 格式文件的保存路径。

除此之外,我们其实还可以在转换的命令中添加几个额外的参数,包括:

模型格式转换

模型转换的本质其实就是将原本使用 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)

代码语言:txt
复制
cd /root/InternLM/XTuner
conda activate xtuner03

# 先获取最后保存的一个pth文件
pth_file=`ls -t ./work_dirs/internlm2_5_chat_20b_qlora_alpaca_e3_copy/*.pth | head -n 1`
export MKL_SERVICE_FORCE_INTEL=1
export MKL_THREADING_LAYER=GNU
export PYTORCH_CUDA_ALLOC_CONF=max_split_size_mb:128
xtuner convert pth_to_hf ./internlm2_5_chat_20b_qlora_alpaca_e3_copy.py ${pth_file} ./hf

目录结构

代码语言:txt
复制
-- hf
|   |-- README.md
|   |-- adapter_config.json
|   |-- adapter_model.bin
|   `-- xtuner_config.py

转换完成后,可以看到模型被转换为 HuggingFace 中常用的 .bin 格式文件,这就代表着文件成功被转化为 HuggingFace 格式了。

此时,hf 文件夹即为我们平时所理解的所谓 “LoRA 模型文件”

可以简单理解:LoRA 模型文件 = Adapter

模型合并

对于 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模型,假如是的话就要加上,不是就不需要添加

代码语言:txt
复制
cd /root/InternLM/XTuner
conda activate xtuner03

export MKL_SERVICE_FORCE_INTEL=1
export MKL_THREADING_LAYER=GNU
xtuner convert merge /root/InternLM/XTuner/Shanghai_AI_Laboratory/internlm2_5-20b-chat ./hf ./merged --max-shard-size 2GB

Merge 权重

代码语言:python
代码运行次数:0
复制
export NAME_OR_PATH_TO_LLM=/root/llm/internlm-7b
export NAME_OR_PATH_TO_ADAPTER=work_dirs/internlm_7b_qlora_alpaca_internlm_assistant/hf
export SAVE_PATH=work_dirs/internlm_7b_qlora_alpaca_internlm_assistant/hf_merge

xtuner convert merge \
    $NAME_OR_PATH_TO_LLM \
    $NAME_OR_PATH_TO_ADAPTER \
    $SAVE_PATH \
    --max-shard-size 2GB
代码语言:txt
复制
export NAME_OR_PATH_TO_LLM=/root/InternLM/XTuner/Shanghai_AI_Laboratory/internlm2_5-20b-chat
export NAME_OR_PATH_TO_ADAPTER=work_dirs/internlm2_5_chat_20b_qlora_alpaca_e3_copy

模型合并完成后,我们的目录结构应该是这样子的。

目录结构

代码语言:txt
复制

模型合并完成后,我们就可以看到最终的模型和原模型文件夹非常相似,包括了分词器、权重文件、配置信息等等

微调完成后,我们可以再次运行xtuner_streamlit_demo.py脚本来观察微调后的对话效果,不过在运行之前,我们需要将脚本中的模型路径修改为微调后的模型的路径。

代码语言:python
代码运行次数:0
复制
# 直接修改脚本文件第18行
- model_name_or_path = "/root/InternLM/XTuner/Shanghai_AI_Laboratory/internlm2-chat-1_8b"
+ model_name_or_path = "/root/InternLM/XTuner/merged"

然后,我们可以直接启动应用。

代码语言:python
代码运行次数:0
复制
conda activate xtuner03

streamlit run /root/InternLM/Tutorial/tools/xtuner_streamlit_demo.py

运行后,确保端口映射正常,如果映射已断开则需要重新做一次端口映射。

代码语言:python
代码运行次数:0
复制
ssh -CNg -L 8501:127.0.0.1:8501 root@ssh.intern-ai.org.cn -p 43551

最后,通过浏览器访问:http://127.0.0.1:8501 来进行对话了。

增量预训练微调

定义一些基本方法。

  • 导入必要的库
代码语言:python
代码运行次数:0
复制
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM
  • 定义模型加载方法
代码语言:python
代码运行次数:0
复制
def load_model(model_path):
    tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)
    model = AutoModelForCausalLM.from_pretrained(model_path, torch_dtype=torch.float16, trust_remote_code=True).cuda()
    model = model.eval()
    return tokenizer, model
  • 定义文本续写方法
代码语言:javascript
复制
def generate(user_input):
    gen_kwargs = {"max_length": 128, "top_p": 0.8, "temperature": 0.8, "do_sample": True, "repetition_penalty": 1.0}

    inputs = tokenizer([user_input], return_tensors="pt")
    for k,v in inputs.items():
        inputs[k] = v.cuda()
    output = model.generate(**inputs, **gen_kwargs)
    output = tokenizer.decode(output[0].tolist(), skip_special_tokens=True)
    return output

基座模型推理

我们先来看看基座模型的推理结果。

  • 加载模型
代码语言:javascript
复制
tokenizer, model = load_model("Shanghai_AI_Laboratory/internlm2-1_8b")
  • 文本续写
代码语言:javascript
复制
generate("书生·浦语大模型实战营第三期是")
  • 释放缓存
代码语言:javascript
复制
del tokenizer, model

torch.cuda.empty_cache()

1.2 增量预训练

我们对基座模型进行增量预训练,让模型增加新的知识。

1.2.1 准备数据文件

为了让模型学习到新的知识,我们需要将新的知识数据整理成指定格式文件,形成数据集,然后让模型来学习这些新数据。这里我们准备一个简单的皮肤科数据集 datas/pretrain.json,仅包含一条知识,然后让数据重复多次。

网上有大量的开源数据集可以供我们进行使用,有些时候我们可以在开源数据集的基础上添加一些我们自己独有的数据集,也可能会有很好的效果。

上传数据集 终端输入

代码语言:javascript
复制
 C:\\sunset\\pretrain.json root@ssh.intern-ai.org.cn:/root/InternLM/XTuner/datas

准备好数据文件后,我们的目录结构应该是这样子的。

代码语言:python
代码运行次数:0
复制
tree -l
准备配置文件

在准备好了模型和数据集后,我们就要根据我们选择的微调方法结合微调方案来找到与我们最匹配的配置文件了,从而减少我们对配置文件的修改量。

这里我们选择使用 internlm2_5_chat_7b_full_finetune_custom_dataset_e1 配置文件。

代码语言:python
代码运行次数:0
复制
xtuner copy-cfg internlm2_5_chat_7b_full_finetune_custom_dataset_e1 .  

根据项目的需求一步步的进行修改和调整吧!

在 PART 1 的部分,由于我们不再需要在 HuggingFace 上自动下载模型,因此我们先要更换模型的路径以及数据集的路径为我们本地的路径。

为了训练过程中能够实时观察到模型的变化情况,XTuner 贴心的推出了一个 evaluation_inputs 的参数来让我们能够设置多个问题来确保模型在训练过程中的变化是朝着我们想要的方向前进的。我们可以添加自己的输入。

在 PART 2 的部分,由于我们复制的配置文件是全参数微调的配置,而我们希望使用 QLoRA 算法进行微调,所以可以添加 QLoRA 算法的配置。

修改完后的完整的配置文件是

代码语言:txt
复制
# Copyright (c) OpenMMLab. All rights reserved.
"""Data format:

[
  {
      "text": "xxx"
  },
  {
      "text": "xxx"
  },
  ...
]
"""  # noqa: E501
from peft import LoraConfig
import torch

from datasets import load_dataset
from mmengine.dataset import DefaultSampler
from mmengine.hooks import (CheckpointHook, DistSamplerSeedHook, IterTimerHook,
                            LoggerHook, ParamSchedulerHook)
from mmengine.optim import AmpOptimWrapper, CosineAnnealingLR, LinearLR
from torch.optim import AdamW
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig

from xtuner.dataset import process_hf_dataset
from xtuner.dataset.collate_fns import default_collate_fn
from xtuner.dataset.map_fns import pretrain_map_fn
from xtuner.engine.hooks import (DatasetInfoHook, EvaluateChatHook,
                                 VarlenAttnArgsToMessageHubHook)
from xtuner.engine.runner import TrainLoop
from xtuner.model import SupervisedFinetune

#######################################################################
#                          PART 1  Settings                           #
#######################################################################
# Model
pretrained_model_name_or_path = '/root/InternLM/XTuner/merged'
use_varlen_attn = False

# Data
data_files = ['datas/pretrain.json']
max_length = 2048
pack_to_max_length = True

# Scheduler & Optimizer
batch_size = 1  # per_device
accumulative_counts = 16  # bs = 1 GPU * 1 batch_size_per_device * 16 acc
dataloader_num_workers = 0
max_epochs = 1
optim_type = AdamW
lr = 2e-5
betas = (0.9, 0.999)
weight_decay = 0
max_norm = 1  # grad clip
warmup_ratio = 0.03

# Save
save_steps = 500
save_total_limit = 2  # Maximum checkpoints to keep (-1 means unlimited)

# Evaluate the generation performance during the training
evaluation_freq = 500
SYSTEM = ''
evaluation_inputs = ['赵炳南在治疗皮肤病时,对于湿热壅盛、热重于湿型的患者,建议使用什么方剂加减进行治疗?', 'When Zhao Bingnan treated skin diseases, for patients with excessive dampness and heat, where heat was more severe than dampness, what prescriptions with modifications were recommended for treatment? ']

#######################################################################
#                      PART 2  Model & Tokenizer                      #
#######################################################################
tokenizer = dict(
    type=AutoTokenizer.from_pretrained,
    pretrained_model_name_or_path=pretrained_model_name_or_path,
    trust_remote_code=True,
    padding_side='right')

model = dict(
    type=SupervisedFinetune,
    use_varlen_attn=use_varlen_attn,
    llm=dict(
        type=AutoModelForCausalLM.from_pretrained,
        pretrained_model_name_or_path=pretrained_model_name_or_path,
        trust_remote_code=True,
        quantization_config=dict(
            type=BitsAndBytesConfig,
            load_in_4bit=True,
            load_in_8bit=False,
            llm_int8_threshold=6.0,
            llm_int8_has_fp16_weight=False,
            bnb_4bit_compute_dtype=torch.float16,
            bnb_4bit_use_double_quant=True,
            bnb_4bit_quant_type='nf4')
    ),
    lora=dict(
        type=LoraConfig,
        r=64,
        lora_alpha=16,
        lora_dropout=0.1,
        bias='none',
        task_type='CAUSAL_LM')
        )

#######################################################################
#                      PART 3  Dataset & Dataloader                   #
#######################################################################
train_dataset = dict(
    type=process_hf_dataset,
    dataset=dict(type=load_dataset, path='json', data_files=data_files),
    tokenizer=tokenizer,
    max_length=max_length,
    dataset_map_fn=pretrain_map_fn,
    template_map_fn=None,
    remove_unused_columns=True,
    shuffle_before_pack=False,
    pack_to_max_length=pack_to_max_length,
    use_varlen_attn=use_varlen_attn)

train_dataloader = dict(
    batch_size=batch_size,
    num_workers=dataloader_num_workers,
    dataset=train_dataset,
    sampler=dict(type=DefaultSampler, shuffle=True),
    collate_fn=dict(type=default_collate_fn, use_varlen_attn=use_varlen_attn))

#######################################################################
#                    PART 4  Scheduler & Optimizer                    #
#######################################################################
# optimizer
optim_wrapper = dict(
    type=AmpOptimWrapper,
    optimizer=dict(
        type=optim_type, lr=lr, betas=betas, weight_decay=weight_decay),
    clip_grad=dict(max_norm=max_norm, error_if_nonfinite=False),
    accumulative_counts=accumulative_counts,
    loss_scale='dynamic',
    dtype='float16')

# learning policy
# More information: https://github.com/open-mmlab/mmengine/blob/main/docs/en/tutorials/param_scheduler.md  # noqa: E501
param_scheduler = [
    dict(
        type=LinearLR,
        start_factor=1e-5,
        by_epoch=True,
        begin=0,
        end=warmup_ratio * max_epochs,
        convert_to_iter_based=True),
    dict(
        type=CosineAnnealingLR,
        eta_min=0.0,
        by_epoch=True,
        begin=warmup_ratio * max_epochs,
        end=max_epochs,
        convert_to_iter_based=True)
]

# train, val, test setting
train_cfg = dict(type=TrainLoop, max_epochs=max_epochs)

#######################################################################
#                           PART 5  Runtime                           #
#######################################################################
# Log the dialogue periodically during the training process, optional
custom_hooks = [
    dict(type=DatasetInfoHook, tokenizer=tokenizer),
    dict(
        type=EvaluateChatHook,
        tokenizer=tokenizer,
        every_n_iters=evaluation_freq,
        evaluation_inputs=evaluation_inputs,
        system=SYSTEM)
]

if use_varlen_attn:
    custom_hooks += [dict(type=VarlenAttnArgsToMessageHubHook)]

# configure default hooks
default_hooks = dict(
    # record the time of every iteration.
    timer=dict(type=IterTimerHook),
    # print log every 10 iterations.
    logger=dict(type=LoggerHook, log_metric_by_epoch=False, interval=10),
    # enable the parameter scheduler.
    param_scheduler=dict(type=ParamSchedulerHook),
    # save checkpoint per `save_steps`.
    checkpoint=dict(
        type=CheckpointHook,
        by_epoch=False,
        interval=save_steps,
        max_keep_ckpts=save_total_limit),
    # set sampler seed in distributed evrionment.
    sampler_seed=dict(type=DistSamplerSeedHook),
)

# configure environment
env_cfg = dict(
    # whether to enable cudnn benchmark
    cudnn_benchmark=False,
    # set multi process parameters
    mp_cfg=dict(mp_start_method='fork', opencv_num_threads=0),
    # set distributed parameters
    dist_cfg=dict(backend='nccl'),
)

# set visualizer
visualizer = None

# set log level
log_level = 'INFO'

# load from which checkpoint
load_from = None

# whether to resume training from the loaded checkpoint
resume = False

# Defaults to use random seed and disable `deterministic`
randomness = dict(seed=None, deterministic=False)

# set log processor
log_processor = dict(by_epoch=False)

启动微调

完成了所有的准备工作后,我们就可以正式的开始我们下一阶段的旅程:XTuner 启动~!

当我们准备好了所有内容,我们只需要将使用 xtuner train 命令令即可开始训练。

代码语言:javascript
复制
xtuner train ./internlm2_5_7b_full_custom_pretrain_e1_copy.py

在训练完后,我们的目录结构应该是这样子的。

模型格式转换

模型转换的本质其实就是将原本使用 Pytorch 训练出来的模型权重文件转换为目前通用的 HuggingFace 格式文件,那么我们可以通过以下命令来实现一键转换。

代码语言:javascript
复制
pth_file=`ls -t ./work_dirs/internlm2_5_7b_full_custom_pretrain_e1_copy/*.pth | head -n 1` && MKL_SERVICE_FORCE_INTEL=1 MKL_THREADING_LAYER=GNU xtuner convert pth_to_hf ./internlm2_1_8b_full_custom_pretrain_e1_copy.py ${pth_file} ./hf

模型格式转换完成后,我们的目录结构应该是这样子的。

代码语言:txt
复制
|-- Laboratory
|   `-- internlm2_5-7b-chat -> /root/share/new_models/Shanghai_AI_Laboratory/internlm2_5-7b-chat
|       |-- README.md
|       |-- config.json
|       |-- configuration_internlm2.py
|       |-- generation_config.json
|       |-- model-00001-of-00008.safetensors
|       |-- model-00002-of-00008.safetensors
|       |-- model-00003-of-00008.safetensors
|       |-- model-00004-of-00008.safetensors
|       |-- model-00005-of-00008.safetensors
|       |-- model-00006-of-00008.safetensors
|       |-- model-00007-of-00008.safetensors
|       |-- model-00008-of-00008.safetensors
|       |-- model.safetensors.index.json
|       |-- modeling_internlm2.py
|       |-- special_tokens_map.json
|       |-- tokenization_internlm2.py
|       |-- tokenization_internlm2_fast.py
|       |-- tokenizer.model
|       `-- tokenizer_config.json
|-- Shanghai_AI_Laboratory
|   `-- internlm2_5-20b-chat -> /root/share/new_models/Shanghai_AI_Laboratory/internlm2_5-20b-chat
|       |-- README.md
|       |-- config.json
|       |-- configuration.json
|       |-- configuration_internlm2.py
|       |-- generation_config.json
|       |-- model-00001-of-00021.safetensors
|       |-- model-00002-of-00021.safetensors
|       |-- model-00003-of-00021.safetensors
|       |-- model-00004-of-00021.safetensors
|       |-- model-00005-of-00021.safetensors
|       |-- model-00006-of-00021.safetensors
|       |-- model-00007-of-00021.safetensors
|       |-- model-00008-of-00021.safetensors
|       |-- model-00009-of-00021.safetensors
|       |-- model-00010-of-00021.safetensors
|       |-- model-00011-of-00021.safetensors
|       |-- model-00012-of-00021.safetensors
|       |-- model-00013-of-00021.safetensors
|       |-- model-00014-of-00021.safetensors
|       |-- model-00015-of-00021.safetensors
|       |-- model-00016-of-00021.safetensors
|       |-- model-00017-of-00021.safetensors
|       |-- model-00018-of-00021.safetensors
|       |-- model-00019-of-00021.safetensors
|       |-- model-00020-of-00021.safetensors
|       |-- model-00021-of-00021.safetensors
|       |-- model.safetensors.index.json
|       |-- modeling_internlm2.py
|       |-- special_tokens_map.json
|       |-- tokenization_internlm2.py
|       |-- tokenization_internlm2_fast.py
|       |-- tokenizer.model
|       `-- tokenizer_config.json
|-- datas
|   |-- assistant.json
|   `-- pretrain.json
|-- hf
|   |-- README.md
|   |-- adapter_config.json
|   |-- adapter_model.bin
|   `-- xtuner_config.py
|-- internlm2_5_7b_full_custom_pretrain_e1_copy.py
|-- internlm2_5_chat_20b_qlora_alpaca_e3_copy.py
|-- internlm2_5_chat_7b_full_finetune_custom_dataset_e1_copy.py
|-- internlm2_5_chat_7b_qlora_alpaca_e3_copy.py
|-- merged
|   |-- config.json
|   |-- configuration_internlm2.py
|   |-- generation_config.json
|   |-- modeling_internlm2.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_internlm2.py
|   |-- tokenization_internlm2_fast.py
|   |-- tokenizer.json
|   |-- tokenizer.model
|   `-- tokenizer_config.json
|-- work_dirs
|   |-- internlm2_5_7b_full_custom_pretrain_e1_copy
|   |   |-- 20241007_220952
|   |   |   |-- 20241007_220952.log
|   |   |   `-- vis_data
|   |   |       `-- config.py
|   |   |-- 20241007_222327
|   |   |   |-- 20241007_222327.log
|   |   |   `-- vis_data
|   |   |       `-- config.py
|   |   |-- 20241007_222511
|   |   |   |-- 20241007_222511.log
|   |   |   `-- vis_data
|   |   |       `-- config.py
|   |   |-- 20241007_222933
|   |   |   |-- 20241007_222933.log
|   |   |   `-- vis_data
|   |   |       |-- 20241007_222933.json
|   |   |       |-- config.py
|   |   |       |-- eval_outputs_iter_1167.txt
|   |   |       |-- eval_outputs_iter_499.txt
|   |   |       |-- eval_outputs_iter_999.txt
|   |   |       `-- scalars.json
|   |   |-- internlm2_5_7b_full_custom_pretrain_e1_copy.py
|   |   |-- iter_1000.pth
|   |   |-- iter_1168.pth
|   |   `-- last_checkpoint
|   |-- internlm2_5_chat_20b_qlora_alpaca_e3_copy
|   |   |-- 20241006_151051
|   |   |   |-- 20241006_151051.log
|   |   |   `-- vis_data
|   |   |       `-- config.py
|   |   |-- 20241006_153349
|   |   |   |-- 20241006_153349.log
|   |   |   `-- vis_data
|   |   |       `-- config.py
|   |   |-- 20241006_154531
|   |   |   |-- 20241006_154531.log
|   |   |   `-- vis_data
|   |   |       |-- 20241006_154531.json
|   |   |       |-- config.py
|   |   |       |-- eval_outputs_iter_1499.txt
|   |   |       |-- eval_outputs_iter_1535.txt
|   |   |       |-- eval_outputs_iter_499.txt
|   |   |       |-- eval_outputs_iter_999.txt
|   |   |       `-- scalars.json
|   |   |-- internlm2_5_chat_20b_qlora_alpaca_e3_copy.py
|   |   |-- iter_1500.pth
|   |   |-- iter_1536.pth
|   |   `-- last_checkpoint
|   `-- internlm2_5_chat_7b_qlora_alpaca_e3_copy
|       |-- 20241007_180551
|       |   |-- 20241007_180551.log
|       |   `-- vis_data
|       |       |-- 20241007_180551.json
|       |       |-- config.py
|       |       |-- eval_outputs_iter_1499.txt
|       |       |-- eval_outputs_iter_1535.txt
|       |       |-- eval_outputs_iter_499.txt
|       |       |-- eval_outputs_iter_999.txt
|       |       `-- scalars.json
|       |-- internlm2_5_chat_7b_qlora_alpaca_e3_copy.py
|       |-- iter_1500.pth
|       |-- iter_1536.pth
|       `-- last_checkpoint
`-- xtuner_generate_assistant.py

27 directories, 127 files

模型合并

对于 LoRA 或者 QLoRA 微调出来的模型其实并不是一个完整的模型,而是一个额外的层(Adapter),训练完的这个层最终还是要与原模型进行合并才能被正常的使用。

代码语言:javascript
复制
MKL_SERVICE_FORCE_INTEL=1 MKL_THREADING_LAYER=GNU xtuner convert merge /root/InternLM/XTuner/merged ./hf ./merged01 --max-shard-size 2GB

模型合并完成后,我们的目录结构应该是这样子的。

代码语言:txt
复制
-- merged
|   |-- config.json
|   |-- configuration_internlm2.py
|   |-- generation_config.json
|   |-- modeling_internlm2.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_internlm2.py
|   |-- tokenization_internlm2_fast.py
|   |-- tokenizer.json
|   |-- tokenizer.model
|   `-- tokenizer_config.json
|-- merged01
|   |-- config.json
|   |-- configuration_internlm2.py
|   |-- generation_config.json
|   |-- modeling_internlm2.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_internlm2.py
|   |-- tokenization_internlm2_fast.py
|   |-- tokenizer.json
|   |-- tokenizer.model
|   `-- tokenizer_config.json
|-- work_dirs

模型合并后生成merged01模型,效果如下。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 2.3 安装 XTuner
  • 模型准备
  • 快速开始
    • 指令跟随微调
      • 模型格式转换
      • 模型格式转换
      • 模型合并
  • Merge 权重
  • 增量预训练微调
    • 基座模型推理
      • 1.2 增量预训练
        • 1.2.1 准备数据文件
        • 准备配置文件
        • 启动微调
        • 模型格式转换
        • 模型合并
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档