[书生实战营] XTuner 微调个人小助手认知

  • 闯关任务:使用 XTuner 微调 InternLM2-Chat-1.8B 实现自己的小助手认知。

1.微调与XTuner

        微调(fine-tuning)是一种基于预训练模型,通过少量的调整来适应新的任务或数据的方法。微调是在预训练模型的基础上,将模型中一些层的权重参数进行微调,以适应新的数据集或任务。预训练模型部分已经在大规模数据上得到了训练,它们通常是较为通用且高性能的模型,因此可以很好地作为新任务的起点。微调可以加快模型的收敛速度,降低模型过拟合的风险,并在不消耗过多计算资源的情况下获取较好的模型性能。

        对于Finetune的两种范式,在大模型的下游应用中,经常会用到两种微调模式:增量预训练和指令跟随 。

        增量预训练是一种在已有预训练模型(比如:InternLM基座模型)的基础上,利用特定领域的数据进行进一步训练的方法。它的目的是在保持模型原有能力的同时,注入新的领域知识,进一步优化现有的预训练模型,从而提升模型在特定领域任务中的表现(比如:InternLM垂类基座模型)。增量预训练模型能够接受少量的新数据进行更新并适应新的任务,而不需要重新训练整个模型,这种方式可以很好地利用现有的预训练模型的知识,并在新数据上获得更好的性能;

        指令跟随是指让模型根据用户输入的指令来执行相应的操作。模型通过对大量自然语言指令和相应操作的数据进行训练,学习如何将指令分解为具体的子任务,并选择合适的模块来执行这些任务(比如:InternLM垂类对话模型)。

        大多数大型语言模型(LLM)的参数规模巨大,且规模日益增大,导致模型的训练和微调成本高昂,直接训练需要耗费大量计算资源和费用。近年来,如何高效地对大模型进行微调成为了研究热点,而LoRA和QLoRA两种微调技术因其高效性和实用性受到了广泛关注。

        LoRA(Low-Rank Adaptation)是一种使用低精度权重对大型预训练语言模型进行微调的技术,它的核心思想是在不改变原有模型权重的情况下,通过添加少量新参数来进行微调。这种方法降低了模型的存储需求,也降低了计算成本,实现了对大模型的快速适应,同时保持了模型性能。然而,由于使用了低精度权重,LoRA的一个潜在的缺点是在微调过程中可能会丢失一些原始模型的高阶特征信息,因此可能会降低模型的准确性;

        QLoRA(Quantized LoRA)微调技术是对LoRA的一种改进,它通过引入高精度权重和可学习的低秩适配器来提高模型的准确性。并且在LoRA的基础上,引入了量化技术。通过将预训练模型量化为int4格式,可以进一步减少微调过程中的计算量,同时也可以减少模型的存储空间,这对于在资源有限的设备上运行模型非常有用。最终,可以使我们在消费级的显卡上进行模型的微调训练。

2.XTuner介绍

        XTuner是一个大语言模型&多模态模型微调工具箱,主要特征为:

傻瓜化:以配置文件的形式封装了大部分微调场景,0基础的非专业人员也能一键开始微调。

轻量级:对于7B参数量的LLM,微调所需的最小显存仅为8GB: 消费级显卡✅,colab✅。

3.XTuner实践

3.1微调前的对话模型

        首先,创建相应的虚拟环境,安装对应的依赖包。接着,安装XTuner:

# 创建一个目录,用来存放源代码
mkdir -p /root/InternLM/code
cd /root/InternLM/code
git clone -b v0.1.21  https://github.com/InternLM/XTuner /root/InternLM/code/XTuner

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

# 进入到源码目录
cd /root/InternLM/code/XTuner

# 执行安装
pip install -e '.[deepspeed]'

        对微调的模型进行软连接:

# 创建一个目录,用来存放微调的所有资料,后续的所有操作都在该路径中进行
mkdir -p /root/InternLM/XTuner
cd /root/InternLM/XTuner
mkdir -p Shanghai_AI_Laboratory
ln -s /root/share/new_models/Shanghai_AI_Laboratory/internlm2-chat-1_8b Shanghai_AI_Laboratory/internlm2-chat-1_8b

        通过软连接的方式(可以理解为快捷方式),我们无需复制任何数据,就可以直接利用现有的模型文件进行后续的微调操作,从而节省存储空间并简化文件管理。模型文件准备好后,可以使用tree命令来观察目录结构

apt-get install -y tree
tree -l

        在目录结构中可以看出,internlm2-chat-1_8b 是一个符号链接。

        这里用 internlm2-chat-1_8b 模型,通过 QLoRA 的方式来微调一个自己的小助手认知作为XTuner实践。准备一个Streamlit程序的脚本,直接启动应用:

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

        进行端口映射,在web中观察微调前的效果:

        下面进行指令跟随微调,需要通过在微调数据集中大量加入这样的数据。我们准备一个数据集文件datas/assistant.json,文件内容为对话数据:

cd /root/InternLM/XTuner
mkdir -p datas
touch datas/assistant.json

        为了简化数据文件准备,我们也可以通过脚本生成的方式来准备数据。创建一个脚本文件 xtuner_generate_assistant.py:

import json

# 设置用户的名字
name = 'Yang'
# 设置需要重复添加的数据次数
n =  3750

# 初始化数据
data = [
    {"conversation": [{"input": "请介绍一下你自己", "output": "我是{}的小助手,内在是上海AI实验室书生·浦语的1.8B大模型哦".format(name)}]},
    {"conversation": [{"input": "你在实战营做什么", "output": "我在这里帮助{}完成XTuner微调个人小助手的任务".format(name)}]}
]

# 通过循环,将初始化的对话数据重复添加到data列表中
for i in range(n):
    data.append(data[0])
    data.append(data[1])

# 将data列表中的数据写入到'datas/assistant.json'文件中
with open('datas/assistant.json', 'w', encoding='utf-8') as f:
    # 使用json.dump方法将数据以JSON格式写入文件
    # ensure_ascii=False 确保中文字符正常显示
    # indent=4 使得文件内容格式化,便于阅读
    json.dump(data, f, ensure_ascii=False, indent=4)

        假如想要让微调后的模型能够完完全全认识到你的身份,还可以把第6行的n的值调大一点。不过n值太大的话容易导致过拟合,无法有效回答其他问题。执行改脚本生成数据文件。

        在准备好了模型和数据集后,就要根据选择的微调方法结合微调方案来找到最匹配的配置文件,从而减少对配置文件的修改量。XTuner提供多个开箱即用的配置文件,可以使用xtuner list-cfg 命令用于列出内置的所有配置文件,参数 -p 或 --pattern 表示模式匹配,后面跟着的内容将会在所有的配置文件里进行模糊匹配搜索,然后返回最有可能得内容。这里微调的是书生·浦语的模型,因此可以匹配搜索 internlm2:

xtuner list-cfg -p internlm2

       

        配置文件名的解释,以 internlm2_1_8b_full_custom_pretrain_e1 和  internlm2_chat_1_8b_qlora_alpaca_e3 举例:

        由于是对internlm2-chat-1_8b模型进行指令微调,所以与需求最匹配的配置文件是 internlm2_chat_1_8b_qlora_alpaca_e3,复制该配置文件:

cd /root/InternLM/XTuner
xtuner copy-cfg internlm2_chat_1_8b_qlora_alpaca_e3 .

3.2微调配置文件修改

        接下来对配置文件进行修改,首先,在Part1 Setting部分,由于不再需要在HuggingFace上自动下载模型,因此更换模型的路径以及数据集的路径为本地路径。为了训练过程中能够实时观察到模型的变化情况,XTuner推出了一个 evaluation_inputs 的参数来让我们能够设置多个问题来确保模型在训练过程中的变化是朝着想要的方向前进的。因此可以添加自己的输入。

- pretrained_model_name_or_path = 'internlm/internlm2-chat-1_8b'
+ pretrained_model_name_or_path = '/root/InternLM/XTuner/Shanghai_AI_Laboratory/internlm2-chat-1_8b'

- 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'
]

        在PART3 Dataset & Dataloader的部分,由于准备的数据集是JSON格式的数据,并且对话内容已经是inputoutput的数据对,所以不需要进行格式转换:

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)

        此外,一些配置文件中的常用参数介绍如下:

        如果想充分利用显卡资源,可以将 max_length 和 batch_size 这两个参数调大。最后,使用 xtuner train 命令开始训练,xtuner train 命令用于启动模型微调进程,该命令需要一个参数:CONFIG用于指定微调配置文件,即修改好的配置文件XXX_qlora_alpaca_e3_copy.py。训练过程中产生的所有文件,包括日志、配置文件、检查点文件、微调后的模型等,默认保存 work_dirs目录下,也可以通过添加 --work-dir 指定特定的文件保存位置:

xtuner train ./internlm2_chat_1_8b_qlora_alpaca_e3_copy.py

        训练完成后,需要进行模型格式转换。模型转换的本质其实就是将原本使用 Pytorch 训练出来的模型权重文件转换为目前通用的 HuggingFace 格式文件。可以使用 xtuner convert pth_to_hf 命令来实现一键转换。xtuner convert pth_to_hf 命令用于进行模型格式转换。该命令需要三个参数:CONFIG 表示微调的配置文件, PATH_TO_PTH_MODEL 表示微调的模型权重文件路径,即要转换的模型权重, SAVE_PATH_TO_HF_MODEL 表示转换后的 HuggingFace 格式文件的保存路径。此外,还可以添加额外的参数:

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

        转换完成后,可以看到模型被转换为 HuggingFace 中常用的 .bin 格式文件,此时,hf 文件夹即为平时所理解的所谓 “LoRA 模型文件”,可以简单理解:LoRA 模型文件 = Adapter。接下来执行模型合并,对于 LoRA 或者 QLoRA 微调出来的模型其实并不是一个完整的模型,而是一个额外的层(Adapter),训练完的这个层最终还是要与原模型进行合并才能被正常的使用。值得注意的是,对于全量微调的模型(full)其实是不需要进行整合这一步的,因为全量微调修改的是原模型的权重而非微调一个新的 Adapter ,因此是不需要进行模型整合的。在 XTuner 中提供了一键合并的命令 xtuner convert merge,该命令需要三个参数:LLM 表示原模型路径,ADAPTER 表示 Adapter 层的路径, SAVE_PATH 表示合并后的模型最终的保存路径。此外,还有可选参数:

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

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

3.3微调后的模型对话

        微调完成后,再次运行xtuner_streamlit_demo.py脚本来观察微调后的对话效果,在运行之前,将脚本中的模型路径修改为微调后的模型的路径:

- model_name_or_path = "/root/InternLM/XTuner/Shanghai_AI_Laboratory/internlm2-chat-1_8b"
+ model_name_or_path = "/root/InternLM/XTuner/merged"

        然后,直接启动应用:

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

        观察微调后的对话效果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值