Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions python/sglang/srt/arg_groups/fields/spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ class Spec:
Optional[int],
"DFLASH only. Block size (verify window length). Alias of --speculative-num-draft-tokens for DFLASH.",
] = None
speculative_domino_candidate_pool_size: A[
int,
"Domino only. Size of the approximate block-shared base-logit candidate pool. Set to 0 to score the full vocabulary.",
] = 2048
speculative_dspark_block_size: A[
Optional[int],
"DSPARK only. Draft block size gamma (number of proposed draft tokens). The verify window is gamma + 1, so this sets --speculative-num-draft-tokens = gamma + 1. Omit to auto-infer gamma from the draft checkpoint block_size.",
Expand Down
62 changes: 62 additions & 0 deletions python/sglang/srt/models/dflash.py
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,35 @@ def grouped_conv():
)
self.hidden_norm = RMSNorm(hidden_size, eps=rms_norm_eps)

# The model loader calls load_weights() before set_block_size(). Build
# Domino projector modules here so their parameters are present while
# checkpoint weights are loaded.
self.projector_type = draft_config.projector_type
self.shift_label = draft_config.shift_label
self.prefix_gru: Optional[nn.GRU] = None
self.embed_proj: Optional[nn.Sequential] = None
if draft_config.is_domino:
assert draft_config.gru_hidden_dim is not None
assert draft_config.emb_dim is not None
self.prefix_gru = nn.GRU(
input_size=hidden_size,
hidden_size=int(draft_config.gru_hidden_dim),
num_layers=1,
batch_first=True,
bias=False,
)
self.embed_proj = nn.Sequential(
nn.Linear(
hidden_size + int(draft_config.gru_hidden_dim),
int(draft_config.emb_dim),
bias=False,
),
nn.SiLU(),
nn.Linear(
int(draft_config.emb_dim), int(config.vocab_size), bias=False
),
)

def set_block_size(self, block_size: int) -> None:
"""Adopt the block size the worker resolved.

Expand Down Expand Up @@ -728,6 +757,7 @@ def load_weights(self, weights: Iterable[Tuple[str, torch.Tensor]]):
]

params_dict = dict(self.named_parameters())
loaded_params = set()

# Alias the native export's "encoder." names.
_VENDOR_ENCODER_ALIASES = {
Expand All @@ -752,6 +782,14 @@ def resolve_param_name(name: str) -> Optional[str]:
return None

for name, loaded_weight in weights:
unprefixed_name = name.removeprefix("model.")
if self.projector_type != "domino" and unprefixed_name.startswith(
("prefix_gru.", "embed_proj.")
):
raise ValueError(
"DFLASH checkpoint contains Domino projector weights but "
f"projector_type={self.projector_type!r}."
)
for param_name, weight_name, shard_id in stacked_params_mapping:
if f".{weight_name}." not in name:
continue
Expand All @@ -762,6 +800,7 @@ def resolve_param_name(name: str) -> Optional[str]:
param = params_dict[resolved_name]
weight_loader = getattr(param, "weight_loader", default_weight_loader)
weight_loader(param, loaded_weight, shard_id)
loaded_params.add(resolved_name)
break
else:
resolved_name = resolve_param_name(name)
Expand Down Expand Up @@ -796,8 +835,31 @@ def resolve_param_name(name: str) -> Optional[str]:
f"(num_context_features={self.num_context_features}, hidden_size={int(self.config.hidden_size)}), "
f"but got {loaded_shape} for weight '{name}'."
)
if resolved_name.startswith(("prefix_gru.", "embed_proj.")) and tuple(
loaded_weight.shape
) != tuple(param.shape):
raise ValueError(
"DFLASH Domino projector weight shape mismatch: "
f"expected {resolved_name}{tuple(param.shape)}, got "
f"{tuple(loaded_weight.shape)} from {name!r}."
)
weight_loader = getattr(param, "weight_loader", default_weight_loader)
weight_loader(param, loaded_weight)
loaded_params.add(resolved_name)

if self.projector_type == "domino":
required = {
"prefix_gru.weight_ih_l0",
"prefix_gru.weight_hh_l0",
"embed_proj.0.weight",
"embed_proj.2.weight",
}
missing = required - loaded_params
if missing:
raise ValueError(
"DFLASH Domino checkpoint is missing required projector weights: "
f"{sorted(missing)}."
)


class DFlashLagunaAttention(DFlashAttention):
Expand Down
80 changes: 80 additions & 0 deletions python/sglang/srt/speculative/dflash_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,15 @@ class DFlashDraftConfig:
target_layer_ids: Optional[List[int]]
mask_token: str
mask_token_id: Optional[int]
projector_type: Optional[str]
shift_label: Optional[bool]
pure_draft_prefix_len: Optional[int]
gru_hidden_dim: Optional[int]
emb_dim: Optional[int]

@property
def is_domino(self) -> bool:
return self.projector_type == "domino"

def require_num_layers(self) -> int:
if self.num_hidden_layers is None:
Expand Down Expand Up @@ -698,6 +707,72 @@ def parse_dflash_draft_config(*, draft_hf_config: Any) -> DFlashDraftConfig:
f"got {mask_token_id}."
)

projector_type = dflash_cfg.get(
"projector_type", _cfg_get(draft_hf_config, "projector_type", None)
)
shift_label = None
pure_draft_prefix_len = None
gru_hidden_dim = None
emb_dim = None
if projector_type == "domino":
shift_label = dflash_cfg.get(
"shift_label", _cfg_get(draft_hf_config, "shift_label", None)
)
pure_draft_prefix_len = _parse_optional_int(
dflash_cfg.get(
"pure_draft_prefix_len",
_cfg_get(draft_hf_config, "pure_draft_prefix_len", None),
),
field_name="DFLASH Domino pure_draft_prefix_len",
min_value=0,
)
gru_hidden_dim = _parse_optional_int(
dflash_cfg.get(
"gru_hidden_dim", _cfg_get(draft_hf_config, "gru_hidden_dim", None)
),
field_name="DFLASH Domino gru_hidden_dim",
min_value=1,
)
nested_emb_dim = _parse_optional_int(
dflash_cfg.get("emb_dim", None),
field_name="DFLASH Domino dflash_config.emb_dim",
min_value=1,
)
top_level_emb_dim = _parse_optional_int(
_cfg_get(draft_hf_config, "emb_dim", None),
field_name="DFLASH Domino top-level emb_dim",
min_value=1,
)
if (
nested_emb_dim is not None
and top_level_emb_dim is not None
and nested_emb_dim != top_level_emb_dim
):
raise ValueError(
"DFLASH Domino emb_dim differs between dflash_config and the "
f"top-level config: {nested_emb_dim} != {top_level_emb_dim}."
)
emb_dim = nested_emb_dim if nested_emb_dim is not None else top_level_emb_dim

if not isinstance(shift_label, bool):
raise ValueError(
"DFLASH Domino requires dflash_config.shift_label to be a bool, "
f"got {shift_label!r}."
)
if pure_draft_prefix_len != 1:
raise ValueError(
"DFLASH Domino currently requires pure_draft_prefix_len=1, "
f"got {pure_draft_prefix_len!r}."
)
if gru_hidden_dim is None:
raise ValueError("DFLASH Domino requires dflash_config.gru_hidden_dim.")
if emb_dim is None:
raise ValueError("DFLASH Domino requires dflash_config.emb_dim.")
if block_size is not None and block_size <= 1:
raise ValueError(
f"DFLASH Domino requires block_size > 1, got {block_size}."
)

return DFlashDraftConfig(
num_hidden_layers=num_hidden_layers,
num_target_layers=num_target_layers,
Expand All @@ -711,6 +786,11 @@ def parse_dflash_draft_config(*, draft_hf_config: Any) -> DFlashDraftConfig:
target_layer_ids=parsed_target_layer_ids,
mask_token=mask_token,
mask_token_id=mask_token_id,
projector_type=projector_type,
shift_label=shift_label,
pure_draft_prefix_len=pure_draft_prefix_len,
gru_hidden_dim=gru_hidden_dim,
emb_dim=emb_dim,
)


Expand Down
Loading
Loading