remove stale/AppleDouble files
Browse files
plugins/sglang_glm5v/patch_sglang_dsa_arch.py
DELETED
|
@@ -1,162 +0,0 @@
|
|
| 1 |
-
#!/usr/bin/env python3
|
| 2 |
-
# SPDX-License-Identifier: Apache-2.0
|
| 3 |
-
"""Register Glm5vForConditionalGeneration as a DSA-capable architecture in SGLang.
|
| 4 |
-
|
| 5 |
-
WHY THIS PATCH IS NECESSARY (not an environment workaround):
|
| 6 |
-
SGLang gates the DeepSeek-Sparse-Attention path on a hardcoded architecture
|
| 7 |
-
tuple in ``is_deepseek_dsa`` (``srt/configs/model_config.py``). Upstream's own
|
| 8 |
-
DSA vision-language model (Mistral Large 3) is supported by adding its VLM
|
| 9 |
-
arch ``PixtralForConditionalGeneration`` to exactly this tuple in-tree — that
|
| 10 |
-
is the upstream mechanism; no env-var/out-of-tree hook exists for it (unlike
|
| 11 |
-
models/processors/mm-arch, which we register via the shipped
|
| 12 |
-
``SGLANG_EXTERNAL_*`` hooks). Our GLM5V wrapper needs the same one-line entry
|
| 13 |
-
so the DSA attention backend (and the ``server_args`` DSA backend defaults)
|
| 14 |
-
recognize the model whose text backbone is GlmMoeDsa.
|
| 15 |
-
|
| 16 |
-
Three insertions, each at a place where upstream registered its own DSA/MLA
|
| 17 |
-
VLM archs (KimiK25 / Pixtral precedents):
|
| 18 |
-
|
| 19 |
-
1. ``model_config.py``: the ``is_deepseek_dsa`` arch tuple — gates the DSA
|
| 20 |
-
attention backend;
|
| 21 |
-
2. ``model_config.py``: the MLA attention-arch condition — without it the
|
| 22 |
-
KV pool is built as MHA and the DSA backend crashes on
|
| 23 |
-
``dsa_kv_cache_store_fp8``;
|
| 24 |
-
3. ``server_args.py``: the DSA model-adjustments gate list — sets the DSA
|
| 25 |
-
dense-attn kv-len threshold (= model index_topk) and the prefill/decode
|
| 26 |
-
DSA backend defaults (trtllm on Blackwell); without it decode dies with
|
| 27 |
-
``Unsupported self.dsa_decode_impl = None``.
|
| 28 |
-
|
| 29 |
-
A 4th insertion (added later) enables MTP/NEXTN speculative decoding: without
|
| 30 |
-
it the draft worker rebuilds the entire ~90GB multimodal model as the "draft"
|
| 31 |
-
and OOMs (our wrapper arch is in none of SGLang's draft-model rewrite lists).
|
| 32 |
-
See the ``DRAFT_ANCHOR`` block below. This is only needed when serving with
|
| 33 |
-
``--speculative-algorithm NEXTN``; it is a no-op otherwise. (Measured: MTP gives
|
| 34 |
-
~1.1-1.16x tok/s at low/moderate batch + ~2.0 accept-len, greedy outputs are
|
| 35 |
-
token-identical to non-spec, but it is graph-capped at batch 256 so plain
|
| 36 |
-
high-batch TP8 wins for throughput-bound RL rollout — MTP is a single-stream
|
| 37 |
-
LATENCY lever, not a throughput one.)
|
| 38 |
-
|
| 39 |
-
Other in-tree arch lists mentioning GlmMoeDsa/KimiK25 are deliberately NOT
|
| 40 |
-
patched: they gate features we do not use (encoder disaggregation) or pure
|
| 41 |
-
performance defaults we set explicitly (flashinfer allreduce fusion,
|
| 42 |
-
attention-backend fallback).
|
| 43 |
-
|
| 44 |
-
The same entries will be needed wherever slime launches SGLang rollout engines
|
| 45 |
-
for glm5v (Milestone 1) — candidate for an upstream sglang PR.
|
| 46 |
-
|
| 47 |
-
Idempotent; run before ``sglang.launch_server`` (serve.sh does this).
|
| 48 |
-
"""
|
| 49 |
-
|
| 50 |
-
import pathlib
|
| 51 |
-
import subprocess
|
| 52 |
-
import sys
|
| 53 |
-
|
| 54 |
-
ARCH = "Glm5vForConditionalGeneration"
|
| 55 |
-
DSA_ANCHOR = '"GlmMoeDsaForCausalLM",'
|
| 56 |
-
DSA_INSERT = (
|
| 57 |
-
DSA_ANCHOR
|
| 58 |
-
+ f'\n "{ARCH}", # glm5v: GLM-5.2 (DSA) text + MoonViT vision (sglang_glm5v)'
|
| 59 |
-
)
|
| 60 |
-
MLA_ANCHOR = 'or "KimiK25ForConditionalGeneration" in self.hf_config.architectures'
|
| 61 |
-
MLA_INSERT = (
|
| 62 |
-
MLA_ANCHOR
|
| 63 |
-
+ f'\n or "{ARCH}" in self.hf_config.architectures # glm5v (sglang_glm5v)'
|
| 64 |
-
)
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
# server_args.py DSA adjustments gate: the list containing KimiK25 is unique
|
| 68 |
-
# to that block (other GlmMoeDsa lists in the file lack it).
|
| 69 |
-
SA_ANCHOR = (
|
| 70 |
-
'"KimiK25ForConditionalGeneration",\n'
|
| 71 |
-
' "MistralLarge3ForCausalLM",\n'
|
| 72 |
-
' "PixtralForConditionalGeneration",\n'
|
| 73 |
-
' "GlmMoeDsaForCausalLM",'
|
| 74 |
-
)
|
| 75 |
-
SA_INSERT = SA_ANCHOR + f'\n "{ARCH}", # glm5v (sglang_glm5v)'
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
# --- MTP / speculative NEXTN draft-model support (4th insertion) ---
|
| 79 |
-
# WHY: with --speculative-algorithm NEXTN, SGLang builds a SEPARATE draft model
|
| 80 |
-
# (is_draft_model=True) whose arch it rewrites to a single-layer NextN module in
|
| 81 |
-
# ``_config_draft_model``. That method maps the *text* backbone
|
| 82 |
-
# ``GlmMoeDsaForCausalLM`` -> ``DeepseekV3ForCausalLMNextN`` (correct: our MTP
|
| 83 |
-
# weights live at text layer 78: eh_proj/enorm/hnorm + one block). But our
|
| 84 |
-
# TOP-LEVEL arch is the multimodal wrapper ``Glm5vForConditionalGeneration``,
|
| 85 |
-
# which is in NONE of the rewrite lists -> the draft worker instead rebuilds the
|
| 86 |
-
# ENTIRE multimodal model (MoonViT + full 78-layer 90GB text model) as the
|
| 87 |
-
# "draft" and OOMs (a second ~90GB copy on top of base weights + KV + graphs).
|
| 88 |
-
#
|
| 89 |
-
# FIX: mirror the shipped ``Step3p7ForConditionalGeneration`` precedent (a VLM
|
| 90 |
-
# wrapper whose draft is its text MTP): when is_draft_model and arch is our
|
| 91 |
-
# wrapper, swap hf_config -> hf_text_config and set arch to GlmMoeDsaForCausalLM.
|
| 92 |
-
# Inserted at the TOP of _config_draft_model so the existing
|
| 93 |
-
# GlmMoeDsaForCausalLM -> DeepseekV3ForCausalLMNextN rule then fires on it.
|
| 94 |
-
DRAFT_ANCHOR = (
|
| 95 |
-
" def _config_draft_model(self):\n"
|
| 96 |
-
" is_draft_model = self.is_draft_model\n"
|
| 97 |
-
)
|
| 98 |
-
DRAFT_INSERT = (
|
| 99 |
-
DRAFT_ANCHOR
|
| 100 |
-
+ "\n"
|
| 101 |
-
+ " # glm5v (sglang_glm5v): map the multimodal wrapper draft to its\n"
|
| 102 |
-
+ " # text backbone so the GlmMoeDsa->NextN rewrite below applies.\n"
|
| 103 |
-
+ f' if is_draft_model and self.hf_config.architectures[0] == "{ARCH}":\n'
|
| 104 |
-
+ " self.hf_config = self.hf_text_config\n"
|
| 105 |
-
+ ' self.hf_config.architectures = ["GlmMoeDsaForCausalLM"]\n'
|
| 106 |
-
)
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
def find_module(mod: str) -> pathlib.Path:
|
| 110 |
-
out = subprocess.run(
|
| 111 |
-
[sys.executable, "-c", f"import {mod} as m; print(m.__file__)"],
|
| 112 |
-
capture_output=True,
|
| 113 |
-
text=True,
|
| 114 |
-
check=True,
|
| 115 |
-
)
|
| 116 |
-
return pathlib.Path(out.stdout.strip())
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
def apply(path: pathlib.Path, anchor: str, insert: str, marker: str, label: str) -> None:
|
| 120 |
-
src = path.read_text()
|
| 121 |
-
if marker in src:
|
| 122 |
-
print(f"{label}: already patched")
|
| 123 |
-
return
|
| 124 |
-
assert anchor in src, f"{label}: anchor not found in {path} (sglang version changed?)"
|
| 125 |
-
path.write_text(src.replace(anchor, insert, 1))
|
| 126 |
-
print(f"{label}: patched ({path})")
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
def main() -> None:
|
| 130 |
-
mc = find_module("sglang.srt.configs.model_config")
|
| 131 |
-
apply(mc, DSA_ANCHOR, DSA_INSERT, f'"{ARCH}", # glm5v', "DSA tuple")
|
| 132 |
-
apply(mc, MLA_ANCHOR, MLA_INSERT, f'or "{ARCH}" in self.hf_config.architectures', "MLA condition")
|
| 133 |
-
apply(
|
| 134 |
-
mc,
|
| 135 |
-
DRAFT_ANCHOR,
|
| 136 |
-
DRAFT_INSERT,
|
| 137 |
-
f'if is_draft_model and self.hf_config.architectures[0] == "{ARCH}"',
|
| 138 |
-
"NEXTN draft-model map",
|
| 139 |
-
)
|
| 140 |
-
sa = find_module("sglang.srt.server_args")
|
| 141 |
-
apply(sa, SA_ANCHOR, SA_INSERT, f'"{ARCH}", # glm5v', "server_args DSA gate")
|
| 142 |
-
|
| 143 |
-
# verify the DSA gate end-to-end
|
| 144 |
-
check = subprocess.run(
|
| 145 |
-
[
|
| 146 |
-
sys.executable,
|
| 147 |
-
"-c",
|
| 148 |
-
(
|
| 149 |
-
"from sglang.srt.configs.model_config import is_deepseek_dsa;"
|
| 150 |
-
f"print(is_deepseek_dsa({{'architectures': ['{ARCH}'], 'index_topk': 2048}}))"
|
| 151 |
-
),
|
| 152 |
-
],
|
| 153 |
-
capture_output=True,
|
| 154 |
-
text=True,
|
| 155 |
-
check=True,
|
| 156 |
-
)
|
| 157 |
-
assert check.stdout.strip() == "True", check.stdout + check.stderr
|
| 158 |
-
print("verified: is_deepseek_dsa recognizes the arch")
|
| 159 |
-
|
| 160 |
-
|
| 161 |
-
if __name__ == "__main__":
|
| 162 |
-
main()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|