Skip to content

Fix models that don't start and request inputs that crash the worker - #1167

Open
dghosef wants to merge 15 commits into
mstar-project:mainfrom
dghosef:bugfix/startup-and-bad-inputs
Open

dghosef wants to merge 15 commits into
mstar-project:mainfrom
dghosef:bugfix/startup-and-bad-inputs

Conversation

@dghosef

@dghosef dghosef commented Nov 3, 2026 •

Copy link
Copy Markdown
Collaborator

Pending GPU testing: only the DiT's own recompile limit under a step-dtype schedule (it needs mxfp8/nvfp4 linears, so Blackwell). Everything else below ran on an H100.

What this does

How it works

  • Bad requests are refused where each model resolves the request (process_prompt / _resolve_gen_params), as a ValueError (400). The bounds come from the model's config: the embodiment table size, the VAE scale, the rotary table, the encoder's token count. Nothing new reaches the worker.
  • compile_transformer_forward sets Dynamo's recompile_limit around each call. Dynamo reads the limit when a call compiles, so this works on every torch version. Before 2.12 the setting is process-wide while the forward runs, so a compile on another thread at the same time would see it too. Today only the GPU thread compiles.
  • Qwen3-TTS: mstar already loads qwen-tts' tokenizer source itself. On that private copy it makes upsample / decoder_transformer plain class attributes. On 5.21+ it maps the checkpoint's flat Mimi names to the nested layout, using the same three renames as transformers' own conversion_mapping.
  • EXIF: one helper, media_limits.open_upright_image, opens an image with Pillow and rotates it. read_image sends a static WebP with an orientation tag through it, because torchvision's WebP decoder ignores EXIF.
  • Cross attention drops the assert. Its captured wrapper sizes the page index buffer with captured_page_capacity, the same helper the self-attention managers use, which comes to about 1 MB for Whisper.

Tests

Test Where Result
ruff check . dev box pass
CPU Core suite vs main CPU (dev box) 11216 passed, 1155 skipped on main 9c6f1ad; 0 failures only on this branch
Changed test files repeated 20× (13 files) CPU (dev box) 20008 passed, 0 failed
DiT recompile limit under the real torch.compile on torch 2.10 (test_flux2_klein_model.py) CPU pass; fails without the fix
Qwen3-TTS codec encoder loads a flat Mimi checkpoint (test_qwen3_tts_model.py) CPU, transformers 5.20.2 and 5.22.1 pass on both; fails without the fix on 5.21+
Same seeded encoder and clip on transformers 5.20.2 vs 5.22.1 CPU identical codes (1, 32, 38)
EXIF orientation on JPEG, static WebP and LingBot, plus a malformed-EXIF case (test_media_decode_limits.py) CPU pass; 6 of 16 cases fail without the fix
Cosmos3 domain_id, action shape, short clip and size cases (cosmos3/tests) CPU pass; fail without the fixes
V-JEPA 2 mask cases, Pi0.5 batch of 5, Z-Image 8208 px, Chatterbox first chunk, FLUX.2 LoRA alpha, Qwen3.5 1/3 px images, loader device spy CPU pass; fail without the fixes
Cross-attention plan with shared context pages, eager and captured (test_cross_attention_plan.py) CPU pass; fails without the fix
Whisper at c=128 with repeated audio on a 400-page cross pool, CUDA graphs on mstar_sim (emulated H100, #1180) main: 363 of 384 fail on the #1006 assert ("indexes 427 pages but the context cache holds 400"); this branch: 384 of 384 served
Whisper at c=128 with repeated audio on a 400-page cross pool, CUDA graphs on GPU (H100) main: 363 of 384 fail on the #1006 assert. This branch: 384 of 384 served, every transcript correct
FLUX.2 klein 4B / Z-Image-Turbo compiled builds on torch 2.10, stock configs GPU (H100) main: both fail at startup (compile() got an unexpected keyword argument 'recompile_limit'). This branch: both build (16 compiled shapes each) and serve a 1024² image, no recompile-limit warning
Whisper with a 160-page cross pool, CUDA graphs on mstar_sim (emulated H100) main: dies at startup on the assert ("indexes 384 pages but the context cache holds 160"); without the assert, the old captured buffer (pool + batch size) would overflow, 192 vs 384. This branch: starts and serves 128 of 128
Served end to end, main vs this branch: EXIF upright reference image (FLUX.2), Cosmos3 action shape / short clip / sub-latent size, V-JEPA 2 lone mask, Pi0.5 eager batch of 8 and 16, Qwen3.5 256×1 image, Chatterbox stream_first_chunk_tokens: 6, Z-Image 8208 px, FLUX.2 / Z-Image compile on torch 2.10 mstar_sim (emulated H100) main fails each as described (500s, a dropped mask, a sideways image, chunk-2 crash, startup TypeError); this branch: 400s where refused, correct output otherwise. Cosmos3 domain_id=40 and a V-JEPA 2 context_mask index of 10**6 device-assert on main and poison the worker (the next requests fail too); this branch answers 400 and keeps serving. The loaders stage a cuda:1 node's weights on cuda:0 on main (64 MB peak on cuda:0), on cuda:1 here
Qwen3-TTS Base reference encoder build and load on transformers 5.22.1, header-only checkpoint mstar_sim (emulated H100) main: "no setter"; with only the setter half, 125 tensors not loaded; this branch: loads
Qwen3-TTS-12Hz-1.7B-Base voice clone on transformers 5.22.1 GPU (H100) main: the worker dies at startup ("no setter"). This branch: clones one sentence (6.0 s of audio), which Whisper transcribes exactly

🤖 Generated with Claude Code

dghosef and others added 6 commits November 3, 2026 20:53
…orch 2.10 builds (L1, R1.6, R1.9)

torch.compile takes recompile_limit only since torch 2.12, so passing it (even None) failed
the FLUX.2 klein, Z-Image and LTX-2.5 builds on torch 2.10, the pyproject floor. Dynamo reads
the limit when a call compiles, so patching its config around each call keeps the
per-forward limit on every supported torch. mstar-project#1145 found this first.

Before torch 2.12 Dynamo's config is process-wide, so the docstring says the limit holds
while the forward runs, not for it alone. A per-call `with` stays: the decorator form shares
one non-reentrant ConfigPatch across calls.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…+ (L2, R1.1)

transformers 5.21 made MimiModel's upsample and decoder_transformer read-only
properties, so qwen-tts 0.1.1's encoder (self.upsample = None) failed to build and
every Base voice-clone load failed on a fresh install (mstar-project#1025). 5.21 also nested the
encoder half (encoder.encoder_seanet / encoder_transformer / downsample) while the
speech-tokenizer checkpoint keeps Mimi's flat names.

The loader already runs qwen-tts' source under a private module, so fix it there
instead of capping transformers for every extra: plain class attributes on the private
encoder class let the None assignments run, and the codec-encoder load maps the flat
checkpoint names onto 5.21's nesting. On a seeded random checkpoint, 5.20.2 and 5.22.1
give bitwise-identical latents and codes through _create_ref_encoder_submodule.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Phone photos are stored sideways with an EXIF Orientation tag; read_image (torchvision and
its Pillow branch), FLUX.2 klein's and LingBot-World's Pillow loaders ignored it, so every
vision model got them rotated. transformers' and diffusers' load_image apply it.

torchvision's WebP decoder ignores EXIF, so read_image sends a static WebP whose header
carries an orientation other than 1 down its Pillow branch. The three Pillow loaders share
open_upright_image, which reads an image with a malformed EXIF block as stored (Pillow
parses EXIF lazily and raises SyntaxError/struct.error there), as main served it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
domain_id indexes the action pathway's nn.Embedding on the GPU; 32 or more device-asserted
the worker, failing every later request. Now a 400.

resolve_action_domain_id takes the table size and holds both bounds, for an id and a name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…, R1.5)

A 1-D or too-narrow 'action' crashed the DiT batch it joined (a 500 for every row in it),
and a missing one conditioned the video on zero actions; the reference pipeline requires
it. Now each is a 400.

action_shape is an INTERNAL_KWARGS key, so a client's own can't stand in for the action.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…, R1.8)

An out-of-range context_mask/target_mask index reached torch.gather on the GPU, a device
assert that poisons the worker, and a lone mask was silently replaced by the full-coverage
defaults together with the other. Both are now a 400, as is a mask that is not one row of indices.

A mask that doesn't parse, or holds non-integer indices, is a 400 too (was a 500, or
silently truncated).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
dghosef and others added 9 commits November 3, 2026 21:25
The encoder truncates the clip to num_frames but never padded a short one, so it encoded
fewer latent frames than the request's latent shape and failed mid-pipeline. Padding would
make up still frames for actions to explain, so it is a 400 naming num_frames instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ing (L41)

The time-embedding buffer is sized to the largest captured batch (4), so an eager
deployment's batch of 5 or more got a 4-row slice and the action step crashed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A side over 512 tokens (8192 px) passes the max_image_area cap when the other side is
short, and indexed past the 512-row RoPE table (a 500).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
width=4 (or a size like 480x8) gave a zero-size latent that failed mid-pipeline; it is
now a 400 at submission. mstar-project#404's strict size parsing is the other half of mstar-project#1054.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e (L25, R1.4)

Requests with one cached context (the same audio twice: a prefix hit) each name its
pages, so a step's index list can outgrow the context pool although the pool is not
full; an assert on the pool size then failed the whole batch (mstar-project#1006: 759 of 768
Whisper requests). The eager wrapper takes any length; a captured one now holds a pool
per row.

The captured size comes from captured_page_capacity, as self-attention's does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… cache (L77)

With stream_first_chunk_tokens=6 the first chunk vocodes 3 tokens (6 mel frames) past
the look-ahead, under the 8-frame vocoder cache, so chunk 2's crossfade read a short tail
and every streamed request failed there. Refused at startup, naming the minimum (7).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
convert_bfl_lora_keys renamed only a block's lora_A/lora_B weights, so its .alpha kept the
BFL module name, matched no adapter and was dropped: those adapters merged at alpha = rank,
the wrong strength. The alpha now follows its module, shared across a fused qkv's q/k/v.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Without input_data_format the HF processor guesses the layout, and an image 1 or 3 px tall
was read as channels first: the wrong grid and pixels for that request.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
load_weights_from_file and load_weights_from_hf_shards opened a cuda:N node's weights on
"cuda", the process's current GPU (0), then moved each tensor: every load staged on
GPU 0. safetensors takes cuda:N itself.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@dghosef
dghosef force-pushed the bugfix/startup-and-bad-inputs branch from df59210 to c22f4f9 Compare November 3, 2026 21:31
dghosef added a commit to dghosef/mstar that referenced this pull request Nov 4, 2026
…m moves, small host floats

From the bug-hunt sweeps of mstar-project#1167, mstar-project#1176, mstar-project#1178 and mstar-project#1179:
- an index out of bounds in an embedding/gather/index_select/index/scatter/
  take over values the emulator keeps raises "device-side assert triggered",
  and, as on CUDA, every later device call fails (Cosmos3 domain_id, V-JEPA 2
  target index served 200);
- CUDA autocast's whole-call casts for composite sdpa, matmul, einsum, linear
  and conv (V-JEPA 2 sdpa, Higgs-Audio conv1d);
- istft's output shape directly (ATen's reads its window envelope on the
  host);
- a weight_norm module moves and loads: a refused parameter swap retries that
  call with assignment (Cosmos3's sound tokenizer);
- small tensors of any dtype that come from host data keep their values on
  the device (Omni's video_second_per_grid read 0);
- torch.compile checks its keywords against the real signature (hid
  recompile_limit on torch 2.10), and compiles for real for a test's own
  callable backend;
- header-only safe_open honours device= (and charges its memory) and takes
  transformers 5.22's backend=; a meta tensor's .to() on the host stays
  value-less in its new dtype;
- checkpoints keep small weight-format files (Chatterbox's conds.pt);
- pytest plugin: --skipped-in <junit.xml> selects exactly what a plain CPU run
  skipped.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
dghosef added a commit to dghosef/mstar that referenced this pull request Nov 4, 2026
…uda generators

From the bug-hunt rounds on mstar-project#1167/mstar-project#1178/mstar-project#1179:
- Small host floats keep their values (a0bfc5a); beside a value-less operand
  in one op they now become value-less too, at the composite call (stft's window,
  weight_norm's g check devices before decomposing) and at the aten op (0-dim
  floats in stack). Integer index operands keep their values for the bounds check.
- memory_allocated / max_memory_allocated / reset_peak_memory_stats / mem_get_info
  / memory_stats count per device.
- torch.cuda.default_generators holds one generator per emulated device, and
  torch.cuda.random's seeding sees the emulated devices: dynamo's RNG save works,
  and manual_seed_all seeds them all (the seeding no-ops are gone).
- --gpu-only also keeps tests that check torch.cuda.is_available() in their body
  or skipif; --skipped-in also keeps the body checks (print-and-return on a CPU).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@dghosef
dghosef marked this pull request as ready for review November 4, 2026 18:27

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant