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,78 @@
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
+
7
+ import importlib
8
+ import sys
9
+
10
+ import torch
11
+
12
+ from . import _ops, utils
13
+ from .autograd._functions import (
14
+ MatmulLtState,
15
+ matmul,
16
+ matmul_4bit,
17
+ )
18
+ from .backends.cpu import ops as cpu_ops
19
+ from .backends.default import ops as default_ops
20
+ from .nn import modules
21
+ from .optim import adam
22
+
23
+ # This is a signal for integrations with transformers/diffusers.
24
+ # Eventually we may remove this but it is currently required for compatibility.
25
+ features = {"multi_backend"}
26
+ supported_torch_devices = {
27
+ "cpu",
28
+ "cuda", # NVIDIA/AMD GPU
29
+ "xpu", # Intel GPU
30
+ "hpu", # Intel Gaudi
31
+ "npu", # Ascend NPU
32
+ "mps", # Apple Silicon
33
+ }
34
+
35
+ if torch.cuda.is_available():
36
+ from .backends.cuda import ops as cuda_ops
37
+
38
+ if hasattr(torch, "xpu") and torch.xpu.is_available():
39
+ from .backends.xpu import ops as xpu_ops
40
+
41
+ if hasattr(torch.backends, "mps") and torch.backends.mps.is_available():
42
+ from .backends.mps import ops as mps_ops
43
+
44
+ if importlib.util.find_spec("habana_frameworks") and importlib.util.find_spec("habana_frameworks.torch"):
45
+ # In case not automatically imported
46
+ import habana_frameworks.torch
47
+
48
+ if hasattr(torch, "hpu") and torch.hpu.is_available():
49
+ from .backends.hpu import ops as hpu_ops
50
+
51
+
52
+ def _import_backends():
53
+ """
54
+ Discover and autoload all available backends installed as separate packages.
55
+ Packages with an entrypoint for "bitsandbytes.backends" will be loaded.
56
+ Inspired by PyTorch implementation: https://pytorch.org/tutorials/prototype/python_extension_autoload.html
57
+ """
58
+ from importlib.metadata import entry_points
59
+
60
+ extensions = entry_points(group="bitsandbytes.backends")
61
+
62
+ for ext in extensions:
63
+ try:
64
+ entry = ext.load()
65
+ entry()
66
+ except Exception as e:
67
+ raise RuntimeError(f"bitsandbytes: failed to load backend {ext.name}: {e}") from e
68
+
69
+
70
+ _import_backends()
71
+
72
+ __pdoc__ = {
73
+ "libbitsandbytes": False,
74
+ "optim.optimizer.Optimizer8bit": False,
75
+ "optim.optimizer.MockArgs": False,
76
+ }
77
+
78
+ __version__ = "0.50.0"
@@ -0,0 +1,4 @@
1
+ if __name__ == "__main__":
2
+ from bitsandbytes.diagnostics.main import main
3
+
4
+ main()
bitsandbytes/_ops.py ADDED
@@ -0,0 +1,510 @@
1
+ from collections.abc import Sequence
2
+ from typing import Optional
3
+
4
+ import torch
5
+
6
+ register_fake = torch.library.register_fake
7
+ register_kernel = torch.library.register_kernel
8
+
9
+ # Int8 mixed precision matmul + dequant + bias
10
+ torch.library.define(
11
+ "bitsandbytes::int8_mixed_scaled_mm",
12
+ "(Tensor A, Tensor CA, Tensor CB, Tensor SCA, Tensor SCB, Tensor? outlier_cols=None, Tensor? bias=None) -> (Tensor, Tensor?)",
13
+ )
14
+
15
+
16
+ @register_fake("bitsandbytes::int8_mixed_scaled_mm")
17
+ def _(
18
+ A: torch.Tensor,
19
+ CA: torch.Tensor,
20
+ CB: torch.Tensor,
21
+ SCA: torch.Tensor,
22
+ SCB: torch.Tensor,
23
+ outlier_cols: Optional[torch.Tensor] = None,
24
+ bias: Optional[torch.Tensor] = None,
25
+ ) -> tuple[torch.Tensor, Optional[torch.Tensor]]:
26
+ shapeC = (*CA.shape[:-1], CB.shape[0])
27
+
28
+ out = torch.empty(shapeC, device=A.device, dtype=A.dtype)
29
+
30
+ outlier_cols = torch.library.get_ctx().new_dynamic_size()
31
+ subA = A.new_empty(outlier_cols, dtype=torch.int64)
32
+
33
+ return out, subA
34
+
35
+
36
+ # Higher level op: int8 matmul + dequant + bias
37
+ torch.library.define(
38
+ "bitsandbytes::int8_scaled_mm",
39
+ "(Tensor A, Tensor B, Tensor row_stats, Tensor col_stats, Tensor? bias=None, ScalarType? dtype=None) -> Tensor",
40
+ )
41
+
42
+
43
+ @register_fake("bitsandbytes::int8_scaled_mm")
44
+ def _(
45
+ A: torch.Tensor,
46
+ B: torch.Tensor,
47
+ row_stats: torch.Tensor,
48
+ col_stats: torch.Tensor,
49
+ bias: Optional[torch.Tensor] = None,
50
+ dtype: Optional[torch.dtype] = None,
51
+ ) -> torch.Tensor:
52
+ shapeC = (*A.shape[:-1], B.shape[0])
53
+ return torch.empty(shapeC, device=A.device, dtype=dtype or torch.float16)
54
+
55
+
56
+ torch.library.define(
57
+ "bitsandbytes::int8_linear_matmul",
58
+ "(Tensor A, Tensor B) -> Tensor",
59
+ )
60
+
61
+
62
+ @register_fake("bitsandbytes::int8_linear_matmul")
63
+ def _(A: torch.Tensor, B: torch.Tensor):
64
+ torch._check(A.dtype == torch.int8, lambda: "A must be int8")
65
+ torch._check(B.dtype == torch.int8, lambda: "B must be int8")
66
+ shapeC = (*A.shape[:-1], B.shape[0])
67
+ return torch.empty(shapeC, device=A.device, dtype=torch.int32)
68
+
69
+
70
+ # More info on `out` overloads:
71
+ # https://github.com/pytorch/pytorch/issues/125044
72
+ torch.library.define(
73
+ "bitsandbytes::int8_linear_matmul.out",
74
+ "(Tensor A, Tensor B, Tensor! out) -> ()",
75
+ )
76
+
77
+
78
+ @register_fake("bitsandbytes::int8_linear_matmul.out")
79
+ def _(A: torch.Tensor, B: torch.Tensor, out: torch.Tensor):
80
+ shapeC = (*A.shape[:-1], B.shape[0])
81
+
82
+ torch._check(A.dtype == torch.int8, lambda: "A must be int8")
83
+ torch._check(B.dtype == torch.int8, lambda: "B must be int8")
84
+ torch._check(out.shape == shapeC, lambda: f"Expected out.shape == {shapeC}, got {out.shape}")
85
+ torch._check(out.device == A.device, lambda: f"Expected out.device == {A.device}, got {out.device}")
86
+ torch._check(out.dtype == torch.int32, lambda: f"Expected out.dtype == int32, got {out.dtype}")
87
+
88
+
89
+ torch.library.define(
90
+ "bitsandbytes::int8_vectorwise_quant",
91
+ "(Tensor A, float threshold=0.0) -> (Tensor, Tensor, Tensor?)",
92
+ )
93
+
94
+
95
+ @register_fake("bitsandbytes::int8_vectorwise_quant")
96
+ def _(A: torch.Tensor, threshold=0.0):
97
+ out_row = torch.empty(A.shape, device=A.device, dtype=torch.int8)
98
+ row_stats = torch.empty(A.numel() // A.shape[-1], device=A.device, dtype=torch.float32)
99
+
100
+ if threshold == 0.0:
101
+ return out_row, row_stats, None
102
+
103
+ outlier_cols = torch.library.get_ctx().new_dynamic_size()
104
+
105
+ return out_row, row_stats, A.new_empty(outlier_cols, dtype=torch.int64)
106
+
107
+
108
+ torch.library.define("bitsandbytes::int8_vectorwise_dequant", "(Tensor A, Tensor stats) -> Tensor")
109
+
110
+
111
+ @register_fake("bitsandbytes::int8_vectorwise_dequant")
112
+ def _(A: torch.Tensor, stats: torch.Tensor) -> torch.Tensor:
113
+ torch._check(A.dtype == torch.int8, lambda: "A must be int8")
114
+ return torch.empty_like(A, dtype=torch.float32)
115
+
116
+
117
+ # Default PyTorch-native implementation
118
+ @register_kernel("bitsandbytes::int8_vectorwise_dequant", "default")
119
+ def _(A: torch.Tensor, stats: torch.Tensor):
120
+ # To dequantize we divide by 127, or multiply by the reciprocal.
121
+ return A * stats.view(-1, 1) * 7.874015718698502e-3
122
+
123
+
124
+ torch.library.define(
125
+ "bitsandbytes::int8_mm_dequant",
126
+ "(Tensor A, Tensor row_stats, Tensor col_stats, ScalarType? dtype=None, Tensor? bias=None) -> Tensor",
127
+ )
128
+
129
+
130
+ @register_fake("bitsandbytes::int8_mm_dequant")
131
+ def _(
132
+ A: torch.Tensor,
133
+ row_stats: torch.Tensor,
134
+ col_stats: torch.Tensor,
135
+ dtype: Optional[torch.dtype] = None,
136
+ bias: Optional[torch.Tensor] = None,
137
+ ) -> torch.Tensor:
138
+ torch._check(A.dtype == torch.int32, lambda: "A must be int32")
139
+ return torch.empty_like(A, dtype=dtype or torch.float16)
140
+
141
+
142
+ torch.library.define(
143
+ "bitsandbytes::int8_double_quant",
144
+ "(Tensor A, float threshold=0.0) -> (Tensor, Tensor, Tensor, Tensor, Tensor?)",
145
+ )
146
+
147
+
148
+ @register_fake("bitsandbytes::int8_double_quant")
149
+ def _(
150
+ A: torch.Tensor,
151
+ threshold=0.0,
152
+ ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor, Optional[torch.Tensor]]:
153
+ out_row = torch.empty_like(A, dtype=torch.int8)
154
+ out_col = torch.empty_like(A, dtype=torch.int8)
155
+ row_stats = torch.empty(A.numel() // A.shape[-1], device=A.device, dtype=torch.float32)
156
+ col_stats = torch.empty(A.shape[-1], device=A.device, dtype=torch.float32)
157
+ outlier_n = torch.library.get_ctx().new_dynamic_size()
158
+ outlier_cols = A.new_empty(outlier_n, dtype=torch.int64)
159
+ return out_row, out_col, row_stats, col_stats, outlier_cols
160
+
161
+
162
+ torch.library.define(
163
+ "bitsandbytes::dequantize_4bit",
164
+ "(Tensor A, Tensor absmax, int blocksize, str quant_type, int[] shape, ScalarType dtype) -> Tensor",
165
+ )
166
+
167
+
168
+ @register_fake("bitsandbytes::dequantize_4bit")
169
+ def _(
170
+ A: torch.Tensor,
171
+ absmax: torch.Tensor,
172
+ blocksize: int,
173
+ quant_type: str,
174
+ shape: Sequence[int],
175
+ dtype: torch.dtype,
176
+ ) -> torch.Tensor:
177
+ torch._check(blocksize in (32, 64, 128, 256, 512, 1024, 2048, 4096), lambda: f"invalid blocksize {blocksize}")
178
+ torch._check(quant_type in ("nf4", "fp4"), lambda: f"quant_type must be 'nf4' or 'fp4', got {quant_type!r}")
179
+ torch._check(absmax.dtype == torch.float32, lambda: f"absmax must be float32, got {absmax.dtype}")
180
+ torch._check(
181
+ dtype in (torch.float16, torch.bfloat16, torch.float32),
182
+ lambda: f"Blockwise 4bit dequantization only supports 16/32-bit floats, but got {dtype}",
183
+ )
184
+ return torch.empty(shape, dtype=dtype, device=A.device)
185
+
186
+
187
+ torch.library.define(
188
+ "bitsandbytes::dequantize_4bit.out",
189
+ "(Tensor A, Tensor absmax, int blocksize, str quant_type, int[] shape, ScalarType dtype, Tensor! out) -> ()",
190
+ )
191
+
192
+
193
+ @register_fake("bitsandbytes::dequantize_4bit.out")
194
+ def _(
195
+ A: torch.Tensor,
196
+ absmax: torch.Tensor,
197
+ blocksize: int,
198
+ quant_type: str,
199
+ shape: Sequence[int],
200
+ dtype: torch.dtype,
201
+ out: torch.Tensor,
202
+ ) -> None:
203
+ torch._check(blocksize in (32, 64, 128, 256, 512, 1024, 2048, 4096), lambda: f"invalid blocksize {blocksize}")
204
+ torch._check(quant_type in ("nf4", "fp4"), lambda: f"quant_type must be 'nf4' or 'fp4', got {quant_type!r}")
205
+ torch._check(absmax.dtype == torch.float32, lambda: f"absmax must be float32, got {absmax.dtype}")
206
+ torch._check(
207
+ dtype in (torch.float16, torch.bfloat16, torch.float32),
208
+ lambda: f"Blockwise 4bit dequantization only supports 16/32-bit floats, but got {dtype}",
209
+ )
210
+ torch._check(out.shape == shape, lambda: f"Expected out.shape == {shape}, got {out.shape}")
211
+ torch._check(out.device == A.device, lambda: f"Expected out.device == {A.device}, got {out.device}")
212
+ torch._check(out.dtype == dtype, lambda: f"Expected out.dtype == {dtype}, got {out.dtype}")
213
+
214
+
215
+ torch.library.define(
216
+ "bitsandbytes::quantize_4bit",
217
+ "(Tensor A, int blocksize, str quant_type, ScalarType quant_storage) -> (Tensor, Tensor)",
218
+ )
219
+
220
+
221
+ @register_fake("bitsandbytes::quantize_4bit")
222
+ def _(
223
+ A: torch.Tensor, blocksize: int, quant_type: str, quant_storage: torch.dtype
224
+ ) -> tuple[torch.Tensor, torch.Tensor]:
225
+ torch._check(blocksize in (32, 64, 128, 256, 512, 1024, 2048, 4096), lambda: f"invalid blocksize {blocksize}")
226
+ torch._check(quant_type in ("nf4", "fp4"), lambda: f"quant_type must be 'nf4' or 'fp4', got {quant_type!r}")
227
+ torch._check(
228
+ A.dtype in (torch.float16, torch.bfloat16, torch.float32),
229
+ lambda: f"Blockwise 4bit quantization only supports 16/32-bit floats, but got {A.dtype}",
230
+ )
231
+
232
+ n = A.numel()
233
+ blocks = -(n // -blocksize)
234
+ absmax = torch.empty((blocks,), device=A.device, dtype=torch.float32)
235
+ out = torch.empty(((n + 1) // (quant_storage.itemsize * 2), 1), device=A.device, dtype=quant_storage)
236
+ return out, absmax
237
+
238
+
239
+ torch.library.define(
240
+ "bitsandbytes::gemm_4bit",
241
+ "(Tensor A, Tensor B, int[] shapeB, Tensor absmax, int blocksize, str quant_type, "
242
+ "Tensor? bias=None, Tensor? absmax_8bit=None, Tensor? absmax_code=None, Tensor? absmax_offset=None) -> Tensor",
243
+ )
244
+
245
+
246
+ @register_fake("bitsandbytes::gemm_4bit")
247
+ def _(
248
+ A: torch.Tensor,
249
+ B: torch.Tensor,
250
+ shapeB: Sequence[int],
251
+ absmax: torch.Tensor,
252
+ blocksize: int,
253
+ quant_type: str,
254
+ bias: Optional[torch.Tensor] = None,
255
+ absmax_8bit: Optional[torch.Tensor] = None,
256
+ absmax_code: Optional[torch.Tensor] = None,
257
+ absmax_offset: Optional[torch.Tensor] = None,
258
+ ) -> torch.Tensor:
259
+ torch._check(len(shapeB) == 2, lambda: f"shapeB must be 2D [N, K], got {list(shapeB)}")
260
+ torch._check(A.shape[-1] == shapeB[1], lambda: f"A inner dim ({A.shape[-1]}) must match shapeB ({shapeB[1]})")
261
+ torch._check(
262
+ A.dtype in (torch.float16, torch.bfloat16, torch.float32),
263
+ lambda: f"A must be float16, bfloat16, or float32, got {A.dtype}",
264
+ )
265
+ torch._check(
266
+ B.dtype in (torch.uint8, torch.bfloat16, torch.float16, torch.float32),
267
+ lambda: f"B must be backed by storage of type uint8, bfloat16, float16, or float32, got {B.dtype}",
268
+ )
269
+ torch._check(blocksize in (32, 64, 128, 256, 512, 1024, 2048, 4096), lambda: f"invalid blocksize {blocksize}")
270
+ torch._check(quant_type in ("nf4", "fp4"), lambda: f"quant_type must be 'nf4' or 'fp4', got {quant_type!r}")
271
+ torch._check(absmax.dtype == torch.float32, lambda: f"absmax must be float32, got {absmax.dtype}")
272
+ if absmax_8bit is not None:
273
+ torch._check(absmax_8bit.ndim == 1, lambda: f"absmax_8bit must be 1D, got {absmax_8bit.ndim}D")
274
+ torch._check(absmax_8bit.dtype == torch.uint8, lambda: f"absmax_8bit must be uint8, got {absmax_8bit.dtype}")
275
+ torch._check(absmax_code is not None, lambda: "absmax_code required when absmax_8bit is provided")
276
+ torch._check(absmax_code.ndim == 1, lambda: f"absmax_code must be 1D, got {absmax_code.ndim}D")
277
+ torch._check(
278
+ absmax_code.shape[0] == 256, lambda: f"absmax_code must have 256 entries, got {absmax_code.shape[0]}"
279
+ )
280
+ torch._check(
281
+ absmax_code.dtype == torch.float32, lambda: f"absmax_code must be float32, got {absmax_code.dtype}"
282
+ )
283
+ torch._check(absmax_offset is not None, lambda: "absmax_offset required when absmax_8bit is provided")
284
+ torch._check(
285
+ absmax_offset.ndim == 0, lambda: f"absmax_offset must be a scalar (0-dim), got {absmax_offset.ndim}D"
286
+ )
287
+ torch._check(
288
+ absmax_offset.dtype == torch.float32, lambda: f"absmax_offset must be float32, got {absmax_offset.dtype}"
289
+ )
290
+ if bias is not None:
291
+ torch._check(bias.ndim == 1, lambda: f"bias must be 1D, got {bias.ndim}D")
292
+ torch._check(bias.shape[0] == shapeB[0], lambda: f"bias length ({bias.shape[0]}) must match N ({shapeB[0]})")
293
+ torch._check(bias.dtype == A.dtype, lambda: f"bias dtype ({bias.dtype}) must match A dtype ({A.dtype})")
294
+ N = shapeB[0]
295
+ return torch.empty((*A.shape[:-1], N), dtype=A.dtype, device=A.device)
296
+
297
+
298
+ torch.library.define(
299
+ "bitsandbytes::dequantize_blockwise",
300
+ "(Tensor A, Tensor absmax, Tensor code, int blocksize, ScalarType dtype) -> Tensor",
301
+ )
302
+
303
+
304
+ @register_fake("bitsandbytes::dequantize_blockwise")
305
+ def _(A: torch.Tensor, absmax: torch.Tensor, code: torch.Tensor, blocksize: int, dtype: torch.dtype) -> torch.Tensor:
306
+ torch._check(blocksize > 0, lambda: f"blocksize must be positive, got {blocksize}")
307
+ torch._check(A.dtype == torch.uint8, lambda: f"A must be uint8, got {A.dtype}")
308
+ torch._check(
309
+ dtype in (torch.float16, torch.bfloat16, torch.float32),
310
+ lambda: f"Blockwise dequantization only supports 16/32-bit floats, but got {dtype}",
311
+ )
312
+ return torch.empty_like(A, dtype=dtype)
313
+
314
+
315
+ torch.library.define(
316
+ "bitsandbytes::dequantize_blockwise.out",
317
+ "(Tensor A, Tensor absmax, Tensor code, int blocksize, ScalarType dtype, Tensor! out) -> ()",
318
+ )
319
+
320
+
321
+ @register_fake("bitsandbytes::dequantize_blockwise.out")
322
+ def _(
323
+ A: torch.Tensor, absmax: torch.Tensor, code: torch.Tensor, blocksize: int, dtype: torch.dtype, out: torch.Tensor
324
+ ):
325
+ torch._check(blocksize > 0, lambda: f"blocksize must be positive, got {blocksize}")
326
+ torch._check(A.dtype == torch.uint8, lambda: f"A must be uint8, got {A.dtype}")
327
+ torch._check(
328
+ dtype in (torch.float16, torch.bfloat16, torch.float32),
329
+ lambda: f"Blockwise dequantization only supports 16/32-bit floats, but got {dtype}",
330
+ )
331
+ torch._check(out.shape == A.shape, lambda: f"Expected out.shape == {A.shape}, got {out.shape}")
332
+ torch._check(out.device == A.device, lambda: f"Expected out.device == {A.device}, got {out.device}")
333
+ torch._check(out.dtype == dtype, lambda: f"Expected out.dtype == {dtype}, got {out.dtype}")
334
+
335
+
336
+ torch.library.define("bitsandbytes::quantize_blockwise", "(Tensor A, Tensor code, int blocksize) -> (Tensor, Tensor)")
337
+
338
+
339
+ @register_fake("bitsandbytes::quantize_blockwise")
340
+ def _(A: torch.Tensor, code: torch.Tensor, blocksize: int) -> tuple[torch.Tensor, torch.Tensor]:
341
+ torch._check(blocksize > 0, lambda: f"blocksize must be positive, got {blocksize}")
342
+ torch._check(
343
+ A.dtype in (torch.float16, torch.bfloat16, torch.float32),
344
+ lambda: f"Blockwise quantization only supports 16/32-bit floats, but got {A.dtype}",
345
+ )
346
+ n = A.numel()
347
+ blocks = -(n // -blocksize)
348
+ absmax = torch.empty((blocks,), device=A.device, dtype=torch.float32)
349
+ out = torch.empty_like(A, dtype=torch.uint8)
350
+ return out, absmax
351
+
352
+
353
+ torch.library.define(
354
+ "bitsandbytes::gemv_4bit",
355
+ "(Tensor A, Tensor B, int[] shapeB, Tensor absmax, Tensor code, int blocksize) -> Tensor",
356
+ )
357
+
358
+
359
+ @register_fake("bitsandbytes::gemv_4bit")
360
+ def _(
361
+ A: torch.Tensor, B: torch.Tensor, shapeB: Sequence[int], absmax: torch.Tensor, code: torch.Tensor, blocksize: int
362
+ ) -> torch.Tensor:
363
+ torch._check(blocksize in (32, 64, 128, 256, 512, 1024, 2048, 4096), lambda: f"invalid blocksize {blocksize}")
364
+ torch._check(
365
+ A.dtype in (torch.float16, torch.bfloat16, torch.float32),
366
+ lambda: f"A must be float16, bfloat16, or float32, got {A.dtype}",
367
+ )
368
+ torch._check(
369
+ B.dtype in (torch.uint8, torch.bfloat16, torch.float16, torch.float32),
370
+ lambda: f"B must be backed by storage of type uint8, bfloat16, float16, or float32, got {B.dtype}",
371
+ )
372
+ shape = (*A.shape[:-1], shapeB[0])
373
+ return torch.empty(shape, device=A.device, dtype=A.dtype)
374
+
375
+
376
+ torch.library.define(
377
+ "bitsandbytes::gemv_4bit.out",
378
+ "(Tensor A, Tensor B, int[] shapeB, Tensor absmax, Tensor code, int blocksize, Tensor! out) -> ()",
379
+ )
380
+
381
+
382
+ @register_fake("bitsandbytes::gemv_4bit.out")
383
+ def _(
384
+ A: torch.Tensor,
385
+ B: torch.Tensor,
386
+ shapeB: Sequence[int],
387
+ absmax: torch.Tensor,
388
+ code: torch.Tensor,
389
+ blocksize: int,
390
+ out: torch.Tensor,
391
+ ) -> None:
392
+ torch._check(blocksize in (32, 64, 128, 256, 512, 1024, 2048, 4096), lambda: f"invalid blocksize {blocksize}")
393
+ torch._check(
394
+ A.dtype in (torch.float16, torch.bfloat16, torch.float32),
395
+ lambda: f"A must be float16, bfloat16, or float32, got {A.dtype}",
396
+ )
397
+ torch._check(
398
+ B.dtype in (torch.uint8, torch.bfloat16, torch.float16, torch.float32),
399
+ lambda: f"B must be backed by storage of type uint8, bfloat16, float16, or float32, got {B.dtype}",
400
+ )
401
+ torch._check(
402
+ out.shape == (*A.shape[:-1], shapeB[0]),
403
+ lambda: f"Expected out.shape == {(*A.shape[:-1], shapeB[0])}, got {out.shape}",
404
+ )
405
+ torch._check(out.device == A.device, lambda: f"Expected out.device == {A.device}, got {out.device}")
406
+ torch._check(out.dtype == A.dtype, lambda: f"Expected out.dtype == {A.dtype}, got {out.dtype}")
407
+
408
+
409
+ torch.library.define(
410
+ "bitsandbytes::optimizer_update_32bit",
411
+ "(str optimizer_name, Tensor(a0!) g, Tensor(a1!) p, Tensor(a2!) state1, Tensor(a3!)? state2, Tensor(a4!)? unorm_vec, float max_unorm, float param_norm, float beta1, float beta2, float beta3, float alpha, float eps, float weight_decay, int step, float lr, float gnorm_scale, bool skip_zeros=False) -> ()",
412
+ )
413
+
414
+
415
+ @register_fake("bitsandbytes::optimizer_update_32bit")
416
+ def _(
417
+ optimizer_name: str,
418
+ g: torch.Tensor,
419
+ p: torch.Tensor,
420
+ state1: torch.Tensor,
421
+ state2: Optional[torch.Tensor],
422
+ unorm_vec: Optional[torch.Tensor],
423
+ max_unorm: float,
424
+ param_norm: float,
425
+ beta1: float,
426
+ beta2: float,
427
+ beta3: float,
428
+ alpha: float,
429
+ eps: float,
430
+ weight_decay: float,
431
+ step: int,
432
+ lr: float,
433
+ gnorm_scale: float,
434
+ skip_zeros=False,
435
+ ) -> None:
436
+ torch._check(
437
+ g.numel() == p.numel(),
438
+ lambda: f"g and p must have the same number of elements, got {g.numel()} and {p.numel()}",
439
+ )
440
+ compute_dtypes = [torch.float16, torch.bfloat16, torch.float32]
441
+
442
+ torch._check(
443
+ g.dtype in compute_dtypes,
444
+ lambda: f"g must be bfloat16, float16, or float32, got {g.dtype}",
445
+ )
446
+ torch._check(
447
+ g.dtype == p.dtype,
448
+ lambda: f"Expected all tensors to have the same dtype, got g.dtype={g.dtype}, p.dtype={p.dtype}",
449
+ )
450
+
451
+
452
+ torch.library.define(
453
+ "bitsandbytes::optimizer_update_8bit_blockwise",
454
+ "(str optimizer_name, Tensor(a0!) g, Tensor(a1!) p, Tensor(a2!) state1, Tensor(a3!)? state2, float beta1, float beta2, float beta3, float alpha, float eps, int step, float lr, Tensor(a4!) qmap1, Tensor(a5!)? qmap2, Tensor(a6!) absmax1, Tensor(a7!)? absmax2, float weight_decay, float gnorm_scale, bool skip_zeros=False) -> ()",
455
+ )
456
+
457
+
458
+ @register_fake("bitsandbytes::optimizer_update_8bit_blockwise")
459
+ def _(
460
+ optimizer_name: str,
461
+ g: torch.Tensor,
462
+ p: torch.Tensor,
463
+ state1: torch.Tensor,
464
+ state2: Optional[torch.Tensor],
465
+ beta1: float,
466
+ beta2: float,
467
+ beta3: float,
468
+ alpha: float,
469
+ eps: float,
470
+ step: int,
471
+ lr: float,
472
+ qmap1: torch.Tensor,
473
+ qmap2: Optional[torch.Tensor],
474
+ absmax1: torch.Tensor,
475
+ absmax2: Optional[torch.Tensor],
476
+ weight_decay: float,
477
+ gnorm_scale: float,
478
+ skip_zeros=False,
479
+ ) -> None:
480
+ torch._check(
481
+ g.numel() == p.numel(),
482
+ lambda: f"g and p must have the same number of elements, got {g.numel()} and {p.numel()}",
483
+ )
484
+ compute_dtypes = [torch.float16, torch.bfloat16, torch.float32]
485
+
486
+ torch._check(
487
+ g.dtype in compute_dtypes,
488
+ lambda: f"g must be bfloat16, float16, or float32, got {g.dtype}",
489
+ )
490
+ torch._check(
491
+ g.dtype == p.dtype,
492
+ lambda: f"Expected all tensors to have the same dtype, got g.dtype={g.dtype}, p.dtype={p.dtype}",
493
+ )
494
+ torch._check(
495
+ state1.dtype == torch.uint8,
496
+ lambda: f"state1 must be uint8, got {state1.dtype}",
497
+ )
498
+ torch._check(
499
+ qmap1.dtype == absmax1.dtype == torch.float32,
500
+ lambda: f"Expected qmap1 and absmax1 to be float32, got qmap1.dtype={qmap1.dtype}, absmax1.dtype={absmax1.dtype}",
501
+ )
502
+ if state2 is not None:
503
+ torch._check(
504
+ state2.dtype == torch.uint8,
505
+ lambda: f"state2 must be uint8, got {state2.dtype}",
506
+ )
507
+ torch._check(
508
+ qmap2.dtype == absmax2.dtype == torch.float32,
509
+ lambda: f"Expected qmap2 and absmax2 to be float32, got qmap2.dtype={qmap2.dtype}, absmax2.dtype={absmax2.dtype}",
510
+ )
File without changes