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,580 @@
|
|
|
1
|
+
from collections.abc import Sequence
|
|
2
|
+
import ctypes as ct
|
|
3
|
+
import logging
|
|
4
|
+
import math
|
|
5
|
+
from math import prod
|
|
6
|
+
from typing import Optional
|
|
7
|
+
|
|
8
|
+
import torch
|
|
9
|
+
|
|
10
|
+
from bitsandbytes.functional import get_ptr, has_avx512bf16
|
|
11
|
+
|
|
12
|
+
from ..._ops import register_kernel
|
|
13
|
+
from ...cextension import ErrorHandlerMockBNBNativeLibrary, lib
|
|
14
|
+
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
16
|
+
|
|
17
|
+
_has_avx512 = torch.backends.cpu.get_cpu_capability() == "AVX512"
|
|
18
|
+
|
|
19
|
+
# torch._int_mm for s8@s8->s32 is supported on CPU from torch 2.4+.
|
|
20
|
+
# However, we can overflow if we use this without AVX512_VNNI support.
|
|
21
|
+
# This is fixed in torch 2.6+, so we set this as the minimum to be safe.
|
|
22
|
+
# For more information: https://github.com/pytorch/pytorch/pull/136942
|
|
23
|
+
#
|
|
24
|
+
# Without AVX-512 (including aarch64), torch._int_mm uses a scalar fallback
|
|
25
|
+
# that is much slower than fp32 matmul. Only use it when AVX-512 is available.
|
|
26
|
+
if torch.__version__ >= (2, 6) and _has_avx512:
|
|
27
|
+
|
|
28
|
+
@register_kernel("bitsandbytes::int8_linear_matmul", "cpu")
|
|
29
|
+
def _(A: torch.Tensor, B: torch.Tensor):
|
|
30
|
+
return torch._int_mm(
|
|
31
|
+
A.reshape(-1, A.shape[-1]),
|
|
32
|
+
B.t(),
|
|
33
|
+
).reshape(*A.shape[:-1], B.shape[0])
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
if not isinstance(lib, ErrorHandlerMockBNBNativeLibrary):
|
|
37
|
+
|
|
38
|
+
@register_kernel("bitsandbytes::quantize_blockwise", "cpu")
|
|
39
|
+
def _(A: torch.Tensor, code: torch.Tensor, blocksize: int) -> tuple[torch.Tensor, torch.Tensor]:
|
|
40
|
+
A = A.contiguous()
|
|
41
|
+
n = A.numel()
|
|
42
|
+
blocks = -(n // -blocksize)
|
|
43
|
+
|
|
44
|
+
absmax = torch.empty((blocks,), device=A.device, dtype=torch.float32)
|
|
45
|
+
out = torch.empty(A.shape, device=A.device, dtype=torch.uint8)
|
|
46
|
+
|
|
47
|
+
if A.dtype == torch.float32:
|
|
48
|
+
lib.cquantize_blockwise_cpu_fp32(
|
|
49
|
+
get_ptr(code),
|
|
50
|
+
get_ptr(A),
|
|
51
|
+
get_ptr(absmax),
|
|
52
|
+
get_ptr(out),
|
|
53
|
+
ct.c_longlong(blocksize),
|
|
54
|
+
ct.c_longlong(n),
|
|
55
|
+
)
|
|
56
|
+
elif A.dtype == torch.bfloat16:
|
|
57
|
+
lib.cquantize_blockwise_cpu_bf16(
|
|
58
|
+
get_ptr(code),
|
|
59
|
+
get_ptr(A),
|
|
60
|
+
get_ptr(absmax),
|
|
61
|
+
get_ptr(out),
|
|
62
|
+
ct.c_longlong(blocksize),
|
|
63
|
+
ct.c_longlong(n),
|
|
64
|
+
)
|
|
65
|
+
elif A.dtype == torch.float16:
|
|
66
|
+
lib.cquantize_blockwise_cpu_fp16(
|
|
67
|
+
get_ptr(code),
|
|
68
|
+
get_ptr(A),
|
|
69
|
+
get_ptr(absmax),
|
|
70
|
+
get_ptr(out),
|
|
71
|
+
ct.c_longlong(blocksize),
|
|
72
|
+
ct.c_longlong(n),
|
|
73
|
+
)
|
|
74
|
+
else:
|
|
75
|
+
# Generic fallback for other dtypes
|
|
76
|
+
A_flat = A.reshape(n).float()
|
|
77
|
+
rem = n % blocksize
|
|
78
|
+
has_rem = rem > 0
|
|
79
|
+
A_com = A_flat[: n - rem]
|
|
80
|
+
A_com_reshaped = A_com.reshape(n // blocksize, blocksize)
|
|
81
|
+
absmax[: blocks - has_rem] = torch.abs(A_com_reshaped).max(dim=-1)[0]
|
|
82
|
+
scaled_A = torch.clamp(A_com_reshaped * (1 / absmax[: blocks - has_rem].view(-1, 1)), -1, 1)
|
|
83
|
+
scaled_A = scaled_A.reshape(-1)
|
|
84
|
+
if has_rem:
|
|
85
|
+
absmax[-1] = torch.abs(A_flat[n - rem :]).max()
|
|
86
|
+
scaled_A_rem = torch.clamp(A_flat[n - rem :] * (1 / absmax[-1]), -1, 1)
|
|
87
|
+
scaled_A = torch.cat([scaled_A, scaled_A_rem], dim=0)
|
|
88
|
+
|
|
89
|
+
diff = torch.abs(scaled_A.unsqueeze(-1) - code.to(scaled_A.device))
|
|
90
|
+
out = torch.argmin(diff, dim=-1).to(torch.uint8).to(scaled_A.device).reshape(A.shape)
|
|
91
|
+
|
|
92
|
+
return out, absmax
|
|
93
|
+
|
|
94
|
+
@register_kernel("bitsandbytes::dequantize_blockwise", "cpu")
|
|
95
|
+
def _(
|
|
96
|
+
A: torch.Tensor, absmax: torch.Tensor, code: torch.Tensor, blocksize: int, dtype: torch.dtype
|
|
97
|
+
) -> torch.Tensor:
|
|
98
|
+
A = A.contiguous()
|
|
99
|
+
out = torch.empty_like(A, dtype=dtype)
|
|
100
|
+
if dtype == torch.float32:
|
|
101
|
+
lib.cdequantize_blockwise_cpu_fp32(
|
|
102
|
+
get_ptr(code),
|
|
103
|
+
get_ptr(A),
|
|
104
|
+
get_ptr(absmax),
|
|
105
|
+
get_ptr(out),
|
|
106
|
+
ct.c_longlong(blocksize),
|
|
107
|
+
ct.c_longlong(A.numel()),
|
|
108
|
+
)
|
|
109
|
+
elif dtype == torch.bfloat16:
|
|
110
|
+
lib.cdequantize_blockwise_cpu_bf16(
|
|
111
|
+
get_ptr(code),
|
|
112
|
+
get_ptr(A),
|
|
113
|
+
get_ptr(absmax),
|
|
114
|
+
get_ptr(out),
|
|
115
|
+
ct.c_longlong(blocksize),
|
|
116
|
+
ct.c_longlong(A.numel()),
|
|
117
|
+
)
|
|
118
|
+
elif dtype == torch.float16:
|
|
119
|
+
lib.cdequantize_blockwise_cpu_fp16(
|
|
120
|
+
get_ptr(code),
|
|
121
|
+
get_ptr(A),
|
|
122
|
+
get_ptr(absmax),
|
|
123
|
+
get_ptr(out),
|
|
124
|
+
ct.c_longlong(blocksize),
|
|
125
|
+
ct.c_longlong(A.numel()),
|
|
126
|
+
)
|
|
127
|
+
else:
|
|
128
|
+
out = code[A.reshape(-1).int()]
|
|
129
|
+
blocks = out.shape[-1] // blocksize
|
|
130
|
+
res = out.shape[-1] % blocksize
|
|
131
|
+
if res != 0:
|
|
132
|
+
out = torch.nn.functional.pad(out, (0, blocksize - res), mode="constant", value=0)
|
|
133
|
+
out = (out.view(-1, blocksize) * absmax.view(-1, 1)).to(dtype).reshape(-1)
|
|
134
|
+
out = out[: blocks * blocksize + res]
|
|
135
|
+
out = out.reshape(A.shape)
|
|
136
|
+
|
|
137
|
+
return out
|
|
138
|
+
|
|
139
|
+
@register_kernel("bitsandbytes::dequantize_4bit", "cpu")
|
|
140
|
+
def _(
|
|
141
|
+
A: torch.Tensor,
|
|
142
|
+
absmax: torch.Tensor,
|
|
143
|
+
blocksize: int,
|
|
144
|
+
quant_type: str,
|
|
145
|
+
shape: Sequence[int],
|
|
146
|
+
dtype: torch.dtype,
|
|
147
|
+
) -> torch.Tensor:
|
|
148
|
+
# Fallback as AVX512 implementation has accuracy issues with blocksize >= 2048.
|
|
149
|
+
# Note: this is not a common use case.
|
|
150
|
+
avx512_fallback = _has_avx512 and blocksize >= 2048
|
|
151
|
+
|
|
152
|
+
# Odd shape is not supported by this kernel; fallback to generic implementation
|
|
153
|
+
shape_fallback = shape[-1] % 2 != 0
|
|
154
|
+
|
|
155
|
+
if avx512_fallback or shape_fallback:
|
|
156
|
+
from ..default.ops import _dequantize_4bit_compute
|
|
157
|
+
from ..utils import _get_4bit_code
|
|
158
|
+
|
|
159
|
+
if A.dtype != torch.uint8:
|
|
160
|
+
A = A.view(torch.uint8)
|
|
161
|
+
code = _get_4bit_code(quant_type, A.device)
|
|
162
|
+
return _dequantize_4bit_compute(A.reshape(-1), absmax, code, blocksize, shape, dtype)
|
|
163
|
+
|
|
164
|
+
# Enable non uint8 dtype
|
|
165
|
+
if A.dtype != torch.uint8:
|
|
166
|
+
A = A.view(torch.uint8)
|
|
167
|
+
|
|
168
|
+
# TODO: support half precision absmax
|
|
169
|
+
if absmax.dtype != torch.float32:
|
|
170
|
+
absmax = absmax.float()
|
|
171
|
+
|
|
172
|
+
if len(shape) == 1:
|
|
173
|
+
shape = (1, shape[0])
|
|
174
|
+
|
|
175
|
+
m = prod(shape[:-1])
|
|
176
|
+
n = shape[-1]
|
|
177
|
+
|
|
178
|
+
A = A.reshape(m, n // 2)
|
|
179
|
+
out = torch.empty(shape, dtype=dtype, device=A.device)
|
|
180
|
+
|
|
181
|
+
if quant_type == "fp4":
|
|
182
|
+
if dtype == torch.float32:
|
|
183
|
+
lib.cdequantize_blockwise_cpu_fp4_fp32(
|
|
184
|
+
get_ptr(A),
|
|
185
|
+
get_ptr(absmax),
|
|
186
|
+
get_ptr(out),
|
|
187
|
+
ct.c_longlong(blocksize),
|
|
188
|
+
ct.c_longlong(m),
|
|
189
|
+
ct.c_longlong(n),
|
|
190
|
+
)
|
|
191
|
+
elif dtype == torch.bfloat16:
|
|
192
|
+
lib.cdequantize_blockwise_cpu_fp4_bf16(
|
|
193
|
+
get_ptr(A),
|
|
194
|
+
get_ptr(absmax),
|
|
195
|
+
get_ptr(out),
|
|
196
|
+
ct.c_longlong(blocksize),
|
|
197
|
+
ct.c_longlong(m),
|
|
198
|
+
ct.c_longlong(n),
|
|
199
|
+
)
|
|
200
|
+
elif dtype == torch.float16:
|
|
201
|
+
lib.cdequantize_blockwise_cpu_fp4_fp16(
|
|
202
|
+
get_ptr(A),
|
|
203
|
+
get_ptr(absmax),
|
|
204
|
+
get_ptr(out),
|
|
205
|
+
ct.c_longlong(blocksize),
|
|
206
|
+
ct.c_longlong(m),
|
|
207
|
+
ct.c_longlong(n),
|
|
208
|
+
)
|
|
209
|
+
elif quant_type == "nf4":
|
|
210
|
+
if dtype == torch.float32:
|
|
211
|
+
lib.cdequantize_blockwise_cpu_nf4_fp32(
|
|
212
|
+
get_ptr(A),
|
|
213
|
+
get_ptr(absmax),
|
|
214
|
+
get_ptr(out),
|
|
215
|
+
ct.c_longlong(blocksize),
|
|
216
|
+
ct.c_longlong(m),
|
|
217
|
+
ct.c_longlong(n),
|
|
218
|
+
)
|
|
219
|
+
elif dtype == torch.bfloat16:
|
|
220
|
+
lib.cdequantize_blockwise_cpu_nf4_bf16(
|
|
221
|
+
get_ptr(A),
|
|
222
|
+
get_ptr(absmax),
|
|
223
|
+
get_ptr(out),
|
|
224
|
+
ct.c_longlong(blocksize),
|
|
225
|
+
ct.c_longlong(m),
|
|
226
|
+
ct.c_longlong(n),
|
|
227
|
+
)
|
|
228
|
+
elif dtype == torch.float16:
|
|
229
|
+
lib.cdequantize_blockwise_cpu_nf4_fp16(
|
|
230
|
+
get_ptr(A),
|
|
231
|
+
get_ptr(absmax),
|
|
232
|
+
get_ptr(out),
|
|
233
|
+
ct.c_longlong(blocksize),
|
|
234
|
+
ct.c_longlong(m),
|
|
235
|
+
ct.c_longlong(n),
|
|
236
|
+
)
|
|
237
|
+
else:
|
|
238
|
+
raise ValueError
|
|
239
|
+
|
|
240
|
+
return out
|
|
241
|
+
|
|
242
|
+
if has_avx512bf16():
|
|
243
|
+
gemm_4bit_forward_kernel = None
|
|
244
|
+
try:
|
|
245
|
+
from kernels import get_kernel
|
|
246
|
+
|
|
247
|
+
gemm_4bit_forward_kernel = get_kernel(
|
|
248
|
+
"kernels-community/quantization-bitsandbytes", version=1
|
|
249
|
+
).gemm_4bit_forward
|
|
250
|
+
except Exception as exc: # pragma: no cover - best effort fallback
|
|
251
|
+
gemm_4bit_forward_kernel = None
|
|
252
|
+
logger.warning(
|
|
253
|
+
"Failed to load CPU gemm_4bit_forward from kernels-community: %s. Please make sure you already `pip install kernels` and the kernels >= 0.11.1",
|
|
254
|
+
exc,
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
@register_kernel("bitsandbytes::gemv_4bit", "cpu")
|
|
258
|
+
def _(
|
|
259
|
+
A: torch.Tensor,
|
|
260
|
+
B: torch.Tensor,
|
|
261
|
+
shapeB: Sequence[int],
|
|
262
|
+
absmax: torch.Tensor,
|
|
263
|
+
code: torch.Tensor,
|
|
264
|
+
blocksize: int,
|
|
265
|
+
) -> torch.Tensor:
|
|
266
|
+
if B.dtype != torch.uint8:
|
|
267
|
+
B = B.contiguous().view(torch.uint8)
|
|
268
|
+
dtype = A.dtype
|
|
269
|
+
quant_type = "fp4" if code[1] > 0 else "nf4"
|
|
270
|
+
# cpu fused op only support bf16 for now.
|
|
271
|
+
if dtype != torch.bfloat16:
|
|
272
|
+
A = A.to(torch.bfloat16)
|
|
273
|
+
if absmax.dtype != torch.bfloat16:
|
|
274
|
+
absmax = absmax.to(torch.bfloat16)
|
|
275
|
+
|
|
276
|
+
final_out_shape = (*A.shape[:-1], shapeB[0])
|
|
277
|
+
A = A.reshape(-1, A.shape[-1])
|
|
278
|
+
out_shape = (*A.shape[:-1], shapeB[0])
|
|
279
|
+
if gemm_4bit_forward_kernel is not None:
|
|
280
|
+
quant_type_num = 1 if quant_type == "fp4" else 0
|
|
281
|
+
# C++ kernel expects weight shape (N, K_packed), ensure 2D contiguous
|
|
282
|
+
B_2d = B.reshape(shapeB[0], -1).contiguous()
|
|
283
|
+
out = gemm_4bit_forward_kernel(A, B_2d, absmax, blocksize, quant_type_num)
|
|
284
|
+
else:
|
|
285
|
+
out = torch.empty(out_shape, dtype=A.dtype, device=A.device)
|
|
286
|
+
M = A.shape[0]
|
|
287
|
+
N = shapeB[0]
|
|
288
|
+
K = A.shape[1]
|
|
289
|
+
x_strideM = A.stride(0)
|
|
290
|
+
out_strideM = out.stride(0)
|
|
291
|
+
if quant_type == "fp4":
|
|
292
|
+
lib.gemv_4bit_inference_cpu_fp4_bf16(
|
|
293
|
+
ct.c_int64(M),
|
|
294
|
+
ct.c_int64(N),
|
|
295
|
+
ct.c_int64(K),
|
|
296
|
+
get_ptr(A),
|
|
297
|
+
get_ptr(B),
|
|
298
|
+
get_ptr(absmax),
|
|
299
|
+
get_ptr(out),
|
|
300
|
+
ct.c_int64(blocksize),
|
|
301
|
+
ct.c_int64(x_strideM),
|
|
302
|
+
ct.c_int64(out_strideM),
|
|
303
|
+
)
|
|
304
|
+
elif quant_type == "nf4":
|
|
305
|
+
lib.gemv_4bit_inference_cpu_nf4_bf16(
|
|
306
|
+
ct.c_int64(M),
|
|
307
|
+
ct.c_int64(N),
|
|
308
|
+
ct.c_int64(K),
|
|
309
|
+
get_ptr(A),
|
|
310
|
+
get_ptr(B),
|
|
311
|
+
get_ptr(absmax),
|
|
312
|
+
get_ptr(out),
|
|
313
|
+
ct.c_int64(blocksize),
|
|
314
|
+
ct.c_int64(x_strideM),
|
|
315
|
+
ct.c_int64(out_strideM),
|
|
316
|
+
)
|
|
317
|
+
|
|
318
|
+
if dtype != torch.bfloat16:
|
|
319
|
+
out = out.to(dtype)
|
|
320
|
+
|
|
321
|
+
return out.reshape(final_out_shape)
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
# ==================== CPU Optimizer Kernels ====================
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
def _compute_update_norm_and_scale(
|
|
328
|
+
update: torch.Tensor,
|
|
329
|
+
unorm_vec: Optional[torch.Tensor],
|
|
330
|
+
max_unorm: float,
|
|
331
|
+
param_norm: float,
|
|
332
|
+
) -> float:
|
|
333
|
+
"""Compute trust-ratio scaling factor for LAMB/LARS and store update norm."""
|
|
334
|
+
if max_unorm <= 0.0:
|
|
335
|
+
return 1.0
|
|
336
|
+
unorm = torch.norm(update).item()
|
|
337
|
+
if unorm_vec is not None:
|
|
338
|
+
unorm_vec.fill_(unorm)
|
|
339
|
+
if unorm > max_unorm * param_norm:
|
|
340
|
+
return (max_unorm * param_norm) / unorm
|
|
341
|
+
return 1.0
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
@torch.no_grad()
|
|
345
|
+
def _optimizer_update_32bit_cpu(
|
|
346
|
+
optimizer_name: str,
|
|
347
|
+
g: torch.Tensor,
|
|
348
|
+
p: torch.Tensor,
|
|
349
|
+
state1: torch.Tensor,
|
|
350
|
+
state2: Optional[torch.Tensor],
|
|
351
|
+
unorm_vec: Optional[torch.Tensor],
|
|
352
|
+
max_unorm: float,
|
|
353
|
+
param_norm: float,
|
|
354
|
+
beta1: float,
|
|
355
|
+
beta2: float,
|
|
356
|
+
beta3: float,
|
|
357
|
+
alpha: float,
|
|
358
|
+
eps: float,
|
|
359
|
+
weight_decay: float,
|
|
360
|
+
step: int,
|
|
361
|
+
lr: float,
|
|
362
|
+
gnorm_scale: float,
|
|
363
|
+
skip_zeros: bool = False,
|
|
364
|
+
) -> None:
|
|
365
|
+
g_float = g.float() * gnorm_scale
|
|
366
|
+
p_float = p.data.float()
|
|
367
|
+
|
|
368
|
+
if optimizer_name in ("adam", "lamb"):
|
|
369
|
+
# Adam / LAMB (2-state): m and v
|
|
370
|
+
state1.mul_(beta1).add_(g_float, alpha=1.0 - beta1)
|
|
371
|
+
state2.mul_(beta2).addcmul_(g_float, g_float, value=1.0 - beta2)
|
|
372
|
+
|
|
373
|
+
correction1 = 1.0 - beta1**step
|
|
374
|
+
correction2 = math.sqrt(1.0 - beta2**step)
|
|
375
|
+
step_size = -lr * correction2 / correction1
|
|
376
|
+
|
|
377
|
+
if weight_decay > 0.0:
|
|
378
|
+
p_float.mul_(1.0 - lr * weight_decay)
|
|
379
|
+
|
|
380
|
+
update = state1 / (state2.sqrt() + eps * correction2)
|
|
381
|
+
|
|
382
|
+
update_scale = _compute_update_norm_and_scale(update, unorm_vec, max_unorm, param_norm)
|
|
383
|
+
p_float.add_(update, alpha=step_size * update_scale)
|
|
384
|
+
|
|
385
|
+
elif optimizer_name == "ademamix":
|
|
386
|
+
# AdEMAMix (2-state): state1 shape is (2, *p.shape), state1[0]=m1, state1[1]=m2
|
|
387
|
+
m1 = state1[0]
|
|
388
|
+
m2 = state1[1]
|
|
389
|
+
nu = state2
|
|
390
|
+
|
|
391
|
+
m1.mul_(beta1).add_(g_float, alpha=1.0 - beta1)
|
|
392
|
+
m2.mul_(beta3).add_(g_float, alpha=1.0 - beta3)
|
|
393
|
+
nu.mul_(beta2).addcmul_(g_float, g_float, value=1.0 - beta2)
|
|
394
|
+
|
|
395
|
+
correction1 = 1.0 - beta1**step
|
|
396
|
+
correction2 = math.sqrt(1.0 - beta2**step)
|
|
397
|
+
|
|
398
|
+
if weight_decay > 0.0:
|
|
399
|
+
p_float.mul_(1.0 - lr * weight_decay)
|
|
400
|
+
|
|
401
|
+
mixed_momentum = (m1 / correction1) + (alpha * m2)
|
|
402
|
+
adaptive_term = (nu.sqrt() / correction2) + eps
|
|
403
|
+
p_float.add_(mixed_momentum / adaptive_term, alpha=-lr)
|
|
404
|
+
|
|
405
|
+
elif optimizer_name in ("momentum", "lars"):
|
|
406
|
+
# SGD with momentum / LARS (1-state)
|
|
407
|
+
g_wd = g_float.add(p_float, alpha=weight_decay) if weight_decay > 0.0 else g_float
|
|
408
|
+
|
|
409
|
+
if step == 1:
|
|
410
|
+
state1.copy_(g_wd)
|
|
411
|
+
else:
|
|
412
|
+
state1.mul_(beta1).add_(g_wd)
|
|
413
|
+
|
|
414
|
+
update_scale = _compute_update_norm_and_scale(state1, unorm_vec, max_unorm, param_norm)
|
|
415
|
+
p_float.add_(state1, alpha=-lr * update_scale)
|
|
416
|
+
|
|
417
|
+
elif optimizer_name == "lion":
|
|
418
|
+
# Lion (2-state sign update)
|
|
419
|
+
if weight_decay > 0.0:
|
|
420
|
+
p_float.mul_(1.0 - lr * weight_decay)
|
|
421
|
+
|
|
422
|
+
update = state1.mul(beta1).add(g_float, alpha=1.0 - beta1)
|
|
423
|
+
p_float.add_(update.sign(), alpha=-lr)
|
|
424
|
+
|
|
425
|
+
state1.mul_(beta2).add_(g_float, alpha=1.0 - beta2)
|
|
426
|
+
|
|
427
|
+
elif optimizer_name == "rmsprop":
|
|
428
|
+
# RMSprop (1-state)
|
|
429
|
+
g_wd = g_float.add(p_float, alpha=weight_decay) if weight_decay > 0.0 else g_float
|
|
430
|
+
state1.mul_(beta1).addcmul_(g_wd, g_wd, value=1.0 - beta1)
|
|
431
|
+
|
|
432
|
+
update = g_wd / (state1.sqrt() + eps)
|
|
433
|
+
update_scale = _compute_update_norm_and_scale(update, unorm_vec, max_unorm, param_norm)
|
|
434
|
+
p_float.add_(update, alpha=-lr * update_scale)
|
|
435
|
+
|
|
436
|
+
elif optimizer_name == "adagrad":
|
|
437
|
+
# Adagrad (1-state)
|
|
438
|
+
g_wd = g_float.add(p_float, alpha=weight_decay) if weight_decay > 0.0 else g_float
|
|
439
|
+
state1.addcmul_(g_wd, g_wd, value=1.0)
|
|
440
|
+
|
|
441
|
+
update = g_wd / (state1.sqrt() + eps)
|
|
442
|
+
p_float.add_(update, alpha=-lr)
|
|
443
|
+
|
|
444
|
+
else:
|
|
445
|
+
raise ValueError(f"Unsupported optimizer for CPU: {optimizer_name}")
|
|
446
|
+
|
|
447
|
+
# Write back to original precision
|
|
448
|
+
p.data.copy_(p_float)
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
register_kernel("bitsandbytes::optimizer_update_32bit", "cpu")(_optimizer_update_32bit_cpu)
|
|
452
|
+
|
|
453
|
+
|
|
454
|
+
@torch.no_grad()
|
|
455
|
+
def _dequant_blockwise_fp32_direct(
|
|
456
|
+
A_uint8: torch.Tensor, absmax: torch.Tensor, code: torch.Tensor, blocksize: int
|
|
457
|
+
) -> torch.Tensor:
|
|
458
|
+
return torch.ops.bitsandbytes.dequantize_blockwise(A_uint8, absmax, code, blocksize, torch.float32)
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
def _quant_blockwise_fp32_direct(
|
|
462
|
+
A_fp32: torch.Tensor, code: torch.Tensor, absmax_out: torch.Tensor, out_uint8: torch.Tensor, blocksize: int
|
|
463
|
+
) -> None:
|
|
464
|
+
out, absmax = torch.ops.bitsandbytes.quantize_blockwise(A_fp32, code, blocksize)
|
|
465
|
+
out_uint8.copy_(out)
|
|
466
|
+
absmax_out.copy_(absmax)
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
def _optimizer_update_8bit_blockwise_cpu(
|
|
470
|
+
optimizer_name: str,
|
|
471
|
+
g: torch.Tensor,
|
|
472
|
+
p: torch.Tensor,
|
|
473
|
+
state1: torch.Tensor,
|
|
474
|
+
state2: Optional[torch.Tensor],
|
|
475
|
+
beta1: float,
|
|
476
|
+
beta2: float,
|
|
477
|
+
beta3: float,
|
|
478
|
+
alpha: float,
|
|
479
|
+
eps: float,
|
|
480
|
+
step: int,
|
|
481
|
+
lr: float,
|
|
482
|
+
qmap1: torch.Tensor,
|
|
483
|
+
qmap2: Optional[torch.Tensor],
|
|
484
|
+
absmax1: torch.Tensor,
|
|
485
|
+
absmax2: Optional[torch.Tensor],
|
|
486
|
+
weight_decay: float,
|
|
487
|
+
gnorm_scale: float,
|
|
488
|
+
skip_zeros: bool = False,
|
|
489
|
+
) -> None:
|
|
490
|
+
blocksize = 256
|
|
491
|
+
|
|
492
|
+
# Dequantize states
|
|
493
|
+
if optimizer_name == "ademamix" and absmax1.ndim == 2:
|
|
494
|
+
s1_1 = _dequant_blockwise_fp32_direct(state1[0], absmax1[0], qmap1, blocksize)
|
|
495
|
+
s1_2 = _dequant_blockwise_fp32_direct(state1[1], absmax1[1], qmap1, blocksize)
|
|
496
|
+
state1_fp32 = torch.stack([s1_1, s1_2])
|
|
497
|
+
else:
|
|
498
|
+
state1_fp32 = _dequant_blockwise_fp32_direct(state1, absmax1, qmap1, blocksize)
|
|
499
|
+
|
|
500
|
+
state2_fp32 = None
|
|
501
|
+
if state2 is not None and qmap2 is not None and absmax2 is not None:
|
|
502
|
+
state2_fp32 = _dequant_blockwise_fp32_direct(state2, absmax2, qmap2, blocksize)
|
|
503
|
+
|
|
504
|
+
grad = g.float() * gnorm_scale
|
|
505
|
+
p_fp32 = p.data.float()
|
|
506
|
+
|
|
507
|
+
if optimizer_name in ("adam", "lamb"):
|
|
508
|
+
state1_fp32.mul_(beta1).add_(grad, alpha=1.0 - beta1)
|
|
509
|
+
state2_fp32.mul_(beta2).addcmul_(grad, grad, value=1.0 - beta2)
|
|
510
|
+
|
|
511
|
+
correction1 = 1.0 - beta1**step
|
|
512
|
+
correction2 = math.sqrt(1.0 - beta2**step)
|
|
513
|
+
|
|
514
|
+
denom = (state2_fp32.sqrt() / correction2).add_(eps)
|
|
515
|
+
if weight_decay > 0.0:
|
|
516
|
+
p_fp32.mul_(1.0 - lr * weight_decay)
|
|
517
|
+
p_fp32.addcdiv_(state1_fp32, denom, value=-lr / correction1)
|
|
518
|
+
|
|
519
|
+
elif optimizer_name == "ademamix":
|
|
520
|
+
m1_fp32, m2_fp32 = state1_fp32[0], state1_fp32[1]
|
|
521
|
+
nu_fp32 = state2_fp32
|
|
522
|
+
|
|
523
|
+
m1_fp32.mul_(beta1).add_(grad, alpha=1.0 - beta1)
|
|
524
|
+
m2_fp32.mul_(beta3).add_(grad, alpha=1.0 - beta3)
|
|
525
|
+
nu_fp32.mul_(beta2).addcmul_(grad, grad, value=1.0 - beta2)
|
|
526
|
+
|
|
527
|
+
correction1 = 1.0 - beta1**step
|
|
528
|
+
correction2 = math.sqrt(1.0 - beta2**step)
|
|
529
|
+
|
|
530
|
+
update = (m1_fp32 / correction1 + alpha * m2_fp32) / (nu_fp32.sqrt() / correction2 + eps)
|
|
531
|
+
if weight_decay > 0.0:
|
|
532
|
+
p_fp32.mul_(1.0 - lr * weight_decay)
|
|
533
|
+
p_fp32.add_(update, alpha=-lr)
|
|
534
|
+
|
|
535
|
+
state1_fp32 = torch.stack([m1_fp32, m2_fp32])
|
|
536
|
+
|
|
537
|
+
elif optimizer_name in ("momentum", "lars"):
|
|
538
|
+
grad.add_(p_fp32, alpha=weight_decay)
|
|
539
|
+
if step == 1:
|
|
540
|
+
state1_fp32.copy_(grad)
|
|
541
|
+
else:
|
|
542
|
+
state1_fp32.mul_(beta1).add_(grad)
|
|
543
|
+
p_fp32.add_(state1_fp32, alpha=-lr)
|
|
544
|
+
|
|
545
|
+
elif optimizer_name == "lion":
|
|
546
|
+
if weight_decay > 0.0:
|
|
547
|
+
p_fp32.mul_(1.0 - lr * weight_decay)
|
|
548
|
+
|
|
549
|
+
update_dir = torch.sign(state1_fp32.mul(beta1) + grad.mul(1.0 - beta1))
|
|
550
|
+
p_fp32.add_(update_dir, alpha=-lr)
|
|
551
|
+
|
|
552
|
+
state1_fp32.mul_(beta2).add_(grad, alpha=1.0 - beta2)
|
|
553
|
+
|
|
554
|
+
elif optimizer_name == "rmsprop":
|
|
555
|
+
grad.add_(p_fp32, alpha=weight_decay)
|
|
556
|
+
state1_fp32.mul_(beta1).addcmul_(grad, grad, value=1.0 - beta1)
|
|
557
|
+
p_fp32.addcdiv_(grad, state1_fp32.sqrt().add_(eps), value=-lr)
|
|
558
|
+
|
|
559
|
+
elif optimizer_name == "adagrad":
|
|
560
|
+
grad.add_(p_fp32, alpha=weight_decay)
|
|
561
|
+
state1_fp32.addcmul_(grad, grad, value=1.0)
|
|
562
|
+
p_fp32.addcdiv_(grad, state1_fp32.sqrt().add_(eps), value=-lr)
|
|
563
|
+
|
|
564
|
+
else:
|
|
565
|
+
raise ValueError(f"Unsupported optimizer for CPU 8-bit: {optimizer_name}")
|
|
566
|
+
|
|
567
|
+
p.data.copy_(p_fp32)
|
|
568
|
+
|
|
569
|
+
# Re-quantize states
|
|
570
|
+
if optimizer_name == "ademamix":
|
|
571
|
+
_quant_blockwise_fp32_direct(state1_fp32[0], qmap1, absmax1[0], state1[0], blocksize)
|
|
572
|
+
_quant_blockwise_fp32_direct(state1_fp32[1], qmap1, absmax1[1], state1[1], blocksize)
|
|
573
|
+
_quant_blockwise_fp32_direct(state2_fp32, qmap2, absmax2, state2, blocksize)
|
|
574
|
+
else:
|
|
575
|
+
_quant_blockwise_fp32_direct(state1_fp32, qmap1, absmax1, state1, blocksize)
|
|
576
|
+
if state2_fp32 is not None:
|
|
577
|
+
_quant_blockwise_fp32_direct(state2_fp32, qmap2, absmax2, state2, blocksize)
|
|
578
|
+
|
|
579
|
+
|
|
580
|
+
register_kernel("bitsandbytes::optimizer_update_8bit_blockwise", "cpu")(_optimizer_update_8bit_blockwise_cpu)
|
|
File without changes
|