Skip to content

convert : fix Granite Switch block_count for MultiSwitch checkpoints - #30621

Merged
CISC merged 2 commits into
ggml-org:masterfrom
planetf1:fix/graniteswitch-blockcount
Oct 15, 2026
Merged

CISC merged 2 commits into
ggml-org:masterfrom
planetf1:fix/graniteswitch-blockcount

Conversation

@planetf1

@planetf1 planetf1 commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Overview

GGUF files converted from newer Granite Switch checkpoints fail to load with the error:

E llama_model_load: error loading model: check_tensor_dims: tensor 'blk.40.attn_norm.weight' not found

The conversion itself succeeds and writes every real decoder layer.

Unfortunate one metadata value is wrong: GraniteSwitchModel assumes the checkpoint's weightless switch owns exactly one KV cache slot and sets block_count = num_hidden_layers - 1.

The newer switch generation (MultiSwitch) owns two slots, so num_hidden_layers counts real layers plus two, and the stored graniteswitch.block_count comes out one too high. So the loader asks for a block that was never written.

This PR derives the block count from the model.layers.N tensors actually present in the checkpoint instead of assuming a fixed offset. That is the count the runtime already expects: granite-switch.cpp sizes the model type from it and adds the router layer beyond n_layer at load time.

Affected are newer-generation Granite Switch checkpoints, for example ibm-granite/granite-switch-4.1-3b-preview. Older SingleSwitch-generation checkpoints convert identically before and after this change.

Fixes #30617

Additional information

  • Without the patch, the 3b preview converts but llama-server fails to load it with the error above; with the patch it loads.
  • An older SingleSwitch-generation revision of the same repo converts to a byte-identical GGUF on master and with this patch.
  • Tensor names and shapes match the set derived from granite-switch.cpp's create_tensor calls.
  • The cache-slot count comes from the Granite Switch reference implementation (generative-computing/granite-switch, num_cache_layers), which builds num_hidden_layers - num_cache_layers decoder layers.
  • A smaller fix (block_count -= 2 if "ms_code_m" in self.hparams else 1) also works today but breaks again the next time the engine's slot budget changes.

NOTE that the flake pre-commit was skipped (SKIP=flake8) due to dependency issues/crashes

Requirements

  • I have read and agree with the contributing guidelines
  • AI usage disclosure: Yes. AI has been used to identify the bug when testing models, initial drafts of issue, pr texts and generate the code fix, which then had manual review and minor edits

Signed-off-by: Nigel Jones <jonesn@uk.ibm.com>
@planetf1
planetf1 marked this pull request as ready for review October 15, 2026 18:44
@planetf1
planetf1 requested a review from CISC as a code owner October 15, 2026 18:44
@taronaeo

Copy link
Copy Markdown
Member

cc: @gabe-l-hart

@gabe-l-hart gabe-l-hart left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

One quick comment NIT, but otherwise this looks like a good quick solution. I confirmed that the updated version of ibm-granite/granite-switch-4.1-3b-preview no longer runs after conversion on master and that this conversion change effectively fixes the hparams and no further c++ side changes are needed to work with the converted file.

Comment thread conversion/granite.py Resolved
@gabe-l-hart

Copy link
Copy Markdown
Collaborator

It's worth noting that ibm-granite/granite-switch-4.1-3b-preview was updated in-place, so older pulls of the model work with the existing conversion, but a fresh pull does not.

@gabe-l-hart

Copy link
Copy Markdown
Collaborator

Related! https://huggingface.co/blog/ibm-granite/granite-switch-4-1 (new Switch with decision adapter, guardian, and ASR baked in).

We'll be working on extending for multimodal adapters soon

Co-authored-by: Gabe Goodhart <ghart@us.ibm.com>
@CISC
CISC merged commit 59d5fad into ggml-org:master Oct 15, 2026
5 checks passed
planetf1 added a commit to planetf1/mellea that referenced this pull request Oct 16, 2026
…MultiSwitch fix

Current Granite Switch checkpoints use MultiSwitch, which reserves two cache
slots. Every llama.cpp converter up to and including v0.7.0 writes a block
count one too high for them, so the script's GGUF converted but llama-server
refused to load it (ggml-org/llama.cpp#30617). Pin the converter to build
b11675, the first with the fix (ggml-org/llama.cpp#30621).

Verified from a cold cache on the current 3b revision: the script downloads,
converts with transformers 5.20.0, and serves on a v0.6.0 llama-server; the
GGUF's block_count is 40, matching blocks 0-39, and the example and the
adapter functions run against it.

Assisted-by: Claude Code
Signed-off-by: Nigel Jones <jonesn@uk.ibm.com>
edwardyoon pushed a commit to edwardyoon/focus-llama that referenced this pull request Oct 24, 2026
…gml-org#30621)

* convert : fix Granite Switch block_count for MultiSwitch checkpoints

Signed-off-by: Nigel Jones <jonesn@uk.ibm.com>

* Update granite.py

Co-authored-by: Gabe Goodhart <ghart@us.ibm.com>

---------

Signed-off-by: Nigel Jones <jonesn@uk.ibm.com>
Co-authored-by: Gabe Goodhart <ghart@us.ibm.com>
auRose94 pushed a commit to auRose94/llama.cpp that referenced this pull request Oct 28, 2026
…gml-org#30621)

* convert : fix Granite Switch block_count for MultiSwitch checkpoints

Signed-off-by: Nigel Jones <jonesn@uk.ibm.com>

* Update granite.py

Co-authored-by: Gabe Goodhart <ghart@us.ibm.com>

---------

Signed-off-by: Nigel Jones <jonesn@uk.ibm.com>
Co-authored-by: Gabe Goodhart <ghart@us.ibm.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Eval bug: convert_hf_to_gguf: Granite Switch conversion writes block_count one too high for newer checkpoints

4 participants