ms-swift多模态数据准备:自定义数据集格式说明

在使用 ms-swift 进行多模态大模型微调时,数据是起点,更是成败的关键。你可能已经成功下载了 Qwen3-VL 或 InternVL3.5 这样的先进模型,也配置好了 A100 或 H100 环境,但一旦运行训练命令却报出 KeyError: 'image'ValueError: unsupported modality,问题往往不出在模型或硬件,而在于——你的数据集没有按 ms-swift 的“语言”说话。

这不是文档缺失导致的困惑,而是框架对多模态数据结构有明确、统一且可扩展的约定。它不强制你用某种数据库或云存储,也不要求你重写整个预处理流水线;它只要求你用一种清晰、稳定、机器可解析的方式描述:“这张图要配哪段文字”、“这段语音对应哪个答案”、“这个框选区域想表达什么”。

本文将完全聚焦于 “如何组织自己的多模态数据” 这一具体动作,不讲原理推导,不堆砌参数列表,只提供可立即验证、可直接复用、经生产环境反复打磨的数据格式规范。你会看到:

  • 为什么 JSONL 是 ms-swift 多模态数据的事实标准;
  • 图像、视频、音频、文本、坐标框等不同模态字段该怎么命名、怎么填值;
  • 如何支持单模态输入、双模态组合、甚至四模态混合(图文+语音+视频);
  • 怎样让同一个数据集既可用于 SFT,也能无缝切到 DPO 或 GRPO 训练;
  • 常见陷阱与绕过方案:路径错误、编码异常、字段缺失、尺寸越界等真实问题。

读完后,你将能独立构建一个符合 ms-swift 要求的本地多模态数据集,并用一行命令启动训练。


1. 核心原则:字段驱动,路径为本,结构即协议

ms-swift 对自定义数据集的设计哲学非常务实:它不解析原始二进制数据,只解析数据描述。换句话说,框架从不直接打开一张 JPG 或 WAV 文件,而是读取你提供的 JSONL 行中关于该文件的“元信息”,再由内部加载器按需拉取、解码、归一化。

因此,所有数据准备工作的核心,就是写出一份字段语义准确、路径指向可靠、结构层次合理的文本描述。

1.1 为什么首选 JSONL(每行一个 JSON)

  • 流式加载:训练时无需一次性载入全部数据到内存,适合百万级样本;
  • 容错性强:某一行 JSON 格式错误,仅跳过该样本,不影响整体训练;
  • 字段灵活:每行可包含不同模态组合(如第1行只有 image+text,第2行含 image+audio+boxes),框架自动适配;
  • 工具链成熟:可用 jq、Python jsonlines、Pandas read_json(..., lines=True) 快速校验与清洗;
  • 不推荐:JSON(单个大对象)、CSV(无法自然表达嵌套结构如 conversations)、Parquet(虽支持但调试成本高,初学者易卡在 schema 定义)。

1.2 字段命名不是随意的:必须与 ms-swift 内置解析器对齐

ms-swift 在 swift.dataset 模块中预定义了一组标准字段名。当你在数据中使用这些字段时,框架会自动触发对应模态的加载逻辑。命名错误 = 模态被忽略 = 训练退化为纯文本任务

以下是必须掌握的 7 个核心字段(区分大小写,不可缩写):

字段名 类型 说明 示例值
image strlist[str] 单张图像路径(相对或绝对),支持本地路径、HTTP URL、ModelScope 资源 ID "data/images/cat.jpg""https://example.com/dog.png"
video str 视频文件路径(MP4/AVI/WebM),框架自动抽帧并采样关键帧 "data/videos/meeting.mp4"
audio str 音频文件路径(WAV/MP3/FLAC),支持单声道/立体声,自动重采样至 16kHz "data/audio/question.wav"
text str 主干文本输入,用于指令微调或作为上下文锚点 "请描述这张图片的内容。"
conversations list[dict] 多轮对话结构,每轮含 role("user"/"assistant")和 content(支持 <img> 等模态标记) [{"role":"user","content":"<img>这是什么动物?"},{"role":"assistant","content":"这是一只橘猫。"}]
boxes list[list[float]] 归一化边界框坐标 [x1, y1, x2, y2](0~1 范围),用于 grounding 任务 [[0.2, 0.3, 0.8, 0.7]]
labels list[str] 分类标签或细粒度描述,常与 boxes 配合使用 ["cat", "furry"]

重要提示conversations 是唯一支持内联模态标记的字段。你在 content 中写的 <img><audio> 不是字符串,而是 ms-swift 的“模态占位符”,会被自动替换为对应图像/音频的 embedding 序列。而 imageaudio 等顶层字段,仅用于单模态任务或作为 conversations 的补充元信息。

1.3 路径规则:本地优先,绝对可靠

  • 所有路径(image/video/audio)默认以 数据集文件所在目录为根
    例如你的数据文件是 ./my_mm_data.jsonl,其中一行写 "image": "imgs/pic1.jpg",则框架会尝试加载 ./imgs/pic1.jpg
  • 支持 file:// 协议前缀(显式声明本地路径):"image": "file:///home/user/data/pic.jpg"
  • 支持 HTTP/HTTPS:"image": "https://cdn.example.com/photo.jpg"(需网络可达,首次加载稍慢);
  • 不支持:相对路径跨目录回溯(如 "../other/img.jpg")、Windows 驱动器盘符裸写("C:\data\img.jpg")、未转义空格("my pic.jpg" → 应写为 "my%20pic.jpg""my pic.jpg" 并确保文件系统支持)。

2. 四种典型数据组织方式:从简单到复杂

你不需要一开始就设计最复杂的格式。ms-swift 允许你从最简结构起步,随着任务演进逐步增强。以下四种模式覆盖 95% 的实际场景。

2.1 单图 + 单文本:VQA / Captioning 基础版

适用于图像问答、图像描述生成等任务。结构最轻量,调试最快。

{
  "image": "images/beach.jpg",
  "text": "这张图片展示了什么场景?"
}

或更贴近对话形式(推荐,兼容性更好):

{
  "image": "images/beach.jpg",
  "conversations": [
    {"role": "user", "content": "这张图片展示了什么场景?"},
    {"role": "assistant", "content": "一片阳光明媚的海滩,有蓝色海水、白色沙滩和几把彩色遮阳伞。"}
  ]
}

优势:字段少,易生成,swift sft 命令开箱即用
注意:若只用 text 字段而无 conversations,则不会触发多模态对齐,模型仅将图像路径当作文本字符串处理

2.2 多图 + 多轮对话:图文交互式 Agent

适用于需要连续理解多张图像并进行多步推理的场景,如电商导购、医疗报告分析。

{
  "image": ["images/xray1.jpg", "images/xray2.jpg"],
  "conversations": [
    {"role": "user", "content": "<img><img>请对比这两张X光片,指出差异。"},
    {"role": "assistant", "content": "第一张显示左肺下叶有模糊阴影,第二张该区域密度增高,提示炎症进展。"}
  ]
}

关键点

  • image 字段支持 list[str],框架会依次加载并拼接 embedding;
  • <img> 标记数量必须与 image 列表长度一致(两个 <img> → 两张图);
  • 可混用:"content": "<img>这是什么?<img>另一张呢?",实现精准位置绑定。

2.3 图文 + 音频 + 坐标框:细粒度指代定位(Grounding)

适用于需要模型精确定位并描述图像中特定区域的任务,如工业质检、教育辅导。

{
  "image": "images/circuit.jpg",
  "audio": "audios/instruction.wav",
  "boxes": [[0.15, 0.22, 0.45, 0.68], [0.62, 0.10, 0.92, 0.40]],
  "labels": ["defective capacitor", "normal resistor"],
  "conversations": [
    {"role": "user", "content": "<img><audio>请检查红色框内的元件状态。"},
    {"role": "assistant", "content": "红色框内是一个失效的电容,顶部已鼓包;绿色框内电阻外观正常。"}
  ]
}

🔧 技术细节

  • boxes 中每个子列表必须是 4 个浮点数,顺序为 [x_min, y_min, x_max, y_max],值域 0.0 ~ 1.0
  • boxeslabels 长度不等,框架会截断或填充 "",但强烈建议严格一一对应;
  • <audio> 标记会触发 Whisper 编码器,输出与图像 patch 同维度的序列,参与跨模态注意力。

2.4 四模态混合:视频 + 图像 + 文本 + 语音(高级研究场景)

面向前沿探索,如多传感器自动驾驶日志分析、沉浸式教育内容生成。

{
  "video": "videos/driving.mp4",
  "image": "images/dashboard.jpg",
  "audio": "audios/voice_command.wav",
  "text": "当前车速60km/h,前方30米有施工区域,请减速并变道。",
  "conversations": [
    {"role": "user", "content": "<video><img><audio>根据画面、仪表盘截图和语音指令,生成安全操作建议。"},
    {"role": "assistant", "content": "请立即松开油门,轻踩刹车将车速降至40km/h以下,并观察左侧车道确认安全后平稳变道。"}
  ]
}

注意事项

  • videoimage 可共存,但 video 会主导视觉输入(自动抽关键帧),image 作为辅助参考;
  • 所有模态标记 <video> <img> <audio> 必须在 conversations.content 中显式声明,否则不会参与建模;
  • 此类样本训练显存占用显著增加,建议搭配 --max_length 4096 和梯度累积。

3. 数据集构建实操指南:三步完成验证

理论终需落地。下面以一个真实可运行的案例,带你走完从零创建到命令行验证的全过程。

3.1 第一步:准备最小可行数据集(3 行 JSONL)

创建文件 demo_mm.jsonl,内容如下(请确保 images/ 目录下存在对应图片):

{"image": "images/cat.jpg", "conversations": [{"role": "user", "content": "<img>这是什么动物?"}, {"role": "assistant", "content": "一只橘猫。"}]}
{"image": "images/dog.jpg", "conversations": [{"role": "user", "content": "<img>这只狗在做什么?"}, {"role": "assistant", "content": "它正坐在草地上吐舌头。"}]}
{"image": "images/bird.jpg", "conversations": [{"role": "user", "content": "<img>这只鸟的羽毛是什么颜色?"}, {"role": "assistant", "content": "主要是蓝绿色,翅膀边缘带黑色条纹。"}]}

验证命令(检查 JSONL 格式):

# Linux/macOS
jq -e '.image and .conversations' demo_mm.jsonl > /dev/null && echo " 格式正确" || echo " 有错误"

3.2 第二步:编写训练命令并启动(单卡快速验证)

使用轻量模型 Qwen2-VL-2B(约 2GB 显存占用),避免资源瓶颈:

CUDA_VISIBLE_DEVICES=0 swift sft \
    --model qwen-vl-chat \
    --dataset ./demo_mm.jsonl \
    --train_type lora \
    --lora_rank 8 \
    --per_device_train_batch_size 1 \
    --gradient_accumulation_steps 4 \
    --learning_rate 1e-4 \
    --num_train_epochs 0.1 \
    --max_length 2048 \
    --output_dir ./output_demo \
    --logging_steps 1 \
    --save_steps 10 \
    --eval_steps 10 \
    --torch_dtype bfloat16

关键参数说明

  • --dataset ./demo_mm.jsonl:指定本地 JSONL 路径,框架自动识别为多模态;
  • --model qwen-vl-chat:必须使用支持多模态的模型 ID(不能用纯文本模型如 qwen2-7b);
  • --max_length 2048:多模态输入 token 更长,需适当增大上限;
  • --logging_steps 1:设为 1 便于第一时间观察是否成功加载图像。

成功标志:日志中出现类似
Loading image from: ./images/cat.jpg
Loaded 3 samples from ./demo_mm.jsonl
Starting training...

3.3 第三步:排查常见失败原因(附解决方案)

现象 可能原因 快速诊断命令 解决方案
FileNotFoundError: images/cat.jpg 路径相对于 JSONL 文件不正确 ls -l ./images/cat.jpg 使用 realpath 检查路径,或改用绝对路径 "image": "/full/path/to/cat.jpg"
KeyError: 'image' JSONL 行中缺少 image 字段 head -n1 demo_mm.jsonl | jq '.image' 确保每行都含 image(即使为空数组 [],但不推荐)
ValueError: invalid literal for int() boxes 中含非数字字符或空字符串 jq -r '.boxes[] | join(",")' demo_mm.jsonl 用 Python 脚本清洗:boxes = [[float(x) for x in box] for box in boxes]
日志无 Loading image 提示 模型未启用多模态分支 swift list-models | grep -i vl 确认 --model 参数值正确,如 qwen-vl-chat 而非 qwen2-7b
训练 loss 不下降 conversations 中未使用 <img> 标记 jq -r '.conversations[].content' demo_mm.jsonl "content": "这是什么?" 改为 "content": "<img>这是什么?"

4. 进阶技巧:让数据集更健壮、更高效

当你已能稳定运行基础训练,可引入以下技巧提升工程鲁棒性与实验效率。

4.1 数据分片与缓存:加速千万级数据加载

对超大数据集(>100 万样本),直接读 JSONL 仍可能成为 I/O 瓶颈。ms-swift 支持 .parquet 格式,其列式存储与内置压缩可提速 3~5 倍。

转换脚本(Python):

import pandas as pd
import jsonlines

# 读取 JSONL
with jsonlines.open('large_mm.jsonl') as reader:
    records = [obj for obj in reader]

# 转为 DataFrame(自动处理 list 字段)
df = pd.DataFrame(records)
# Parquet 会将 list 序列化为 string,但 ms-swift 加载器可自动反序列化
df.to_parquet('large_mm.parquet', index=False, compression='zstd')

训练时直接使用:

swift sft --dataset ./large_mm.parquet ...

优势:文件体积减小 60%,随机采样速度提升,支持 Spark/Dask 分布式预处理。

4.2 动态字段注入:同一份数据适配多种任务

你无需为 SFT、DPO、GRPO 分别准备三套数据。通过 conversations 结构微调,一份 JSONL 可复用:

  • SFT 格式(监督微调):

    {"conversations": [{"role":"user","content":"<img>描述一下"},{"role":"assistant","content":"一只猫。"}]}
    
  • DPO 格式(偏好学习):

    {
      "conversations": [{"role":"user","content":"<img>描述一下"}],
      "chosen": "一只橘猫蹲在窗台上,毛发蓬松。",
      "rejected": "猫。"
    }
    
  • GRPO 格式(强化学习):

    {
      "conversations": [{"role":"user","content":"<img>描述一下"}],
      "response": "一只橘猫蹲在窗台上,毛发蓬松。",
      "reward": 0.92
    }
    

ms-swift 的 Dataset 加载器会自动检测字段存在性,并路由到对应任务处理器。你只需在命令中指定 --rlhf_type dpo--rlhf_type grpo,数据逻辑完全解耦。

4.3 模态缺失容错:优雅降级策略

现实数据总有缺失。ms-swift 允许你定义 fallback 行为:

  • image 字段为空或文件不存在,默认跳过该样本(--drop_invalid true,默认开启);
  • audio 缺失,但 conversations.content<audio>,则静音向量替代(不影响训练);
  • 最佳实践:预处理脚本中添加完整性检查:
from PIL import Image
import os

def validate_sample(sample):
    if 'image' in sample and isinstance(sample['image'], str):
        return os.path.exists(sample['image']) and Image.open(sample['image']).size[0] > 0
    return True  # 其他模态暂不强校验

5. 总结:数据即契约,格式即生产力

在 ms-swift 的多模态工作流中,数据集不是训练的“输入”,而是你与框架之间的一份隐式契约。这份契约规定了:

  • 你承诺提供哪些模态(image/video/audio);
  • 你承诺如何组织它们(conversations 中的 <img> 顺序);
  • 你承诺字段值的语义(boxes 是归一化坐标,不是像素值);
  • 框架承诺据此加载、对齐、融合,并端到端优化。

遵守这份契约,你获得的是:
一次写好,多任务复用(SFT/DPO/GRPO);
本地调试与集群训练无缝切换;
新增模态(如 3D 点云、传感器信号)只需扩展字段与加载器;
团队协作时,数据格式即文档,无需口头解释。

反之,若绕过格式规范,试图用 hack 方式“骗过”框架,最终只会陷入无限 debug 循环——因为问题不在代码,而在你与框架的沟通失效。

所以,请把本文当作一份可执行的数据协议说明书。下次准备数据时,先打开 VS Code,新建 my_dataset.jsonl,对照本文的字段表与示例,逐行填写。运行 swift sft,看到 Loading image... 的日志那一刻,你就真正掌握了 ms-swift 多模态能力的第一把钥匙。


获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐