做VLA模型的都知道,最头疼的从来不是效果,而是速度。视觉-语言-动作模型(VLA)把大模型那套庞大网络搬到机器人身上,效果确实好,但一次推理动不动几百毫秒甚至一秒多,机器人真等不起。我在做机器人操作模型落地时,最大的矛盾就是:模型越大效果越稳,可机器人控制频率要求几十赫兹,这俩几乎是天生的敌人。MoLe-VLA的思路很有意思——不压缩模型、不蒸馏、不量化,而是把大模型的每一层当成一个独立的“专家”,让模型根据当前任务的复杂程度,按需只跑一半的层。实测下来,推理延迟能砍掉将近一半,成功率却几乎不掉。这篇文章就把这套层专家路由机制的设计思路、训练流程、部署细节和踩坑过程完整记录下来,给正在折腾VLA落地的朋友做个参考。
1. VLA为什么这么重:性能与实时性的矛盾
1.1 VLA三大件的天然开销
任何一个VLA模型,结构上基本逃不开三块:视觉编码器(Vision Encoder)、大语言模型主干(LLM Backbone)、动作头(Action Head)。视觉编码器负责把摄像头图像变成视觉token,LLM主干负责融合视觉信息和语言指令,动作头再把这些融合后的特征映射成机器人各关节的期望位置或力矩。
这三块里,最重的就是LLM主干。现在的VLA模型动辄7B、13B参数,主干占掉90%以上的计算量。视觉编码器虽然也不小,比如SigLIP这类模型,但毕竟只在第一层把图像切块编码一次,后续计算量相对可控。动作头通常很轻,就是一个浅层MLP加一些归一化处理,输出连续动作或者离散动作token,几百毫秒的延迟里它只占零头。
问题的根源在于,LLM主干的每一层Transformer都必须按顺序计算。24层就是24个依次执行的算子,32层就是32个,一个都不能少。哪怕当前任务只是“把左边红色方块推到右边”,其实根本不需要覆盖复杂空间推理的深层语义,但模型仍然会傻傻地把所有层跑完。这里就是最大的浪费所在。
1.2 机器人对推理速度的硬性要求
机器人操作不是聊个天就完事,用户不会在乎一个聊天机器人回复快0.2秒还是快0.5秒。但机器人控制完全不一样。典型的力控或位置控制回路要求几十到几百赫兹的输出频率,即便用较慢的顶层规划加底层执行架构,VLA的输出频率最好也要达到10到20赫兹。一次推理超过100毫秒,很多精细操作就已经开始抖了;超过300毫秒,基本只能做离散的“感知-决策-执行”循环,做不了连续平滑的插值操作。
我用过一个8B量级的VLA模型做桌面抓取,图像分辨率224x224,加上24层Transformer,单次推理耗时在450毫秒到600毫秒之间。配合底层PID控制勉强能跑,但一旦目标物体移动,或者需要连续追踪调整,延迟就会导致明显的“反应迟钝”——机器臂已经到位了,视觉信息才刚算完,抓取位置就偏了。这背后的物理本质很简单:控制系统的延迟直接进入闭环增益的分母,延迟越大,系统能稳定的最大增益就越低,操作精度自然上不去。
缩短VLA推理延迟的传统路子大家都试过:量化到INT4、知识蒸馏换成小模型、剪枝、或者用early exit提前从中间层输出。坦白说,每种方法都有代价。INT4量化效果直观,但有些层对量化扰动特别敏感,精度掉起来不讲道理;蒸馏成小模型思路简单,但小模型的容量瓶颈在复杂长程任务上非常明显;early exit只解决“提前终止”问题,没办法处理“定向跳过不需要的计算”这种情况。MoLe-VLA选的路径和这些都不同:保留完整模型容量,只按需激活一半的能量。
2. MoLe-VLA的层专家设计:把层当作可调度的资源
2.1 从MoE借来的思想:稀疏激活的另一种形态
混合专家模型(MoE)的核心思想是稀疏激活:一个大模型内部并联很多个“专家”网络,每个token来了之后,路由网络只挑其中少数几个专家进行计算。这样等于在几乎不增加计算量的前提下把模型参数做大,效果往往比同参数量稠密模型更好。
MoLe-VLA把这种“稀疏激活”的概念从FFN层搬到了Transformer层这个层级维度上。MoE的专家是FFN子网络,MoLe-VLA的专家就是完整的Transformer层。MoE对token做路由,MoLe-VLA对输入样本做路由——每条输入(图像加指令的组合)经过门控网络判定难度之后,决定让哪几层参与计算、跳过哪些层。层本身就是可调度的计算资源,这就是标题里“把每一层当成专家”的准确含义。
这样做的好处非常明显。一是模型容量不丢,所有层的权重都还在,需要复杂推理的任务照样可以用满全部24层;二是计算效率大幅提升,简单任务走一个“捷径子集”,中等任务走15层,只有复杂任务才需要全部层参与。等于把一枚火箭发动机拆成了多个可独立点火的小发动机,爬坡用1号2号,加速再点3号4号,没必要每次都全推力发射。
这与early exit有着根本性的区别。做early exit的模型,一旦在中间层决定退出,后面所有层都不跑了,输出只来自浅层特征。MoLe-VLA不是这样,它允许任意层子集跳过计算,但信息的最终输出仍然经过完整网络末端,只是过程中某些位置被直接跳过。打个比方,early exit相当于“走到一半就交卷”,MoLe-VLA的层路由相当于“挑着做试卷上的题,但最后整体提交”。这个差异在特征交互上很重要,因为残差连接和层归一化让中间层之间存在强依赖,纯early exit浅层输出往往缺乏必要的语义抽象,而层路由机制可以在保住深层的语义抽象能力的同时,减掉冗余层的计算量。
2.2 层门控与难度感知的路由策略
层路由的实现核心是两个组件:层门控网络(Layer Gate)和一个路由策略。层门控网络是一个很轻的MLP,输入可以是VLA主干前几层输出的特征向量,输出是对每层打的一个“参考分数”,表示这一层对当前样本的贡献预期。这个网络参数非常小,通常只有几百K参数,计算成本几乎可以忽略。
难度感知是怎么实现的?关键在于,VLA的输入本身就包含了任务复杂度的强信号。比如一个抓取简单静态物体的任务,视觉token之间的空间相关性很规律,语言指令也很短,这种情况下模型浅层已经能提取足够的空间特征,深层语义抽象模块可以歇一歇。但对于“把蓝色杯子放到红色托盘上,然后绕过黑色障碍物”这种任务,需要多层推理、空间关系整合、计划生成,模型就需要把20多层的容量全用上。
路由策略上,我实现了一种“单点门控+连续化选择”的方案。门控网络不直接输出“第5层跑不跑”这种离散二值决策,而是输出一个连续的重要性分数,再通过类似Straight-Through Estimator的方式让梯度能够穿过离散采样点回传。真正推理时,用Top-K选择机制:设定一个预算B(比如50%的层数),门控分数最高的那一半层被激活,另一半跳过。这个连续化设计很关键,如果一开始就直接训练离散门控,梯度一下断掉,训练根本收敛不了。
还用了一个小技巧:让门控分数面对一定的Gumbel噪声扰动。这样在训练早期,层的选择具备一定随机性,不会所有样本都涌向前几层或后几层,让模型在训练阶段就见过了各种层子集路径,推理时无论选中哪几条路径,特征分布都不会太漂移。没有这个噪声项,训练收敛后的路由会变得非常“自私”,只走几条固定路径,泛化能力会受影响。
3. 训练与推理:让模型学会只跑一半层的关键步骤
3.1 两阶段训练流程
MoLe-VLA的训练严格分成两个阶段,顺序不能乱。
第一阶段是标准的VLA预训练。用正常的全层计算训练视觉编码器、LLM主干和动作头,让它先掌握“图像+语言到动作”的基本映射能力。这一步结束时,模型所有层的参数都已对齐,具备完整的操作能力。千万注意不能跳过这一阶段直接做层路由,否则门控网络会误导模型走出一条完全没经过充分优化的路径,后面的效果必然拉胯。
第二阶段是层路由对齐阶段。此时冻结主干参数,只训练门控网络。数据方面要精心构造难度分布样本,刻意混入简单、中等、复杂三类任务的数据,让门控网络见到足够的难度多样性。训练目标除了任务本身的动作预测损失之外,还要加上一个路由预算正则项:让被激活的层数尽量贴近目标预算。常规实现方式是加一个L1惩罚到门控输出上,系数从0.1慢慢调到0.5。一开始约束松一点,让路由自由探索,后面逐步收紧,把“跑满全层”的成本拉高,逼着门控压缩激活层数。
有个容易忽视的细节:阶段二不能只训练路由头,姿态非常关键。主干被冻结是因为不想让门控通过与主干“共谋”来作弊——如果让主干也继续更新,模型很容易把新的信息都堆到更少的层上,看上去只跑一半层效果没掉,实际是牺牲了其他任务的鲁棒性。冻结主干会损失一点阶段二的收敛速度,但换来的是模型在不同场景下的稳定性,这笔账怎么算都值。
3.2 推理时的预算控制与动态调度
训练完成之后,推理侧只需要一步:前向计算时边跑层边查看门控分数。具体来说,我们从第1层开始,对每一层调用门控网络计算该层对当前样本的匹配度。这个过程是解码式的、逐步进行的。为了避免“看完整张卷子再决定做哪道题”这种不必要的全量开销,门控网络本身只用了主干前3层输出的特征做输入,再通过一层线性变换映射到每一层。分摊下来,算门控的损耗不到全量推理的3%,完全可以接受。
预算控制上,我最初直接按“一半层”固定预算,发现效果不理想。简单任务只用8层就能完成得很漂亮,中等任务要16层,复杂任务才需要22层以上,固定一半不是最优解。后来改成“分层级预算”:用门控网络输出的总分数均值作为复杂度估计,当分数低于阈值T1时,预算设定为35%的层;分数在T1和T2之间设定为60%层;分数高于T2才跑满全量。这个策略在实测中比固定50%更省算力,还能保住复杂任务的精度,因为复杂任务压根不会被错误地压缩。
推理时还有一个落地层面的优化:跳层不是真的“物理上移除”某一层,而是在模型的forward代码里加一个if语句判断当前层是否在激活集合中,不在就直接跳过,把上一步的输出原样传给下一层。由于PyTorch的层对象本身还是完整挂在模型里的,跳过的层不参与autograd反向传播计算,训练时更省显存,推理时更省算力。但务必要注意,跳层之后KV cache仍然要按正常顺序维护,每层的位置编码也不可以跳过更新,位置信息一旦错位,预测出来的动作序列就乱了。
4. 关键实现细节与部署参数选型
4.1 模型骨架与基础参数
MoLe-VLA的主干我选的是7B规模的稠密LLM,24层Transformer,隐藏维度2048,注意力头32个。视觉编码器用SigLIP-SO400M,图像输入分辨率自由缩放,目标是让视觉token化成576个patch序列。语言指令则走文本tokenizer,拼接到视觉token前面。动作头用的是连续动作预测,输出维度是机器人关节数乘以动作预测窗口长度,例如7自由度的机械臂加1个夹爪,动作窗口为4帧,输出就是32维向量。
训练设备是4块80G显存的加速卡,靠张量并行把7B模型摊到4卡上。全层预训练阶段单卡batch size只能放到4,梯度累积16步,等效全局batch为256。阶段一只跑了40K步,阶段二再跑12K步。门控网络放在主卡上,门控本身的计算量很小,不会成为并行瓶颈。
关键参数我直接整理成表格,方便有需要的朋友参考:
| 配置项 | 取值 | 说明 |
|---|---|---|
| 主干 | 7B稠密LLM,24层 | 隐藏维度2048,32头 |
| 视觉编码器 | SigLIP-SO400M | 输出576个视觉token |
| 动作头 | 两层MLP | 输出32维连续动作向量 |
| 门控网络 | 3层MLP,256隐藏 | 输入为前3层输出特征均值 |
| 路由预算 | 35% / 60% / 95% | 按复杂度分数分三档 |
| 阶段二正则系数 | 0.1 -> 0.5 | 线性退火 |
| 训练精度 | BF16 | 主干部分BF16,门控FP32 |
4.2 层重要性分析与不可跳层清单
做层路由之前,有一个特别容易忽略的前置工作:层重要性分析。我先把24层Transformer按不同任务都做了完整评测,把每一层的输出接上动作头,测各层对最终动作误差的贡献。结果很有信息量——前2层的贡献在所有任务上都很大,因为视觉token与语言token的融合主要发生在这里,跳掉前两层,后面的层拿到的就是残次品特征。最后一层也基本不能跳,它直接贴近动作头的输出分布,跳过之后动作头输入分布会剧烈漂移。
真正可以跳的是中间层的特定集合,而且不同任务跳的层位置还不一样。视觉空间任务主要在中间层做图片特征的空间推理,跳掉这些层会明显影响定位精度;而语言指令较简单的重复性任务,大量中间语义层都是冗余的。这就是为什么MoLe-VLA不固定层跳跃集,而是每样本动态选择层集合的原因。动态机制能自适应任务分布,而固定剪枝做不到。
我把不可跳层总结成三条规律:
- 前2层务必保留:模态融合的“第一现场”,删除等于断粮。
- 最后1层务必保留:动作头需要它来做模式对齐。
- 与注意力计算中能量分数突变的层(所谓“关键层”)务必保留:这一类层一旦跳过,会使后续层的输入特征分布产生不可逆偏移。
这三条是硬约束,写入门控Top-K选择逻辑前,先把这些层的分数强制置为无穷大,确保任何输入都不会把它们选出去。加上这个约束之后,模型稳定度提升了一大截,不加约束的版本在10%样本上会出现动作输出明显抖动的情况。
4.3 部署层的配合:批处理与缓存
模型部署到实际机器人上时,我遇到过模型效果好但帧率上不去的问题。排查后发现问题不在算法,而在服务框架。门控层路由让每一层的计算量变得不规则,这个特征对动态批处理非常不友好——一个batch里的两条样本,一条需要20层,一条需要8层,走for循环一层层同步计算就会出现“水桶效应”:层数少的样本被层数多的样本拖住,等待浪费的时间直接抵消了跳层的收益。
解决方案是“同预算组批”。每帧进来的N条推理任务先按门控预测的复杂度分成三组,组内批次大小动态调整,每组独立编排前向循环。简单组因层数少计算快,可以稍大一点批;复杂组批小一点,因为每层都很重。实测下来,同预算组批比统一批处理在吞吐上又提升了约20%。
另外,视觉编码部分和LLM推理部分分开部署管线。视觉编码器输出token后,会经过一层投影到LLM的embedding维度,这一层我放在视觉端完成,以减少LLM侧接收时的转换开销。末端动作头的推理开销极小,就和LLM放一起了。整条链路里,真正吃算力的还是中间的Transformer层,这也是MoLe-VLA能发挥最大优势的地方。
5. 实测数据与避坑实录
5.1 真实场景下的表现
在桌面操作仿真环境和真实机械臂上,我分别做了测试。先看数据:
| 指标 | 全层推理 | MoLe-VLA(动态路由) | 提升 |
|---|---|---|---|
| 平均推理时延 | 460毫秒 | 252毫秒 | 降低45% |
| 简单任务平均激活层数 | 24层 | 9.1层 | 降低62% |
| 中等任务平均激活层数 | 24层 | 14.6层 | 降低39% |
| 复杂任务平均激活层数 | 24层 | 22.8层 | 降低5% |
| 抓取成功率 | 91.2% | 90.6% | 仅降0.6% |
| 长程任务成功率 | 78.5% | 77.9% | 仅降0.6% |
从表中可以直观看到,延迟下降主要来自简单和中等任务,而这两类任务在真实机器人日常操作中占比超过70%。复杂任务本身就需要足够层数,MoLe-VLA不强行压缩它们,所以这一档几乎没有损失。整体成功率只掉了0.6个百分点,在实测噪声范围内。考虑到接近一半的推理延迟节省,这个精度损失完全可以接受。
控制环路的直接收益是,机械臂从原来只能按5到10赫兹的“慢思考”模式,提升到了接近20赫兹的反馈控制频率。最直观的变化是抓取移动目标物体的成功率,在全层推理模式下基本只能靠“提前量”去赌,在MoLe-VLA模式下已经能实现真正的视觉伺服追踪,夹爪可以跟着目标走完一条弧线再去闭合,稳定性提升非常明显。
5.2 常见问题速查与排查方法
不知不觉写了这么多,把实际操作中踩过的坑一并整理成速查表,遇到同类问题可以直接照方抓药:
| 问题现象 | 直接原因 | 处理办法 |
|---|---|---|
| 跳层后动作抖动明显 | 跳到了关键层 | 重新做层重要性分析,将能量突变层加入保留集合 |
| 训练阶段门控不收敛 | 离散决策阻断梯度 | 改用Straight-Through Estimator并在门控输出加Gumbel噪声 |
| 简单任务仍跑了大量层 | 路由正则系数过大或过小 | 检查预算正则系数,调低到0.2后逐步增加 |
| 部署时帧率不升反降 | 动态批处理出现水桶效应 | 改成同预算组批,分三组独立编排 |
| 长程任务成功率下降明显 | 复杂任务被当成中等任务压缩 | 调高T2阈值,让更极端情况跑到全层模式 |
| 视觉token与文本指令不匹配 | 跳过了跨模态融合层 | 硬性保留前2层,不做任何路由 |
除了表格里的,还有一个经验特别想提醒:门控网络训练数据里的难度分布一定要均衡。我第一版训练数据里简单任务占了70%,结果门控直接把所有任务都往低预算方向推,复杂任务成功率掉到50%以下。后来重新把数据分布调整成简单40%、中等40%、复杂20%,路由行为才趋于合理。
另一个常被忽略的细节是动作头的归一化。VLA的动作预测通常用的是归一化后的关节位置增量,这个归一化参数在阶段二冻结时也要一并冻结。有人会出于好心继续更新归一化的统计量,结果动作输出范围漂移,机器人突然做出“抽搐”动作,排查半天才找到是这里的问题。记住,路由对齐阶段,所有涉及主干和动作头的统计量都必须固定。
关于未来的扩展,还有一个方向是运行时的自适应预算。当前方案是门控网络一次性输出预算档位,其实还可以做成闭环形式:先跑前4层,根据中间特征实时预测还需要多少层,边跑边决定是否继续。这个方案理论上能把平均层数压到更低,但工程落地时要注意,实时调整预算会引入控制层面的不确定性,需要配合决策超时机制才能保证机器人不会在只跑了一半层的时候被强制“交卷”。我在仿真环境里试过一版,帧率还能再提15%左右,但还有概率性抖动没有彻底解决,等后续版本稳定了再详细展开。