XTuner微调个人小助手
-
环境配置
# conda create --name xtuner python=3.10 -y # conda activate xtuner # cd code # git clone -b v0.1.17 https://github.com/InternLM/xtuner # pip install -e '.[all]'
-
前期准备
-
数据集准备
# mkdir -p ft/data # cd ft/data # vim generate_data.py import json # 设置用户的名字 name = '悠悠球大佬' # 设置需要重复添加的数据次数 n = 10000 # 初始化OpenAI格式的数据结构 data = [ { "messages": [ { "role": "user", "content": "请做一下自我介绍" }, { "role": "assistant", "content": "我是{}的小助手,内在是上海AI实验室书生·浦语的1.8B大模型哦".format(name) } ] } ] # 通过循环,将初始化的对话数据重复添加到data列表中 for i in range(n): data.append(data[0]) # 将data列表中的数据写入到一个名为'personal_assistant.json'的文件中 with open('personal_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)
-
运行脚本生成数据集
# python ft/data/generate_data.py
-
模型准备
# 使用Modelscope下载模型文件 import torch from modelscope import snapshot_download, AutoModel, AutoTokenizer from modelscope import GenerationConfig # model_dir = snapshot_download("Shanghai_AI_Laboratory/internlm-xcomposer2-7b", cache_dir='/xm/cywin/model', revision='master') #model_dir = snapshot_download("Shanghai_AI_Laboratory/internlm-xcomposer2-vl-7b", cache_dir='/xm/cywin/model', revision='master') model_dir = snapshot_download("Shanghai_AI_Laboratory/internlm2-chat-1_8b", cache_dir='/xm/cywin/model', revision='master')
-
配置文件选择
# xtuner list-cfg -p internlm2_1_8b 创建配置文件存在路径 # mkdir /xm/cywin/code/ft/config (xtuner) [root@vsic internlm2-chat-1_8b]# xtuner copy-cfg internlm2_1_8b_qlora_alpaca_e3 /xm/cywin/code/ft/config Copy to /xm/cywin/code/ft/config/internlm2_1_8b_qlora_alpaca_e3_copy.py
-
-
配置文件修改
要更换模型的路径以及数据集的路径为我们本地的路径。
# vim internlm2_1_8b_qlora_alpaca_e3_copy.py 27 pretrained_model_name_or_path = '/xm/cywin/model/Shanghai_AI_Laboratory/internlm2-chat-1_8b' 28 use_varlen_attn = False 29 30 # Data 31 alpaca_en_path = '/xm/cywin/code/ft/data/personal_assistant.json' 32 prompt_template = PROMPT_TEMPLATE.default
对一些重要的参数进行调整,包括学习率(lr)、训练的轮数(max_epochs)等等。由于我们这次只是一个简单的让模型知道自己的身份弟位,因此我们的训练轮数以及单条数据最大的 Token 数(max_length)都可以不用那么大
# 修改max_length来降低显存的消耗(在第33行的位置) max_length = 1024 # 减少训练的轮数(在第44行的位置) max_epochs = 2 # 增加保存权重文件的总数(在第54行的位置) save_total_limit = 3
为了训练过程中能够实时观察到模型的变化情况,XTuner 也是贴心的推出了一个
evaluation_inputs
的参数来让我们能够设置多个问题来确保模型在训练过程中的变化是朝着我们想要的方向前进的。比如说我们这里是希望在问出 “请你介绍一下你自己” 或者说 “你是谁” 的时候,模型能够给你的回复是 “我是XXX的小助手...” 这样的回复。因此我们也可以根据这个需求进行更改。# 修改每多少轮进行一次评估(在第57行的位置) + evaluation_freq = 300 # 修改具体评估的问题(在第59到61行的位置) # 可以自由拓展其他问题 + evaluation_inputs = ['请你介绍一下你自己', '你是谁', '你是我的小助手吗']
由于我们的数据集不再是原本的 aplaca 数据集,因此我们也要进入 PART 3 的部分对相关的内容进行修改。包括说我们数据集输入的不是一个文件夹而是一个单纯的 json 文件以及我们的数据集格式要求改为我们最通用的 OpenAI 数据集格式。
# 把 OpenAI 格式的 map_fn 载入进来(在第15行的位置) from xtuner.dataset.map_fns import openai_map_fn, template_map_fn_factory # 将原本是 alpaca 的地址改为是 json 文件的地址(在第102行的位置) dataset=dict(type=load_dataset, path='json', data_files=dict(train=alpaca_en_path)), # 将 dataset_map_fn 改为通用的 OpenAI 数据集格式(在第105行的位置) dataset_map_fn=openai_map_fn,
常用超参
参数名 解释 data_path 数据路径或 HuggingFace 仓库名 max_length 单条数据最大 Token 数,超过则截断 pack_to_max_length 是否将多条短数据拼接到 max_length,提高 GPU 利用率 accumulative_counts 梯度累积,每多少次 backward 更新一次参数 sequence_parallel_size 并行序列处理的大小,用于模型训练时的序列并行 batch_size 每个设备上的批量大小 dataloader_num_workers 数据加载器中工作进程的数量 max_epochs 训练的最大轮数 optim_type 优化器类型,例如 AdamW lr 学习率 betas 优化器中的 beta 参数,控制动量和平方梯度的移动平均 weight_decay 权重衰减系数,用于正则化和避免过拟合 max_norm 梯度裁剪的最大范数,用于防止梯度爆炸 warmup_ratio 预热的比例,学习率在这个比例的训练过程中线性增加到初始学习率 save_steps 保存模型的步数间隔 save_total_limit 保存的模型总数限制,超过限制时删除旧的模型文件 prompt_template 模板提示,用于定义生成文本的格式或结构 ...... ......
-
训练
规训练
可以通过添加
--work-dir
指定特定的文件保存位置。 (使用显存空间5.5G)# mkdir /xm/cywin/code/ft/train # time xtuner train /xm/cywin/code/ft/config/internlm2_1_8b_qlora_alpaca_e3_copy.py --work-dir /xm/cywin/code/ft/train
deepspeed 来加速训练
-
如果你的模型较小,或者内存资源充足,可能不需要使用最高级别的优化。
-
如果你正在尝试训练非常大的模型,或者你的硬件资源有限,使用deepspeed_zero2或deepspeed_zero3可能更合适,因为它们可以显著降低内存占用,允许更大模型的训练。
-
选择时也要考虑到实现的复杂性和运行时的开销,更高级的优化可能需要更复杂的设置,并可能增加一些计算开销。
-
除此之外,我们也可以结合 XTuner 内置的
deepspeed
来加速整体的训练过程,共有三种不同的deepspeed
类型可进行选择,分别是deepspeed_zero1
,deepspeed_zero2
和deepspeed_zero3
DeepSpeed是一个深度学习优化库,由微软开发,旨在提高大规模模型训练的效率和速度。它通过几种关键技术来优化训练过程,包括模型分割、梯度累积、以及内存和带宽优化等。DeepSpeed特别适用于需要巨大计算资源的大型模型和数据集。
在DeepSpeed中,
zero
代表“ZeRO”(Zero Redundancy Optimizer),是一种旨在降低训练大型模型所需内存占用的优化器。ZeRO 通过优化数据并行训练过程中的内存使用,允许更大的模型和更快的训练速度。ZeRO 分为几个不同的级别,主要包括:选择哪种deepspeed类型主要取决于你的具体需求,包括模型的大小、可用的硬件资源(特别是GPU内存)以及训练的效率需求。一般来说:
-
deepspeed_zero1:这是ZeRO的基本版本,它优化了模型参数的存储,使得每个GPU只存储一部分参数,从而减少内存的使用。
-
deepspeed_zero2:在deepspeed_zero1的基础上,deepspeed_zero2进一步优化了梯度和优化器状态的存储。它将这些信息也分散到不同的GPU上,进一步降低了单个GPU的内存需求。
-
deepspeed_zero3:这是目前最高级的优化等级,它不仅包括了deepspeed_zero1和deepspeed_zero2的优化,还进一步减少了激活函数的内存占用。这通过在需要时重新计算激活(而不是存储它们)来实现,从而实现了对大型模型极其内存效率的训练。
-
# mkdir /xm/cywin/code/ft/train_deepspeed # time xtuner train /xm/cywin/code/ft/config/internlm2_1_8b_qlora_alpaca_e3_copy.py --work-dir /xm/cywin/code/ft/train_deepspeed --deepspeed deepspeed_zero2
-
模型转换
模型转换的本质其实就是将原本使用 Pytorch 训练出来的模型权重文件转换为目前通用的 Huggingface 格式文件
# mkdir -p /xm/cywin/code/ft/huggingface # 模型转换 # xtuner convert pth_to_hf ${配置文件地址} ${权重文件地址} ${转换后模型保存地址} # xtuner convert pth_to_hf /xm/cywin/code/ft/train/internlm2_1_8b_qlora_alpaca_e3_copy.py /xm/cywin/code/ft/train/iter_768.pth /xm/cywin/code/ft/huggingface
除此之外,我们其实还可以在转换的指令中添加几个额外的参数,包括以下两个:
参数名 | 解释 |
---|---|
--fp32 | 代表以fp32的精度开启,假如不输入则默认为fp16 |
--max-shard-size {GB} | 代表每个权重文件最大的大小(默认为2GB) |
假如有特定的需要,我们可以在上面的转换指令后进行添加。由于本次测试的模型文件较小,并且已经验证过拟合,故没有添加。假如加上的话应该是这样的
# xtuner convert pth_to_hf /xm/cywin/code/ft/train/internlm2_1_8b_qlora_alpaca_e3_copy.py /xm/cywin/code/ft/train/iter_768.pth /xm/cywin/code/ft/huggingface --fp32 --max-shard-size 2GB
-
模型整合
对于 LoRA 或者 QLoRA 微调出来的模型其实并不是一个完整的模型,而是一个额外的层(adapter)。那么训练完的这个层最终还是要与原模型进行组合才能被正常的使用。
而对于全量微调的模型(full)其实是不需要进行整合这一步的,因为全量微调修改的是原模型的权重而非微调一个新的 adapter ,因此是不需要进行模型整合的。
在 XTuner 中也是提供了一键整合的指令,但是在使用前我们需要准备好三个地址,包括原模型的地址、训练好的 adapter 层的地址(转为 Huggingface 格式后保存的部分)以及最终保存的地址
# mkdir /xm/cywin/code/ft/final_model # export MKL_SERVICE_FORCE_INTEL=1 # xtuner convert merge ${NAME_OR_PATH_TO_LLM} ${NAME_OR_PATH_TO_ADAPTER} ${SAVE_PATH} xtuner convert merge /xm/cywin/model/Shanghai_AI_Laboratory/internlm2-chat-1_8b /xm/cywin/code/ft/huggingface /xm/cywin/code/ft/final_model
那除了以上的三个基本参数以外,其实在模型整合这一步还是其他很多的可选参数,包括:
参数名 | 解释 |
---|---|
--max-shard-size {GB} | 代表每个权重文件最大的大小(默认为2GB) |
--device {device_name} | 这里指的就是device的名称,可选择的有cuda、cpu和auto,默认为cuda即使用gpu进行运算 |
--is-clip | 这个参数主要用于确定模型是不是CLIP模型,假如是的话就要加上,不是就不需要添加 |
CLIP(Contrastive Language–Image Pre-training)模型是 OpenAI 开发的一种预训练模型,它能够理解图像和描述它们的文本之间的关系。CLIP 通过在大规模数据集上学习图像和对应文本之间的对应关系,从而实现了对图像内容的理解和分类,甚至能够根据文本提示生成图像。 在模型整合完成后,我们就可以看到 final_model 文件夹里生成了和原模型文件夹非常近似的内容,包括了分词器、权重文件、配置信息等等。当我们整合完成后,我们就能够正常的调用这个模型进行对话测试了。
-
对话测试
# xtuner chat /xm/cywin/code/ft/final_model --prompt-template internlm2_chat
对比原模型测试:
# xtuner chat /xm/cywin/model/Shanghai_AI_Laboratory/internlm2-chat-1_8b --prompt-template internlm2_chat
那对于 xtuner chat
这个指令而言,还有很多其他的参数可以进行设置的,包括:
启动参数 | 解释 |
---|---|
--system | 指定SYSTEM文本,用于在对话中插入特定的系统级信息 |
--system-template | 指定SYSTEM模板,用于自定义系统信息的模板 |
--bits | 指定LLM运行时使用的位数,决定了处理数据时的精度 |
--bot-name | 设置bot的名称,用于在对话或其他交互中识别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 | 设置累计概率阈值,仅保留概率累加高于top-p的最小标记集,影响生成文本的连贯性 |
--seed | 设置随机种子,用于生成可重现的文本内容 |
除了这些参数以外其实还有一个非常重要的参数就是 --adapter
,这个参数主要的作用就是可以在转化后的 adapter 层与原模型整合之前来对该层进行测试。使用这个额外的参数对话的模型和整合后的模型几乎没有什么太多的区别,因此我们可以通过测试不同的权重文件生成的 adapter 来找到最优的 adapter 进行最终的模型整合工作。
# 使用 --adapter 参数与完整的模型进行对话 xtuner chat /root/ft/model --adapter /root/ft/huggingface --prompt-template internlm2_chat
-
web_demo部署
# mkdir -p /xm/cywin/code/ft/web_demo && cd /xm/cywin/code/ft/web_demo # 拉取 InternLM 源文件 git clone https://github.com/InternLM/InternLM.git # 进入该库中 cd /xm/cywin/code/ft/web_demo/InternLM 修改chat/web_demo.py # 启动web界面 streamlit run /xm/cywin/code/ft/web_demo/InternLM/chat/web_demo.py --server.address 10.200.30.188 --server.port 6006