3、数据准备与预处理:多模态数据集格式与对齐策略

数据准备这件事,说实话,是VLA模型训练里最容易被低估的环节。我见过太多团队花几个月调模型,最后发现是数据格式出了问题——图像和文本对不上,动作序列标注有偏差,训练出来的模型像个“睁眼瞎”。

今天我们就来聊聊多模态数据到底该怎么准备。我会把我在多个项目中踩过的坑、总结的经验,一次性讲清楚。

3.1 多模态数据集格式:三种主流方案

多模态数据存储,说白了就是要把图像、文本、动作序列这些不同类型的数据,塞进一个统一的容器里。目前主流的有三种格式:JSON、HDF5、TFRecord。我个人的习惯是:小规模实验用JSON,大规模训练用HDF5或TFRecord。

3.1.1 JSON格式:灵活但别滥用

JSON的好处是直观,人类可读。但坏处也很明显——文件大了以后,加载速度慢得让人抓狂。

{
  "dataset_name": "vla_robot_arm",
  "samples": [
    {
      "image_path": "data/images/001.jpg",
      "text": "将红色方块放到蓝色盒子里",
      "actions": [
        {"joint_angles": [0.1, 0.2, 0.3, 0.4, 0.5, 0.6], "gripper": 0.0},
        {"joint_angles": [0.2, 0.3, 0.4, 0.5, 0.6, 0.7], "gripper": 0.5}
      ],
      "metadata": {
        "task_id": "pick_place_001",
        "timestamp": 1234567890
      }
    }
  ]
}
注意: 我曾经在一个项目中用JSON存了10万条数据,结果每次加载要花5分钟。后来改成HDF5,加载时间降到了10秒。所以,数据量超过1万条,就别用JSON了。

3.1.2 HDF5格式:大规模数据的首选

HDF5是我个人最推荐的格式。它支持分层存储,可以高效地读取部分数据,不用一次性加载全部。

import h5py
import numpy as np

# 创建HDF5文件
with h5py.File('vla_dataset.h5', 'w') as f:
    # 创建组
    grp = f.create_group('sample_001')
    
    # 存储图像(RGB格式)
    grp.create_dataset('image', data=np.random.rand(224, 224, 3))
    
    # 存储文本(需要编码)
    grp.create_dataset('text', data="将红色方块放到蓝色盒子里".encode('utf-8'))
    
    # 存储动作序列
    grp.create_dataset('actions', data=np.random.rand(10, 7))  # 10个时间步,7维动作
    
    # 存储元数据
    grp.attrs['task_id'] = 'pick_place_001'
    grp.attrs['timestamp'] = 1234567890
小技巧: 用HDF5时,建议把图像数据压缩存储。我一般用gzip压缩级别4,压缩比大概3:1,读取速度影响不大。

3.1.3 TFRecord格式:TensorFlow生态的标配

如果你用TensorFlow,TFRecord是绕不开的。它的优势在于和TF的数据管道无缝集成,支持高效的并行读取。

import tensorflow as tf

def serialize_example(image, text, actions):
    feature = {
        'image': tf.train.Feature(bytes_list=tf.train.BytesList(value=[image.tobytes()])),
        'text': tf.train.Feature(bytes_list=tf.train.BytesList(value=[text.encode('utf-8')])),
        'actions': tf.train.Feature(float_list=tf.train.FloatList(value=actions.flatten())),
        'action_shape': tf.train.Feature(int64_list=tf.train.Int64List(value=actions.shape))
    }
    example = tf.train.Example(features=tf.train.Features(feature=feature))
    return example.SerializeToString()

# 写入TFRecord
with tf.io.TFRecordWriter('vla_dataset.tfrecord') as writer:
    for i in range(1000):
        example = serialize_example(
            image=np.random.rand(224, 224, 3).astype(np.float32),
            text="将红色方块放到蓝色盒子里",
            actions=np.random.rand(10, 7).astype(np.float32)
        )
        writer.write(example)

3.2 图像与文本对齐:别让模型“看错话”

图像和文本的对齐,说白了就是确保模型看到的图像和它读到的文本描述的是同一件事。这个问题看似简单,但实际项目中经常出问题。

我记得有一次,数据标注员把图像文件名和文本描述搞混了,结果模型训练了三天,loss死活降不下去。后来一查,发现30%的数据对不齐。

3.2.1 对齐策略

  • 时间戳对齐: 如果数据是实时采集的,用时间戳做对齐是最可靠的。我一般用微秒级的时间戳,避免精度问题。
  • 帧号对齐: 对于视频数据,用帧号对齐更直观。但要注意帧率变化,我曾经遇到过相机掉帧导致对齐错位的情况。
  • 语义对齐: 用CLIP等模型做语义匹配,检查图像和文本是否描述同一场景。这个方法适合做数据清洗。
核心原则: 对齐的粒度要细。图像和文本的对齐误差不要超过1帧(约33ms),否则模型会学到错误的关联。

3.3 动作序列标注:机器人动作的“语言”

动作序列标注,是VLA模型训练中最费时费力的环节。你需要把机器人的每个动作都标注清楚,包括关节角度、末端执行器位置、夹爪状态等。

3.3.1 标注格式

字段 类型 说明
timestamp float 时间戳(秒)
joint_angles float[6] 6个关节的角度(弧度)
gripper float 夹爪开合度(0.0~1.0)
ee_pose float[7] 末端执行器位姿(位置+四元数)
action_type int 动作类型(0:移动, 1:抓取, 2:放置)
# 动作序列标注示例
action_sequence = [
    {
        "timestamp": 0.0,
        "joint_angles": [0.1, 0.2, 0.3, 0.4, 0.5, 0.6],
        "gripper": 0.0,
        "ee_pose": [0.5, 0.3, 0.2, 0.0, 0.0, 0.0, 1.0],
        "action_type": 0  # 移动
    },
    {
        "timestamp": 0.5,
        "joint_angles": [0.2, 0.3, 0.4, 0.5, 0.6, 0.7],
        "gripper": 0.5,
        "ee_pose": [0.6, 0.4, 0.3, 0.0, 0.0, 0.0, 1.0],
        "action_type": 1  # 抓取
    }
]
避坑指南: 我曾经在标注时忽略了夹爪状态的连续性。比如抓取动作,夹爪从0.0到1.0需要时间,如果标注成瞬间变化,模型学到的动作会非常生硬。建议用插值方式标注过渡帧。

3.4 数据增强策略:让模型更“皮实”

数据增强,说白了就是给模型制造“困难”。你想想看,如果训练数据全是完美光照、标准角度,模型到了真实环境肯定抓瞎。

3.4.1 图像增强

  • 颜色抖动: 调整亮度、对比度、饱和度。我一般用0.2的幅度,太大反而会破坏语义信息。
  • 随机裁剪: 从原图中随机裁剪224x224的区域。注意不要裁掉关键物体。
  • 高斯噪声: 模拟传感器噪声。我习惯用均值为0、标准差为0.01的噪声。
  • 随机擦除: 随机遮挡图像的一部分,强迫模型关注全局特征。

3.4.2 文本增强

  • 同义词替换: 把“放置”换成“摆放”、“放好”。注意不要改变动作语义。
  • 语序调整: “将红色方块放到蓝色盒子里” -> “把红色方块放进蓝色盒子”。
  • 随机删除: 随机删除10%的词语,模拟语音识别错误。

3.4.3 动作序列增强

  • 时间缩放: 把动作序列的时间轴拉伸或压缩。我一般用0.8~1.2的缩放因子。
  • 动作抖动: 在关节角度上添加小幅度噪声(标准差0.01弧度)。
  • 轨迹平滑: 用Savitzky-Golay滤波器平滑动作轨迹,去除高频噪声。
我的经验: 数据增强不是越多越好。我曾经在一个项目里用了10种增强策略,结果模型训练时间翻了三倍,效果只提升了2%。建议先选3~5种最有效的,再逐步增加。

3.5 知识体系总览

下面这张图,是我对本章知识体系的总结。你可以把它当作一个检查清单,看看自己有没有遗漏什么。

多模态数据准备与预处理知识体系 数据准备与预处理 数据集格式 JSON(小规模实验) HDF5(大规模首选) TFRecord(TF生态) 图像与文本对齐 时间戳对齐 帧号对齐 语义对齐(CLIP) 动作序列标注 关节角度标注 末端执行器位姿 夹爪状态连续性 数据增强策略 图像增强 文本增强 动作序列增强 核心原则:格式统一、对齐精确、增强适度 数据质量决定模型上限,预处理决定训练效率

嗯,到这里,数据准备与预处理的核心内容就讲完了。说实话,这部分工作很琐碎,但真的值得花时间做好。我见过太多项目因为数据问题翻车,最后不得不返工。

记住一句话:数据质量决定模型上限,预处理决定训练效率。把这两件事做好了,后面的模型训练会顺畅很多。

专注资料整理