InternVL 部署微调实践闯关任务
文章目录
前言
- 理解多模态大模型的常见设计模式,可以大概讲出多模态大模型的工作原理。
- 了解InternVL2的设计模式,可以大概描述InternVL2的模型架构和训练流程。
- 了解LMDeploy部署多模态大模型的核心代码,并运行提供的gradio代码,在UI界面体验与InternVL2的对话。
- 了解XTuner,并利用给定数据集微调InternVL2-2B后,再次启动UI界面,体验模型美食鉴赏能力的变化。
一、多模态大模型的常见设计模式
多模态大模型通过处理和整合不同模态的数据(如图像、文本、语音等)实现跨模态的理解与生成。它们的核心设计模式主要分为 Q-Former(如 BLIP-2 系列) 和 ViT+MLP(如 LLaVA 系列) 两种。以下是这两种架构的工作原理及其特点的详细介绍:
1. BLIP-2 系列的 Q-Former
基本原理
BLIP-2(Bootstrapped Language-Image Pretraining)采用了一种名为 Q-Former(Query-Transformer) 的中间模块,作为视觉模态和语言模态的桥梁。其工作流程如下:
- 视觉特征提取:通过一个预训练的视觉编码器(如 ViT,Vision Transformer)提取图像的底层特征,这些特征可以看作是图像的多维嵌入表示。
- Q-Former 对接视觉特征:
- Q-Former 是一个轻量级的 Transformer 模块,包含固定数量的 learnable queries(可学习查询向量)。
- Q-Former通过 self-attention 和 cross-attention 机制,将 learnable queries 与视觉特征进行交互,从图像特征中提取与语言模态关联性更强的信息。
- 语言生成:
- 经过 Q-Former 编码的模态对齐特征被传递到一个冻结的语言模型(如 GPT 或 LLaMA)。
- 语言模型负责对齐模态特征后执行下游任务(如图像描述生成、跨模态问答等)。
特点
- 高效性:通过轻量化的 Q-Former,BLIP-2 不需要对大型语言模型(LLM)进行微调,能高效地连接视觉和语言模态。
- 灵活性:Q-Former模块作为一个中介层,可以适配不同的视觉编码器和语言模型。
- 任务能力强:在图文生成、问答等任务上表现优异,尤其是在对图像与文本信息高度相关的场景中。
2. LLaVA 系列的 ViT + MLP
基本原理
LLaVA(Large Language and Vision Assistant)系列模型主要使用 ViT(Vision Transformer)+ MLP(多层感知机) 的设计,将视觉特征直接映射到语言模型可以理解的嵌入空间。工作流程如下:
- 视觉特征提取:
- 使用 ViT 作为图像编码器,从图像中提取 patch 特征,将其表示为一组嵌入向量。
- 这些向量捕捉了局部和全局的视觉模式。
- 特征映射:
- 使用一个多层感知机(MLP)将视觉特征映射到与语言嵌入对齐的空间。
- MLP 的作用是对视觉特征进行简单的非线性变换,使其与语言模型的输入维度匹配。
- 语言生成:
- 映射后的视觉特征直接与语言模型(如 LLaMA 或 GPT)交互,作为语言模型的输入,结合已有的上下文信息生成跨模态的输出(如对图像的问答)。
特点
- 简单直接:ViT + MLP 模块设计简单,易于实现且推理速度快。
- 端到端训练:LLaVA 采用端到端的方式微调视觉特征提取模块和语言模型,更紧密地结合视觉和语言模态。
- 成本较低:由于去除了 Q-Former 等中介层,整体架构较为轻量。
- 适合交互:尤其适用于需要实时响应的对话类任务,如跨模态聊天和辅助。
两者的对比
特性 | BLIP-2(Q-Former) | LLaVA(ViT + MLP) |
---|---|---|
模态对齐方法 | 通过 Q-Former 的交互机制从视觉特征中提取语言相关信息 | 通过 MLP 将视觉特征直接映射到语言嵌入空间 |
复杂性 | Q-Former 增加了模型复杂性 | 简单直接,依赖 ViT 和 MLP |
可扩展性 | 模块化设计,适配性强 | 端到端设计,需在特定任务上微调 |
推理效率 | 较慢(需要额外计算 Q-Former 的 attention) | 快速(ViT + MLP 的计算开销较小) |
表现任务 | 图文描述、问答、图文生成 | 图像相关对话、辅助工具 |
应用场景和选择
- BLIP-2 系列的 Q-Former 更适合复杂的跨模态任务,例如需要精确提取图像信息并生成与语言高度相关的描述时。
- LLaVA 系列的 ViT + MLP 则适用于对交互速度要求高的场景,例如实时跨模态对话或简单图像问答。
两种设计理念都在多模态学习中体现了独特的优越性,其选择主要取决于具体任务的复杂度和计算资源的限制。
二、InternVL2的设计模式
InternVL2 是一种多模态大模型,主要架构包括 ViT、Pixel Shuffle 和 MLP,并在训练过程中采用动态分辨率。以下是对其模型架构和训练流程的详细解读:
模型架构
-
ViT(Vision Transformer)
- InternVL2 使用了 ViT 作为主要的视觉编码器,用于提取图像的视觉特征。
- ViT 将图像分割为 patch(图像块),并将每个 patch 转换为嵌入表示,输入 Transformer 模块以捕获全局信息。
- 这种设计保留了图像的细粒度信息,非常适合多模态任务。
-
Pixel Shuffle
- 在 InternVL2 中,Pixel Shuffle 的作用是对视觉特征进行空间重构,提升特征的分辨率,从而在下游任务中捕获更细致的视觉细节。
- Pixel Shuffle 可以在不显著增加计算开销的情况下提高视觉特征的解析度。
-
MLP(多层感知机)
- 用于对视觉特征进行进一步变换,映射到语言模型可以理解的嵌入空间。
- MLP 模块在 InternVL2 的早期阶段单独训练,主要目的是为视觉模态与语言模态之间建立初步连接。
-
动态分辨率
- 在训练过程中,InternVL2 支持动态分辨率,从低分辨率开始训练,逐渐过渡到高分辨率。
- 动态分辨率的使用能够有效减少训练资源,同时保证模型在高分辨率任务上的性能。
-
Text Encoder 的保留
- 不同于 CLIP(丢弃了文本编码器,仅使用视觉编码器生成跨模态嵌入),InternVL2 保留了文本编码器,使得模型能够直接处理文本信息,而不依赖额外的嵌入生成步骤。
- 保留文本编码器增强了模型对文本模态的处理能力,提高了跨模态对齐的精度。
训练流程
第一阶段:单独训练 MLP
-
数据
- 使用高质量的视觉预训练数据,包括多种视觉任务(如视觉问答、检测、图像分割和 OCR)。
- 数据来源广泛,涵盖公开数据集和人工标注数据。
- 动态分辨率:输入图像从较低分辨率开始训练,逐步提升至高分辨率。
-
目标
- 单独训练 MLP 模块,以确保视觉特征能够被有效地映射到语言模态。
-
训练模块
- ViT:提取视觉特征。
- MLP:对视觉特征进行转换。
第二阶段:联合训练 ViT、MLP 和 LLM
-
数据
- 使用高质量的视觉-文本指令数据,涵盖视觉问答、图像描述生成、文本指令响应等任务。
- 特别加入了多模态问答和手写 OCR 数据,进一步增强模型在特定任务上的表现。
-
目标
- 优化整个模型的端到端性能,确保视觉模态与语言模态之间的无缝对接。
-
训练模块
- ViT:作为视觉编码器,捕获图像全局信息。
- MLP:将视觉特征映射到与语言模型对齐的嵌入空间。
- LLM(大语言模型):结合视觉特征和文本输入,执行跨模态生成和推理任务。
三、在UI界面体验与InternVL2的对话
新建虚拟环境并进入:
conda create --name xtuner-env python=3.10 -y
conda activate xtuner-env
"xtuner-env"为训练环境名,可以根据个人喜好设置,在本教程中后续提到训练环境均指"xtuner-env"环境。
安装与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
训练环境既为安装成功。
配置推理所需环境:
conda create -n lmdeploy1 python=3.10 -y
conda activate lmdeploy1
pip install lmdeploy gradio==4.44.1 timm==1.0.9
"lmdeploy"为推理使用环境名。
我们主要通过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)
lmdeploy推理的核心代码如上注释所述。
我们可以使用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自带端口转发,可以把部署在服务器上的网页服务转发到本地。
或者使用端口转发
ssh -CNg -L 1096:127.0.0.1:1096 root@ssh.intern-ai.org.cn -p <你的ssh端口号>
访问链接
http://127.0.0.1:1096
会看到如下界面:
点击Start Chat即可开始聊天,下方食物快捷栏可以快速输入图片,输入示例可以快速输入文字。输入完毕后,按enter键即可发送。
如果输入多张图,或者开多轮对话时报错:
可以参考github的issuehttps://github.com/InternLM/lmdeploy/issues/2101:
屏蔽报错的engine.py的126,127行,添加self._create_event_loop_task()
后,即可解决上面报错。
四、微调InternVL2-2B
在InternStudio开发机的/root/xtuner
路径下,即为开机自带的xtuner,先进入工作目录并激活训练环境:
cd root/xtuner
conda activate xtuner-env # 或者是你自命名的训练环境
原始internvl的微调配置文件在路径./xtuner/configs/internvl/v2
下,假设上面克隆的仓库在/root/InternVL2-Tutorial
,复制配置文件到目标目录下:
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
在第一部分的设置中,有如下参数:
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, beta2weight_decay
: 权重衰减,防止训练过拟合用max_norm
: 梯度裁剪时的梯度最大值warmup_ratio
: 预热比例,前多少的数据训练时,学习率将会逐步增加。save_steps
: 多少步存一次checkpointsave_total_limit
: 最多保存几个checkpoint,设为-1即无限制
LoRA相关参数:
r
: 低秩矩阵的秩,决定了低秩矩阵的维度。lora_alpha
缩放因子,用于调整低秩矩阵的权重。lora_dropout
dropout 概率,以防止过拟合。
如果想断点重训,可以在最下面传入参数:
把这里的load_from
传入你想要载入的checkpoint,并设置resume=True
即可断点重续。
我们采用的是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 是一个专门为研究中国各地美食文化而设计的数据集。它包含了大量关于食物的图片和问题,帮助多模态大模型更好地理解不同地区的饮食习惯和文化特色。这个数据集的推出,让我们能够更深入地探索和理解食物背后的文化意义。
你数据集的路径:
有能力的同学,建议去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
变量与自己下载路径的区别
由于该数据集即需要登录huggingface的方法,又需要申请,下完还需要自己处理,因此我把处理后的文件放在开发机的/root/share/datasets/FoodieQA
路径下了。
运行命令,开始微调:
xtuner train internvl_v2_internlm2_2b_lora_finetune_food --deepspeed deepspeed_zero2
看到有日志输出,即为启动成功:
如果报错如:keyerror或者Filenotfound之类的,可能是XTuner没识别到新写的配置文件,需要指定配置文件的完整路径:
xtuner train /root/xtuner/xtuner/configs/internvl/v2/internvl_v2_internlm2_2b_lora_finetune_food.py --deepspeed deepspeed_zero2
把/root/xtuner/xtuner/configs/internvl/v2/internvl_v2_internlm2_2b_lora_finetune_food.py
换成自己配置文件的路径即可。
微调后,把模型checkpoint的格式转化为便于测试的格式:
python xtuner/configs/internvl/v1_5/convert_to_official.py xtuner/configs/internvl/v2/internvl_v2_internlm2_2b_lora_finetune_food.py ./work_dirs/internvl_v2_internlm2_2b_lora_finetune_food/iter_640.pth ./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保存的路径。
修改MODEL_PATH为刚刚转换后保存的模型路径:
就像在第2节中做的那样,启动网页应用:
cd /root/InternVL2-Tutorial
conda activate lmdeploy
python demo.py
部分case展示:
微调前无法识别大盘鸡:
微调后识别出大盘鸡: