From 0b1c537326f69d46e12eb0a5cb2873f2c8cacf39 Mon Sep 17 00:00:00 2001 From: Daniel Hanchen Date: Tue, 10 Feb 2026 13:33:46 +0000 Subject: [PATCH] Patch should_convert_module on transformers 5.x for substring component matching On transformers 4.x, Unsloth patches _replace_with_bnb_linear with check_conversion_mappings which does substring matching (skip_key + "." in key_name_str). This ensures entries like "vision_tower" in llm_int8_skip_modules match module names like "model.vision_tower.vision_model.encoder.layers.0.self_attn.q_proj". On transformers 5.x, _replace_with_bnb_linear was replaced by replace_with_bnb_linear which delegates to should_convert_module. should_convert_module only uses re.match (prefix-anchored) and endswith, so "vision_tower" fails to match "model.vision_tower.*" submodules. This patch adds substring component matching (".key." in ".full_name.") to should_convert_module on 5.x, restoring parity with the 4.x behavior. Patches both the source module (quantizers_utils) and the imported reference in bitsandbytes. Result: Gemma3 4B 4-bit loading goes from 184 vision_tower "Skipping" warnings to 0. Vision tower layers correctly stay as regular Linear modules (bf16) instead of being wrapped in Linear4bit. --- unsloth_zoo/patching_utils.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/unsloth_zoo/patching_utils.py b/unsloth_zoo/patching_utils.py index 4398e83ce..ba77af906 100644 --- a/unsloth_zoo/patching_utils.py +++ b/unsloth_zoo/patching_utils.py @@ -751,6 +751,38 @@ def add_score_code(match): transformers.integrations.bitsandbytes._replace_with_bnb_linear = _unsloth_replace_with_bnb_linear pass +# Patch for transformers 5.x: should_convert_module uses re.match (prefix-anchored) +# and endswith, but does not do substring component matching. This means entries like +# "vision_tower" in llm_int8_skip_modules fail to match module names like +# "model.vision_tower.vision_model.encoder.layers.0.self_attn.q_proj". +# On 4.x, Unsloth patches _replace_with_bnb_linear with check_conversion_mappings +# (substring matching). On 5.x, _replace_with_bnb_linear doesn't exist, so we +# patch should_convert_module instead. +import transformers.quantizers.quantizers_utils as _quantizers_utils +if not hasattr(transformers.integrations.bitsandbytes, "_replace_with_bnb_linear") and \ + hasattr(_quantizers_utils, "should_convert_module") and \ + getattr(_quantizers_utils.should_convert_module, "__name__", "") != "_unsloth_should_convert_module": + + _original_should_convert_module = _quantizers_utils.should_convert_module + + def _unsloth_should_convert_module(full_name, patterns=None): + if patterns is None: + return True + should_not_convert = any( + re.match(f"{key}\\.", full_name) or + re.match(f"{key}", full_name) or + full_name.endswith(key) or + f".{key}." in f".{full_name}." + for key in patterns + ) + return not should_not_convert + + _quantizers_utils.should_convert_module = _unsloth_should_convert_module + # Also patch the imported reference in bitsandbytes module + if hasattr(transformers.integrations.bitsandbytes, "should_convert_module"): + transformers.integrations.bitsandbytes.should_convert_module = _unsloth_should_convert_module +pass + # Unsloth Zoo - Utilities for Unsloth # Copyright 2023-present Daniel Han-Chen, Michael Han-Chen & the Unsloth team. All rights reserved. #