Bootstrap

书生大模型实战营第4期——3.4 InternVL 多模态模型部署微调实践

1 基础任务

了解LMDeploy部署多模态大模型的核心代码,并运行提供的gradio代码,在UI界面体验与InternVL2的对话。
了解XTuner,并利用给定数据集微调InternVL2-2B后,再次启动UI界面,体验模型美食鉴赏能力的变化。

2 多模态大模型

2.1 训练环境配置

开发机选择 50% A100,镜像选择为 Cuda12.2-conda。

新建名为xtuner的虚拟环境并进入。实验手册上新环境名称是xtuner-env,这个在之前的课程中已经有了,保险期间换个名称再新建一个。

conda create --name xtuner python=3.10 -y
conda activate xtuner

"xtuner"为训练环境名,可以根据个人喜好设置,在本教程中后续提到训练环境均指"xtuner"环境。

安装与deepspeed集成的xtuner和相关包:

pip install -U 'xtuner[deepspeed]' timm==1.0.9
pip install torch==2.4.1 torchvision==0.19.1 torchaudio==2.4.1 --index-url https://download.pytorch.org/whl/cu121
pip install transformers==4.39.0

# Deepspeed 是一个由微软开发的深度学习优化库,它能够帮助加速大规模模型的训练过程
pip install deepspeed

2.2 推理环境配置

新建和配置名为lmdeploy的推理环境:

conda create -n lmdeploy python=3.10 -y
conda activate lmdeploy
pip install lmdeploy gradio==4.44.1 timm==1.0.9

3 LMDeploy部署

3.1 MDeploy基本用法

我们主要通过pipeline.chat 接口来构造多轮对话管线,核心代码为:

## 1.导入相关依赖包
from lmdeploy import pipeline, TurbomindEngineConfig, GenerationConfig
from lmdeploy.vl import load_image

## 2.使用你的模型初始化推理管线
model_path = "your_model_path"
pipe = pipeline(model_path,
                backend_config=TurbomindEngineConfig(session_len=8192))
                
## 3.读取图片(此处使用PIL读取也行)
image = load_image('your_image_path')

## 4.配置推理参数
gen_config = GenerationConfig(top_p=0.8, temperature=0.8)
## 5.利用 pipeline.chat 接口 进行对话,需传入生成参数
sess = pipe.chat(('describe this image', image), gen_config=gen_config)
print(sess.response.text)
## 6.之后的对话轮次需要传入之前的session,以告知模型历史上下文
sess = pipe.chat('What is the woman doing?', session=sess, gen_config=gen_config)
print(sess.response.text)

3.2 网页应用部署体验

我们可以使用UI界面先体验与InternVL对话:

拉取本教程的github仓库https://github.com/Control-derek/InternVL2-Tutorial.git:

git clone https://github.com/Control-derek/InternVL2-Tutorial.git
cd InternVL2-Tutorial

demo.py文件中,MODEL_PATH处传入InternVL2-2B的路径,如果使用的是InternStudio的开发机则无需修改,否则改为模型路径。

启动demo:

conda activate lmdeploy
python demo.py

在这里插入图片描述

上述命令请在vscode下运行,因为vscode自带端口转发,可以把部署在服务器上的网页服务转发到本地。

启动后,CTRL+鼠标左键点进这个链接或者复制链接到浏览器

会看到如下界面:

点击Start Chat即可开始聊天,下方食物快捷栏可以快速输入图片,输入示例可以快速输入文字。输入完毕后,按enter键即可发送。

4 XTuner微调实践

4.1 准备基本配置文件

在InternStudio开发机的/root/xtuner路径下,并激活训练环境:

cd root/xtuner
conda activate xtuner-env  # 或者是你自命名的训练环境

原始internvl的微调配置文件在路径./xtuner/configs/internvl/v2下,假设上面克隆的仓库在/root/InternVL2-Tutorial,复制配置文件internvl_v2_internlm2_2b_lora_finetune_food.py到目标目录./xtuner/configs/internvl/v2下:

cp /root/InternVL2-Tutorial/xtuner_config/internvl_v2_internlm2_2b_lora_finetune_food.py /root/xtuner/xtuner/configs/internvl/v2/internvl_v2_internlm2_2b_lora_finetune_food.py

打开internvl_v2_internlm2_2b_lora_finetune_food.py,查看第一部分模型和微调文件路径是否正确。
在这里插入图片描述

在这一部分的设置中,有如下参数:

  • path: 需要微调的模型路径,在InternStudio环境下,无需修改。
  • data_root: 数据集所在路径。
  • data_path: 训练数据文件路径。
  • image_folder: 训练图像根路径。
  • prompt_temple: 配置模型训练时使用的聊天模板、系统提示等。使用与模型对应的即可,此处无需修改。
  • max_length: 训练数据每一条最大token数。
  • batch_size: 训练批次大小,可以根据显存大小调整。
  • accumulative_counts: 梯度累积的步数,用于模拟较大的batch_size,在显存有限的情况下,提高训练稳定性。
  • dataloader_num_workers: 指定数据集加载时子进程的个数。
  • max_epochs:训练轮次。
  • optim_type:优化器类型。
  • lr: 学习率
  • betas: Adam优化器的beta1, beta2
  • weight_decay: 权重衰减,防止训练过拟合用
  • max_norm: 梯度裁剪时的梯度最大值
  • warmup_ratio: 预热比例,前多少的数据训练时,学习率将会逐步增加。
  • save_steps: 多少步存一次checkpoint
  • save_total_limit: 最多保存几个checkpoint,设为-1即无限制

LoRA相关参数:

  • r: 低秩矩阵的秩,决定了低秩矩阵的维度。
  • lora_alpha 缩放因子,用于调整低秩矩阵的权重。
  • lora_dropout dropout 概率,以防止过拟合。

如果想断点重训,可以在最下面传入参数:

  • 把这里的load_from传入你想要载入的checkpoint,并设置resume=True即可断点重续。

4.2 数据集下载

我们采用的是FoodieQA数据集,这篇文章中了2024EMNLP的主会,其引用信息如下:

@article{li2024foodieqa,
  title={FoodieQA: A Multimodal Dataset for Fine-Grained Understanding of Chinese Food Culture},
  author={Li, Wenyan and Zhang, Xinyu and Li, Jiaang and Peng, Qiwei and Tang, Raphael and Zhou, Li and Zhang, Weijia and Hu, Guimin and Yuan, Yifei and S{\o}gaard, Anders and others},
  journal={arXiv preprint arXiv:2406.11030},
  year={2024}
}

FoodieQA 是一个专门为研究中国各地美食文化而设计的数据集。它包含了大量关于食物的图片和问题,帮助多模态大模型更好地理解不同地区的饮食习惯和文化特色。这个数据集的推出,让我们能够更深入地探索和理解食物背后的文化意义。

可以通过4.2.1和4.2.2两种方式获取数据集,根据获取方式的不同,可能需要修改配置文件中的data_root变量为你数据集的路径:

4.2.1 通过huggingface下载

有能力的同学,建议去huggingface下载此数据集:https://huggingface.co/datasets/lyan62/FoodieQA。该数据集为了防止网络爬虫污染测评效果,需要向提交申请后下载使用。

由于申请的与huggingface账号绑定,需要在命令行登录huggingface后直接在服务器上下载:

huggingface-cli login

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

然后在这里输入huggingface的具有read权限的token即可成功登录。

再使用命令行下载数据集:

huggingface-cli download --repo-type dataset --resume-download lyan62/FoodieQA --local-dir /root/huggingface/FoodieQA --local-dir-use-symlinks False

如果觉得上述过程麻烦,可以用浏览器下载后,再上传服务器即可😊

由于原始数据集格式不符合微调需要格式,需要处理方可使用,在InternVL2-Tutorial下,运行:

python process_food.py

即可把数据处理为XTuner所需格式。注意查看input_path和output_path变量与自己下载路径的区别。

4.2.2 利用share目录下处理好的数据集

由于该数据集即需要登录huggingface的方法,又需要申请,下完还需要自己处理,因此我把处理后的文件放在开发机的/root/share/datasets/FoodieQA路径下了。
在这里插入图片描述

4.3 开始微调

进入到internvl_v2_internlm2_2b_lora_finetune_food.py文件所在的目录下,运行命令,开始微调。或者在运行命令中写完整路径都可以。

xtuner train internvl_v2_internlm2_2b_lora_finetune_food --deepspeed deepspeed_zero2

看到有日志输出,即为启动成功。
其间遇到两次报错,缺少mmengine、peft库,安装后再运行微调。
在这里插入图片描述
微调后,把模型checkpoint的格式转化为便于测试的格式:

# 重新设定工作目录,方便作为下一句命令中各文件目录的相对地址起点
cd /root/xtuner/xtuner/configs/internvl/

python ./v1_5/convert_to_official.py ./v2/internvl_v2_internlm2_2b_lora_finetune_food.py ./v2/work_dirs/internvl_v2_internlm2_2b_lora_finetune_food/iter_640.pth ./v2/work_dirs/internvl_v2_internlm2_2b_lora_finetune_food/lr35_ep10/

如果修改了超参数,iter_xxx.pth需要修改为对应的想要转的checkpoint。 ./work_dirs/internvl_v2_internlm2_2b_lora_finetune_food/lr35_ep10/为转换后的模型checkpoint保存的路径。
在这里插入图片描述

5 与AI美食家玩耍

找到/root/InternVL2-Tutorial目录下的demo.py文件,修改MODEL_PATH为刚刚转换后保存的模型路径:

MODEL_PATH = "/root/xtuner/xtuner/configs/internvl/v2/work_dirs/internvl_v2_internlm2_2b_lora_finetune_food/lr35_ep10"

然后运行改文件,就像在第2节中做的那样,启动网页应用:

cd /root/InternVL2-Tutorial
conda activate lmdeploy
python demo.py

在这里多次出错中止,多试几次,重启开发机后成功。出错信息有:

RuntimeError: [TM][ERROR] CUDA runtime error: out of memory /lmdeploy/src/turbomind/utils/allocator.h:246 

或者:

Running on local URL:  http://127.0.0.1:1096
2024-12-01 15:00:39,508 _client.py[line:1027] INFO || HTTP Request: GET http://127.0.0.1:1096/startup-events "HTTP/1.1 200 OK"
2024-12-01 15:00:39,585 _client.py[line:1027] INFO || HTTP Request: HEAD http://127.0.0.1:1096/ "HTTP/1.1 200 OK"
2024-12-01 15:00:39,762 _client.py[line:1027] INFO || HTTP Request: GET https://api.gradio.app/pkg-version "HTTP/1.1 200 OK"
2024-12-01 15:00:40,426 _client.py[line:1027] INFO || HTTP Request: GET https://api.gradio.app/v2/tunnel-request "HTTP/1.1 200 OK"

Could not create share link. Please check your internet connection or our status page: https://status.gradio.app.

这个信息,如果是在VSCode里运行,仍然会成功跳出运行页面。

微调前,把小笼包错认成饺子,微调后,正确识别。
在这里插入图片描述

在这里插入图片描述

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;