From 7ecb049ac9d0d13525d17950dbe251e6ab5655eb Mon Sep 17 00:00:00 2001 From: Daniel Han-Chen Date: Sun, 8 Feb 2026 16:20:03 +0000 Subject: [PATCH 1/3] Make bitsandbytes optional on ROCm and add bf16 helper --- unsloth/__init__.py | 6 +++++ unsloth/import_fixes.py | 5 +++- unsloth/kernels/utils.py | 43 +++++++++++++++++++------------ unsloth/models/_utils.py | 11 ++++++-- unsloth/models/granite.py | 17 +++++++++--- unsloth/models/llama.py | 8 ++++++ unsloth/models/rl_replacements.py | 7 +++++ unsloth/save.py | 15 ++++++++--- 8 files changed, 87 insertions(+), 25 deletions(-) diff --git a/unsloth/__init__.py b/unsloth/__init__.py index 4357ad63aa..19b433a680 100644 --- a/unsloth/__init__.py +++ b/unsloth/__init__.py @@ -205,6 +205,12 @@ elif DEVICE_TYPE == "xpu": # set SUPPORTS_BFLOAT16 as torch.xpu.is_bf16_supported() SUPPORTS_BFLOAT16 = torch.xpu.is_bf16_supported() +# Backwards compatibility: some notebooks import `unsloth.is_bf16_supported`. +# Ensure it exists on all backends (HIP / XPU) and has a stable signature. +if "is_bf16_supported" not in globals(): + def is_bf16_supported(including_emulation = False): + return SUPPORTS_BFLOAT16 + # For Gradio HF Spaces? # if "SPACE_AUTHOR_NAME" not in os.environ and "SPACE_REPO_NAME" not in os.environ: import triton diff --git a/unsloth/import_fixes.py b/unsloth/import_fixes.py index 97e74dfb57..af90de1bdb 100644 --- a/unsloth/import_fixes.py +++ b/unsloth/import_fixes.py @@ -309,7 +309,10 @@ def fix_vllm_aimv2_issue(): spec = importlib.util.find_spec("vllm") if spec is None: return - vllm_version = importlib_version("vllm") + try: + vllm_version = importlib_version("vllm") + except Exception: + return if Version(vllm_version) < Version("0.10.1"): vllm_location = spec.origin if vllm_location is None: diff --git a/unsloth/kernels/utils.py b/unsloth/kernels/utils.py index 5dcc7c232c..63b1966b32 100644 --- a/unsloth/kernels/utils.py +++ b/unsloth/kernels/utils.py @@ -108,11 +108,14 @@ def calculate_settings( HAS_CUDA_STREAM = False -import bitsandbytes as bnb - -# https://github.com/bitsandbytes-foundation/bitsandbytes/pull/1330/files -HAS_CUDA_STREAM = Version(bnb.__version__) > Version("0.43.3") -get_ptr = bnb.functional.get_ptr +try: + import bitsandbytes as bnb + # https://github.com/bitsandbytes-foundation/bitsandbytes/pull/1330/files + HAS_CUDA_STREAM = Version(bnb.__version__) > Version("0.43.3") + get_ptr = bnb.functional.get_ptr +except Exception: + bnb = None + get_ptr = None if DEVICE_TYPE == "xpu": HAS_XPU_STREAM = True @@ -180,21 +183,29 @@ else: CUDA_STREAMS = tuple(CUDA_STREAMS) del _CUDA_STREAMS -# Bitsandbytes operations +# Bitsandbytes operations (optional) ctypes_c_int = ctypes.c_int ctypes_c_int32 = ctypes.c_int32 -cdequantize_blockwise_fp32 = bnb.functional.lib.cdequantize_blockwise_fp32 -cdequantize_blockwise_fp16_nf4 = bnb.functional.lib.cdequantize_blockwise_fp16_nf4 -cdequantize_blockwise_bf16_nf4 = bnb.functional.lib.cdequantize_blockwise_bf16_nf4 -if DEVICE_TYPE == "xpu": - # https://github.com/bitsandbytes-foundation/bitsandbytes/blob/c3b8de268fdb55a88f92feada23fc811a1e6877a/bitsandbytes/backends/xpu/ops.py#L115 - # for xpu, inference gemv using above link - cgemm_4bit_inference_naive_fp16 = bnb.functional.lib.cgemv_4bit_inference_fp16 - cgemm_4bit_inference_naive_bf16 = bnb.functional.lib.cgemv_4bit_inference_bf16 +if bnb is not None: + cdequantize_blockwise_fp32 = bnb.functional.lib.cdequantize_blockwise_fp32 + cdequantize_blockwise_fp16_nf4 = bnb.functional.lib.cdequantize_blockwise_fp16_nf4 + cdequantize_blockwise_bf16_nf4 = bnb.functional.lib.cdequantize_blockwise_bf16_nf4 + + if DEVICE_TYPE == "xpu": + # https://github.com/bitsandbytes-foundation/bitsandbytes/blob/c3b8de268fdb55a88f92feada23fc811a1e6877a/bitsandbytes/backends/xpu/ops.py#L115 + cgemm_4bit_inference_naive_fp16 = bnb.functional.lib.cgemv_4bit_inference_fp16 + cgemm_4bit_inference_naive_bf16 = bnb.functional.lib.cgemv_4bit_inference_bf16 + else: + cgemm_4bit_inference_naive_fp16 = bnb.functional.lib.cgemm_4bit_inference_naive_fp16 + cgemm_4bit_inference_naive_bf16 = bnb.functional.lib.cgemm_4bit_inference_naive_bf16 else: - cgemm_4bit_inference_naive_fp16 = bnb.functional.lib.cgemm_4bit_inference_naive_fp16 - cgemm_4bit_inference_naive_bf16 = bnb.functional.lib.cgemm_4bit_inference_naive_bf16 + cdequantize_blockwise_fp32 = None + cdequantize_blockwise_fp16_nf4 = None + cdequantize_blockwise_bf16_nf4 = None + cgemm_4bit_inference_naive_fp16 = None + cgemm_4bit_inference_naive_bf16 = None + torch_device_stream = ( diff --git a/unsloth/models/_utils.py b/unsloth/models/_utils.py index 48e5683076..3d48438800 100644 --- a/unsloth/models/_utils.py +++ b/unsloth/models/_utils.py @@ -723,7 +723,10 @@ if is_openai_available(): # ============================================= # Get Flash Attention v2 if Ampere (RTX 30xx, A100) -import bitsandbytes as bnb +try: + import bitsandbytes as bnb +except Exception: + bnb = None from transformers import AutoTokenizer from transformers.utils.import_utils import _is_package_available @@ -1908,7 +1911,11 @@ def patch_tokenizer(model, tokenizer): def patch_fast_lora(): - import peft.tuners.lora.bnb + try: + import peft.tuners.lora.bnb + except Exception as e: + print("Unsloth: bitsandbytes/peft bnb not available - skipping 4bit LoRA patch.", repr(e)) + return peft.tuners.lora.bnb.Linear4bit.forward = fast_lora_forward diff --git a/unsloth/models/granite.py b/unsloth/models/granite.py index aae746aed1..e28c21233d 100644 --- a/unsloth/models/granite.py +++ b/unsloth/models/granite.py @@ -30,8 +30,19 @@ from .llama import ( LlamaLinearScalingRotaryEmbedding, ) from .mistral import * -from bitsandbytes.nn import Linear4bit as Bnb_Linear4bit -from peft.tuners.lora import Linear4bit as Peft_Linear4bit +try: + from bitsandbytes.nn import Linear4bit as Bnb_Linear4bit +except Exception: + Bnb_Linear4bit = None + +try: + from peft.tuners.lora import Linear4bit as Peft_Linear4bit +except Exception: + Peft_Linear4bit = None + +_BNB_LINEAR_TYPES = tuple( + t for t in (Bnb_Linear4bit, Peft_Linear4bit) if t is not None +) try: from transformers.models.granite.modeling_granite import ( @@ -575,7 +586,7 @@ class FastGraniteModel(FastLlamaModel): correct_dtype = lm_head.weight.dtype for name, module in model.named_modules(): - if isinstance(module, (Bnb_Linear4bit, Peft_Linear4bit)): + if _BNB_LINEAR_TYPES and isinstance(module, _BNB_LINEAR_TYPES): weight = module.weight quant_state = weight.quant_state diff --git a/unsloth/models/llama.py b/unsloth/models/llama.py index f18a07ac3c..63390a4927 100644 --- a/unsloth/models/llama.py +++ b/unsloth/models/llama.py @@ -3001,6 +3001,14 @@ class FastLlamaModel: if not SUPPORTS_RSLORA: del arguments["use_rslora"] + # PEFT API compatibility: only pass kwargs supported by the installed peft version. + try: + import inspect as _inspect + if "ensure_weight_tying" not in _inspect.signature(LoraConfig.__init__).parameters: + arguments.pop("ensure_weight_tying", None) + except Exception: + arguments.pop("ensure_weight_tying", None) + _saved_temp_tokenizer = model._saved_temp_tokenizer lora_config = LoraConfig(**arguments) diff --git a/unsloth/models/rl_replacements.py b/unsloth/models/rl_replacements.py index 410eee66e6..237a584bdd 100755 --- a/unsloth/models/rl_replacements.py +++ b/unsloth/models/rl_replacements.py @@ -1143,6 +1143,13 @@ def grpo_trainer_compute_loss(function_name, function): if x.shape[1] == 1: # when importance_sampling_level == "sequence" return x.mean() else: + # Align mask/coef lengths when left-padding adds extra tokens. + if x.shape[1] != completion_mask.shape[1]: + min_len = min(x.shape[1], completion_mask.shape[1]) + x = x[:, -min_len:] + cm = completion_mask[:, -min_len:] + denom = cm.sum().clamp(min = 1.0) + return (x * cm).sum() / denom return (x * completion_mask).sum() / completion_token_count if advantages.dim() == 1: diff --git a/unsloth/save.py b/unsloth/save.py index 071e032c53..0187ded794 100644 --- a/unsloth/save.py +++ b/unsloth/save.py @@ -23,8 +23,15 @@ from unsloth_zoo.llama_cpp import ( check_llama_cpp, _download_convert_hf_to_gguf, ) -from bitsandbytes.nn import Linear4bit as Bnb_Linear4bit -from peft.tuners.lora import Linear4bit as Peft_Linear4bit +try: + from bitsandbytes.nn import Linear4bit as Bnb_Linear4bit +except Exception: + Bnb_Linear4bit = None + +try: + from peft.tuners.lora import Linear4bit as Peft_Linear4bit +except Exception: + Peft_Linear4bit = None from peft.tuners.lora import Linear as Peft_Linear from typing import Optional, Callable, Union, List import sys @@ -58,6 +65,8 @@ except: from pathlib import Path from peft import PeftModelForCausalLM, PeftModel +_MERGE_LORA_LINEAR_TYPES = tuple(t for t in (Bnb_Linear4bit, Peft_Linear4bit, Peft_Linear) if t is not None) + __all__ = [ "print_quantization_methods", "unsloth_save_model", @@ -188,7 +197,7 @@ def _free_cached_model(model): def _merge_lora(layer, name): bias = getattr(layer, "bias", None) - if isinstance(layer, (Bnb_Linear4bit, Peft_Linear4bit, Peft_Linear)): + if _MERGE_LORA_LINEAR_TYPES and isinstance(layer, _MERGE_LORA_LINEAR_TYPES): # Is LoRA so we need to merge! W, quant_state, A, B, s, bias = get_lora_parameters_bias(layer) if quant_state is not None: From e8d897466ee842e873197999e5ba0e4e4b4956af Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 8 Feb 2026 16:21:23 +0000 Subject: [PATCH 2/3] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- unsloth/__init__.py | 2 ++ unsloth/kernels/utils.py | 10 +++++++--- unsloth/models/_utils.py | 5 ++++- unsloth/models/granite.py | 5 ++--- unsloth/models/llama.py | 6 +++++- unsloth/save.py | 5 ++++- 6 files changed, 24 insertions(+), 9 deletions(-) diff --git a/unsloth/__init__.py b/unsloth/__init__.py index 19b433a680..19639a11c7 100644 --- a/unsloth/__init__.py +++ b/unsloth/__init__.py @@ -208,9 +208,11 @@ elif DEVICE_TYPE == "xpu": # Backwards compatibility: some notebooks import `unsloth.is_bf16_supported`. # Ensure it exists on all backends (HIP / XPU) and has a stable signature. if "is_bf16_supported" not in globals(): + def is_bf16_supported(including_emulation = False): return SUPPORTS_BFLOAT16 + # For Gradio HF Spaces? # if "SPACE_AUTHOR_NAME" not in os.environ and "SPACE_REPO_NAME" not in os.environ: import triton diff --git a/unsloth/kernels/utils.py b/unsloth/kernels/utils.py index 63b1966b32..29d47c35e3 100644 --- a/unsloth/kernels/utils.py +++ b/unsloth/kernels/utils.py @@ -110,6 +110,7 @@ def calculate_settings( HAS_CUDA_STREAM = False try: import bitsandbytes as bnb + # https://github.com/bitsandbytes-foundation/bitsandbytes/pull/1330/files HAS_CUDA_STREAM = Version(bnb.__version__) > Version("0.43.3") get_ptr = bnb.functional.get_ptr @@ -197,8 +198,12 @@ if bnb is not None: cgemm_4bit_inference_naive_fp16 = bnb.functional.lib.cgemv_4bit_inference_fp16 cgemm_4bit_inference_naive_bf16 = bnb.functional.lib.cgemv_4bit_inference_bf16 else: - cgemm_4bit_inference_naive_fp16 = bnb.functional.lib.cgemm_4bit_inference_naive_fp16 - cgemm_4bit_inference_naive_bf16 = bnb.functional.lib.cgemm_4bit_inference_naive_bf16 + cgemm_4bit_inference_naive_fp16 = ( + bnb.functional.lib.cgemm_4bit_inference_naive_fp16 + ) + cgemm_4bit_inference_naive_bf16 = ( + bnb.functional.lib.cgemm_4bit_inference_naive_bf16 + ) else: cdequantize_blockwise_fp32 = None cdequantize_blockwise_fp16_nf4 = None @@ -207,7 +212,6 @@ else: cgemm_4bit_inference_naive_bf16 = None - torch_device_stream = ( torch.xpu.current_stream if DEVICE_TYPE == "xpu" else torch.cuda.current_stream ) diff --git a/unsloth/models/_utils.py b/unsloth/models/_utils.py index 3d48438800..4c75b9f64f 100644 --- a/unsloth/models/_utils.py +++ b/unsloth/models/_utils.py @@ -1914,7 +1914,10 @@ def patch_fast_lora(): try: import peft.tuners.lora.bnb except Exception as e: - print("Unsloth: bitsandbytes/peft bnb not available - skipping 4bit LoRA patch.", repr(e)) + print( + "Unsloth: bitsandbytes/peft bnb not available - skipping 4bit LoRA patch.", + repr(e), + ) return peft.tuners.lora.bnb.Linear4bit.forward = fast_lora_forward diff --git a/unsloth/models/granite.py b/unsloth/models/granite.py index e28c21233d..c40be8dfdb 100644 --- a/unsloth/models/granite.py +++ b/unsloth/models/granite.py @@ -30,6 +30,7 @@ from .llama import ( LlamaLinearScalingRotaryEmbedding, ) from .mistral import * + try: from bitsandbytes.nn import Linear4bit as Bnb_Linear4bit except Exception: @@ -40,9 +41,7 @@ try: except Exception: Peft_Linear4bit = None -_BNB_LINEAR_TYPES = tuple( - t for t in (Bnb_Linear4bit, Peft_Linear4bit) if t is not None -) +_BNB_LINEAR_TYPES = tuple(t for t in (Bnb_Linear4bit, Peft_Linear4bit) if t is not None) try: from transformers.models.granite.modeling_granite import ( diff --git a/unsloth/models/llama.py b/unsloth/models/llama.py index 63390a4927..9d3ab0ecaf 100644 --- a/unsloth/models/llama.py +++ b/unsloth/models/llama.py @@ -3004,7 +3004,11 @@ class FastLlamaModel: # PEFT API compatibility: only pass kwargs supported by the installed peft version. try: import inspect as _inspect - if "ensure_weight_tying" not in _inspect.signature(LoraConfig.__init__).parameters: + + if ( + "ensure_weight_tying" + not in _inspect.signature(LoraConfig.__init__).parameters + ): arguments.pop("ensure_weight_tying", None) except Exception: arguments.pop("ensure_weight_tying", None) diff --git a/unsloth/save.py b/unsloth/save.py index 0187ded794..5f26e0a210 100644 --- a/unsloth/save.py +++ b/unsloth/save.py @@ -23,6 +23,7 @@ from unsloth_zoo.llama_cpp import ( check_llama_cpp, _download_convert_hf_to_gguf, ) + try: from bitsandbytes.nn import Linear4bit as Bnb_Linear4bit except Exception: @@ -65,7 +66,9 @@ except: from pathlib import Path from peft import PeftModelForCausalLM, PeftModel -_MERGE_LORA_LINEAR_TYPES = tuple(t for t in (Bnb_Linear4bit, Peft_Linear4bit, Peft_Linear) if t is not None) +_MERGE_LORA_LINEAR_TYPES = tuple( + t for t in (Bnb_Linear4bit, Peft_Linear4bit, Peft_Linear) if t is not None +) __all__ = [ "print_quantization_methods", From c3d86a89839c9be64852d79f08eab03d640fe7e6 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 31 May 2026 10:12:59 +0000 Subject: [PATCH 3/3] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- unsloth/_gpu_init.py | 1 + 1 file changed, 1 insertion(+) diff --git a/unsloth/_gpu_init.py b/unsloth/_gpu_init.py index d7a7b2ca6e..b35e18cf75 100644 --- a/unsloth/_gpu_init.py +++ b/unsloth/_gpu_init.py @@ -241,6 +241,7 @@ if "is_bf16_supported" not in globals(): def is_bf16_supported(including_emulation = False): return SUPPORTS_BFLOAT16 + # For Gradio HF Spaces? # if "SPACE_AUTHOR_NAME" not in os.environ and "SPACE_REPO_NAME" not in os.environ: import triton