recipe.toml 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. # GLM-5.3 (FULL, non-Flash) MXFP4 — RedHatAI official quant — 4× DGX Spark, TP=4.
  2. #
  3. # REPLACES the failed full-model variant: `local-inference-lab/GLM-5.3-NVFP4-Spark`
  4. # (406 GiB → 101.5 GiB weights/node → OOM-proven on 4 nodes 2026-09-08/09: the
  5. # engine crash-restarted and began a SECOND full load while the first copy was
  6. # still resident → 2×101.5 > 121.63 GiB → all four nodes OOM-thrashed, sshd down
  7. # on 3 of 4, HA power-cycle required). That checkpoint is abandoned (recipes
  8. # glm53-full-nvfp4-spark-lab / -aiden / glm53-spark-nvfp4-4x deleted).
  9. #
  10. # THIS checkpoint: RedHatAI/GLM-5.3-MXFP4 — 403.4 GB (375.6 GiB) → 100.85 GB
  11. # (93.9 GiB) weights/node on 4x. ~7.6 GiB/node more headroom than the NVFP4
  12. # attempt, which is what makes 4x plausible at all. LLM-Compressor
  13. # (compressed-tensors) quant: "mxfp4-pack-quantized", weights FP4-e2m1 group-32
  14. # with E8M0 scales, dynamic per-group FP4 activations; mlp.gate / lm_head /
  15. # embed_tokens / eh_proj / indexer.{wk,weights_proj} stay bf16.
  16. # Model: https://huggingface.co/RedHatAI/GLM-5.3-MXFP4
  17. # Parent: zai-org/GLM-5.3 (FP8). Card: gsm8k 96.36 vs 97.60 (FP8) = 98.7%
  18. # recovery; ifeval 89.25 vs 93.53 = 95.4%.
  19. # Card's serving recipe (4× B200): --kv-cache-dtype fp8_e4m3 --tp 4
  20. # --reasoning-parser glm45 --speculative-config '{"method":"mtp","num_speculative_tokens":5}'
  21. #
  22. # GEOMETRY (config.json, verified 2026-09-13): arch GlmMoeDsaForCausalLM
  23. # (model_type glm_moe_dsa), 78 layers, hidden 6144, 256 routed experts + 1
  24. # shared, top-8, moe_inter 2048, MLA (kv_lora 512 / q_lora 2048 / qk_nope 192 /
  25. # qk_rope 64 / v 256), DSA lightning indexer (index_topk 2048), 1M native ctx,
  26. # first_k_dense_replace 3, num_nextn_predict_layers 1 (MTP head IN the
  27. # checkpoint), 141 shards, no separate drafter.
  28. # ~740B total params / ~40B active. The Flash variant we serve in prod is
  29. # 320B/18B (45 layers, hidden 4096, 288 experts) — this is a different model.
  30. #
  31. # ── BASE STACK: our own jovian r35 build (docker-images/glm53-jovian-r27 +
  32. # build_profile glm53-r35 → image glm53-jovian-r35:local) ────────────────
  33. # Selected 2026-09-13. Evidence (all verified by read-only inspection of the
  34. # images on dgx1):
  35. # * registers the full-model arch: registry.py →
  36. # "GlmMoeDsaForCausalLM": ("vllm.models.deepseek_v32", ...) — the NEW
  37. # `deepseek_v32` implementation, which is "MLA + a lightning indexer that
  38. # selects the top-k tokens for a sparse MLA" and dispatches to an
  39. # NVIDIA-specific path (deepseek_v32/nvidia/model.py:
  40. # DeepseekV32ForCausalLM as GlmMoeDsaForCausalLM). That is exactly the
  41. # GB10/sm_121a target; the lab fork and aiden's image register the same
  42. # class from the older `deepseek_v2` module instead.
  43. # * ships the MXFP4 scheme: model_executor/layers/quantization/
  44. # compressed_tensors/schemes/compressed_tensors_w4a4_mxfp4.py
  45. # ("mxfp4-pack-quantized") → the RedHat checkpoint loads natively.
  46. # * it is OUR reproducible clone-at-pin build (vLLM de982a50 + b12x 98086604,
  47. # r35 lock 2026-09-11 = newest published lab composition), all gates green,
  48. # patches ours to write — and it is the SAME image our GLM-5.3-Flash 4x
  49. # prod runs, so the A/B vs prod is clean and the JIT caches are warm.
  50. # * the b12x MoE/attention backends are the GB10-tuned ones our GLM prod
  51. # uses (--moe-backend b12x / --attention-backend B12X).
  52. # Rejected: `glm53-flash-nvfp4-lab:local` and aiden's
  53. # `aidendle94/sparkrun-vllm-glm53-gb10:production-1.2` — both older vLLM
  54. # (0.1.dev20051+g487ecf187, `deepseek_v2` GLM class); the lab fork needed two
  55. # SM120 mla_attention hotfix mods to boot the full model at all
  56. # (masked_mha_available AttributeError + forward_mha NotImplementedError, both
  57. # never re-tested — the lane parked). Keep them as a fallback reference only:
  58. # if the r35 deepseek_v32 path trips on the DSA/indexer kernels, port those
  59. # two sed mods (documented in the deleted glm53-full-nvfp4-spark-lab history)
  60. # onto the lab image and re-point docker_image/docker_image_dir.
  61. #
  62. # ── MEMORY PLAN (the binding constraint — read before the first boot) ──────
  63. # 121.63 GiB unified/node. Idle free: 116-117 GiB.
  64. # weights 93.9 GiB (403.4 GB / 4) ← ~101.5 was fatal
  65. # vLLM procs+docker ~12 GiB
  66. # KV pin 8 GiB (--kv-cache-memory-bytes)
  67. # activations + CUDA graphs ~4 GiB
  68. # ⇒ ~118 GiB — tight but inside the node. GMU 0.85 is the ADMISSION
  69. # guardrail only (free ≥ 0.85×121.63 = 103.4 GiB; 0.88 = 107.0 GiB fails
  70. # once the ~12 GiB of starting processes are counted, the 2026-09-08
  71. # #48140 class) — the KV pool is pinned, so GMU does not change capacity.
  72. #
  73. # WHY DCP4: the full model's attention KV is NOT the Flash lane's compact
  74. # MLA cache. The parked run measured ~54 KB/token (4 GiB ↔ ~79.6K tokens;
  75. # "524288 would need 26.34 GiB") vs the Flash lane's ~2 KB/token at 512K.
  76. # Decode-context-parallel-4 shards the KV across the 4 ranks, so the 8 GiB
  77. # pin buys 32 GiB aggregate → a single 524288-token request needs ~27 GiB
  78. # aggregate (≈6.8 GiB/rank) and just fits. Without DCP a 512K request is
  79. # impossible behind these weights. CAVEAT: DCP4 is qualified in r35 for the
  80. # Flash model (CP1/CP4 shapes); it is UNVERIFIED for the full model — if the
  81. # boot rejects it (the GLM C4 page-stride / interleave-multiple-of-4 gates
  82. # that block DFlash2 on 2x), drop --decode-context-parallel-size +
  83. # --cp-kv-cache-interleave-size and lower --max-model-len to fit ~10 GiB of
  84. # aggregate KV (~180K tokens).
  85. #
  86. # --max-model-len 524288 = the operator's floor (128K/131K profiles are not
  87. # usable for us). --max-num-seqs 8 keeps the pool from being shredded by
  88. # short requests; the admission scheduler handles the rest.
  89. #
  90. # ── BOOT PLAN / HAZARD ─────────────────────────────────────────────────────
  91. # The 2026-09-08 disaster was NOT a bad weight footprint per se — it was a
  92. # post-load crash + auto-restart that started a SECOND full load on top of
  93. # the first. Watch the first boot: if the engine logs a second
  94. # "Loading safetensors" pass, kill immediately (`sm121 stop`), do not wait.
  95. # Always `sm121 serve --keep` for the first/unknown boot (default is --rm,
  96. # which wipes the crash logs).
  97. # Ladder if the boot dies: (1) disable DCP4, max-model-len 131072, KV pin
  98. # 4 GiB (prove stack+checkpoint end-to-end, the parked lane's approach);
  99. # (2) then re-add DCP4 + 512K; (3) only then add spec.
  100. # Boot markers to record: "Model loading took X GiB", the KV line
  101. # ("GPU KV cache size: N tokens, Maximum concurrency for 524288 tokens per
  102. # request: Mx"), "Application startup complete". MAX_JOBS=2 below is the
  103. # compile-OOM guard (12 parallel nvcc jobs × ~3 GiB behind 94 GiB of weights
  104. # = cicc OOM-killed, 2026-09-04 lesson).
  105. #
  106. # ── SPECULATIVE DECODING ───────────────────────────────────────────────────
  107. # NOT enabled on the first boot: the checkpoint's MTP head is real
  108. # (num_nextn_predict_layers=1) and the card suggests mtp k=5, but spec adds
  109. # draft KV + graph shapes onto a memory budget that has no room for
  110. # surprises, and the full-model MTP path is unproven on this stack. After a
  111. # clean boot + smoke + bench, add:
  112. # "--speculative-config", """'{"method":"mtp","num_speculative_tokens":3,"attention_backend":"B12X"}'"""
  113. # (k=3 = our Flash prod's verified depth; try 5 after k=3 is clean).
  114. #
  115. # PREREQUISITE: weights in the shared NAS HF cache on all 4 nodes
  116. # (models--RedHatAI--GLM-5.3-MXFP4, 403.4 GB, 141 shards) —
  117. # `hf download RedHatAI/GLM-5.3-MXFP4`; HF_HUB_OFFLINE=1 below makes a
  118. # missing shard a hard load failure. NAS had 16 TB free at 2026-09-13.
  119. #
  120. # A/B TARGET: our GLM-5.3-Flash r35 MTP3 4x prod (dev65/seed 42, hardmode):
  121. # 163/176 (93), 1,554 pp / 49.6 tg / 1,544 ms TTFT @d0 c1, KV 8.06M @512K.
  122. # This lane is a capability/quality lane first (does the full model fit and
  123. # hold 512K on 4 nodes), throughput second.
  124. engine = "vllm"
  125. name = "GLM-5.3 (full) MXFP4 (r35 img, RedHatAI ckpt, 4x DCP4)"
  126. docker_image = "glm53-jovian-r35:local"
  127. docker_image_dir = "glm53-jovian-r27"
  128. # NOTE: build_profile must stay a TOP-LEVEL key — a bare key after
  129. # [[extra_mounts]] would parse into the last mount table and be silently
  130. # ignored (2026-09-08).
  131. build_profile = "glm53-r35"
  132. entrypoint = ["vllm", "serve"]
  133. model = "RedHatAI/GLM-5.3-MXFP4"
  134. parent_model = "zai-org/GLM-5.3"
  135. required_nodes = 4
  136. tensor_parallel_size = 4
  137. pipeline_parallel_size = 1
  138. distributed_backend = "mp"
  139. shm_size = "32gb"
  140. args = [
  141. # R31/r35 delta (their qualified locks): adaptive prefill/decode
  142. # compute-time sharing with a fixed 40% prefill floor.
  143. "--prefill-compute-share", "0.4",
  144. # Stable served name — quant-agnostic (shared across glm53 lanes)
  145. "--served-model-name", "glm53",
  146. "--trust-remote-code",
  147. "--distributed-executor-backend", "mp",
  148. # Admission guardrail only (KV is pinned below): 0.85×121.63 = 103.4 GiB.
  149. # 0.88 (107.0) is the Flash lane's value and is too tight here — the full
  150. # model's weights leave ~24 GiB before the engine's own ~12 GiB.
  151. "--gpu-memory-utilization", "0.85",
  152. # 8 GiB/rank. With DCP4 that is 32 GiB aggregate ≈ one 524288-token request
  153. # (+headroom). See the memory plan above before changing either number.
  154. "--kv-cache-memory-bytes", "8589934592",
  155. # DCP4 — required to make 512K fit (KV sharded across the 4 TP ranks).
  156. # Unverified for the full model; first fallback is to drop both lines.
  157. "--decode-context-parallel-size", "4",
  158. "--cp-kv-cache-interleave-size", "4",
  159. # No --kv-cache-dtype: let the r35 fork pick its native default for
  160. # GlmMoeDsa attention (the Flash lane's explicit fp8/fp8_ds_mla spellings
  161. # both failed auto-selection on this build, and those were Flash-MLA
  162. # knobs). The card's --kv-cache-dtype fp8_e4m3 is the fallback spelling
  163. # if the pool needs to shrink.
  164. "--attention-backend", "B12X",
  165. # pure I/O loader (kept across every GLM config)
  166. "--load-format", "instanttensor",
  167. "--block-size", "256",
  168. "--max-model-len", "524288",
  169. "--max-num-seqs", "8",
  170. "--max-num-batched-tokens", "4096",
  171. "--enable-chunked-prefill",
  172. "--async-scheduling",
  173. "--enable-prefix-caching",
  174. # Their proven boot: no flashinfer autotune, no CuTe-DSL warmup (the
  175. # autotune scratch at 512K shapes does not fit the headroom, 2026-08-28).
  176. "--kernel-config", """
  177. '{"enable_cutedsl_warmup":false,"enable_flashinfer_autotune":false}'""",
  178. "--language-model-only",
  179. # NO --speculative-config on the first boot — see the header. MTP head is
  180. # in the checkpoint (num_nextn_predict_layers=1); add mtp k=3 after a
  181. # clean boot + bench.
  182. "--tool-call-parser", "glm47",
  183. "--enable-auto-tool-choice",
  184. "--reasoning-parser", "glm45",
  185. ]
  186. [env]
  187. # R31 lock: 16 NCCL channels (their qualified runtime).
  188. NCCL_NCHANNELS = "16"
  189. HF_HUB_OFFLINE = "1"
  190. # RoCEnante (b12x one-shot RoCE all-reduce/all-gather) — default on for r27+
  191. # lanes since the 2026-09-08 A/B (4x DCP4: decode +31..+90%, quality 160 vs
  192. # 155; specs/tech-architecture/glm53-recipe-state.md). Needs the CX-7 RoCE
  193. # fabric (all of ours); single-node serves skip it silently.
  194. VLLM_ENABLE_ROCE_ALLREDUCE = "1"
  195. # Compile-OOM guard: first boot JIT-compiles the mxfp8 gemm module with 12
  196. # parallel nvcc jobs (~3 GiB each) behind ~94 GiB of resident weights →
  197. # cicc OOM-killed (2026-09-04). flashinfer's run_ninja reads MAX_JOBS.
  198. MAX_JOBS = "2"
  199. # NoPE-MLA rope-pad runtime gate (mod baked into the image)
  200. VLLM_MLA_NOPE_PAD_ROPE = "1"
  201. VLLM_ENGINE_READY_TIMEOUT_S = "3600"
  202. # Upstream launch-script env (memory + compile knobs)
  203. PYTORCH_CUDA_ALLOC_CONF = "expandable_segments:True"
  204. VLLM_USE_AOT_COMPILE = "0"
  205. VLLM_USE_STANDALONE_COMPILE = "1"
  206. VLLM_USE_FLASHINFER_SAMPLER = "1"
  207. VLLM_USE_BREAKABLE_CUDAGRAPH = "0"
  208. TORCH_USE_RTLD_GLOBAL = "1"
  209. VLLM_NO_USAGE_STATS = "1"
  210. # Architecture (aarch64 / sm_121a DGX Spark)
  211. TORCH_CUDA_ARCH_LIST = "12.1a"
  212. FLASHINFER_CUDA_ARCH_LIST = "12.1f"
  213. CUTE_DSL_ARCH = "sm_121a"
  214. CMAKE_CUDA_ARCHITECTURES = "121"
  215. OMP_NUM_THREADS = "2"
  216. [[extra_mounts]]
  217. host = "~/sm121-cache/glm53-jit-121f/b12x"
  218. container = "/root/.cache/b12x"
  219. # JIT caches persist per-node across serves (was: cold /root/.cache per
  220. # container -> ~20 min flashinfer/torch recompile every serve). The host
  221. # dirs are shared between lanes of the same arch — each cache
  222. # self-namespaces by its engine version key internally.
  223. [[extra_mounts]]
  224. host = "~/sm121-cache/jit-121f/flashinfer"
  225. container = "/root/.cache/flashinfer"
  226. [[extra_mounts]]
  227. host = "~/sm121-cache/jit-121f/torchinductor"
  228. container = "/root/.cache/torchinductor"
  229. [[extra_mounts]]
  230. host = "~/sm121-cache/jit-121f/vllm"
  231. container = "/root/.cache/vllm"