- 大模型
- 模型微调
【免费下载链接】xtuner
A Next-Generation Training Engine Built for Ultra-Large MoE Models
导读
本文基于 XTuner 仓库中的多模态训练文档,系统讲解如何利用 XTuner 完成 LLaVA 图文模型的微调:从开源 LLaVA 数据集与自定义多模态数据集的准备,到「预训练 + 指令跟随微调」两步训练、PTH 模型转换与 LoRA 合并,再到xtuner chat图文对话与 MMBench 评测。以仓库内置的xtuner/llava-internlm2-7b配置为例,读完本文你将掌握一套完整可复现的 VLM 训练、转换、对话与评测链路,并理解底层数据管线(LLaVADataset、llava_map_fn、图像 token 编码)与模型结构(LLaVAModel投影层与 LoRA)的实现原理。
一、多模态训练整体路线
XTuner 支持 LLaVA 格式数据集的多模态图文预训练与微调。多模态图文训练一般分为两步:
- 预训练(pretrain):冻结 LLM 与视觉编码器(CLIP-ViT),仅训练连接视觉与语言特征的投影层(MLP Projector),让模型学会将图像特征对齐到文本语义空间;
- 指令跟随微调(finetune):载入预训练得到的
.pth权重作为初始化,使用图文对话数据微调,使模型具备多轮图文问答能力。
对应到仓库中的配置(xtuner/configs/llava/README_zh-CN.md):
./${LLM}_${ViT}/下是与 LLaVA-InternLM 训练设置对齐的配置(即使用 LoRA / QLoRA);./official/下是与 LLaVA-v1.5 官方训练设置对齐的配置。
以llava-internlm2-7b为例,预训练配置与指令跟随微调配置分别位于:
- 预训练:xtuner/configs/llava/internlm2_chat_7b_clip_vit_large_p14_336/pretrain/llava_internlm2_chat_7b_clip_vit_large_p14_336_e1_gpu8_pretrain.py
- 指令跟随微调(QLoRA):xtuner/configs/llava/internlm2_chat_7b_clip_vit_large_p14_336/finetune/llava_internlm2_chat_7b_qlora_clip_vit_large_p14_336_lora_e1_gpu8_finetune.py
关于各模型在各评测集上的结果,仓库内置的 xtuner/configs/llava/README_zh-CN.md 提供了 MMBench、MME、SEEDBench_IMG、MMVet、MMMU、MathVista、HallusionBench 等多项评测数据,可直接参考。
二、数据准备:LLaVA 开源数据集
多模态训练的第一步是准备数据。本节从「LLaVA 开源数据集准备」和「自定义数据集准备」两部分展开。
2.1 数据文件结构
下载并整理后的数据应具备如下目录结构(这也是所有内置配置文件默认假设的路径,data_root = './data/llava_data/'):
./data/llava_data ├── LLaVA-Pretrain │ ├── blip_laion_cc_sbu_558k.json │ ├── blip_laion_cc_sbu_558k_meta.json │ └── images ├── LLaVA-Instruct-150K │ └── llava_v1_5_mix665k.json └── llava_images ├── coco │ └── train2017 ├── gqa │ └── images ├── ocr_vqa │ └── images ├── textvqa │ └── train_images └── vg ├── VG_100K └── VG_100K_2其中LLaVA-Pretrain用于第一阶段预训练(558K 图文对,训练投影层),LLaVA-Instruct-150K的llava_v1_5_mix665k.json与llava_images目录下的多来源图片用于第二阶段指令跟随微调。该结构在 docs/zh_cn/user_guides/dataset_prepare.md 中有完整对应说明。
2.2 预训练数据下载(LLaVA-Pretrain)
# Make sure you have git-lfs installed (https://git-lfs.com) git lfs install git clone https://huggingface.co/datasets/liuhaotian/LLaVA-Pretrain --depth=12.3 指令微调数据下载
文本数据:LLaVA-Instruct-150K
# Make sure you have git-lfs installed (https://git-lfs.com) git lfs install git clone https://huggingface.co/datasets/liuhaotian/LLaVA-Instruct-150K --depth=1图像数据(对应llava_images下的五个子目录):
| 数据集 | 用途目录 | 下载 |
|---|---|---|
| COCO | coco/train2017 | 下载train2017.zip并解压 |
| GQA | gqa/images | 下载 GQAimages.zip |
| TextVQA | textvqa/train_images | 下载train_val_images.zip |
| VisualGenome | vg/VG_100K、vg/VG_100K_2 | 下载 part1、part2 两个压缩包 |
| OCR-VQA | ocr_vqa/images | 使用官方 download script 下载 |
⚠️ 特别注意 OCR-VQA 图片命名:OCR-VQA 所下载的图片命名需要利用如下脚本进行处理,以确保所有图片后缀为
.jpg:
#!/bin/bash ocr_vqa_path="<your-directory-path>" find "$target_dir" -type f | while read file; do extension="${file##*.}" if [ "$extension" != "jpg" ] then cp -- "$file" "${file%.*}.jpg" fi done2.4 自定义数据集准备
如果用户期望使用自定义数据集进行图文训练,可以参照 LLaVA 开源数据集格式进行准备,JSON 格式如下:
[ { "image": "xxx/xxx", "conversations": [ { "from": "human", "value": "<image>\nHello! What's this?" }, { "from": "gpt", "value": "This is a dog!" }, { "from": "human", "value": "Is it cute?" }, { "from": "gpt", "value": "Yes." } ] }, ... ]针对自定义数据目前有一些约束:
image字段表示图片路径,且仅能有一张图片;conversations字段第 0 条的value需要包括<image>,以确保图片被正确嵌入到首轮输入中。
源码层面的印证:<image>是仓库定义的图片占位 tokenDEFAULT_IMAGE_TOKEN,其 token 索引为IMAGE_TOKEN_INDEX = -200(见 xtuner/utils/constants.py)。在数据管线中:
- xtuner/dataset/map_fns/dataset_map_fns/llava_map_fn.py 的
llava_map_fn会将 human 轮次中的<image>从消息中间提到开头并规范化为<image>\n...的格式,再切分为{'input', 'output'}单轮对话结构;同时跳过数据集开头可能出现的from == 'gpt'轮次; - xtuner/dataset/utils.py 的
encode_fn在编码含<image>的输入时,按DEFAULT_IMAGE_TOKEN切分文本,并在切分位置插入IMAGE_TOKEN_INDEX,随后对输入部分打上IGNORE_INDEX = -100标签(不计算损失),仅对output部分计算 loss——这正是「只学回答、不学提问」的多模态 SFT 标签策略; - 同样的约束也体现在仅含图片 token 的
llava_image_only_map_fn(用于图文预训练阶段,输入仅含<image>)。
扩展到 InternVL 系列数据集:除 LLaVA 外,XTuner 还内置了InternVL_V1_5_Dataset(xtuner/dataset/internvl_dataset.py),用于 InternVL 系列 VLM 的多模态训练。其配置支持data_paths与image_folders以列表形式传入多份数据(图片目录可为None,表示该数据源无图片),例如 xtuner/configs/internvl/v1_5/internvl_v1_5_internlm2_26b_finetune.py:
llava_dataset = dict( type=InternVL_V1_5_Dataset, model_path=path, data_paths=data_path, # 可为 ['a.json','b.jsonl','c.json'] image_folders=image_folder, # 可为 ['a', None, 'c'] template=prompt_template, max_length=max_length)InternVL_V1_5_Dataset支持根据min_dynamic_patch/max_dynamic_patch对图像做动态切分(dynamic preprocess),并按downsample_ratio计算 patch token 数,max_length默认放宽到 4096。
三、训练:预训练与指令跟随微调
多模态图文训练一般分为两步:预训练(pretrain)、指令跟随微调(finetune)。下面以llava-internlm2-7b为例给出完整命令,用户可以对其中的模型路径、数据路径进行自定义修改。
3.1 预训练(Pretrain)
$ NPROC_PER_NODE=8 xtuner train llava_internlm2_chat_7b_clip_vit_large_p14_336_e1_gpu8_pretrain --deepspeed deepspeed_zero2训练得到的模型将默认保存在
./work_dirs/,用户可以通过命令xtuner train --work-dir ${SAVE_PATH}指定保存路径。
预训练配置要点(预训练配置文件):
- 模型:
llm_name_or_path = 'internlm/internlm2-chat-7b',visual_encoder_name_or_path = 'openai/clip-vit-large-patch14-336'; - 冻结策略:
freeze_llm=True、freeze_visual_encoder=True,即 LLM 与 CLIP-ViT 全程冻结,只有投影层(projector)参与训练; - LLM 采用 4bit QLoRA 量化加载(
BitsAndBytesConfig:load_in_4bit=True、bnb_4bit_quant_type='nf4'、bnb_4bit_use_double_quant=True),显著降低显存占用; - 数据:
data_path = './data/llava_data/LLaVA-Pretrain/blip_laion_cc_sbu_558k.json',image_folder = './data/llava_data/LLaVA-Pretrain/images'; - 序列长度:
max_length = int(2048 - (336 / 14)**2) = 1472(CLIP 336×336 输入在 14×14 patch 下产生 24×24=576 个视觉 token,从 2048 中扣除后即为文本侧可用长度); - 优化:
AdamW,lr = 1e-3,betas = (0.9, 0.999),weight_decay = 0,max_norm = 1(梯度裁剪),warmup_ratio = 0.03(LinearLR 预热后接 CosineAnnealingLR); - 训练:
batch_size = 32(per_device)、max_epochs = 1、dataloader_num_workers = 4; - 保存与评测:
save_steps = 500、save_total_limit = 2;custom_hooks中的EvaluateChatHook每 500 步用evaluation_images(一张示例图片)与evaluation_inputs(中英文提示词)自动进行一轮对话生成并打印日志。
3.2 指令跟随微调(Finetune)
指令跟随微调时,需要载入预训练阶段所得到的.pth模型,以提供良好的初始化。这一通过在配置文件中的pretrained_pth指定(默认指向./work_dirs/llava_internlm2_chat_7b_clip_vit_large_p14_336_e1_gpu8_pretrain/iter_2181.pth),用户可以自行修改。
$ NPROC_PER_NODE=8 xtuner train llava_internlm2_chat_7b_qlora_clip_vit_large_p14_336_lora_e1_gpu8_finetune --deepspeed deepspeed_zero2QLoRA 微调配置要点(微调配置文件):
- 数据:
data_path = './data/llava_data/LLaVA-Instruct-150K/llava_v1_5_mix665k.json',image_folder = './data/llava_data/llava_images'; - LoRA 注入:LLM 侧
llm_lora(r=512、lora_alpha=256、lora_dropout=0.05),视觉编码器侧visual_encoder_lora(r=64、lora_alpha=16),target_modules未指定时由find_all_linear_names自动识别(见 xtuner/model/llava.py); - 冻结策略:
freeze_llm=True、freeze_visual_encoder=True,冻结基座权重、仅训练 LoRA 适配器; - 优化:
lr = 2e-4,batch_size = 16,其余优化器设置与预训练一致; - 图像预处理:
pad_image_to_square=True,即调用 xtuner/dataset/utils.py 的expand2square将图片按 RGB 均值色填充为正方形后再送入 CLIPImageProcessor; - 采样器:使用
LengthGroupedSampler,length_property='modality_length',按「模态长度」分桶采样。该属性由LLaVADataset.modality_length提供——有图的样本记正长度、无图的样本记负长度,从而实现图文样本按长度分组、减少 padding 浪费。
此外仓库还提供了全参数微调配置 llava_internlm2_chat_7b_clip_vit_large_p14_336_e1_gpu8_finetune.py(freeze_llm=False、LLM 以 fp32 加载、lr=2e-5、batch_size=8、accumulative_counts=2),以及llava_internlm2_chat_7b_clip_vit_large_p14_336_e1_gpu8_finetune.py之外的多种 LLM + ViT 组合(vicuna、internlm、internlm2-20b 等,见 xtuner/configs/llava)。
3.3 数据管线源码解读:LLaVADataset
理解LLaVADataset(xtuner/dataset/llava.py)有助于把握上述配置参数的底层影响:
- 文本与图像分离处理:构造时先读取
data_path(支持.json与.jsonl),经process_hf_dataset完成 tokenize、dataset_map_fn(llava_map_fn)与template_map_fn(template_map_fn_factory,按PROMPT_TEMPLATE.internlm2_chat套上<|im_start|>对话模板,见 xtuner/dataset/map_fns/template_map_fn.py)处理,得到text_data;真正的图片在__getitem__时才按image_folder + image_file在线读取并预处理为pixel_values; modality_length属性:返回每个样本的文本长度,无图样本取负值,供LengthGroupedSampler使用;- 无图样本的兜底:若某样本没有
image字段,则填充一张与image_processor.crop_size等尺寸的全零pixel_values,保证 batch 结构一致; - 离线处理文本数据:当
offline_processed_text_folder被指定时(与data_path同时存在时优先加载离线数据),直接从本地加载已 tokenize 好的 HF Dataset,跳过在线处理,这是大数据量场景下提速的关键(详见下文 4.4 节)。
四、模型转换与合并
4.1 PTH 转 HuggingFace(pth_to_hf)
模型训练后会自动保存成 PTH 模型(例如iter_5198.pth),但 PTH 并不是通用的 HuggingFace 格式,需要利用xtuner convert pth_to_hf将其转换为 HuggingFace 模型,以便后续对话、评测与部署使用。具体命令为:
$ xtuner convert pth_to_hf $FINETUNE_CFG $PTH_PATH $SAVE_PATH $ # 例如:xtuner convert pth_to_hf llava_internlm2_chat_7b_qlora_clip_vit_large_p14_336_lora_e1_gpu8_finetune ./iter_5198.pth ./iter_5198_hf转换器源码位于 xtuner/tools/model_converters/pth_to_hf.py,其要点包括:
- 通过
--cfg-options支持命令行覆盖配置;默认输出 LLM 为 fp16(可加--fp32保存为 fp32),并支持--max-shard-size(默认 2GB)分片与--safe-serialization; - 对
LLaVAModel会清空pretrained_pth后按配置重建模型,再逐参数装载权重并调用model.to_hf(...)落盘; LLaVAModel.to_hf(xtuner/model/llava.py)根据训练范式输出不同目录结构:- 默认
save_format='xtuner':若使用 LoRA,则输出llm_adapter/、visual_encoder_adapter/与projector/;若为全参数微调,则输出完整 LLM 权重、visual_encoder/与projector/,同时保存 tokenizer 与 image_processor; - 也可选择
save_format='huggingface'或'official',将状态字典按映射关系重组为LlavaForConditionalGeneration/ 官方 LLaVA 结构(含图像 token 的 embedding 扩容处理)。
- 默认
使用默认的微调范式时,转换后的文件结构与仓库文档描述的
xtuner/llava-internlm2-7b发布结构一致(LLM/LLM-adapter + visual_encoder/visual_encoder-adapter + projector)。
4.2 LoRA / QLoRA 模型合并(可选)
如果您使用了 LoRA / QLoRA 微调,则模型转换后将得到 adapter 参数,而并不包含原 LLM 参数。如果您期望获得合并后的模型权重,那么可以利用xtuner convert merge:
$ xtuner convert merge $LLM $LLM_ADAPTER $SAVE_PATH $ xtuner convert merge $CLIP $CLIP_ADAPTER $SAVE_PATH --is-clip其中第一条合并 LLM 与其 LoRA adapter,第二条用--is-clip标记合并 CLIP-ViT 与其 LoRA adapter。合并工具(xtuner/tools/model_converters/merge.py)内部通过PeftModel.from_pretrained加载 adapter 并调用merge_and_unload()完成权重合并,之后save_pretrained落盘,同时保存 tokenizer / image_processor;默认设备为cuda,可用--device cpu/auto调整。
4.3 离线处理数据集的加速技巧(可选)
当训练数据量非常大时,每次训练都先在线处理数据会极为耗时。XTuner 提供了离线处理 LLaVA 数据的流程(详见 docs/zh_cn/user_guides/llava_offline.md):
- 用
xtuner list-cfg -p llava查看 LLaVA 相关配置,用xtuner copy-cfg ${CONFIG_NAME} .导出配置; - 运行
python xtuner/tools/process_untokenized_llava_data.py ${CONFIG_PATH} --save-folder /folder/to/save/processed/dataset离线处理文本数据; - 修改导出的配置,把
llava_dataset中的data_path/tokenizer替换为offline_processed_text_folder=/folder/to/save/processed/dataset; - 直接使用修改后的配置训练。
LLaVADataset会优先加载offline_processed_text_folder,多次训练无需重复 tokenize。
五、对话测试
用户可以利用xtuner chat实现与微调后的多模态图文模型对话。假设模型转换阶段获得的模型路径为./iter_5198_hf,则可以利用下列命令实现对话:
$ xtuner chat internlm/internlm2-chat-7b \ $ --visual-encoder openai/clip-vit-large-patch14-336 \ $ --llava ./iter_5198_hf \ $ --prompt-template internlm2_chat \ $ --image $IMAGE_PATH参数与运行机制(见 xtuner/tools/chat.py):
- 第一个参数为 LLM 路径或 HuggingFace Hub ID。如果训练阶段 LLM 使用的是 LoRA / QLoRA 微调,则此参数请传入基础 LLM,如
internlm/internlm2-chat-7b;如果使用的是全参数微调,则此参数请传入转换(xtuner convert pth_to_hf)所得到的模型权重,如./iter_5198_hf; --visual-encoder:指定 CLIP 视觉编码器;若--llava目录内已包含visual_encoder/子目录,则无需再传(工具会自动检测目录结构);--llava:模型转换阶段获得的权重目录,工具会按需加载其中的projector/、llm_adapter/、visual_encoder_adapter/;--prompt-template internlm2_chat:与训练时的PROMPT_TEMPLATE保持一致,工具会据此套用对话模板并自动注入停止词;--image:指定本地图片路径或 URL,工具内部经expand2square+CLIPImageProcessor预处理后,由 visual_encoder 提取特征、projector 投影,最终通过prepare_inputs_labels_for_multimodal将视觉 token 拼入input_ids后执行生成;- 其它可选参数:
--torch-dtype(默认 fp16)、--bits(4/8 位量化加载 LLM)、--max-new-tokens(默认 2048)、--temperature(默认 0.1)、--top-k(默认 40)、--top-p(默认 0.75)等。
六、评测
6.1 VLMEvalKit
XTuner 的 LLaVA 模型可以利用 VLMEvalKit 进行评测,可参考其 Quickstart 快速上手(按该工具链的标准流程准备数据集与配置文件即可)。
6.2 XTuner 内置 MMBench 评测
为了方便使用,XTuner 内也集成了 MMBench 评测。您可以通过下列命令下载 MMBench 评测数据集:
$ wget https://opencompass.openxlab.space/utils/VLMEval/MMBench_DEV_EN.tsv $ wget https://opencompass.openxlab.space/utils/VLMEval/MMBench_TEST_EN.tsv $ wget https://opencompass.openxlab.space/utils/VLMEval/MMBench_DEV_CN.tsv $ wget https://opencompass.openxlab.space/utils/VLMEval/MMBench_TEST_CN.tsv $ wget https://opencompass.openxlab.space/utils/VLMEval/CCBench.tsv之后,您可以利用下列命令实现评测:
$ xtuner mmbench internlm/internlm2-chat-7b \ $ --visual-encoder openai/clip-vit-large-patch14-336 \ $ --llava ./iter_5198_hf \ $ --prompt-template internlm2_chat \ $ --data-path $DATA_PATH \ $ --work-dir $RESULT_PATH要点说明(见 xtuner/tools/mmbench.py):
- 第一个参数为 LLM 路径或 HuggingFace Hub ID,规则与
xtuner chat相同(LoRA/QLoRA 传基础 LLM,全参微调传转换后的权重); $DATA_PATH指上一步骤所下载的某一个 tsv 文件,如MMBench_DEV_EN.tsv;- 工具内部用
MMBenchDataset解析 tsv:若首行含answer列则判定为dev集,否则为test集;推理时对每个样本拼接「题目 + 选项」并提示模型"直接回答选项字母",生成采用do_sample=False; - 评测结果保存到
--work-dir下的mmbench_result.xlsx与mmbench_result.json; - 评测完成后,若为开发集则会直接打印结果(按 Average 及 CP / FP-S / FP-C / LR / RR / AR 等能力维度分类给出准确率表格);若为测试集,则需将
mmbench_result.xlsx提交至 MMBench 官方完成评测以取得精度结果。
七、FAQ
7.1 如何更换 LLM?
修改 LLM 的方式与训练单模态的大语言模型类似:
- 修改配置文件中的
llm_name_or_path参数至您期望使用的 LLM,例如internlm/internlm2-chat-20b等; - 修改配置文件中的
prompt_template参数,与您所选择的 LLM 保持对齐,具体选择可参考对话模板文档。
更换 LLM 后,需注意其 tokenizer 与对话模板与数据管线的兼容性(模板注入由 xtuner/dataset/map_fns/template_map_fn.py 完成)。
7.2 ValueError:bos_token_idhas to be defined when noinput_idsare provided.
这是由于老版本transformers的 LLMgenerate接口在接受inputs_embeds输入时,必须传入有效的bos_token_id(对应 transformers 的修复 PR #29772)。
更新transformers即可解决:
$ pip install -U transformers八、关键文件索引
- 多模态训练文档:docs/zh_cn/training/multi_modal_dataset.rst
- LLaVA 数据准备:docs/zh_cn/user_guides/dataset_prepare.md、离线处理:docs/zh_cn/user_guides/llava_offline.md
- 配置示例:xtuner/configs/llava/internlm2_chat_7b_clip_vit_large_p14_336/pretrain 与 xtuner/configs/llava/internlm2_chat_7b_clip_vit_large_p14_336/finetune
- 数据集实现:xtuner/dataset/llava.py、xtuner/dataset/map_fns/dataset_map_fns/llava_map_fn.py、xtuner/dataset/internvl_dataset.py
- 模型实现:xtuner/model/llava.py
- 工具链:xtuner/tools/chat.py、xtuner/tools/mmbench.py、xtuner/tools/model_converters/pth_to_hf.py、xtuner/tools/model_converters/merge.py
- LLaVA 全流程说明与评测结果:xtuner/configs/llava/README_zh-CN.md
- 大模型
- 模型微调
【免费下载链接】xtuner
A Next-Generation Training Engine Built for Ultra-Large MoE Models
相关推荐
XTuner 多模态(VLM)数据集训练实战:从 LLaVA 数据准备到对话评测的全流程指南
XTuner 多模态(VLM)数据集训练实战:从 LLaVA 数据准备到对话评测的全流程指南 本文以 XTuner 内置的 xtuner/llava inter
大模型模型微调XTuner 数据集准备完全指南:从 HuggingFace 到 LLaVA 与 RefCOCO 的多模态数据管线
XTuner 数据集准备完全指南:从 HuggingFace 到 LLaVA 与 RefCOCO 的多模态数据管线 XTuner 作为面向超大规模 MoE 模型
大模型模型微调XTuner 自定义预训练数据集实战:从数据准备到增量预训练全流程指南
XTuner 自定义预训练数据集实战:从数据准备到增量预训练全流程指南 XTuner 支持使用自定义数据集对基座大语言模型进行增量预训练(Incremental
大模型模型微调
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考