glm5_next: support GLM-5.3-Flash (hybrid KDA + DSA, mHC, NVFP4 expert offload) - #270
Open
Cerynitius wants to merge 5 commits into
Open
glm5_next: support GLM-5.3-Flash (hybrid KDA + DSA, mHC, NVFP4 expert offload)#270Cerynitius wants to merge 5 commits into
Cerynitius wants to merge 5 commits into
Conversation
…FP4 experts) 320B/A18B natively-multimodal MoE (text tower only): 34 KDA linear-attention layers + 11 MLA/DSA sparse-attention layers (NoPE throughout), Manifold- Constrained Hyper-Connections, 288-expert top-8 routing with clamped swiglu. Includes the hotness-driven resident/offload expert split (FREETOKEN_GLM5_RESIDENT_LAYERS keeps chosen layers' experts on the GPU as model weights so a 157 GiB host can pin the rest), optional per-row FP8 for the non-expert projections, and inert MTP scaffolding (off by default). The three fused Triton kernels (KDA gate math, mHC pre-norm, router epilogue) match the eager chains to 1 ulp; router expert selection is id-identical to torch.topk on 200 random batches.
…nd selection Plumbing GLM-5.3-Flash needs from the shared GLM/DSA stack: rotary_dim=0 guards (NoPE) in attention and the sparse kernels, dense layer_ids remapping so hybrid models only allocate latent slabs for their MLA/DSA layers, the DSA k-pool sparsity path (pooled keys score bitwise-identical to HF), and routing configs carrying swiglu_limit to the Triton NVFP4 backend (marlin/b12x hard-code plain silu and are correctly rejected).
silu(min(gate, lim)) * clamp(up, +-lim) when the limit is finite (GLM-5.3 swiglu_clamp); lim == +inf leaves every other model's path bitwise unchanged. Registers swiglu_clamp as a silu-family activation id.
…safe prefix caching) Loads the checkpoint's Glm5NextVisionModel tower behind FREETOKEN_GLM5_VISION (default off; text-only behavior is byte-identical when unset) and wires image and video input through the online serving stack. Model side: - models/glm5_next/vision.py: eager port of the 0.6B ViT (Conv3d patch embed, 24 blocks, 2x2 spatial-merge downsample, clamped-swiglu merger). Attention runs one segment per temporal unit (qwen2_vl convention). Validated stage-by-stage against the HF reference on real weights: patch embed and rotary tables bitwise-equal; per-layer drift within the bf16 kernel-noise envelope measured between HF's own sdpa and eager backends (t=1 and t=2). - models/glm5_next/image_process.py: vendored preprocessing. Images: bitwise- equal pixel_values vs Glm5NextImageProcessorPil (needs pillow). Video: PyAV decode, fps-2 sampling with even padding, paired-frame temporal patches, HF-faithful smart_resize budgets (FREETOKEN_GLM5_VIDEO_FPS / MAX_VIDEO_TOKENS / MAX_VIDEO_FRAMES / MAX_IMAGE_TOKENS knobs). - weight.py streams model.visual.* through verbatim (BF16) when enabled. Serving side: - OpenAI chat: image_url (data URI / http) and video_url content parts; Anthropic messages: base64/url image blocks. The chat template's own image/video branches emit the placeholders; the tokenize worker expands them per grid (videos expand to per-unit frame blocks with timestamps, mirroring Glm5NextProcessor.replace_video_token). - Pixels ride the ZMQ msgpack codec as raw fp32 bytes; the scheduler process (which owns the GPU) encodes them at admission and reuses the existing mm_embeds scatter rails. - Prefix caching is made media-safe instead of skipped: image-span placeholder ids are replaced by a per-image pixel blake2b hash (negative id range) in the radix cache keys, so identical text+media prefixes hit while different media diverges at the span's first token; covered leading spans slice the scatter rows, and generated tokens splice back into the key stream. The offline mm path (no key ids) keeps the previous cache skip. Verified end-to-end on an RTX PRO 6000 Blackwell 96 GB serving GLM-5.3-Flash-NVFP4: image shapes/colors/positions, counting, two-image comparison, text-in-image reading on both APIs; synthetic-clip motion direction, start/end positions and colors; same-image repeat TTFT 3.8 -> 1.0 s and image-conversation turn-2 2.8 -> 1.1 s under --cache-type radix with no false hits across different images and no page-accounting drift; text-only paths regression-free.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds serving support for zai-org/GLM-5.3-Flash (
model_type: glm5_next) — Z.ai's 320B / 18B-active MoE and the first GLM to combine sparse and linear attention — targeting single-GPU hosts with expert offload:models/glm5_nextpackage: 34 KDA linear-attention layers (fla-corechunk_kda/fused_recurrent_kda, decode passescu_seqlensso batched single-token requests keep per-request state), 11 MLA/DSA sparse-attention layers, Manifold-Constrained Hyper-Connections (the DSV4 kernels, plus a weightless meanhc_head), 288-expert top-8 routing, and the MTP head skipped at load (FREETOKEN_GLM5_MTP=1scaffolding is inert without engine hooks)rotary_dim=0guards in the shared GLM/DSA attention andD_R=0constexpr branches in the sparse kernelsindex_kpool_*weights): pooled keys reuse the decode-logits kernel over strided rows and score bitwise-identical to the HF referencelayer_idsremapping so only the 11 MLA/DSA layers allocate latent slabs (without it the 34 KDA layers each claimed one)swiglu_limit: 10.0): configs carrying the limit route to the Triton NVFP4 expert backend (marlin/b12xhard-code plain silu and are rejected), and the CPU MoE epilogue appliessilu(min(gate, lim)) * clamp(up, ±lim)—lim == +infleaves every other model bitwise unchangedFREETOKEN_GLM5_RESIDENT_LAYERS=3-6,8-11keeps the named layers' experts on the GPU as model weights (no host bank, no cache slots), cutting the host pin from ~163 GiB to ~129 GiB so a 157 GiB host fits;num_moe_layersexcludes them for every bank/cache consumertorch.topkon 200 random batchesFREETOKEN_GLM5_ATTN_FP8/_MLP_FP8/_KDA_FP8, all default off)Validation
Validated on a single RTX PRO 6000 Blackwell Workstation Edition (96 GB), 157 GiB host RAM, PCIe Gen5 x16; torch
2.11.0+cu130, triton3.6.0, CUDA 13.0:LibertAIDAI/GLM-5.3-Flash-NVFP4(181 GiB experts) served withFREETOKEN_GLM5_RESIDENT_LAYERS=3-6,8-11,--moe-cache-auto, 256K--max-seq-len-override: greedy arithmetic and Chinese-QA probes returned the expected answers; an 8K-token needle prompt recalled the planted passphrase; single-stream decode at this branch's defaults (BF16 non-expert weights) ran 23.5–23.7 tok/spython -m compileall -q pythonpasses; every patch applies cleanly onto currentmainScope
Serving-throughput work from the same effort is intentionally left out to keep this reviewable: speculative expert prefetch, short-prompt on-demand prefill, decode-GEMV retuning, and the MTP speculative-decoding engine hooks (measured net-negative on PCIe-bound offload) are follow-up material. The vision tower is not loaded (text-only). Defaults are conservative: no resident split, no FP8, no MTP unless the environment variables opt in.
Tuned companion
The defaults here are deliberately conservative. The full tuning layer from the same effort is maintained separately as a patch overlay in Cerynitius/freetoken-ox-boost; on the same single-GPU box it takes single-stream decode from this branch's 23.7 tok/s (BF16 defaults) to ~35 tok/s, 2-way concurrent aggregate to 44.9, and 10-token TTFT to 0.59 s.
What it adds on top of this PR: the non-expert FP8 switches enabled by default, speculative expert prefetch (layer L+1's gate scored a layer early, +8%), short-prompt on-demand prefill (TTFT 3.5x), decode-GEMV retuning (marlin tile config, +4.5%), an M-tiled FP8 GEMV for decode micro-batches (2-way aggregate +13%), and a 2-slot 256K KV pool that frees ~10 GiB for the expert cache (~84% hit rate).
What it trades for that: FP8 numerics on the non-expert projections by default (MMLU-100 spot-check held at 94 vs 89 for BF16, but the numerics are not bitwise), epsilon-level reduction-order changes in the retuned GEMVs, decode-GEMV tile defaults retuned for one card (RTX PRO 6000) rather than swept across GPUs, prefetch/prefill hooks in the shared offload serving path, and a KV-capacity-for-cache default that assumes the 2x256K working set. Those trade-offs are why this PR keeps upstream defaults untouched.