OpenVLA和OmniVLA的一些对比

2026年3月13日
预计阅读时间:26 分钟

OpenVLA和OmniVLA的一些对比

13.1. 架构继承关系

Llama-2(基座 LLM)
   │
   ├─ Decoder-only Transformer,32层,hidden_dim=4096
   ├─ Causal Attention(只能看到前面的 token)
   ├─ 输出层 lm_head: Linear(4096 → 32000) 预测下一个词
   │
   ↓
Vicuna-7B(指令微调)
   │
   ├─ 在 Llama-2 上用对话数据微调
   ├─ 架构不变,只是权重更新
   │
   ↓
LLaVA v1.5(加视觉能力)
   │
   ├─ 加 CLIP ViT 作为视觉编码器
   ├─ 加 MLP 投影层:将视觉特征投影到 LLM 维度
   ├─ 序列格式:[BOS] + [视觉 token] + [文本 token]
   ├─ LLM 骨干仍然是 Vicuna-7B,架构不变
   │
   ↓
Prismatic VLM(改进视觉编码)
   │
   ├─ 将单 ViT 改为 双 ViT(SigLIP + DINOv2)
   ├─ 两路视觉特征拼接后投影,产生 512 个视觉 token
   ├─ 其余沿用 LLaVA 架构
   │
   ↓
OpenVLA(加动作预测 —— 自回归离散方案)
   │
   ├─ 加 ActionTokenizer:连续动作 → 256-bin 离散化 → token
   ├─ 动作预测方式:用 lm_head 自回归生成动作 token(和生成文字一样)
   ├─ 序列格式:[BOS] [视觉×512] [文本指令] → generate() → [动作 token×7]
   ├─ Loss:Cross-Entropy(离散分类)
   ├─ 推理:调用 generate(),逐 token 自回归生成,7个 token 需要 7 次前向传播
   │
   ↓
OpenVLA-OFT(优化微调 —— 并行连续方案,核心转折点)
   │
   ├─ 【动作生成】自回归 → 并行解码(一次前向传播输出所有动作)
   ├─ 【动作表示】离散 token → 连续数值
   ├─ 【输出层】  lm_head → MLP Action Head(新增独立网络)
   ├─ 【Loss】   Cross-Entropy → L1 回归
   ├─ 【输入改动】插入空 action embeddings 作为占位符
   ├─ 【注意力】  Causal Attention → Bidirectional Attention(动作位置改为双向)
   ├─ 【Action Chunking】支持 K 步动作块(如 K=8),一次输出 K×D 个动作值
   ├─ 【可选】FiLM 语言调制(OFT+ 版本,增强语言理解)
   ├─ 推理速度:比 OpenVLA 快 26×
   │
   ↓
OmniVLA(本项目 —— 沿用 OFT 动作方案 + 多模态目标条件)
   │
   ├─ 【沿用 OFT】MLP Action Head(MLPResNet_idcat,带 ResBlock)
   ├─ 【沿用 OFT】并行解码,一次前向传播输出 8 个 waypoint
   ├─ 【沿用 OFT】连续动作回归(MSE 替代 L1,效果类似)
   ├─ 【沿用 OFT】Action Chunking:8 waypoint × 4 维 = 32 个占位 token
   │
   ├─ 【不同于 OFT】保留 Causal Attention(未改为双向)
   ├─ 【不同于 OFT】占位 token 的 embedding 清零(OFT 用空 embedding)
   │
   ├─ 【OmniVLA 新增】多模态目标条件:视觉目标 / GPS位置目标 / 语言目标
   ├─ 【OmniVLA 新增】Pose Token:ProprioProjector 将 GPS 位置投影为 1 个 token
   ├─ 【OmniVLA 新增】Modality ID:在 Action Head 中拼接任务模态标识
   ├─ 【OmniVLA 新增】Modality Dropout:训练时随机丢弃目标模态
   ├─ 【OmniVLA 新增】平滑正则化:相邻 waypoint 差异的 MSE 作为额外 Loss
   │
   ├─ 序列格式:[BOS] [视觉×512] [Pose×1] [文本指令] [动作占位×32] [EOS]
   ├─ Loss:MSE(主) + 目标物体 Loss + 平滑正则
   └─ LLM 骨干仍然是 Vicuna-7B(Llama-2),架构未修改

有一个重要的实现细节不同:

  • OpenVLA-OFT:将 causal attention mask 改为 bidirectional attention(双向注意力),让动作 token 之间可以互相看到
  • OmniVLA保留 causal attention mask,动作 token 只能看到前面的 token,不能看到后面的

这意味着 OmniVLA 的做法更保守——它没有修改 Llama-2 的注意力机制,而 OpenVLA-OFT 为了让并行解码更有效,专门把动作位置的注意力改成了双向的。

OpenVLA-OFT 是对原始 OpenVLA 的微调方案优化,核心改动正好就是 OmniVLA 继承的部分:

OmniVLA 沿用了 OFT 的动作预测框架,然后在此基础上加了自己的东西:

  1. 多模态目标条件:支持视觉/位置/语言三种目标输入(OFT 只有语言)
  2. Modality ID:在 Action Head 中拼接 modality_id(OFT 没有)
  3. Pose TokenProprioProjector 将 GPS 位置投影为 token(OFT 用的是 robot state projector,概念类似但用途不同)
  4. MLP 结构不同:OmniVLA 用 MLPResNet_idcat(带 ResBlock),OFT 论文中描述的是更简单的 MLP
  5. Loss 不同:OmniVLA 用 MSE + 平滑正则化,OFT 用 L1回归

13.1.1. 原版 OpenVLA:自回归 token 预测

原版 OpenVLA 把动作预测当作文本生成——和 ChatGPT 生成回答一样,一个 token 一个 token 地自回归输出:

训练时(teacher forcing):
输入:  [BOS] [视觉...] [指令...] [动作1] [动作2] ... [动作31]
                                    ↓       ↓            ↓
预测:                             [动作2] [动作3] ... [动作32]
                                    ↑       ↑            ↑
                                  用 cross-entropy loss 与真实 token ID 做对比

推理时(自回归生成):
[BOS] [视觉...] [指令...] → 预测动作1 → 把动作1拼上去 → 预测动作2 → ... → 逐个生成32个

在这种模式下,动作 token 的 embedding 必须有意义——因为"动作1 的 embedding"是模型预测"动作2"的输入。如果清零了,模型就失去了"上一步预测了什么"的信息,无法做自回归。

所以原版 OpenVLA 中这 256 个动作 bin 的 embedding 会被训练、会被更新,它们是自回归预测链条中不可或缺的一环。

13.1.2. OmniVLA:Action Head 回归

OmniVLA 改成了一次性前向传播 + MLP 回归:

训练和推理都是:
[BOS] [视觉...] [指令...] [占位×32] → LLM一次性处理 → 取动作位置的hidden states → Action Head(MLP) → 连续动作值
                              ↑
                         清零(这些位置靠 positional encoding + attention 从上下文获取信息)

动作 token 不再是自回归链条的一部分,它们只是"留出 32 个位置"让 LLM 在这些位置生成 hidden state,再交给 MLP 回归出连续动作值。所以 embedding 清零没问题——甚至是必须的,避免无意义的词表 embedding 干扰。

13.2. 为什么omnivla没有像openvla那样,直接从预测token反解码出连续动作?

13.2.1. 原因 1:推理速度——1 次 vs 32 次前向传播

这是最直接的原因,对机器人实时控制至关重要。

OpenVLA(自回归)

预测动作1 → 拼到输入 → 预测动作2 → 拼到输入 → ... → 预测动作32
     ↑                      ↑                           ↑
  第1次前向传播           第2次前向传播              第32次前向传播

一个 7B 参数的 LLM,前向传播一次大约需要 几十到几百毫秒。32 次 = 数秒级延迟

OmniVLA(回归)

[所有输入一次性送入] → LLM 单次前向传播 → 取32个位置的hidden states → MLP → 32个动作值
                         ↑
                     仅1次前向传播

延迟降低约 30 倍。对于需要 10Hz+ 控制频率的机器人来说,这是质的区别。

13.2.2. 原因 2:离散化精度损失

OpenVLA 把连续动作值(如 0.3847)映射到 256 个离散 bin 之一:

连续值空间 [-1, 1]  被切成 256 格

每格宽度 = 2/256 = 0.0078

真实动作: 0.3847
最近bin中心: 0.3828  (bin #177)
量化误差: 0.0019

这个误差在每个维度、每个时间步都存在,会累积

OmniVLA 的 MLP 直接回归连续值,没有量化误差

hidden_states → MLP → 0.3847(直接输出浮点数)

13.2.3. 原因 3:动作维度之间的耦合

OmniVLA 预测 8 个 waypoint × 4 维 = 32 个值。

OpenVLA 的做法:逐个 token 生成,每个 token 对应一个维度。预测 x 方向速度时,只能看到之前已生成的 token(因为是自回归的),不能"偷看"同一时间步的 y 方向速度。

OmniVLA 的做法

# L1RegressionActionHead_idcat.predict_action
def predict_action(self, actions_hidden_states, taskid):
    batch_size = actions_hidden_states.shape[0]
    rearranged_actions_hidden_states = actions_hidden_states.reshape(batch_size, NUM_ACTIONS_CHUNK, -1)
    # ↑ 把 32 个 hidden states reshape 成 [B, 8, 4*4096]
    # 每个 waypoint 同时看到 4 个维度的信息
    action = self.model(rearranged_actions_hidden_states, taskid)
    return action

MLP 把同一个 waypoint 的 4 个维度的 hidden states 拼在一起reshape 操作),然后一次性预测出 4 维动作。这意味着 x、y、cos、sin 之间的关系(比如 cos²+sin²≈1)可以被 MLP 隐式学习。

13.2.4. 原因 4:Loss 函数更直接

OpenVLA:用 cross-entropy loss,优化的是"预测正确的 bin ID"。模型不知道 bin #177 和 bin #178 之间只差 0.0078——在 cross-entropy 看来,预测错一个 bin 和预测错 100 个 bin 的 loss 是一样的。

OmniVLA:用 MSE loss(看训练代码),直接优化预测值与真实值的距离:

loss = 1.0*torch.nn.MSELoss()(action_ref, predicted_actions) \
     + 0.1*torch.nn.MSELoss()(obj_pose_norm[lan_bool], predicted_actions[:,-1,0:2][lan_bool]) \
     + 0.1*torch.nn.MSELoss()(predicted_actions[:,0:-1], predicted_actions[:,1:])

注意第三项 MSELoss(predicted_actions[:,0:-1], predicted_actions[:,1:])——这是一个平滑正则化,鼓励相邻 waypoint 之间的动作连续变化。这种 loss 在自回归 token 预测的框架下根本无法实现(因为预测的是 token ID,不是连续值)。 代价是什么? MLP Action Head 需要额外训练一个小网络(MLPResNet,约几百万参数),而且放弃了 LLM 自带的 token 预测能力(32064 维 logits 输出被闲置)。但对于需要实时控制的机器人场景来说,这个 trade-off 非常划算。

13.3. MLP 如何回归

13.3.1. 单个 hidden state 长什么样?

LLM(Vicuna-7B)的每个位置输出一个 4096 维的向量。序列中有 32 个动作占位 token,所以有 32 个 hidden state:

动作占位位置:  [占位1] [占位2] [占位3] [占位4] [占位5] ... [占位32]
                ↓       ↓       ↓       ↓       ↓           ↓
hidden state:  h_1     h_2     h_3     h_4     h_5    ...  h_32
               4096维   4096维   4096维   4096维   4096维      4096维

提取出来后的 shape 是 [B, 32, 4096]

13.3.2. 32 个 token 怎么对应 8 个 waypoint?

常量定义:NUM_ACTIONS_CHUNK = 8ACTION_DIM = 4,所以 8 × 4 = 32 个 token。 每 4 个连续的 hidden state 对应 1 个 waypoint。reshape 操作把它们拼接起来:

# predict_action() 第 129 行
rearranged = actions_hidden_states.reshape(batch_size, NUM_ACTIONS_CHUNK, -1)
# [B, 32, 4096] → [B, 8, 4*4096] = [B, 8, 16384]

具体过程:

reshape 前: [B, 32, 4096]
  token 1:  [h_1]  ─┐
  token 2:  [h_2]  ─┤── 拼接 → waypoint 1: [h_1 | h_2 | h_3 | h_4] = 16384 维
  token 3:  [h_3]  ─┤
  token 4:  [h_4]  ─┘
  token 5:  [h_5]  ─┐
  token 6:  [h_6]  ─┤── 拼接 → waypoint 2: [h_5 | h_6 | h_7 | h_8] = 16384 维
  token 7:  [h_7]  ─┤
  token 8:  [h_8]  ─┘
  ...
  token 29: [h_29] ─┐
  token 30: [h_30] ─┤── 拼接 → waypoint 8: [h_29 | h_30 | h_31 | h_32] = 16384 维
  token 31: [h_31] ─┤
  token 32: [h_32] ─┘
reshape 后: [B, 8, 16384]

13.3.3. MLP 是逐个 waypoint 回归吗?需要回归 8 次?

MLP 利用 PyTorch 的张量并行,一次调用就同时处理 8 个 waypoint。 看 MLPResNet_idcat.forward() 的实际执行:

def forward(self, x, taskid):
    # x 的 shape: [B, 8, 16384]  ← 8 个 waypoint 在 dim=1 上并排
    x = self.layer_norm1(x)       # [B, 8, 16384]  LayerNorm 对最后一维操作
    x = torch.cat((x, taskid...), axis=2)  # [B, 8, 16385]  拼上 modality_id
    x = self.fc1(x)               # [B, 8, 4096]   Linear(16385, 4096) 对每个 waypoint 独立作用
    x = self.relu(x)              # [B, 8, 4096]
    x = block1(x)                 # [B, 8, 4096]   ResBlock
    x = block2(x)                 # [B, 8, 4096]   ResBlock
    x = self.layer_norm2(x)       # [B, 8, 4096]
    x = self.fc2(x)               # [B, 8, 4]      Linear(4096, 4) → 每个 waypoint 输出 4 维
    return x                      # [B, 8, 4]

nn.Linear 作用于张量的最后一维。当输入是 [B, 8, 16384] 时,它对 8 个 waypoint 共享同一组权重,但在计算上是并行的——就像 batch 维度一样。

所以准确地说:

  • 逻辑上:是的,每个 waypoint 独立经过同一个 MLP(权重共享)
  • 计算上:不是 8 次调用,而是 1 次矩阵乘法,8 个 waypoint 并行处理
  • 类比:就像 Linear 处理 batch_size=32 的数据不需要循环 32 次一样,dim=1 上的 8 个 waypoint 也不需要循环
一次矩阵乘法:
[B, 8, 16384] × [16384, 4096] = [B, 8, 4096]
  ↑                                ↑
  8个waypoint并排               8个waypoint同时算完

完整数据流程:

LLM 输出的 hidden states
[B, 32, 4096]
     │
     │ reshape: 每4个token拼成1个waypoint
     ↓
[B, 8, 16384]          ← 8个waypoint,每个16384维(4个4096拼接)
     │
     │ LayerNorm + concat(modality_id)
     ↓
[B, 8, 16385]
     │
     │ Linear(16385 → 4096) + ReLU
     ↓
[B, 8, 4096]
     │
     │ ResBlock × 2
     ↓
[B, 8, 4096]
     │
     │ LayerNorm + Linear(4096 → 4)
     ↓
[B, 8, 4]              ← 8个waypoint,每个4维 (y, x, cosθ, sinθ)

13.4. 自回归和一次性输出

同样都是基于llama 2,为什么openvla是autoregressive的,而omnivla不是?为什么openvla需要一个 token 一个 token 地生成动作串,而omnivla可以一次性就输出动作串? Llama-2 本身并不是"只能自回归"的——自回归是一种使用方式,不是模型的固有限制。

13.4.1. 先理解 Llama-2 的前向传播到底做了什么

Llama-2 的 forward 本质上就是:给定一条序列,对每个位置并行计算 hidden state。

输入:   [token_1] [token_2] [token_3] [token_4] [token_5]
         ↓         ↓         ↓         ↓         ↓
LLM:    并行处理所有位置(通过 causal attention mask 控制可见范围)
         ↓         ↓         ↓         ↓         ↓
输出:   [h_1]     [h_2]     [h_3]     [h_4]     [h_5]     ← hidden states
         ↓         ↓         ↓         ↓         ↓
lm_head: [logits_1] [logits_2] [logits_3] [logits_4] [logits_5]  ← 词表概率

一次 forward 就已经把所有位置的 hidden state 都算出来了。这在训练时每个 batch 都在发生——teacher forcing 就是一次性把整个序列(含正确答案)喂进去,一次 forward 算出所有位置的 loss。

13.4.2. OpenVLA 为什么需要自回归?

OpenVLA 把动作预测当成了文本生成任务——它用的是 lm_head(最后那个 Linear(4096, 32064) 分类器)来预测动作 token:

# openvla.py
generated_ids = super().generate(input_ids=..., max_new_tokens=7)

generate() 做的事情是:

第 1 步: 输入 [prompt...],lm_head 预测下一个 token → action_1
第 2 步: 输入 [prompt... action_1],预测 → action_2
第 3 步: 输入 [prompt... action_1 action_2],预测 → action_3
...

为什么必须一个一个来? 因为 lm_head 在位置 ii 预测的是"位置 i+1i+1 应该是什么 token"。在推理时,位置 i+1i+1 的 token 还不存在——你不知道该在那个位置放什么输入。你必须先得到 action_1 的预测结果,才能把它作为输入去预测 action_2。 这就是自回归的本质约束:当你依赖模型自己的预测结果作为下一步的输入时,就只能串行生成。

13.3.4. OmniVLA 为什么可以一次性输出?

OmniVLA 做了一个关键的设计转变——它不用 lm_head,也不需要模型"预测"动作 token 是什么。 它的做法是:推理前就把 32 个占位 token 全部放进输入序列。

OpenVLA 推理时的输入:  [BOS] [视觉] [指令]              ← 动作 token 还不存在,需要逐个生成
OmniVLA 推理时的输入:  [BOS] [视觉] [指令] [占位×32]    ← 32 个位置已经在那了(虽然 embedding 被清零)

因为所有位置都已经有了输入,LLM 可以一次 forward 把所有位置的 hidden state 都算出来:

OmniVLA 一次 forward:
[BOS] [视觉...] [指令...] [零] [零] [零] ... [零]   ← 32 个清零的占位
  ↓      ↓         ↓       ↓    ↓    ↓         ↓
  h_0   h_1...   h_n...   h_a1  h_a2  h_a3 ... h_a32  ← 所有 hidden states 一次算出
                            ↓    ↓    ↓         ↓
                         Action Head (MLP) → 连续动作值

OmniVLA 不需要知道"动作 token 是什么",因为它根本不用 token 来表示动作。它只需要 LLM 在这些位置产出有意义的 hidden state——这些 hidden state 通过 causal attention 聚合了前面视觉和文本的全部信息,Action Head 再从中回归出连续动作值。

13.5. 基础概念

13.5.1. 前置概念

机器学习里,一个模型大致有三件事要说清楚:

(1) 模型输出什么

比如输出:

  • 一个类别概率分布
  • 一个连续数值
  • 一个 token 序列
  • 一段连续动作序列 这叫 输出形式 / 预测目标

(2) 模型怎么输出

比如:

  • 一次性直接输出
  • 一个一个往后生成
  • 用 MLP 从 hidden state 映射出来 这叫 生成方式 / 结构形式

(3) 训练时怎么衡量错得多不多

比如:

  • Cross-entropy
  • MSE
  • L1 loss 这叫 损失函数

13.5.2. 怎么预测

13.5.2.1. 自回归(Autoregressive)

自回归不是损失函数,而是一种生成方式,所以“自回归”描述的是生成过程,不是“输出是离散还是连续”。 含义:逐个生成,后一个依赖前一个。 就是你选中的这段代码在做的事:

generated_ids = super(PrismaticVLM, self).generate(
    input_ids=input_ids,
    max_new_tokens=self.get_action_dim(unnorm_key),  # 7个token,逐个生成
)

generate() 内部做的事:

第1步:输入 [prompt] → 模型预测 → 采样得到 token_1
第2步:输入 [prompt, token_1] → 模型预测 → 采样得到 token_2
第3步:输入 [prompt, token_1, token_2] → 模型预测 → 采样得到 token_3
...重复7次

就像写作文——写完第一个字才能写第二个字,因为你要根据前文决定后文。ChatGPT 回复你的时候就是自回归的,一个字一个字蹦出来。

13.5.2.2. MLP 回归(MLP Regression)

含义:用一个神经网络(MLP = Multi-Layer Perceptron,多层感知机)直接算出一个连续数值。

输入: hidden_state [16384维向量]
        ↓
  Linear(16384 → 4096) + ReLU   ← 第1层
        ↓
  ResBlock × 2                   ← 中间层
        ↓
  Linear(4096 → 4)               ← 最后一层
        ↓
输出: [0.32, -0.15, 0.87, 0.49]  ← 4个连续数值,直接就是动作

13.5.2.3. L1 回归是什么

这个词经常被说得不严谨。严格来说,“L1 回归”通常指: 回归任务中使用 L1 loss(绝对值误差)作为损失函数

自回归MLP 回归
输出类型离散 token(从词表中选一个词)连续数值(直接输出小数)
输出过程逐个生成,串行一次计算,并行
类比做选择题(从 256 个选项中选 1 个)做填空题(直接写一个数字)

13.5.2.4. 什么是回归

这是机器学习里的基本术语。 定义:回归 = 预测连续数值 例如:

  • 预测一个标量:速度 vv
  • 预测一个向量:[x,y,θ][x,y,\theta]
  • 预测一个序列:[a1,a2,,aT][a_1, a_2, \dots, a_T]

只要输出是连续实数,通常就叫回归。

13.5.3. 怎么算错误(Loss 函数)

Loss 函数衡量"模型预测"和"正确答案"之间的差距。差距越大,Loss 越大,模型就调整更多。

13.5.3.1. Cross-entropy(交叉熵)

Cross-entropy 通常用于模型输出是离散类别分布时,也就是分类问题,或者 token prediction 问题。例如:

  • 图片是猫/狗/鸟
  • 下一个 token 是哪个词
  • 动作 token 应该是第几个 bin 如果真值是某个离散类别,那么最常见的损失就是 cross-entropy loss。

它在 token 预测里的意义: LLM 或 OpenVLA 原始版中,模型输出的是词表上的 logits,softmax 后得到每个 token 的概率。比如真实动作 token 是 132,模型若给 token 132 很高概率,则损失小;如果给别的 token 高概率,则损失大。

Cross-entropy 适合:

  • 分类任务
  • 离散 token 预测
  • 自回归语言建模
  • 离散化动作建模 不适合直接监督连续浮点数。

场景:模型输出一个概率分布(比如 256 个 bin 各自的概率),正确答案是其中一个 bin。

模型输出(概率分布):
  bin_0: 0.01
  bin_1: 0.02
  ...
  bin_127: 0.70  ← 模型觉得最可能是这个
  ...
  bin_200: 0.03
  bin_255: 0.01

正确答案: bin_130

Cross-Entropy Loss = -log(模型给正确答案的概率)
                   = -log(0.005)   ← 模型只给了 bin_130 0.5% 的概率
                   = 5.3           ← Loss 很大,说明预测得不好

OpenVLA 用它:因为 OpenVLA 把动作离散化成 256 个 bin,预测动作就是"从 256 个选项中选一个"——这就是分类问题。

13.5.3. 2. MSE(Mean Squared Error,均方误差)—— 用于连续回归

场景:模型直接输出一个数值,正确答案也是一个数值。

模型预测: [0.32, -0.15, 0.87, 0.49]
正确答案: [0.30, -0.10, 0.90, 0.50]

MSE = 平均((0.32-0.30)² + (-0.15-(-0.10))² + (0.87-0.90)² + (0.49-0.50)²)
    = 平均(0.0004 + 0.0025 + 0.0009 + 0.0001)
    = 0.000975

OmniVLA 用它torch.nn.MSELoss()(action_ref, predicted_actions)

13.5.3.3. L1 回归(L1 Regression)—— 也用于连续回归

场景:和 MSE 一样,模型输出数值,正确答案也是数值。

模型预测: [0.32, -0.15, 0.87, 0.49]
正确答案: [0.30, -0.10, 0.90, 0.50]

L1 = 平均(|0.32-0.30| + |-0.15-(-0.10)| + |0.87-0.90| + |0.49-0.50|)
   = 平均(0.02 + 0.05 + 0.03 + 0.01)
   = 0.0275

算每个维度的误差的绝对值,取平均。不做平方——对大误差和小误差一视同仁OpenVLA-OFT 用它

MSE vs L1 的区别

MSEL1
对大误差惩罚更重(平方放大)线性惩罚
对异常值敏感(容易被带偏)更鲁棒
训练效果倾向于学到"平均值"倾向于学到"中位数"

13.5.3.4. 平滑正则化(Smoothness Regularization)

OmniVLA 特有的额外 Loss 项:

# train_omnivla.py
loss = 1.0 * MSE(action_ref, predicted_actions)           # 主Loss:预测要准
     + 0.1 * MSE(obj_pose, predicted_actions[:,-1,0:2])   # 目标Loss
     + 0.1 * MSE(predicted_actions[:,0:-1], predicted_actions[:,1:])  # 平滑Loss

第三项的含义——相邻 waypoint 之间不要差太多

8个waypoint: [wp1] [wp2] [wp3] [wp4] [wp5] [wp6] [wp7] [wp8]

平滑Loss = MSE(wp1, wp2) + MSE(wp2, wp3) + ... + MSE(wp7, wp8)

如果: wp1=[0.1, 0.2] wp2=[0.8, 0.9]  → 差距大 → Loss大 → 惩罚
如果: wp1=[0.1, 0.2] wp2=[0.12, 0.22] → 差距小 → Loss小 → 鼓励

机器人的未来轨迹应该是平滑的曲线,不应该突然跳变。这个 Loss 就是在说"相邻的路径点要连续、不要抖动"。

总结:

OpenVLA:      自回归生成离散 token  +  Cross-Entropy Loss
                ↓                        ↓
              "从256个选项中选1个"      "选对了吗?概率给够了吗?"

OpenVLA-OFT:  MLP 回归连续值        +  L1 Loss
                ↓                        ↓
              "直接算出一个数"          "|预测值 - 真实值| 的绝对差"

OmniVLA:      MLP 回归连续值        +  MSE Loss + 平滑正则
                ↓                        ↓
              "直接算出一个数"          "(预测值 - 真实值)² + 相邻waypoint要平滑"

评论

请登录后发表评论

登录

0 条评论

加载评论中...

关于栏目

这个栏目专注于大模型相关内容的探讨和分析,带你了解最新的技术发展和应用案例。

分享文章