Skip to content

GLM 5.2 Indexer support#25407

Open
pcuenca wants to merge 6 commits into
ggml-org:masterfrom
pcuenca:glm-dsa-indexer
Open

GLM 5.2 Indexer support#25407
pcuenca wants to merge 6 commits into
ggml-org:masterfrom
pcuenca:glm-dsa-indexer

Conversation

@pcuenca

@pcuenca pcuenca commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Overview

Adds indexer support to GLM 5.2. Currently, indexer tensors are loaded when present, but ignored. If accepted, this PR would in my understanding complete the implementation of GLM 5.2.

The implementation just copies the graph from Deepseek 3.2 and applies the GLM 5.2 changes:

  • Only "full" indexers compute top_k, "shared" ones reuse top_k from the previous full layer. In Deepseek 3.2, all indexers are "full".
  • The indexer uses interleaved rope, instead of the neox-style used by Deepseek 3.2.

Additional information

  • Existing unsloth checkpoints work without conversion. They contain indexer weights at every layer, but only those in "full" indexers are used.
  • Here's another checkpoint, quantized using this PR, that can be used for testing purposes. It uses unsloth's imatrix, and preserves indexer weights in Q8_0.
  • I verified that generations in greedy mode match the previous implementation for short sequences (indexers are essentially a no-op the first 2048 tokens). I have verified that long sequences remain coherent, but have not compared KLD against a reference implementation.
  • I was a bit surprised to find decoding speed to be much slower than with the previous (deepseek2-based) implementation. I haven't investigated the reason yet, if there are ways to make it faster, or if it happens across all sequence lengths.

Requirements

  • I have read and agree with the contributing guidelines
  • AI usage disclosure: YES, as follows:
    • All code, debugging, and testing performed by a human 🙋‍♂️
    • PR description written by the same person
    • AI was used to ask about the codebase, navigate it, find patterns, identify idiomatic approaches.

pcuenca added 6 commits July 5, 2026 19:17
This is transformers' `apply_rotary_pos_emb_interleave`
Previous converted GGUFs like https://huggingface.co/unsloth/GLM-5.2-GGUF write indexer weights to _all_ layers, even if they are only required for "full" types. This PR relies on a new key "%s.attention.indexer.types"; if absent, it will use the default GLM 5.2 schedule as defined in https://huggingface.co/zai-org/GLM-5.2/blob/main/config.json#L26.

Note that conversion is not saving this key yet.
@pcuenca pcuenca requested review from CISC and ggerganov as code owners July 7, 2026 14:18
Comment thread src/models/glm-dsa.cpp
#include "llama-kv-cache-dsa.h"

// https://huggingface.co/zai-org/GLM-5.2/blob/main/config.json#L26
const std::array<uint32_t, LLAMA_MAX_LAYERS> GLM_DSA_DEFAULT_INDEXER_TYPES = {

@pcuenca pcuenca Jul 7, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I considered the alternative to store just two numbers to represent the frequency of full indexers, and the number of prefix full indexers before the regular pattern. I decided towards the array because:

  • There are also precedents in the codebase for irregular patterns.
  • Deepseek 3.2 could be included in this pattern via get_key_or_arr with a single scalar (all DS indexers are "full").

Comment thread src/models/glm-dsa.cpp

switch (hparams.n_layer()) {
case 79: type = LLM_TYPE_744B_A40B; break;
case 78: type = LLM_TYPE_744B_A40B; break;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a previous inoffensive bug introduced during the n_layer refactor; n_layer() excludes MTP layers so this should be 78.

Comment thread src/models/glm-dsa.cpp
return std::make_unique<graph>(*this, params);
}

llama_model_glm_dsa::graph::graph(const llama_model & model, const llm_graph_params & params) :

@pcuenca pcuenca Jul 7, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same graph as Deepseek v3.2, except for the two differences noted in the PR description.

I didn't want to touch other modules, but we can generalize these changes into Deepseek's and reuse the graph here.

@github-actions github-actions Bot added model Model specific conversion labels Jul 7, 2026
@am17an

am17an commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

As I understand GLM 5.2 uses the same lighting indexer as DS3.2 but the top-k is shared across 4 layers. If this is correct then #24231 should be used

@pcuenca

pcuenca commented Jul 7, 2026

Copy link
Copy Markdown
Contributor Author

As I understand GLM 5.2 uses the same lighting indexer as DS3.2 but the top-k is shared across 4 layers. If this is correct then #24231 should be used

Yes, indeed, thanks for linking to it, I had missed the recent activity there.

My understanding is that #24231 is about creating a new op that we can use from both the Deepseek and gml-dsa modeling files when it's merged, and when cuda / metal implementations are added. This PR (mine) is about contributing the remaining aspects of the architecture that were deferred from the initial GLM 5.2 implementation, and that are mostly available in the deepseek 3.2 one.

But I'm new to the project, happy to coordinate with the team as necessary!

@am17an

am17an commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Yes, my comment is for your awareness w.r.t. to the lightning indexer and not anything else different for GLM5.2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

conversion model Model specific

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants