Skip to content

Commit d29189f

Browse files
eaglstunclaude
andcommitted
Merge upstream/main into fork main (Apple Silicon MPS line)
Brings in 6 upstream commits (through bitsandbytes-foundation#2004). Conflict resolutions: - csrc/mps_kernels.metal, csrc/mps_ops.mm: upstream bitsandbytes-foundation#2004 DELETED these as 'unused metal build code' (they were stubs upstream); the fork built them into the real MPS port. Kept the fork's versions (rejected the deletion). - CMakeLists.txt: bitsandbytes-foundation#2004 removed upstream's stub metal build. Restored the fork's full MPS build support that the auto-merge dropped: the COMPUTE_BACKEND=mps -> BUILD_MPS selection branch, set(MPS_FILES)/set(METAL_FILES), and the late if(BUILD_MPS) framework-linking + add_dependencies(metallib) block. Verified a clean MPS build produces the metallib + _mps.dylib. - bitsandbytes/backends/default/ops.py: dropped the stale Lion NOTE (claimed CUDA and Triton still had the coupled-decay bug -- all three are now fixed on this fork); took upstream's cleaner version. The decoupled-decay code is unchanged. - tests/test_optim.py: kept the fork's test_lion8bit_blockwise_weight_decay alongside upstream's test_lion32bit_weight_decay. - csrc/pythonInterface.cpp: took upstream's removal of a commented-out dead #include (fork's MPS loads via dladdr, doesn't use it). Verified on the merged tree: MPS builds, tests/test_mps_parity.py 329 passed under BNB_MPS_REQUIRE_NATIVE=1 (bit-exact quant/dequant + native matmul intact). Pre-existing paged_lion-on-mps test_optim failures are unchanged (paging is CUDA-only; identical on fork main pre-merge). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2 parents 9afd664 + b4057b8 commit d29189f

8 files changed

Lines changed: 26 additions & 34 deletions

File tree

.github/workflows/python-package.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ jobs:
118118
strategy:
119119
matrix:
120120
os: [ubuntu-22.04]
121-
rocm_version: ["6.2.4", "6.3.4", "6.4.4", "7.0.2", "7.1.1", "7.2.3"]
121+
rocm_version: ["6.2.4", "6.3.4", "6.4.4", "7.0.2", "7.1.1", "7.2.4"]
122122
include:
123123
- os: windows-2025
124124
rocm_version: "7.2.1"

CMakeLists.txt

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# For GCC: `cmake -B build . && cmake --build build`
44
# For MSVC: `cmake -B build . && cmake --build build --config Release`
55
# You can also use the following options and variables
6-
# - COMPUTE_BACKEND: Set to `cpu`, `cuda`, or `mps` to select the backend
6+
# - COMPUTE_BACKEND: Set to `cpu`, `cuda`, `hip`, or `xpu` to select the backend
77
# - CUDA_VERSION: The expected CUDA version, for sanity checking. The actual version
88
# is whatever CMake finds on your path.
99
# - COMPUTE_CAPABILITY: Which GPU Arch/Compute codes to provide to NVCC.
@@ -62,14 +62,14 @@ set(CMAKE_CXX_EXTENSIONS OFF)
6262
# Define included source files
6363
set(CPP_FILES csrc/cpu_ops.cpp csrc/pythonInterface.cpp)
6464
set(GPU_FILES csrc/ops.cu csrc/kernels.cu)
65+
set(XPU_FILES csrc/xpu_ops.cpp csrc/xpu_kernels.cpp)
6566
set(MPS_FILES csrc/mps_ops.mm)
6667
set(METAL_FILES csrc/mps_kernels.metal)
67-
set(XPU_FILES csrc/xpu_ops.cpp csrc/xpu_kernels.cpp)
6868
# C++ sources are always included
6969
list(APPEND SRC_FILES ${CPP_FILES})
7070

71-
set(COMPUTE_BACKEND "cpu" CACHE STRING "The compute backend to use (cpu, cuda, hip, mps, xpu)")
72-
set_property(CACHE COMPUTE_BACKEND PROPERTY STRINGS cpu cuda hip mps xpu)
71+
set(COMPUTE_BACKEND "cpu" CACHE STRING "The compute backend to use (cpu, cuda, hip, xpu, mps)")
72+
set_property(CACHE COMPUTE_BACKEND PROPERTY STRINGS cpu cuda hip xpu mps)
7373
option(PTXAS_VERBOSE "Pass through -v flag to PTX Assembler" OFF)
7474

7575
if(APPLE)
@@ -86,34 +86,32 @@ if(${COMPUTE_BACKEND} STREQUAL "cuda")
8686
endif()
8787
set(BUILD_CUDA ON)
8888
set(BUILD_HIP OFF)
89-
set(BUILD_MPS OFF)
9089
elseif(${COMPUTE_BACKEND} STREQUAL "hip")
9190
if(APPLE)
9291
message(FATAL_ERROR "HIP is not supported on macOS" )
9392
endif()
9493
set(BUILD_CUDA OFF)
9594
set(BUILD_HIP ON)
96-
set(BUILD_MPS OFF)
97-
elseif(${COMPUTE_BACKEND} STREQUAL "mps")
98-
if(NOT APPLE)
99-
message(FATAL_ERROR "MPS is only supported on macOS" )
100-
endif()
101-
set(BUILD_CUDA OFF)
102-
set(BUILD_HIP OFF)
103-
set(BUILD_MPS ON)
10495
elseif(${COMPUTE_BACKEND} STREQUAL "xpu")
10596
if(APPLE)
10697
message(FATAL_ERROR "XPU is not supported on macOS" )
10798
endif()
10899
set(BUILD_CUDA OFF)
109100
set(BUILD_HIP OFF)
110-
set(BUILD_MPS OFF)
111101
set(BUILD_XPU ON)
102+
elseif(${COMPUTE_BACKEND} STREQUAL "mps")
103+
if(NOT APPLE)
104+
message(FATAL_ERROR "MPS is only supported on macOS" )
105+
endif()
106+
set(BUILD_CUDA OFF)
107+
set(BUILD_HIP OFF)
108+
set(BUILD_XPU OFF)
109+
set(BUILD_MPS ON)
112110
else()
113111
set(BUILD_CUDA OFF)
114112
set(BUILD_HIP OFF)
115-
set(BUILD_MPS OFF)
116113
set(BUILD_XPU OFF)
114+
set(BUILD_MPS OFF)
117115
set(BUILD_CPU ON)
118116
endif()
119117

bitsandbytes/backends/cpu/ops.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ def _(A: torch.Tensor, B: torch.Tensor):
3737

3838
@register_kernel("bitsandbytes::quantize_blockwise", "cpu")
3939
def _(A: torch.Tensor, code: torch.Tensor, blocksize: int) -> tuple[torch.Tensor, torch.Tensor]:
40+
A = A.contiguous()
4041
n = A.numel()
4142
blocks = -(n // -blocksize)
4243

@@ -94,6 +95,7 @@ def _(A: torch.Tensor, code: torch.Tensor, blocksize: int) -> tuple[torch.Tensor
9495
def _(
9596
A: torch.Tensor, absmax: torch.Tensor, code: torch.Tensor, blocksize: int, dtype: torch.dtype
9697
) -> torch.Tensor:
98+
A = A.contiguous()
9799
out = torch.empty_like(A, dtype=dtype)
98100
if dtype == torch.float32:
99101
lib.cdequantize_blockwise_cpu_fp32(

bitsandbytes/backends/default/ops.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -522,9 +522,6 @@ def _optimizer_update_32bit(
522522
# Lion uses decoupled weight decay: shrink the param directly (p *= 1 - lr*wd)
523523
# rather than folding wd into the gradient. Matches the cpu backend, the CUDA
524524
# 8-bit blockwise kernel, and the Lion paper (Chen et al. 2023).
525-
# NOTE: the CUDA 32-bit kernel (csrc/kernels.cu::kOptimizer32bit1State) and the
526-
# Triton 1-state kernel (backends/triton/kernels_optim.py) still apply *coupled*
527-
# decay to Lion — the same bug this fixes — and need a separate upstream fix.
528525
if weight_decay > 0.0:
529526
p_vals = p_vals * (1.0 - lr * weight_decay)
530527

bitsandbytes/functional.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import numpy as np
1212
import torch
1313
from torch import Tensor
14+
from typing_extensions import deprecated
1415

1516
from bitsandbytes.utils import pack_dict_to_tensor, unpack_tensor_to_dict
1617

@@ -1211,6 +1212,7 @@ def optimizer_update_8bit_blockwise(
12111212
)
12121213

12131214

1215+
@deprecated("This function is deprecated and will be removed in a future release.", category=FutureWarning)
12141216
def check_matmul(A, B, out, transposed_A, transposed_B, expected_type=torch.int8):
12151217
if not torch.cuda.is_initialized():
12161218
torch.cuda.init()
@@ -1332,6 +1334,7 @@ def gemv_4bit(
13321334
)
13331335

13341336

1337+
@deprecated("This function is deprecated and will be removed in a future release.", category=FutureWarning)
13351338
def igemm(
13361339
A: Tensor,
13371340
B: Tensor,
@@ -1433,6 +1436,7 @@ def igemm(
14331436
return out
14341437

14351438

1439+
@deprecated("This function is deprecated and will be removed in a future release.", category=FutureWarning)
14361440
def batched_igemm(
14371441
A: Tensor,
14381442
B: Tensor,

csrc/pythonInterface.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,6 @@
1010
#if BUILD_HIP
1111
#include <ops.cuh>
1212
#endif
13-
#if BUILD_MPS
14-
// #include <mps_ops.h>
15-
#endif
1613
#if BUILD_XPU
1714
#include <xpu_ops.h>
1815
#endif

docs/source/installation.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ The currently distributed `bitsandbytes` are built with the following configurat
248248
| **Linux x86-64** | 6.4.4 | CDNA: gfx90a, gfx942 / RDNA: gfx1100, gfx1101, gfx1102, gfx1103, gfx1150, gfx1151, gfx1152, gfx1153, gfx1200, gfx1201
249249
| **Linux x86-64** | 7.0.2 | CDNA: gfx90a, gfx942, gfx950 / RDNA: gfx1100, gfx1101, gfx1102, gfx1103, gfx1150, gfx1151, gfx1152, gfx1153, gfx1200, gfx1201
250250
| **Linux x86-64** | 7.1.1 | CDNA: gfx90a, gfx942, gfx950 / RDNA: gfx1100, gfx1101, gfx1102, gfx1103, gfx1150, gfx1151, gfx1152, gfx1153, gfx1200, gfx1201
251-
| **Linux x86-64** | 7.2.3 | CDNA: gfx90a, gfx942, gfx950 / RDNA: gfx1100, gfx1101, gfx1102, gfx1103, gfx1150, gfx1151, gfx1152, gfx1153, gfx1200, gfx1201
251+
| **Linux x86-64** | 7.2.4 | CDNA: gfx90a, gfx942, gfx950 / RDNA: gfx1100, gfx1101, gfx1102, gfx1103, gfx1150, gfx1151, gfx1152, gfx1153, gfx1200, gfx1201
252252
| **Windows x86-64** | 7.2.1 | RDNA: gfx1100, gfx1101, gfx1102, gfx1150, gfx1151, gfx1200, gfx1201
253253

254254
Use `pip` or `uv` to install the latest release:
@@ -259,7 +259,7 @@ pip install bitsandbytes
259259

260260
### Compile from Source[[rocm-compile]]
261261

262-
bitsandbytes can be compiled from ROCm 6.2 - ROCm 7.2.3. See the `CMakeLists.txt` for additional options.
262+
bitsandbytes can be compiled from ROCm 6.2 - ROCm 7.2.4. See the `CMakeLists.txt` for additional options.
263263

264264
<hfoptions id="rocm-source">
265265
<hfoption id="Linux">

tests/test_ops.py

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -382,9 +382,6 @@ class TestNonContiguousInputs:
382382
@pytest.mark.parametrize("dtype", [torch.float16, torch.bfloat16, torch.float32], ids=id_formatter("dtype"))
383383
@pytest.mark.parametrize("blocksize", [64, 128, 256])
384384
def test_quantize_blockwise_non_contiguous(self, device, dtype, blocksize):
385-
if device == "cpu":
386-
pytest.skip("Non-contiguous fix targets CUDA backend only")
387-
388385
code = bitsandbytes.functional.create_dynamic_map().to(device)
389386

390387
# Create non-contiguous tensor via slicing
@@ -404,9 +401,6 @@ def test_quantize_blockwise_non_contiguous(self, device, dtype, blocksize):
404401
@pytest.mark.parametrize("dtype", [torch.float16, torch.bfloat16, torch.float32], ids=id_formatter("dtype"))
405402
@pytest.mark.parametrize("blocksize", [64, 128, 256])
406403
def test_dequantize_blockwise_non_contiguous(self, device, dtype, blocksize):
407-
if device == "cpu":
408-
pytest.skip("Non-contiguous fix targets CUDA backend only")
409-
410404
code = bitsandbytes.functional.create_dynamic_map().to(device, dtype=torch.float32)
411405

412406
# Quantize a contiguous tensor, then create non-contiguous uint8 via transpose
@@ -435,8 +429,8 @@ def test_dequantize_blockwise_non_contiguous(self, device, dtype, blocksize):
435429
@pytest.mark.parametrize("quant_type", ["fp4", "nf4"])
436430
@pytest.mark.parametrize("blocksize", [64, 128, 256])
437431
def test_quantize_4bit_non_contiguous(self, device, dtype, quant_type, blocksize):
438-
if device != "cuda":
439-
pytest.skip("Non-contiguous fix targets CUDA backend only")
432+
if device not in ("cuda", "mps"):
433+
pytest.skip("Non-contiguous input handling not implemented for this backend")
440434

441435
# Reproduce issue #1342: non-contiguous tensor from slicing
442436
A_full = torch.randn(3, 4, 6, 256, dtype=dtype, device=device)
@@ -458,8 +452,8 @@ def test_quantize_4bit_non_contiguous(self, device, dtype, quant_type, blocksize
458452
@pytest.mark.parametrize("blocksize", [64, 128, 256])
459453
def test_quantize_4bit_roundtrip_non_contiguous(self, device, dtype, quant_type, blocksize):
460454
"""End-to-end test: quantize non-contiguous, dequantize, compare with contiguous path."""
461-
if device != "cuda":
462-
pytest.skip("Non-contiguous fix targets CUDA backend only")
455+
if device not in ("cuda", "mps"):
456+
pytest.skip("Non-contiguous input handling not implemented for this backend")
463457

464458
A_full = torch.randn(3, 4, 6, 256, dtype=dtype, device=device)
465459
A_noncontig = A_full[:, ::2, :, :]

0 commit comments

Comments
 (0)