94057c3d3e
PR Test (NPU) / check-changes (push) Has been cancelled
PR Test (NPU) / pr-gate (push) Has been cancelled
PR Test (NPU) / set-image-config (push) Has been cancelled
PR Test (NPU) / stage-b-test-1-npu-a2 (0) (push) Has been cancelled
PR Test (NPU) / stage-b-test-1-npu-a2 (1) (push) Has been cancelled
PR Test (NPU) / stage-b-test-2-npu-a2 (0) (push) Has been cancelled
PR Test (NPU) / stage-b-test-2-npu-a2 (1) (push) Has been cancelled
PR Test (NPU) / stage-b-test-4-npu-a3 (push) Has been cancelled
PR Test (NPU) / stage-b-test-16-npu-a3 (push) Has been cancelled
PR Test (NPU) / multimodal-gen-test-1-npu-a3 (push) Has been cancelled
PR Test (NPU) / multimodal-gen-test-2-npu-a3 (push) Has been cancelled
PR Test (Arm64) / pr-gate (push) Has been cancelled
PR Test (Arm64) / check-changes (push) Has been cancelled
PR Test (Arm64) / build-test (push) Has been cancelled
PR Test (sgl-router) / gate (push) Has been cancelled
PR Test (sgl-router) / tier-1 — lint (push) Has been cancelled
PR Test (sgl-router) / tier-2 — build + test (push) Has been cancelled
PR Test (sgl-router) / tier-3 — docker (placeholder) (push) Has been cancelled
PR Test (sgl-router) / tier-3 — k8s integration (push) Has been cancelled
PR Test (sgl-router) / tier-3 — e2e (push) Has been cancelled
PR Test (sgl-router) / finish (push) Has been cancelled
PR Test (NPU) / single-node-poc (map[name:qwen3_6_27b_w8a8_1p_in64k_out1k_50ms runner:linux-aarch64-a3-2 test_case:test/registered/ascend/performance/qwen3_6_27b/test_npu_qwen3_6_27b_w8a8_1p_in64k_out1k_50ms.py test_type:perf]) (push) Has been cancelled
PR Test (NPU) / pr-test-npu-finish (push) Has been cancelled
PR Test (Xeon) / pr-gate (push) Has been cancelled
PR Test (Xeon) / check-changes (push) Has been cancelled
PR Test (Xeon) / build-test (, xeon-gnr, base-b-test-cpu) (push) Has been cancelled
PR Test (XPU) / check-changes (push) Has been cancelled
PR Test (XPU) / pr-gate (push) Has been cancelled
PR Test (XPU) / stage-a-test-1-gpu-xpu (push) Has been cancelled
PR Test (XPU) / wait-for-stage-a (push) Has been cancelled
PR Test (XPU) / stage-b-test-1-gpu-xpu (push) Has been cancelled
PR Test (XPU) / finish (push) Has been cancelled
CI Model Inventory / build-inventory (push) Has been cancelled
Lint / lint (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark Compilation Check (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark - Manual Policy (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark - Request Processing (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark Summary (push) Has been cancelled
PR Test (SMG) / build-wheel (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on windows (x86_64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on macos (x86_64 - auto) (push) Has been cancelled
PR Test (SMG) / python-unit-tests (push) Has been cancelled
PR Test (SMG) / unit-tests (push) Has been cancelled
PR Test (SMG) / benchmarks (push) Has been cancelled
PR Test (SMG) / chat-completions (push) Has been cancelled
PR Test (SMG) / chat-completions-4gpu (push) Has been cancelled
PR Test (SMG) / e2e (push) Has been cancelled
PR Test (SMG) / docker-build-test (push) Has been cancelled
PR Test (SMG) / k8s-integration (push) Has been cancelled
PR Test (SMG) / finish (push) Has been cancelled
PR Test (SMG) / summarize-benchmarks (push) Has been cancelled
Release SGLang Model Gateway Docker Image / publish (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on macos (aarch64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (aarch64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (x86_64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (aarch64 - musllinux_1_1) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (x86_64 - musllinux_1_1) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / Build SDist (push) Has been cancelled
Release SGLang Model Gateway to PyPI / Upload to PyPI (push) Has been cancelled
Release SGLang Kernels / build-cu129-matrix (aarch64, 12.9, 3.10, arm-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / build-cu129-matrix (x86_64, 12.9, 3.10, x64-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / release-cu129 (push) Has been cancelled
Release SGLang Kernels / build-cu130-matrix (aarch64, 13.0, 3.10, arm-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / build-cu130-matrix (x86_64, 13.0, 3.10, x64-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / release-cu130 (push) Has been cancelled
Release SGLang Kernels / build-rocm-matrix (3.10, 700) (push) Has been cancelled
Release SGLang Kernels / build-rocm-matrix (3.10, 720) (push) Has been cancelled
Release SGLang Kernels / release-rocm700 (push) Has been cancelled
Release SGLang Kernels / release-rocm720 (push) Has been cancelled
Release SGLang Kernels / build-musa43 (43, 3.10) (push) Has been cancelled
Release SGLang Kernels / release-musa43 (push) Has been cancelled
510 lines
18 KiB
Python
510 lines
18 KiB
Python
from __future__ import annotations
|
|
|
|
import logging
|
|
from typing import Callable, Iterable, Optional, Tuple
|
|
|
|
import torch
|
|
from torch import nn
|
|
|
|
from sglang.srt.distributed.communication_op import tensor_model_parallel_all_gather
|
|
from sglang.srt.model_loader.weight_utils import default_weight_loader
|
|
from sglang.srt.models.dflash import DFlashDraftModel
|
|
from sglang.srt.speculative.dspark_components.dspark_config import (
|
|
parse_dspark_draft_config,
|
|
)
|
|
from sglang.srt.speculative.ragged_verify import (
|
|
RaggedVerifyMode,
|
|
read_ragged_verify_mode,
|
|
)
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
StepSampler = Callable[[torch.Tensor, int], torch.Tensor]
|
|
|
|
|
|
def gather_and_crop_vocab(
|
|
local_logits: torch.Tensor, lm_head: nn.Module
|
|
) -> torch.Tensor:
|
|
full_logits = tensor_model_parallel_all_gather(local_logits, dim=-1)
|
|
return full_logits[..., : int(lm_head.org_vocab_size)]
|
|
|
|
|
|
def run_markov_block(
|
|
head: nn.Module,
|
|
base_logits: torch.Tensor,
|
|
*,
|
|
first_prev_tokens: torch.Tensor,
|
|
hidden_states: Optional[torch.Tensor],
|
|
sampler: StepSampler,
|
|
) -> Tuple[torch.Tensor, torch.Tensor]:
|
|
batch_size, proposal_len = base_logits.shape[:2]
|
|
if proposal_len == 0:
|
|
empty = torch.empty(batch_size, 0, dtype=torch.long, device=base_logits.device)
|
|
return empty, base_logits
|
|
|
|
sampled_tokens = []
|
|
corrected_logits = []
|
|
prev_tokens = first_prev_tokens.long()
|
|
for step_idx in range(proposal_len):
|
|
step_hidden = None if hidden_states is None else hidden_states[:, step_idx, ...]
|
|
step_logits = head.apply_step_logits(
|
|
base_logits[:, step_idx, :],
|
|
token_ids=prev_tokens,
|
|
hidden_states=step_hidden,
|
|
)
|
|
next_tokens = sampler(step_logits, step_idx)
|
|
sampled_tokens.append(next_tokens)
|
|
corrected_logits.append(step_logits.unsqueeze(1))
|
|
prev_tokens = next_tokens
|
|
return (
|
|
torch.stack(sampled_tokens, dim=1),
|
|
torch.cat(corrected_logits, dim=1),
|
|
)
|
|
|
|
|
|
class VanillaMarkov(nn.Module):
|
|
|
|
markov_head_type = "vanilla"
|
|
|
|
def __init__(self, *, vocab_size: int, markov_rank: int) -> None:
|
|
super().__init__()
|
|
self.vocab_size = int(vocab_size)
|
|
self.markov_rank = int(markov_rank)
|
|
if self.markov_rank <= 0:
|
|
raise ValueError(
|
|
f"VanillaMarkov requires markov_rank > 0, got {self.markov_rank}."
|
|
)
|
|
self.markov_w1 = nn.Embedding(self.vocab_size, self.markov_rank)
|
|
self.markov_w2 = nn.Linear(self.markov_rank, self.vocab_size, bias=False)
|
|
|
|
def get_prev_embeddings(self, token_ids: torch.Tensor) -> torch.Tensor:
|
|
return self.markov_w1(token_ids.long())
|
|
|
|
def project_bias(self, latent_states: torch.Tensor) -> torch.Tensor:
|
|
return self.markov_w2(latent_states)
|
|
|
|
def compute_step_bias(
|
|
self,
|
|
token_ids: torch.Tensor,
|
|
hidden_states: Optional[torch.Tensor],
|
|
) -> torch.Tensor:
|
|
del hidden_states
|
|
return self.project_bias(self.get_prev_embeddings(token_ids))
|
|
|
|
def apply_step_logits(
|
|
self,
|
|
logits: torch.Tensor,
|
|
*,
|
|
token_ids: torch.Tensor,
|
|
hidden_states: Optional[torch.Tensor],
|
|
) -> torch.Tensor:
|
|
return logits + self.compute_step_bias(token_ids, hidden_states)
|
|
|
|
def apply_block_logits(
|
|
self,
|
|
base_logits: torch.Tensor,
|
|
*,
|
|
token_ids: torch.Tensor,
|
|
hidden_states: Optional[torch.Tensor],
|
|
) -> torch.Tensor:
|
|
if base_logits.size(-2) == 0:
|
|
return base_logits
|
|
return base_logits + self.compute_step_bias(token_ids, hidden_states)
|
|
|
|
def sample_block(
|
|
self,
|
|
base_logits: torch.Tensor,
|
|
*,
|
|
first_prev_tokens: torch.Tensor,
|
|
hidden_states: Optional[torch.Tensor],
|
|
sampler: StepSampler,
|
|
) -> Tuple[torch.Tensor, torch.Tensor]:
|
|
return run_markov_block(
|
|
self,
|
|
base_logits,
|
|
first_prev_tokens=first_prev_tokens,
|
|
hidden_states=hidden_states,
|
|
sampler=sampler,
|
|
)
|
|
|
|
|
|
class GatedMarkovHead(VanillaMarkov):
|
|
|
|
markov_head_type = "gated"
|
|
|
|
def __init__(self, *, vocab_size: int, markov_rank: int, hidden_size: int) -> None:
|
|
super().__init__(vocab_size=vocab_size, markov_rank=markov_rank)
|
|
self.gate_proj = nn.Linear(int(hidden_size) + markov_rank, markov_rank)
|
|
|
|
def compute_gate(
|
|
self,
|
|
token_ids: torch.Tensor,
|
|
hidden_states: Optional[torch.Tensor],
|
|
) -> torch.Tensor:
|
|
if hidden_states is None:
|
|
raise ValueError("GatedMarkovHead requires hidden_states.")
|
|
prev_embeddings = self.get_prev_embeddings(token_ids)
|
|
gate_inputs = torch.cat([hidden_states, prev_embeddings], dim=-1)
|
|
return torch.sigmoid(self.gate_proj(gate_inputs))
|
|
|
|
def compute_step_bias(
|
|
self,
|
|
token_ids: torch.Tensor,
|
|
hidden_states: Optional[torch.Tensor],
|
|
) -> torch.Tensor:
|
|
prev_embeddings = self.get_prev_embeddings(token_ids)
|
|
gate = self.compute_gate(token_ids, hidden_states).to(
|
|
dtype=prev_embeddings.dtype
|
|
)
|
|
return self.project_bias(gate * prev_embeddings)
|
|
|
|
|
|
class RNNHead(VanillaMarkov):
|
|
|
|
markov_head_type = "rnn"
|
|
|
|
def __init__(self, *, vocab_size: int, markov_rank: int, hidden_size: int) -> None:
|
|
super().__init__(vocab_size=vocab_size, markov_rank=markov_rank)
|
|
self.hidden_size = int(hidden_size)
|
|
self.state_size = markov_rank
|
|
self.joint_proj = nn.Linear(2 * markov_rank + self.hidden_size, 3 * markov_rank)
|
|
|
|
def _rnn_step(
|
|
self,
|
|
state: torch.Tensor,
|
|
prev_embeddings: torch.Tensor,
|
|
hidden_states: torch.Tensor,
|
|
) -> Tuple[torch.Tensor, torch.Tensor]:
|
|
z = torch.cat([state, prev_embeddings, hidden_states], dim=-1)
|
|
gate_raw, candidate_raw, output_raw = self.joint_proj(z).chunk(3, dim=-1)
|
|
gate = torch.sigmoid(gate_raw)
|
|
candidate = torch.tanh(candidate_raw)
|
|
new_state = gate * state + (1.0 - gate) * candidate
|
|
bias = self.project_bias(torch.tanh(output_raw))
|
|
return new_state, bias
|
|
|
|
def compute_step_bias(
|
|
self,
|
|
token_ids: torch.Tensor,
|
|
hidden_states: Optional[torch.Tensor],
|
|
) -> torch.Tensor:
|
|
if hidden_states is None:
|
|
raise ValueError("RNNHead requires hidden_states.")
|
|
prev_embeddings = self.get_prev_embeddings(token_ids)
|
|
state = torch.zeros_like(prev_embeddings)
|
|
_, bias = self._rnn_step(state, prev_embeddings, hidden_states)
|
|
return bias
|
|
|
|
def apply_block_logits(
|
|
self,
|
|
base_logits: torch.Tensor,
|
|
*,
|
|
token_ids: torch.Tensor,
|
|
hidden_states: Optional[torch.Tensor],
|
|
) -> torch.Tensor:
|
|
if hidden_states is None:
|
|
raise ValueError("RNNHead requires hidden_states.")
|
|
block_size = base_logits.size(-2)
|
|
if block_size == 0:
|
|
return base_logits
|
|
leading_shape = base_logits.shape[:-2]
|
|
state = torch.zeros(
|
|
*leading_shape,
|
|
self.markov_rank,
|
|
device=base_logits.device,
|
|
dtype=hidden_states.dtype,
|
|
)
|
|
output_logits = []
|
|
for k in range(block_size):
|
|
prev_emb = self.get_prev_embeddings(token_ids[..., k])
|
|
state, bias = self._rnn_step(state, prev_emb, hidden_states[..., k, :])
|
|
output_logits.append(base_logits[..., k, :] + bias)
|
|
return torch.stack(output_logits, dim=-2)
|
|
|
|
def sample_block(
|
|
self,
|
|
base_logits: torch.Tensor,
|
|
*,
|
|
first_prev_tokens: torch.Tensor,
|
|
hidden_states: Optional[torch.Tensor],
|
|
sampler: StepSampler,
|
|
) -> Tuple[torch.Tensor, torch.Tensor]:
|
|
if hidden_states is None:
|
|
raise ValueError("RNNHead requires hidden_states.")
|
|
batch_size, proposal_len = base_logits.shape[:2]
|
|
if proposal_len == 0:
|
|
empty = torch.empty(
|
|
batch_size, 0, dtype=torch.long, device=base_logits.device
|
|
)
|
|
return empty, base_logits
|
|
|
|
state = torch.zeros(
|
|
batch_size,
|
|
self.markov_rank,
|
|
device=base_logits.device,
|
|
dtype=hidden_states.dtype,
|
|
)
|
|
sampled_tokens = []
|
|
corrected_logits = []
|
|
prev_tokens = first_prev_tokens.long()
|
|
for step_idx in range(proposal_len):
|
|
prev_emb = self.get_prev_embeddings(prev_tokens)
|
|
state, bias = self._rnn_step(state, prev_emb, hidden_states[:, step_idx, :])
|
|
step_logits = base_logits[:, step_idx, :] + bias
|
|
next_tokens = sampler(step_logits, step_idx)
|
|
sampled_tokens.append(next_tokens)
|
|
corrected_logits.append(step_logits.unsqueeze(1))
|
|
prev_tokens = next_tokens
|
|
return (
|
|
torch.stack(sampled_tokens, dim=1),
|
|
torch.cat(corrected_logits, dim=1),
|
|
)
|
|
|
|
|
|
def build_markov_head(config) -> Optional[nn.Module]:
|
|
markov_rank = int(getattr(config, "markov_rank", 0))
|
|
if markov_rank <= 0:
|
|
raise ValueError(
|
|
"DSpark requires markov_rank > 0 (the Markov head is the core of the "
|
|
f"semi-AR draft); got markov_rank={markov_rank}."
|
|
)
|
|
markov_head_type = str(getattr(config, "markov_head_type", "vanilla")).lower()
|
|
vocab_size = int(config.vocab_size)
|
|
hidden_size = int(config.hidden_size)
|
|
if markov_head_type == "vanilla":
|
|
return VanillaMarkov(vocab_size=vocab_size, markov_rank=markov_rank)
|
|
if markov_head_type == "gated":
|
|
return GatedMarkovHead(
|
|
vocab_size=vocab_size, markov_rank=markov_rank, hidden_size=hidden_size
|
|
)
|
|
if markov_head_type == "rnn":
|
|
return RNNHead(
|
|
vocab_size=vocab_size, markov_rank=markov_rank, hidden_size=hidden_size
|
|
)
|
|
raise ValueError(f"Unsupported DSpark markov_head_type={markov_head_type!r}.")
|
|
|
|
|
|
class DSparkConfidenceHead(nn.Module):
|
|
|
|
def __init__(
|
|
self,
|
|
*,
|
|
hidden_size: int,
|
|
markov_rank: int,
|
|
with_markov: bool = True,
|
|
bias: bool = True,
|
|
dtype: torch.dtype = torch.float32,
|
|
) -> None:
|
|
super().__init__()
|
|
self.with_markov = bool(with_markov)
|
|
input_dim = int(hidden_size) + (int(markov_rank) if self.with_markov else 0)
|
|
self.proj = nn.Linear(input_dim, 1, bias=bias, dtype=dtype)
|
|
self.register_buffer(
|
|
"sts_temperatures", torch.ones((), dtype=torch.float32), persistent=False
|
|
)
|
|
self._last_confidence_raw: Optional[torch.Tensor] = None
|
|
|
|
def forward(
|
|
self,
|
|
hidden_states: torch.Tensor,
|
|
markov_embed_stack: Optional[torch.Tensor] = None,
|
|
) -> torch.Tensor:
|
|
if self.with_markov:
|
|
if markov_embed_stack is None:
|
|
raise ValueError(
|
|
"DSparkConfidenceHead(with_markov=True) requires markov_embed_stack."
|
|
)
|
|
features = torch.cat(
|
|
[hidden_states, markov_embed_stack.to(dtype=hidden_states.dtype)],
|
|
dim=-1,
|
|
)
|
|
else:
|
|
features = hidden_states
|
|
features = features.to(dtype=self.proj.weight.dtype)
|
|
return self.proj(features).squeeze(-1)
|
|
|
|
def apply_sts(self, confidence_raw: torch.Tensor) -> torch.Tensor:
|
|
self._last_confidence_raw = confidence_raw
|
|
return torch.sigmoid(confidence_raw.float() / self.sts_temperatures)
|
|
|
|
|
|
def build_confidence_head(config) -> Optional[nn.Module]:
|
|
if read_ragged_verify_mode() is RaggedVerifyMode.STATIC:
|
|
return None
|
|
if not hasattr(config, "enable_confidence_head"):
|
|
logger.warning(
|
|
"DSpark draft config has no enable_confidence_head field; treating the "
|
|
"confidence head as enabled."
|
|
)
|
|
hidden_size = int(config.hidden_size)
|
|
markov_rank = int(getattr(config, "markov_rank", 0))
|
|
with_markov = bool(getattr(config, "confidence_head_with_markov", markov_rank > 0))
|
|
if with_markov and markov_rank <= 0:
|
|
raise ValueError(
|
|
"DSpark confidence_head_with_markov requires markov_rank > 0, "
|
|
f"got markov_rank={markov_rank}."
|
|
)
|
|
return DSparkConfidenceHead(
|
|
hidden_size=hidden_size,
|
|
markov_rank=markov_rank,
|
|
with_markov=with_markov,
|
|
)
|
|
|
|
|
|
_DSPARK_SKIPPED_WEIGHT_PREFIXES = (
|
|
"embed_tokens.",
|
|
"lm_head.",
|
|
"rotary_emb.",
|
|
)
|
|
|
|
|
|
class DSparkDraftMixin:
|
|
|
|
def __init__(self, config, quant_config=None, prefix: str = "") -> None:
|
|
super().__init__(config=config, quant_config=quant_config, prefix=prefix)
|
|
dspark_config = parse_dspark_draft_config(draft_hf_config=config)
|
|
if not dspark_config.require_markov():
|
|
raise ValueError(
|
|
"DSpark draft requires markov_rank > 0, "
|
|
f"got markov_rank={dspark_config.markov_rank}."
|
|
)
|
|
self.gamma = int(dspark_config.resolve_gamma(default=self.block_size))
|
|
self.markov_head = build_markov_head(config)
|
|
self.confidence_head = build_confidence_head(config)
|
|
self.lm_head: Optional[nn.Module] = None
|
|
|
|
def attach_shared_modules(
|
|
self, *, embed_tokens: nn.Module, lm_head: nn.Module
|
|
) -> None:
|
|
del embed_tokens
|
|
self.lm_head = lm_head
|
|
|
|
def compute_base_logits(
|
|
self, hidden: torch.Tensor
|
|
) -> tuple[torch.Tensor, Optional[torch.Tensor]]:
|
|
if self.lm_head is None:
|
|
raise ValueError(
|
|
"DSpark dense draft requires the target lm_head "
|
|
"(call attach_shared_modules first)."
|
|
)
|
|
weight = self.lm_head.weight
|
|
if hidden.dtype != weight.dtype:
|
|
hidden = hidden.to(weight.dtype)
|
|
local_logits = torch.matmul(hidden, weight.T)
|
|
base_logits = gather_and_crop_vocab(local_logits, self.lm_head)
|
|
return base_logits, None
|
|
|
|
def load_weights(self, weights: Iterable[Tuple[str, torch.Tensor]]):
|
|
markov_weights = []
|
|
confidence_weights = []
|
|
backbone_weights = []
|
|
params_dict = dict(self.named_parameters())
|
|
for name, loaded_weight in weights:
|
|
if any(name.startswith(p) for p in _DSPARK_SKIPPED_WEIGHT_PREFIXES):
|
|
continue
|
|
if name.startswith("confidence_head."):
|
|
if self.confidence_head is None:
|
|
continue
|
|
confidence_weights.append((name, loaded_weight))
|
|
elif name.startswith("markov_head."):
|
|
markov_weights.append((name, loaded_weight))
|
|
else:
|
|
backbone_weights.append((name, loaded_weight))
|
|
|
|
super().load_weights(backbone_weights)
|
|
|
|
for name, loaded_weight in markov_weights:
|
|
if name not in params_dict:
|
|
raise ValueError(
|
|
f"DSpark unexpected markov weight {name!r} not found in model "
|
|
f"parameters (known markov params require a {type(self.markov_head).__name__} head)."
|
|
)
|
|
param = params_dict[name]
|
|
weight_loader = getattr(param, "weight_loader", default_weight_loader)
|
|
weight_loader(param, loaded_weight)
|
|
|
|
self._load_confidence_weights(
|
|
confidence_weights=confidence_weights, params_dict=params_dict
|
|
)
|
|
|
|
def _load_confidence_weights(
|
|
self,
|
|
*,
|
|
confidence_weights: list,
|
|
params_dict: dict,
|
|
) -> None:
|
|
if self.confidence_head is None:
|
|
return
|
|
loaded_names = set()
|
|
for name, loaded_weight in confidence_weights:
|
|
if name not in params_dict:
|
|
raise ValueError(
|
|
f"DSpark unexpected confidence weight {name!r} not found in "
|
|
"model parameters."
|
|
)
|
|
param = params_dict[name]
|
|
weight_loader = getattr(param, "weight_loader", default_weight_loader)
|
|
weight_loader(param, loaded_weight)
|
|
loaded_names.add(name)
|
|
|
|
confidence_param_names = {
|
|
name for name in params_dict if name.startswith("confidence_head.")
|
|
}
|
|
missing = confidence_param_names - loaded_names
|
|
if missing:
|
|
raise ValueError(
|
|
f"DSpark confidence head is enabled but the checkpoint is missing "
|
|
f"{sorted(missing)}. Provide a checkpoint with trained confidence weights, "
|
|
f"or disable the confidence head (enable_confidence_head=False)."
|
|
)
|
|
|
|
def write_target_hidden_kv(
|
|
self,
|
|
*,
|
|
target_hidden: torch.Tensor,
|
|
pool,
|
|
positions: torch.Tensor,
|
|
cache_loc: torch.Tensor,
|
|
cache_loc_2d: Optional[torch.Tensor] = None,
|
|
commit_lens: Optional[torch.Tensor] = None,
|
|
) -> None:
|
|
ctx_hidden = self.project_target_hidden(target_hidden)
|
|
for layer in self.layers:
|
|
attn = layer.self_attn
|
|
k, v = attn.kv_proj_only(ctx_hidden)
|
|
k = attn.apply_k_norm(k)
|
|
k = attn.apply_k_rope(positions, k)
|
|
k = k.view(-1, attn.num_kv_heads, attn.head_dim)
|
|
v = v.view(-1, attn.num_kv_heads, attn.head_dim)
|
|
if cache_loc_2d is not None and commit_lens is not None:
|
|
pool.set_kv_buffer_prefix_valid(
|
|
attn.attn,
|
|
cache_loc_2d,
|
|
commit_lens,
|
|
k,
|
|
v,
|
|
attn.attn.k_scale,
|
|
attn.attn.v_scale,
|
|
)
|
|
else:
|
|
pool.set_kv_buffer(
|
|
attn.attn,
|
|
cache_loc,
|
|
k,
|
|
v,
|
|
attn.attn.k_scale,
|
|
attn.attn.v_scale,
|
|
)
|
|
|
|
|
|
class DSparkDraftModel(DSparkDraftMixin, DFlashDraftModel):
|
|
|
|
pass
|
|
|
|
|
|
class Qwen3DSparkModel(DSparkDraftModel):
|
|
pass
|
|
|
|
|
|
EntryClass = [Qwen3DSparkModel]
|