OpenVLA-OFT-LIBERO进阶实战:自定义任务微调与LIBERO评测避坑指南
OpenVLA-OFT-LIBERO进阶实战:自定义任务微调与LIBERO评测避坑指南
本仓库是 OpenVLA-OFT 视觉-语言-动作(VLA)模型 在 LIBERO-Spatial 基准上的微调权重(checkpoint),约 15GB,可直接用于机器人动作推理与评测。本文将从模型结构、快速推理、自定义任务微调到 LIBERO 评测中最容易踩的 6 个坑,带你完整走通这套"连续动作版 OpenVLA"。
一、OpenVLA-OFT 是什么?为什么值得上手
OpenVLA-OFT(论文:Fine-Tuning Vision-Language-Action Models: Optimizing Speed and Success,arXiv:2502.19645)是对原版 OpenVLA 的微调优化方案,核心改进可以概括为 3 点 🚀:
| 对比维度 | 原版 OpenVLA | OpenVLA-OFT |
|---|---|---|
| 动作输出方式 | 离散 token 逐字解码 | 连续回归(MLP 头,L1 损失) |
| 推理速度 | 慢(自回归解码 70 个动作 token) | 快 5 倍以上(一次前向出 10 步动作) |
| LIBERO 成功率 | 基线 | 显著提升 |
一句话理解:OFT 把"机器人动作"从"写作文"变成了"填坐标",既快又稳。本仓库即 LIBERO-Spatial 套件微调后的成品权重。
二、模型构成速览:看懂这份 checkpoint 里装了什么
仓库是一个标准的 HuggingFace 模型目录,核心文件如下(详见 README.md):
| 文件 | 作用 |
|---|---|
| model-00001-of-00004.safetensors ~ model-00004-of-00004.safetensors | 模型权重,共 4 片,约 15GB,索引见 model.safetensors.index.json |
| config.json | 模型主配置:骨干网络、动作维度、归一化统计等 |
| dataset_statistics.json | 动作/本体感知的 q01/q99 归一化统计量 |
| modeling_prismatic.py | 模型定义,核心类 OpenVLAForActionPrediction |
| configuration_prismatic.py | 配置类 OpenVLAConfig 定义 |
| processing_prismatic.py | 图像/文本处理器 PrismaticProcessor |
| preprocessor_config.json | 图像预处理参数(224×224 双图输入) |
| tokenizer_config.json | Llama 分词器配置 |
从 config.json 可以读出几个关键超参,建议先记住它们,后面微调与评测全靠对号入座:
action_dim: 7—— 7 维动作:xyz 平移 + 3 维姿态 + 夹爪;num_actions_chunk: 10—— 每次前向输出未来 10 步动作(action chunk);num_images_in_input: 2—— 同时输入第三人称相机 + 腕部相机两张图;vision_backbone_id: dinosiglip-vit-so-224px—— DINOv2 + SigLIP 融合双视觉骨干;llm_backbone_id: llama2-7b-pure—— Llama-2-7B 语言骨干;n_action_bins: 256—— 离散动作 bin 数(仅离散模式使用,OFT 连续模式下由 MLP 头输出);invert_gripper: true—— 夹爪维度方向需翻转(评测时容易忽略的细节)。
三、快速上手教程:5 步生成机器人动作
注意:本仓库只含模型权重,训练/推理代码在 OpenVLA-OFT 官方代码项目中(clone 方式:
git clone https://gitcode.com/hf_mirrors/Sakits/openvla-oft-libero仅拉权重,代码需另配 conda 环境,见官方 README 说明)。
推理管线固定为 5 步加载 + 1 次前向(官方 Quick Start 见 README.md):
cfg = GenerateConfig(
pretrained_checkpoint="moojink/openvla-7b-oft-finetuned-libero-spatial",
use_l1_regression=True, # 关键:MLP 头直接回归连续动作
use_diffusion=False, # 不使用扩散头
use_film=False, # 不使用 FiLM 噪声动作
num_images_in_input=2, # 第三人称 + 腕部双图
use_proprio=True, # 注入本体感知 state
center_crop=True, # 与训练保持一致的裁剪
num_open_loop_steps=1, # 闭环评测时置 1(见坑 3)
unnorm_key="libero_aggregated", # 必须与 norm_stats 中的 key 一致!
)
vla = get_vla(cfg) # 1. 加载 VLA 主干
processor = get_processor(cfg) # 2. 加载图像/文本处理器
action_head = get_action_head(cfg, llm_dim=vla.llm_dim) # 3. 连续动作 MLP 头
proprio_projector = get_proprio_projector(cfg, llm_dim=vla.llm_dim, proprio_dim=PROPRIO_DIM) # 4. 本体感知投影器
actions = get_vla_action(cfg, vla, processor, obs, obs["task_description"], action_head, proprio_projector) # 5. 生成动作块
输入 observation 是一个字典,四个键缺一不可:full_image(主视角)、wrist_image(腕部)、state(7 维本体感知)、task_description(英文任务指令)。输出为 (10, 7) 的动作块张量。
四、自定义任务微调:数据格式与归一化统计是命门
想在 LIBERO 之外的新任务(或新套件)上微调,核心只做好两件事 👇
1. 按标准格式组织观测数据
采集数据时保证每条样本包含上述四元组,图像统一为 224×224 输入(处理器使用 resize-naive 策略直接缩放,不做 letterbox,见 preprocessor_config.json)。动作统一为 7 维末端执行器增量 + 夹爪。
2. 为每个数据集计算并注册归一化统计量
OFT 推理时会把模型输出的 -1, 1] 归一化动作,用训练集的 q01/q99 边界反归一化回真实动作空间(实现见 [modeling_prismatic.py)。本仓库只预置了 libero_aggregated 这一份统计量(见 dataset_statistics.json),且第 7 维(夹爪)mask=false 不参与缩放、只做翻转。
微调自定义任务时,必须:
- 用官方
compute_stats类脚本对新数据集统计q01/q99; - 以新的 key(如
libero_object_no_noops)写入 checkpoint 的norm_stats; - 推理配置里
unnorm_key指向新 key。
五、LIBERO 评测避坑指南:6 个常见坑一次讲清
坑 1:unnorm_key 对不上,动作直接"乱飞"
官方 README 示例中写的是 unnorm_key="libero_spatial_no_noops",但本 checkpoint 的 norm_stats 里只有 libero_aggregated(见 config.json)。key 不一致会导致 KeyError 或用错统计量,表现就是机械臂抖动、抓取全失败。
✅ 对策:评测前先 print(cfg.unnorm_key),确认它存在于 norm_stats 字典中。
坑 2:找不到 sample_libero_spatial_observation.pkl
README 示例加载的示例观测文件 experiments/robot/libero/sample_libero_spatial_observation.pkl 位于代码仓库中,而本仓库是纯权重目录,里面没有它。
✅ 对策:从官方代码项目同步该文件,或用自己采集的一条真实观测代替——后者更能暴露环境配置问题。
坑 3:num_open_loop_steps 开环/闭环搞混
Quick Start 为了演示一次打印完整动作块,用的是开环模式(num_open_loop_steps=NUM_ACTIONS_CHUNK,即 10 步不回流新观测)。LIBERO 正式评测必须闭环:每执行 1 步就重新推理,否则累积误差会让成功率大幅缩水。
✅ 对策:评测脚本中固定 num_open_loop_steps=1。
坑 4:显存不够直接 OOM
权重 bf16 约 15GB,FP16 加载加激活开销,24GB 显卡跑闭环评测都很紧张。
✅ 对策:显存 <20GB 时开 load_in_8bit=True 或 load_in_4bit=True(QLoRA 式量化加载),推理精度损失很小,是评测场景性价比最高的选择。
坑 5:图像预处理与训练不一致
模型要求恰好两张 224×224 图(主视角 + 腕部),center_crop、resize-naive 等参数必须与训练对齐。只传一张图、分辨率不对、或 use_proprio 开关与训练不符,都会让成功率"无声地"掉一截。
✅ 对策:逐字对照 preprocessor_config.json 的 input_sizes 和 image_resize_strategy 检查输入管线。
坑 6:忽略夹爪翻转 invert_gripper
本 checkpoint 配置了 invert_gripper: true:训练数据中夹爪是"开=1",部分真实/仿真环境是"开=0"。方向接反的表现是"抓取时松手、该松手时夹紧",非常难排查。
✅ 对策:把推理输出的第 7 维送到环境前,统一做一次 1 - gripper 转换,并在环境端验证一次开/闭爪动作。
六、延伸阅读与关键文件索引
| 想了解 | 看这里 |
|---|---|
| 模型加载与推理示例 | README.md |
| 连续动作反归一化逻辑 | modeling_prismatic.py |
| 动作 bin 与词表构造 | modeling_prismatic.py |
| 视觉/LLM 骨干映射表 | configuration_prismatic.py |
| 双视觉骨干融合加载 | modeling_prismatic.py |
| 归一化统计量 | dataset_statistics.json |
总结:用好 OpenVLA-OFT-LIBERO 的关键在于"三对齐"——归一化 key 对齐、图像预处理对齐、闭环策略对齐。把本文 6 个坑逐一排掉后,你就能在它之上平滑扩展到自定义任务的微调与评测 🎯。