FlowVLA — Flow Matching Vision-Language-Action
基于 Qwen3-VL-2B-Instruct + Flow Matching 的 VLA 模型,在 4 个开源 LeRobot 数据集上联合训练,用于通用机器人操作。
🧠 动机
MSE 回归式 VLA 的本质局限:
- 多模态动作分布 → 只能学到"平均动作"(从上面抓和从侧面抓的平均 ≈ 抓不住)
- 缺乏时序建模 → 单步预测,无动作连贯性
Flow Matching 解决:
- 多模态分布建模 — 学习完整速度场矢量,而非单点回归
- 动作块 (Action Chunking) — 一次预测 K=16 步连续动作
- 比扩散快 — 仅 10 步 Euler 积分即可生成(扩散通常需 50-100 步)
🏗 架构
Qwen3-VL-2B-Instruct
├── Vision Encoder (最后4层解冻)
├── LLM 28L (hidden=2048, FROZEN)
│
├── VLM prefix → full hidden sequence (cond_dim=1536)
├── state tokens → 离散化拼入 prompt
│
└── ───────────────────────────────────
│
┌────┴────┐
│ Action Expert(~16.8M 可训练)
│ · 4 层 Transformer
│ · 8 heads, d_model=512
│ · self-attention + cross-attention to VLM prefix
│ · time embedding (Fourier)
│ · state embedding (MLP)
│ · FFN 2048
└────┬────┘
│
Flow Matching Head → [K=16, D=7] action chunk
| 组件 | 参数量 | 状态 |
|---|---|---|
| Qwen3-VL-2B (整体) | ~2.1B | ❄️ 大部分冻结 |
| Vision Encoder 最后4层 | ~4.5M | 🔥 可训练 (epoch 12+) |
| Action Expert (Transformer 4L) | ~16.8M | 🔥 可训练 |
| 总计可训练 | ~21.3M |
📝 epoch 6-11 仅训练 Action Expert(~16.8M),epoch 12 后解冻 Vision Encoder 最后4层(总计 ~21.3M)。
Flow Matching 原理
训练:
noise = randn_like(actions)
τ ~ Beta(1.5, 1.0) · 0.999 + 0.001 # 时间采样
x_τ = τ · noise + (1-τ) · actions # τ=1→噪声, τ=0→数据
u_τ = noise - actions # 速度目标
v_pred = action_expert(x_τ, τ, vlm_prefix, state)
loss = MSE(v_pred, u_τ)
推理 (Euler, 10 步):
x = randn() # τ=1
dt = -1/10
for step in 0..9:
v = action_expert(x, τ, vlm_prefix, state)
x = x + dt · v
τ = τ + dt
return x # τ=0
📊 训练数据
4 个 LeRobot 格式数据集联合训练:
| 数据集 | Episodes | 权重 | 相机数 | 说明 |
|---|---|---|---|---|
| BridgeData v2 | 2,618 | 40% | 1 | 高质量单臂桌面操作 |
| Libero OpenVLA | 1,314 | 25% | 2 (primary + wrist) | 多任务 goal/object/spatial |
| Libero Long | 500 | 20% | 2 (agentview + wrist) | 长序列 (long-horizon) |
| Fractal | 86,871 | 15% | 1 | 最大但质量参差,降权避免 dominate |
| 总计 | ~91,000 | — | — | ~3.9M 帧 |
数据管线特性
- 按数据集权重加权随机采样
- 动作 Z-score 归一化 (per-dataset)
- 状态归一化 (per-dataset)
- Domain randomization (ColorJitter + GaussianNoise)
- LRU video cache (跨 worker 安全)
- 缺失相机自动 fallback
- 滑动窗口 action chunking (K=16)
📈 训练详情
| 项目 | 详情 |
|---|---|
| 硬件 | AutoDL A800 40GB × 1 |
| Batch size | 32 × grad_accum=2 = 等效 64 |
| 每 epoch 样本 | 1,200,000(有放回采样) |
| 优化器 | AdamW (lr=5e-5, wd=1e-2, grad_clip=1.0) |
| 调度 | Cosine decay · 1,000 warmup steps |
| 精度 | bf16 mixed precision |
| 图像 | 256×256 |
| 动作 | 7D EEF delta: [dx, dy, dz, ax, ay, az, gripper] |
| 状态 | 8D: EEF 6D + gripper 2D (Bridge/Fractal 7D → zero-pad) |
| 动作块 | K=16 |
| Flow 参数 | sigma_min=0.001 · τ~Beta(1.5,1.0) · N=10 Euler steps |
Checkpoint 演进
| Epoch | 大小 | 变化 |
|---|---|---|
| 6-11 | 233 MB | 仅训练 Action Expert(Qwen3-VL 全冻结) |
| 12-15 | 329 MB | 视觉编码器最后4层解冻(~+4.5M 可训练) |
说明: epoch 1-5 为早期实验未包含,epoch 13 保存异常(0.1MB),epoch 16 未完成。
🚀 快速开始
安装
pip install torch>=2.5.0 transformers>=4.51.0 accelerate sentencepiece protobuf Pillow
加载 & 推理
import torch
from PIL import Image
from models.flow_vla import FlowVLA
# 初始化模型
model = FlowVLA(
model_name="Qwen/Qwen3-VL-2B-Instruct",
action_dim=7,
action_chunk_size=16,
state_dim=8,
num_inference_steps=10,
flow_expert_type="transformer",
llm_mode="frozen_last_n", # epoch 12+ 解冻了最后4层
lora_rank=4,
)
# 加载权重
ckpt = torch.load("checkpoints/epoch_15.pt", map_location="cpu")
model.load_state_dict(ckpt["model_state_dict"], strict=False)
model = model.to("cuda").eval()
# 推理 (~8 GB VRAM)
images = [Image.open(f"cam_{i}.jpg").convert("RGB") for i in range(2)]
state = torch.zeros(8) # 归一化后的机器人状态
with torch.no_grad():
action_chunk = model.sample_actions(images, "pick the red block", state)
print(action_chunk.shape) # torch.Size([1, 16, 7]) — 16步动作块
# 取第一步发给机器人
first_action = action_chunk[0, 0].float().cpu().numpy() # (7,)
部署到 SO-ARM101
模型输出 EEF delta,部署到 SO-ARM101 需通过 IK 反算关节角:
# IK 层(参考 deploy/kinematics/fk_ik_server.py, ikpy 后端)
joint_angles = ik_convert(first_action[:6], current_joints)
robot.set_joints(joint_angles, gripper=first_action[6])
| 平台 | VRAM | 备注 |
|---|---|---|
| RTX 4060 Laptop 8GB | ~8 GB | sdpa · bf16 |
| A800 40GB | ~8 GB | flash_attn · bf16 |
📁 文件清单
| 路径 | 说明 |
|---|---|
checkpoints/epoch_15.pt |
最新(329 MB,含解冻视觉层) |
checkpoints/epoch_12.pt |
首个解冻视觉层的 epoch(329 MB) |
checkpoints/epoch_6~11.pt |
仅训练 Action Expert(233 MB × 6) |
checkpoints/epoch_14.pt |
过渡 epoch(329 MB) |
models/flow_vla.py |
FlowVLA 主模型 |
models/flow_expert.py |
Action Expert (Transformer) |
models/base.py |
Qwen3-VL 编码器封装 |
models/lora_utils.py |
权重加载工具函数 |
flow_matching/scheduler.py |
Flow Matching 调度器 |
data.py |
多数据集加权采样加载器 |
train_flow.py |
训练主循环 |
config_flow_autodl.yaml |
完整训练配置 |
utils/checkpoint.py |
检查点保存/恢复 |
utils/chunking.py |
动作分块工具 |
rollout_sim.py |
仿真 rollout 评估脚本 |
⚠️ 已知局限性
- 无自采数据 — 全部来自公开数据集,未与 SO-ARM101 对齐。部署需 IK 转换层
- 未实物 rollout — 仅完成训练,实物闭环评估未做,成功率未知
- MSE loss 不直接反映任务成功率 — training loss ~0.7 正常范围,但不等同于成功率
- 256×256 低分辨率 → 可能影响细粒度操作
- 仅英文指令 → 未训练中文
- Fractal 质量参差 → 已降权但仍有噪声
📝 Citation
@misc{flowvla-2026,
title = {FlowVLA: Flow Matching Vision-Language-Action for Robot Manipulation},
author = {},
year = {2026},
url = {https://huggingface.co/LingArm/lingarm-vla-1.0-preview}
}