[NPU] DFlash Speculative Decoding Support NPU (#23122)
This commit is contained in:
@@ -1675,6 +1675,12 @@ class AscendAttnBackend(AttentionBackend):
|
|||||||
self.speculative_num_draft_tokens + query.shape[0],
|
self.speculative_num_draft_tokens + query.shape[0],
|
||||||
self.speculative_num_draft_tokens,
|
self.speculative_num_draft_tokens,
|
||||||
)
|
)
|
||||||
|
if layer.attn_type == AttentionType.ENCODER_ONLY:
|
||||||
|
mask = None
|
||||||
|
sparse_mode = 0
|
||||||
|
else:
|
||||||
|
mask = self.mtp_mask
|
||||||
|
sparse_mode = 3
|
||||||
|
|
||||||
attn_output, _ = torch.ops.npu.npu_fused_infer_attention_score(
|
attn_output, _ = torch.ops.npu.npu_fused_infer_attention_score(
|
||||||
query,
|
query,
|
||||||
@@ -1685,15 +1691,16 @@ class AscendAttnBackend(AttentionBackend):
|
|||||||
num_heads=layer.tp_q_head_num,
|
num_heads=layer.tp_q_head_num,
|
||||||
num_key_value_heads=layer.tp_k_head_num,
|
num_key_value_heads=layer.tp_k_head_num,
|
||||||
input_layout="TND",
|
input_layout="TND",
|
||||||
atten_mask=self.mtp_mask,
|
atten_mask=mask,
|
||||||
scale=layer.scaling,
|
scale=layer.scaling,
|
||||||
actual_seq_lengths=actual_seq_lengths,
|
actual_seq_lengths=actual_seq_lengths,
|
||||||
actual_seq_lengths_kv=actual_seq_lengths_kv,
|
actual_seq_lengths_kv=actual_seq_lengths_kv,
|
||||||
sparse_mode=3,
|
sparse_mode=sparse_mode,
|
||||||
)
|
)
|
||||||
attn_output = attn_output.view(-1, layer.tp_q_head_num * layer.v_head_dim)
|
attn_output = attn_output.view(-1, layer.tp_q_head_num * layer.v_head_dim)
|
||||||
if (
|
if (
|
||||||
not self.graph_mode
|
not self.graph_mode
|
||||||
|
and forward_batch.num_token_non_padded_cpu is not None
|
||||||
and forward_batch.num_token_non_padded_cpu != num_token_padding
|
and forward_batch.num_token_non_padded_cpu != num_token_padding
|
||||||
):
|
):
|
||||||
attn_output = torch.cat(
|
attn_output = torch.cat(
|
||||||
|
|||||||
@@ -177,6 +177,14 @@ class NPUGraphRunner(CudaGraphRunner):
|
|||||||
# In speculative decoding, these two fields are still needed.
|
# In speculative decoding, these two fields are still needed.
|
||||||
self.buffers.input_ids[: self.raw_num_token].copy_(forward_batch.input_ids)
|
self.buffers.input_ids[: self.raw_num_token].copy_(forward_batch.input_ids)
|
||||||
self.buffers.positions[: self.raw_num_token].copy_(forward_batch.positions)
|
self.buffers.positions[: self.raw_num_token].copy_(forward_batch.positions)
|
||||||
|
if (
|
||||||
|
self.model_runner.spec_algorithm.is_dflash()
|
||||||
|
and self.model_runner.is_draft_worker
|
||||||
|
and forward_batch.input_embeds is not None
|
||||||
|
):
|
||||||
|
self.buffers.input_embeds[: self.raw_num_token].copy_(
|
||||||
|
forward_batch.input_embeds
|
||||||
|
)
|
||||||
if (
|
if (
|
||||||
envs.SGLANG_ENABLE_OVERLAP_PLAN_STREAM.get()
|
envs.SGLANG_ENABLE_OVERLAP_PLAN_STREAM.get()
|
||||||
and forward_batch.mrope_positions is not None
|
and forward_batch.mrope_positions is not None
|
||||||
@@ -207,10 +215,18 @@ class NPUGraphRunner(CudaGraphRunner):
|
|||||||
if isinstance(output, LogitsProcessorOutput):
|
if isinstance(output, LogitsProcessorOutput):
|
||||||
if self.is_dllm:
|
if self.is_dllm:
|
||||||
next_token_logits = None
|
next_token_logits = None
|
||||||
full_logits = output.full_logits[: self.raw_num_token]
|
full_logits = (
|
||||||
|
output.full_logits[: self.raw_num_token]
|
||||||
|
if output.full_logits is not None
|
||||||
|
else None
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
full_logits = None
|
full_logits = None
|
||||||
next_token_logits = output.next_token_logits[: self.raw_num_token]
|
next_token_logits = (
|
||||||
|
output.next_token_logits[: self.raw_num_token]
|
||||||
|
if output.next_token_logits is not None
|
||||||
|
else None
|
||||||
|
)
|
||||||
return LogitsProcessorOutput(
|
return LogitsProcessorOutput(
|
||||||
next_token_logits=next_token_logits,
|
next_token_logits=next_token_logits,
|
||||||
full_logits=full_logits,
|
full_logits=full_logits,
|
||||||
|
|||||||
@@ -30,7 +30,11 @@ from sglang.srt.speculative.dflash_utils import (
|
|||||||
can_dflash_slice_qkv_weight,
|
can_dflash_slice_qkv_weight,
|
||||||
parse_dflash_draft_config,
|
parse_dflash_draft_config,
|
||||||
)
|
)
|
||||||
|
from sglang.srt.utils import is_npu
|
||||||
|
|
||||||
|
_is_npu = is_npu()
|
||||||
|
if _is_npu:
|
||||||
|
from sgl_kernel_npu.norm.split_qkv_rmsnorm_rope import split_qkv_rmsnorm_rope
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@@ -118,6 +122,26 @@ class DFlashAttention(nn.Module):
|
|||||||
attn_type=AttentionType.ENCODER_ONLY,
|
attn_type=AttentionType.ENCODER_ONLY,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def forward_prepare_npu(self, positions, hidden_states):
|
||||||
|
qkv, _ = self.qkv_proj(hidden_states)
|
||||||
|
|
||||||
|
if self.attn.layer_id == 0:
|
||||||
|
self.rotary_emb.get_cos_sin_with_position(positions)
|
||||||
|
q, k, v = split_qkv_rmsnorm_rope(
|
||||||
|
qkv,
|
||||||
|
self.rotary_emb.position_sin,
|
||||||
|
self.rotary_emb.position_cos,
|
||||||
|
self.q_size,
|
||||||
|
self.kv_size,
|
||||||
|
self.head_dim,
|
||||||
|
eps=self.q_norm.variance_epsilon,
|
||||||
|
q_weight=self.q_norm.weight,
|
||||||
|
k_weight=self.k_norm.weight,
|
||||||
|
q_bias=getattr(self.q_norm, "bias", None),
|
||||||
|
k_bias=getattr(self.k_norm, "bias", None),
|
||||||
|
)
|
||||||
|
return q, k, v
|
||||||
|
|
||||||
def forward(
|
def forward(
|
||||||
self,
|
self,
|
||||||
positions: torch.Tensor,
|
positions: torch.Tensor,
|
||||||
@@ -125,6 +149,9 @@ class DFlashAttention(nn.Module):
|
|||||||
forward_batch: ForwardBatch,
|
forward_batch: ForwardBatch,
|
||||||
) -> torch.Tensor:
|
) -> torch.Tensor:
|
||||||
qkv, _ = self.qkv_proj(hidden_states)
|
qkv, _ = self.qkv_proj(hidden_states)
|
||||||
|
if _is_npu:
|
||||||
|
q, k, v = self.forward_prepare_npu(positions, hidden_states)
|
||||||
|
else:
|
||||||
q, k, v = qkv.split([self.q_size, self.kv_size, self.kv_size], dim=-1)
|
q, k, v = qkv.split([self.q_size, self.kv_size, self.kv_size], dim=-1)
|
||||||
q, k = apply_qk_norm(q, k, self.q_norm, self.k_norm, self.head_dim)
|
q, k = apply_qk_norm(q, k, self.q_norm, self.k_norm, self.head_dim)
|
||||||
q, k = self.rotary_emb(positions, q, k)
|
q, k = self.rotary_emb(positions, q, k)
|
||||||
|
|||||||
@@ -29,7 +29,10 @@ from sglang.srt.speculative.dflash_utils import (
|
|||||||
)
|
)
|
||||||
from sglang.srt.speculative.spec_info import SpeculativeAlgorithm
|
from sglang.srt.speculative.spec_info import SpeculativeAlgorithm
|
||||||
from sglang.srt.speculative.spec_utils import assign_req_to_token_pool_func
|
from sglang.srt.speculative.spec_utils import assign_req_to_token_pool_func
|
||||||
from sglang.srt.utils import is_cuda
|
from sglang.srt.utils import is_cuda, is_npu
|
||||||
|
|
||||||
|
_is_npu = is_npu()
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -98,7 +101,7 @@ class DFlashWorker:
|
|||||||
draft_server_args = deepcopy(server_args)
|
draft_server_args = deepcopy(server_args)
|
||||||
draft_server_args.skip_tokenizer_init = True
|
draft_server_args.skip_tokenizer_init = True
|
||||||
draft_backend = draft_server_args.speculative_draft_attention_backend
|
draft_backend = draft_server_args.speculative_draft_attention_backend
|
||||||
supported_draft_backends = ("flashinfer", "fa3", "fa4", "triton")
|
supported_draft_backends = ("flashinfer", "fa3", "fa4", "triton", "ascend")
|
||||||
if draft_backend is None:
|
if draft_backend is None:
|
||||||
draft_backend, _ = draft_server_args.get_attention_backends()
|
draft_backend, _ = draft_server_args.get_attention_backends()
|
||||||
if draft_backend is None:
|
if draft_backend is None:
|
||||||
@@ -1016,6 +1019,9 @@ class DFlashWorker:
|
|||||||
) -> None:
|
) -> None:
|
||||||
for layer in self.draft_model.layers:
|
for layer in self.draft_model.layers:
|
||||||
attn = layer.self_attn
|
attn = layer.self_attn
|
||||||
|
if _is_npu:
|
||||||
|
_, k, v = attn.forward_prepare_npu(ctx_positions, ctx_hidden)
|
||||||
|
else:
|
||||||
k, v = attn.kv_proj_only(ctx_hidden)
|
k, v = attn.kv_proj_only(ctx_hidden)
|
||||||
k = attn.apply_k_norm(k)
|
k = attn.apply_k_norm(k)
|
||||||
k = attn.apply_k_rope(ctx_positions, k)
|
k = attn.apply_k_rope(ctx_positions, k)
|
||||||
|
|||||||
Reference in New Issue
Block a user