GLM-5.2-Demolition-q4a4-soul-MLX / install_glm_dsa_patch.py
philipjohnbasile's picture
Upload install_glm_dsa_patch.py with huggingface_hub
1b5c7e0 verified
Raw
History Blame Contribute Delete
6.18 kB
#!/usr/bin/env python3
"""Put the GLM-5.2 DSA fix INTO every local mlx_lm — including LM Studio's
vendored backend — so the demolished GLM-5.2 loads WITHOUT depending on the
LM Studio app (closed source) shipping it.
The LM Studio *app* is closed, but the engine it loads MLX models with is
**open-source mlx_lm**, vendored on disk under ~/.lmstudio. Stock mlx_lm ships
only a 53-line stub for `glm_moe_dsa` (GLM-5.2's DeepSeek-Sparse-Attention MoE),
which is why GLM-5.2 fails to load ("Missing 285 parameters"). This script
overwrites that stub with our full 238-line implementation (full/shared indexer
handling), in place, with a one-time `.orig` backup.
python dist/install_glm_dsa_patch.py # patch every install found
python dist/install_glm_dsa_patch.py --dry-run # show targets, change nothing
python dist/install_glm_dsa_patch.py --revert # restore the .orig stubs
After patching, FULLY QUIT and reopen LM Studio so the backend reloads the engine.
"""
import argparse
import glob
import os
import shutil
import sys
HERE = os.path.dirname(os.path.abspath(__file__))
PATCH = os.path.join(HERE, "glm_moe_dsa.py")
REL = os.path.join("mlx_lm", "models", "glm_moe_dsa.py")
def targets():
found = set()
home = os.path.expanduser("~")
# scan EVERY common location an mlx_lm install may live, so we patch them ALL on this machine
# (LM Studio, Ollama, conda/venv/virtualenv, project venvs, homebrew/usr-local/framework pythons)
for g in [
home + "/.lmstudio/**/site-packages/" + REL, # LM Studio's vendored engines
home + "/.ollama/**/site-packages/" + REL, # Ollama (if it vendors mlx_lm)
home + "/miniconda3/envs/*/lib/python*/site-packages/" + REL,
home + "/anaconda3/envs/*/lib/python*/site-packages/" + REL,
home + "/.conda/envs/*/lib/python*/site-packages/" + REL,
home + "/.virtualenvs/*/lib/python*/site-packages/" + REL,
home + "/.venv/lib/python*/site-packages/" + REL,
home + "/*/.venv/lib/python*/site-packages/" + REL, # project venvs under ~
"/opt/homebrew/lib/python*/site-packages/" + REL,
"/usr/local/lib/python*/site-packages/" + REL,
"/Library/Frameworks/Python.framework/Versions/*/lib/python*/site-packages/" + REL,
]:
found.update(glob.glob(g, recursive=("**" in g)))
# plus the mlx_lm importable in THIS interpreter (pip/venv)
try:
import mlx_lm
found.add(os.path.join(os.path.dirname(mlx_lm.__file__), "models", "glm_moe_dsa.py"))
except Exception: # noqa: BLE001
pass
return sorted(p for p in found if os.path.exists(os.path.dirname(p)))
# The deepseek_v32.py MoE fix that unblocks gradient-based RL (GRPO) on the
# quantized MoE: the routed expert indices are non-differentiable (GatherQMM VJP),
# so they must be stop_gradient'd. Targeted, idempotent patch.
DSV32_OLD = "inds = mx.argpartition(-scores, kth=k - 1, axis=-1)[..., :k]"
DSV32_NEW = ("inds = mx.stop_gradient(mx.argpartition(-scores, kth=k - 1, axis=-1)[..., :k])"
" # stop_gradient: MoE top-K indices non-diff (GatherQMM VJP); needed for GRPO")
def patch_dsv32(glm_target, dry_run=False, revert=False):
"""Patch deepseek_v32.py (same models/ dir as glm_moe_dsa.py). Idempotent;
backs up .orig. Returns a status string or None if the file isn't there."""
d = os.path.join(os.path.dirname(glm_target), "deepseek_v32.py")
if not os.path.exists(d):
return None
if revert:
if os.path.exists(d + ".orig"):
shutil.copy(d + ".orig", d)
return "reverted"
return None
src = open(d).read()
if "stop_gradient(mx.argpartition(-scores" in src:
return "already"
if DSV32_OLD not in src:
return "pattern-not-found"
if dry_run:
return "would-patch"
if not os.path.exists(d + ".orig"):
shutil.copy(d, d + ".orig")
open(d, "w").write(src.replace(DSV32_OLD, DSV32_NEW))
return "patched"
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--dry-run", action="store_true")
ap.add_argument("--revert", action="store_true")
args = ap.parse_args()
if not os.path.exists(PATCH):
sys.exit(f" [stop] bundled fix not found: {PATCH}")
patch_src = open(PATCH).read()
tg = targets()
if not tg:
print(" no mlx_lm installs found (LM Studio not installed, no venv?).")
return
changed = 0
for t in tg:
tag = "lmstudio" if ".lmstudio" in t else "mlx_lm"
if args.revert:
if os.path.exists(t + ".orig"):
shutil.copy(t + ".orig", t)
print(f" [revert {tag}] {t}")
changed += 1
else:
print(f" [skip {tag}: no .orig] {t}")
continue
already = os.path.exists(t) and open(t).read() == patch_src
if already:
print(f" [ok {tag}: already patched] {t}")
continue
print(f" [{'would patch' if args.dry_run else 'PATCH'} {tag}] {t}")
if args.dry_run:
continue
if not os.path.exists(t + ".orig"): # back up the stub once
shutil.copy(t, t + ".orig")
shutil.copy(PATCH, t)
changed += 1
# also apply the deepseek_v32.py MoE stop_gradient fix (GRPO/RL portability)
for t in tg:
st = patch_dsv32(t, args.dry_run, args.revert)
if st in ("patched", "reverted", "would-patch"):
print(f" [dsv32 {st}] {os.path.join(os.path.dirname(t), 'deepseek_v32.py')}")
if st in ("patched", "reverted"):
changed += 1
elif st == "pattern-not-found":
print(f" [dsv32 SKIP: line not found — different mlx_lm version] "
f"{os.path.join(os.path.dirname(t), 'deepseek_v32.py')}")
print(f"\n {'(dry-run) ' if args.dry_run else ''}{changed} file(s) "
f"{'to change' if args.dry_run else 'changed'}.")
if changed and not args.dry_run and not args.revert:
print(" -> FULLY QUIT and reopen LM Studio so it reloads the patched engine.")
if __name__ == "__main__":
main()