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,304 @@
1
+ from collections.abc import Sequence
2
+ from typing import Optional
3
+
4
+ import torch
5
+
6
+ from . import kernels_4bit, kernels_8bit_quant, kernels_optim
7
+
8
+ # currently codes unused, kept for reference
9
+ # Should be the same for quant/dequant
10
+ # from bitsandbytes.functional import get_4bit_type
11
+ # _FP4_QUANT_TABLE = get_4bit_type("fp4", device="xpu")
12
+ # _NF4_QUANT_TABLE = get_4bit_type("nf4", device="xpu")
13
+ device_type = torch.accelerator.current_accelerator().type if hasattr(torch, "accelerator") else "cuda"
14
+ torch_accelerator_module = getattr(torch, device_type, torch.cuda)
15
+
16
+
17
+ def quantize_blockwise(A: torch.Tensor, code: torch.Tensor, blocksize: int) -> tuple[torch.Tensor, torch.Tensor]:
18
+ # torch._check(A.dtype == torch.float32, lambda: f"A must be float32 on xpu, got {A.dtype}")
19
+ with torch_accelerator_module.device(A.device):
20
+ out, absmax = kernels_8bit_quant.quantize_blockwise_triton(A.contiguous(), code, blocksize)
21
+ return out, absmax.float()
22
+
23
+
24
+ def dequantize_blockwise(
25
+ A: torch.Tensor, absmax: torch.Tensor, code: torch.Tensor, blocksize: int, dtype: torch.dtype
26
+ ) -> torch.Tensor:
27
+ if A.dtype != torch.uint8:
28
+ raise ValueError(f"A must be uint8, got {A.dtype}")
29
+ # torch._check(dtype == torch.float32, lambda: f"dtype must be float32 on xpu, got {dtype}")
30
+ with torch_accelerator_module.device(A.device):
31
+ out = kernels_8bit_quant.dequant_8bit_blockwise(
32
+ A.contiguous(),
33
+ absmax,
34
+ code,
35
+ blocksize,
36
+ dtype=dtype,
37
+ )
38
+ return out
39
+
40
+
41
+ def dequantize_blockwise_inplace(
42
+ A: torch.Tensor,
43
+ absmax: torch.Tensor,
44
+ code: torch.Tensor,
45
+ blocksize: int,
46
+ dtype: torch.dtype,
47
+ out: torch.Tensor,
48
+ ) -> None:
49
+ if A.dtype != torch.uint8:
50
+ raise ValueError(f"A must be uint8, got {A.dtype}")
51
+ if out.shape != A.shape:
52
+ raise ValueError(f"Expected out.shape == {A.shape}, got {out.shape}")
53
+ if out.device != A.device:
54
+ raise ValueError(f"Expected out.device == {A.device}, got {out.device}")
55
+ if out.dtype != dtype:
56
+ raise ValueError(f"Expected out.dtype == {dtype}, got {out.dtype}")
57
+
58
+ with torch_accelerator_module.device(A.device):
59
+ kernels_8bit_quant.dequant_8bit_blockwise(
60
+ A,
61
+ absmax,
62
+ code,
63
+ blocksize,
64
+ dtype=dtype,
65
+ out=out,
66
+ )
67
+
68
+
69
+ def quantize_4bit(
70
+ A: torch.Tensor, blocksize: int, quant_type: str, quant_storage: torch.dtype
71
+ ) -> tuple[torch.Tensor, torch.Tensor]:
72
+ # torch._check(quant_type == "nf4", lambda: f"quant_type must be nf4 on CPU, got {quant_type}")
73
+ if A.dtype not in (torch.bfloat16, torch.float16, torch.float32):
74
+ raise ValueError(f"Blockwise 4bit quantization only supports 16/32-bit floats, but got {A.dtype}")
75
+
76
+ n = A.numel()
77
+
78
+ # Pad to next multiple of blocksize so the kernel always processes full blocks
79
+ remainder = n % blocksize
80
+ if remainder != 0:
81
+ padding = blocksize - remainder
82
+ A = torch.nn.functional.pad(A.view(-1), (0, padding), value=0.0)
83
+ n = A.numel()
84
+
85
+ blocks = -(n // -(blocksize * 2))
86
+
87
+ absmax = torch.empty((blocks * 2,), device=A.device, dtype=A.dtype)
88
+ # Use n - n//2 instead of (n+1)//2 to avoid integer overflow for large n
89
+ out = torch.empty((n - n // 2, 1), device=A.device, dtype=torch.uint8)
90
+
91
+ with torch_accelerator_module.device(A.device):
92
+ kernels_4bit.quantize_4bit_blockwise_triton(
93
+ A, blocksize, quant_type, blocks, absmax, num_elements=n, quantized_out=out
94
+ )
95
+ packed = out
96
+
97
+ if quant_storage != torch.uint8:
98
+ packed = out.squeeze().view(quant_storage).unsqueeze(1)
99
+
100
+ return packed, absmax.float()
101
+
102
+
103
+ def dequantize_4bit(
104
+ A: torch.Tensor,
105
+ absmax: torch.Tensor,
106
+ blocksize: int,
107
+ quant_type: str,
108
+ shape: Sequence[int],
109
+ dtype: torch.dtype,
110
+ ) -> torch.Tensor:
111
+ # torch._check(quant_type == "nf4", lambda: f"quant_type must be nf4 on XPU, got {quant_type}")
112
+ if dtype not in (torch.bfloat16, torch.float16, torch.float32):
113
+ raise ValueError(f"Blockwise 4bit dequantization only supports 16/32-bit floats, but got {dtype}")
114
+ # torch._check(
115
+ # A.dtype == torch.uint8,
116
+ # lambda: f"Blockwise 4bit dequantization on XPU only supports uint8 storage, got {A.dtype}",
117
+ # )
118
+ # Check if this is fine and fast
119
+ if A.dtype != torch.uint8:
120
+ A = A.squeeze().view(torch.uint8).unsqueeze(1)
121
+
122
+ out = torch.empty(shape, dtype=dtype, device=A.device)
123
+ with torch_accelerator_module.device(A.device):
124
+ kernels_4bit.dequantize_4bit_impl(A, absmax, blocksize, quant_type, dtype, out=out)
125
+
126
+ return out
127
+
128
+
129
+ def dequantize_4bit_inplace(
130
+ A: torch.Tensor,
131
+ absmax: torch.Tensor,
132
+ blocksize: int,
133
+ quant_type: str,
134
+ shape: Sequence[int],
135
+ dtype: torch.dtype,
136
+ out: torch.Tensor,
137
+ ) -> None:
138
+ if out.shape != tuple(shape):
139
+ raise ValueError(f"Expected out.shape == {shape}, got {out.shape}")
140
+ if out.dtype != dtype:
141
+ raise ValueError(f"Expected out.dtype == {dtype}, got {out.dtype}")
142
+ with torch_accelerator_module.device(A.device):
143
+ kernels_4bit.dequantize_4bit_impl(A, absmax, blocksize, quant_type, dtype, out=out)
144
+
145
+
146
+ def gemv_4bit(
147
+ A: torch.Tensor,
148
+ B: torch.Tensor,
149
+ shapeB: Sequence[int],
150
+ absmax: torch.Tensor,
151
+ code: torch.Tensor,
152
+ blocksize: int,
153
+ ) -> torch.Tensor:
154
+ if B.dtype != torch.uint8:
155
+ B = B.squeeze().view(torch.uint8).unsqueeze(1)
156
+
157
+ B_dq_triton = torch.empty(shapeB, dtype=A.dtype, device=A.device)
158
+
159
+ with torch_accelerator_module.device(A.device):
160
+ kernels_4bit.dequantize_4bit_impl_passing_code(
161
+ B,
162
+ absmax,
163
+ blocksize,
164
+ code,
165
+ dtype=A.dtype,
166
+ out=B_dq_triton,
167
+ )
168
+
169
+ return torch.nn.functional.linear(
170
+ A,
171
+ B_dq_triton,
172
+ bias=None,
173
+ )
174
+
175
+
176
+ # optimizer_update_8bit_blockwise_impl = kernels_optim.optimizer_update_8bit_blockwise_pytorch
177
+ # optimizer_update_8bit_blockwise_impl = torch.compile(kernels_optim.optimizer_update_8bit_blockwise_pytorch) # 60ms
178
+ # optimizer_update_8bit_blockwise_impl = kernels_optim.optimizer_update_8bit_blockwise_triton_quant #2.8ms
179
+ # optimizer_update_8bit_blockwise_impl = torch.compile(kernels_optim.optimizer_update_8bit_blockwise_triton_quant) # 2.3ms
180
+ optimizer_update_8bit_blockwise_impl = kernels_optim.optimizer_update_8bit_blockwise_impl # ~0.95ms for adam
181
+
182
+
183
+ def optimizer_update_8bit_blockwise(
184
+ optimizer_name: str,
185
+ g: torch.Tensor,
186
+ p: torch.Tensor,
187
+ state1: torch.Tensor,
188
+ state2: Optional[torch.Tensor],
189
+ beta1: float,
190
+ beta2: float,
191
+ beta3: float,
192
+ alpha: float,
193
+ eps: float,
194
+ step: int,
195
+ lr: float,
196
+ qmap1: torch.Tensor,
197
+ qmap2: Optional[torch.Tensor],
198
+ absmax1: torch.Tensor,
199
+ absmax2: Optional[torch.Tensor],
200
+ weight_decay: float = 0.0,
201
+ gnorm_scale: float = 1.0,
202
+ skip_zeros=False,
203
+ ) -> None:
204
+ # torch._check(
205
+ # g.numel() == p.numel(),
206
+ # lambda: f"g and p must have the same number of elements, got {g.numel()} and {p.numel()}",
207
+ # )
208
+ # compute_dtypes = [torch.float16, torch.bfloat16, torch.float32]
209
+
210
+ # torch._check(
211
+ # g.dtype in compute_dtypes,
212
+ # lambda: f"g must be bfloat16, float16, or float32, got {g.dtype}",
213
+ # )
214
+ # torch._check(
215
+ # g.dtype == p.dtype,
216
+ # lambda: f"Expected all tensors to have the same dtype, got g.dtype={g.dtype}, p.dtype={p.dtype}",
217
+ # )
218
+ # torch._check(
219
+ # state1.dtype == torch.uint8,
220
+ # lambda: f"state1 must be uint8, got {state1.dtype}",
221
+ # )
222
+ # torch._check(
223
+ # qmap1.dtype == absmax1.dtype == torch.float32,
224
+ # lambda: f"Expected qmap1 and absmax1 to be float32, got qmap1.dtype={qmap1.dtype}, absmax1.dtype={absmax1.dtype}",
225
+ # )
226
+ # if state2 is not None:
227
+ # torch._check(
228
+ # state2.dtype == torch.uint8,
229
+ # lambda: f"state2 must be uint8, got {state2.dtype}",
230
+ # )
231
+ # torch._check(
232
+ # qmap2.dtype == absmax2.dtype == torch.float32,
233
+ # lambda: f"Expected qmap2 and absmax2 to be float32, got qmap2.dtype={qmap2.dtype}, absmax2.dtype={absmax2.dtype}",
234
+ # )
235
+
236
+ # Use g.device for device context: paged state tensors appear as CPU tensors
237
+ # but are backed by USM shared memory and accessible from the accelerator.
238
+ with torch_accelerator_module.device(g.device):
239
+ optimizer_update_8bit_blockwise_impl(
240
+ optimizer_name=optimizer_name,
241
+ g=g,
242
+ p=p,
243
+ state1=state1,
244
+ state2=state2,
245
+ beta1=beta1,
246
+ beta2=beta2,
247
+ beta3=beta3,
248
+ alpha=alpha,
249
+ eps=eps,
250
+ step=step,
251
+ lr=lr,
252
+ qmap1=qmap1,
253
+ qmap2=qmap2,
254
+ absmax1=absmax1,
255
+ absmax2=absmax2,
256
+ weight_decay=weight_decay,
257
+ gnorm_scale=gnorm_scale,
258
+ skip_zeros=skip_zeros,
259
+ )
260
+
261
+
262
+ def optimizer_update_32bit(
263
+ optimizer_name: str,
264
+ g: torch.Tensor,
265
+ p: torch.Tensor,
266
+ state1: torch.Tensor,
267
+ state2: Optional[torch.Tensor],
268
+ unorm_vec: Optional[torch.Tensor],
269
+ max_unorm: float,
270
+ param_norm: float,
271
+ beta1: float,
272
+ beta2: float,
273
+ beta3: float,
274
+ alpha: float,
275
+ eps: float,
276
+ weight_decay: float,
277
+ step: int,
278
+ lr: float,
279
+ gnorm_scale: float,
280
+ skip_zeros=False,
281
+ ) -> None:
282
+ # Use g.device for device context: paged state tensors appear as CPU tensors
283
+ # but are backed by USM shared memory and accessible from the accelerator.
284
+ with torch_accelerator_module.device(g.device):
285
+ kernels_optim.optimizer_update_32bit_impl(
286
+ optimizer_name=optimizer_name,
287
+ g=g,
288
+ p=p,
289
+ state1=state1,
290
+ state2=state2,
291
+ unorm_vec=unorm_vec,
292
+ max_unorm=max_unorm,
293
+ param_norm=param_norm,
294
+ beta1=beta1,
295
+ beta2=beta2,
296
+ beta3=beta3,
297
+ alpha=alpha,
298
+ eps=eps,
299
+ weight_decay=weight_decay,
300
+ step=step,
301
+ lr=lr,
302
+ gnorm_scale=gnorm_scale,
303
+ skip_zeros=skip_zeros,
304
+ )
@@ -0,0 +1,94 @@
1
+ from importlib.metadata import metadata
2
+
3
+ from packaging import version
4
+ import torch
5
+
6
+ try:
7
+ import triton # noqa: F401
8
+ import triton.language as tl # noqa: F401
9
+
10
+ triton_available = True
11
+ except ImportError:
12
+ triton_available = False
13
+
14
+
15
+ _NF4_QUANT_TABLE = torch.tensor(
16
+ [
17
+ -1.0,
18
+ -0.6961928009986877,
19
+ -0.5250730514526367,
20
+ -0.39491748809814453,
21
+ -0.28444138169288635,
22
+ -0.18477343022823334,
23
+ -0.09105003625154495,
24
+ 0.0,
25
+ 0.07958029955625534,
26
+ 0.16093020141124725,
27
+ 0.24611230194568634,
28
+ 0.33791524171829224,
29
+ 0.44070982933044434,
30
+ 0.5626170039176941,
31
+ 0.7229568362236023,
32
+ 1.0,
33
+ ],
34
+ dtype=torch.float32,
35
+ device="xpu"
36
+ if hasattr(torch, "xpu") and torch.xpu.is_available()
37
+ else "cpu", # Only cpu/xpu use this table for now.
38
+ )
39
+ _FP4_QUANT_TABLE = torch.tensor(
40
+ [
41
+ 0.0000,
42
+ 0.0052,
43
+ 0.6667,
44
+ 1.0000,
45
+ 0.3333,
46
+ 0.5000,
47
+ 0.1667,
48
+ 0.2500,
49
+ 0.0000,
50
+ -0.0052,
51
+ -0.6667,
52
+ -1.0000,
53
+ -0.3333,
54
+ -0.5000,
55
+ -0.1667,
56
+ -0.2500,
57
+ ],
58
+ dtype=torch.float32,
59
+ device="xpu"
60
+ if hasattr(torch, "xpu") and torch.xpu.is_available()
61
+ else "cpu", # Only cpu/xpu use this table for now.
62
+ )
63
+ CODE = {"nf4": _NF4_QUANT_TABLE, "fp4": _FP4_QUANT_TABLE}
64
+
65
+ # Cache 4-bit dequantization code tensors per (quant_type, device).
66
+ _code_4bit_cache: dict[tuple[str, torch.device], torch.Tensor] = {}
67
+
68
+
69
+ def _get_4bit_code(quant_type: str, device: torch.device) -> torch.Tensor:
70
+ key = (quant_type, device)
71
+ if key not in _code_4bit_cache:
72
+ from bitsandbytes.functional import get_4bit_type
73
+
74
+ _code_4bit_cache[key] = get_4bit_type(quant_type, device=device)
75
+ return _code_4bit_cache[key]
76
+
77
+
78
+ def get_gaudi_sw_version():
79
+ """
80
+ Returns the installed version of Gaudi SW.
81
+ """
82
+ try:
83
+ # if we find the spec, examine the installed version
84
+ plugin_metadata = metadata("habana-torch-plugin")
85
+ plugin_version = plugin_metadata.get("Version")
86
+ if plugin_version:
87
+ gaudi_version = version.parse(plugin_version)
88
+ except Exception:
89
+ gaudi_version = None
90
+
91
+ return gaudi_version
92
+
93
+
94
+ GAUDI_SW_VER = get_gaudi_sw_version()
File without changes
@@ -0,0 +1,305 @@
1
+ from collections.abc import Sequence
2
+ import ctypes as ct
3
+ import logging
4
+ from typing import Optional
5
+ from warnings import warn
6
+
7
+ from packaging import version
8
+ import torch
9
+
10
+ from bitsandbytes.functional import _get_tensor_stream, get_ptr
11
+
12
+ from ..._ops import register_kernel
13
+ from ...cextension import ErrorHandlerMockBNBNativeLibrary, lib
14
+ from ..default.ops import _gemm_4bit_default_impl
15
+ from ..utils import _get_4bit_code, triton_available
16
+
17
+ logger = logging.getLogger(__name__)
18
+
19
+ # _int_mm is available in torch starting from 2.9 version
20
+ if version.parse(torch.__version__).release >= version.parse("2.9").release:
21
+
22
+ @register_kernel("bitsandbytes::int8_linear_matmul", "xpu")
23
+ def _(A: torch.Tensor, B: torch.Tensor):
24
+ return torch._int_mm(
25
+ A.reshape(-1, A.shape[-1]),
26
+ B.t(),
27
+ ).reshape(*A.shape[:-1], B.shape[0])
28
+
29
+
30
+ def _dequantize_4bit_impl(
31
+ A: torch.Tensor,
32
+ absmax: torch.Tensor,
33
+ blocksize: int,
34
+ quant_type: str,
35
+ dtype: torch.dtype,
36
+ out: torch.Tensor,
37
+ ) -> None:
38
+ # XPU SYCL kernels only support contiguous tensors.
39
+ A = A.contiguous()
40
+ args = (
41
+ None,
42
+ get_ptr(A),
43
+ get_ptr(absmax),
44
+ get_ptr(out),
45
+ ct.c_int(blocksize),
46
+ ct.c_int(out.numel()),
47
+ _get_tensor_stream(A),
48
+ )
49
+ if dtype == torch.bfloat16:
50
+ if quant_type == "fp4":
51
+ lib.cdequantize_blockwise_bf16_fp4(*args)
52
+ else:
53
+ lib.cdequantize_blockwise_bf16_nf4(*args)
54
+ elif dtype == torch.float16:
55
+ if quant_type == "fp4":
56
+ lib.cdequantize_blockwise_fp16_fp4(*args)
57
+ else:
58
+ lib.cdequantize_blockwise_fp16_nf4(*args)
59
+ elif dtype == torch.float32:
60
+ if quant_type == "fp4":
61
+ lib.cdequantize_blockwise_fp32_fp4(*args)
62
+ else:
63
+ lib.cdequantize_blockwise_fp32_nf4(*args)
64
+
65
+
66
+ def _dequantize_blockwise_impl(
67
+ A: torch.Tensor, absmax: torch.Tensor, code: torch.Tensor, blocksize: int, dtype: torch.dtype, out: torch.Tensor
68
+ ) -> None:
69
+ # XPU SYCL kernels only support contiguous tensors.
70
+ A = A.contiguous()
71
+ args = (
72
+ get_ptr(code),
73
+ get_ptr(A),
74
+ get_ptr(absmax),
75
+ get_ptr(out),
76
+ ct.c_int(blocksize),
77
+ ct.c_int(A.numel()),
78
+ _get_tensor_stream(A),
79
+ )
80
+ if dtype == torch.float16:
81
+ lib.cdequantize_blockwise_fp16(*args)
82
+ elif dtype == torch.bfloat16:
83
+ lib.cdequantize_blockwise_bf16(*args)
84
+ elif dtype == torch.float32:
85
+ lib.cdequantize_blockwise_fp32(*args)
86
+
87
+
88
+ def _gemv_4bit_impl(
89
+ A: torch.Tensor,
90
+ B: torch.Tensor,
91
+ shapeB: Sequence[int],
92
+ absmax: torch.Tensor,
93
+ code: torch.Tensor,
94
+ blocksize: int,
95
+ out: torch.Tensor,
96
+ ) -> None:
97
+ m = ct.c_int32(1)
98
+ n = ct.c_int32(shapeB[0])
99
+ k = ct.c_int32(shapeB[1])
100
+
101
+ lda = m
102
+ ldb = ct.c_int32((A.shape[-1] + 1) // 2)
103
+ ldc = m
104
+
105
+ stream = _get_tensor_stream(A)
106
+ if A.dtype == torch.float16:
107
+ lib.cgemv_4bit_inference_fp16(
108
+ m,
109
+ n,
110
+ k,
111
+ get_ptr(A),
112
+ get_ptr(B),
113
+ get_ptr(absmax),
114
+ get_ptr(code),
115
+ get_ptr(out),
116
+ lda,
117
+ ldb,
118
+ ldc,
119
+ ct.c_int32(blocksize),
120
+ stream,
121
+ )
122
+ elif A.dtype == torch.bfloat16:
123
+ lib.cgemv_4bit_inference_bf16(
124
+ m,
125
+ n,
126
+ k,
127
+ get_ptr(A),
128
+ get_ptr(B),
129
+ get_ptr(absmax),
130
+ get_ptr(code),
131
+ get_ptr(out),
132
+ lda,
133
+ ldb,
134
+ ldc,
135
+ ct.c_int32(blocksize),
136
+ stream,
137
+ )
138
+ elif A.dtype == torch.float32:
139
+ lib.cgemv_4bit_inference_fp32(
140
+ m,
141
+ n,
142
+ k,
143
+ get_ptr(A),
144
+ get_ptr(B),
145
+ get_ptr(absmax),
146
+ get_ptr(code),
147
+ get_ptr(out),
148
+ lda,
149
+ ldb,
150
+ ldc,
151
+ ct.c_int32(blocksize),
152
+ stream,
153
+ )
154
+
155
+
156
+ @register_kernel("bitsandbytes::gemm_4bit", "xpu")
157
+ def _(
158
+ A: torch.Tensor,
159
+ B: torch.Tensor,
160
+ shapeB: Sequence[int],
161
+ absmax: torch.Tensor,
162
+ blocksize: int,
163
+ quant_type: str,
164
+ bias: Optional[torch.Tensor] = None,
165
+ absmax_8bit: Optional[torch.Tensor] = None,
166
+ absmax_code: Optional[torch.Tensor] = None,
167
+ absmax_offset: Optional[torch.Tensor] = None,
168
+ ) -> torch.Tensor:
169
+ K = A.shape[-1]
170
+ M = A.numel() // K
171
+
172
+ if M == 1:
173
+ if K % blocksize == 0:
174
+ if absmax_8bit is not None:
175
+ absmax = (
176
+ torch.ops.bitsandbytes.dequantize_blockwise.default(
177
+ absmax_8bit, absmax, absmax_code, 256, torch.float32
178
+ )
179
+ + absmax_offset
180
+ )
181
+
182
+ code = _get_4bit_code(quant_type, A.device)
183
+ out = torch.ops.bitsandbytes.gemv_4bit.default(A, B, shapeB, absmax, code, blocksize)
184
+
185
+ if bias is not None:
186
+ out = out + bias
187
+ return out
188
+
189
+ warn(
190
+ f"inner dimension ({K}) is not aligned for fast kernel "
191
+ f"with blocksize={blocksize}, falling back to slower implementation.",
192
+ UserWarning,
193
+ )
194
+
195
+ return _gemm_4bit_default_impl(
196
+ A,
197
+ B,
198
+ shapeB,
199
+ absmax,
200
+ blocksize,
201
+ quant_type,
202
+ bias,
203
+ absmax_8bit=absmax_8bit,
204
+ absmax_code=absmax_code,
205
+ absmax_offset=absmax_offset,
206
+ )
207
+
208
+
209
+ # SYCL should be faster for xpu, so at first checking if it is available.
210
+ if not isinstance(lib, ErrorHandlerMockBNBNativeLibrary):
211
+ logger.info("Register sycl bitsandbytes kernels for XPU")
212
+
213
+ # TODO: Remove the triton register when quantization sycl kernel is ready.
214
+ if triton_available:
215
+ from ..triton import ops as triton_ops
216
+
217
+ register_kernel("bitsandbytes::quantize_blockwise", "xpu")(triton_ops.quantize_blockwise)
218
+ register_kernel("bitsandbytes::quantize_4bit", "xpu")(triton_ops.quantize_4bit)
219
+ register_kernel("bitsandbytes::optimizer_update_8bit_blockwise", "xpu")(
220
+ triton_ops.optimizer_update_8bit_blockwise
221
+ )
222
+ register_kernel("bitsandbytes::optimizer_update_32bit", "xpu")(triton_ops.optimizer_update_32bit)
223
+
224
+ @register_kernel("bitsandbytes::dequantize_4bit", "xpu")
225
+ def _(
226
+ A: torch.Tensor,
227
+ absmax: torch.Tensor,
228
+ blocksize: int,
229
+ quant_type: str,
230
+ shape: Sequence[int],
231
+ dtype: torch.dtype,
232
+ ) -> torch.Tensor:
233
+ out = torch.empty(shape, dtype=dtype, device=A.device)
234
+ _dequantize_4bit_impl(A, absmax, blocksize, quant_type, dtype, out=out)
235
+ return out
236
+
237
+ @register_kernel("bitsandbytes::dequantize_blockwise", "xpu")
238
+ def _(
239
+ A: torch.Tensor, absmax: torch.Tensor, code: torch.Tensor, blocksize: int, dtype: torch.dtype
240
+ ) -> torch.Tensor:
241
+ out = torch.empty_like(A, dtype=dtype)
242
+ _dequantize_blockwise_impl(A, absmax, code, blocksize, dtype, out=out)
243
+ return out
244
+
245
+ @register_kernel("bitsandbytes::dequantize_blockwise.out", "xpu")
246
+ def _(
247
+ A: torch.Tensor,
248
+ absmax: torch.Tensor,
249
+ code: torch.Tensor,
250
+ blocksize: int,
251
+ dtype: torch.dtype,
252
+ out: torch.Tensor,
253
+ ) -> None:
254
+ if out.dtype != dtype:
255
+ raise ValueError(f"Expected out.dtype == {dtype}, got {out.dtype}")
256
+ if out.shape != A.shape:
257
+ raise ValueError(f"Expected out.shape == {A.shape}, got {out.shape}")
258
+ _dequantize_blockwise_impl(A, absmax, code, blocksize, dtype, out=out)
259
+
260
+ @register_kernel("bitsandbytes::gemv_4bit", "xpu")
261
+ def _(
262
+ A: torch.Tensor,
263
+ B: torch.Tensor,
264
+ shapeB: Sequence[int],
265
+ absmax: torch.Tensor,
266
+ code: torch.Tensor,
267
+ blocksize: int,
268
+ ) -> torch.Tensor:
269
+ shape = (*A.shape[:-1], shapeB[0])
270
+ out = torch.empty(shape, device=A.device, dtype=A.dtype)
271
+ _gemv_4bit_impl(A, B, shapeB, absmax, code, blocksize, out=out)
272
+ return out
273
+
274
+ @register_kernel("bitsandbytes::gemv_4bit.out", "xpu")
275
+ def _(
276
+ A: torch.Tensor,
277
+ B: torch.Tensor,
278
+ shapeB: Sequence[int],
279
+ absmax: torch.Tensor,
280
+ code: torch.Tensor,
281
+ blocksize: int,
282
+ out: torch.Tensor,
283
+ ) -> None:
284
+ expected_shape = (*A.shape[:-1], shapeB[0])
285
+ if out.shape != expected_shape:
286
+ raise ValueError(f"Expected out.shape == {expected_shape}, got {out.shape}")
287
+ if out.dtype != A.dtype:
288
+ raise ValueError(f"Expected out.dtype == {A.dtype}, got {out.dtype}")
289
+ _gemv_4bit_impl(A, B, shapeB, absmax, code, blocksize, out=out)
290
+
291
+ elif triton_available:
292
+ logger.info("Register triton bitsandbytes kernels for XPU")
293
+ from ..triton import ops as triton_ops
294
+
295
+ register_kernel("bitsandbytes::quantize_blockwise", "xpu")(triton_ops.quantize_blockwise)
296
+ register_kernel("bitsandbytes::dequantize_blockwise.out", "xpu")(triton_ops.dequantize_blockwise_inplace)
297
+ register_kernel("bitsandbytes::dequantize_blockwise", "xpu")(triton_ops.dequantize_blockwise)
298
+ register_kernel("bitsandbytes::quantize_4bit", "xpu")(triton_ops.quantize_4bit)
299
+ register_kernel("bitsandbytes::dequantize_4bit.out", "xpu")(triton_ops.dequantize_4bit_inplace)
300
+ register_kernel("bitsandbytes::dequantize_4bit", "xpu")(triton_ops.dequantize_4bit)
301
+ register_kernel("bitsandbytes::gemv_4bit", "xpu")(triton_ops.gemv_4bit)
302
+ register_kernel("bitsandbytes::optimizer_update_8bit_blockwise", "xpu")(triton_ops.optimizer_update_8bit_blockwise)
303
+ register_kernel("bitsandbytes::optimizer_update_32bit", "xpu")(triton_ops.optimizer_update_32bit)
304
+ else:
305
+ logger.warning("Register pytorch bitsandbytes kernels for XPU because no native library or triton packages found.")