bitsandbytes 0.50.0__py3-none-win_arm64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. bitsandbytes/__init__.py +78 -0
  2. bitsandbytes/__main__.py +4 -0
  3. bitsandbytes/_ops.py +510 -0
  4. bitsandbytes/autograd/__init__.py +0 -0
  5. bitsandbytes/autograd/_functions.py +491 -0
  6. bitsandbytes/backends/__init__.py +0 -0
  7. bitsandbytes/backends/cpu/__init__.py +0 -0
  8. bitsandbytes/backends/cpu/ops.py +580 -0
  9. bitsandbytes/backends/cuda/__init__.py +0 -0
  10. bitsandbytes/backends/cuda/ops.py +1199 -0
  11. bitsandbytes/backends/default/__init__.py +0 -0
  12. bitsandbytes/backends/default/ops.py +632 -0
  13. bitsandbytes/backends/hpu/__init__.py +0 -0
  14. bitsandbytes/backends/hpu/ops.py +53 -0
  15. bitsandbytes/backends/mps/__init__.py +0 -0
  16. bitsandbytes/backends/mps/ops.py +277 -0
  17. bitsandbytes/backends/triton/__init__.py +0 -0
  18. bitsandbytes/backends/triton/kernels_4bit.py +577 -0
  19. bitsandbytes/backends/triton/kernels_8bit_quant.py +195 -0
  20. bitsandbytes/backends/triton/kernels_optim.py +1177 -0
  21. bitsandbytes/backends/triton/ops.py +304 -0
  22. bitsandbytes/backends/utils.py +94 -0
  23. bitsandbytes/backends/xpu/__init__.py +0 -0
  24. bitsandbytes/backends/xpu/ops.py +305 -0
  25. bitsandbytes/cextension.py +405 -0
  26. bitsandbytes/consts.py +12 -0
  27. bitsandbytes/cuda_specs.py +111 -0
  28. bitsandbytes/diagnostics/__init__.py +0 -0
  29. bitsandbytes/diagnostics/cuda.py +193 -0
  30. bitsandbytes/diagnostics/main.py +134 -0
  31. bitsandbytes/diagnostics/utils.py +12 -0
  32. bitsandbytes/functional.py +1810 -0
  33. bitsandbytes/libbitsandbytes_cpu.dll +0 -0
  34. bitsandbytes/nn/__init__.py +19 -0
  35. bitsandbytes/nn/modules.py +1220 -0
  36. bitsandbytes/nn/parametrize.py +206 -0
  37. bitsandbytes/optim/__init__.py +22 -0
  38. bitsandbytes/optim/adagrad.py +187 -0
  39. bitsandbytes/optim/adam.py +346 -0
  40. bitsandbytes/optim/adamw.py +337 -0
  41. bitsandbytes/optim/ademamix.py +410 -0
  42. bitsandbytes/optim/lamb.py +190 -0
  43. bitsandbytes/optim/lars.py +259 -0
  44. bitsandbytes/optim/lion.py +266 -0
  45. bitsandbytes/optim/optimizer.py +756 -0
  46. bitsandbytes/optim/rmsprop.py +170 -0
  47. bitsandbytes/optim/sgd.py +152 -0
  48. bitsandbytes/py.typed +0 -0
  49. bitsandbytes/utils.py +208 -0
  50. bitsandbytes-0.50.0.dist-info/METADATA +288 -0
  51. bitsandbytes-0.50.0.dist-info/RECORD +54 -0
  52. bitsandbytes-0.50.0.dist-info/WHEEL +5 -0
  53. bitsandbytes-0.50.0.dist-info/licenses/LICENSE +21 -0
  54. bitsandbytes-0.50.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,206 @@
1
+ from functools import partial
2
+ from typing import Any, Literal, Optional
3
+
4
+ import torch
5
+ import torch.nn as nn
6
+ import torch.nn.utils.parametrize as P
7
+
8
+ from .. import functional as F
9
+
10
+
11
+ class Bnb4bitParametrization(nn.Module):
12
+ """
13
+ A parametrization module that handles dequantization of a 4-bit quantized parameter.
14
+
15
+ The parameter data is expected to be already quantized when this parametrization is applied.
16
+ This module will dequantize the parameter data to its original floating-point representation
17
+ when the forward method is called (i.e. when the parameter is accessed).
18
+
19
+ Args:
20
+ quant_state (`F.QuantState`):
21
+ The quantization state containing the necessary information for dequantization.
22
+ """
23
+
24
+ def __init__(self, quant_state: F.QuantState):
25
+ super().__init__()
26
+ self.quant_state = quant_state
27
+
28
+ @torch.no_grad()
29
+ def forward(self, quantized_param: torch.Tensor) -> torch.Tensor:
30
+ """
31
+ Forward pass to dequantize the parameter.
32
+
33
+ Args:
34
+ quantized_param (`torch.Tensor`): The quantized parameter tensor (from .original)
35
+
36
+ Returns:
37
+ `torch.Tensor`: The dequantized parameter tensor in the original shape and dtype.
38
+ """
39
+ return F.dequantize_4bit(quantized_param, self.quant_state)
40
+
41
+
42
+ def replace_parameter_4bit_prequantized(
43
+ module: nn.Module, param_name: str, qs_dict: dict[str, Any], device: torch.device
44
+ ):
45
+ if not hasattr(module, param_name):
46
+ raise AttributeError(f"Module does not have parameter '{param_name}'")
47
+
48
+ original_param = getattr(module, param_name)
49
+
50
+ if not isinstance(original_param, nn.Parameter):
51
+ raise TypeError(f"Parameter '{param_name}' is not an instance of nn.Parameter")
52
+
53
+ quant_state = F.QuantState.from_dict(qs_dict, device=device)
54
+
55
+ # Apply a parametrization to the module to handle dequantization.
56
+ P.register_parametrization(module, param_name, Bnb4bitParametrization(quant_state), unsafe=True)
57
+
58
+ # Next, register hooks.
59
+ _register_parametrization_hooks(module, param_name)
60
+
61
+
62
+ def replace_parameter_4bit(
63
+ module: nn.Module,
64
+ param_name: str,
65
+ compress_statistics: bool = False,
66
+ quant_type: Literal["nf4", "fp4"] = "nf4",
67
+ blocksize: Optional[int] = None,
68
+ ):
69
+ """
70
+ Replace a module parameter with a 4-bit quantized version using parametrization.
71
+
72
+ This function quantizes an existing parameter in a PyTorch module to 4-bit precision
73
+ and sets up parametrization to handle automatic dequantization during forward passes.
74
+ The original parameter is replaced with quantized data, and a parametrization layer
75
+ is registered to manage the quantization state and dequantization process.
76
+
77
+ Additional, it registers a state dict post-hook to ensure that the quantization state
78
+ is saved correctly when the model's state dict is saved.
79
+
80
+ It is useful for MoE models or other scenarios where you want to quantize parameters
81
+ outside of nn.Linear layers without changing the model's architecture.
82
+
83
+ <Tip warning={true}>This feature is experimental and may change in future releases.</Tip>
84
+
85
+ Args:
86
+ module (`nn.Module`):
87
+ The PyTorch module containing the parameter to be quantized.
88
+ param_name (`str`):
89
+ The name of the parameter within the module to quantize.
90
+ compress_statistics (`bool`, *optional*, defaults to `False`):
91
+ Whether to compress quantization statistics to reduce memory usage.
92
+ quant_type (`Literal["nf4", "fp4"]`, *optional*, defaults to `"nf4"`):
93
+ The quantization format to use.
94
+ blocksize (`int`, *optional*, defaults to `None`):
95
+ The block size for quantization. If None, uses the default block size.
96
+
97
+ Raises:
98
+ AttributeError: If the module does not have the specified parameter.
99
+ TypeError: If the specified attribute is not an instance of nn.Parameter.
100
+ """
101
+
102
+ if not hasattr(module, param_name):
103
+ raise AttributeError(f"Module does not have parameter '{param_name}'")
104
+
105
+ original_param = getattr(module, param_name)
106
+
107
+ if not isinstance(original_param, nn.Parameter):
108
+ raise TypeError(f"Parameter '{param_name}' is not an instance of nn.Parameter")
109
+
110
+ # Quantize the original parameter.
111
+ quantized_data, quant_state = F.quantize_4bit(
112
+ original_param.data,
113
+ blocksize=blocksize,
114
+ compress_statistics=compress_statistics,
115
+ quant_type=quant_type,
116
+ )
117
+
118
+ # Replace the parameter with the quantized data.
119
+ setattr(module, param_name, nn.Parameter(quantized_data, requires_grad=False))
120
+ del original_param
121
+
122
+ # Apply a parametrization to the module to handle dequantization.
123
+ P.register_parametrization(module, param_name, Bnb4bitParametrization(quant_state), unsafe=True)
124
+
125
+ # Next, register hooks.
126
+ _register_parametrization_hooks(module, param_name)
127
+
128
+
129
+ def _disable_parametrization_cache(module: nn.Module, inputs: tuple[Any, ...], output: Any):
130
+ # Clamp instead of a bare decrement: with ``always_call=True`` this hook also runs
131
+ # when the forward raised before the pre-hook incremented (e.g. an earlier pre-hook
132
+ # failed), and the counter must never go negative — a negative value is truthy, so
133
+ # ``if not P._cache_enabled`` would stop clearing the cache forever.
134
+ P._cache_enabled = max(0, P._cache_enabled - 1)
135
+ if not P._cache_enabled:
136
+ P._cache = {}
137
+
138
+
139
+ def _enable_parametrization_cache(module: nn.Module, inputs: tuple[Any, ...]):
140
+ P._cache_enabled += 1
141
+
142
+
143
+ def _register_parametrization_hooks(module: nn.Module, param_name: str):
144
+ # Register a state dict hook for saving. Note that this requires torch >= 2.5.0.
145
+ if torch.__version__ >= (2, 5):
146
+ module.register_state_dict_post_hook(
147
+ partial(
148
+ _parametrized_state_dict_post_hook,
149
+ param_name=param_name,
150
+ )
151
+ )
152
+
153
+ # Register hooks to enable caching for the dequantization parametrization.
154
+ # This helps preserve time and memory when the same quantized parameter
155
+ # is accessed multiple times in the forward computation.
156
+ #
157
+ # ``always_call=True`` is load-bearing: activation checkpointing with
158
+ # ``use_reentrant=False`` aborts its backward recompute mid-forward by design
159
+ # (early stop, via an internal exception) once the last needed activation has
160
+ # been rematerialized. A plain forward hook is skipped in that case, so the
161
+ # global ``parametrize._cache_enabled`` counter leaks upward once per
162
+ # checkpointed region per step, after which the cache is enabled (and never
163
+ # cleared) for the remainder of training — every dequantized parameter this
164
+ # module produces stays resident, i.e. a memory leak of the full dequantized
165
+ # model size (4x the packed 4-bit bytes).
166
+ module.register_forward_pre_hook(_enable_parametrization_cache)
167
+ module.register_forward_hook(_disable_parametrization_cache, always_call=True)
168
+
169
+
170
+ def _parametrized_state_dict_post_hook(
171
+ module: nn.Module,
172
+ state_dict: dict[str, Any],
173
+ prefix: str,
174
+ local_metadata: Any,
175
+ *,
176
+ param_name: str = "weight",
177
+ **kwargs: dict[str, Any],
178
+ ) -> None:
179
+ """
180
+ Hook to modify the state dict to include the quantization state.
181
+ """
182
+
183
+ original_key = f"{prefix}parametrizations.{param_name}.original"
184
+
185
+ if original_key in state_dict:
186
+ # Create a clean entry.
187
+ # The `parametrizations.{param_name}.original` key will have the quantized data,
188
+ # but we would like it to keep it in the state_dict as `{param_name}`.
189
+ clean_key = f"{prefix}{param_name}"
190
+ state_dict[clean_key] = state_dict.pop(original_key)
191
+
192
+ assert P.is_parametrized(module, param_name)
193
+
194
+ # Find the parametrization, which should have the quantization state.
195
+ parametrization: Bnb4bitParametrization = next(
196
+ filter(lambda x: isinstance(x, Bnb4bitParametrization), module.parametrizations[param_name]), None
197
+ )
198
+
199
+ assert parametrization is not None, "Parametrization not found for the parameter."
200
+
201
+ quant_state = parametrization.quant_state
202
+
203
+ # Next, we need to store the quantization state.
204
+ if quant_state is not None:
205
+ for k, v in quant_state.as_dict(packed=True).items():
206
+ state_dict[f"{prefix}{param_name}.{k}"] = v
@@ -0,0 +1,22 @@
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ from .adagrad import Adagrad, Adagrad8bit, Adagrad32bit
7
+ from .adam import Adam, Adam8bit, Adam32bit, PagedAdam, PagedAdam8bit, PagedAdam32bit
8
+ from .adamw import (
9
+ AdamW,
10
+ AdamW8bit,
11
+ AdamW32bit,
12
+ PagedAdamW,
13
+ PagedAdamW8bit,
14
+ PagedAdamW32bit,
15
+ )
16
+ from .ademamix import AdEMAMix, AdEMAMix8bit, AdEMAMix32bit, PagedAdEMAMix, PagedAdEMAMix8bit, PagedAdEMAMix32bit
17
+ from .lamb import LAMB, LAMB8bit, LAMB32bit
18
+ from .lars import LARS, LARS8bit, LARS32bit, PytorchLARS
19
+ from .lion import Lion, Lion8bit, Lion32bit, PagedLion, PagedLion8bit, PagedLion32bit
20
+ from .optimizer import GlobalOptimManager
21
+ from .rmsprop import RMSprop, RMSprop8bit, RMSprop32bit
22
+ from .sgd import SGD, SGD8bit, SGD32bit
@@ -0,0 +1,187 @@
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+ from bitsandbytes.optim.optimizer import Optimizer1State
6
+
7
+
8
+ class Adagrad(Optimizer1State):
9
+ def __init__(
10
+ self,
11
+ params,
12
+ lr=1e-2,
13
+ lr_decay=0,
14
+ weight_decay=0,
15
+ initial_accumulator_value=0,
16
+ eps=1e-10,
17
+ optim_bits=32,
18
+ args=None,
19
+ min_8bit_size=4096,
20
+ ):
21
+ """
22
+ Base Adagrad optimizer.
23
+
24
+ Arguments:
25
+ params (`torch.tensor`):
26
+ The input parameters to optimize.
27
+ lr (`float`, defaults to 1e-2):
28
+ The learning rate.
29
+ lr_decay (`int`, defaults to 0):
30
+ The learning rate decay.
31
+ weight_decay (`float`, defaults to 0.0):
32
+ The weight decay value for the optimizer.
33
+ initial_accumulator_value (`int`, defaults to 0):
34
+ The initial momemtum values.
35
+ eps (`float`, defaults to 1e-10):
36
+ The epsilon value prevents division by zero in the optimizer.
37
+ optim_bits (`int`, defaults to 32):
38
+ The number of bits of the optimizer state.
39
+ args (`object`, defaults to `None`):
40
+ An object with additional arguments.
41
+ min_8bit_size (`int`, defaults to 4096):
42
+ The minimum number of elements of the parameter tensors for 8-bit optimization.
43
+ """
44
+ if not 0.0 <= lr:
45
+ raise ValueError(f"Invalid learning rate: {lr}")
46
+ if not 0.0 <= weight_decay:
47
+ raise ValueError(f"Invalid weight_decay value: {weight_decay}")
48
+ if not 0.0 <= eps:
49
+ raise ValueError(f"Invalid epsilon value: {eps}")
50
+ if initial_accumulator_value != 0.0:
51
+ raise ValueError("Initial accumulator value != 0.0 not supported!")
52
+ if lr_decay != 0.0:
53
+ raise ValueError("Lr Decay != 0.0 not supported!")
54
+ super().__init__(
55
+ "adagrad",
56
+ params,
57
+ lr,
58
+ (0.0, 0.0),
59
+ eps,
60
+ weight_decay,
61
+ optim_bits,
62
+ args,
63
+ min_8bit_size,
64
+ )
65
+
66
+
67
+ class Adagrad8bit(Optimizer1State):
68
+ def __init__(
69
+ self,
70
+ params,
71
+ lr=1e-2,
72
+ lr_decay=0,
73
+ weight_decay=0,
74
+ initial_accumulator_value=0,
75
+ eps=1e-10,
76
+ optim_bits=8,
77
+ args=None,
78
+ min_8bit_size=4096,
79
+ ):
80
+ """
81
+ 8-bit Adagrad optimizer.
82
+
83
+ Arguments:
84
+ params (`torch.tensor`):
85
+ The input parameters to optimize.
86
+ lr (`float`, defaults to 1e-2):
87
+ The learning rate.
88
+ lr_decay (`int`, defaults to 0):
89
+ The learning rate decay.
90
+ weight_decay (`float`, defaults to 0.0):
91
+ The weight decay value for the optimizer.
92
+ initial_accumulator_value (`int`, defaults to 0):
93
+ The initial momemtum values.
94
+ eps (`float`, defaults to 1e-10):
95
+ The epsilon value prevents division by zero in the optimizer.
96
+ optim_bits (`int`, defaults to 8):
97
+ The number of bits of the optimizer state.
98
+ Note: This parameter is not used in Adagrad8bit as it always uses 8-bit optimization.
99
+ args (`object`, defaults to `None`):
100
+ An object with additional arguments.
101
+ min_8bit_size (`int`, defaults to 4096):
102
+ The minimum number of elements of the parameter tensors for 8-bit optimization.
103
+ """
104
+ if not 0.0 <= lr:
105
+ raise ValueError(f"Invalid learning rate: {lr}")
106
+ if not 0.0 <= weight_decay:
107
+ raise ValueError(f"Invalid weight_decay value: {weight_decay}")
108
+ if not 0.0 <= eps:
109
+ raise ValueError(f"Invalid epsilon value: {eps}")
110
+ if initial_accumulator_value != 0.0:
111
+ raise ValueError("Initial accumulator value != 0.0 not supported!")
112
+ if lr_decay != 0.0:
113
+ raise ValueError("Lr Decay != 0.0 not supported!")
114
+ if optim_bits != 8:
115
+ # We allow the default value of 8 to maintain compatibility with the function signature,
116
+ # but any other value is invalid since Adagrad8bit always uses 8-bit optimization
117
+ raise ValueError("Adagrad8bit only supports optim_bits=8 (default value for compatibility)")
118
+ super().__init__(
119
+ "adagrad",
120
+ params,
121
+ lr,
122
+ (0.0, 0.0),
123
+ eps,
124
+ weight_decay,
125
+ 8,
126
+ args,
127
+ min_8bit_size,
128
+ )
129
+
130
+
131
+ class Adagrad32bit(Optimizer1State):
132
+ def __init__(
133
+ self,
134
+ params,
135
+ lr=1e-2,
136
+ lr_decay=0,
137
+ weight_decay=0,
138
+ initial_accumulator_value=0,
139
+ eps=1e-10,
140
+ optim_bits=32,
141
+ args=None,
142
+ min_8bit_size=4096,
143
+ ):
144
+ """
145
+ 32-bit Adagrad optimizer.
146
+
147
+ Arguments:
148
+ params (`torch.tensor`):
149
+ The input parameters to optimize.
150
+ lr (`float`, defaults to 1e-2):
151
+ The learning rate.
152
+ lr_decay (`int`, defaults to 0):
153
+ The learning rate decay.
154
+ weight_decay (`float`, defaults to 0.0):
155
+ The weight decay value for the optimizer.
156
+ initial_accumulator_value (`int`, defaults to 0):
157
+ The initial momemtum values.
158
+ eps (`float`, defaults to 1e-10):
159
+ The epsilon value prevents division by zero in the optimizer.
160
+ optim_bits (`int`, defaults to 32):
161
+ The number of bits of the optimizer state.
162
+ args (`object`, defaults to `None`):
163
+ An object with additional arguments.
164
+ min_8bit_size (`int`, defaults to 4096):
165
+ The minimum number of elements of the parameter tensors for 8-bit optimization.
166
+ """
167
+ if not 0.0 <= lr:
168
+ raise ValueError(f"Invalid learning rate: {lr}")
169
+ if not 0.0 <= weight_decay:
170
+ raise ValueError(f"Invalid weight_decay value: {weight_decay}")
171
+ if not 0.0 <= eps:
172
+ raise ValueError(f"Invalid epsilon value: {eps}")
173
+ if initial_accumulator_value != 0.0:
174
+ raise ValueError("Initial accumulator value != 0.0 not supported!")
175
+ if lr_decay != 0.0:
176
+ raise ValueError("Lr Decay != 0.0 not supported!")
177
+ super().__init__(
178
+ "adagrad",
179
+ params,
180
+ lr,
181
+ (0.0, 0.0),
182
+ eps,
183
+ weight_decay,
184
+ 32,
185
+ args,
186
+ min_8bit_size,
187
+ )