11-models_deepseek_v4_1_sparse_mla.py.diff 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. --- baked-ours/models/deepseek_v4_1/sparse_mla.py 2026-09-10 19:56:14.000000000 +0200
  2. +++ baked/models/deepseek_v4_1/sparse_mla.py 2026-09-11 10:13:47.000000000 +0200
  3. @@ -20,14 +20,18 @@
  4. MultipleOf,
  5. )
  6. from vllm.v1.attention.backends.mla.compressor_utils import get_compressed_slot_mapping
  7. +from vllm.v1.attention.backends.utils import get_dcp_local_seq_lens
  8. from vllm.v1.attention.backends.mla.sparse_swa import (
  9. _LAYER_TYPE_C1A,
  10. _LAYER_TYPE_C2A,
  11. _LAYER_TYPE_SWAONLY,
  12. DeepseekSparseSWAMetadataBuilder,
  13. )
  14. +from vllm.logger import init_logger
  15. from vllm.v1.kv_cache_interface import AttentionSpec
  16. +logger = init_logger(__name__)
  17. +
  18. # v4.1 per-layer compress ratios: 0 = pure sliding window, 1 = full-length
  19. # compressed cache, 2 = ratio-2 compressed cache. Ratio-1 and ratio-2 layers
  20. # both attend over indexer topk indices into a shared compressed cache but
  21. @@ -58,6 +62,8 @@
  22. tile-scheduler plans from the v4.1 topology.
  23. """
  24. + supports_non_causal_multi_token_dcp: ClassVar[bool] = True
  25. +
  26. def __init__(self, *args, **kwargs):
  27. super().__init__(*args, **kwargs)
  28. compress_ratios = getattr(
  29. @@ -139,12 +145,23 @@
  30. req_id_per_token: torch.Tensor
  31. block_size: int
  32. topk_tokens: int
  33. + # DCP: the compressed cache is sharded over STATES with this interleave;
  34. + # block_size stays the per-rank kernel page (tokens). seq_lens are the
  35. + # global lengths (tokens); dcp_local_seq_lens this rank's share of the
  36. + # compressed length (states), None at DCP1.
  37. + cp_kv_cache_interleave_size: int = 1
  38. + seq_lens: torch.Tensor | None = None
  39. + dcp_local_seq_lens: torch.Tensor | None = None
  40. class DeepseekV4SparseMLAMetadataBuilder(
  41. AttentionMetadataBuilder[DeepseekV4FlashMLAMetadata]
  42. ):
  43. _cudagraph_support: ClassVar[AttentionCGSupport] = AttentionCGSupport.UNIFORM_BATCH
  44. + # The SM120 backend gathers queries / combines per token, so DSpark's
  45. + # non-causal multi-token decode is supported under DCP (the draft layers
  46. + # themselves are SWA-only and bypass the DCP path).
  47. + supports_non_causal_multi_token_dcp: ClassVar[bool] = True
  48. def __init__(
  49. self,
  50. @@ -155,9 +172,22 @@
  51. ) -> None:
  52. super().__init__(kv_cache_spec, layer_names, vllm_config, device)
  53. self.model_config = vllm_config.model_config
  54. + # DCP geometry (self.dcp_world_size / dcp_rank come from the base
  55. + # builder: process DCP for this sharded group). The V4.1 SM120 backend
  56. + # gathers queries and combines LSEs per token, so multi-token (DSpark)
  57. + # decodes stay decodes under DCP.
  58. + self.cp_kv_cache_interleave_size = (
  59. + vllm_config.parallel_config.cp_kv_cache_interleave_size
  60. + )
  61. + if self.dcp_world_size > 1 and self.cp_kv_cache_interleave_size != 1:
  62. + raise NotImplementedError(
  63. + "DeepSeek-V4.1 DCP supports cp_kv_cache_interleave_size=1 only"
  64. + )
  65. # Classify single-token queries (plus num_speculative_tokens via
  66. # supports_spec_as_decode=True) as decodes; longer queries go to prefill.
  67. - self._init_reorder_batch_threshold(1, supports_spec_as_decode=True)
  68. + self._init_reorder_batch_threshold(
  69. + 1, supports_spec_as_decode=True, supports_dcp_with_varlen=True
  70. + )
  71. self.topk_tokens = self.model_config.hf_config.index_topk
  72. max_num_batched_tokens = vllm_config.scheduler_config.max_num_batched_tokens
  73. @@ -174,6 +204,20 @@
  74. "DeepSeek V4.1 compressed-KV caches use compress_ratio 1 or 2; "
  75. f"got {self.compress_ratio}."
  76. )
  77. + if self.dcp_world_size > 1:
  78. + # Per-rank page geometry the state-space sharding relies on: the
  79. + # builder must see the kernel page (block_size tokens = num_states
  80. + # states per rank), never the manager block (x dcp).
  81. + assert self.kv_cache_spec.block_size % self.compress_ratio == 0
  82. + logger.info_once(
  83. + "DeepSeek-V4.1 compressed KV under DCP%d: ratio %d, %d tokens "
  84. + "(%d states) per page per rank, interleave %d",
  85. + self.dcp_world_size,
  86. + self.compress_ratio,
  87. + self.kv_cache_spec.block_size,
  88. + int(self.kv_cache_spec.num_states),
  89. + self.cp_kv_cache_interleave_size,
  90. + )
  91. # Pre-allocate compressed slot mapping buffer for CUDA graph address
  92. # stability when compress_ratio > 1.
  93. @@ -201,6 +245,17 @@
  94. int(self.kv_cache_spec.num_states),
  95. self.compress_ratio,
  96. out=self.compressed_slot_mapping_buffer,
  97. + dcp_world_size=self.dcp_world_size,
  98. + dcp_rank=self.dcp_rank,
  99. + cp_kv_cache_interleave_size=self.cp_kv_cache_interleave_size,
  100. + )
  101. + dcp_local_seq_lens = None
  102. + if self.dcp_world_size > 1:
  103. + dcp_local_seq_lens = get_dcp_local_seq_lens(
  104. + cm.seq_lens // self.compress_ratio,
  105. + self.dcp_world_size,
  106. + self.dcp_rank,
  107. + self.cp_kv_cache_interleave_size,
  108. )
  109. return DeepseekV4FlashMLAMetadata(
  110. @@ -214,6 +269,9 @@
  111. req_id_per_token=req_id_per_token,
  112. block_size=self.kv_cache_spec.block_size,
  113. topk_tokens=self.topk_tokens,
  114. + cp_kv_cache_interleave_size=self.cp_kv_cache_interleave_size,
  115. + seq_lens=cm.seq_lens,
  116. + dcp_local_seq_lens=dcp_local_seq_lens,
  117. )