Skip to content

Commit 88bfee1

Browse files
model: add GLM 5.2 Indexer support (#25407)
* Start building graph - reuse deepseek32 * Enable kv cache and rotation for glm_dsa architecture Just follow Deepseek 3.2 for now. * Reuse prev_top_k for "shared" indexer layers * GLM 5.2 uses LLAMA_ROPE_TYPE_NORM for the indexer. This is transformers' `apply_rotary_pos_emb_interleave` * Default indexer types to GLM pattern 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. * Save indexer types to gguf, restore on load * Use ggml_lightning_indexer when cparams.fused_lid Co-authored-by: fairydreaming <166155368+fairydreaming@users.noreply.github.com> * GLM 5 and 5.1 use full indexers Co-authored-by: fairydreaming <166155368+fairydreaming@users.noreply.github.com> * Fix indentation * Ensure array is zero-filled * Prefer explicit std::fill * Assert prev_top_k exists for shared indexer --------- Co-authored-by: fairydreaming <166155368+fairydreaming@users.noreply.github.com>
1 parent 95a923a commit 88bfee1

12 files changed

Lines changed: 426 additions & 4 deletions

File tree

conversion/glm.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,9 @@ def set_gguf_parameters(self):
237237
self.gguf_writer.add_indexer_head_count(self.hparams["index_n_heads"])
238238
self.gguf_writer.add_indexer_key_length(self.hparams["index_head_dim"])
239239
self.gguf_writer.add_indexer_top_k(self.hparams["index_topk"])
240+
if (indexer_types := self.hparams.get("indexer_types")) is not None:
241+
indexer_types = [t == "full" for t in indexer_types]
242+
self.gguf_writer.add_indexer_types(indexer_types)
240243

241244

242245
@ModelBase.register("SolarOpenForCausalLM")

gguf-py/gguf/constants.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ class Indexer:
200200
HEAD_COUNT = "{arch}.attention.indexer.head_count"
201201
KEY_LENGTH = "{arch}.attention.indexer.key_length"
202202
TOP_K = "{arch}.attention.indexer.top_k"
203+
TYPES = "{arch}.attention.indexer.types"
203204

204205
class HyperConnection:
205206
COUNT = "{arch}.hyper_connection.count"

gguf-py/gguf/gguf_writer.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -793,6 +793,10 @@ def add_indexer_key_length(self, length: int) -> None:
793793
def add_indexer_top_k(self, top_k: int) -> None:
794794
self.add_uint32(Keys.Attention.Indexer.TOP_K.format(arch=self.arch), top_k)
795795

796+
def add_indexer_types(self, value: Sequence[bool]) -> None:
797+
key = Keys.Attention.Indexer.TYPES.format(arch=self.arch)
798+
self.add_array(key, value)
799+
796800
def add_max_alibi_bias(self, bias: float) -> None:
797801
self.add_float32(Keys.Attention.MAX_ALIBI_BIAS.format(arch=self.arch), bias)
798802

src/llama-arch.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ static const std::map<llm_kv, const char *> LLM_KV_NAMES = {
253253
{ LLM_KV_ATTENTION_INDEXER_HEAD_COUNT, "%s.attention.indexer.head_count" },
254254
{ LLM_KV_ATTENTION_INDEXER_KEY_LENGTH, "%s.attention.indexer.key_length" },
255255
{ LLM_KV_ATTENTION_INDEXER_TOP_K, "%s.attention.indexer.top_k" },
256+
{ LLM_KV_ATTENTION_INDEXER_TYPES, "%s.attention.indexer.types" },
256257
{ LLM_KV_ATTENTION_OUTPUT_GROUP_COUNT, "%s.attention.output_group_count" },
257258
{ LLM_KV_ATTENTION_OUTPUT_LORA_RANK, "%s.attention.output_lora_rank" },
258259
{ LLM_KV_ATTENTION_COMPRESS_ROPE_FREQ_BASE, "%s.attention.compress_rope_freq_base" },

src/llama-arch.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@ enum llm_kv {
258258
LLM_KV_ATTENTION_INDEXER_HEAD_COUNT,
259259
LLM_KV_ATTENTION_INDEXER_KEY_LENGTH,
260260
LLM_KV_ATTENTION_INDEXER_TOP_K,
261+
LLM_KV_ATTENTION_INDEXER_TYPES,
261262
LLM_KV_ATTENTION_OUTPUT_GROUP_COUNT,
262263
LLM_KV_ATTENTION_OUTPUT_LORA_RANK,
263264
LLM_KV_ATTENTION_COMPRESS_ROPE_FREQ_BASE,

src/llama-hparams.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,14 @@ bool llama_hparams::is_mla() const {
248248
return n_embd_head_k_mla_impl != 0 && n_embd_head_v_mla_impl != 0;
249249
}
250250

251+
bool llama_hparams::is_indexer_full(uint32_t il) const {
252+
if (il < n_layer()) {
253+
return is_indexer_full_impl[il];
254+
}
255+
256+
GGML_ABORT("%s: il (%u) out of bounds (n_layer: %u)\n", __func__, il, n_layer());
257+
}
258+
251259
uint32_t llama_hparams::n_embd_head_k_mla() const {
252260
return is_mla() ? n_embd_head_k_mla_impl : n_embd_head_k();
253261
}

src/llama-hparams.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,10 @@ struct llama_hparams {
227227
uint32_t indexer_head_size = 0;
228228
uint32_t indexer_top_k = 0;
229229

230+
// Indexer is "full" (1) or "shared" (0)
231+
// Shared indexers reuse top-k from previous full layer
232+
std::array<uint32_t, LLAMA_MAX_LAYERS> is_indexer_full_impl;
233+
230234
// DeepSeek-V4
231235
uint32_t dsv4_o_group_count = 0;
232236
uint32_t dsv4_o_lora_rank = 0;
@@ -302,6 +306,8 @@ struct llama_hparams {
302306

303307
bool is_swa(uint32_t il) const;
304308

309+
bool is_indexer_full(uint32_t il) const;
310+
305311
void set_recr_pattern(uint32_t n_pattern, bool dense_first = false);
306312

307313
// whether or not the given layer is recurrent (for hybrid models)

src/llama-kv-cache.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ llama_kv_cache::llama_kv_cache(
323323
hparams.n_embd_head_k() % 64 == 0;
324324

325325
// always create Hadamard rotation tensors for DeepSeek lightning indexers
326-
if ((model.arch == LLM_ARCH_DEEPSEEK32 || model.arch == LLM_ARCH_DEEPSEEK4) &&
326+
if ((model.arch == LLM_ARCH_DEEPSEEK32 || model.arch == LLM_ARCH_DEEPSEEK4 || model.arch == LLM_ARCH_GLM_DSA) &&
327327
hparams.n_embd_head_k_full == hparams.indexer_head_size) {
328328
attn_rot_k = true;
329329
}

src/llama-model-saver.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,7 @@ void llama_model_saver::add_kv_from_model() {
281281
add_kv(LLM_KV_ATTENTION_INDEXER_HEAD_COUNT, hparams.indexer_n_head);
282282
add_kv(LLM_KV_ATTENTION_INDEXER_KEY_LENGTH, hparams.indexer_head_size);
283283
add_kv(LLM_KV_ATTENTION_INDEXER_TOP_K, hparams.indexer_top_k);
284+
add_kv(LLM_KV_ATTENTION_INDEXER_TYPES, hparams.is_indexer_full_impl, true);
284285
add_kv(LLM_KV_ATTENTION_RECURRENT_LAYERS, hparams.is_recr_impl, true);
285286

286287
const float rope_scaling_factor = hparams.rope_freq_scale_train == 1.0f ? 0.0f : 1.0f/hparams.rope_freq_scale_train;

src/llama-model.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1129,6 +1129,7 @@ void llama_model_base::load_hparams(llama_model_loader & ml) {
11291129
std::fill(hparams.rope_sections.begin(), hparams.rope_sections.end(), 0);
11301130
std::fill(hparams.is_swa_impl.begin(), hparams.is_swa_impl.end(), 0);
11311131
std::fill(hparams.is_recr_impl.begin(), hparams.is_recr_impl.end(), llm_arch_is_recurrent(ml.get_arch()) ? 1 : 0);
1132+
std::fill(hparams.is_indexer_full_impl.begin(), hparams.is_indexer_full_impl.end(), 0);
11321133

11331134
std::fill(hparams.xielu_alpha_n.begin(), hparams.xielu_alpha_n.end(), 0.0f);
11341135
std::fill(hparams.xielu_alpha_p.begin(), hparams.xielu_alpha_p.end(), 0.0f);
@@ -2065,6 +2066,7 @@ llama_memory_i * llama_model::create_memory(const llama_memory_params & params,
20652066
res = nullptr;
20662067
} break;
20672068
case LLM_ARCH_DEEPSEEK32:
2069+
case LLM_ARCH_GLM_DSA:
20682070
{
20692071
res = new llama_kv_cache_dsa(
20702072
*this,

0 commit comments

Comments
 (0)