Skip to content

Add the Cosmos3-Edge world-action model (LIBERO) - #79

Merged
khanhnd61-vr merged 18 commits into
VinRobotics:mainfrom
kvgkvg:cosmos3-edge
Nov 9, 2026
Merged

khanhnd61-vr merged 18 commits into
VinRobotics:mainfrom
kvgkvg:cosmos3-edge

Conversation

@kvgkvg

@kvgkvg kvgkvg commented Nov 9, 2026

Copy link
Copy Markdown
Contributor

Written for: vla.cpp maintainers reviewing the PR.

Add the Cosmos3-Edge world-action model (LIBERO)

  • What: a new architecture for lerobot/Cosmos3-Edge-Policy-LIBERO (28-layer Mixture-of-Transformers, 30 UniPC steps). The five stage graphs are generated by ggml-compiler and used as generated. scripts/port_cosmos3_graphs.py regenerates them.
  • Added:
    • the engine, including the two-view canvas built the way lerobot's processor does;
    • a C++ prompt builder (caption, chat template, an ASCII-only BPE read from the GGUF) and a rot6d → LIBERO decode;
    • vla-cli --text and --libero;
    • a converter;
    • a cosmos3_edge client preset and an eval/run_libero.sh block;
    • tests and docs.
  • Unchanged: vla-server and the public C API.
  • Verified (bf16, CPU and CUDA on an RTX 3090 only):
    • Given lerobot's canvas, output is bit-identical to ggml-compiler's runtime (CPU on 3 prompts, CUDA on 1).
    • Captions and token ids match lerobot and Hugging Face on every LIBERO task (45 of 45 prompts, 550 of 550 extra texts). The rot6d decode is within 7e-7.
    • The C++ canvas is within one pixel of torch's CPU result.
    • Closed loop on libero_spatial: 18/20 and 19/20 episodes.
    • A request through vla-server returns the same bits as a direct call, and the harness solved one episode through it (CPU).
    • ctest: 11/11.
  • Not verified:
    • Other backends, and the server on a GPU.
    • 20 episodes cannot separate these results from the PyTorch baseline.
    • The 2,000-episode result (96.45% against PyTorch's 96.6%) was measured through ggml-compiler's runtime, not vla.cpp.
  • Limits:
    • It is specialized: two views, a 192×320 canvas, prompts of at most 192 tokens, 30 steps.
    • Prompts must be ASCII.
    • Some options are refused: --weight-dtype, --act-dtype, --flash-attn, --mm-prec-f32 and --num-steps.
    • 16-bit weights add rounding of about 1e-3 to 2e-3 on the actions, and PyTorch's own bf16 run is further from f32.
  • Notes:
    • cosmos3_edge_graphs.cpp is about 5,000 generated lines, so review the generator and the engine.
    • No GGUF is released, so the README matrix shows ~, not Y.

kvgkvg and others added 14 commits November 9, 2026 10:47
Cosmos3-Edge-Policy-LIBERO: a 28-layer Mixture-of-Transformers that denoises 4 latent video frames and a
16-step action chunk together, 30 UniPC steps.

The five stage graphs (Wan2.2 VAE encoder, prompt prefix, init, one UniPC step, de-normalization) were
generated by ggml-compiler and are used as generated: src/models/cosmos3_edge_graphs.cpp, ported by
scripts/port_cosmos3_graphs.py. cosmos3_edge_build.h gives them the five runtime calls they use, and
cosmos3_edge_ops.h is ggml-compiler's ops header, copied unchanged. cosmos3_edge.cpp is the engine: weights,
the stage graphs with a persistent buffer for what crosses stages, the 30-step loop, and the canvas the model
expects (two views side by side, bicubic with antialias, reflection padding; or one canvas the caller made).

cosmos3_edge_prompt.cpp builds the prompt from the instruction (JSON caption, chat template, a byte-level
BPE read from the GGUF; ASCII text only, anything else is refused) and decodes rot6d to LIBERO commands.
vla-cli --text and --libero use them.

scripts/convert_cosmos3_edge_to_gguf.py turns a `ggml-compiler compile` output into the vla.cpp GGUF, with
the tensors copied byte for byte; --policy-dir adds the tokenizer and the caption settings.

Verified, bf16 GGUF, CPU and CUDA (RTX 3090) only; no other arch or backend touched, no existing output moved:
- given lerobot's canvas, bit-identical to ggml-compiler's runtime: CPU on three prompts of 150, 153 and 161
  tokens, CUDA on one (tests/py/cosmos3_edge_parity.py);
- captions byte-identical and ids identical to lerobot and Hugging Face for the 40 LIBERO tasks and five edge
  cases, and for 550 random ASCII and special-token texts; llama.cpp b11223's BPE gave the same ids on 607 of 607
  (test_cosmos3_edge_prompt, data in tests/data); rot6d decode within 7e-7 of lerobot's on 62 rows;
- libero_spatial, 2 episodes per task, seed 0, CUDA: 18/20 with lerobot's canvas and tokens, 19/20 with the
  C++ canvas, tokenizer and decode in the loop (0 token mismatches in 168 calls). Twenty episodes do not
  separate these from each other or from the PyTorch policy;
- ctest: 11/11.

Not verified: ROCm, SYCL, Metal, OpenVINO, Hexagon, vla-server, a full 50-episode-per-task run through vla.cpp.
README support-matrix row (CPU and CUDA marked in progress: no GGUF is released), CHANGELOG entry, the
256-wide two-view size in CONTRIBUTING's predict_check list, and docs/MODELS.md#cosmos3-edge-world-action-model
with the four build steps, the inputs and outputs, the limits (ASCII text, one fixed setup) and the numbers
behind each claim, including the ones that do not settle anything (20 closed-loop episodes).
…heck

vla-server needs no change for this model: it passes the images, token ids and noise of a request to predict() for
any architecture, and Cosmos3-Edge fits its checks (no state, a 16x10 noise and response, a warm-up its engine
accepts). The server has no text field, so the client sends token ids.

eval/client/vla_cpp_client.py gets a `cosmos3_edge` preset: it builds the JSON caption of lerobot's
Cosmos3PromptProcessorStep and the chat template of Cosmos3TokenizerProcessorStep with the policy's tokenizer,
sends the two 256x256 views as float RGB, and decodes the 16x10 rot6d chunk to 16 LIBERO commands (numpy,
float64, as lerobot's Cosmos3LiberoActionProcessorStep does). Use it with --n-action-steps 16.

tests/py/cosmos3_edge_server_check.py checks a running server, bit for bit against a direct libvla call, and the
client's tokens, rot6d decode and get_action.

Verified, bf16 GGUF of revision 0a81054, CPU only: a request returns bit-identical actions to a direct call (after
a 62 s warm-up); the client builds the same 150 token ids as the case's; its rot6d decode is within 7e-7 of
lerobot's on 62 rows; get_action returns a chunk of 16 finite LIBERO commands. No other arch touched; ctest 11/11.

Not verified: the server on a GPU, a closed-loop LIBERO run through the server, eval/run_libero.sh (no Cosmos3-Edge
block until there is a released model directory).
run_libero.sh -m cosmos3_edge starts vla-server on cosmos3-edge-libero-gguf/cosmos3-edge-libero-bf16.gguf under the
models directory, runs the LIBERO client with 16 action steps per chunk, and stops the server, like the other models.
A missing model directory is skipped, so -m all is unaffected.

The client needs a Python with LIBERO and a transformers that reads the policy's tokenizer, which the LIBERO venv of
setup_libero.sh (transformers 4.51) may not: COSMOS3_EDGE_PYTHON picks another, as VLA_JEPA_PYTHON does for vla_jepa,
and the LIBERO venv check is skipped when it is set. COSMOS3_EDGE_TOKENIZER names a local tokenizer/ directory, and
the client waits 300 s per chunk by default (a chunk takes about a minute on a CPU).

Verified, bf16 GGUF of revision 0a81054, CPU server, no other arch touched: libero_spatial task 0, one episode,
through this script: solved in 79 steps (reward 1.00; server RSS 6.5 GB). One episode shows that the path works end to
end, not a success rate.

Not verified: the server on a GPU (both GPUs of the test machine were full), more than one episode.
…e 10 scalars as one tensor, size the stage arenas from the graph cap and drop the tensor-count pin
…s3 and a converter from the checkpoint's safetensors, in place of the ggml-compiler output
… the converter, the prompt test and the docs remain
@khanhnd61-vr
khanhnd61-vr merged commit 50580fe into VinRobotics:main Nov 9, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants