先用一句话建立直觉
OpenVLA 的本质是:

把“机器人看到什么、听到什么指令、下一步怎么动”这个控制问题,
改写成“多模态语言模型在图像条件下生成一串动作 token”的问题。
普通视觉语言模型通常是:

图片 + 问题 -> 文本回答
OpenVLA 是:

图片 + 任务指令 -> 动作 token -> 连续机器人动作
类比一下:

一个传统机器人策略像“直接输出方向盘角度和油门大小”的驾驶控制器。
OpenVLA 更像是先发明一套“动作密码本”,把方向盘角度和油门大小编码成若干特殊词,然后让一个会看图的语言模型根据路况和指令生成这些特殊词。最后系统再把特殊词翻译回真实控制量。

这个思路看起来绕,但它把机器人动作预测接入了语言模型最擅长的能力:

根据上下文生成下一个 token。
OpenVLA 到底在解决什么问题
机器人模仿学习里,一条训练数据大致包含三类信息:

  1. 观测

    • 相机图像
    • 可选的本体状态,例如关节角、末端位置、夹爪状态
  2. 任务

    • 人类语言指令,例如“把胡萝卜放进碗里”
  3. 动作

    • 机器人专家在这个状态下执行的动作
    • 常见形式是连续向量,例如:
      [x方向移动, y方向移动, z方向移动, 旋转1, 旋转2, 旋转3, 夹爪开合]
      模型要学的是一个条件策略:

policy(image, instruction) -> action
也就是:

当前画面 + 当前任务 -> 下一步机器人动作
传统做法可能直接训练一个神经网络回归动作:

图片特征 + 语言特征 -> MLP -> 连续动作向量
OpenVLA 选择了另一条路:

图片特征 + 语言 token -> LLM -> 动作 token -> 连续动作向量
这样做的关键收益是:

可以复用大型语言模型的自回归生成框架。
可以复用视觉语言模型的图文对齐能力。
可以把“动作预测”纳入通用 token 预测范式。
可以用语言指令自然地控制机器人行为。
核心思想:把机器人控制改写成 token 生成
语言模型最擅长的问题是:

给定前文,预测下一个 token。
例如:

输入: The robot should pick up the
输出: cup
OpenVLA 想让语言模型做:

输入: 图像 + “机器人应该如何执行:把杯子拿起来?”
输出: 动作 token 1, 动作 token 2, …, 动作 token N
这里的动作 token 不是普通词语,而是人为约定的“动作编码符号”。

如果动作是 7 维:

action = [a1, a2, a3, a4, a5, a6, a7]
模型就可以生成 7 个动作 token:

tokens = [t1, t2, t3, t4, t5, t6, t7]
每个 token 对应一个动作维度的离散值。

于是原问题:

回归一个连续向量
被改写成:

生成一串离散 token
这一步是 OpenVLA 的思想核心。

从机器人动作到语言模型 token
机器人动作通常是连续数值。比如机械臂末端移动动作:

dx = 0.021
dy = -0.014
dz = 0.007
语言模型不能天然生成“高精度浮点控制量”。它生成的是 token。因此需要一个动作编码器。

第一步:归一化动作
不同机器人、不同数据集的动作尺度不一样。

例如:

机器人 A:
dx 的合理范围可能是 [-0.05, 0.05]

机器人 B:
dx 的合理范围可能是 [-0.5, 0.5]
如果直接混在一起训练,模型会很混乱。

所以先把动作统一映射到一个标准区间,通常是:

[-1, 1]
一种常见的分位数归一化方式是:

normalized = 2 * (raw - q01) / (q99 - q01) - 1
其中:

q01 = 这个动作维度在数据集中的 1% 分位数
q99 = 这个动作维度在数据集中的 99% 分位数
使用分位数而不是最小值/最大值,是为了降低异常动作值的影响。

q01 和 q99 到底是什么意思
分位数可以理解成:

把一堆数从小到大排序后,位于某个百分比位置的值。
假设某个数据集里,dx 这个动作维度一共有 10000 个样本。把所有 dx 从小到大排序:

dx_sorted = [
最小值,
第二小,
第三小,

最大值
]
那么:

q01 = 排在 1% 位置附近的值
q99 = 排在 99% 位置附近的值
更白话地说:

q01 ≈ “正常小值边界”
q99 ≈ “正常大值边界”
它们不是最小值和最大值,而是把最极端的少量异常值排除掉之后的范围。

举个具体例子。假设某个机器人数据集里,dx 的一批值从小到大大概是:

[-10.0, -0.06, -0.05, -0.04, -0.03,
-0.02, -0.01, 0.00, 0.01, 0.02,
0.03, 0.04, 0.05, 0.06, 0.07,
0.08, 0.09, 0.10, 0.11, 8.0]
这里 -10.0 和 8.0 很可能是异常值,例如传感器错误、数据记录异常、碰撞瞬间动作等。

如果用最小值/最大值归一化:

min = -10.0
max = 8.0
那么正常动作值,比如 0.05,会被压到非常靠近中间的位置。模型会把大量正常动作都挤在很窄的归一化区间里,难以区分细微差别。

如果用分位数,系统会更关注大多数正常数据。例如可以近似认为:

q01 ≈ -0.06
q99 ≈ 0.11
这表示:

绝大多数正常 dx 动作大概落在 [-0.06, 0.11] 之间。
然后再把这个正常范围映射到 [-1, 1]。

例如:

q01 = -0.06
q99 = 0.11
raw = 0.025
代入公式:

normalized = 2 * (raw - q01) / (q99 - q01) - 1
= 2 * (0.025 - (-0.06)) / (0.11 - (-0.06)) - 1
= 2 * 0.085 / 0.17 - 1
= 0
所以 raw = 0.025 位于正常范围中间,会被映射成 0。

边界也很好理解:

raw = -0.06 -> normalized = -1
raw = 0.11 -> normalized = 1
因此,使用 q01/q99 的含义是:

不要让最极端的 1% 小值和最极端的 1% 大值决定整个动作范围;
用中间 98% 的主要数据范围来定义“正常动作尺度”。
这能让模型更关注真实控制中常见的动作变化,而不是被少量异常值带偏。

第二步:离散化
归一化后的动作在 [-1, 1] 之间。

OpenVLA 风格的离散化会把这个区间切成固定数量的桶,例如 256 个桶。

[-1, 1] -> 256 个离散区间
于是:

-1.0 附近 -> 第 1 桶
0.0 附近 -> 中间桶
1.0 附近 -> 第 256 桶
类比:

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐