GR00T N1 数据工程实录:88 小时遥操作如何裂变成 78 万条轨迹——潜动作标注、神经轨迹、DexMimicGen 三条产线的完整拆解
本文以数据工程师的视角,拆解 GR00T N1 的训练数据是怎么从无到有生产出来的。所有数字均出自论文正文与附录,代码与数据样例对照官方仓库 Isaac-GR00T。最后一节回到启元 Q1。
一、先看账本:GR00T N1 的数据资产负债表
GR00T N1 论文有一个基本判断:具身智能的瓶颈不在模型架构,而在数据——互联网上不存在"机器人行为"的语料库。模型侧它的答案是双系统(VLM 理解场景,Flow-Matching DiT 生成动作),但真正让这套架构跑起来的,是数据侧一条覆盖三层的数据生产线——这也是本文的主角。做数据工程,第一步是把账算清楚。GR00T N1 的全部训练数据可以列成一张表:
| 数据资产 | 数量 | 折算时长 | 生产成本 | 来源 |
|---|---|---|---|---|
| 真机遥操作数据(GR-1) | — | 88 小时 | 人工遥操作,20Hz 采集 | 自建团队 |
| 神经轨迹(视频生成) | ~30 万条 | 827 小时 | 10.5 万 L40 GPU 时 | 视频模型生成 |
| 仿真轨迹(DexMimicGen) | 78 万条 | 6,500 小时 | 11 小时挂机生成 | 物理仿真 |
| 人类视频(无动作标签) | — | 数十万小时级 | 数据集整理 | Ego4D 等 7 个公开集 |
| Open X-Embodiment | — | — | 公开集整合 | RT-1/Bridge-v2/DROID 等 |
| AgiBot-Alpha | 14 万条 | — | 公开集 | 智元 100 台机器人 |
两个数字值得停下来想一想:
6,500 小时 / 11 小时。DexMimicGen 用 11 个小时,把几十条人类演示自动扩展成了 78 万条仿真轨迹——折算下来等于一个人类演示员不吃不喝连续录 9 个月。这就是论文里合成数据的杠杆率。
88 小时 → 827 小时。神经轨迹这条路用视频生成模型做同样的事:拿 88 小时真机数据微调一个图生视频模型,再从已有初始帧出发生成"反事实"轨迹(换个物体、换个放置位置),数据量直接 10 倍。
真机数据是最贵的(人工遥操作),但它是锚点——所有合成数据的质量都靠它兜底。
二、底层:没有动作标签的人类视频怎么进训练集
2.1 问题定义
Ego4D、EPIC-KITCHENS 这些数据集有几十万小时的人类第一视角操作视频,是机器人最想要的"行为先验"。但它们只有一个致命问题:视频里只有画面,没有动作标注。你不知道人在操作时手臂的关节角是多少。
GR00T N1 的解法分两步:先用 VQ-VAE 把"画面变化"翻译成"潜动作",再把潜动作当作一种虚拟机型的动作标签直接进训练。
2.2 潜动作提取:VQ-VAE 的实现逻辑
论文对模型结构的描述很简洁:编码器吃连续两帧,吐出离散潜动作;解码器拿潜动作加当前帧,重建未来帧。
# 潜动作 VQ-VAEclassLatentActionVQVAE(nn.Module):""" 训练目标:给定 (x_t, x_{t+H}),让模型学会把"画面发生了什么变化" 压缩成一个离散 code z_t,并用 (z_t, x_t) 重建 x_{t+H} """def__init__(self,codebook_size):self.encoder=VideoEncoder()# 输入当前帧+未来帧self.codebook=nn.Embedding(codebook_size,d_latent)# 离散码本self.decoder=FrameDecoder()# 输入潜动作+当前帧defencode(self,x_t,x_future,H):z_cont=self.encoder(x_t,x_future)# 连续潜变量z_t=quantize_nearest(z_cont,self.codebook)# VQ 量化为离散码returnz_tdefforward(self,x_t,x_future,H):z_t=self.encode(x_t,x_future,H)x_recon=self.decoder(z_t,x_t)# z_t + 当前帧 -> 未来帧returnvqvae_loss(x_recon,x_future,z_cont,z_t)# 训练完成后,编码器即"逆动力学模型":# 输入任意两帧,输出潜动作标签,供策略预训练使用deflabel_video_with_latent_actions(vqvae,video,H):return[vqvae.encode(video[t],video[t+H],H)fortinrange(0,len(video)-H)]这里最巧妙的设计是把潜动作当成一个独立机型(论文称 LAPA embodiment)。策略模型不需要知道"潜动作"和"真机动作"的区别,它们在训练管道里地位完全相同——一个统一了所有数据源的动作接口。
2.3 潜动作真的跨机型一致吗
论文 Figure 4 给了一个很有说服力的验证:在 8 种不同机型(含人类)的视频里检索相似潜动作,同一个"潜动作 1"在所有机型上对应的都是"右臂向左移",“潜动作 2"对应的都是"右臂向右移”。
潜空间自己学出了"移动方向"这种与具体机体无关的运动语义。这就是跨机型训练能 work 的根基。
三、中层(上):神经轨迹——用视频模型"脑补"反事实数据
3.1 生产流水线全流程
神经轨迹的完整生产流程,我按论文 Sec 2.2 和附录 F 的描述整理成流水线:
# 神经轨迹生产流水线defneural_trajectory_pipeline(real_teleop_data):# Stage 1: 微调图生视频模型# 真实数据: 3000 条样本, 480P, 81 帧/条, 带语言标注video_model=finetune_img2vid_model(real_teleop_data,epochs=100)# Stage 2: 生成新任务指令# 用多模态 LLM 检测初始帧中的物体,枚举物理合理的组合forinitial_frameincollect_initial_frames(real_teleop_data):objects=mllm.detect_objects(initial_frame)prompts=mllm.generate_combinations(template="pick up {obj} from {src} to {dst}",objects=objects,constraint="only physically feasible combinations")# Stage 3: 生成视频(2 分钟 L40 时间生成 1 秒视频)forpromptinprompts:video=video_model.generate(initial_frame,prompt)# Stage 4: 质量过滤——多模态 LLM 当裁判keyframes=downsample(video,n=8)ifnotmllm.judge_follows_instruction(keyframes,prompt):continue# 滤掉不听指令的caption=mllm.recaption(video)# 重新生成高质量标注# Stage 5: 动作标注(两条路)latent_actions=vqvae.label(video)# 路线 A: 潜动作pseudo_actions=idm.predict(video)# 路线 B: 逆动力学模型伪动作yieldTrainingSample(video,caption,latent_actions,pseudo_actions)3.2 三个工程细节
细节一:指令多样性是"编"出来的。生成模型自己不会想"我该生成什么任务",多样性完全靠 Stage 2 的 LLM 组合枚举——检测初始帧里有什么物体,然后按"把 X 从 A 拿到 B"的模板穷举物理合理的组合。左hand改右手、盘子换篮子,一条真机数据就这样裂变成几十条合成数据。
细节二:质量过滤靠"AI 裁判"。生成视频最大的坑是模型不严格遵守指令(让它拿黄瓜它拿了苹果)。论文的做法是降采样 8 帧喂给另一个多模态 LLM 判卷,不合格的直接丢弃,合格的用 LLM 重新标注(recaption)。整条流水线没有人工质检环节——这个规模(30 万条)也确实没法人工质检。
细节三:生成成本要算总账。L40 上 2 分钟生成 1 秒视频,827 小时视频 = 105,000 L40 GPU 时,用 3600 块 L40 并行跑了约 1.5 天。折算云成本大约 15-30 万美元。贵吗?对比人工遥操作每小时真机数据的成本(设备折旧 + 操作员工时 + 数据管理),这个价格反而便宜——而且是一次性投入。
四、中层(下):仿真轨迹——DexMimicGen 的自动扩展
仿真这条线的核心工具是 DexMimicGen(NVIDIA 参与的开源项目)。它的原理可以概括为"演示切割 + 物体对齐 + 自动重放":
# DexMimicGen 数据扩展原理defdexmimicgen_expand(few_human_demos,simulator):# 1) 演示切割:把完整演示拆成以物体为中心的子任务片段segments=[]fordemoinfew_human_demos:segments+=segment_by_object(demo)# "抓苹果"是一段,"开抽屉"是另一段# 2) 环境随机化:新场景里物体位置随机摆放fornew_envinrandomize_scenes(simulator,n_scenes=10000):forseginsegments:# 3) 片段变换:保持"末端执行器-物体"相对位姿,把片段# 适配到新环境中物体的新位置transformed=transform_segment(seg,align_to=new_env.objects[seg.target_object])# 4) 插值衔接 + 逐步重放 + 成功校验replay_with_interpolation(simulator,transformed,verify_success=True)# 只有校验成功的轨迹才入库"只保留成功轨迹"这一步很关键——仿真里校验成功的标准是确定的(物体进了目标容器没有),所以仿真数据天然带高质量标签,这也是它和神经轨迹最大的区别:仿真给的是有真值动作的数据,神经轨迹给的只有伪标签。
任务体系上,仿真数据基于 RoboCasa 框架构建,任务形式统一为"把 A 从 B 重排到 C",覆盖 54 种容器组合,每种组合生成 1 万条演示,合计 54 万条(预训练部分;加上后训练共 78 万条)。
五、顶层:88 小时真机数据是怎么采集的
顶层数据量最小,但采集工程反而最重。论文列了三套遥操作方案:
| 方案 | 硬件 | 捕捉内容 | 定位 |
|---|---|---|---|
| 方案一 | Manus Glove + VIVE Ultimate Tracker | 腕部 6-DoF + 手指骨架 | 高精度主力方案 |
| 方案二 | Apple Vision Pro | 头显 + 手势 | 消费级备选 |
| 方案三 | Leap Motion | 腕部 6-DoF + 手指 | 仿真数据采集用 |
采集流程:操作员穿戴设备 → 实时动作捕捉 → 逆运动学重定向到 GR-1 全身 IK 控制器 → 20Hz 控制频率执行 → 同时记录头部相机图像 + 人体本体感知 + 动作序列。标注分两层:细粒度(抓取/移动/放置等原子动作)和粗粒度(高层任务描述),分层标注支撑了策略同时学"精确运动控制"和"高层任务推理"。
六、混合训练:三层数据怎么"下锅"
数据生产完,最后一道工序是混合。论文 Table 1 给出了每类数据适用的标注技术,我转译成一张操作矩阵:
| 数据类型 | 潜动作标注 | 神经轨迹扩展 | 仿真扩展 |
|---|---|---|---|
| 真机数据 | 可用 | 可用 | 可用 |
| 仿真数据 | 可用 | 可用 | — |
| 人类视频 | 可用 | — | — |
预训练时跨三层混合采样,后训练时针对单一机型微调,并探索了"真实数据 : 神经轨迹 = 1:1"的混合比例。
混合这件事在官方仓库里有一套完整的工程实现,三个关键环节都能在代码里找到:
环节一:多数据集加权采样。训练入口脚本 examples/finetune.sh 提供了数据混合的调度参数:
# examples/finetune.shGLOBAL_BATCH_SIZE="${GLOBAL_BATCH_SIZE:-32}"SHARD_SIZE="${SHARD_SIZE:-1024}"NUM_SHARDS_PER_EPOCH="${NUM_SHARDS_PER_EPOCH:-100000}"EPISODE_SAMPLING_RATE="${EPISODE_SAMPLING_RATE:-0.1}"# 单 episode 被采到的概率DS_WEIGHTS_ALPHA="${DS_WEIGHTS_ALPHA:-}"# 多数据集采样权重dataset_path 参数本身接受 os.pathsep 分隔的多个数据集根目录(gr00t/configs/finetune_config.py),配合 DS_WEIGHTS_ALPHA 控制每个数据集在混合桶里的占比——论文里"三层混合采样"落到工程上就是这几个旋钮。
环节二:跨数据集统计量合并。不同数据集的状态/动作分布不同,归一化参数必须合并计算。真实实现(gr00t/data/dataset/sharded_mixture_dataset.py):
defmerge_statistics(per_dataset_stats,dataset_sampling_weights,...):"""按采样权重合并多数据集统计量,公式: Var_combined = Σ(w_i * (σ_i² + μ_i²)) - (Σ(w_i * μ_i))² """dataset_sampling_weights=np.array(dataset_sampling_weights)normalized_weights=dataset_sampling_weights/dataset_sampling_weights.sum()# ...... 加权合并 mean/std,跨数据集取全局 min/max/q01/q99 ......。一个容易被忽略的细节:mean/std 按权重加权,但 q01/q99 是跨数据集取 min/max 包络——保证任何一条数据归一化后都不会超出 [0,1] 区间。
环节三:归一化分位数。数据统计默认用 1%/99% 分位数而不是绝对极值(gr00t/data/stats.py):
q01=np.quantile(np_data,0.01,axis=0).tolist(),q99=np.quantile(np_data,0.99,axis=0).tolist(),遥操作数据里总有几帧异常抖动,用绝对 min/max 归一化会把有效信号压得很窄;分位数归一化是机器人数据管线的标配——Q1 将来做数据管线,这一条直接抄。
数据策略的实验回报。论文的消融实验验证了这套体系每一环的含金量:后训练混入神经轨迹,RoboCasa 30/100/300 演示档分别提升 +4.2%/+8.8%/+6.8%,中等数据档收益最大;真机 10% 数据档平均提升 +5.8%。这套体系养出来的模型,仿真三基准平均成功率 45.0%、真机 13 任务平均 76.8%,均为同数据量对比中的最优;而整座数据金字塔最终兑成的总账是:只用 10% 真机数据(42.6%)几乎追平 Diffusion Policy 全量数据的成绩(46.4%)。数据生产体系的杠杆,在实验上是被验证过的杠杆。
七、启元 Q1 的数据工程开工清单
把 GR00T N1 的数据方法论压到 Q1 的尺度,我的判断是:Q1 的数据金字塔不需要 GR00T N1 的量级,但需要同样的结构。
对照开工清单:
第一优先级:把"规则"转成"数据"(现在就能做)
Q1 每个技能包的 JSON 配置(motions、emotion_id、led、lines)本身就是结构化的行为描述。把技能包的执行过程录制成"图像 + 语言指令 + 动作序列"三元组,现有鼓励/早安/倒计时三个技能立即变成种子数据。这是 Q1 手里唯一零成本的数据资产,不录就浪费了。
录的时候格式别自己发明,直接对齐 GR00T 的 LeRobot 格式——仓库自带了一个标准样例 demo_data/cube_to_bowl_5,目录结构是三层:
cube_to_bowl_5/ ├── data/chunk-000/episode_000000.parquet# 状态+动作,每 episode 一个 parquet├── videos/chunk-000/observation.images.front/# 相机视频,每路一个目录└── meta/modality.json# 模态切片声明(关键)其中 modality.json 声明了状态/动作向量的切片方式:
{"state":{"single_arm":{"start":0,"end":5},"gripper":{"start":5,"end":6}},"action":{"single_arm":{"start":0,"end":5},"gripper":{"start":5,"end":6}},"video":{"front":{"original_key":"observation.images.front"},"wrist":{"original_key":"observation.images.wrist"}},"annotation":{"human.task_description":{"original_key":"task_index"}}}这套格式的价值在于"切片声明与数据分离":动作向量里哪几维是手臂、哪几维是夹爪,由 modality.json 声明而不是隐含在数据里,训练侧按声明切片组合。Q1 的技能包导出脚本只要落成这个格式,将来接 GR00T 后训练管线就是零改造。
第二优先级:仿真数据(1-2 个月)
Q1 只需仿真上肢动作,物理复杂度远低于 GR-1 全身灵巧手。用 Isaac Sim 搭 Q1 数字孪生,把"招手""比心"这类动作做成参数化任务(幅度、次数、时长可调),DexMimicGen 式的"演示切割 + 重放 + 成功校验"可以直接套用。目标量级:几十小时仿真数据就够后训练用。
第三优先级:遥操作设备选型(同步启动)
参考 GR00T N1 的三套方案,Q1 的合理选择是 Leap Motion(约几百元,捕捉上肢 + 手指,正好覆盖 Q1 的动作空间),不必上 VIVE + 数据手套的全身方案。
暂不建议碰的:人类视频预训练
潜动作预训练的收益来自海量数据,Q1 的场景太窄(上肢交互),直接在人类视频上做潜动作预训练的性价比不高。更务实的路线是等 Q1 仿真数据攒起来后,直接微调 GR00T N1 的开源权重——它的底层先验 NVIDIA 已经替你预训练好了。
一句话总结:GR00T N1 证明了"数据不够,工程来凑"是可行的——88 小时真机数据 + 视频生成 + 仿真扩展 + 潜动作标注,四件套把数据问题从"有没有"变成了"怎么生产"。Q1 要抄的不是数据本身,是这套生产体系。
论文信息
- GR00T N1: An Open Foundation Model for Generalist Humanoid Robots
- NVIDIA,2025 年 3 月
- arXiv:2503.14734
开源项目信息
- 项目地址:https://github.com/NVIDIA/Isaac-GR00T
- 项目定位:GR00T N1 系列基础模型的官方实现,Apache 2.0 协议
- 数据资产:仓库自带 5 个 LeRobot 格式演示数据集(demo_data/ 目录,含 parquet、相机视频与模态声明),格式规范见 getting_started/data_preparation.md
- 数据工具:统计量生成(gr00t/data/stats.py)、多数据集混合(sharded_mixture_dataset.py)、机型模态配置注册(gr00t/configs/data/embodiment_configs.py)
- 格式参考:本文引用的 modality.json 样例出自 demo_data/cube_to_bowl_5,可直接作为自建数据集的格式模板
访问启元机器人开发者社区,获取 SDK、仿真工具、开发文档,完成从代码仿真到真机落地的全流程开发:https://dev.primebot.com/