Repository navigation
Cosmos3: give the generation positions a contiguous tensor so a new prompt length does not recompile the denoise step - #922
Conversation
Action and sound requests passed position_ids[:, und_len:] to the compiled denoise step. That view's stride is the prompt length plus the generation length, and the step is compiled with dynamic=False, so every new prompt length failed the stride guard and recompiled it: 2-3 s on the first request with a cold Inductor cache. The static inputs now carry a contiguous copy, made once per request, and a new prompt length replays the step compiled at startup.
Automated review🟡 No findings on Description
What the review checked
Advisory, not a merge gate. Rules: |
NSagan271
left a comment
There was a problem hiding this comment.
LGTM, pending some live testing that I'm running
Live test: #922 Cosmos3 generation position idsHead Verdict: ✅ A new prompt length no longer recompiles the denoise step, and eager outputs are bit-identical to base.
Other
|
Main since 73c6c17: #883 mstar_rust in the Linux wheels, #901 output spans (BatchedModelOutput.output_spans, NodeSubmodule.spanned_outputs, the worker's crop), #904 DiT seed noise drawn at ingest (on_request_added, NoiseStager deleted, to_device_nonblocking as one memcpy into pinned memory), #903 API-server torch pool from the CPU quota and pooled image encodes, #924 robotics harness, #819 Inductor cache under ~/.cache, #881 CommGroup.agree / JointGroups.agree (agree_across_ranks and flagged_on_any_rank deleted), #724 CUDA IPC KV in one 2D memcpy a page, #387 GLM-5.2 (MLA, fp8 MoE with NoAuxTcRouter, the DSA resource), #921 vjepa2 AC crop, #922 Cosmos3 contiguous positions, #923 dense attention falls back when fa3-fwd has no kernel for the GPU. Conflicts: - mstar/utils/h2d.py, to_device_nonblocking: the stack's signature (data: Tensor | Sequence, device, dtype=None) and DeviceCapability pin_memory gate, with main's tensor path (#904): a CPU tensor is written into a fresh pinned buffer with one memcpy rather than pin_memory()'s copy_ over the intra-op pool. Every CPU tensor now goes through a fresh buffer, so the stack's "an already-pinned source is read in place" caveat (R3.3) no longer applies and is dropped from the docstring. test_accelerator_graph_backend's pinning test checks the pinned torch.empty and its non-blocking copy instead of pin_memory(). - mstar/model/components/diffusion/denoise_loop.py: imports, both (main's copy, the stack's functools). Main code on a superseded path, ported here: - GLM-5.2 (glm52/submodules.py): its own check_stop / check_stop_batched (four arguments, step_walk, its own row-map loop) / _stops -> token_stop = TokenStop(decode_loop, new_token, eos_token_ids, sampler) with a _token_stops override for its two differences (a stop token at prefill ends the reply at the first decode step; max_tokens counts the prefill's token), and a check_stop override for that closing step, whose token postprocess drops. test_glm52_model's helper and test_model_kv_layouts' GLM cap test build the real submodule (over a stub language model) instead of object.__new__, which would leave token_stop unset. - PinnedStager.to_device (#387), a second "host values -> new device tensor" helper beside to_device_nonblocking: deleted with its test (test_pinned_stager_to_device.py); its callers, GLM-5.2's prefill seq_lens and the DSA resource's page tables, call to_device_nonblocking(list, device, dtype=torch.long). test_dsa_resource spies on that instead. The other files both sides touched (engine.py, accelerator_graph_runner.py, kv/manager.py, attn/base.py, ragged/base.py, communication.py, model/base.py, submodule_base.py, entrypoint.py, conductor.py, moe.py, image_io.py, vjepa2_model.py, docs, tests) auto-merged into disjoint hunks: per file the merged delta equals main's own. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Cosmos3 policy's compiled
denoise_step(dynamic=False) recompiled for every new prompt length: 2.2-3.4 s on that request with a cold Inductor cache, 0.5-0.6 s warm, and a busy server walking toward the 84-recompile limit.TORCH_LOGS=recompilesshows each new prompt failing one guard, the stride ofposition_ids_cond: the action and sound paths passposition_ids[:, und_len:], a view whose row stride is the prompt plus generation length, while the text K/V only enters after the attention graph break.The static inputs now carry
gen_position_ids, a contiguous copy made once per request inpacking.py, used at every call site. The video paths already passed their own tensor. No padding or bucketing needed.Numbers, 2x B300, 8 droid_100 observations with 8 distinct prompt lengths (6-22 tokens), seeds 1000+i:
Tests: a CPU test that the generation band has the same size, stride and offset for 4, 9 and 23 prompt tokens (fails on main).
mstar/model/cosmos3/tests,test_cosmos3_edge_model.py,test_cosmos3_graph_switch.py: 217 passed, 21 skipped (main 216 / 21). e2e--tier fullcosmos3_edge_droid and cosmos3_nano_ar pass on B300 with the flashinfer configs. ruff clean.