一、概述

Ψ₀(Psi-Zero)是南加州大学物理超智能实验室(USC PSI Lab)于2026年3月发布的开源人形机器人视觉-语言-动作(VLA)基础模型,相关论文发表于arXiv:2603.12263,并在RSS 2026会议上发表。12

核心创新点

特性描述
核心洞察正确的数据策略比数据量更重要
预训练数据800小时人类第一人称视频 + 30小时真实机器人交互
模型架构2.5B VLM + 700M MM-DiT动作专家
推理机制实时动作分块(RTC)
训练范式三阶段渐进式训练

Ψ₀的核心理念是:与其堆砌海量机器人数据,不如精心设计数据来源和训练策略。这一”less is more”的思想使其在仅使用约830小时数据的情况下,达到了与使用更多数据的竞品相当甚至更好的性能。

二、核心洞察:数据策略优先

2.1 传统方法的困境

过去的人形机器人VLA模型往往追求”数据为王”:

  • 收集百万级别的机器人轨迹数据
  • 投入大量计算资源进行大规模训练
  • 但泛化能力依然有限

2.2 Ψ₀的数据哲学

Ψ₀团队提出了一个关键洞察:数据来源的多样性比数据量更重要

┌─────────────────────────────────────────────────────────────┐
│                    Ψ₀ 数据策略                                │
├─────────────────────────────────────────────────────────────┤
│  800小时 人类第一人称视频                                     │
│  ├── 包含丰富的日常操作、导航、交互行为                         │
│  ├── 涵盖多样化的场景和任务                                    │
│  └── 学习人类的运动模式和意图理解                              │
├─────────────────────────────────────────────────────────────┤
│  + 30小时 真实机器人数据                                      │
│      └── 关键:建立人类动作到机器人动作的映射                   │
└─────────────────────────────────────────────────────────────┘

2.3 为什么这种方法有效?

  1. 跨具身迁移:人类视频中的操作知识天然具有多样性,可以泛化到不同的机器人形态
  2. 效率提升:800小时精心挑选的人类视频,胜过数百万条同质化的机器人轨迹
  3. 成本降低:数据采集成本显著降低,使小团队也能训练基础模型

三、三阶段训练流程

Ψ₀采用三阶段渐进式训练范式,逐步从通用视觉-语言理解过渡到人形机器人控制。

3.1 阶段总览

┌─────────────────────────────────────────────────────────────────────────┐
│                         Ψ₀ 三阶段训练流程                                │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  ┌─────────────┐     ┌─────────────┐     ┌─────────────┐              │
│  │  Stage 1    │     │  Stage 2    │     │  Stage 3    │              │
│  │  VLM预训练   │ ──▶ │  动作专家    │ ──▶ │  任务微调    │              │
│  │  (人类视频)  │     │  后训练     │     │            │              │
│  └─────────────┘     └─────────────┘     └─────────────┘              │
│       │                   │                   │                        │
│  ┌────┴────┐        ┌────┴────┐        ┌────┴────┐                    │
│  │  800h   │        │  800h   │        │ 任务相关  │                    │
│  │ 人类视频 │        │ + 30h   │        │ 少量数据  │                    │
│  └─────────┘        │ 机器人   │        └─────────┘                    │
│                     └─────────┘                                        │
│                                                                         │
│  输出: 2.5B VLM      输出: +700M MM-DiT   输出: 领域适配               │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

3.2 Stage 1: VLM预训练

目标:建立强大的视觉-语言基础理解能力

数据

  • 约800小时的自我中心(egocentric)人类视频
  • 来自多种场景:厨房、办公室、仓库、户外等
  • 涵盖丰富的操作任务:抓取、放置、推拉、旋转等

方法

  • 使用标准的VLM预训练范式
  • 训练视觉编码器与语言模型的联合表示
  • 学习图像-文本对齐的通用语义理解

核心价值

  • VLM习得了对人类动作的语义理解
  • 理解”做什么”(意图识别)
  • 为后续的动作生成奠定基础

3.3 Stage 2: 动作专家后训练

目标:将VLM的语义理解能力转化为动作生成能力

数据

  • Stage 1使用的800小时人类视频(保留语义知识)
  • 新增约30小时真实人形机器人交互数据
  • 关键桥梁:建立人类动作到机器人动作的映射

架构升级

┌─────────────────────────────────────────────────────────┐
│                    MM-DiT 动作专家                       │
│                                                         │
│   VLM语义特征 ──▶ ┌────────────────────┐               │
│                   │  Cross-Attention  │ ──▶ 动作序列  │
│   隐变量 z ──▶    │     (7层)          │               │
│                   └────────────────────┘               │
│                                                         │
│   使用Flow Matching生成连续动作                          │
└─────────────────────────────────────────────────────────┘

技术细节

  • 添加700M参数的MM-DiT(Multi-Modal DiT)作为动作专家
  • 使用Flow Matching而非传统扩散模型进行动作生成
  • 7层交叉注意力结构,融合VLM特征与隐变量

3.4 Stage 3: 任务微调

目标:适配特定任务场景

方法

  • 使用少量(任务相关的)高质量机器人数据
  • 保持模型泛化能力的同时提升任务性能
  • 可根据部署需求灵活调整

典型应用

  • 仓库物流任务
  • 家庭服务场景
  • 工业装配操作

四、MM-DiT架构详解

4.1 架构概述

MM-DiT(Multi-Modal Diffusion Transformer)是Ψ₀的动作生成核心模块。它在VLM的基础上添加了一个轻量级的动作生成头。

┌──────────────────────────────────────────────────────────────────┐
│                         MM-DiT 架构                              │
├──────────────────────────────────────────────────────────────────┤
│                                                                  │
│   输入表示                                                        │
│   ┌─────────────┐                                               │
│   │ VLM视觉特征  │  来自预训练VLM的深层表示                        │
│   │ Visual(F)   │                                               │
│   └──────┬──────┘                                               │
│          │                                                      │
│   ┌──────┴──────┐                                               │
│   │ Cross-Attn  │  Layer × 7                                    │
│   │ (Q, K, V)   │  Q = 动作查询                                  │
│   └──────┬──────┘  K,V = VLM特征                                │
│          │                                                      │
│   ┌──────┴──────┐                                               │
│   │  DiT Block  │  隐向量 z 的逐步变换                            │
│   │ (标准残差)  │                                               │
│   └──────┬──────┘                                               │
│          │                                                      │
│   ┌──────┴──────┐                                               │
│   │   输出层    │  生成 $a_t$ 动作向量                           │
│   │  Linear    │                                               │
│   └─────────────┘                                               │
│                                                                  │
└──────────────────────────────────────────────────────────────────┘

4.2 Flow Matching动作生成

Ψ₀采用Flow Matching进行连续动作的生成,这是一种比传统扩散模型更高效的方法。

核心思想

  • 定义从噪声 到数据 的概率路径
  • 学习一个向量场 来驱动这个过程
  • 通过ODE求解器从噪声生成动作

数学表述

其中:

  • :初始噪声
  • :目标动作序列
  • :时间步
  • :插值后的隐变量

4.3 与其他扩散方法的对比

方法特点优缺点
DDPM逐步去噪,训练稳定推理慢,需要多步迭代
DDIM加速采样质量略有下降
Flow Matching直接预测向量场推理效率高,生成质量好
rectified flow线性插值简化训练,简单高效

五、实时动作分块(RTC)机制

5.1 为什么需要RTC?

人形机器人的控制面临两个挑战:

  1. 反应速度:需要低延迟的实时响应
  2. 平滑性:避免动作抖动或不连贯

传统的VLA推理方式:

用户指令 ──▶ VLA推理(慢) ──▶ 执行动作 ──▶ 等待 ──▶ 下一个推理

这种串行方式的问题:

  • 推理延迟高(可能数百毫秒)
  • 动作之间可能不连贯
  • 实时性差

5.2 RTC核心思想

RTC(Real-Time Chunking)通过异步推理+动作分块解决上述问题:

┌─────────────────────────────────────────────────────────────────┐
│                    RTC 工作原理                                   │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  时间线 ──▶─────────────────────────────────────────────────────│
│                                                                  │
│  推理线程:  ┌─────┐     ┌─────┐     ┌─────┐                    │
│            │ P1  │ ──▶ │ P2  │ ──▶ │ P3  │ ...                │
│            └─────┘     └─────┘     └─────┘                    │
│              │           │           │                         │
│  执行线程:   │    ┌─────┘    ┌─────┘                         │
│            ▼    ▼          ▼                                  │
│  执行:    [A1] [A2] [A3] [A4] [A5] [A6] ...                   │
│            └─────┘       └─────┘                              │
│              chunk        chunk                                │
│                                                                  │
│  P1: 推理预测动作块 A1-A4                                       │
│  执行: 逐个执行已生成的动作                                       │
│  并行: 执行时同时推理下一个块                                     │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

5.3 关键技术细节

动作块结构

  • 每个块包含多个时间步的动作预测(如4-8步)
  • 块之间有重叠区域,用于平滑过渡
  • 使用”inpainting”机制处理重叠部分

异步流水线

  1. 主线程维护执行状态
  2. 推理线程异步生成下一个动作块
  3. 通过共享缓冲区传递预测结果
  4. 执行时跳过已执行的动作

延迟分析

指标传统方法RTC
感知延迟100ms100ms
推理延迟200ms200ms(隐藏)
执行频率10Hz30Hz
有效延迟300ms100ms

5.4 RTC伪代码

import torch
import threading
from collections import deque
 
class RealTimeChunking:
    """
    实时动作分块推理
    - 推理线程异步生成动作块
    - 主线程执行已生成的动作
    """
    
    def __init__(self, model, chunk_size=8, overlap=2, device='cuda'):
        self.model = model
        self.chunk_size = chunk_size      # 每个块的动作步数
        self.overlap = overlap              # 块之间的重叠步数
        self.device = device
        
        # 动作缓冲区(双缓冲)
        self.action_buffer = deque()
        self.lock = threading.Lock()
        
        # 控制信号
        self.stop_flag = threading.Event()
        self.new_chunk_event = threading.Event()
        
    @torch.no_grad()
    def inference_thread(self, obs_queue, command):
        """
        推理线程:持续生成动作块
        """
        # 初始化:生成第一个块
        obs = obs_queue.get()
        action_chunk = self._predict_chunk(obs, command, prev_actions=None)
        
        with self.lock:
            self.action_buffer.append(action_chunk)
        self.new_chunk_event.set()
        
        # 持续推理循环
        while not self.stop_flag.is_set():
            # 等待需要新推理的信号
            self.new_chunk_event.wait()
            self.new_chunk_event.clear()
            
            if self.stop_flag.is_set():
                break
                
            # 获取当前观察和前一个块的最后几个动作(用于重叠)
            obs = obs_queue.get()
            with self.lock:
                prev_chunk = self.action_buffer[-1]
                # 取最后overlap个动作作为条件
                prev_actions = prev_chunk[-self.overlap:]
            
            # 生成新块
            action_chunk = self._predict_chunk(
                obs, command, 
                prev_actions=prev_actions
            )
            
            with self.lock:
                self.action_buffer.append(action_chunk)
            
            self.new_chunk_event.set()
    
    def _predict_chunk(self, obs, command, prev_actions=None):
        """
        预测一个动作块(Flow Matching推理)
        """
        # 将观察编码为特征
        visual_feat = self.model.encode_vision(obs['image'])
        state_feat = self.model.encode_state(obs['state'])
        
        # 融合特征
        fused_feat = self.model.fuse_features(visual_feat, state_feat)
        
        # Flow Matching去噪
        if prev_actions is not None:
            # Inpainting模式:用已知动作作为条件
            noise = torch.randn(
                self.chunk_size, 
                self.model.action_dim, 
                device=self.device
            )
            actions = self._flow_matching_denoise(
                noise, fused_feat, command, 
                context_actions=prev_actions
            )
        else:
            # 正常模式:从纯噪声开始
            noise = torch.randn(
                self.chunk_size, 
                self.model.action_dim, 
                device=self.device
            )
            actions = self._flow_matching_denoise(
                noise, fused_feat, command
            )
        
        return actions
    
    def _flow_matching_denoise(self, noise, feat, command, context_actions=None):
        """
        Flow Matching 去噪过程
        """
        T = 1.0  # 起始时间
        dt = 0.1  # 时间步长
        z = noise
        
        while T > 0:
            # 预测向量场
            if context_actions is not None and T < 0.3:
                # 接近已知区域,使用插值
                vec_field = self.model.predict_vector_field(
                    z, feat, command, T,
                    context=context_actions
                )
            else:
                vec_field = self.model.predict_vector_field(z, feat, command, T)
            
            # Euler更新
            z = z - dt * vec_field
            T -= dt
        
        return z
    
    def execute_loop(self, obs_queue, action_executor):
        """
        执行主循环
        """
        pending_actions = []
        
        while not self.stop_flag.is_set():
            # 检查缓冲区
            with self.lock:
                while len(self.action_buffer) > 0 and len(pending_actions) == 0:
                    chunk = self.action_buffer.popleft()
                    # 第一个块完整使用,后续块跳过前overlap个
                    skip = self.overlap if len(pending_actions) > 0 else 0
                    pending_actions.extend(chunk[skip:].tolist())
            
            # 执行动作
            if len(pending_actions) > 0:
                action = pending_actions.pop(0)
                action_executor.execute(action)
                obs_queue.put(action_executor.get_observation())
                self.new_chunk_event.set()
            
            else:
                time.sleep(0.001)  # 避免CPU busy wait
    
    def run(self, obs_queue, action_executor, command):
        """
        启动RTC流水线
        """
        # 启动推理线程
        self.infer_thread = threading.Thread(
            target=self.inference_thread,
            args=(obs_queue, command)
        )
        self.infer_thread.start()
        
        # 主执行循环
        self.execute_loop(obs_queue, action_executor)

六、与GR00T N1的技术对比

GR00T N1是NVIDIA于2025年3月发布的人形机器人基础模型,两者有相似的目标但架构设计上有显著差异。

6.1 架构对比

维度Ψ₀GR00T N1
基础架构VLM + MM-DiT双系统(System 1 + System 2)
VLM规模2.5B未公开
动作专家700M Flow Matching扩散模型
动作表示连续值(Flow Matching)连续值(扩散)
数据策略800h人类视频 + 30h机器人大量机器人数据
泛化来源人类视频多样性机器人数据规模

6.2 设计哲学差异

┌─────────────────────────────────────────────────────────────────┐
│                     设计哲学对比                                  │
├────────────────────────────┬────────────────────────────────────┤
│           Ψ₀              │            GR00T N1                │
├────────────────────────────┼────────────────────────────────────┤
│                            │                                    │
│  人类视频 ──▶ 语义理解     │     机器人数据 ──▶ 动作模式          │
│      │                     │           │                        │
│      ▼                     │           ▼                        │
│  机器人数据 ──▶ 动作映射   │     规模 + 泛化                     │
│                            │                                    │
│  "正确的数据 > 数据量"     │     "数据为王"                      │
│                            │                                    │
│  优点: 数据成本低          │     优点: 直接针对机器人优化         │
│  优点: 泛化能力强          │     缺点: 数据采集成本高             │
│  缺点: 需要领域适配        │     缺点: 依赖大规模数据采集         │
│                            │                                    │
└────────────────────────────┴────────────────────────────────────┘

6.3 技术路线对比

Ψ₀的技术路线

  1. 数据来源:优先使用容易获取的人类视频
  2. 训练策略:三阶段渐进式,从通用到专用
  3. 泛化方式:通过人类视频的多样性实现跨场景泛化

GR00T N1的技术路线

  1. 数据来源:大量真实的机器人轨迹数据
  2. 训练策略:统一的大规模预训练
  3. 泛化方式:通过数据规模和多样性实现泛化

6.4 互补性分析

两者代表了两种不同的范式:

方面Ψ₀GR00T N1
数据效率⭐⭐⭐⭐⭐ 高⭐⭐⭐ 中
直接部署⭐⭐⭐ 中(需适配)⭐⭐⭐⭐⭐ 高
跨具身迁移⭐⭐⭐⭐⭐ 强⭐⭐⭐ 中
学术贡献⭐⭐⭐⭐⭐ 完整开源⭐⭐ 部分开源

七、数据效率分析

7.1 数据量对比

Ψ₀最引人注目的特点是其极高的数据效率:

模型数据量核心策略
Ψ₀~830小时800h人类视频 + 30h机器人
GR00T N1数万小时(估算)大量机器人数据
π0数千小时多种机器人数据混合
OpenVLA~100万条轨迹大规模机器人遥操作

7.2 为什么Ψ₀能如此高效?

1. 数据来源优化

数据价值密度比较:

1小时人类视频 ──▶ 包含 ~3600秒 × 多种场景 × 多种任务
1小时机器人数据 ──▶ 仅包含特定机器人、特定任务的固定轨迹

价值密度比:人类视频 ≈ 10-50倍于同质机器人数据

2. 跨具身学习的杠杆效应

人类视频中的知识具有天然的泛化性:

  • 视觉模式识别:任何场景
  • 动作意图理解:任何任务
  • 物理规律隐含:重力、摩擦、碰撞

这些知识可以直接迁移到人形机器人上。

3. 三阶段训练的价值

Stage 1: 学习"做什么"(语义)
Stage 2: 学习"怎么做"(动作映射)
Stage 3: 学习"做好"(任务优化)

每一阶段只使用必要的数据,避免信息浪费

7.3 效率提升的量化分析

假设任务性能与数据量的关系为对数关系:

其中:

  • :任务性能
  • :数据量
  • :任务相关常数

则:

数据量Ψ₀风格策略性能传统策略性能
100h80%60%
500h90%75%
1000h95%82%
10000h100%95%

关键发现:在相同数据量下,Ψ₀的数据策略可以实现接近10%的性能提升。

八、完整PyTorch实现框架

8.1 模型定义

import torch
import torch.nn as nn
from torch.nn import TransformerEncoder, TransformerEncoderLayer
import math
 
class Psi0Model(nn.Module):
    """
    Ψ₀: VLM + MM-DiT 人形机器人基础模型
    """
    
    def __init__(
        self,
        # VLM 配置
        vision_hidden_size=1024,
        lang_hidden_size=4096,
        vision_patch_size=14,
        num_vision_tokens=1024,
        
        # MM-DiT 配置
        mmdit_hidden_size=1024,
        mmdit_num_layers=7,
        mmdit_num_heads=16,
        
        # 动作配置
        action_dim=38,  # 人形机器人自由度
        chunk_size=8,   # 动作块大小
        
        # Flow Matching 配置
        num_denoise_steps=10,
    ):
        super().__init__()
        
        # 1. 视觉编码器
        self.vision_encoder = VisionEncoder(
            hidden_size=vision_hidden_size,
            patch_size=vision_patch_size,
        )
        
        # 2. 状态编码器(机器人关节状态)
        self.state_encoder = StateEncoder(
            input_dim=action_dim,
            hidden_size=vision_hidden_size,
        )
        
        # 3. 语言编码器
        self.lang_encoder = LangEncoder(
            hidden_size=lang_hidden_size,
        )
        
        # 4. 模态融合层
        self.modality_fusion = ModalityFusion(
            vision_size=vision_hidden_size,
            lang_size=lang_hidden_size,
            output_size=mmdit_hidden_size,
        )
        
        # 5. MM-DiT 动作专家
        self.mmdit = MMDitActionExpert(
            hidden_size=mmdit_hidden_size,
            num_layers=mmdit_num_layers,
            num_heads=mmdit_num_heads,
            action_dim=action_dim,
        )
        
        # 6. Flow Matching 参数
        self.num_denoise_steps = num_denoise_steps
        self.chunk_size = chunk_size
        self.action_dim = action_dim
        
    def encode_observations(self, images, states):
        """
        编码多模态观察
        """
        # 视觉特征
        visual_feat = self.vision_encoder(images)
        
        # 状态特征
        state_feat = self.state_encoder(states)
        
        # 融合视觉和状态
        fused = torch.cat([visual_feat, state_feat], dim=1)
        
        return fused
    
    def encode_language(self, input_ids, attention_mask):
        """
        编码语言指令
        """
        lang_feat = self.lang_encoder(input_ids, attention_mask)
        return lang_feat
    
    @torch.no_grad()
    def generate_actions(
        self, 
        images, 
        states, 
        input_ids, 
        attention_mask,
        num_steps=None,
    ):
        """
        使用Flow Matching生成动作
        """
        num_steps = num_steps or self.num_denoise_steps
        
        # 编码观察和语言
        obs_feat = self.encode_observations(images, states)
        lang_feat = self.encode_language(input_ids, attention_mask)
        
        # 合并为条件
        condition = torch.cat([obs_feat, lang_feat], dim=1)
        
        # 从纯噪声开始
        batch_size = images.shape[0]
        action_chunk = torch.randn(
            batch_size, 
            self.chunk_size, 
            self.action_dim,
            device=images.device,
            dtype=images.dtype,
        )
        
        # Flow Matching 去噪
        dt = 1.0 / num_steps
        t = 1.0
        
        while t > 0:
            # 预测向量场
            vec_field = self.mmdit(action_chunk, condition, t)
            
            # Euler更新
            action_chunk = action_chunk - dt * vec_field
            t -= dt
        
        return action_chunk
    
    def forward(self, images, states, input_ids, attention_mask, target_actions):
        """
        训练时的前向传播
        """
        # 编码观察和语言
        obs_feat = self.encode_observations(images, states)
        lang_feat = self.encode_language(input_ids, attention_mask)
        condition = torch.cat([obs_feat, lang_feat], dim=1)
        
        # Flow Matching 训练目标
        batch_size = images.shape[0]
        T = torch.rand(batch_size, device=images.device)
        
        # 采样插值时间点
        t_expanded = T.view(batch_size, 1, 1)
        noise = torch.randn_like(target_actions)
        interpolated = t_expanded * target_actions + (1 - t_expanded) * noise
        
        # 预测向量场
        pred_vec_field = self.mmdit(interpolated, condition, T)
        
        # 真实向量场
        true_vec_field = target_actions - noise
        
        # MSE损失
        loss = F.mse_loss(pred_vec_field, true_vec_field)
        
        return loss
 
 
class VisionEncoder(nn.Module):
    """视觉编码器(简化版ViT)"""
    
    def __init__(self, hidden_size=1024, patch_size=14):
        super().__init__()
        self.proj = nn.Conv2d(3, hidden_size, kernel_size=patch_size, stride=patch_size)
        self.pos_embed = nn.Parameter(torch.randn(1, 1024, hidden_size))
        
    def forward(self, x):
        # x: [B, 3, H, W]
        x = self.proj(x)  # [B, hidden, H', W']
        B, C, H, W = x.shape
        x = x.flatten(2).transpose(1, 2)  # [B, H'*W', C]
        x = x + self.pos_embed[:, :x.shape[1]]
        return x
 
 
class StateEncoder(nn.Module):
    """机器人状态编码器"""
    
    def __init__(self, input_dim=38, hidden_size=1024):
        super().__init__()
        self.encoder = nn.Sequential(
            nn.Linear(input_dim, hidden_size // 4),
            nn.GELU(),
            nn.Linear(hidden_size // 4, hidden_size),
        )
        
    def forward(self, x):
        return self.encoder(x).unsqueeze(1)
 
 
class MMDitActionExpert(nn.Module):
    """
    MM-DiT 动作专家
    使用交叉注意力融合VLM特征与隐变量
    """
    
    def __init__(self, hidden_size=1024, num_layers=7, num_heads=16, action_dim=38):
        super().__init__()
        
        # 输入投影
        self.action_proj = nn.Linear(action_dim, hidden_size)
        self.time_embed = nn.Sequential(
            nn.Linear(1, hidden_size),
            nn.SiLU(),
            nn.Linear(hidden_size, hidden_size),
        )
        
        # 交叉注意力层
        self.cross_attention_layers = nn.ModuleList([
            CrossAttentionBlock(hidden_size, num_heads)
            for _ in range(num_layers)
        ])
        
        # 自注意力层(可选,用于动作序列建模)
        self.self_attention_layers = nn.ModuleList([
            SelfAttentionBlock(hidden_size, num_heads)
            for _ in range(num_layers)
        ])
        
        # 输出投影
        self.out_proj = nn.Linear(hidden_size, action_dim)
        
        # LayerNorm
        self.norm1 = nn.LayerNorm(hidden_size)
        self.norm2 = nn.LayerNorm(hidden_size)
        
    def forward(self, action_seq, condition, t):
        """
        action_seq: [B, chunk_size, action_dim]
        condition: [B, seq_len, hidden_size] (VLM特征)
        t: [B] (时间步,0-1)
        """
        B = action_seq.shape[0]
        
        # 投影动作序列
        x = self.action_proj(action_seq)
        
        # 时间嵌入
        t_emb = self.time_embed(t.unsqueeze(-1))  # [B, hidden]
        t_emb = t_emb.unsqueeze(1)  # [B, 1, hidden]
        x = x + t_emb
        
        # 交替使用交叉注意力和自注意力
        for i in range(len(self.cross_attention_layers)):
            # 交叉注意力:融合VLM条件
            x = self.norm1(x)
            x = x + self.cross_attention_layers[i](x, condition)
            
            # 自注意力:建模动作序列
            x = self.norm2(x)
            x = x + self.self_attention_layers[i](x)
        
        # 输出动作
        out = self.out_proj(x)
        return out
 
 
class CrossAttentionBlock(nn.Module):
    """交叉注意力块"""
    
    def __init__(self, d_model, num_heads):
        super().__init__()
        self.attn = nn.MultiheadAttention(d_model, num_heads, batch_first=True)
        self.norm = nn.LayerNorm(d_model)
        
    def forward(self, x, context):
        # x: query, context: key, value
        attn_out, _ = self.attn(x, context, context)
        return self.norm(attn_out)
 
 
class SelfAttentionBlock(nn.Module):
    """自注意力块"""
    
    def __init__(self, d_model, num_heads):
        super().__init__()
        self.attn = nn.MultiheadAttention(d_model, num_heads, batch_first=True)
        self.norm = nn.LayerNorm(d_model)
        
    def forward(self, x):
        attn_out, _ = self.attn(x, x, x)
        return self.norm(attn_out)

8.2 训练循环

def train_psi0(
    model: Psi0Model,
    train_loader,
    optimizer,
    device,
    num_epochs=100,
    log_every=100,
):
    """
    Ψ₀训练循环
    """
    model.train()
    
    for epoch in range(num_epochs):
        total_loss = 0
        
        for batch_idx, batch in enumerate(train_loader):
            images = batch['images'].to(device)
            states = batch['states'].to(device)
            input_ids = batch['input_ids'].to(device)
            attention_mask = batch['attention_mask'].to(device)
            target_actions = batch['actions'].to(device)
            
            # 前向传播
            optimizer.zero_grad()
            loss = model(
                images, states, 
                input_ids, attention_mask,
                target_actions
            )
            
            # 反向传播
            loss.backward()
            torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
            optimizer.step()
            
            total_loss += loss.item()
            
            if batch_idx % log_every == 0:
                print(f"Epoch {epoch} | Batch {batch_idx} | Loss: {loss.item():.4f}")
        
        avg_loss = total_loss / len(train_loader)
        print(f"Epoch {epoch} Average Loss: {avg_loss:.4f}")

九、实验结果

9.1 基线对比

Ψ₀在多个基准测试上展现出色的性能:

任务Ψ₀GR00T N1π0
物体抓取92%90%88%
抽屉操作87%85%82%
移动导航95%93%90%
全身协调89%88%85%

9.2 泛化能力

Ψ₀展现出优秀的跨场景泛化能力:

  • 未见过的场景:在新环境中保持80%以上的成功率
  • 新物体:对未训练过物体的泛化达75%
  • 新指令:理解并执行训练集外语言指令

十、总结与展望

10.1 主要贡献

  1. 数据策略创新:证明正确的数据选择比单纯追求数据量更重要
  2. 三阶段训练范式:为通用人形机器人控制提供了可复用的训练框架
  3. MM-DiT架构:高效融合视觉-语言表示与动作生成
  4. RTC推理机制:实现低延迟、流畅的人形机器人控制

10.2 局限性

  • Stage 2需要少量高质量机器人数据
  • 对于极端精细操作任务可能需要额外微调
  • 目前主要针对特定人形机器人平台

10.3 未来方向

  • 扩展到更多人形机器人形态
  • 结合强化学习进行在线适应
  • 探索视频预训练的更大规模数据

参考资料

Footnotes

  1. Wei, S., Jing, H., Li, B., et al. (2026). Ψ₀: An Open Foundation Model Towards Universal Humanoid Loco-Manipulation. arXiv:2603.12263. USC Physical Superintelligence (PSI) Lab.

  2. Ψ₀ Project Page. https://psi-lab.ai/Psi0