Files
deepseek-v4-quant/memory/2026-05-11.md
biondizzle 02b8ea536f Update MEMORY.md and memory files with vLLM NVFP4 serving progress
Server running on B200 port 8000 with full NVFP4→vLLM bridge.
All critical bugs fixed: DeepGEMM scale format, compressor shapes, block scale values.
2026-05-11 02:02:49 +00:00

3.4 KiB
Raw Blame History

2026-05-11 — DeepSeek V4 NVFP4 vLLM Serving: Full End-to-End

🎉 SERVER RUNNING ON PORT 8000

The vLLM server successfully loads the NVFP4 model and serves API requests on 8× B200.

What We Fixed (Session Summary)

1. DeepGEMM sf.dim() Assertion (CRITICAL)

  • Error: Assertion error layout.hpp:94: sf.dim() == num_groups + 2
  • Cause: weight_scale_inv was 1D per-tensor scale. DeepGEMM expects 2D/3D block-scale tensor from transform_sf_into_required_layout.
  • Fix: Use deepgemm_post_process_fp8_weight_block(wq, ws, quant_block_shape=(128,128), use_e8m0=True) to produce correct block-scale format. Store result in weight_scale_inv.
  • Key insight: The attention runtime reads self.wo_a.weight_scale_inv as b_scale for the einsum. It MUST be the DeepGEMM-formatted block scale.

2. Block Scale dtype

  • Error: Expected float32 or float8_e8m0fnu, got float8_e4m3fn
  • Fix: Create block scale as dtype=torch.float32

3. Missing deepgemm_post_process args

  • Error: missing 2 required positional arguments: 'quant_block_shape' and 'use_e8m0'
  • Fix: Pass quant_block_shape=(128, 128) and use_e8m0=True

4. Compressor Indexer Shape Mismatch (CRITICAL)

  • Error: split_with_sizes expects 2048, got split_sizes=[256, 256]
  • Cause: _reconstruct_compressor_weight used wrong checkpoint prefix for indexer. Main compressor keys: compressor.kv_proj.*. Indexer keys: compressor.indexer.kv_proj.*. Loading main compressor weight into indexer's fused_wkv_wgate = 4× size mismatch.
  • Fix: Added sub_path parameter, pass ".indexer" for indexer compressors.

5. All-Ones Block Scale → Garbage Output (CRITICAL)

  • Symptom: Server runs, outputs tokens, but text is incoherent gibberish (repeating "Palm", "sulfuric", "东海")
  • Cause: Block scale was torch.ones(...) = 1.0. DeepGEMM divides by block scale at runtime, so output was divided by 1.0 instead of actual fp8_scale.
  • Fix: torch.full(..., fp8_scale.item()) — fill each block with the per-tensor FP8 scale value.

Conversion Summary

  • 61 NVFP4→FP8 (wo_a attention, DeepGEMM block-scale BMM einsum)
  • 0 BF16→FP8
  • 305 attn/shared→BF16 (UnquantizedLinearMethod)
  • 91 compressor→BF16 (reconstructed from separate NVFP4 kv_proj+gate_proj)
  • MoE experts: stay NVFP4 (FLASHINFER_TRTLLM FusedMoE backend)

Architecture Map

wo_a → FP8 + DeepGEMM block scale (weight_scale_inv = dg_ws)
fused_wqa_wkv, wo_b → BF16 (UnquantizedLinearMethod)
compressor.fused_wkv_wgate → BF16 (read from checkpoint, unpack, dequant, cat)
shared_expert → FP8 (Fp8LinearMethod, DeepGEMM)
MoE w13/w2 → NVFP4 (FusedMoE, FLASHINFER_TRTLLM)

Key Code Locations

  • Patch: /root/nvidia-meeting/deepseek-v4-quant/patches/deepseek_v4.py
  • Runtime attention: deepseek_v4_attention.py:319 — reads wo_a.weight_scale_inv
  • Runtime einsum: deepseek_v4_fp8_einsum → DeepGEMM fp8_einsum
  • DeepGEMM scale format: deepgemm_post_process_fp8_weight_block in fp8_utils.py
  • Compressor forward: deepseek_compressor.py:281kv, score = kv_score.split(...)

Outstanding Issues

  • Output quality: Still producing garbled text after block-scale fix. Need to verify the latest fix (fp8_scale in block scale) produces coherent output.
  • Possible causes if still garbled: subtle dequant bug, sign handling in E2M1 unpack, wrong scale ordering