Conversation
|
In the new KV-ring resource: Writes can only accept a fixed number of tokens per step; however, I am not sure if future models with ring KV mechanics will depart from this, or if it will be easy to book-keep for a dynamic write-size system. Why is Nit: |
5a3c562 to
25ffb5e
Compare
@stephen-dwq Yeah that makes although for the scope of this model port I was thinking we can stuck to the fixed KV ring structure ? I have enabled batching in my latest commit, had deferred for ease of implementation and code review for myself initially. Addressed the nit. |
Native port of the Waypoint 1.5-1B autoregressive video world model.
Additive only -- no existing mstar file is touched.
- config.py WaypointConfig, 720P and 360P variants, ring sizing.
- components/ rope.py (OrthoRoPE over disjoint head-dim bands),
layers.py (AdaLN-Zero, MLPFusion, CondHead),
attention.py (GQA with value-residual threading),
kv_backend.py (model-owned ring + FlexAttention
BlockMask), dit.py (24 blocks, the 4+1 pass loop).
- weight_loader.py maps the 1.86B-parameter checkpoint onto the 1.28B
instantiated model, including the cond_proj tie shared
24x and re-established after to_empty().
Three choices worth flagging at review time.
The KV cache is a model-owned ring and get_node_resources() returns [].
For this model the cache *is* the world state, so eviction is amnesia
rather than a cost. An engine-owned ring is not currently expressible:
SequenceView asserts start == 0 ("dense attention reads a stream from its
first page"), and RetentionPolicy is declared but unimplemented. When both
land the swap is local to kv_backend.py and nothing else changes.
FlexAttention is used instead of FlashInfer, at a model-local seam, for
numerical parity with the reference. Attention is per-layer heterogeneous
(18 local dense window-16, 6 global stride-8 dilated window-128), which the
BlockMask expresses directly.
There is no working eager mode. Eager ignores a no-op-mask_mod BlockMask
and silently attends to unwritten ring slots -- wrong output, no error --
so the flex_attention call is compiled unconditionally.
120 cases across three files.
- test_waypoint_components.py 38 cases: RoPE band layout, ring wraparound,
BlockMask shape, AdaLN-Zero, CondHead tying.
- test_waypoint_dit.py 21 cases: the 4+1 pass structure, value
residual threading, per-layer local/global
heterogeneity, ring commit semantics.
- test_waypoint_weight_loader.py 61 cases, covering four defects an
independent audit found -- two of them
silent. A pre-fused qkv_proj alongside split
shards would load both, because conflicts
were keyed on (target, shard_id) and so
(t, None) never collided with (t, "q");
safetensors' sorted key order then gave Q
and K from the fused blob and V from v_proj.
And the cond_proj tie probe compared only the
first 64 columns, so a divergent block passed
clean. Each regression test was confirmed to
fail against the pre-fix loader.
Mutation-checked rather than coverage-checked: 10 injected mutants in the
components and DiT, all killed.
What these do NOT cover, since they run on CPU in fp32 against synthetic
state dicts: the real checkpoint, bf16, the compiled regions, and a
mislabelled K/V pair on disk. The last is worth calling out -- n_heads=32
over n_kv_heads=16 means a checkpoint with k_proj and v_proj transposed
relative to what the reference wrote would load with matching shapes and
produce only wrong output. Nothing static distinguishes it; only a forward
parity run against the reference can.
…viewed manager and cache changes
…rame streaming Model: dit, taehv, rope, attention, layers, weight_loader, checkpoint, submodules. Engine: ring KV backend, flex attention resource, CUDA graph buckets. Serving: video_frame modality across api_server, data_worker and client SDK. Tests: component, equivalence, pixel, packaging and streaming benchmark suites.
The api_server process emitted no NVTX at all: APIServer was constructed without enable_nvtx, so the flag only ever reached the conductor. Traces therefore ended at worker.send_outputs, leaving ~90ms of the 116.9ms 720p inter-chunk gap unattributed. Adds: apiserver.b64encode / json_dumps / chunk_available / yield_line, dataworker.get_tensor / postprocess / queue_output, cg.replay.slot, and benchmark.stream / await_chunk / chunk_arrival to anchor the client clock. All gated on the existing --enable-nvtx flag.
NDJSON has to base64 each chunk so it fits on one line. At 720p that turns 11 MB into 14.7 MB, and json.dumps then scans every character of it. That is more CPU than the 66.67 ms frame budget allows, so the event loop stalls and the socket jams on backpressure. Binary framing sends a JSON header with nbytes, then the payload untouched. Nothing has to scan for a delimiter, so nothing needs escaping or encoding. NDJSON stays the default; clients opt in via Accept. Also lands the client-side NVTX ranges used to measure this, gated on enable_nvtx.
Startup p95 -7.6% at 720p and -14.2% at 360p for 0.12 MB more graph memory.
…waypoint Loop-external inputs (re-injected into ready_signals each iteration) now count as ready for same-node speculation. Waypoint fuses TAEHV decode into the DiT step and runs the rollout loop async with a clock self-edge; 720p payload SHA unchanged.
…ame_noise drew fp32 on a CPU generator and copied to device. That pageable H2D was a blocking copy
…9x/1.74x faster per call at 720p/360p The Triton flex kernel runs one 4-warp CTA per SM (~27% of tensor peak on H100). The sm90 kernel from the flash-attn-4 CuTe package runs 3 warpgroups per CTA with TMA loads and softmax/GEMM overlap across warpgroups, so the same ring-masked attention gets far more parallelism per SM. Ring-full median per call: 720p 129.4 -> 72.3 us (12.5 -> 7.0 ms/step, 2.62 -> 3.10x realtime), 360p 35.1 -> 20.2 us (3.46 -> 2.03 ms/step, 4.19 -> 4.99x). MSTAR_FLEX_BACKEND=TRITON restores the previous kernel bit-for-bit. flash-attn-4 is installed separately (docs/installation.rst). flashinfer FA3 paged prefill was only 1.12x at batch 1; revisit it once batch size > 1 is in play.
The ring KV cache called its per-request partition a "world", which is waypoint-specific jargon. Rename it to "session" across the KV resource layer and the code that drives it: num_worlds->num_sessions, world_idx->session_idx, world_span->session_span, world_base-> session_base, _free_worlds->_free_sessions, total_worlds->total_sessions, world_of->session_of and the remaining world_* helpers, plus the bare world/worlds nouns inside kv/ring, flex and the kv config. Used session_idx rather than the suggested span_idx: "span" already names the (lo, hi) KV tensor slice a session occupies (session_span), so span_idx there would be ambiguous. Left untouched: the distributed rank count (world_size / tp_world_size), the separate world-model / world_engine abstraction in model/waypoint, and the benchmark harness --worlds flag.
ebd1f69 to
b643c9b
Compare
CI runs `ruff check --output-format=github .` and was failing on 12 findings across waypoint code: - B905 zip() without strict=: flex._stage, serve_rollout diff summary, test_waypoint_shell, and 5 sites in benchmark_streaming. Parallel arrays that must match length get strict=True; the adjacent-pairs zip(timestamps, timestamps[1:]) keeps its length-off-by-one intent with strict=False. - W291 trailing whitespace in the frame-noise docstring (submodules). - PLW0108 lambda: object() -> object for the graph_pool_handle stub (identical: both return a fresh object when called). - PLR1730 if/assign -> max(max_abs_diff, diff) in serve_rollout.
…nce gates Untrack (kept local) the benchmark/profiler/summary meta-tests and the nsys replay parser; no peer model port (wan22, orpheus, pi05, vjepa2, ...) commits benchmark/profiler pytest tests. Drops test_batch_sweep_summary.py (also a hardcoded out-of-repo _tools path), test_waypoint_streaming_benchmark.py, test_waypoint_profiler.py, and test/waypoint/check_nsys_replay.py from the tree. Share _load_reference and _seed_clip across the equivalence gates via test_waypoint_reference_equivalence.py instead of the 360p file re-implementing them, and skip the pixel tests that need the second 'repro' oracle recording when it is absent rather than hard-failing.
Condense essay docstrings and drop historical notes, baked-in perf numbers, and references to local-only docs (VALIDATION.md, OPTIMIZATION_BACKLOG.md) across the model port, matching the terse functional comment style of peer ports (orpheus). Keeps the non-obvious why (numerics/perf hazards, ordering constraints, shape/dtype contracts). Comments and docstrings only; no code changed (AST-verified, py_compile clean). ~370 lines removed across 9 files.
benchmark_streaming.py gains --protocol {binary,ndjson} (default binary) to force the base64 NDJSON path for A/B runs against the raw-bytes streaming format; wires enable_nvtx and prefer_binary through MStarClient and records stream_protocol in the report.
Comment/docstring-only cleanup across the Waypoint test suite, oracle/serving
scripts, and config, matching peer model ports (wan22, pi05, orpheus). No code
changed - verified by comparing docstring-stripped ASTs against HEAD.
- test/modular/test_waypoint_*.py: trim narrative docstrings, drop dead-doc
references left by the model-folder prune (T*/PARAM_TREE/S* labels), and
remove verbatim duplicates between module and per-test docstrings; keep
WHY-only comments, the F1-F4 regression catalog, and cross-referenced banners.
- test/waypoint/record_oracle.py: 81-line module docstring -> 38, keeping the
artifact layout, numerics/reproducibility contract, and usage.
- test/waypoint/{serve_rollout,benchmark_streaming}.py: tighten docstrings;
keep the isolation-gate invariants and protocol rationale.
- configs/waypoint.yaml: essays -> terse invariants (values unchanged).
- .gitignore: revert the branch's additions (.claude_scratch/, docs/waypoint/,
WAYPOINT_PROGRESS.md) to keep main's .gitignore unpolluted.
efcb345 to
330cfed
Compare
Overview
This PR adds Waypoint 1.5 1B, an interactive video world model, to mstar. Given a seed clip and a sequence of user actions, Waypoint maintains an internal world and streams generated RGB frames as that world advances.
Model shape
Prime once:
seed clip -> VAE encoder -> DiT [seed world state; no client output]-> VAE decoder
Roll out N times:
action + world state -> DiT -> VAE decoder -> 4 RGB frames -> client
This maps to three mstar nodes and two graph walks:
Added
video_frameas a separate modalityThe existing
videomodality represents a complete encoded video artifact, such as an H.264 MP4. The container is finalized after generation and returned as one playable result. Waypoint has a different output shape. It generates four frames per rollout step and must send them immediately while the world continues running.video_frametherefore represents an ordered batch of raw RGB24 frames.Resource boundary
In mstar, a resource is state or execution support that the engine must coordinate around a forward pass through admission, planning, stable allocation, commit, and cleanup.
Waypoint’s ring KV cache meets that definition: it is the persistent world state, must survive CUDA graph capture, assigns isolated world slots to requests, and must be reset when a request ends. FlexAttention is also an engine resource planned over that cache. The encoder and decoder remain normal model submodules because they do not require shared capacity or engine-level admission.
KV configuration
The previous KVConfig described both common KV geometry and paged-cache behavior. Waypoint uses a fixed-size ring that overwrites old frames, so fields such as page size, maximum pages, and offload policy do not apply.
We split the configuration into:
KVSpec selects the appropriate manager from the concrete config. Existing models continue to use the same paged behavior, now named explicitly, while invalid storage-specific options fail instead of being silently ignored.
Async Execution
carried_namesto address this.Benchmarking numbers [FLASH backend]
360p
720p
Gap p50 = median across streams; Gap p95 = worst stream's p95. On-time chunk % = worst stream's fraction of chunks within the 66.7 ms budget. Realtime = every stream sustained ≥1× with gap p95 ≤ 66.7 ms and no stalls. Headline: 360p realtime to batch 8; 720p realtime only at batch 1.
Follow-up TODOs