Commit Graph

163 Commits

Author SHA1 Message Date
04999d86cf fix: add quantize_to_nvfp4 import 2026-05-17 08:24:57 +00:00
7073daaffa fix: allocate token_indices on CPU, move to GPU AFTER JIT compilation
CuTeDSL's cute.compile corrupts GPU memory during JIT compilation.
Tensors allocated on GPU before/during compilation get zeroed.
Fix: create token_indices on CPU, then .to(device) after JIT is done.
2026-05-17 08:22:51 +00:00
0e7b06b55c debug: clone + sync token indices before JIT 2026-05-17 08:22:11 +00:00
70c0618361 fix: allocate token_indices before CuTeDSL JIT compilation
CuTeDSL's cute.compile appears to corrupt GPU memory state,
causing torch.arange to produce zero-filled tensors when allocated
after the JIT compilation. Moving token_indices allocation before
the weight stacking operations fixes the corruption.
2026-05-17 08:20:41 +00:00
2bbe04efd8 debug: remove assert, test token corruption 2026-05-17 08:19:45 +00:00
66627926c5 debug: int32 token indices with sync verify 2026-05-17 08:18:37 +00:00
da02a5dc11 debug: assert token indices are correct after allocation 2026-05-17 08:16:09 +00:00
c0d016a472 feat: compute_activation_global_scales warmup method
Uses quantize_to_nvfp4 during warmup to get exact gs values for L1 and L2.
L1 gs comes from slot_hidden, L2 gs from the actual L1 GEMM output.
These values are then used with quantize_activation_nvfp4 (cudagraph-safe)
during inference.
2026-05-17 08:11:01 +00:00
ae6b879d38 fix: pass expert_offsets without leading 0 to GEMM (matches pipeline) 2026-05-17 07:59:00 +00:00
a1e6f5f891 fix: searchsorted right=True for correct expert assignment 2026-05-17 07:57:00 +00:00
ed90341ea9 fix: scatter+per-expert-swizzle scale assembly (cudagraph-safe) 2026-05-17 07:47:14 +00:00
37fecb588f fix: separate L1/L2 scale buffers (different K_sf), fix assembly calls 2026-05-17 07:43:05 +00:00
b824b838a9 fix: 128-row-align each expert's scales in padded buffer 2026-05-17 07:39:49 +00:00
8642946274 fix: padded x_sf buffer for fixed-shape scale assembly 2026-05-17 07:37:04 +00:00
418e29f7f5 fix: per-expert scale assembly (match assemble_scales_2d_side) 2026-05-17 07:35:49 +00:00
48e4cb625d fix: default activation global_scale so runner works without finalize_weights 2026-05-17 06:24:15 +00:00
d2965b432d fix: set _l1_activation_global_scale (with underscore) — attribute name mismatch 2026-05-17 03:35:20 +00:00
b382a7a528 fix: handle input_scale as 1D or 2D (EP splits change the shape) 2026-05-16 22:49:30 +00:00
139c9c37cd fix: read input_scale from nn.Parameter before it's freed 2026-05-16 22:23:24 +00:00
152648789d fix: use checkpoint input_scale for activation global scale (not hardcoded 1/2688)
The checkpoint stores input_scale per projection — the pre-computed
activation normalization factor. Using 1/2688 was wrong for most layers
(e.g. down_proj input_scale=0.031 vs 1/2688=0.000372 — 83x off).
This caused under-quantized activations and garbage output.
2026-05-16 21:46:00 +00:00
103fd451ce fix: use full padded_scales_buf (no GPU scalar slicing in cudagraph)
buf[:gpu_scalar, :] triggers cudaErrorStreamCaptureInvalidated.
Always use the full pre-allocated buffer; extra rows are zeros.
2026-05-16 18:50:35 +00:00
53c25bee0b rewrite: cudagraph-safe runner - no dynamic slicing, no GPU scalar indices
- Removed all [:total_slots] dynamic slicing with GPU scalars
- slot_hidden gathers from hidden_states directly using sorted_token_ids
- scatter_add uses full sorted_token_ids (padding slots have zero weight)
- _assemble_scales_cudagraph_safe returns 2D via padded_scales.shape[0]
- Fixed padded_scales_buf allocation via float16->float8 cast
- GEMM output size: n_dim * 2 for float4_e2m1fn_x2 packed format
2026-05-16 18:44:25 +00:00
4300775bfe fix: remove .item() sync in scale reshape — use padded_scales.shape[0] instead 2026-05-16 18:29:12 +00:00
95a1345b92 fix: return 2D scale tensor from _assemble_scales_cudagraph_safe 2026-05-16 18:26:57 +00:00
533089c9d2 fix: token_indices slice bug + torch.zeros for float4/float8 dtypes 2026-05-16 18:21:27 +00:00
5121074782 cudagraph-safe CuTeDSL MoE: searchsorted-based scale assembly
Key changes for cudagraph compatibility:
- No .item() or .tolist() calls (zero CPU-GPU syncs)
- Pre-allocated buffers at max_num_tokens size
- GPU-only expert offsets via bincount+cumsum
- searchsorted to map rows to experts (no Python for-loop with GPU indices)
- Single scatter operation for scale padding
- Pre-allocated token_indices reused for searchsorted row mapping
- quantize_activation_nvfp4 with fixed global scale (no .max() sync)
- Cached CuTeDSL kernel (no cute.compile per forward)
- No torch.cuda.synchronize() in forward path
2026-05-16 18:01:47 +00:00
ab126b0c0d fix: revert to .item() based scale assembly (fixes index OOB)
The fully GPU-vectorized _assemble_scales_gpu() caused index out of
bounds errors because tensor slicing with GPU-computed indices from
Python is undefined behavior.

Went back to .item() on expert_offsets for the per-expert scale split.
This forces CPU-GPU syncs (breaks cudagraph) but produces correct results.

The path to cudagraph compatibility is either:
1. Modify CuTeDSL scale assembly API to accept flat tensor + offsets
2. Use the CUTLASS kernel (already verified working)
2026-05-16 17:55:32 +00:00
7594968482 WIP: cudagraph-compatible CuTeDSL MoE runner
- Cache compiled CuTeDSL kernel (compile once, reuse every forward)
- Remove torch.cuda.synchronize() from forward path
- Add quantize_activation_nvfp4() (no .max() CPU-GPU sync)
- Pre-allocate buffers (token_indices, expert_id_range, output_bufs)
- GPU-only expert offset computation (bincount + cumsum)
- Replace Python for-loop scale assembly with GPU-vectorized version

Still TODO:
- Test with FULL_AND_PIECEWISE cudagraph mode
- Add vllm::deepseek_v4_mega_moe_experts to splitting_ops
- Verify CuTeDSL kernel launch is cudagraph-safe
2026-05-16 16:36:19 +00:00
f0c1be3ced fix: remove broken hc_head warmup (wrong tensor shape)
hc_head_fuse_tilelang expects fn shape[0]=hc_mult (4) but we passed
hc_mult*(2+hc_mult) (24). Since --enforce-eager disables @torch.compile
anyway, hc_head runs eagerly and doesn't need warmup.
2026-05-16 10:11:34 +00:00
c803180706 fix: handle freed weight lists in _check_runtime_supported and _run_mega_moe
After _ensure_stacked frees per-expert lists, code that accesses
l1_fp4 or w13_weight.device crashes with NoneType errors. Fix:
- _check_runtime_supported: fall back to _l1_mat_b.device
- _run_mega_moe assertion: check _l1_mat_b as alternative
- finalize_weights guard: check _l1_mat_b as alternative
2026-05-16 09:16:24 +00:00
cdd813cf7e fix: free per-expert weight lists after stacking in CuTeDSL runner
_ensure_stacked() creates stacked copies of all weights but never freed
the per-expert lists. For 256 experts on a 175GB model, this doubles
weight memory to ~350GB, causing OOM.

Now the per-expert lists (l1_fp4, l1_sf, l1_gs, l2_fp4, l2_sf, l2_gs)
are set to None after stacking, keeping only the single stacked copy.
2026-05-16 08:54:52 +00:00
906ee80a42 Add tilelang kernel warmup in load_weights
Force-compile all lazy tilelang JIT kernels (mhc_pre, mhc_post)
and torch.compile'd hc_head during model loading, BEFORE the HTTP
server comes up. This eliminates the crash when eager mode inference
hits the model before tilelang compilation finishes.

Fixes the core issue: cudagraph capture forced eager compilation but
ate all GPU memory. Now we can run eager mode safely.
2026-05-16 08:28:39 +00:00
a2cac7a7fe fix: remove CuTeDSL warmup — OOM with 175GB model loaded
The warmup allocated 1GB of dummy tensors but the model already
uses 175.7GB of the 178.35GB per GPU. No room.

With FULL_AND_PIEWISE CUDA graph mode, the kernel compiles during
the graph capture phase (which manages memory properly). The warmup
was a band-aid for eager mode and is now redundant.
2026-05-16 07:32:17 +00:00
e0814eb54e fix: cast expert_offsets to int32 for CuTeDSL kernel
CuTeDSL's grouped GEMM uses int32 for expert offsets internally.
Our cumsum produced int64, causing a type mismatch inside a dynamic
if-branch (prev_off changes from Int32 to Int64).

Also cast tokens_per_expert to int32 before cumsum.
2026-05-16 07:15:57 +00:00
4b0a9557f0 fix: rewrite CuTeDSLMoERunner for CUDA graph compatibility
CUDA graphs forbid CPU-GPU syncs (.item()) and Python loops over
tokens during graph capture. The old scatter loop did both.

Changes:
- Slot routing: replaced Python loop with GPU-native argsort + gather
  (sort tokens by expert id, gather hidden states in slot order)
- Scatter: replaced Python loop with torch.scatter_add_ (GPU-native)
- Weight stacking: lazily pre-built once, reused every forward call
- Removed all .item() calls from the forward path
- expert_offsets built from GPU tensor operations

This is required for FULL_AND_PIECEWISE CUDA graph mode which
compiles and captures graphs during startup.
2026-05-16 07:03:08 +00:00
dab31b0961 fix: missing tqdm import in weight_loader 2026-05-16 06:31:14 +00:00
8496ac99bc dang clonkurs 2026-05-16 06:28:16 +00:00
5d975d00d9 feat: tqdm progress bar for expert weight loading
Replaces heartbeat prints with a clean tqdm bar:
  Loading Native NVFP4 Expert Weights: 50%|██████████░░| 480/960
2026-05-16 06:09:22 +00:00
a569612df5 feat: add load progress heartbeats to prevent k8s health check kills
The 5-minute gap after safetensors load is GPU weight upload — no
output, k8s marks the pod unhealthy. Now prints a heartbeat every
256 weight loads during the expert loading phase.

Also adds checkpoint-ready and model-ready prints around finalize:
  Checkpoint loaded. Transferring weights to GPU & preparing NVFP4...
  (JIT compile)NVFP4 MoE layers: 50%|██████████░░░░░░░░░░| 31/61
  NVFP4 model ready ✓
2026-05-16 05:51:35 +00:00
3445bd24c1 feat: keep attention weights native NVFP4 — stop dequantizing to BF16
_convert_nvfp4_post_load() was converting wq_b, wo_b, fused_wqa_wkv
from NVFP4→BF16. These layers already have FlashInferCutlassNvFp4LinearKernel
registered as their quant_method — they CAN run native NVFP4.

Now only wo_a gets FP8 conversion (fp8_einsum requires FP8) and
compressor gets BF16 reconstruction (weight_loader issue).
Everything else stays NVFP4 native — Blackwell FP4 acceleration
for the full model, not just the MoE experts.

This also eliminates the 5-minute NVFP4→BF16 conversion loop.
2026-05-16 05:36:34 +00:00
4d4cfa6b28 fix: tqdm over MoE layer warmup, compile every layer, no print spam
The outer loop tqdm now covers the full finalize_weights + warmup for
each MoE layer. CuTeDSL caches by (M,N,K) so every layer shape gets
compiled during warmup — no RPC timeouts during inference.

  (JIT compile)NVFP4 MoE layers:  50%|██████████░░░░░░░░░░| 31/61
2026-05-16 05:21:11 +00:00
3838561c19 fix: only suppress compile message, still warmup all layers
CuTeDSL caches kernels by (M, N, K) shape. Different layer shapes
(L1 vs L2, different expert counts) trigger new compiles. We can't
skip the warmup call — only suppress the print spam.

Flag now gates the message, not the warmup.
2026-05-16 05:18:10 +00:00
f19932d8db fix: compile CuTeDSL kernel once per process, not per MoE layer
The warmup was running for every MoE layer (61 layers × 8 ranks = 488
compile attempts). The kernel is cached after the first compile —
subsequent calls are instant. But the print spam was insane.

Now uses a class-level flag to compile exactly once per process.
All 61 layers on a rank share the same compiled kernel.
2026-05-16 05:16:53 +00:00
936982c5aa fix: add layer-level tqdm for expert finalization, remove inner expert tqdm
Progress now shows per-layer instead of per-expert — cleaner and
covers the full finalize_mega_moe_weights loop (61 layers) which was
the silent 5-minute gap after checkpoint loading.

  (view-cast)uint8→NVFP4 experts:  80%|████████████████░░░░| 49/61
  (upcast)NVFP4→FP8/BF16 convert:  30%|██████░░░░░░░░░░░░░░| 20/61
2026-05-16 05:01:20 +00:00
cf0731cf4b fix: warmup with 128 tokens (fills MMA tile), better error handling
The CuTeDSL kernel uses MMA tiler (128,128,256). With only 1 token,
the kernel can't fill a tile and may access illegal memory. Using 128
tokens for the warmup.

Also improved error message — after CUDA illegal memory access, the
context is corrupted and can't recover.
2026-05-16 04:56:45 +00:00
a70d2d3984 fix: clearer warmup message — 'Compiling CuTeDSL NVFP4 MegaMoE kernel' 2026-05-16 04:40:31 +00:00
f191af7e29 feat: warm up CuTeDSL kernel during model loading
JIT compiles the MLIR→PTX during finalize_weights instead of on the
first inference request. Prevents vLLM's 5-min RPC timeout from
killing the engine while workers are busy compiling.

Warmup runs a single-token, single-expert forward pass — just enough
to trigger compilation. Takes ~1-2 min, same as layertest.
2026-05-16 04:39:05 +00:00
4d67b570b9 fix: descriptive tqdm labels — uint8→NVFP4 and NVFP4→FP8/BF16
Makes it crystal clear what's happening:
- Experts: direct uint8→float4 view-cast (Blackwell native, no BF16)
- Convert: NVFP4→FP8/BF16 for attention weights (non-expert path)
2026-05-16 04:28:25 +00:00
8efdd165da fix: use tqdm for progress bars — single line, live updating
Replaces manual bar printing with tqdm. Overwrites the same line
instead of spewing one line per update.
2026-05-16 04:26:43 +00:00
00b766af60 feat: add progress bars for expert quantization and post-load conversion
Visual feedback during the slow parts of model loading:
  NVFP4 experts [████████████████░░░░]  80% (26/32)
  NVFP4 convert [██████░░░░░░░░░░░░░░]  30% (20/61)

Updates every 10% so it's not spammy.
2026-05-16 04:14:07 +00:00