LAP: Language-Action Pre-Training Enables Zero-shot Cross-Embodiment Transfer · arXiv 2602.10556 · PDF + 官方代码核对
LAP 的核心不是“把动作 caption 一下”,而是把低层连续动作监督重新放回 VLM 熟悉的自然语言分布中。它用确定性模板把 action chunk 转成 language-action,让 VLM 先学“动作是什么意思”,再由轻量 flow-matching action expert 负责高速连续控制。
/home/chenzhiyuan/projects/paper/2026-LAP/LAP.pdf;代码来自官方仓库 /home/chenzhiyuan/projects/lap;本页不把论文未说清或代码未实现的机制硬写成事实。| 项 | 内容 |
|---|---|
| 核心瓶颈 | 现有 VLA 常用连续动作、离散 action token 或 learned tokenizer,和 VLM 预训练语言分布不对齐,容易损伤语义表征和跨本体泛化。 |
| 核心方法 | 把 action chunk 的净位移写成结构化自然语言:move/tilt/rotate/open/close;同时训练 VLM 的 language-action CE loss 和 action expert 的 flow-matching loss。 |
| 模型 | LAP-3B:PaliGemma-3B backbone + π0.5/MoT 风格 action expert;代码中继承 OpenPI / Pi0 结构。 |
| 数据 | Open X-Embodiment + MolmoAct;DROID 权重最高 85.26%;用全局 1/99 分位统计归一化 state/action。 |
| 训练 | 论文主设:64 TPU v6e,batch 2048,15k steps 约 10h;hero run 约 50h;代码默认 lap 配置 40k steps。 |
| 部署 | 实际控制时不自回归生成语言动作,而是由 action expert 采样连续动作;RTX 4090 上 25Hz。 |
| 主结果 | 未见本体 zero-shot 平均超过 50%;LIBERO fine-tune 6 epoch 96.8%;LIBERO 表格 LAP-3B 96.8,LAP-3B+VQA 97.2。 |
LAP 把问题定义为:VLA 的“动作监督形式”本身阻碍跨本体泛化。一个 VLM 本来擅长语言、视觉语义和图文推理;如果让它输出 learned tokenizer 的离散码、连续向量或本体特定动作 token,就把动作学习放在了 VLM 预训练分布之外。
| 动作表示 | 优点 | LAP 认为的问题 |
|---|---|---|
| 连续动作回归 | 直接、适合控制 | 和语言模型输出空间不一致;跨本体时 state/action 维度与物理含义不统一。 |
| 离散 action token / FAST | 可用 CE 训练,便于大模型建模 | token 是非语言符号,可能破坏 VLM 的语言/语义分布。 |
| VLA-0 数字串 | 零结构修改 | 数字 token 与物理动作语义弱绑定,扩展到大规模噪声数据时可能不稳。 |
| LAP language-action | 动作以自然语言短句表达 | 需要模板、坐标约定和解析;高频细节仍交给 action expert。 |
LAP 的 language-action 不是为了给轨迹多一个 caption,而是作为训练接口:VLM backbone 被监督去输出“动作语义”,action expert 再用 flow matching 输出高频连续动作。它把“动作该如何表达”变成一个训练范式问题。
LAP 利用机器人数据天然有 end-effector trajectory 的结构,不靠人工逐条标注。它对 action chunk 的累计位移做确定性解析,再用固定模板表达成自然语言。
| 成分 | 设计 | 例子 |
|---|---|---|
| 坐标系 | +x forward,+y left,+z up;旋转用 Euler/right-hand rule | base frame / end-effector frame 随机 50/50 |
| 平移 | move + forward/back/left/right/up/down + cm | move forward 5 cm |
| 旋转 | tilt / rotate + direction + degrees | rotate clockwise 15 degrees |
| 夹爪 | open gripper / close gripper / set gripper | close gripper |
| 时间抽象 | 不是每个 timestep 生成一句,而是 action chunk 的净位移 | 降低频率,避免 VLM 学高频噪声 |
论文训练 mixture 里 DROID 占比最高,因为它任务覆盖广、环境多样;MolmoAct 占 1.73%。代码中由 OXEDatasets 读取 mixture、计算全局统计,并对 state/action 做 bounds_q99 归一化。
| 训练数据 | 论文比例 | 用途 |
|---|---|---|
| DROID | 85.26% | 主力真实机器人数据,环境和任务覆盖最广。 |
| Fractal | 5.86% | 补充大规模机器人操作分布。 |
| Bridge | 3.39% | 补充 tabletop 操作泛化。 |
| MolmoAct | 1.73% | 补充视觉-动作相关数据。 |
| 其余 OXE 数据 | 小比例 | 扩展本体、相机、任务多样性。 |
论文说 LAP 可以接任何 VLM-based policy;实际系统 LAP-3B 用 PaliGemma-3B 初始化 VLM backbone,并沿用 π0.5 的 Mixture-of-Transformers 思路:一个 VLM expert 负责 image/text/language-action,另一个 action expert 负责 continuous action flow matching。
observation images ─► SigLIP image encoder ─┐
task prompt + discrete state ─► tokenizer ─┤
language-action tokens ─► causal CE loss ──┤
├─► PaliGemma / Gemma MoT backbone
noisy action chunk + τ ─► action suffix ───┘
└─► action expert velocity field ─► continuous action chunk
关键注意力规则:image/prompt/state 是 prefix;language-action tokens 自回归;action expert 对 prefix 全注意,但不能 attend 到 language-action tokens。这样避免 raw action 和 language-action 互相偷看。
如果真实机器人控制时每步都让 VLM 自回归生成一句 language-action,再解析成动作,会很慢。LAP 的做法是:language-action 主要用于训练 VLM 表征;部署时走 flow-matching action expert 直接采样连续动作,因此达到实时控制。
| 路径 | 训练时 | 推理时 |
|---|---|---|
| 语言动作 CE | 启用,训练 VLM 输出 structured language-action | 默认不用于控制;可用 LAP_AR 调试/可解释输出 |
| Action expert flow matching | 启用,学习连续动作速度场 | 主部署路径,输出 action chunk |
| stop action-to-VLM grad | 预训练默认启用 | 推理无意义,代码中 serve 会关闭该 flag |
L_CE 监督 VLM 生成 language-action;L_flow 监督 action expert 从噪声到真实 action chunk 的速度场。
| 阶段 | 论文设置 | 代码默认 |
|---|---|---|
| 预训练 | batch 2048,64 TPU v6e,15k steps 已可用;hero run 约 50h | TrainConfig(name="lap"),batch 2048,默认 40k steps |
| 优化器 | AdamW,LR 1e-4,warmup 5k,weight decay 1e-4 | build_cosine_lr() + AdamW |
| EMA | 5k steps 后启用 | EmaScheduleChoice(kind="cosine_delayed", start_step=5000) |
| fine-tune | λ 从 0.8 降到 0.4 | lap_libero 配置 language_loss_weight=0.4 |
# 安装
GIT_LFS_SKIP_SMUDGE=1 uv sync
GIT_LFS_SKIP_SMUDGE=1 uv pip install -e .
# GPU 上训练 LIBERO fine-tune
JAX_PLATFORMS=cuda uv run --group cuda scripts/train.py lap_libero \
--exp-name=lap_libero \
--data.rlds_data_dir=<your_data_dir>
# 大规模 LAP 预训练配置入口
uv run scripts/train.py lap --exp-name=lap_pretrain \
--data.rlds_data_dir=<oxe_data_dir>
代码训练入口是 scripts/train.py:初始化 JAX/FSDP mesh、加载 partial weights、构造 TrainState、读取 RLDS/VQA mixture、运行 train step 并保存 checkpoint。
| 功能 | 路径 | 作用 |
|---|---|---|
| 模型主体 | src/lap/models/lap.py | LAP 继承 openpi.models.pi0.Pi0,实现 prefix/suffix、language loss、action flow loss、sample actions。 |
| 模型配置 | src/lap/models/lap_config.py | action_dim/horizon、PaliGemma/Gemma variant、loss 开关、stop gradient、image keys。 |
| 训练配置 | src/lap/training/config.py | lap、lap_libero、lap_cotrain、Gemma3 scaling 等配置。 |
| 语言动作格式 | src/lap/policies/lang_action_formats.py | 解析/格式化 move/tilt/rotate/open/close,支持 eef frame 和 VLA-0 格式。 |
| 数据混合 | src/lap/datasets/dataset_mixer.py | 构造 OXE/VQA mixture、全局归一化、weighted interleave、batch pipeline。 |
| 服务部署 | scripts/serve_policy.py | WebSocket policy server,支持 LAP/LAP_AR/LAP_LIBERO/PI05_DROID。 |
| LIBERO 评测 | scripts/libero/main.py | 连接 policy server,执行 LIBERO rollout、保存视频和 JSON 结果。 |
# src/lap/models/lap.py
class LAP(_pi0.Pi0):
def __init__(self, config, rngs):
paligemma_config = _gemma.get_config(config.paligemma_variant)
action_expert_config = _gemma.get_config(config.action_expert_variant)
llm = _gemma.Module(configs=[paligemma_config, action_expert_config],
stop_action_to_vlm_grad=config.stop_action_to_vlm_grad)
self.action_in_proj = nnx.Linear(config.action_dim, action_expert_config.width)
self.action_out_proj = nnx.Linear(action_expert_config.width, config.action_dim)
self.PaliGemma = nnx.Dict(llm=llm, img=SigLIP(...))
这证明 LAP 是 OpenPI/π0 系结构,不是单独搭一个 PyTorch transformer。
# src/lap/models/lap.py
if self.enable_langact_training:
lang_loss = self._compute_language_loss(observation, pre_logits[0])
if self.enable_action_training:
action_loss = self._compute_action_loss(pre_logits[1], suffix_inputs["u_t"])
total_loss = language_loss_weight * lang_loss + action_loss_weight * action_loss
实际代码还有 VQA/prediction mask、per-dataset VQA loss weights、verbose token accuracy 等工程细节。
# src/lap/policies/lang_action_formats.py
VERBOSE_EEF_WITH_ROTATION_FORMAT = LanguageActionFormat(
name="verbose_eef_with_rotation",
style="verbose",
include_rotation=True,
use_eef_frame=True,
)
# parse: move left/right/forward/back/up/down + cm
# parse: tilt/rotate + degrees
# parse: open gripper / close gripper
这对应论文的模板化动作语言。重要点是它可逆:训练时把动作转语言,调试或 AR 路径可以把语言动作再解析回 delta。
LAP 不是把 language-action tokens 和 raw action suffix 随便拼一起训练。代码里显式构造了两套 prefix mask:一套给 language-action CE,一套给 action expert。action expert 可以看 image/prompt/state,但不能看 language-action tokens,避免连续动作预测直接“偷看”语言动作答案。
# src/lap/models/lap.py
def _build_prefix_action_mask(prefix_mask, observation):
# language-action tokens are removed from the prefix visible to action expert
langact_mask_full = concat(zeros_for_image_tokens, tokenized_langact_mask)
return prefix_mask & (~langact_mask_full)
def _build_combined_attention_mask(...):
# prefix: image/prompt bidirectional; langact causal
# suffix/action rows: attend to image+prompt, not langact
combined[:prefix_len, :prefix_len] = prefix_attn
combined[prefix_len:, :] = action_mask
这和论文 Appendix B.7 的 attention mask 描述一致:prefix tokens 双向注意;language-action tokens 自回归;action expert 全自注意并 attend prefix,但不 attend language-action tokens。
RLDS datasets
└─► dataset registry / dataset config
└─► OXEDatasets
├─ instantiate each dataset
├─ compute global state/action statistics
├─ normalize with bounds_q99
├─ weighted interleave by mixture weights
└─ prepare_batched_dataset
├─ resize image to 224×224
├─ augment robot images
├─ build prompt + language_action
└─ pad state/action to model dims
代码里的 TrajectoryOutputBuilder 统一输出字段:observation、actions、language_action、language_instruction、dataset_name、raw_state 等。VQA 样本也被包装成相同风格,只是 action 用零填充、is_vqa_sample=True。
虽然本页没有逐行展开完整 sample_actions,但代码结构清楚:推理时先用同一套 image/prompt/state transforms 构造 observation,再由模型从噪声动作出发,用 action expert 的 velocity field 迭代得到 action chunk。输出还要经过 Unnormalize 和 robot-specific output transforms。
policy.infer(request)
└─► input transforms
├─ inject default prompt
├─ normalize image/state
└─ tokenize prompt/state
└─► model.sample_actions(...)
├─ initialize noisy action chunk
├─ run flow/ODE steps
└─ output normalized actions
└─► output transforms
├─ unnormalize with checkpoint assets
├─ robot-specific action conversion
└─ return actions to websocket client
复现时最容易错的地方不是模型 forward,而是 checkpoint 的 normalization stats、action convention、gripper inversion、replan_steps 是否和训练保持一致。
LAP 最有价值的工程 insight 是:不要只把 language-action 当数据字段,而要把它做成贯穿 data transform、tokenizer、attention mask、loss、policy serving 的一整条接口。如果只在数据集里多存一句 “move left 5 cm”,但训练时不控制 mask、不控制 loss、不接入 action expert,那就只是 caption augmentation。
| Insight | LAP 代码中的实现 | 我们复用时应怎么做 |
|---|---|---|
| 动作语言必须可逆/可计算 | lang_action_formats.py 同时实现 summarize 与 parse_language_to_deltas | CLAP/VLMGuide 的语言动作也必须能映射回动作维度或候选动作属性,不能只写自然语言描述。 |
| 不同样本类型共用 schema | TrajectoryOutputBuilder 与 VQA builder 输出统一字段 | 正样本、负样本、VQA、prediction sample 要统一成同一 batch schema,再用 mask 控制 loss。 |
| action expert 不能偷看 language-action 答案 | _build_prefix_action_mask 排除 langact tokens | 做 preference/rejection 时也要防止 action head 直接看到 label text,否则 ranking 指标虚高。 |
| 训练目标要分样本类型加权 | compute_loss 按 VQA/pred/langact/action mask 分别计 loss | CLAP 应有 positive CE、preference loss、action FM loss 的清晰权重和 denominator。 |
| 部署路径要走 action expert | serve_policy.py 默认 flow policy,AR 只是可解释路径 | 论文贡献必须落到 action selection/action chunk,而不是只生成解释文字。 |
LAPConfig、CoTInputs、PaligemmaTokenizer 和 policy server,保证原 LAP/LIBERO 跑通。candidate_language_action、preference_label、negative_type、stage,保留原 language_actions。RobotSampleHandler / PredictionSampleHandler,写 PreferenceSampleHandler,把正负动作格式化为统一 prompt。compute_loss 中加 preference 分支。不要混在普通 lang_loss 里,否则无法做消融和权重控制。src/lap/policies/transforms/preference_handler.py
# 处理 positive / negative language-action preference 样本
src/lap/models/preference_head.py
# 可选:从 prefix representation 输出 action suitability score
src/lap/training/preference_losses.py
# pairwise ranking / DPO-style / binary rejection loss
src/lap/datasets/preference_dataset.py
# 从 LIBERO/DROID/LAP action format 构造 hard negatives
scripts/eval_preference.py
# offline: ranking accuracy / negative type breakdown
scripts/libero/eval_counterfactual.py
# rollout: wrong-object / wrong-stage / wrong-direction tasks
lap.py 主类。先用小模块 + config flag 接入,保留原 LAP baseline 可复现,这样实验对比才干净。| 环节 | 最低实现 | 验收 |
|---|---|---|
| 数据 | 每个 observation 构造 1 个正确 language-action + 3 类 hard negatives:错方向、错物体、错阶段 | 人工抽查 200 条,负样本必须 plausible-but-wrong。 |
| 训练 | 冻结或半冻结 LAP backbone,训练 suitability/rejection loss | offline hard-negative AUC/accuracy 分类型报告。 |
| 推理 | action expert 采样 K 个 action chunk,转 language-action 或提取动作属性,scorer rerank | rerank 后错误动作比例下降。 |
| 仿真 | LIBERO counterfactual 指令、相似物体、阶段扰动 | success 提升,wrong-object/wrong-stage 下降。 |
| 消融 | random negatives、no stage、no visual、no rerank、only offline | 证明不是“多训数据”或“普通正则化”。 |
官方部署采用 server-client:GPU 机器上跑 JAX policy server,机器人控制端通过 OpenPI client 发送图像/state/prompt,请求 action chunk。
# 下载 checkpoint
hf download lihzha/LAP-3B --local-dir ./checkpoints/lap
# 启动策略服务器
JAX_PLATFORMS=cuda uv run --group cuda scripts/serve_policy.py --env=LAP
# DROID 控制端
python scripts/real_robot/droid_main.py \
--external_camera=right \
--left_camera_id=<left> --right_camera_id=<right> --wrist_camera_id=<wrist>
| 模式 | 代码枚举 | 用途 |
|---|---|---|
| LAP | EnvMode.LAP | LAP-3B flow action expert,默认控制路径。 |
| LAP_AR | EnvMode.LAP_AR | 自回归生成语言动作,适合解释/调试,不是高速主路径。 |
| LAP_LIBERO | EnvMode.LAP_LIBERO | 加载 LIBERO fine-tuned checkpoint。 |
| PI05_DROID | EnvMode.PI05_DROID | 对比 OpenPI/π0.5 DROID policy。 |
# 终端1:server
JAX_PLATFORMS=cuda uv run --group cuda --active scripts/serve_policy.py \
policy:checkpoint --policy.config=lap_libero \
--policy.dir=checkpoints/LAP-3B-Libero --policy.type=flow
# 终端2:sim
source scripts/libero/.venv/bin/activate
export LIBERO_CONFIG_PATH=$PWD/third_party/openpi/third_party/libero
python scripts/libero/main.py --task_suite_name=libero_spatial
scripts/libero/main.py 默认每个 task 50 rollouts,replan every 5 steps,读取 base/wrist image,向 server 请求 action chunk,再执行 OSC_POSE 控制。
| 问题 | 常见原因 | 检查方式 |
|---|---|---|
| 动作幅度极小 | normalization stats 未加载、action bounds 不匹配、模型输出仍在 normalized 空间 | 打印 checkpoint assets 下 norm stats;检查 Unnormalize 是否在 output transforms 中。 |
| 夹爪方向反了 | LIBERO / DROID / 自定义机器人 gripper convention 不同 | 看 invert_and_scale_gripper;单独执行 open/close 指令。 |
| 动作方向相反 | base frame/eef frame 描述不一致;相机/坐标系变换错 | 固定 prompt 为 move left/up/forward,观察 end-effector delta。 |
| server 能跑但 client 超时 | JAX 首次编译慢、端口/host 设置、GPU 内存不足 | 先发 dummy request 预热;确认 websocket port=8000。 |
| LIBERO 成功率低 | 分辨率、初始等待步数、replan_steps、control_mode 和训练/评测不一致 | 按官方 scripts/libero/README.md 保持 224 resize、OSC_POSE、replan 5。 |
| 评测块 | Benchmark / 平台 | 任务与数据 | 为什么这样测 | 本地复现/核对状态 |
|---|---|---|---|---|
| Seen embodiment | DROID setup | 训练中见过的真实机器人本体,评估真实操作成功率。 | 确认 language-action 不会牺牲已见平台能力,避免只在新平台上“看起来泛化”。 | 代码仓库已读;未做真机复现。 |
| Zero-shot cross-embodiment | Custom Franka / YAM / Kinova | 三个未见本体;任务含 pick-place、sort、tissue、put towel、pour;每任务 20 trials。 | 这是 LAP 主 claim:换 gripper、相机、DoF、控制接口后,language-action 是否比 FAST/action-token 更可迁移。 | 硬件不可用;本页基于论文与代码核对。 |
| 仿真 fine-tuning | LIBERO | Spatial/Object/Goal/Long;标准 suite success;报告 1 epoch 与 6 epoch 收敛。 | 检验 language-action pretraining 是否提升下游收敛速度,同时与常规 VLA benchmark 对齐。 | 官方代码和 LIBERO 入口已定位;未跑全量复现。 |
| 真机 fine-tuning | YAM + Custom Franka | Hang Tape on Rack、Fold Towel and Place in Basket;比较 demos 数量与 task progress。 | 检验少样本适应效率,证明不是只会 zero-shot,也能更省数据地微调。 | 未复现。 |
| 表示控制实验 | 同架构 replicated baselines | π0.5-replicated、π0-replicated、VLA-0-replicated,只改变动作表示/监督路径。 | 隔离变量:收益是否来自 language-action 表示,而不是数据、架构或训练步数。 | 已在代码层核对配置入口;未完整训练。 |
LAP 在 4 类机器人本体上评测:DROID 是训练中见过的本体;Custom Franka、YAM、Kinova 是未见本体。任务包括 pick-place、sort、tissue、put towel、pour 等,覆盖长时序、变形物体、旋转控制和 6-DoF 操作。
| 实验 | 结果 | 意义 |
|---|---|---|
| LIBERO fine-tune | 1 epoch 已 78%;6 epoch 到 96.8% | 说明 language-action pretraining 给了更可迁移初始化。 |
| YAM Hang Tape | 约 20 demos 达到 50% progress | 比 baseline 约少 2.5× demos。 |
| Franka Fold Towel | 多数据量下稳定优于 π0/π0.5 replicated | 对复杂长时任务也提升适应效率。 |
| 方法 | Spatial | Object | Goal | LIBERO-10 | Avg |
|---|---|---|---|---|---|
| X-VLA | 98.2 | 98.6 | 97.8 | 97.6 | 98.1 |
| π0.5 | 98.8 | 98.2 | 98.0 | 92.4 | 96.9 |
| LAP-3B | 98.2 | 99.0 | 98.8 | 91.2 | 96.8 |
| LAP-3B + VQA Co. | 99.0 | 99.0 | 97.2 | 93.4 | 97.2 |
注意:LAP 的核心卖点不是 LIBERO 排第一,而是跨本体 zero-shot 和 fine-tune efficiency。LIBERO 主要证明它在常规 benchmark 上没有牺牲能力。
LAP 的语言动作格式天然可作为 VQA answer。论文构造 motion-prediction VQA:给两帧图像,问“机器人从第一帧到第二帧做了什么运动?”,答案就是 language-action。
代码中支持 enable_prediction_training、enable_vqa_training,并有 VQA dataset registry:COCO captions、VQAv2、LVIS/PACO/PixMo 等。这说明发布仓库已经把 VQA co-training 做成工程开关。
LAP 证明“把 action supervision 放进语言空间”有迁移收益;VQA co-training 进一步说明:如果任务输出形式与 VLM 本来会的问答形式一致,就可以吸收更广泛的视觉语言数据。对 CLAP/VLMGuide 来说,这启发是:不要只造 robot-only 数据,可以把 action suitability / rejection 也设计成 VQA-like 监督。
| 工作 | 表面动作 | 真正贡献 | policy 证据 |
|---|---|---|---|
| LAP | 把 action chunk 写成自然语言 | 动作表示范式:让 VLA action supervision 对齐 VLM 语言分布 | zero-shot 跨本体 + fine-tune efficiency |
| LA4VLA | 从 DROID 切 33K atomic LA episodes | 去视觉 language-action pretraining,减少视觉捷径 | MetaWorld/LIBERO/真机/视觉扰动提升 |
| CLAP 应该做 | 构造正/负 language-action preference | action suitability / rejection:不仅知道该做什么,也知道当前不该做什么 | 必须证明 reranking/rejection 改变 rollout 成功率 |
lap_libero checkpoint 的 LIBERO eval,验证 server-client、图像预处理、action unnormalize 正确。compute_loss 的 language/action loss 都正常下降。