XTuner Llava 训练数据集离线处理指南:四步告别在线预处理耗时
2026/9/18 7:46:15 网站建设 项目流程

XTuner Llava 训练数据集离线处理指南:四步告别在线预处理耗时

【免费下载链接】xtunerA Next-Generation Training Engine Built for Ultra-Large MoE Models项目地址: https://gitcode.com/GitHub_Trending/xt/xtuner

导读

本文讲解 XTuner 中 Llava(视觉语言模型)训练数据集的离线处理方案。当训练数据量非常大时,每次训练前在线处理数据(分词、映射对话格式、按模板组装 prompt)会极为耗时,甚至可能触发分布式训练中的超时问题。通过本指南,你将掌握一套完整的四步流程:导出 config、离线处理数据并保存至本地、修改 config 指向离线数据、直接启动训练,让多次重复训练直接复用预处理结果,显著缩短训练启动时间。

为什么需要离线处理 Llava 数据

XTuner 默认采用在线数据预处理策略,即训练启动时通过process_hf_dataset对原始数据实时完成分词、对话映射与 prompt 模板组装,得到训练所需的input_idslabels等张量。这一策略降低了使用门槛,但存在明显短板:

  • 耗时集中在启动阶段:数据量越大,每次训练启动前需要等待的预处理时间越长,且该过程为纯 CPU 任务;
  • 可能触发nccl timeout:在分布式训练中,XTuner 由 rank0 统一完成预处理后通过torch.distributed.broadcast_object_list广播至其他 rank,而该广播的超时时间与 nccl 通信超时时间相同(默认 30 分钟)。当训练集过大时,rank0 可能无法在超时时间内处理完全部数据而导致报错(详见 超大规模数据集 的说明)。

离线处理的思路是:把"数据处理"这一一次性成本从每次训练中剥离出来——先对原始数据做一次完整的文本预处理并保存到本地磁盘,之后无论训练多少次,都直接读取这份已处理好的数据,跳过重复计算。

前置条件

  • 已正确安装 XTuner 及其依赖(含datasetstransformersmmengine等);
  • 已准备 Llava 训练所需的原始数据,包括:
    • JSON 格式的对话标注文件(如llava_v1_5_mix665k.jsonblip_laion_cc_sbu_558k.json);
    • 对应的图片目录(image_folder);
    • 视觉编码器与 LLM 的预训练权重路径。
  • 已了解 Llava 训练 config 的基本结构,可参考 xtuner/configs/llava 下的官方示例。

Step 1:导出模板 config 文件

首先查看 XTuner 提供的所有与 Llava 训练相关的 config:

xtuner list-cfg -p llava

该命令会列出仓库中所有文件名或路径匹配llava的配置文件。仓库当前提供的 Llava config 覆盖了多种模型组合,例如:

  • llava_internlm2_chat_7b_clip_vit_large_p14_336_e1_gpu8_pretrain.py(InternLM2-Chat-7B + CLIP ViT-Large/14-336,预训练)
  • llava_internlm2_chat_7b_qlora_clip_vit_large_p14_336_lora_e1_gpu8_finetune.py(同上,QLoRA 微调)
  • 以及基于 InternLM2-Chat-1.8B/20B、LLaMA3-8B/70B、Phi-3-mini、Vicuna-7B/13B 等底座的各种 pretrain/finetune 配置(完整清单见 xtuner/configs/llava)。

找到需要使用的 config 名称(下文以${CONFIG_NAME}指代)后,将其导出至当前目录:

xtuner copy-cfg ${CONFIG_NAME} .

执行后当前目录会生成一个名为${CONFIG_NAME}_copy.py的副本文件(与原配置内容完全一致),后续所有修改都在这个副本上进行。

Step 2:离线处理数据集

使用 XTuner 提供的专用工具脚本离线处理 Llava 训练数据中的文本部分:

python xtuner/tools/process_untokenized_llava_data.py \ ${CONFIG_PATH} \ --save-folder /folder/to/save/processed/dataset

参数说明:

参数含义
${CONFIG_PATH}Step 1 中导出的 config 文件路径(即${CONFIG_NAME}_copy.py
--save-folder离线处理后数据集的保存路径,例如/folder/to/save/processed/dataset

底层实现原理

从源码看,该脚本的核心逻辑非常简洁,位于 process_untokenized_llava_data.py:

  1. 通过 mmengine 的Config.fromfile读取 config 文件;
  2. 调用BUILDER.build(config.train_dataloader.dataset)构建LLaVADataset实例——这一步会完整执行数据加载、dataset_map_fn对话映射、template_map_fn模板组装以及 tokenizer 分词等全部文本预处理;
  3. 取出llava_dataset.text_data属性(即预处理完成后的 HuggingFace Dataset 对象);
  4. 调用text_data.save_to_disk(args.save_folder)将结果以磁盘数据集(Arrow 格式)形式保存。

也就是说,Step 2 实质上就是在训练之外单独执行了一遍"在线预处理",并把预处理产物持久化。注意:这一步只处理文本数据input_idslabels、图片路径引用等),图片本身仍然以原始文件形式存放于image_folder,训练时再按需读取。

验证离线处理结果

处理完成后,可立即读取验证数据是否符合预期:

from datasets import load_from_disk ds = load_from_disk('/folder/to/save/processed/dataset') print(ds)

应能看到保存的 dataset 结构与原始text_data一致,包含input_idslabelsimage等字段。

Step 3:修改 config 文件

对 Step 1 导出的 config 做如下修改,将数据源从"在线处理"切换为"读取离线数据":

####################################################################### # PART 3 Dataset & Dataloader # ####################################################################### llava_dataset = dict( - data_path=data_path, - tokenizer=tokenizer, + offline_processed_text_folder=/folder/to/save/processed/dataset ...)

其中/folder/to/save/processed/dataset为 Step 2 中--save-folder指定的路径。

修改后 config 中 LlavaDataset 的完整形态

以仓库中 QLoRA 微调配置(llava_internlm2_chat_7b_qlora_clip_vit_large_p14_336_lora_e1_gpu8_finetune.py)为例,修改后llava_dataset大致为:

llava_dataset = dict( type=LLaVADataset, offline_processed_text_folder='/folder/to/save/processed/dataset', image_folder=image_folder, image_processor=image_processor, dataset_map_fn=llava_map_fn, template_map_fn=dict( type=template_map_fn_factory, template=prompt_template), max_length=max_length, pad_image_to_square=True)

源码层面的行为说明

从 llava.py 中LLaVADataset.__init__的实现可以看到,构造时通过assert offline_processed_text_folder or (data_path and tokenizer)保证两种数据来源至少指定其一:

  • 当设置了offline_processed_text_folder时,直接调用load_from_disk(offline_processed_text_folder)加载文本数据,不再执行data_path加载与process_hf_dataset分词流程,这正是节省启动时间的关键;
  • 若同时设置了offline_processed_text_folderdata_path,源码会打印一条 WARNING,提示将优先从offline_processed_text_folder加载数据(if offline_processed_text_folder and data_path:分支);
  • 图片的加载在__getitem__中按需完成:根据text_data中的image字段,通过Image.open(os.path.join(self.image_folder, image_file))读取并交给image_processor预处理为pixel_values;没有图片的样本则填充全零张量。因此 config 中的image_folder必须保留并指向真实图片目录。

此外,LLaVADataset.modality_length属性(用于LengthGroupedSampler的长度分组采样)同样基于text_data计算,离线加载后依然正常工作。

Step 4:开始训练

使用 Step 3 修改得到的 config 直接训练即可。以预训练 config(llava_internlm2_chat_7b_clip_vit_large_p14_336_e1_gpu8_pretrain.py)为例:

# 单卡 xtuner train llava_internlm2_chat_7b_clip_vit_large_p14_336_e1_gpu8_pretrain_copy.py --deepspeed deepspeed_zero2 # 多卡(torchrun) NPROC_PER_NODE=${GPU_NUM} xtuner train llava_internlm2_chat_7b_clip_vit_large_p14_336_e1_gpu8_pretrain_copy.py --deepspeed deepspeed_zero2 # 多卡(slurm) srun ${SRUN_ARGS} xtuner train llava_internlm2_chat_7b_clip_vit_large_p14_336_e1_gpu8_pretrain_copy.py --launcher slurm --deepspeed deepspeed_zero2

其中--deepspeed deepspeed_zero2指定使用 DeepSpeed ZeRO-2 策略,对应配置见 xtuner/configs/deepspeed 目录(可选deepspeed_zero1deepspeed_zero2deepspeed_zero3及对应的 offload 版本)。训练启动后,数据加载阶段将直接读取磁盘上的预处理结果,不再执行耗时的大规模分词。

注意事项

  • 切换 tokenizer 或修改数据处理超参数后必须重新离线处理:离线数据是"某个 tokenizer + 某组超参数"下的产物。若更换了llm_name_or_path(tokenizer 随之变化),或调整了单条数据的最大长度max_lengthdataset_map_fntemplate_map_fn等,都必须重新执行 Step 2,否则直接训练会因 token 序列与配置不匹配而报错;
  • image_folder仍需保留:离线处理仅覆盖文本部分,训练时图片依旧按image_folder实时加载,因此该目录路径不能删除或改动;
  • 磁盘占用save_to_disk以 Arrow 格式落盘,数据量极大时注意预留足够的磁盘空间;
  • 与纯文本模型的差异:纯语言模型数据集的离线处理使用另一脚本xtuner/tools/process_untokenized_datasets.py,其会额外生成*_modified.py配置文件并自动改写train_dataloader.dataset;而 Llava 场景的process_untokenized_llava_data.py仅负责保存文本数据,config 的改写需要按 Step 3 手动完成。两者的处理对象与流程不同,使用时应加以区分。

【免费下载链接】xtunerA Next-Generation Training Engine Built for Ultra-Large MoE Models项目地址: https://gitcode.com/GitHub_Trending/xt/xtuner

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询