diff --git a/unsloth/models/_utils.py b/unsloth/models/_utils.py index 76952b00a5..301cdf7b80 100644 --- a/unsloth/models/_utils.py +++ b/unsloth/models/_utils.py @@ -59,6 +59,7 @@ __all__ = [ "unsloth_fused_ce_loss", "patch_unsloth_smart_gradient_checkpointing", "unpatch_unsloth_smart_gradient_checkpointing", + "apply_unsloth_gradient_checkpointing", "patch_compiled_autograd", "process_vision_info", "unsloth_compile_transformers", @@ -148,6 +149,41 @@ from unsloth_zoo.temporary_patches import ( TEMPORARY_PATCHES, ) + +def apply_unsloth_gradient_checkpointing( + use_gradient_checkpointing, max_seq_length, dtype +): + """ + Apply gradient checkpointing with smart heuristics. + + For seq < 512, the overhead of gradient offloading in gc="unsloth" mode + is not worth it. Benchmarks show standard gc is faster for small sequences. + + Args: + use_gradient_checkpointing: "unsloth", True, False, or None + max_seq_length: The maximum sequence length + dtype: The model dtype for patching + + Returns: + The effective use_gradient_checkpointing value (may change from "unsloth" to True) + """ + if use_gradient_checkpointing == "unsloth": + # Gradient offloading overhead is not worth it for small sequences. + # Benchmarks show crossover point is around seq_len 384-512. + # For seq < 512, standard gradient checkpointing is faster. + if max_seq_length < 512: + unpatch_unsloth_smart_gradient_checkpointing() + return True + else: + patch_unsloth_smart_gradient_checkpointing(dtype = dtype) + return "unsloth" + elif use_gradient_checkpointing in (True, False): + # User explicitly set True or False - unpatch any previous "unsloth" patching + unpatch_unsloth_smart_gradient_checkpointing() + return use_gradient_checkpointing + return use_gradient_checkpointing + + for temporary_patch in TEMPORARY_PATCHES: temporary_patch() diff --git a/unsloth/models/llama.py b/unsloth/models/llama.py index 39f2ba1460..fb3b8133a5 100644 --- a/unsloth/models/llama.py +++ b/unsloth/models/llama.py @@ -19,7 +19,7 @@ import functools from typing import Optional, Tuple, List, Union from ._utils import * -from ._utils import patch_unsloth_smart_gradient_checkpointing +from ._utils import apply_unsloth_gradient_checkpointing from ._utils import __version__, importlib_version from ._utils import move_to_device from ._utils import ( @@ -2693,10 +2693,12 @@ class FastLlamaModel: return model transformers_set_seed(random_state) - if use_gradient_checkpointing == "unsloth": - patch_unsloth_smart_gradient_checkpointing( - dtype = model.get_input_embeddings().weight.dtype - ) + # Apply gradient checkpointing with smart heuristics + max_seq = getattr(model, "max_seq_length", 512) + dtype = model.get_input_embeddings().weight.dtype + use_gradient_checkpointing = apply_unsloth_gradient_checkpointing( + use_gradient_checkpointing, max_seq, dtype + ) if type(r) is not int: raise TypeError(f"Unsloth: Rank of {str(r)} must be an integer.") diff --git a/unsloth/models/loader.py b/unsloth/models/loader.py index eb3b21e206..ef7e67b468 100644 --- a/unsloth/models/loader.py +++ b/unsloth/models/loader.py @@ -88,7 +88,7 @@ from ._utils import ( patch_compiling_bitsandbytes, patch_model_and_tokenizer, prepare_model_for_kbit_training, - patch_unsloth_smart_gradient_checkpointing, + apply_unsloth_gradient_checkpointing, patch_compiled_autograd, process_vision_info, unsloth_compile_transformers, @@ -559,8 +559,10 @@ class FastLanguageModel(FastLlamaModel): **kwargs, ) - if use_gradient_checkpointing == "unsloth": - patch_unsloth_smart_gradient_checkpointing(dtype = dtype) + # Apply gradient checkpointing with smart heuristics + use_gradient_checkpointing = apply_unsloth_gradient_checkpointing( + use_gradient_checkpointing, max_seq_length, dtype + ) # Check if this is local model since the tokenizer gets overwritten if ( @@ -1188,9 +1190,10 @@ class FastModel(FastBaseModel): os.environ["UNSLOTH_FORCE_FLOAT32"] = "1" dtype = torch.bfloat16 # Change to bfloat16 loading break - # Patch gradient checkpointing - if use_gradient_checkpointing == "unsloth": - patch_unsloth_smart_gradient_checkpointing(dtype = dtype) + # Apply gradient checkpointing with smart heuristics + use_gradient_checkpointing = apply_unsloth_gradient_checkpointing( + use_gradient_checkpointing, max_seq_length, dtype + ) with redirector: patch_loss_functions(torch_compile = False) model_types, supports_sdpa = unsloth_compile_transformers(