Skip to content

Commit 8eccfc8

Browse files
fearblackcatshenjun
authored andcommitted
add motus to loongforge vla
Change-Id: I8b7d9541e7b41f5d73b3a0fc6b719918b08cd03b
1 parent a17058e commit 8eccfc8

76 files changed

Lines changed: 16519 additions & 15 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

configs/models/embodied/motus.yaml

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# Motus VLA (WAN video + Qwen3-VL + Action Expert three-modal MoT) embodied config.
2+
# Values mirror the source repo configs/lerobot.yaml (model + dataset sections).
3+
model:
4+
model_type: motus
5+
6+
# WAN video backbone
7+
wan_config_path: "/workspace/motus/models/hf/Wan2.2-TI2V-5B"
8+
wan_checkpoint_path: "/workspace/motus/models/hf/Wan2.2-TI2V-5B"
9+
vae_path: "/workspace/motus/models/hf/Wan2.2-TI2V-5B/Wan2.2_VAE.pth"
10+
video_precision: bfloat16
11+
12+
# VLM (frozen)
13+
vlm_checkpoint_path: "/workspace/motus/models/hf/Qwen3-VL-2B-Instruct"
14+
vlm_precision: bfloat16
15+
16+
# Task dimensions (shared with data side)
17+
action_dim: 14
18+
state_dim: 14
19+
20+
# Action expert
21+
action_expert_hidden_size: 1024
22+
action_expert_ffn_dim_multiplier: 4
23+
action_expert_norm_eps: 1.0e-5
24+
25+
# Understanding expert
26+
und_expert_hidden_size: 512
27+
und_expert_ffn_dim_multiplier: 4
28+
und_expert_norm_eps: 1.0e-5
29+
vlm_adapter_input_dim: 2048
30+
vlm_adapter_projector_type: mlp3x_silu
31+
32+
# MoT backbone depth
33+
num_layers: 30
34+
35+
# Video / sampling geometry (shared with data side)
36+
num_video_frames: 8
37+
video_action_freq_ratio: 6
38+
global_downsample_rate: 1
39+
video_height: 384
40+
video_width: 320
41+
42+
# Loss weights
43+
video_loss_weight: 1.0
44+
action_loss_weight: 1.0
45+
46+
# Training mode / switches
47+
training_mode: finetune
48+
load_pretrained_backbones: null
49+
50+
data:
51+
# LeRobot dataset location
52+
repo_id: "/workspace/motus/data/aloha_mobile_cabinet"
53+
root: "/workspace/motus/data/aloha_mobile_cabinet"
54+
55+
# Task selection
56+
task_mode: single
57+
task_name: null
58+
max_episodes: null
59+
image_aug: false
60+
61+
# Normalization / embodiment
62+
embodiment_type: aloha_agilex_2
63+
64+
# Video decoding
65+
video_backend: torchcodec
66+
67+
# T5 language embedding (on-the-fly encode + cache fallback)
68+
enable_t5_fallback: true
69+
t5_wan_path: "/workspace/motus/models/hf/Wan2.2-TI2V-5B/"
70+
t5_folder_name: t5_embedding
71+
t5_text_len: 512
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#!/usr/bin/env python3
2+
# Copyright 2026 The LoongForge Authors.
3+
# SPDX-License-Identifier: Apache-2.0
4+
"""Online-vs-online VAE-input parity check (DATA link).
5+
6+
Compares the LATENT_DUMP dumps of TWO separate online training runs (both
7+
launched with the SAME PARITY_DATA_SEED so the sampler visits identical anchors
8+
in identical order). For each matching rankR_stepN.pt it bit-compares:
9+
10+
- first_frame (decode + normalization + H2D)
11+
- video_frames (decode + normalization + H2D)
12+
- clean_full_latent (end-to-end: data + VAE compute)
13+
14+
A `torch.equal` pass on first_frame / video_frames proves the data pipeline
15+
(torchcodec decode + transform + collate) is bit-deterministic ACROSS PROCESSES
16+
-- i.e. re-fetching the same (episode, condition_frame) anchor in the offline
17+
precompute will get the exact same input pixels. Combined with
18+
verify_offline_latents.py (compute link), a pass on both scripts means the
19+
offline latent cache is end-to-end bit-identical to the online encode.
20+
21+
Usage
22+
-----
23+
python examples/embodied/motus/diff_online_dumps.py \
24+
--dir-a /tmp/latent_dump_run1 --dir-b /tmp/latent_dump_run2
25+
"""
26+
from __future__ import annotations
27+
28+
import argparse
29+
import glob
30+
import os
31+
32+
import torch
33+
34+
35+
def _cmp(a: torch.Tensor, b: torch.Tensor) -> str:
36+
if a.shape != b.shape:
37+
return f"SHAPE-MISMATCH {tuple(a.shape)} vs {tuple(b.shape)}"
38+
if torch.equal(a, b):
39+
return "equal"
40+
diff = (a.float() - b.float()).abs().max().item()
41+
return f"DIFFERS max|abs|={diff:.3e}"
42+
43+
44+
def main() -> int:
45+
ap = argparse.ArgumentParser()
46+
ap.add_argument("--dir-a", required=True, help="dump dir of online run #1")
47+
ap.add_argument("--dir-b", required=True, help="dump dir of online run #2")
48+
args = ap.parse_args()
49+
50+
files_a = sorted(glob.glob(os.path.join(args.dir_a, "rank*_step*.pt")))
51+
if not files_a:
52+
print(f"[FAIL] no dumps in {args.dir_a}")
53+
return 2
54+
55+
all_ok = True
56+
for fa in files_a:
57+
name = os.path.basename(fa)
58+
fb = os.path.join(args.dir_b, name)
59+
if not os.path.exists(fb):
60+
print(f"{name}: MISSING in dir-b")
61+
all_ok = False
62+
continue
63+
da = torch.load(fa, map_location="cpu")
64+
db = torch.load(fb, map_location="cpu")
65+
ff = _cmp(da["first_frame"], db["first_frame"])
66+
vf = _cmp(da["video_frames"], db["video_frames"])
67+
lat = _cmp(da["clean_full_latent"], db["clean_full_latent"])
68+
ok = ff == "equal" and vf == "equal"
69+
all_ok = all_ok and ok
70+
print(f"{name}: first_frame={ff} | video_frames={vf} | latent={lat}")
71+
72+
print()
73+
if all_ok:
74+
print("[PASS] data pipeline is bit-deterministic across processes.")
75+
print(" -> offline precompute will get identical VAE inputs per anchor.")
76+
return 0
77+
print("[WARN] VAE inputs differ across runs -> decode/transform is not")
78+
print(" cross-process deterministic; offline cache keys must pin the")
79+
print(" exact decoded frames (store inputs, not just anchor ids).")
80+
return 1
81+
82+
83+
if __name__ == "__main__":
84+
raise SystemExit(main())

0 commit comments

Comments
 (0)