recipe.toml 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. # DeepSeek-V4.1-Flash (552B MoE, MXFP4 experts, Engram-on-disk, DCP2) — 4x
  2. # DGX Spark.
  3. #
  4. # DCP2 variant of dsv41-flash-4x-b12x (the 167/176 lane): same config plus
  5. # decode context parallelism (4 TP ranks = 2 DCP groups of 2) with Aiden's
  6. # a2a all-to-all combine — the production-1.1 overlay ported onto our tree
  7. # (docker-images/dsv41-flash-dcp2/, 23-file superset; provenance + triage in
  8. # top-level dcp2/README.md).
  9. #
  10. # A/B target: DSV4.1 quality/speed at DCP2's KV capacity. On Aiden's own
  11. # stack DCP2 gave 2.5M-token KV @300K but 158/176 (−9) and slower single-
  12. # stream; this variant measures the same trade on our stack.
  13. #
  14. # Image: dsv41-flash-dcp2:local (docker-images/dsv41-flash-dcp2/ — thin
  15. # FROM over dsv41-flash-b12x:local, 23-file DCP2 overlay COPY, verified
  16. # symbol-complete at build time).
  17. #
  18. # Model: deepseek-ai/DeepSeek-V4.1-Flash (476 GB on the NFS HF cache,
  19. # refs/main). The two 203 GB FP8 Engram n-gram tables are NEVER loaded into
  20. # HBM — the baked engram.py patch keeps them on disk (DSV41_ENGRAM_DISK=1)
  21. # and reads rows on demand. Node-local sparse copies of each rank's rows
  22. # (48 GB, engram-local.json) accelerate decode once created (DSV41_ENGRAM_DIR
  23. # below, added after the copies exist — first boot reads straight from NFS).
  24. #
  25. # Config mirrors their boot-10 serving setup (launch/dsv41-tp4.sh) with
  26. # local deviations:
  27. # CUDA graphs FULL_AND_PIECEWISE + exact DSpark capture sizes (no padded
  28. # rows — padded speculative batches hang SM120 sparse MLA, FlashInfer
  29. # #5015), DSpark k=5 with the checkpoint's own draft layers, tools +
  30. # vision on.
  31. # * GMU 0.85 (their 0.80): the indexer prefill buffer grows with max
  32. # context (~5.2 GiB at 1M, ~2.6 GiB at 512K); the extra budget keeps
  33. # the KV pool at ~11 GiB (≈1.6M tokens) with host headroom.
  34. # * 512K ctx (2026-09-11, operator): matches the GLM prod convention
  35. # (524288) and stays inside the row width their top-k fix was
  36. # validated for (300K measured, 1M-wide never re-run even by them).
  37. # The 1.6M-token pool gives 3× headroom at 512K.
  38. # * thinking ON + reasoning_effort=max by default (request can override
  39. # via chat_template_kwargs), served as "deepseek-v4-flash" (gateway
  40. # alias, no config churn).
  41. #
  42. # Reference: Aiden's write-up of the same stack + their deltas (B12X MoE
  43. # backend, explicit KV budget, DCP2 port) —
  44. # https://aidenle.com/recipes/deepseek-v4-1-flash-4x-dgx-spark/
  45. # (page says production-1.1 in places; the DCP2-baked image is
  46. # production-1.2 — the page was not updated to the end).
  47. engine = "vllm"
  48. name = "DeepSeek-V4.1-Flash MXFP4 (dsv41 img, 4x, DSpark k=5, Engram-on-disk, DCP2 a2a)"
  49. docker_image = "dsv41-flash-dcp2:local"
  50. docker_image_dir = "dsv41-flash-dcp2"
  51. model = "deepseek-ai/DeepSeek-V4.1-Flash"
  52. required_nodes = 4
  53. tensor_parallel_size = 4
  54. pipeline_parallel_size = 1
  55. distributed_backend = "mp"
  56. shm_size = "32gb"
  57. # NO recipe entrypoint: the base image bakes ENTRYPOINT ["vllm","serve"]
  58. # (vllm/vllm-openai), so the launcher's CMD (model + flags) completes it.
  59. args = [
  60. # Stable gateway alias — clients/gateways keep the DeepSeek-V4-Flash
  61. # model name; no per-deployment config churn.
  62. "--served-model-name", "deepseek-v4-flash",
  63. "--trust-remote-code",
  64. "--distributed-executor-backend", "mp",
  65. "--gpu-memory-utilization", "0.85",
  66. "--max-model-len", "524288",
  67. "--max-num-seqs", "8",
  68. "--max-num-batched-tokens", "8192",
  69. # boot-4 fix: the V4 indexer backend refuses the smallest-listed block
  70. "--block-size", "128",
  71. # boot-10: exact capture sizes for DSpark k=5, SEQS=8 (multiples of 5
  72. # and 6 up to 48 — every decode batch gets an exact FULL graph, no padding)
  73. "--compilation-config", """
  74. '{"cudagraph_mode":"FULL_AND_PIECEWISE","cudagraph_capture_sizes":[5,6,10,12,15,18,20,24,25,30,35,36,40,42,48]}'""",
  75. "--speculative-config", """
  76. '{"method":"dspark","num_speculative_tokens":5,"draft_sample_method":"probabilistic","rejection_sample_method":"block","enable_adaptive_verification":false}'""",
  77. "--moe-backend", "b12x",
  78. # DCP2: sharded KV across DCP groups (2 ranks each), the new
  79. # all-to-all + LSE combine path (Aiden production-1.1's runtime config).
  80. "--decode-context-parallel-size", "2",
  81. "--dcp-comm-backend", "a2a",
  82. "--tool-call-parser", "deepseek_v41",
  83. "--enable-auto-tool-choice",
  84. "--reasoning-parser", "deepseek_v41",
  85. "--default-chat-template-kwargs", """
  86. '{"thinking": true, "reasoning_effort": "max"}'""",
  87. ]
  88. [env]
  89. HF_HUB_OFFLINE = "1"
  90. # Engram tables stay on disk (the baked engram.py patch); 32 parallel row
  91. # reads, 16 MB chunks (their launch defaults)
  92. DSV41_ENGRAM_DISK = "1"
  93. DSV41_ENGRAM_DISK_THREADS = "32"
  94. DSV41_ENGRAM_DISK_CHUNK = "16"
  95. # Node-local sparse Engram copy (per-rank row ranges from the first boot's
  96. # "Engram DISK mode" log lines; built with tools/engram_local.py, verified
  97. # byte-for-byte). NVMe instead of NFS for the 23.6 GiB/rank tables.
  98. DSV41_ENGRAM_LOCAL = "1"
  99. DSV41_ENGRAM_DIR = "/engram-local"
  100. # CUDA graphs: the Engram rows are staged in prepare_inputs (baked
  101. # model_state.py prestage patch) so the whole decode step is capturable
  102. VLLM_USE_BREAKABLE_CUDAGRAPH = "1"
  103. VLLM_HAS_FLASHINFER_CUBIN = "1"
  104. VLLM_USE_RUST_FRONTEND = "0"
  105. # runtime JIT wedge countermeasure (their boot-3 lesson): kernels are
  106. # prebuilt in the image, but any residual JIT must not OOM the box
  107. MAX_JOBS = "2"
  108. VLLM_ENGINE_READY_TIMEOUT_S = "3600"
  109. PYTORCH_CUDA_ALLOC_CONF = "expandable_segments:True"
  110. TORCH_CUDA_ARCH_LIST = "12.1a"
  111. FLASHINFER_CUDA_ARCH_LIST = "12.1a"
  112. OMP_NUM_THREADS = "2"
  113. # Per-node sparse Engram copy (model-00047/00048 shards + engram-local.json)
  114. [[extra_mounts]]
  115. host = "/var/tmp/engram-local/DeepSeek-V4.1-Flash"
  116. container = "/engram-local"
  117. read_only = true
  118. # JIT caches persist per-node (self-namespace by engine version key; the
  119. # image prebakes the flashinfer 0.7.0rc1 SM120 kernels, first boots re-JIT
  120. # the rest)
  121. [[extra_mounts]]
  122. host = "~/sm121-cache/jit-121f/flashinfer"
  123. container = "/root/.cache/flashinfer"
  124. [[extra_mounts]]
  125. host = "~/sm121-cache/jit-121f/torchinductor"
  126. container = "/root/.cache/torchinductor"
  127. [[extra_mounts]]
  128. host = "~/sm121-cache/jit-121f/vllm"
  129. container = "/root/.cache/vllm"
  130. # B12X kernel JIT cache (B12X_CACHE_DIR; prebuilt into the image, persists
  131. # per node like the other JIT caches)
  132. [[extra_mounts]]
  133. host = "~/sm121-cache/jit-121f/b12x"
  134. container = "/root/.cache/b12x"