资讯动态

OpenVLA ActionTokenizer详解:从连续动作到token序列的工程平衡

发布时间:2026/9/19 17:10:08 来源:尧图企业网站定制
1. 从“7维连续动作”到“token序列”VLA动作建模的第一性原理先聊一个很多人刚接触OpenVLA时都会产生的疑问机器人动作明明是连续量比如末端执行器在三维空间里的x、y、z坐标绕三个轴的旋转角再加上夹爪开合量一共7个维度每个维度都是带小数的实数。这类连续信号怎么塞进一个基于Transformer的大语言模型LLM里LLM天生只会处理离散token你让它直接回归输出一个浮点向量模型结构和训练目标全都对不上。这就是ActionTokenizer存在的根本原因。它的核心思路是把连续动作空间“切碎”成离散格子每个维度独立映射成一个离散编号再把编号当作token id交给LLM去预测。相当于把“末端执行器往前移动0.023米”翻译成“在动作词表里选第57号token”把“夹爪开合0.8”翻译成“选第203号token”。模型要做的不是算出一个精确到小数点的坐标而是像做阅读理解选择题一样从256个候选项里挑出最合适的那一项。这套思路最早在大规模VLA模型RT-2里已经验证过但RT-2对动作的离散化做得比较粗糙每个动作维度只分了8个区间八分之一的粒度控制精度基本只能用来做粗粒度抓取。OpenVLA把每个维度的量化桶数提高到了256这个粒度足以承载真实机械臂的闭环控制需求。也正因如此OpenVLA的ActionTokenizer被后来一堆下游工作当成了默认动作接口比如OpenVLA-LoRA、RoboCoder、OpenVLA-Flash等直接复用这套token化方案做微调。这里有个前置概念需要澄清256不是动作token的总数而是每个动作维度可选的离散取值数量。7维动作在OpenVLA里对应7个token每个token在各自的256个桶里选一个id。整篇文章我会围绕“为什么这样设计”“底层怎么算的”“实际用起来有哪些坑”来展开。2. ActionTokenizer到底切了什么256是量化桶数不是token个数2.1 逐维独立量化的数学过程OpenVLA的ActionTokenizer做得相当朴素但朴素不等于简单。它对7个动作维度分别计算最小值、最大值然后把每个维度归一化到[0, 1]区间再乘上256后向下取整截断到[0, 255]。伪代码大致是import numpy as np def tokenize_action(action, min_vals, max_vals, num_bins256): normalized (action - min_vals) / (max_vals - min_vals 1e-6) normalized np.clip(normalized, 0.0, 1.0) bin_indices (normalized * (num_bins - 1)).astype(np.int64) return bin_indices # shape: (7,)每个元素是0~255的整数这里有三个细节值得展开。第一个细节max_vals、min_vals是从训练数据集里统计出来的全局范围而不是单条轨迹的局部范围。这意味着不同数据集的统计结果不一样直接导致同一个token id在不同数据集上对应完全不同的物理动作。比如BridgeData V2里机械臂末端的x轴变化范围可能是[-0.3, 0.3]米而LIBERO某个任务里可能只有[-0.1, 0.1]米同样是第100号token前者代表大约0.0024米的位移后者只代表0.0008米。这是OpenVLA跨数据集/跨机械臂迁移时最隐蔽的坑后面专门讲。第二个细节除以max - min之前加了一个极小值防止除零。这个在代码里很不起眼但没有它某个维度如果全程恒定比如固定高度抓取任务里z轴几乎不变就会直接算出NaN整个训练batch就崩了。我自己第一次跑数据预处理时就踩过这个报错信息还不是“divide by zero”而是莫名其妙的loss变成NaN查了半天才定位到是量化函数的问题。第三个细节旋转维度通常用axis-angle轴角表示范数范围远小于平移维度。末端执行器位置可能变化几十厘米但旋转角度的变化往往在正负π之间。如果直接把所有维度丢进同一个归一化框架旋转维度的小幅变化很容易被量化噪声吞掉。OpenVLA的做法是对每个维度单独统计范围这本身就是逐维独立量化带来的好处——如果做一个统一的多维向量量化比如VQ-VAE那套某些维度的细节就丢了。2.2 token id如何映射回机器人动作反量化过程相对直观就是在量化过程倒着算一遍def detokenize_action(token_ids, min_vals, max_vals, num_bins256): bin_centers (token_ids 0.5) / (num_bins - 1) actions bin_centers * (max_vals - min_vals 1e-6) min_vals return actions # shape: (7,)注意这里取的是token_id 0.5的桶中心不是桶的左边沿。如果你习惯性地用token_id / (num_bins - 1)去还原会发现所有动作都系统性偏小累积误差在长程任务里会越来越明显。这个0.5偏移是量化感知训练和部署里的一个常见小陷阱很多从图像量化迁移过来的人会在这里翻车。还原后的动作直接下发到机械臂控制器吗严格说不是。OpenVLA官方流程里还原得到的7维动作会被当作目标位姿发给机械臂的底层控制器比如位置控制模式下的目标点然后由控制器内部做插值和PID跟踪。模型不需要输出关节力矩这种高频量它只负责规划宏观的末端轨迹点动作执行频率通常在3到10赫兹。这也意味着量化误差只要小于机械臂本身的位置闭环精度就可以忽略不计。2.3 256这个数字为什么刚刚好既然动作精度取决于量化桶数是不是桶数越多越好理论上是的但工程上要平衡三重成本。第一重成本是词表大小。OpenVLA用的LLM骨干是Llama-2 7B原始词表是32000个tokenOpenVLA把动作token追加在词表末尾每个维度256个候选值7个维度一共扩展了7×2561792个token另外还有停止token等特殊标记词表变成大约33800。如果桶数提高到1024动作token数会变成7×10247168词表膨胀22%左右embedding矩阵变大训练和推理显存压力都上升。在7B模型里这不算致命但对显存敏感的部署场景并不友好。第二重成本是训练难度。动作token本质上是在做256分类相比RT-2的8分类学习难度明显更高。模型需要在海量样本里充分观察到每个桶的边界情况才能把“相近动作落在相邻桶”这种连续性关系学出来。桶数越大冷启动时没被充分覆盖的桶就越多模型容易在部分桶上过拟合或出现死桶。第三重成本是动作执行的真实精度需求。这里做一个粗略的定量估算如果机械臂末端的工作空间在x轴方向跨度约25厘米256个桶意味着每桶约0.1厘米也就是1毫米左右。末端执行器位置控制精度在这个量级已经是相当不错的表现再往下细分到亚毫米级别关节间隙、标定误差、控制延迟带来的扰动都比量化误差大得多单纯加密量化桶数没有实际意义。256这个数字本质上是一个“够用且不浪费”的工程平衡点。3. 从训练到推理动作token在OpenVLA里的完整生命周期3.1 训练阶段如何构造动作token标签OpenVLA的训练数据格式是长这样的一张或多张当前相机图像一段自然语言指令以及一条动作序列。这条动作序列需要被转成token标签和指令文本拼接在一起喂给模型做自回归预测。具体来说一个训练样本长这样用户image 把红色杯子放到托盘上 助手action_57 action_203 action_128 action_44 action_91 action_176 action_232 eos其中action_57表示第0维动作选择了第57号桶依此类推7个动作token对应7个维度。动作序列可以是一步也可以是未来多步。OpenVLA在训练时会把未来T个时间步的动作全部展开像文本一样逐token预测。这里有个关键设计**每个动作token的预测都具备独立的梯度路径模型在预测第2维动作token时可以看到前面维度已经预测出的token。**这种自回归分解本质上是在利用维度间条件依赖关系比一次性直接回归整个7维向量更容易建模复杂的关节约束。损失函数就是标准的交叉熵只计算动作token部分以及停止符token指令和图像的交叉熵会被mask掉。这意味着模型学习的核心目标是给定视觉观察和语言指令准确推断“每个动作维度该落在哪个256分类的桶里”。3.2 推理阶段自回归生成与机器人执行的衔接推理时VLA模型逐token生成动作序列。官方实现默认的做法是贪心解码greedy decoding也就是每个token都选分类概率最高的那个桶。7个动作token全部生成完后通过反量化得到7维动作向量送入机械臂控制器执行一步然后重新采集图像开始下一轮预测。这个流程可以设计成两种模式一种是single-step模式每次只生成一步动作做完就停机等新图像。这种方式控制频率低但每一步动作都基于最新观测适合环境动态变化较强的场景。另一种是multi-step/chunk模式一次生成未来多步的动作序列机械臂连续执行完再重新规划OpenVLA也支持这种方式。好处是动作更平滑减少模型频繁切换带来的抖动坏处是中间步骤缺少新图像反馈碰到突然出现的障碍物容易反应不过来。实际操作中chunk size取3到5步时体验比较均衡。无论哪种模式有一个点必须注意**执行频率要低于模型的单步推理时间否则会产生动作积压。**假设模型单步推理耗时800毫秒机械臂执行一步动作只需要300毫秒你就必须在代码里加一个锁等模型给出新动作后再覆盖目标位姿而不是让控制器一个劲地执行旧目标。3.3 为什么7维动作用7个token而不是1个token这是另一个高频问题。能不能把7维动作拼成一个高维id比如第36291号token代表某个特定的6维位姿加1维夹爪组合理论上可以但工程上完全是灾难。首先是组合爆炸。7个维度每个维度256个桶总组合数是256的7次方大约7.2×10的16次方个可能组合。词表不可能装下这么多项即使只采样常见组合也会严重限制动作空间的覆盖度。其次是泛化能力崩坏。模型见过“位置为第57桶、夹爪为第203桶”的组合但新任务里出现“位置为第58桶、夹爪为第203桶”这种相邻但没见过的组合就完全无法推断了因为token之间没有结构化的连续性。逐维token化相当于把大组合空间拆成了7个独立的256分类小问题每个分类的边界清晰、样本充足模型学起来既稳又准。更妙的是这种设计让LLM的自回归特性完美发挥了作用。第1维token确定后第2维token的预测分布可以基于第1维的结果做条件调整这种逐步细化的生成逻辑和人类规划动作时的思维方式天然对齐——先定大致位置再微调姿态最后决定夹爪开合。4. 我在实践里踩过的坑和实测建议动作量化的细节4.1 归一化范围不一致导致的动作偏移这是我在微调OpenVLA模型时踩过最大的坑。事情是这样的我从官方仓库下载了在BridgeData V2上训好的权重直接拿来跑仿真环境里的一个抓取任务。理论上应该能跑通但机械臂末端总在目标位置上方大约1到2厘米处悬停差那么一口气就是抓不下来。查了几轮prompt、图像输入、动作执行频率都没发现问题最后把模型预测出的动作token反量化回数值和真实动作做对比才发现x、y、z三个维度的值整体偏小了一截。问题的根源就在于我用的仿真环境动作空间范围-0.5到0.5米比BridgeData V2训练集的统计范围-0.25到0.25米更大。模型学到的是“在BridgeData的范围里选一个桶”同样的桶编号在我的环境里反量化出的实际位移自然地按我的环境范围换算但模型并没有见过更大范围的样本输出的桶集中在中间区域导致动作幅度被压缩。解决办法很简单微调时把目标环境的数据和原始数据混合重新统计归一化范围让量化器适配新的环境。如果是零样本部署则要尽量选择动作空间范围与训练集接近的任务。4.2 夹爪维度的特殊处理7维动作中前6维是末端执行器的位置和姿态最后一维是夹爪开合。夹爪动作的特点和笛卡尔坐标完全不同它往往是离散开关式的要么全开要么全闭中间过渡态极少。这在很多数据集的记录里会体现为夹爪维度数值呈双峰分布0附近和1附近各占一大片。直接把夹爪维度塞进统一的256量化框架里问题在于模型会把中间值比如0.4、0.6也当作合法输出来预测。机械臂控制器收到这类半开半闭的目标值夹爪电机可能会来回抖动甚至卡在中间状态夹不住东西。我在实际测试里遇到过不明原因抓取失败仔细看执行录像才发现夹爪在接近物体时从全开变成了半开物体直接卡在指缝里掉下去。解决方式有几种一种是在反量化后加阈值大于0.5置1小于0.5置0简单粗暴但很有效另一种是在数据预处理阶段就把夹爪维度二值化让模型只学两个桶还有一种是在推理时把夹爪token单独限制在256个桶中的两端若干个桶内用mask方式禁止输出中间桶。我自己更推荐第一种改动最小且在大多数基于夹爪抓取的场景下完全够用。4.3 贪心采样还是加温度采样官方推理默认是贪心解码每个token选概率最高的桶。这个模式下动作序列通常比较稳定但会牺牲一定的多样性。在符号化的任务中比如“把杯子放到托盘左侧”和“把杯子放到托盘右侧”都是合法指令贪心解码会倾向于概率最高的一条如果高概率路径因为环境扰动被堵死模型可能反复输出同一个被阻塞的动作形成死循环。有些下游工作会改成带温度的采样采样前对logits除以一个温度系数一般取0.8到1.2。温度小于1会让分布更尖锐动作更保守温度大于1会增加探索动作更多样但代价是偶尔会从低概率桶里抽到明显不合理的动作比如夹爪突然翻转180度。我的实测感受是**在固定任务评估里用贪心在开放语义的灵巧操作里用温度0.9到1.0的采样同时配合动作平滑滤波。**千万别用temperature接近2的激进参数VLA模型的输出空间本质上还是高维连续动作的低维投影过度随机化会稀释动作的连续性。4.4 迁移到其他机械臂时如何重算量化范围OpenVLA官方模型在高自由度机械臂上表现不错但迁移到UR5、Franka以外的新机械臂时量化范围需要重新匹配。这个过程我建议遵循三步。第一步采集目标机械臂在任务空间里的实际运动范围不一定要完整跑任务只要操作员手动示教或者用随机策略扫一遍工作空间记录末端位姿的最大最小值即可。第二步把采集到的统计量替换掉原来的min_vals和max_vals重新tokenize目标数据。第三步用一两百条包含新机械臂动作的小数据集对模型做轻量微调让LLM适应新的量化映射关系。这里有个值得注意的细节替换范围后同一token id对应的物理含义变了模型的输出分布需要时间重新适应。如果跳过第三步直接零样本部署前期大概率会出现大幅度且连贯的报错动作因为模型还在用旧环境的比例尺去解释新环境的256个桶。这与很多人想象的“量化函数改一下就行”完全相反。实测下来即使只微调几十步比如LoRA rank16下训练2000步也能让动作质量的提升非常明显。5. 与大语言模型之外的动作解码方式对比token化方案的代价与补偿5.1 直接回归、GMM与Diffusion方案的本质区别token化不是唯一的动作输出方式。在OpenVLA之前和之后学界对“如何从神经网络里吐出连续动作”主要探索过三条路线。直接回归是最朴素的做法模型在最顶层接一个全连接层输出7维实数值。优点是实现简单没有量化误差缺点是LLM训得好好的序列生成能力被架空了模型被迫把“连续值推理”这个和语言建模目标不一致的任务强行压到最后一个隐藏层上训练效率低而且容易在复杂多模态分布上取均值导致动作震荡。**GMM高斯混合模型**让模型输出多个高斯分量的均值、方差和权重最后从混合分布中采样。相比单值回归GMM可以表达多模态动作比如“绕过障碍物从左边走还是从右边走都行”这类分布。缺点是参数数量多、训练不稳定——方差头很容易坍缩到极小值而且采样和似然计算在自回归框架里都比较别扭。Diffusion Policy是这两年连续动作生成的主流方案通过一个扩散模型逐步去噪生成一整段动作序列。它的动作质量很高能够处理强多模态分布也天然支持变长动作生成。但和VLA结合时有个难题扩散模型的去噪迭代通常在推理时需要多步采样每一步都要过U-Net或DiT的主网络这就导致推理延迟明显增加。虽然有很多蒸馏方案能压缩到一步或几步但和LLM的“一次前向、自回归生成文本”机制相比结构仍然笨重得多。OpenVLA选择token化核心考量是让动作生成完全复用LLM的语言建模能力不引入任何额外的网络结构。模型用训练语言的方式去训练动作用生成语言的方式去生成动作整个VLA模型就是一个加了视觉输入和动作词表的自回归Transformer推理前向次数和文本生成一致。5.2 token化方案的代价到底在哪token化方案最常被吐槽的就是精度损失。256个桶看似够用但在高精度装配等任务里毫米级的量化误差直接影响成功率。这个问题确实存在但要看清两点第一OpenVLA并不是为亚毫米级精密装配设计的它更擅长长程任务的理解与规划第二很多实时控制任务在底层本来就有平滑、滤波和PID补偿量化噪声会在闭环中被打磨掉一部分。另一个代价是训练效率。模型要从256个类别的交叉熵损失中学会动作语义相比连续回归需要更多样本。尤其是一些数量稀少的桶如果训练数据里从没出现过对应的动作区域模型的预测分布就会在这些桶上出现空洞推理时只能靠插值猜效果自然打折。这也是为什么OpenVLA的数据预处理很重要数据多样性直接决定了动作空间覆盖度。某些任务如果训练集动作范围只覆盖了理论工作空间的30%换到完全没见过的位置附近部署性能衰减会很明显。5.3 基于ActionTokenizer的改进方向从OpenVLA发布到现在围绕ActionTokenizer做了不少改进工作有几个方向我认为很值得关注。一个是自适应离散化。统一256桶的思路在表示效率上不够最优一些区域动作变化剧烈但训练样本少有些区域平缓但样本多。按数据分布加密热点区域、稀疏冷门区域理论上能提升精度上限代价是实现复杂度变高。另一个是连续与离散混合。主干的6维位姿走扩散或回归夹爪等开关型动作走token化分类。这种混合架构能兼顾精度和稳当性在不少下游任务中有效但牺牲了纯token化方案的结构统一性。还有一个是层级化动作token。先预测粗粒度的动作意图桶再细分为精确桶相当于做两级分类第一级告诉模型“去左边还是右边”第二级决定具体偏多少。这能让模型在语义理解和运动控制之间多一层抽象理论上对泛化有帮助目前也有一些三维空间量化的研究在做类似尝试。从我自己的经验看现阶段最值得投资的改进不是把256改成1024而是把动作范围的统计方式、夹爪维度的处理、采样策略这些工程细节打磨好。这些问题看起来琐碎但每一个都在实验中真实影响过我的成功率。对一个机器人工程师来说把一套方案用透比频繁换方案更能积累稳定的手感。6. 我的最终实践建议如果用一句话总结OpenVLA的ActionTokenizer就是把连续动作空间用256个离散桶逐维切碎7个维度变成7个token交给LLM用语言建模的方式去学习和预测。这套方案牺牲了一点精度换来了结构统一性、训练稳定性和推理效率在VLA这个赛道上是一个相当实用的工程选择。给准备入手的同学三点建议。第一不要光盯着模型的参数和benchmark先把动作token化这一步的细节吃透尤其是归一化范围、夹爪二值化和反量化时的桶中心偏移这三件事直接决定你部署能不能通。第二拿到官方权重后先在仿真环境里可视化预测出的动作token序列确认模型的行为符合预期再上真机。真机上一旦出现奇怪动作优先检查token化和反量化环节别第一时间改prompt。第三如果要在自己的数据集上微调至少包含与原训练集重叠的一部分数据让模型在重新统计的范围里缓慢过渡否则动作分布会崩得很厉害。我在跑完这些实验之后最大的感受是VLA模型的智能层级往往让人把注意力全放在多模态理解上而真正决定任务成败的反而是动作接口这些“不起眼”的工程细节。ActionTokenizer看起来只是简单地把连续值离散化但它的设计取舍深刻影响了OpenVLA整体的性能上限和迁移能力。理解了这一层你再去看各类VLA模型的设计差异心里会清晰很多。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价