引言
GR00T N1 是 NVIDIA 于 2025 年 3 月发布的开源人形机器人基础模型,首次将视觉-语言-动作(Vision-Language-Action, VLA)架构应用于通用人形机器人领域1。该模型的核心创新在于双系统架构:一个慢速推理系统(VLM,10Hz)负责高层语义理解和任务规划,一个快速动作生成系统(Diffusion Transformer,120Hz)负责低层运动控制。这种设计分离了”思考”与”执行”,使机器人能够同时具备强大的泛化能力和实时控制能力。
核心架构:双系统设计
┌─────────────────────────────────────────────────────────────────────┐
│ GR00T N1 整体架构 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────────┐ │
│ │ 视觉输入 │ │ 语言指令 │ │ 本体感受 │ │
│ │ (多视角RGB) │ │ (文本) │ │ (关节状态/力矩) │ │
│ └──────┬───────┘ └──────┬───────┘ └──────────┬───────────┘ │
│ │ │ │ │
│ └────────────────────┼────────────────────────┘ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ Eagle-2 VLM │ System 1: 慢速推理 (10Hz) │
│ │ (视觉-语言模型) │ │
│ └────────┬────────┘ │
│ │ │
│ ┌────────▼────────┐ │
│ │ 隐式动作嵌入 │ Latent Action Embedding │
│ │ (Latent z) │ │
│ └────────┬────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Diffusion Transformer Action Head │ │
│ │ System 2: 快速动作生成 (120Hz) │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────────────┐ │ │
│ │ │噪声预测 │──│Temporal │──│FiLM │──│ 隐式动作解码 │ │ │
│ │ │网络 │ │Attention│ │调制 │ │ → 关节动作 │ │ │
│ │ └─────────┘ └─────────┘ └─────────┘ └─────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ 机器人执行 │ │
│ │ (关节控制信号) │ │
│ └─────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
系统 1:Eagle-2 VLM 推理模块(10Hz)
System 1 是基于 NVIDIA Eagle-2 视觉语言模型的推理引擎,运行频率为 10Hz,负责:
- 视觉感知:处理来自机器人头部/手部的多视角 RGB 图像,提取场景特征
- 语言理解:解析自然语言指令,提取任务目标、约束条件
- 隐式动作预测:基于视觉和语言输入,预测下一时刻的隐式动作嵌入
- 任务状态跟踪:维护任务进度,支持长程任务规划
VLM 模块的核心作用是将高维感知信息压缩为紧凑的语义表示,为动作生成提供高层意图指导。
系统 2:Diffusion Transformer 动作生成模块(120Hz)
System 2 是基于 Diffusion Transformer 的高速动作生成器,运行频率为 120Hz,负责:
- 动作去噪:从高斯噪声 开始,通过 步迭代去噪,生成隐式动作
- 时序建模:利用 Temporal Attention 机制捕捉动作序列的时间依赖关系
- 条件调制:接收 VLM 输出的隐式动作嵌入 作为条件信号,通过 FiLM(Feature-wise Linear Modulation)层进行特征调制
120Hz 的高频输出确保了动作的平滑性和响应速度,能够满足人形机器人实时控制的需求。
流匹配动作生成
问题定义
GR00T N1 采用流匹配(Flow Matching) 作为动作生成的核心算法。给定条件 (视觉、语言、隐式动作嵌入),目标是学习一个从噪声分布到数据分布的映射。
定义数据分布为 ,噪声分布为 。流匹配旨在学习一个向量场 ,使得概率路径 从 演化到 。
线性插值路径
采用最简单的线性插值路径:
其中:
- 是噪声样本
- 是目标动作
- 是时间步
对应的目标向量场为:
损失函数
训练目标是让神经网络 预测目标向量场:
推理过程:常微分方程求解
推理时,从噪声 开始,通过求解 ODE:
使用 Euler 方法或更高阶的 ODE 求解器进行离散化:
通常采用 步迭代即可获得高质量动作。
隐式动作学习(Latent Actions)
为什么需要隐式动作?
传统 VLA 模型直接预测高维关节动作空间 (例如 30~50 维),面临以下挑战:
- 数据异构性:不同机器人具有不同的关节数量和配置,直接预测面临跨具身泛化难题
- 时序一致性:短时动作序列需要保持平滑性和物理一致性
- 语义对齐:低层动作与高层语义意图之间存在语义鸿沟
隐式动作的定义
GR00T N1 引入隐式动作(Latent Actions) 的概念:
- 将高维关节动作 编码到低维隐式空间 (通常 )
- 隐式动作 捕捉的是”运动意图”而非具体关节位移
- 通过 VQ-VAE 或对比学习学习隐式动作表示
隐式动作的优势
| 方面 | 显式动作 | 隐式动作 |
|---|---|---|
| 跨具身泛化 | 困难(需重映射) | 优秀(语义级别对齐) |
| 动作平滑性 | 需额外后处理 | 隐式建模 |
| 表征能力 | 完整但冗余 | 紧凑但有信息损失 |
| 与 VLM 对齐 | 语义鸿沟大 | 自然对齐 |
学习方法
隐式动作通过以下两阶段学习:
阶段 1:预训练隐式动作编码器
从大规模机器人轨迹数据中学习编码器 :
或使用对比学习直接学习判别性隐式表示。
阶段 2:VLM + Diffusion 联合训练
VLM 模块预测隐式动作嵌入 ,Diffusion Transformer 在隐式空间中进行去噪,最后解码为具体动作:
数据金字塔策略
GR00T N1 的训练数据呈现明显的金字塔结构,体现了异构数据混合的策略:
┌─────────────────┐
│ 模拟数据 │ ← 金字塔顶层
│ (Synthetic) │ 数千万条轨迹
│ Physics Sim │
└────────┬────────┘
│
┌────────────────────────────────┼────────────────────────────────┐
│ 异构数据混合层 │
├────────────────────────────────┼────────────────────────────────┤
│ │ │
│ ┌─────────────┐ ┌─────────────┴─────────────┐ ┌─────────────┐│
│ │ 人类视频数据 │ │ 机器人演示数据 │ │ 运动捕捉数据 ││
│ │ (HumanVid) │ │ (Robot Demonstrations) │ │ (MoCap) ││
│ │ ARKitPose │ │ 真实机器人 + 遥操作 │ │ ││
│ │ EgoMotion │ │ │ │ ││
│ └─────────────┘ └────────────────────────────┘ └─────────────┘│
│ │ │
└────────────────────────────────┼────────────────────────────────┘
│
┌────────▼────────┐
│ 真实世界机器人数据 │ ← 金字塔底层
│ (Real Robot) │ 高质量但数量有限
│ 精细标注 + 反馈 │
└─────────────────┘
各层数据特点
| 数据层 | 来源 | 数量级 | 质量 | 成本 | 标注难度 |
|---|---|---|---|---|---|
| 真实机器人 | 遥操作收集 | 10K~100K 条 | ★★★★★ | 极高 | 低 |
| 运动捕捉 | MoCap 系统 | 100K~1M 条 | ★★★★☆ | 高 | 中 |
| 人类视频 | Ego4D, etc. | 1M~10M 条 | ★★★☆☆ | 低 | 高(需Pose提取) |
| 合成数据 | 物理引擎 | 10M+ 条 | ★★☆☆☆ | 极低 | 低 |
数据混合策略
GR00T N1 的关键洞察是合成数据与真实数据的协同效应:
在模拟轨迹和神经轨迹(真实数据)同时使用时,相比仅用真实数据,性能提升 40%1。
这说明合成数据不仅是真实数据的补充,更能提供互补的学习信号。
LAPA:人类视频动作标注
NVIDIA 提出的 LAPA(Large-scale Action Parsing from Videos) 管道可以从人类视频中自动生成动作标签:
- 利用预训练的姿态估计模型(e.g., ARKit, MediaPipe)提取人体姿态
- 通过逆运动学(IK)映射到机器人关节空间
- 在 11 小时内自动生成 780K 条轨迹
这一管道极大缓解了机器人数据稀缺的瓶颈。
与 GR00T N1.5 的区别
| 特性 | GR00T N1 | GR00T N1.5 |
|---|---|---|
| 发布时间 | 2025年3月 | 2025年6月 |
| 模型规模 | 2B 参数 | 约 2B~7B 参数 |
| 架构改进 | 基础双系统架构 | 优化 VLM + Action Head 耦合 |
| 训练数据 | 初期数据混合 | 大规模数据重筛选 |
| 推理频率 | 10Hz (VLM) / 120Hz (Action) | 保持相同 |
| 跨具身能力 | 初步验证 | 显著增强 |
| Sim-to-Real | 基础方案 | 改进域随机化 |
| Benchmark 表现 | 基线水平 | 显著提升 |
主要改进方向
GR00T N1.5 的改进集中在:
- 数据质量筛选:更精细的数据过滤和质量评估
- 架构微调:VLM 与 Diffusion Transformer 之间的信息流优化
- 训练稳定性:改进课程学习策略,平衡不同数据源的分布
- 长程任务:增强任务状态跟踪和子目标分解能力
PyTorch 伪代码实现
流匹配 Diffusion Transformer
import torch
import torch.nn as nn
import torch.nn.functional as F
from typing import Dict, Optional
class FlowMatchingTransformer(nn.Module):
"""
GR00T N1 的 Diffusion Transformer 动作生成模块
实现流匹配算法进行动作去噪
"""
def __init__(
self,
latent_dim: int = 32, # 隐式动作维度
action_dim: int = 39, # 实际关节动作维度
hidden_dim: int = 512,
num_heads: int = 8,
num_layers: int = 6,
noise_steps: int = 50, # 去噪步数
context_dim: int = 768, # VLM 上下文维度
):
super().__init__()
self.latent_dim = latent_dim
self.action_dim = action_dim
self.noise_steps = noise_steps
# 隐式动作解码器:z -> a
self.latent_to_action = nn.Sequential(
nn.Linear(latent_dim, hidden_dim),
nn.ReLU(),
nn.Linear(hidden_dim, hidden_dim),
nn.ReLU(),
nn.Linear(hidden_dim, action_dim)
)
# 时间步嵌入
self.time_emb = nn.Sequential(
nn.Linear(1, hidden_dim),
nn.SiLU(),
nn.Linear(hidden_dim, hidden_dim)
)
# 条件调制 (FiLM)
self.film_scale = nn.Linear(context_dim, hidden_dim)
self.film_shift = nn.Linear(context_dim, hidden_dim)
# Transformer 去噪网络
self.input_proj = nn.Linear(latent_dim + 1, hidden_dim) # +1 for time
encoder_layer = nn.TransformerEncoderLayer(
d_model=hidden_dim,
nhead=num_heads,
dim_feedforward=hidden_dim * 4,
dropout=0.1,
batch_first=True
)
self.transformer = nn.TransformerEncoder(encoder_layer, num_layers=num_layers)
# 输出预测网络
self.output_net = nn.Sequential(
nn.Linear(hidden_dim, hidden_dim),
nn.ReLU(),
nn.Linear(hidden_dim, latent_dim)
)
def vector_field(self, x: torch.Tensor, t: torch.Tensor, context: torch.Tensor) -> torch.Tensor:
"""
预测向量场 v(x, t, c)
Args:
x: 当前隐式动作 [B, T, latent_dim] T=时序长度
t: 时间步 [B, T, 1] 范围 [0, 1]
context: 条件上下文(VLM输出)[B, context_dim]
Returns:
预测的向量场 [B, T, latent_dim]
"""
B, T, D = x.shape
# 时间步嵌入
t_emb = self.time_emb(t) # [B, T, hidden_dim]
# FiLM 条件调制
scale = self.film_scale(context).unsqueeze(1) # [B, 1, hidden_dim]
shift = self.film_shift(context).unsqueeze(1) # [B, 1, hidden_dim]
# 输入投影 + 条件调制
h = self.input_proj(torch.cat([x, t], dim=-1)) # [B, T, hidden_dim]
h = h * (1 + scale) + shift
# Transformer 处理
h = self.transformer(h) # [B, T, hidden_dim]
# 输出向量场(预测目标值 a1 - a0)
v = self.output_net(h) # [B, T, latent_dim]
return v
def forward(self, batch: Dict[str, torch.Tensor]) -> Dict[str, torch.Tensor]:
"""
训练时的前向传播
Args:
batch: 包含以下键的字典
- 'latent_action': 目标隐式动作 [B, T, latent_dim]
- 'context': VLM 上下文 [B, context_dim]
- 'noise_level': 可选,固定的噪声水平
"""
latent_action = batch['latent_action'] # a_1
context = batch['context']
B, T, D = latent_action.shape
# 采样时间步 t ~ Uniform(0, 1)
t = torch.rand(B, 1, 1, device=latent_action.device)
# 采样噪声
noise = torch.randn_like(latent_action) # a_0
# 线性插值:a_t = (1-t)*a_0 + t*a_1
x_t = (1 - t) * noise + t * latent_action
# 预测向量场
v_pred = self.vector_field(x_t, t * torch.ones(B, T, 1, device=x_t.device), context)
# 目标向量场:v_target = a_1 - a_0
v_target = latent_action - noise
# MSE 损失
loss = F.mse_loss(v_pred, v_target)
return {'loss': loss}
@torch.no_grad()
def sample(
self,
context: torch.Tensor,
num_steps: Optional[int] = None,
ode_method: str = 'euler',
step_size: float = 0.1
) -> torch.Tensor:
"""
推理时的动作采样(ODE 求解)
Args:
context: VLM 上下文 [B, context_dim]
num_steps: 去噪步数(None 则用连续 ODE)
ode_method: ODE 求解方法 ('euler', 'midpoint')
step_size: 步长
Returns:
生成的隐式动作 [B, T, latent_dim]
"""
num_steps = num_steps or self.noise_steps
B = context.shape[0]
T = 1 # 单步生成
# 从噪声开始
x = torch.randn(B, T, self.latent_dim, device=context.device)
# 离散时间步
dt = 1.0 / num_steps
for i in range(num_steps):
t = torch.full((B, T, 1), i * dt, device=context.device)
# 预测向量场
v = self.vector_field(x, t, context)
# Euler 更新
x = x + dt * v
# 转换为实际动作
action = self.latent_to_action(x)
return action
class GR00T_N1(nn.Module):
"""
GR00T N1 完整模型
包含 VLM backbone 和 Diffusion Transformer action head
"""
def __init__(self, config: dict):
super().__init__()
# VLM backbone (Eagle-2)
self.vlm = self._build_vlm(config)
# Diffusion action head
self.action_head = FlowMatchingTransformer(
latent_dim=config.get('latent_dim', 32),
action_dim=config.get('action_dim', 39),
hidden_dim=config.get('hidden_dim', 512),
num_heads=config.get('num_heads', 8),
num_layers=config.get('num_layers', 6),
noise_steps=config.get('noise_steps', 50),
context_dim=config.get('context_dim', 768),
)
# 隐式动作编码器
self.latent_encoder = nn.Sequential(
nn.Linear(config.get('action_dim', 39), 256),
nn.ReLU(),
nn.Linear(256, 128),
nn.ReLU(),
nn.Linear(128, config.get('latent_dim', 32))
)
def _build_vlm(self, config: dict):
# 这里使用简化的 VLM 接口
# 实际使用 NVIDIA Eagle-2 或类似模型
from transformers import AutoModel
model = AutoModel.from_pretrained(config.get('vlm_ckpt', 'Eagle-2'))
return model
def forward(self, observations: Dict[str, torch.Tensor]) -> Dict[str, torch.Tensor]:
"""
完整前向传播
Args:
observations: 观测数据
- 'image': RGB 图像 [B, C, H, W]
- 'language': 语言指令 token IDs [B, L]
- 'proprio': 本体感受 [B, D_proprio]
Returns:
预测的动作 [B, action_dim]
"""
# Step 1: VLM 推理 (10Hz) - 提取高层语义
vlm_output = self.vlm(
pixel_values=observations['image'],
input_ids=observations['language'],
return_dict=True
)
# 提取隐式动作嵌入和上下文
latent_hint = vlm_output['latent_action'] # 隐式动作提示
context = vlm_output['multimodal_embedding'] # 多模态上下文
# Step 2: Diffusion 动作生成 (120Hz)
action_latent = self.action_head.sample(
context=context,
num_steps=20 # 可根据延迟要求调整
)
# Step 3: 隐式动作解码为实际动作
action = self.action_head.latent_to_action(action_latent)
return {'action': action, 'latent': latent_hint}
# 训练循环示例
def train_step(model: GR00T_N1, batch: dict, optimizer: torch.optim.Optimizer):
model.train()
# 前向传播
outputs = model(observations={
'image': batch['image'],
'language': batch['language'],
'proprio': batch['proprio']
})
# 计算流匹配损失
loss_dict = model.action_head({'latent_action': batch['latent_action'], 'context': outputs['context']})
loss = loss_dict['loss']
# 反向传播
optimizer.zero_grad()
loss.backward()
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
optimizer.step()
return {'loss': loss.item()}隐式动作编码器训练
class LatentActionVAE(nn.Module):
"""
隐式动作的 VQ-VAE 编码器
用于将高维关节动作压缩到低维隐式空间
"""
def __init__(self, action_dim: int = 39, latent_dim: int = 32, hidden_dim: int = 256):
super().__init__()
# 编码器
self.encoder = nn.Sequential(
nn.Linear(action_dim, hidden_dim),
nn.ReLU(),
nn.Linear(hidden_dim, hidden_dim),
nn.ReLU(),
nn.Linear(hidden_dim, latent_dim * 2) # 预测均值和方差
)
# 解码器
self.decoder = nn.Sequential(
nn.Linear(latent_dim, hidden_dim),
nn.ReLU(),
nn.Linear(hidden_dim, hidden_dim),
nn.ReLU(),
nn.Linear(hidden_dim, action_dim)
)
# VQ 层(可选)
self.codebook = nn.Embedding(num_embeddings=256, embedding_dim=latent_dim)
def reparameterize(self, mu: torch.Tensor, logvar: torch.Tensor) -> torch.Tensor:
std = torch.exp(0.5 * logvar)
eps = torch.randn_like(std)
return mu + eps * std
def forward(self, action: torch.Tensor) -> tuple:
"""
Args:
action: 原始关节动作 [B, action_dim]
Returns:
recon_action: 重构动作 [B, action_dim]
latent: 采样得到的隐式动作 [B, latent_dim]
mu, logvar: 分布参数
"""
# 编码
h = self.encoder(action)
mu, logvar = h.chunk(2, dim=-1)
# 重参数化
latent = self.reparameterize(mu, logvar)
# 解码
recon_action = self.decoder(latent)
return recon_action, latent, mu, logvar
def vae_loss(recon_action: torch.Tensor, action: torch.Tensor,
mu: torch.Tensor, logvar: torch.Tensor, beta: float = 0.01):
"""
VAE 损失函数
Args:
recon_action: 重构动作
action: 原始动作
mu, logvar: 潜在分布参数
beta: KL 散度权重
"""
# 重构损失
recon_loss = F.mse_loss(recon_action, action)
# KL 散度
kl_loss = -0.5 * torch.sum(1 + logvar - mu.pow(2) - logvar.exp())
return recon_loss + beta * kl_loss实验结果与消融分析
基准测试表现
GR00T N1 在多个标准基准上进行了评估:
| 基准 | 任务类型 | GR00T N1 | 最佳 Baseline | 提升 |
|---|---|---|---|---|
| LIBERO | 长期任务 | 72.3% | 65.1% | +7.2% |
| CALVIN | 长程操作 | 81.5% | 76.8% | +4.7% |
| Sim-to-Real | 域迁移 | 68.2% | 54.3% | +13.9% |
消融实验关键发现
-
双系统频率分离
- 固定频率(如 30Hz) vs 分离设计(10Hz VLM + 120Hz Action)
- 结果:分离设计在保持响应速度的同时,任务成功率提升 12%
-
隐式动作的作用
- 直接预测关节动作 vs 隐式动作 + 解码
- 结果:隐式动作使跨具身泛化能力提升 18%
-
数据金字塔的效果
- 仅真实数据 vs 混合合成数据
- 结果:混合训练使性能提升 40%
-
流匹配 vs DDPM
- 使用 DDPM(100步去噪)vs 流匹配(20步去噪)
- 结果:流匹配在 5倍推理加速 的同时,保持相近的动作质量
架构总结
GR00T N1 的核心设计哲学可以概括为:
“慢思考,快执行” —— 将复杂的语义推理(10Hz)与实时的动作控制(120Hz)解耦,实现既有泛化能力又有实时性的通用人形机器人控制。
这种双系统架构借鉴了人类认知的快慢系统理论:
- 系统 1(VLM):类似人类的直觉和经验判断,负责”理解要做什么”
- 系统 2(Diffusion):类似人类的精确运动控制,负责”怎么做”
通过隐式动作作为两个系统之间的桥梁,实现了语义层与执行层的有效连接。
参考资料
本文档基于 GR00T N1 论文(arXiv:2503.14734)撰写,内容持续更新中。