创建一个虚拟环境。使用Anaconda
创建一个名为xtuner03
的虚拟环境,可以直接执行命令
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
虚拟环境创建完成后,就可以安装 XTuner 了。首先,从 Github 上下载源码。
# 创建一个目录,用来存放源代码
mkdir -p /root/InternLM/code
cd /root/InternLM/code
git clone -b v0.1.23 https://github.com/InternLM/XTuner /root/InternLM/code/XTuner
进入源码目录,执行安装。
# 进入到源码目录
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
验证一下安装结果。
xtuner version
10/06 12:01:58 - mmengine - INFO - 0.1.23
通过 xtuner help
熟悉 XTuner 的用法
InternLM 推出的 7B 模型来完成此次微调演示,可以通过 HuggingFace、OpenXLab 或者 Modelscope 进行模型的下载
# 创建一个目录,用来存放微调的所有资料,后续的所有操作都在该路径中进行
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
命令来观察目录结构。
apt-get install -y tree
tree -l
目录结构
`-- 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
的方式来微调一个自己的小助手认知作为案例来进行演示。
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
xtuner copy-cfg internlm2_5_chat_7b_qlora_alpaca_e3 .
修改为 internlm2_5_chat_20b_qlora_alpaca_e3_copy
- 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
指定特定的文件保存位置。
cd /root/InternLM/XTuner
conda activate xtuner03
xtuner train ./internlm2_5_chat_20b_qlora_alpaca_e3_copy.py (50%)
在训练完后,我们的目录结构应该是这样子的。
-- 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) |
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
目录结构
-- 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模型,假如是的话就要加上,不是就不需要添加 |
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
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
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
模型合并完成后,我们的目录结构应该是这样子的。
目录结构
模型合并完成后,我们就可以看到最终的模型和原模型文件夹非常相似,包括了分词器、权重文件、配置信息等等
微调完成后,我们可以再次运行xtuner_streamlit_demo.py
脚本来观察微调后的对话效果,不过在运行之前,我们需要将脚本中的模型路径修改为微调后的模型的路径。
# 直接修改脚本文件第18行
- model_name_or_path = "/root/InternLM/XTuner/Shanghai_AI_Laboratory/internlm2-chat-1_8b"
+ model_name_or_path = "/root/InternLM/XTuner/merged"
然后,我们可以直接启动应用。
conda activate xtuner03
streamlit run /root/InternLM/Tutorial/tools/xtuner_streamlit_demo.py
运行后,确保端口映射正常,如果映射已断开则需要重新做一次端口映射。
ssh -CNg -L 8501:127.0.0.1:8501 root@ssh.intern-ai.org.cn -p 43551
最后,通过浏览器访问:http://127.0.0.1:8501 来进行对话了。
定义一些基本方法。
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM
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
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
我们先来看看基座模型的推理结果。
tokenizer, model = load_model("Shanghai_AI_Laboratory/internlm2-1_8b")
generate("书生·浦语大模型实战营第三期是")
del tokenizer, model
torch.cuda.empty_cache()
我们对基座模型进行增量预训练,让模型增加新的知识。
为了让模型学习到新的知识,我们需要将新的知识数据整理成指定格式文件,形成数据集,然后让模型来学习这些新数据。这里我们准备一个简单的皮肤科数据集 datas/pretrain.json
,仅包含一条知识,然后让数据重复多次。
网上有大量的开源数据集可以供我们进行使用,有些时候我们可以在开源数据集的基础上添加一些我们自己独有的数据集,也可能会有很好的效果。
上传数据集 终端输入
C:\\sunset\\pretrain.json root@ssh.intern-ai.org.cn:/root/InternLM/XTuner/datas
准备好数据文件后,我们的目录结构应该是这样子的。
tree -l
在准备好了模型和数据集后,我们就要根据我们选择的微调方法结合微调方案来找到与我们最匹配的配置文件了,从而减少我们对配置文件的修改量。
这里我们选择使用 internlm2_5_chat_7b_full_finetune_custom_dataset_e1
配置文件。
xtuner copy-cfg internlm2_5_chat_7b_full_finetune_custom_dataset_e1 .
根据项目的需求一步步的进行修改和调整吧!
在 PART 1 的部分,由于我们不再需要在 HuggingFace 上自动下载模型,因此我们先要更换模型的路径以及数据集的路径为我们本地的路径。
为了训练过程中能够实时观察到模型的变化情况,XTuner 贴心的推出了一个 evaluation_inputs
的参数来让我们能够设置多个问题来确保模型在训练过程中的变化是朝着我们想要的方向前进的。我们可以添加自己的输入。
在 PART 2 的部分,由于我们复制的配置文件是全参数微调的配置,而我们希望使用 QLoRA
算法进行微调,所以可以添加 QLoRA
算法的配置。
修改完后的完整的配置文件是
# 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
命令令即可开始训练。
xtuner train ./internlm2_5_7b_full_custom_pretrain_e1_copy.py
在训练完后,我们的目录结构应该是这样子的。
模型转换的本质其实就是将原本使用 Pytorch 训练出来的模型权重文件转换为目前通用的 HuggingFace 格式文件,那么我们可以通过以下命令来实现一键转换。
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
模型格式转换完成后,我们的目录结构应该是这样子的。
|-- 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),训练完的这个层最终还是要与原模型进行合并才能被正常的使用。
MKL_SERVICE_FORCE_INTEL=1 MKL_THREADING_LAYER=GNU xtuner convert merge /root/InternLM/XTuner/merged ./hf ./merged01 --max-shard-size 2GB
模型合并完成后,我们的目录结构应该是这样子的。
-- 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 删除。