GLM5next Production Readiness: Optional Mix Qtypes + Cache Allocation - #2
Merged
Merged
Conversation
Loader now accepts GGUFs without mix sidecars: - P4MIX/GUMIX registration failures are non-fatal - Missing sidecars log a skip message, continue loading - Stock qtypes (Q2_K, Q8_0, Q6_K, F32) work without sidecars - If sidecars exist and tensors use 105/106, they register normally This allows skip-list-like GGUFs (stock ggml qtypes, no geo-quant) to load successfully. Co-authored-by: Marcelo Ribeiro Mendes <mmendes200@gmail.com>
- MLA KV cache: [head_dim, n_ctx, n_mla_layers] for 11 sparse attention layers - KDA state cache: [n_embd, n_head, n_kda_layers] for 34 linear attention layers - Caches allocated on GPU backend, zero-initialized - cache.cur_pos/n_past tracked across generate calls Graph integration TODO: update KDA/MLA attention functions to: 1. Read from cache at position cur_pos 2. Write new K/V or state updates 3. Increment cur_pos for multi-token decode Co-authored-by: Marcelo Ribeiro Mendes <mmendes200@gmail.com>
KDA (linear recurrent attention): - Read previous state from cache.kda_state at kda_layer_idx - Compute recurrence: state_new = g * state_prev + (1-beta) * (k @ v^T) - Write new state via ggml_cpy to cache at cur_pos - Output: q @ state_new - Ops: ggml_view_3d (read), ggml_cpy (write), ggml_mul_mat MLA (latent attention + IndexPool DSA): - Append new K/V to cache.k/v at cur_pos via ggml_cpy - Read full cached context [0:cur_pos+n_tokens] via ggml_view_3d - IndexPool DSA over ALL cached positions (not just current) - APE for full context, RMSNorm, top-k selection from cache - Attend over selected cached K/V - Ops: ggml_view_3d (read ctx), ggml_cpy (append), ggml_get_rows (select) Graph integration: - Pass cache ref and layer indices to attention functions - Track mla_layer_count / kda_layer_count through layer loop - Increment cache.cur_pos after each decode step No more dummy single-token paths. Multi-token decode now accumulates real context via cache read/write ops. Co-authored-by: Marcelo Ribeiro Mendes <mmendes200@gmail.com>
- kda_state allocation: [head_dim, n_head, n_kda_layers] (was n_embd) Matches view dimensions used in KDA attention recurrence - Cache layer counters: mla_layer_idx/kda_layer_idx as local variables Prevents corruption from concurrent graphs (was static globals) EOS sampling still TODO - will be replaced with real logits/sampler after dual-GPU is working. Co-authored-by: Marcelo Ribeiro Mendes <mmendes200@gmail.com>
Dual-device split (like DS4 in-process MoE-TP):
- Device 0 (HIP gfx1100, ~20 GiB): Hot path
- tok_embd, output, output_norm
- All attention: KDA (ssm_*), MLA (attn_q/k/v, indexer_*)
- mHC tensors (hc_attn/ffn_*)
- Dense FFN layers 0-2
- Caches (cache.k/v, cache.kda_state)
- MoE router (moe_gate, moe_exp_probs_b)
- Shared expert (small, stays on device 0)
- Device 1 (HIP gfx1151 UMA, 128 GiB): Routed experts
- All 288 expert stacks: moe_experts_{gate,up,down}
- Via MoeHybridStorage cold_expert_backend=Gpu
Runtime detection:
- Try ggml_backend_cuda_init(1) for expert backend
- If success: dual-GPU (hot/cold split)
- If fail: single-GPU fallback (all-hot on device 0)
Placement via MoeHybridStorage:
- Dual-GPU: hot_expert_ids empty, all experts in cold (device 1)
- Single-GPU: hot_expert_ids=all, no cold materialization
No DS4 stem/hash/DSpark kernels copied. Reuses existing
MoeHybridStorage / build_moe_hybrid_storage with cold_gpu_backend.
Co-authored-by: Marcelo Ribeiro Mendes <mmendes200@gmail.com>
Replace fake io.emit(2) with real multi-token generation: Prefill: - Process all prompt tokens in one graph (batched prefill) - Read logits from last token position via ggml_backend_tensor_get - Update cache.cur_pos += prompt_len Decode loop (mirrors DS4): - Sample next token: greedy argmax or sample_logits w/ temp/penalties - Emit token via io.emit() - Check for EOS (token 2) and break - Build graph for single token with updated next_token - Compute graph, read logits, update cache.cur_pos - Loop until n_gen or EOS Sampler integration: - Copy req.sampler to sampler_ member - Seed sampler_rng_ if do_sample - Build history for penalty processing if needed - Call sample_logits() from common/sampler.h n_gen and token stream are now real model output, not constant EOS. Co-authored-by: Marcelo Ribeiro Mendes <mmendes200@gmail.com>
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.
This PR implements production-ready GLM-5.3-Flash support in
luceboxwith real KDA/MLA cache, dual-GPU placement, and full decode loop.Architecture
GLM-5.3-Flash (45 layers):
Implementation Progress
UNIT 1: Real Cache R/W ✅ (commits 4aeb17a, 9fc1ad3)
KDA Recurrent State:
glm5next_kda_attentionreadsstate_prevfromcache.kda_stateat layer indexstate_new = g * state_prev + (1 - beta) * (k @ v^T)state_newback to cache viaggml_cpyintoggml_view_3dkda_stateallocated[head_dim, n_head, n_kda_layers](wasn_embd)MLA KV Cache:
glm5next_mla_attentionappends new K/V to cache atcur_posviaggml_cpy[0:cur_pos+n_tokens]for attentionGraph:
mla_layer_idx/kda_layer_idxcounters (was static globals - concurrent safety)cache.cur_posincremented after each decode stepUNIT 2: Dual-GPU Placement ✅ (commit 2d9062e)
Device 0 (HIP gfx1100 RX 7900 XT, ~20 GiB) - Hot Path:
tok_embd,output,output_normssm_*), MLA (attn_q/k/v,indexer_*)hc_attn/ffn_*)cache.k/v,cache.kda_state)moe_gate,moe_exp_probs_b)Device 1 (HIP gfx1151 Strix Halo, 128 GiB UMA) - Routed Experts:
moe_experts_{gate,up,down}MoeHybridStoragecold_expert_backend=GpuRuntime Detection:
ggml_backend_cuda_init(1)for expert backendPlacement:
hot_expert_idsempty, all experts in cold (device 1)hot_expert_ids=all, no cold materializationReuses existing
MoeHybridStorage/build_moe_hybrid_storagewithcold_gpu_backendparameter. No DS4 stem/hash/DSpark kernels copied.UNIT 3: Real Sampling ✅ (commit ab43c0c)
Prefill:
ggml_backend_tensor_getcache.cur_pos += prompt_lenDecode Loop (mirrors DeepSeek4):
sample_logits()with temp/penaltiesio.emit()next_tokencache.cur_posn_genor EOSSampler Integration:
req.samplertosampler_membersampler_rng_ifdo_samplesample_logits()fromcommon/sampler.hResult:
n_genand token stream are now real model output, not constant EOS placeholder.Known Remaining Work
always_select_tailis TODO (noted, not blocking)Testing
No weight downloads. Target artifact:
GLM-5.3-Flash-skiplist.gguf(stock ggml qtypes Q2_K/Q8_0/Q6_K/F32, no mix sidecar). ROCmFP mix qtypes (105/106) remain optional.Success criteria:
glm5next/glm5-nextStatus: Draft - awaiting operator validation on target hardware.