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.
- bitsandbytes/__init__.py +78 -0
- bitsandbytes/__main__.py +4 -0
- bitsandbytes/_ops.py +510 -0
- bitsandbytes/autograd/__init__.py +0 -0
- bitsandbytes/autograd/_functions.py +491 -0
- bitsandbytes/backends/__init__.py +0 -0
- bitsandbytes/backends/cpu/__init__.py +0 -0
- bitsandbytes/backends/cpu/ops.py +580 -0
- bitsandbytes/backends/cuda/__init__.py +0 -0
- bitsandbytes/backends/cuda/ops.py +1199 -0
- bitsandbytes/backends/default/__init__.py +0 -0
- bitsandbytes/backends/default/ops.py +632 -0
- bitsandbytes/backends/hpu/__init__.py +0 -0
- bitsandbytes/backends/hpu/ops.py +53 -0
- bitsandbytes/backends/mps/__init__.py +0 -0
- bitsandbytes/backends/mps/ops.py +277 -0
- bitsandbytes/backends/triton/__init__.py +0 -0
- bitsandbytes/backends/triton/kernels_4bit.py +577 -0
- bitsandbytes/backends/triton/kernels_8bit_quant.py +195 -0
- bitsandbytes/backends/triton/kernels_optim.py +1177 -0
- bitsandbytes/backends/triton/ops.py +304 -0
- bitsandbytes/backends/utils.py +94 -0
- bitsandbytes/backends/xpu/__init__.py +0 -0
- bitsandbytes/backends/xpu/ops.py +305 -0
- bitsandbytes/cextension.py +405 -0
- bitsandbytes/consts.py +12 -0
- bitsandbytes/cuda_specs.py +111 -0
- bitsandbytes/diagnostics/__init__.py +0 -0
- bitsandbytes/diagnostics/cuda.py +193 -0
- bitsandbytes/diagnostics/main.py +134 -0
- bitsandbytes/diagnostics/utils.py +12 -0
- bitsandbytes/functional.py +1810 -0
- bitsandbytes/libbitsandbytes_cpu.dll +0 -0
- bitsandbytes/nn/__init__.py +19 -0
- bitsandbytes/nn/modules.py +1220 -0
- bitsandbytes/nn/parametrize.py +206 -0
- bitsandbytes/optim/__init__.py +22 -0
- bitsandbytes/optim/adagrad.py +187 -0
- bitsandbytes/optim/adam.py +346 -0
- bitsandbytes/optim/adamw.py +337 -0
- bitsandbytes/optim/ademamix.py +410 -0
- bitsandbytes/optim/lamb.py +190 -0
- bitsandbytes/optim/lars.py +259 -0
- bitsandbytes/optim/lion.py +266 -0
- bitsandbytes/optim/optimizer.py +756 -0
- bitsandbytes/optim/rmsprop.py +170 -0
- bitsandbytes/optim/sgd.py +152 -0
- bitsandbytes/py.typed +0 -0
- bitsandbytes/utils.py +208 -0
- bitsandbytes-0.50.0.dist-info/METADATA +288 -0
- bitsandbytes-0.50.0.dist-info/RECORD +54 -0
- bitsandbytes-0.50.0.dist-info/WHEEL +5 -0
- bitsandbytes-0.50.0.dist-info/licenses/LICENSE +21 -0
- 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.")
|