From fe0f35e51779aefe0ad2b38b2d455d43200cb03f Mon Sep 17 00:00:00 2001 From: "rhyce.git" Date: Sat, 22 Aug 2026 22:51:02 +0000 Subject: [PATCH] gemma4/gguf: accept a scalar attention.head_count_kv llama.cpp writes gemma4.attention.head_count_kv as a single value when every block shares it, so parse_gguf_config raised "'int' object is not subscriptable" on the official google/gemma-4-E2B-it-qat-q4_0-gguf checkpoint. Broadcast the scalar to one entry per block before the per-layer lookups. Fixes #63 Co-Authored-By: Claude Opus 5 --- python/freetoken/models/gemma4/gguf.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/python/freetoken/models/gemma4/gguf.py b/python/freetoken/models/gemma4/gguf.py index 437822b..0b058c0 100644 --- a/python/freetoken/models/gemma4/gguf.py +++ b/python/freetoken/models/gemma4/gguf.py @@ -60,7 +60,12 @@ def g(key: str): num_layers = int(g("block_count")) hidden = int(g("embedding_length")) num_qo_heads = int(g("attention.head_count")) - kv_per_layer = g("attention.head_count_kv") # per-layer list + # Per-layer list, or a single value when every layer shares it: llama.cpp collapses + # a uniform array to a scalar, which the official gemma-4 E2B QAT q4_0 GGUF hits + # (head_count_kv == 1 for all 35 blocks). Broadcast so the indexing below holds. + kv_per_layer = g("attention.head_count_kv") + if isinstance(kv_per_layer, (int, float)): + kv_per_layer = [int(kv_per_layer)] * num_layers # True -> sliding-window (SWA) layer, False -> full attention. swa_pattern = [bool(x) for x in g("attention.sliding_window_pattern")] assert len(swa_pattern) == num_layers, "sliding_window_pattern length != block_count"