Skip to the content.

第17章 长程规划与语言的作用:通向通用具身智能

原课程: Robots That Learn, UC Berkeley CS294-291, Spring 2026 本章基于 Lecture 12 (Final Lecture): Long-Horizon Planning and Language 精读论文:

本章定位: 本书的终章。前16章从生物力学、机构学、扩散模型、触觉感知、运动控制、RL、行为克隆、视觉模仿一路走来,完成了从”肢体的物理基础”到”低层技能学习”的知识链构建。本章抵达这条知识链的顶端——语言、推理与长程规划,回答机器人学最宏大的问题:如何构建一个能在开放世界中执行复杂多阶段任务的通用具身智能体?


一、本章概要

核心问题: 机器人学经历了从经典控制 (PID, LQR) 到数据驱动技能学习 (RL, BC) 的范式迁移。然而,前16章所建立的方法论面临一个共同边界:它们擅长学习短视距、单任务的技能——抓取杯子、打开抽屉、四足行走——却难以组合这些技能以完成长程多阶段任务(如”清理厨房”: 需要依次执行”捡起盘子→放入水槽→打开柜门→放入碗→擦拭台面→关闭柜门”)。本章回答三个层层递进的问题:

  1. 表征问题: 语言如何作为连接感知与行动的桥梁,使机器人理解开放世界的语义?(Vision-Language-Action 模型)
  2. 规模问题: 如何构建可扩展的评估基础设施,衡量策略在长尾分布上的泛化能力?(MolmoSpaces 生态系统)
  3. 规划问题: 如何将长程任务分解为子任务序列,并在执行层面实现鲁棒的闭环控制?(层次化推理与 Chain-of-Thought)

与前后章节的逻辑关系: 第8章 (动力学与控制) 建立了底层运动生成的数学基础,第10章 (视频世界模型) 构建了环境的内部表征,第11章 (RL) 和第12章 (BC) 提供了策略学习算法,第13章 (视觉模仿) 将感知融入技能学习。本章将这些组件编织为一个统一架构: VLA 模型将视觉 (vision)、语言 (language) 和动作 (action) 在同一个 Transformer 中融合,实现从高层语义指令到低层运动控制的端到端推理。

本章路线图:


二、核心概念与数学基础

2.1 Vision-Language-Action (VLA) 模型的形式化

VLA 模型是本章的核心方法论,代表了具身智能从”单模态控制”到”多模态推理”的范式跃迁。我们从其数学定义出发,逐层构建其全部组件。

2.1.1 VLA 的基本定义

VLA 模型的目标是学习一个从多模态观察到动作的条件分布。形式上,给定:

VLA 模型需要最大化:

\[\max_{\boldsymbol{\theta}} \mathbb{E}_{(\mathbf{a}_{t:t+H}, \mathbf{o}_t, \ell) \sim \mathcal{D}} \log \pi_{\boldsymbol{\theta}}(\mathbf{a}_{t:t+H} \mid \mathbf{o}_t, \ell)\]

其中 \(\mathcal{D}\) 是包含多种机器人平台、环境和任务的异构数据集。这个公式虽然简洁,但其实现涉及三个关键技术挑战:(1) 多模态 Token 化(如何将图像、文本、动作统一为同一序列),(2) 动作表示的连续 vs. 离散之辩,以及 (3) 层次化推理(如何将长程任务分解)。

2.1.2 多模态 Token 化与 Transformer 骨干

\(\pi_{0.5}\) 的架构遵循现代 VLM (Vision-Language Model) 的设计范式:不同模态的输入被各自的 tokenizer 映射到统一的嵌入空间,然后由一个大规模自回归 Transformer 处理。

记输入序列为 \(\mathbf{x}_{1:N}\),其中每个 token \(\mathbf{x}_i\) 可以是以下三种类型之一:

Token 类型 数学表示 编码方式
文本 token \(x_i^w \in \mathbb{N}\) 可学习嵌入矩阵 \(\mathbf{E} \in \mathbb{R}^{V \times d}\)
图像块 token \(x_i^I \in \mathbb{R}^{p \times p \times 3}\) 预训练视觉编码器 (SigLIP/ViT) \(\to\) 线性投影 \(\to \mathbb{R}^d\)
动作 token \(x_i^a \in \mathbb{R}^{d_a}\) 线性投影 \(\mathbf{W}_a \in \mathbb{R}^{d_a \times d}\)

Transformer 输出 \(\mathbf{y}_{1:N} = f(\mathbf{x}_{1:N}, \mathbf{A}(\mathbf{x}_{1:N}), \boldsymbol{\rho}(\mathbf{x}_{1:N}))\),其中 \(\mathbf{A}\) 是注意力掩码矩阵,\(\boldsymbol{\rho}\) 是 token 类型路由函数 (决定每个 token 由哪个 “expert” 权重处理)。

关键设计 — 注意力掩码: 与标准因果注意力不同,VLA 模型使用部分双向注意力:

这一设计的物理直觉: 图像和语言构成了”场景理解”,它们可以任意交互;动作生成是”从理解到执行的单向信息流”,因此信息只能从 VLM 流向 action expert,反之不行。

2.1.3 离散动作 + 连续动作的混合表示

\(\pi_{0.5}\) 的一个核心创新是将离散 token 训练的高效性与流匹配 (Flow Matching) 的连续表示精度结合。

阶段 1 — 预训练 (离散 token):

使用 FAST tokenizer [Pertsch et al., 2025] 将动作序列 \(\mathbf{a}_{t:t+H}\) 压缩为离散 token 序列。FAST 的核心思想是通过 VQ-VAE 风格的 vector quantization 将连续动作块压缩为短序列的离散 codes。训练目标为标准的交叉熵:

\[\mathcal{L}_{\text{pretrain}} = \mathbb{E}_{\mathcal{D}}\left[\sum_{m=1}^{M} \log \pi_{\boldsymbol{\theta}}(x_m^{\text{action}} \mid \mathbf{x}_{1:N}^{\text{prefix}}, x_{<m}^{\text{action}})\right]\]

其中 \(\mathbf{x}^{\text{prefix}}\) 包含图像、文本提示和本体感觉 token。这一阶段的优势在于:自回归离散 token 预测可以利用成熟的 LLM 训练基础设施,训练效率远高于连续扩散方法。

阶段 2 — 后训练 (流匹配连续动作):

在后训练阶段,引入一个较小的 action expert (约 300M 参数,独立于 VLM 骨干的 2B 参数),使用流匹配目标生成连续动作:

\[\mathcal{L}_{\text{flow}} = \mathbb{E}_{t, \boldsymbol{\omega}}\left[\|\boldsymbol{\omega} - \mathbf{a}_{t:t+H} - \mathbf{f}_{\boldsymbol{\theta}}^a(\mathbf{a}_{t:t+H}^{\tau, \boldsymbol{\omega}}, \mathbf{o}_t, \ell)\|^2\right]\]

其中:

流匹配的直觉: 在概率空间中,有一条从噪声分布(高斯)到数据分布(专家动作)的”最优传输路径”。Action expert 学习预测沿着这条路径的”速度场” \(\mathbf{v}(\mathbf{a}^{\tau}, \tau)\),使得从噪声出发,沿向量场积分 \(\tau: 0 \to 1\) 即可到达目标动作分布。

组合损失函数:

\[\mathcal{L} = \underbrace{H(\mathbf{x}_{1:M}^{\ell}, \mathbf{y}_{1:M}^{\ell})}_{\text{文本交叉熵 (含 FAST token)}} + \alpha \cdot \underbrace{\|\boldsymbol{\omega} - \mathbf{a}_{t:t+H} - \mathbf{f}_{\boldsymbol{\theta}}^a(\mathbf{a}_{t:t+H}^{\tau, \boldsymbol{\omega}}, \mathbf{o}_t, \ell)\|^2}_{\text{流匹配损失 (action expert)}}\]

其中 \(\alpha = 10.0\) 平衡两个损失的尺度。

2.1.4 层次化推理 — 从高层子任务到低层动作

\(\pi_{0.5}\) 的推理过程被分解为两个层次,遵循 Chain-of-Thought 范式:

\[\pi_{\boldsymbol{\theta}}(\mathbf{a}_{t:t+H}, \hat{\ell} \mid \mathbf{o}_t, \ell) = \underbrace{\pi_{\boldsymbol{\theta}}(\mathbf{a}_{t:t+H} \mid \mathbf{o}_t, \hat{\ell})}_{\text{低层动作推理}} \cdot \underbrace{\pi_{\boldsymbol{\theta}}(\hat{\ell} \mid \mathbf{o}_t, \ell)}_{\text{高层子任务推理}}\]

其中 \(\ell\) 是用户给定的高层指令(”清理厨房”),\(\hat{\ell}\) 是模型推断的子任务(”捡起盘子”)。

推理过程:

  1. Step 1 — 子任务推断: 视觉观察 \(\mathbf{o}_t\) 和任务指令 \(\ell\) 输入 VLM 骨干,自回归解码出文本子任务 \(\hat{\ell}\)(如”把杯子放进抽屉”)
  2. Step 2 — 动作生成: 以 \(\hat{\ell}\) 为条件,action expert 通过流匹配的 10 步去噪过程生成连续动作块 \(\mathbf{a}_{t:t+H}\)
  3. Step 3 — 执行与重规划: 执行前 \(K\) 步动作 (\(K < H\)),获取新观察,重新推断子任务(高频: 每 \(\sim\)0.5-1s;低频动作: 50Hz)

这种设计使同一个模型同时充当”规划器”(高层)和”控制器”(低层),避免了传统方法中分离式 LLM 规划器 + 独立低层策略的通信与延迟问题。

2.1.5 协同训练 (Co-Training) — 泛化能力的来源

\(\pi_{0.5}\) 的泛化能力源于其精心设计的异构数据协同训练配方。预训练阶段的数据构成:

数据源 缩写 规模 作用机制
移动操作机器人 MM \(\sim\)400小时, \(\sim\)100个家庭 核心任务相关的第一手经验
多环境非移动机器人 ME \(\sim\)2.4% (但覆盖更多家庭) 跨具身迁移 (不同手臂/底座)
实验室跨具身数据 CE 大量多样化桌面任务 技能多样性的广度
高层子任务预测 HL 人工标注的子任务描述 学习任务分解结构
多模态网络数据 WD 图像描述, VQA, 目标定位 开放世界语义知识
口头语言指令 VI 人类”语言遥操作”演示 高层规划行为的示范

关键发现: 97.6% 的预训练数据并非来自目标移动操作平台,但这些数据源对于泛化至关重要。消融实验显示,移除跨具身数据 (ME 或 CE) 会导致性能显著下降;移除网络数据 (WD) 则显著降低对未见物体类别的语言遵循能力。

泛化的缩放法则: 随着训练中不同家庭环境数量从 3 增加到 104,所有任务的性能单调提升。当模型看到 104 个不同环境时,其在全新测试家庭中的表现近似于直接在测试家庭上训练的模型——这表明充分的场景多样性训练可以弥合泛化差距。


2.2 空间推理的形式化

空间推理是具身智能的第二个核心支柱。如果说 VLA 模型解决了”理解指令并生成动作”的问题,空间推理解决的是”理解三维世界中的物体位置、关系和可操作性”。MolmoSpaces 为此提供了一个数学框架。

2.2.1 场景-物体-任务的形式化

定义具身智能的环境为:

\[\mathcal{E} = (\mathcal{S}, \mathcal{O}, \mathcal{R}, \mathcal{T}, \mathcal{C})\]

其中:

2.2.2 抓取的形式化定义

MolmoSpaces-Grasp 数据集中,每个抓取被定义为一个 6-DoF 位姿:

\[\mathbf{g} = (\mathbf{p}, \mathbf{R}) \in SE(3)\]

其中 \(\mathbf{p} \in \mathbb{R}^3\) 是夹爪中心位置,\(\mathbf{R} \in SO(3)\) 是夹爪朝向。抓取生成遵循对跖接触 (antipodal contact) 采样:

对跖接触对: \(\{(\mathbf{c}_1, \mathbf{n}_1), (\mathbf{c}_2, \mathbf{n}_2)\}\) 满足:

2.2.3 Sim-to-Real 相关性

空间推理的一个核心挑战是: 在仿真中表现良好的策略,在真实世界中也能成功吗?MolmoSpaces-Bench 的 Sim-to-Real 相关性通过 Pearson 相关系数和 Spearman 秩相关系数量化:

\[R = \frac{\text{Cov}(S_{\text{sim}}, S_{\text{real}})}{\sigma_{\text{sim}} \sigma_{\text{real}}}, \quad \rho = \frac{\text{Cov}(\text{rank}(S_{\text{sim}}), \text{rank}(S_{\text{real}}))}{\sigma_{\text{rank(sim)}} \sigma_{\text{rank(real)}}}\]

实验结果显示: 对于 Pick 任务,\(R = 0.96\), \(\rho = 0.98\)——这个极高的相关性验证了大规模仿真评估作为真实世界性能代理的有效性。

2.2.4 分布外评估的形式化

MolmoSpaces 的核心价值在于系统性地评估策略在分布偏移下的表现。定义分布偏移为对基准环境施加的受控扰动:

\[\mathcal{E}_{\text{perturbed}} = \Phi(\mathcal{E}_{\text{base}}; \boldsymbol{\delta})\]

其中 \(\boldsymbol{\delta}\) 是扰动参数向量,可以包括:

这一方法论揭示了一个关键发现: \(\pi_0\) (早期 VLA) 的泛化瓶颈主要来自语言条件组件 (language-conditioning component),而非动作头部 (action head)。当使用 DROID 数据集中高频动词序列时,\(\pi_0\) 的成功率与 \(\pi_{0.5}\) 差距仅 1%,但使用低频动词时差距扩大到 14%——这强调了训练数据中语言多样性的重要性。


2.3 长程规划 (Long-Horizon Planning)

长程规划是将前两节的技术栈——VLA 模型和空间推理——组合成完整任务执行链的方法论。本节形式化三种主流的规划范式。

2.3.1 Task and Motion Planning (TAMP) 的经典形式化

TAMP 将规划问题分解为两个耦合层次:

任务层 (离散): 在符号空间中搜索动作序列: \(\boldsymbol{\pi} = (a_1, a_2, \ldots, a_K), \quad a_k \in \mathcal{A}_{\text{symbolic}}\) 使得目标谓词 \(G\) 从初始状态 \(\mathbf{s}_0\) 可达。

运动层 (连续): 为每个符号动作 \(a_k\) 求解连续轨迹: \(\boldsymbol{\xi}_k: [0, T_k] \to \mathcal{C} \quad \text{s.t.} \quad \boldsymbol{\xi}_k(0) = \mathbf{q}_{\text{start}}^{(k)}, \; \boldsymbol{\xi}_k(T_k) = \mathbf{q}_{\text{goal}}^{(k)}\)

TAMP 的经典瓶颈在于: 符号规划器和运动规划器是分离的,一个层次的失败需要回溯到另一个层次,导致组合爆炸。VLA 模型通过将两个层次统一到同一个 Transformer 中,以端到端方式隐式地解决了这个问题。

2.3.2 LLM 驱动的任务分解

利用大语言模型 (LLM) 将高层自然语言指令分解为子任务序列:

\[\{\hat{\ell}_1, \hat{\ell}_2, \ldots, \hat{\ell}_K\} = \text{LLM}(\ell, \text{SceneDescription}(\mathbf{o}_t))\]

MolmoSpaces 的 LLM 长程任务生成器展示了这一范式:

  1. 从场景中提取物体位置、包围盒和空间关系
  2. 构造文本形式的场景描述
  3. LLM 生成可行的长程任务描述,例如”做一份沙拉” \(\to\) [Pick_Place(Tomato, Bowl), Open(Refrigerator), Pick_Place(Lettuce, Bowl)]

2.3.3 层次化强化学习 (Hierarchical RL)

层次化 RL 提供了第三种长程规划范式。高层策略 \(\pi^H(\hat{\ell} \mid \mathbf{s})\) 选择子目标,低层策略 \(\pi^L(\mathbf{a} \mid \mathbf{s}, \hat{\ell})\) 实现子目标。这与 \(\pi_{0.5}\) 的层次化推理在结构上完全对偶:

\[\underbrace{\pi^H(\hat{\ell} \mid \mathbf{o}_t, \ell)}_{\text{高层 VLM 推断子任务}} \;\longleftrightarrow\; \underbrace{\pi_{\boldsymbol{\theta}}(\hat{\ell} \mid \mathbf{o}_t, \ell)}_{\text{VLA 的高层推理}}\] \[\underbrace{\pi^L(\mathbf{a}_{t:t+H} \mid \mathbf{o}_t, \hat{\ell})}_{\text{低层控制器}} \;\longleftrightarrow\; \underbrace{\pi_{\boldsymbol{\theta}}(\mathbf{a}_{t:t+H} \mid \mathbf{o}_t, \hat{\ell})}_{\text{VLA 的低层动作生成}}\]

\(\pi_{0.5}\) 的关键创新在于: 不使用两个独立的神经网络,而是用同一个模型实现两层推理,通过不同的输出模态 (文本 vs. 连续动作) 和不同的 attention mask 自然地区分层次。


三、论文精读

3.1 \(\pi_{0.5}\): 开放世界泛化的 VLA 模型

论文: Physical Intelligence, “\(\pi_{0.5}\): a Vision-Language-Action Model with Open-World Generalization,” CoRL 2025

3.1.1 方法论核心

\(\pi_{0.5}\) 的方法论建立在三个支柱之上:

支柱 1 — 异构数据的协同训练: \(\pi_{0.5}\) 的设计哲学是”让模型从尽可能多样化的数据源中提取可迁移知识”。数据源包括: (i) 移动操作机器人在约 100 个真实家庭中采集的约 400 小时数据 (MM), (ii) 非移动机器人在更多家庭中采集的数据 (ME), (iii) 实验室环境下的跨具身数据 (CE), (iv) 人工标注的高层子任务 (HL), (v) 来自网络的多模态数据——图像描述、VQA、目标定位 (WD), (vi) 人类”语言遥操作”示范 (VI)。其泛化假说是: 通过在足够广泛的数据分布上训练,模型能在未见过的环境中组合这些知识以完成新任务。

支柱 2 — 两阶段训练: 预训练阶段 (280k 步) 使用离散 FAST token 做标准自回归训练;后训练阶段 (80k 步) 添加 flow matching action expert 生成连续动作。这种分离设计同时获得了离散训练的高效性(预训练)和连续表示的精度(后训练)。

支柱 3 — 层次化推理: 模型先推断子任务(如”捡起枕头”),再基于子任务生成低层动作。消融实验揭示了两个反直觉的发现:

3.1.2 关键实验结果

开放世界泛化: \(\pi_{0.5}\) 能在训练中从未见过的真实家庭中执行 10-15 分钟的长程清洁任务(清理厨房、收拾卧室),包括”把衣物放入洗衣篮”“整理床铺”“把所有盘子放入水槽”等多阶段行为。这是首个端到端学习系统能在全新家庭中完成此复杂度任务的演示。

Co-Training 消融: 移除跨具身数据 (ME 或 CE) 导致性能大幅下降;同时移除两者则更糟。网络数据 (WD) 对分布内任务影响不显著,但对分布外物体类别的语言遵循能力至关重要——这验证了”开放世界的语义知识来自互联网数据”的假说。

缩放法则: 随着训练环境数量从 3 增加到 104,性能单调提升。在 104 个环境下训练的模型在全新测试环境中达到与”在测试环境中直接训练”相近的性能——这表明充分的场景多样性训练可以弥合泛化差距。

与 \(\pi_0\) 的比较: \(\pi_{0.5}\) 在所有任务上显著优于原始的 \(\pi_0\) VLA,包括增强了 FAST+Flow 的 \(\pi_0\) 版本。这表明 Co-Training 配方 (HL + WD) 和两阶段训练策略带来的增益超过了纯架构改进。

3.1.3 局限性

\(\pi_{0.5}\) 仍然会犯错误: 不熟悉的抽屉把手会导致失败;部分可观察性 (如机械臂遮挡了要擦拭的污渍) 仍是挑战;高层推理有时会”分心”(反复开关同一个抽屉)。模型的 prompt 复杂度受限于训练数据的标注质量。这些都是未来工作的方向。


3.2 MolmoSpaces: 大规模空间推理与评估生态系统

论文: Kim et al., “MolmoSpaces: A Large-Scale Open Ecosystem for Robot Navigation and Manipulation,” arXiv 2026

3.2.1 核心贡献

MolmoSpaces 的目标是解决一个基础性的基础设施问题: 如何以足够的规模和多样性评估通用机器人策略?当最新的 VLA 模型在现有 benchmark 上已经接近性能饱和时,需要新一代的评估工具来衡量真正的进展。

五大组件:

  1. MolmoSpaces-Scenes (\(>230\text{k}\) 个室内环境): 包括手工制作的 120 个单房间场景、12k 程序生成住宅、110k 含 Objaverse 物体的场景、110k LLM 生成的多类型场景,以及 1 个真实厨房的数字孪生

  2. MolmoSpaces-Objects (130k 个高质量 3D 物体): 1.6k THOR 物体 + 129k Objaverse 物体,涵盖 2.8k WordNet synsets,携带 GPT-4o 生成的语义描述、质量估计和材质信息

  3. MolmoSpaces-Grasp (42M 个标注抓取): 覆盖 48k 个可交互物体,包含刚体和铰接物体的抓取位姿,通过原位 (in-situ) 碰撞检测和稳定性测试验证

  4. MolmoSpaces-Bench (8 种任务类型): navigate-to, pick, pick-and-place, pick-and-place-next-to, pick-and-place-color, open, close, open-door。所有任务在 Zero-Shot 设置下评估(不在 benchmark 数据上微调)

  5. 仿真基础设施: 支持 MuJoCo, Isaac Sim, ManiSkill 三种物理引擎;模块化的实验组合;JAX 加速的并行 IK 求解器

3.2.2 关键实验发现

Sim-to-Real 强相关性: Pick 任务的 \(R = 0.96, \rho = 0.98\),验证了仿真评估的代用有效性。这在方法论上非常重要——意味着大规模仿真实验可以作为真实世界性能的可靠预筛选。

策略鲁棒性的精细分析: MolmoSpaces 揭示了仅靠聚合成功率指标无法察觉的策略行为特征:

DualVLN vs. RING 对比: 在导航任务上,RING (语义目标导航) 的 zero-shot 成功率为 48%,而 DualVLN (详细指令导航) 仅 21%——差异源于任务格式的分布匹配。这证实了 benchmark 设计对公平评估的重要性。

3.2.3 方法论价值

MolmoSpaces 的核心方法论贡献是分布性评估 (Distributional Evaluation) 的概念: 不仅仅报告”成功率”这个标量,而是系统性地变化环境参数 (物体类别、光照、相机位姿、初始关节位置、语言措辞),在参数空间中绘制策略性能的完整分布图。这一方法论为机器人学提供了类似”软件测试”的评估范式——通过可控的压力测试揭示策略的隐藏脆弱性。


四、算法与代码实现

以下实现一个简化版的 VLA 模型,展示核心架构组件。完整模型 (2B VLM + 300M Action Expert) 的规模超出单机训练范围,但我们保留其关键设计原则: (1) 多模态 token 化,(2) 层次化推理,(3) 流匹配动作生成,以及 (4) 混合离散/连续动作表示。

4.1 视觉编码器 — SigLIP/ViT 简化版

"""
ch17/simplified_vla.py — 简化版 Vision-Language-Action 模型
用途: 展示 π₀.₅ 的核心架构组件
参考: π₀.₅ (CoRL 2025), Appendix E
"""

import torch
import torch.nn as nn
import torch.nn.functional as F
import math
from dataclasses import dataclass
from typing import Optional, Tuple, List

# ============================================================
# 4.1 视觉编码器 — 将图像映射为 patch token 序列
# 参考: π₀.₅ §IV-A; PaliGemma VLM backbone
# ============================================================

class VisionEncoder(nn.Module):
    """简化版 ViT 视觉编码器,将图像切块并嵌入到统一维度。
    
    输入: [B, 3, H, W] 图像 (可有多视角)
    输出: [B, N_patches * n_views, d_model] 图像 token 序列
    """
    def __init__(
        self,
        image_size: int = 224,
        patch_size: int = 14,
        d_model: int = 512,
        n_views: int = 2,  # 腕部 + 第三人称
    ):
        super().__init__()
        self.patch_size = patch_size
        self.n_patches = (image_size // patch_size) ** 2
        self.n_views = n_views
        
        # 图像块嵌入 (实现了 "p×p×3 → d_model" 的线性投影)
        self.patch_embed = nn.Conv2d(
            3, d_model, kernel_size=patch_size, stride=patch_size
        )
        
        # 可学习的视角嵌入 (区分不同相机视角)
        self.view_embed = nn.Parameter(torch.randn(1, n_views, 1, d_model) * 0.02)
        
        # 可学习的位置嵌入
        self.pos_embed = nn.Parameter(
            torch.randn(1, n_views * self.n_patches, d_model) * 0.02
        )
        
        # 简化的 Transformer 层 (2层,真实模型有18层)
        self.transformer = nn.ModuleList([
            TransformerBlock(d_model, n_heads=8) for _ in range(2)
        ])
        
    def forward(self, images: torch.Tensor) -> torch.Tensor:
        """
        Args:
            images: [B, n_views, 3, H, W]
        Returns:
            tokens: [B, n_views * N_patches, d_model]
        """
        B, V, C, H, W = images.shape
        # 合并 batch 和视角维度进行并行处理
        x = images.view(B * V, C, H, W)
        
        # Patch embedding: [B*V, d_model, H/P, W/P]
        x = self.patch_embed(x)
        x = x.flatten(2).transpose(1, 2)  # [B*V, N_patches, d_model]
        x = x.view(B, V, self.n_patches, -1)
        
        # 添加视角嵌入
        x = x + self.view_embed[:, :V, :, :]
        x = x.view(B, V * self.n_patches, -1)
        
        # 添加位置嵌入
        x = x + self.pos_embed
        
        # Transformer 层
        for layer in self.transformer:
            x = layer(x)
        return x


class TransformerBlock(nn.Module):
    """标准 Transformer 块 (pre-LN 架构)"""
    def __init__(self, d_model: int, n_heads: int, mlp_ratio: float = 4.0):
        super().__init__()
        self.norm1 = nn.LayerNorm(d_model)
        self.attn = nn.MultiheadAttention(
            d_model, n_heads, batch_first=True
        )
        self.norm2 = nn.LayerNorm(d_model)
        self.mlp = nn.Sequential(
            nn.Linear(d_model, int(d_model * mlp_ratio)),
            nn.GELU(),
            nn.Linear(int(d_model * mlp_ratio), d_model),
        )
        
    def forward(
        self, x: torch.Tensor,
        attn_mask: Optional[torch.Tensor] = None
    ) -> torch.Tensor:
        # Self-attention (pre-LN)
        x = x + self.attn(
            self.norm1(x), self.norm1(x), self.norm1(x),
            attn_mask=attn_mask
        )[0]
        # FFN
        x = x + self.mlp(self.norm2(x))
        return x

4.2 VLA 主干 — 多模态 Transformer

# ============================================================
# 4.2 VLA 主干网络 — 统一处理文本+图像+动作 token
# 参考: π₀.₅ §IV-A, Figure 3, Appendix E
# ============================================================

@dataclass
class VLAModelConfig:
    """VLA 模型配置 (简化版)"""
    d_model: int = 512
    n_heads: int = 8
    n_layers: int = 8
    n_layers_action_expert: int = 2
    vocab_size: int = 32000
    max_text_len: int = 256
    action_dim: int = 18  # 双机械臂 + 移动底盘 + 躯干升降
    action_horizon: int = 50
    n_image_tokens: int = 256  # (224/14)^2  per view
    n_views: int = 2


class VLAModel(nn.Module):
    """简化版 Vision-Language-Action 模型。
    
    架构遵循 π₀.₅ (Figure 3):
      视觉编码器 (ViT) → 图像 token
      文本嵌入 → 文本 token
      本体感觉编码 → proprio token
      → 共享 Transformer 骨干 (VLM)
      → [文本输出头] + [Action Expert] → 动作输出
    
    关键设计:
      - 层次化推理: ℓ̂ → a_{t:t+H}
      - Action Expert 与 VLM 骨干分离
      - 不同的注意力掩码用于不同 token 类型
    """
    def __init__(self, config: VLAModelConfig):
        super().__init__()
        self.config = config
        
        # --- 模态编码器 ---
        self.vision_encoder = VisionEncoder(
            d_model=config.d_model, n_views=config.n_views
        )
        
        self.text_embed = nn.Embedding(config.vocab_size, config.d_model)
        
        # 本体感觉编码 (关节角度 → d_model)
        self.proprio_encoder = nn.Sequential(
            nn.Linear(config.action_dim, config.d_model),
            nn.GELU(),
            nn.Linear(config.d_model, config.d_model),
        )
        
        # --- 共享 VLM 骨干 ---
        self.vlm_layers = nn.ModuleList([
            TransformerBlock(config.d_model, config.n_heads)
            for _ in range(config.n_layers)
        ])
        
        # --- 文本输出头 (用于子任务预测 ℓ̂) ---
        self.text_head = nn.Linear(config.d_model, config.vocab_size)
        
        # --- Action Expert (独立的较小 Transformer) ---
        # 参考 π₀.₅ Appendix E: VLM 2B + Action Expert 300M
        self.action_proj_in = nn.Linear(config.action_dim, config.d_model)
        self.action_expert_layers = nn.ModuleList([
            TransformerBlock(config.d_model // 2, config.n_heads // 2)
            for _ in range(config.n_layers_action_expert)
        ])
        self.action_proj_out = nn.Linear(config.d_model // 2, config.action_dim)
        
        # --- 流匹配时间嵌入 ---
        # 用于将 τ 注入 Action Expert 的各层
        self.time_mlp = nn.Sequential(
            nn.Linear(config.d_model // 2, config.d_model // 2),
            nn.SiLU(),
            nn.Linear(config.d_model // 2, config.d_model // 2),
        )
        
        # 固定位置编码 (sinusoidal)
        self.register_buffer('pos_encoding', self._sinusoidal_pos_encoding(
            config.max_text_len + config.n_image_tokens * config.n_views + 100,
            config.d_model
        ))
        
    @staticmethod
    def _sinusoidal_pos_encoding(max_len: int, d_model: int) -> torch.Tensor:
        pe = torch.zeros(max_len, d_model)
        position = torch.arange(0, max_len).unsqueeze(1).float()
        div_term = torch.exp(
            torch.arange(0, d_model, 2).float() * 
            (-math.log(10000.0) / d_model)
        )
        pe[:, 0::2] = torch.sin(position * div_term)
        pe[:, 1::2] = torch.cos(position * div_term)
        return pe

    def _apply_attention_mask(
        self, x: torch.Tensor, token_types: torch.Tensor
    ) -> torch.Tensor:
        """构建部分双向注意力掩码。
        
        Token 类型编码 (参考 π₀.₅ Figure 18):
          0: prefix (图像/文本 prompt/本体感觉) — 双向注意力
          1: FAST 离散动作 — 自回归因果注意力
          2: 连续动作 (action expert) — 对 prefix 双向,不对 FAST token 施加注意力
        
        简化实现: 全部使用双向注意力 (训练阶段使用 teacher forcing)
        """
        seq_len = x.shape[1]
        # 全零掩码 = 双向注意力 (所有 token 可以互相看到)
        return torch.zeros(seq_len, seq_len, device=x.device)

    def high_level_inference(
        self,
        images: torch.Tensor,
        text_tokens: torch.Tensor,
        proprio: torch.Tensor,
        max_new_tokens: int = 20,
    ) -> torch.Tensor:
        """高层推理 — 预测子任务 ℓ̂。
        
        Eq: ℓ̂ ~ π_θ(ℓ̂ | o_t, ℓ)  (参考 π₀.₅ §IV-A)
        
        Args:
            images: [B, n_views, 3, H, W]
            text_tokens: [B, L_text] 输入任务指令 token
            proprio: [B, action_dim] 本体感觉状态
            max_new_tokens: 最大生成的子任务 token 数
        
        Returns:
            subtask_tokens: [B, max_new_tokens] 生成的子任务
        """
        B = images.shape[0]
        
        # 编码多模态输入
        img_tokens = self.vision_encoder(images)           # [B, N_img, d]
        txt_emb = self.text_embed(text_tokens)              # [B, L_text, d]
        prop_emb = self.proprio_encoder(proprio).unsqueeze(1)  # [B, 1, d]
        
        # 拼接为 prefix
        prefix = torch.cat([img_tokens, txt_emb, prop_emb], dim=1)
        
        # 通过 VLM 骨干
        h = prefix
        attn_mask = self._apply_attention_mask(h, torch.zeros(1))
        for layer in self.vlm_layers:
            h = layer(h, attn_mask=attn_mask)
        
        # 自回归解码文本
        generated = []
        current = h
        for _ in range(max_new_tokens):
            logits = self.text_head(current[:, -1, :])  # [B, vocab_size]
            next_token = logits.argmax(dim=-1)           # [B]
            generated.append(next_token)
            
            # 将新 token 嵌入并拼接到序列
            next_emb = self.text_embed(next_token).unsqueeze(1)
            current = torch.cat([current, next_emb], dim=1)
            
            # 对新增 token 做一次 Transformer forward
            attn_mask = self._apply_attention_mask(current, torch.zeros(1))
            for layer in self.vlm_layers:
                current = layer(current, attn_mask=attn_mask)
        
        return torch.stack(generated, dim=1)  # [B, max_new_tokens]

    def low_level_inference(
        self,
        images: torch.Tensor,
        text_tokens: torch.Tensor,  # 包含任务指令 ℓ 和子任务 ℓ̂
        proprio: torch.Tensor,
        action_noise: Optional[torch.Tensor] = None,
        flow_timestep: float = 0.0,
        n_denoising_steps: int = 10,
    ) -> torch.Tensor:
        """低层推理 — 通过流匹配生成动作块。
        
        Eq: a_{t:t+H} ~ π_θ(a | o_t, ℓ̂)  (参考 π₀.₅ §IV-B)
        
        流匹配推理:
          从噪声 ω ~ N(0, I) 开始
          使用 Euler 积分沿向量场推进 τ: 0 → 1
          
        Args:
            images: [B, n_views, 3, H, W]
            text_tokens: [B, L_text] 指令+子任务 token
            proprio: [B, action_dim]
            action_noise: [B, H+1, action_dim] 可选初始噪声
            n_denoising_steps: 流匹配去噪步数 (π₀.₅ 使用 10)
        
        Returns:
            action_chunk: [B, H+1, action_dim] 预测动作块
        """
        B = images.shape[0]
        H = self.config.action_horizon  # = 50
        
        if action_noise is None:
            action_noise = torch.randn(B, H, self.config.action_dim)
        
        # 编码 prefix (与高层推理相同)
        img_tokens = self.vision_encoder(images)
        txt_emb = self.text_embed(text_tokens)
        prop_emb = self.proprio_encoder(proprio).unsqueeze(1)
        prefix = torch.cat([img_tokens, txt_emb, prop_emb], dim=1)
        
        # 通过 VLM 骨干获取 context
        context = prefix
        attn_mask = self._apply_attention_mask(context, torch.zeros(1))
        for layer in self.vlm_layers:
            context = layer(context, attn_mask=attn_mask)
        
        # 流匹配去噪循环
        a_current = action_noise.clone()
        dt = 1.0 / n_denoising_steps
        
        for step in range(n_denoising_steps):
            tau = step / n_denoising_steps
            
            # 预测向量场 v(a^τ, τ, context)
            v_field = self._action_expert_forward(
                a_current, context, tau
            )
            
            # Euler 积分: a^{τ+dt} = a^τ + v · dt
            a_current = a_current + v_field * dt
        
        return a_current  # [B, H, action_dim]

    def _action_expert_forward(
        self,
        a_tau: torch.Tensor,
        context: torch.Tensor,
        tau: float,
    ) -> torch.Tensor:
        """
        Action Expert 前向传播 — 预测流匹配向量场。
        
        参考 π₀.₅ Appendix E:
          - Action Expert 是一个较小的 Transformer (width=1024, mlp_dim=4096 vs VLM width=2048)
          - 时间步 τ 通过 MLP + adaptive RMSNorm 注入各层
          - 输出: 向量场 v = ω − a (用于流匹配损失)
        """
        B, H, _ = a_tau.shape
        d_expert = self.config.d_model // 2
        
        # 投影动作到 expert 维度
        x = self.action_proj_in(a_tau)  # [B, H, d_model]
        x = x[:, :, :d_expert]          # [B, H, d_expert]  (降维以模拟 expert 更小)
        
        # 时间嵌入
        tau_tensor = torch.tensor([tau], device=a_tau.device).float()
        tau_emb = self.time_mlp(tau_tensor.expand(B, 1).unsqueeze(-1)
                                 .expand(-1, 1, d_expert))
        
        # 拼接 context 信息 (取 context 的平均表示)
        ctx_summary = context.mean(dim=1, keepdim=True)  # [B, 1, d_model]
        ctx_summary = ctx_summary[:, :, :d_expert]       # [B, 1, d_expert]
        
        # 将 context summary 和时间嵌入 prepend 到动作序列前
        x = torch.cat([ctx_summary + tau_emb, x], dim=1)  # [B, 1+H, d_expert]
        
        # Action Expert Transformer 层
        for layer in self.action_expert_layers:
            x = layer(x)
        
        # 去除 context token, 只保留动作 token
        x = x[:, 1:, :]  # [B, H, d_expert]
        
        # 投影回动作维度 → 向量场
        v_field = F.linear(x, self.action_proj_out.weight[:, :d_expert])
        
        return v_field

    def forward(
        self,
        images: torch.Tensor,
        text_tokens: torch.Tensor,
        proprio: torch.Tensor,
        actions_gt: torch.Tensor,
        flow_timestep: float = 0.5,
    ) -> Tuple[torch.Tensor, torch.Tensor]:
        """训练前向传播 — 同时计算文本损失和流匹配损失。
        
        训练分为两个阶段:
          Phase 1 (预训练): α=0, 仅用离散 FAST token (本简化版用文本损失代替)
          Phase 2 (后训练): α>0, 联合训练文本+流匹配 (Eq. 1)
        
        Args:
            images: [B, n_views, 3, H, W]
            text_tokens: [B, L_text]
            proprio: [B, action_dim]
            actions_gt: [B, H, action_dim] 真实动作序列
            flow_timestep: τ ∈ [0, 1] 流匹配时间参数
        
        Returns:
            text_loss, flow_loss
        """
        # 编码 prefix
        img_tokens = self.vision_encoder(images)
        txt_emb = self.text_embed(text_tokens)
        prop_emb = self.proprio_encoder(proprio).unsqueeze(1)
        prefix = torch.cat([img_tokens, txt_emb, prop_emb], dim=1)
        
        # VLM 骨干
        h = prefix
        attn_mask = self._apply_attention_mask(h, torch.zeros(1))
        for layer in self.vlm_layers:
            h = layer(h, attn_mask=attn_mask)
        
        # 文本损失 (交叉熵)
        text_logits = self.text_head(h[:, -text_tokens.shape[1]:, :])
        text_loss = F.cross_entropy(
            text_logits.reshape(-1, self.config.vocab_size),
            text_tokens.reshape(-1)
        )
        
        # 流匹配损失 (Eq. 1 in π₀.₅)
        # 采样噪声并构造插值
        omega = torch.randn_like(actions_gt)
        a_tau = flow_timestep * actions_gt + (1 - flow_timestep) * omega
        v_target = omega - actions_gt  # 流匹配目标: ω − a
        
        # Action Expert 预测向量场
        v_pred = self._action_expert_forward(
            a_tau,
            h.detach(),  # 阻断 VLM 梯度传播到 action expert (分离训练)
            flow_timestep,
        )
        
        flow_loss = F.mse_loss(v_pred, v_target)
        
        return text_loss, flow_loss

4.3 训练与推理流程

# ============================================================
# 4.3 训练循环 (简化版)
# ============================================================

def train_step(
    model: VLAModel,
    batch: dict,
    optimizer: torch.optim.Optimizer,
    alpha: float = 10.0,  # 流匹配损失权重 (π₀.₅ Eq. 1)
    phase: str = "posttrain",  # "pretrain" | "posttrain"
) -> dict:
    """单步训练。
    
    参考:
      - 预训练 (phase="pretrain"): 纯自回归, α=0
      - 后训练 (phase="posttrain"): 联合训练, α=10.0 (π₀.₅ §IV-D)
    """
    images = batch['images']
    text_tokens = batch['text_tokens']
    proprio = batch['proprio']
    actions = batch['actions']
    
    # 采样子任务 token (简化: 从文本中截取)
    subtask_tokens = text_tokens[:, :20]  # 子任务在文本开头
    
    # 流匹配时间步采样 (π₀.₅ Appendix E: Beta 分布偏重低 τ)
    tau = torch.distributions.Beta(1.5, 1.0).sample()
    
    if phase == "pretrain":
        # 仅文本损失
        text_loss, _ = model(images, text_tokens, proprio, actions, tau)
        total_loss = text_loss
    else:
        # 联合损失: Eq. (1) in π₀.₅
        text_loss, flow_loss = model(images, text_tokens, proprio, actions, tau)
        total_loss = text_loss + alpha * flow_loss
    
    optimizer.zero_grad()
    total_loss.backward()
    optimizer.step()
    
    return {
        'total': total_loss.item(),
        'text': text_loss.item(),
        'flow': flow_loss.item() if phase == "posttrain" else 0.0,
    }


def rollout(
    model: VLAModel,
    env,  # 简化: 假设有一个环境接口
    task_instruction: str,
    tokenizer,  # 文本 tokenizer
    max_episode_steps: int = 300,
) -> bool:
    """执行一次完整的 rollout。
    
    参考 π₀.₅ §IV-A: 层次化推理流程
      Step 1: 高层推理 → 子任务 ℓ̂
      Step 2: 低层推理 → 动作 a_{t:t+H}
      Step 3: 执行 K 步, 重新推理
    """
    obs = env.reset()
    
    # Tokenize 任务指令
    text_tokens = tokenizer.encode(task_instruction)
    
    for step in range(max_episode_steps):
        # 每 25 步 (0.5s @ 50Hz) 重新推断子任务
        if step % 25 == 0:
            images = obs['images']
            proprio = obs['proprio']
            
            # 高层推理: ℓ̂ ~ π_θ(· | o_t, ℓ)
            subtask_tokens = model.high_level_inference(
                images, text_tokens, proprio, max_new_tokens=10
            )
            
            # 拼接指令 + 子任务
            full_prompt = torch.cat([text_tokens, subtask_tokens], dim=1)
            
            # 低层推理: a_{t:t+H} ~ π_θ(· | o_t, ℓ̂)
            action_chunk = model.low_level_inference(
                images, full_prompt, proprio, n_denoising_steps=10
            )
        
        # 执行动作块中的当前步
        chunk_idx = step % model.config.action_horizon
        action = action_chunk[:, chunk_idx, :]
        obs, reward, done, info = env.step(action)
        
        if done:
            return info.get('success', False)
    
    return False

五、课程总结与未来展望

5.1 17 章知识地图

本课程从具身智能的”物理根基”出发,穿越”学习算法”,最终抵达”通用智能”的边界。以下是完整的知识地图:

层次                              核心问题                       代表章节
──────────────────────────────────────────────────────────────────────────
Layer 5: 通用具身智能          如何构建开放世界中的通用策略?   Ch17 (本章)
  ↕ 语言作为抽象接口
Layer 4: 长程规划与推理        如何组合技能完成复杂多阶段任务? Ch17, Ch13
  ↕ 任务分解与层次化策略
Layer 3: 技能学习              如何从数据中学习动作策略?       Ch11(RL), Ch12(BC),
                                                            Ch13(视觉模仿),
                                                            Ch14(运动控制),
                                                            Ch15(导航), Ch16(灵巧操作)
  ↕ 数据驱动的策略优化
Layer 2: 感知与预测            如何构建环境的世界模型?         Ch4(扩散模型),
                                                            Ch6(触觉),
                                                            Ch10(视频世界模型)
  ↕ 多模态感知融合
Layer 1: 物理基础              机器人如何运动并与世界交互?    Ch2(生物运动力学),
                                                            Ch3(机构学),
                                                            Ch5(灵巧手),
                                                            Ch7(运动发育),
                                                            Ch8(动力学与控制),
                                                            Ch9(计算神经科学)

从下到上的知识流: Layer 1 的物理定律 (Newton-Euler, Lagrange) 定义了机器人行为的约束空间;Layer 2 的感知模型将物理世界映射为可学习的表征空间;Layer 3 的技能学习算法在这个表征空间中搜索最优策略;Layer 4 的规划方法将原子技能组合为行为序列;Layer 5 的语言接口最终将所有这些能力封装为人类可理解的指令。

整个课程的逻辑是: 不存在不经过物理和感知的”纯推理”通用智能——具身智能体的每一层抽象都必须扎根于它下面的层。这正是”Embodied Intelligence”与”Disembodied AI”的本质区别。

5.2 核心开放挑战

挑战 1 — 数据效率: \(\pi_{0.5}\) 需要 \(\sim\)400 小时的移动操作数据加上 PB 级别的网络数据。人类婴儿学会抓取只需几个月。如何缩小这个效率差距?潜在方向包括更好的世界模型预训练、3D 感知辅助、以及从人类视频中迁移知识。

挑战 2 — 安全的探索与部署: 当前所有 VLA 模型的失败模式仍不可预测——模型可能在没有警告的情况下做出危险动作(如过度用力抓取易碎品)。如何在保持端到端灵活性的同时嵌入硬安全约束?

挑战 3 — 持续学习: \(\pi_{0.5}\) 的权重在训练后固定。真实世界中的机器人应该能够在部署中持续学习——记住新物体的外观,适应新家庭的布局,从失败中改进。当前的 VLA 架构不天然支持这种持续学习。

挑战 4 — 具身形式的泛化 (Cross-Embodiment): 在 Franka 手臂上训练的抓取策略能否迁移到人形机器人的五指手?\(\pi_{0.5}\) 展示了有限的 cross-embodiment 迁移(通过协同训练),但从根本上将策略与特定具身形式的运动学解耦仍是一个开放问题。

挑战 5 — 评估的生态有效性: MolmoSpaces 展示了大规模仿真评估的价值,但仿真永远是不完美的(渲染 gap、物理 gap、传感器噪声 gap)。如何在保持评估规模的同时提高生态有效性?

挑战 6 — 触觉与力感知的整合: 本课程从 Ch6 (触觉) 到 Ch17 (VLA),但与视觉和语言相比,触觉信息在现代 VLA 中仍然严重地未被充分利用。将触觉 (GelSight) 和力/扭矩信息整合到端到端策略中是一个重要方向。

挑战 7 — 形式化验证: 在一个 \(\pi_{0.5}\) 驱动的机器人进入家庭之前,我们能否形式化地证明它不会在特定条件下做出危险行为?这触及了深度学习的形式化验证与具身智能的安全需求之间的深层张力。

5.3 通向通用具身智能的路线图

展望未来 5-10 年,通向通用具身智能的可能路线:

  1. 短期 (2026-2028): VLA 模型将从双手机械臂扩展到更多人形机器人平台;仿真环境 (MolmoSpaces-style) 将嵌入更真实的物理 (软体、流体);Co-Training 配方将系统化——不再只是”什么数据都加”,而是基于信息论的”数据价值”自动选择数据源。

  2. 中期 (2028-2031): 视频生成模型 (Sora-style) 将作为世界模型被整合进 VLA 训练循环——机器人可以”想象”动作的后果;触觉在策略中的使用将变得普遍;云端训练+边缘推理的分层架构将成为标准。

  3. 远期 (2031+): 通用机器人基础模型可能遵循与 LLM 类似的缩放法则——”足够的多样性数据 + 足够大的模型 + 足够的计算”就能涌现通用操作能力。但具身智能的独特约束(安全性、实时性、物理交互成本)可能意味着这条路径比纯语言的缩放更陡峭。

本课程的最后一句话: 具身智能是一个”思维”与”身体”不可分割的领域。任何试图脱离物理约束来构建”通用机器人智能”的努力都注定失败——正如任何试图脱离感知和学习来手工设计机器人行为的努力一样。真正的进展来自于在各层次之间建立反馈循环: 物理基础约束着学习算法的设计空间;学习算法的进展反哺了更优的感知和规划;而语言和推理将这些能力封装为人类可以理解和使用的形式。这正是本课程 17 章试图传达的核心信息。


六、核心 Takeaway 与延伸阅读

核心洞察

  1. VLA = 统一表征 + 异构训练: VLA 模型的威力不在于单一的架构创新,而在于其将视觉、语言和动作统一到同一个 Token 空间的能力,使来自网络、机器人、人类指令的异构数据能够通过同一个 Transformer 骨干进行协同训练。

  2. 泛化来自多样性,而非规模: \(\pi_{0.5}\) 的实验表明,多 100 倍但同质的数据不如多样化的异构数据。97.6% 的预训练数据来自非目标平台,但这些数据对泛化至关重要——这暗示着”场景多样性”比”任务数据量”更重要。

  3. 层次化推理的微妙性: 显式的高层推理有帮助,但大部分益处来自”在训练中暴露于任务结构”(隐式层次化)。这意味着精心设计的数据标注策略可能比精巧的架构设计更有影响力。

  4. 仿真评估的预测价值: MolmoSpaces 的 Sim-to-Real 相关性 (\(R = 0.96\)) 确认了大规模仿真的预测价值。但 MolmoSpaces 真正的贡献不是另一个 benchmark,而是一种方法论——通过系统性的参数扰动绘制策略性能的完整分布图。

  5. 语言的脆弱性: prompt 措辞的微小变化就可以导致早期 VLA 模型成功率从 28% 跌至 14%——这表明当前 VLA 的语言理解能力远未达到人类水平的鲁棒性。这对于部署到真实家庭是一个严肃的可靠性问题。

延伸阅读


七、练习与思考

基础题

7.1 VLA 架构推导: 给定 VLA 模型的形式化定义 (Eq. 1),推导当 \(\alpha \to \infty\) 和 \(\alpha \to 0\) 时模型的极限行为。分析为何 \(\pi_{0.5}\) 选择 \(\alpha = 10.0\) 而非无限大。

7.2 流匹配的直觉: 用 200 字以内解释流匹配 (Flow Matching) 和扩散模型 (DDPM) 的本质区别。为什么 \(\pi_{0.5}\) 选择流匹配而非 DDPM?

7.3 注意力掩码设计: 解释 \(\pi_{0.5}\) 中为什么连续动作 token 不应关注 FAST 离散动作 token (信息泄漏问题)。设计一个具体场景,说明这种信息泄漏如何导致训练-推理不一致。

进阶题

7.4 协同训练的博弈论分析: 将 \(\pi_{0.5}\) 的协同训练形式化为一个多任务学习问题,其中每个数据源 \(d_i\) 提供一个损失函数 \(\mathcal{L}_i\)。使用梯度冲突分析 (gradient cosine similarity) 方法,推导何时添加一个数据源会损害而非改善整体性能。提示: 考虑 \(\langle \nabla \mathcal{L}_i, \nabla \mathcal{L}_{\text{target}} \rangle\) 的符号和大小。

7.5 Sim-to-Real Gap 的数学建模: 假设仿真动力学 \(\hat{P}\) 与真实动力学 \(P\) 之间的差距由 Wasserstein 距离 \(W_2(\hat{P}(\cdot \mid \mathbf{s}, \mathbf{a}), P(\cdot \mid \mathbf{s}, \mathbf{a})) \leq \epsilon\) 上界约束。推导仿真中训练的策略在真实环境中的性能下界 (performance bound)。讨论 MolmoSpaces 的 Sim-to-Real 相关性 (\(R = 0.96\)) 在此框架下的含义。

7.6 17 章知识地图的图论建模: 将本课程的 17 章表示为有向无环图 \(\mathcal{G} = (\mathcal{V}, \mathcal{E})\),其中 \(\mathcal{V}\) 是章节,边 \((i, j) \in \mathcal{E}\) 表示第 \(i\) 章是第 \(j\) 章的前置知识。分析 \(\mathcal{G}\) 的拓扑排序、关键路径 (critical path),并讨论: 如果我们只能选择其中 5 章构成一个”最小可行课程”,应该选择哪 5 章?为什么?

开放研究问题

7.7 语言作为策略压缩: 语言指令可以被视为一种”策略压缩”——”清理厨房”这个 4 字的指令包含了一个可能需要 10 分钟执行的行为程序的全部信息。估算这个压缩率 (以 bits 为单位),并与当前最优的无损压缩方法比较。这种”语义压缩”对策略泛化意味着什么?

7.8 触觉 VLA: 设计一个将触觉信号 (GelSight 触觉图像或力/扭矩读数) 整合进 VLA 架构的方案。触觉 token 与视觉 token 的关键区别是什么?如何处理触觉的时间尺度 (通常比视觉快 5-10 倍) 与 VLA 推理频率的失配问题?

7.9 具身智能的缩放法则: 假设存在一个”机器人基础模型”,其性能 \(P\) 服从缩放法则 \(P(N, D, C) \approx \left(\frac{N}{N_0}\right)^{\alpha} \left(\frac{D}{D_0}\right)^{\beta} \left(\frac{C}{C_0}\right)^{\gamma}\),其中 \(N\) 是模型参数量,\(D\) 是机器人交互数据量,\(C\) 是计算量。讨论: (a) 这个缩放法则与 LLM 的 Kaplan scaling law 是否有本质不同?(b) 在物理交互数据的收集成本远高于文本数据的前提下,最优的资源分配策略是什么?


全书完 (共 17 章)

从生物运动力学的肌骨模型到视觉-语言-动作的通用策略,从 DH 参数的机构学到 42M 个标注抓取的大规模仿真生态——这 17 章覆盖了具身智能从”身体的物理”到”思维的算法”的完整光谱。具身智能的真正挑战不在于任何一个单点技术,而在于这些层次之间的整合与涌现。希望本课程能为你在这条路上的探索提供坚实的基础。

“Stuff your eyes with wonder… See the world. It’s more fantastic than any dream made or paid for in factories.” — Ray Bradbury, Fahrenheit 451 (引自 \(\pi_{0.5}\) 论文开篇)


← 第16章 灵巧操作案例研究
↑ 目录