qwen3_dflash2.py 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. # SPDX-License-Identifier: Apache-2.0
  2. # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
  3. import torch
  4. import torch.nn.functional as F
  5. from torch import nn
  6. from vllm.compilation.backends import set_model_tag
  7. from vllm.compilation.decorators import support_torch_compile
  8. from vllm.config import CacheConfig, VllmConfig
  9. from vllm.model_executor.layers.linear import ReplicatedLinear
  10. from vllm.model_executor.layers.logits_processor import LogitsProcessor
  11. from vllm.model_executor.layers.quantization.base_config import QuantizationConfig
  12. from .qwen3_dflash import (
  13. DFlashQwen3DecoderLayer,
  14. DFlashQwen3ForCausalLM,
  15. DFlashQwen3Model,
  16. )
  17. from .utils import maybe_prefix
  18. def _grouped_conv(
  19. hidden_states: torch.Tensor,
  20. delta: torch.Tensor,
  21. base: torch.Tensor,
  22. block_size: int,
  23. num_groups: int,
  24. group_size: int,
  25. taps: int,
  26. ) -> torch.Tensor:
  27. blocks = hidden_states.unflatten(-1, (num_groups, group_size))
  28. coefficients = base.view(1, taps, num_groups, group_size) + delta.unsqueeze(-1)
  29. output = coefficients[:, 0] * blocks
  30. position = torch.arange(hidden_states.shape[0], device=hidden_states.device)
  31. if block_size & (block_size - 1) == 0:
  32. position = position & (block_size - 1)
  33. else:
  34. position = position % block_size
  35. for tap in range(1, taps):
  36. shifted = F.pad(blocks[:-tap], (0, 0, 0, 0, tap, 0))
  37. output += coefficients[:, tap] * shifted * (position >= tap).view(-1, 1, 1)
  38. return output.flatten(-2)
  39. class DFlashGroupedConv(nn.Module):
  40. def __init__(
  41. self,
  42. hidden_size: int,
  43. taps: int,
  44. group_size: int,
  45. block_size: int,
  46. params_dtype: torch.dtype,
  47. quant_config: QuantizationConfig | None,
  48. prefix: str,
  49. ) -> None:
  50. super().__init__()
  51. if hidden_size % group_size:
  52. raise ValueError(
  53. f"conv_group_size={group_size} must divide hidden_size={hidden_size}."
  54. )
  55. self.block_size = block_size
  56. self.taps = taps
  57. self.group_size = group_size
  58. self.num_groups = hidden_size // group_size
  59. self.base_kernel = nn.Parameter(
  60. torch.empty(2, taps, hidden_size, dtype=params_dtype),
  61. requires_grad=False,
  62. )
  63. self.kernel_projection = ReplicatedLinear(
  64. hidden_size,
  65. 2 * taps * self.num_groups,
  66. bias=False,
  67. params_dtype=params_dtype,
  68. quant_config=quant_config,
  69. prefix=maybe_prefix(prefix, "kernel_projection"),
  70. return_bias=False,
  71. )
  72. def _convolve(
  73. self, hidden_states: torch.Tensor, delta: torch.Tensor, side: int
  74. ) -> torch.Tensor:
  75. return _grouped_conv(
  76. hidden_states,
  77. delta,
  78. self.base_kernel[side],
  79. self.block_size,
  80. self.num_groups,
  81. self.group_size,
  82. self.taps,
  83. )
  84. def prepare(self, hidden_states: torch.Tensor) -> tuple[torch.Tensor, torch.Tensor]:
  85. coefficients = self.kernel_projection(hidden_states).reshape(
  86. hidden_states.shape[0], 2, self.taps, self.num_groups
  87. )
  88. return self._convolve(hidden_states, coefficients[:, 0], 0), coefficients[:, 1]
  89. def finish(
  90. self, hidden_states: torch.Tensor, coefficients: torch.Tensor
  91. ) -> torch.Tensor:
  92. return self._convolve(hidden_states, coefficients, 1)
  93. class DFlash2Qwen3DecoderLayer(DFlashQwen3DecoderLayer):
  94. def __init__(
  95. self,
  96. vllm_config: VllmConfig,
  97. *,
  98. config,
  99. layer_idx: int,
  100. cache_config: CacheConfig | None = None,
  101. quant_config: QuantizationConfig | None = None,
  102. prefix: str = "",
  103. ) -> None:
  104. super().__init__(
  105. vllm_config,
  106. config=config,
  107. layer_idx=layer_idx,
  108. cache_config=cache_config,
  109. quant_config=quant_config,
  110. prefix=prefix,
  111. )
  112. draft_config = config.dflash_config
  113. speculative_config = vllm_config.speculative_config
  114. assert speculative_config is not None
  115. conv_args = dict(
  116. hidden_size=config.hidden_size,
  117. taps=int(draft_config["conv_kernel_size"]),
  118. group_size=int(draft_config["conv_group_size"]),
  119. # Query tokens per request: the bonus token plus the mask tokens.
  120. block_size=1 + speculative_config.num_speculative_tokens,
  121. params_dtype=vllm_config.model_config.dtype,
  122. quant_config=quant_config,
  123. )
  124. self.attention_conv = DFlashGroupedConv(
  125. **conv_args, prefix=maybe_prefix(prefix, "attention_conv")
  126. )
  127. self.mlp_conv = DFlashGroupedConv(
  128. **conv_args, prefix=maybe_prefix(prefix, "mlp_conv")
  129. )
  130. def forward(
  131. self,
  132. positions: torch.Tensor,
  133. hidden_states: torch.Tensor,
  134. residual: torch.Tensor | None,
  135. ) -> tuple[torch.Tensor, torch.Tensor]:
  136. if residual is None:
  137. residual = hidden_states
  138. hidden_states = self.input_layernorm(hidden_states)
  139. else:
  140. hidden_states, residual = self.input_layernorm(hidden_states, residual)
  141. hidden_states, coefficients = self.attention_conv.prepare(hidden_states)
  142. hidden_states = self.self_attn(positions=positions, hidden_states=hidden_states)
  143. hidden_states = self.attention_conv.finish(hidden_states, coefficients)
  144. hidden_states, residual = self.post_attention_layernorm(hidden_states, residual)
  145. hidden_states, coefficients = self.mlp_conv.prepare(hidden_states)
  146. hidden_states = self.mlp(hidden_states)
  147. hidden_states = self.mlp_conv.finish(hidden_states, coefficients)
  148. return hidden_states, residual
  149. def _score_edges(
  150. predecessor_table: torch.Tensor,
  151. successor_table: torch.Tensor,
  152. candidate_ids: torch.Tensor,
  153. unary_logits: torch.Tensor,
  154. hidden: torch.Tensor,
  155. anchor_token_ids: torch.Tensor,
  156. top_k: int,
  157. ) -> torch.Tensor:
  158. successors = successor_table[candidate_ids]
  159. predecessor_ids = torch.cat(
  160. (
  161. anchor_token_ids[:, None, None].expand(-1, 1, top_k),
  162. candidate_ids[:, :-1],
  163. ),
  164. dim=1,
  165. )
  166. predecessors = predecessor_table[predecessor_ids]
  167. return unary_logits[:, :, None] + torch.einsum(
  168. "blpr,blcr->blpc", predecessors * hidden[:, :, None], successors
  169. )
  170. @support_torch_compile
  171. class CandidateSelector(nn.Module):
  172. def __init__(
  173. self,
  174. hidden_size: int,
  175. vocab_size: int,
  176. rank: int,
  177. top_k: int,
  178. params_dtype: torch.dtype,
  179. quant_config: QuantizationConfig | None,
  180. prefix: str,
  181. ) -> None:
  182. super().__init__()
  183. self.top_k = top_k
  184. self.predecessor_codebook = nn.Parameter(
  185. torch.empty(vocab_size, rank, dtype=params_dtype), requires_grad=False
  186. )
  187. self.successor_codebook = nn.Parameter(
  188. torch.empty(vocab_size, rank, dtype=params_dtype), requires_grad=False
  189. )
  190. self.hidden_projection = ReplicatedLinear(
  191. hidden_size,
  192. rank,
  193. bias=False,
  194. params_dtype=params_dtype,
  195. quant_config=quant_config,
  196. prefix=maybe_prefix(prefix, "hidden_projection"),
  197. return_bias=False,
  198. )
  199. def forward(
  200. self,
  201. candidate_ids: torch.Tensor,
  202. unary_logits: torch.Tensor,
  203. hidden_states: torch.Tensor,
  204. anchor_token_ids: torch.Tensor,
  205. ) -> torch.Tensor:
  206. hidden = self.hidden_projection(hidden_states)
  207. return _score_edges(
  208. self.predecessor_codebook,
  209. self.successor_codebook,
  210. candidate_ids,
  211. unary_logits,
  212. hidden,
  213. anchor_token_ids,
  214. self.top_k,
  215. )
  216. class DFlash2Qwen3Model(DFlashQwen3Model):
  217. decoder_layer_cls = DFlash2Qwen3DecoderLayer
  218. def __init__(
  219. self,
  220. *,
  221. vllm_config: VllmConfig,
  222. start_layer_id: int = 0,
  223. prefix: str = "",
  224. ) -> None:
  225. super().__init__(
  226. vllm_config=vllm_config,
  227. start_layer_id=start_layer_id,
  228. prefix=prefix,
  229. )
  230. draft_config = self.config.dflash_config
  231. self.input_embedding_scale = float(
  232. draft_config.get("input_embedding_scale", 1.0)
  233. )
  234. # Without its own tag the selector shares the draft head's compile cache.
  235. with set_model_tag("dflash2_candidate_selector"):
  236. self.candidate_selector = CandidateSelector(
  237. hidden_size=self.config.hidden_size,
  238. vocab_size=self.config.vocab_size,
  239. rank=int(draft_config["selector_rank"]),
  240. top_k=int(draft_config["selector_top_k"]),
  241. params_dtype=vllm_config.model_config.dtype,
  242. quant_config=self.quant_config,
  243. prefix=maybe_prefix(prefix, "candidate_selector"),
  244. )
  245. def embed_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor:
  246. return super().embed_input_ids(input_ids) * self.input_embedding_scale
  247. class DFlash2Qwen3ForCausalLM(DFlashQwen3ForCausalLM):
  248. model_cls = DFlash2Qwen3Model
  249. def __init__(self, *, vllm_config: VllmConfig, prefix: str = "") -> None:
  250. super().__init__(vllm_config=vllm_config, prefix=prefix)
  251. draft_config = self.config.dflash_config
  252. softcap = float(draft_config.get("final_logit_softcapping") or 0.0)
  253. self.candidate_logits_processor = LogitsProcessor(
  254. vllm_config.model_config.get_vocab_size(),
  255. scale=float(draft_config.get("output_multiplier", 1.0)),
  256. soft_cap=softcap if softcap > 0 else None,
  257. )
  258. def compute_candidates(
  259. self, hidden_states: torch.Tensor
  260. ) -> tuple[torch.Tensor, torch.Tensor]:
  261. return self.candidate_logits_processor.get_top_k_tokens(
  262. self.lm_head, hidden_states, self.model.candidate_selector.top_k
  263. )
  264. EntryClass = DFlash2Qwen3ForCausalLM