Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions unsloth_zoo/llama_cpp.py
Original file line number Diff line number Diff line change
Expand Up @@ -2276,10 +2276,17 @@ def convert_to_gguf(
with open(config_path, "r", encoding = "utf-8") as f:
config_file = json.load(f)

# Strip MTP / nextn config keys so the downstream convert_hf_to_gguf.py
# doesn't inflate block_count / inject nextn_predict_layers.
# Preserve MTP / nextn config so the downstream convert_hf_to_gguf.py keeps
# the extra nextn block (block_count += mtp_num_hidden_layers) and emits the
# nextn tensors (blk.N.nextn.*). gguf-py has full nextn support, so the
# leftover `mtp.*` weights remap cleanly via _Qwen35MtpMixin instead of being
# forced into a phantom out-of-range layer. Stripping mtp_num_hidden_layers
# shrank block_count to num_hidden_layers, so `mtp.fc` -> `model.layers.<N>.eh_proj`
# pointed at a layer index that no longer existed, raising
# "Can not map tensor ...eh_proj" for Qwen3.5/3.6 MTP checkpoints.
# Only strip Unsloth's internal marker, never the real MTP config.
_changed = False
for _key in ("mtp_num_hidden_layers", "unsloth_fixed_mtp"):
for _key in ("unsloth_fixed_mtp",):

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve MTP only when tensors are present

When input_folder is a saved/fine-tuned Qwen checkpoint whose config.json still advertises mtp_num_hidden_layers but the exported safetensors only contain the base num_hidden_layers, this loop no longer removes that stale key. The downstream converter will therefore inflate block_count/nextn metadata for a layer that has no weights (the MLX path has _sync_gguf_nextn_layer_config specifically to handle this mismatch), so direct convert_to_gguf() callers regress from a convertible base model to a failed or unloadable GGUF unless they manually scrub the config first.

Useful? React with 👍 / 👎.

if config_file.pop(_key, None) is not None:
_changed = True
_tc = config_file.get("text_config")
Expand Down
Loading