amd: require bitsandbytes>=0.50.0 in the amd extra (fixes ROCm 4-bit NaNs) (#7535)
* amd: require bitsandbytes>=0.50.0 in the amd extra bnb <= 0.49.2 NaNs at decode shape on every AMD GPU. The ROCm 4-bit GEMV fix (bnb PR #1887) first ships in 0.50.0, on PyPI since 2026-07-24, so the old >=0.49.1 floor could still resolve the broken range. Mirrors the same change made on the pip release branch in #7278. * amd: cite the 0.50.0 ROCm work accurately in the bnb floor comment The comment credited bnb PR #1887 as "the ROCm 4-bit GEMV fix" for every AMD GPU. #1887 decouples blocksize from warp size and fixes a hardcoded warp size of 32 in kgemm_4bit_inference_naive, which is a CDNA problem by construction. The RDNA-side work is #1979 (fused 4-bit SIMT GEMM) and #2012 (RDNA3/4 workgroup resonance). All three first ship in 0.50.0, so the >=0.50.0 floor is unchanged; only the justification was wrong. * amd: raise the installer bitsandbytes fallback floors to 0.50.0 * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * amd: stop reporting the bitsandbytes PyPI fallback as broken * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Tighten AMD bnb floor comments * Keep the amd extra citation and the AMD install guide reference * amd: do not promise aarch64 a ROCm 4-bit backend it never gets * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * amd: fall back to the PyPI bitsandbytes floor on Windows ROCm too * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: Daniel Han <danielhanchen@gmail.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
parent
85c63e7903
commit
411cb86d62
5 changed files with 206 additions and 46 deletions
|
|
@ -862,3 +862,76 @@ class TestNoTorchPersistenceParity:
|
|||
manifest = (REPO_ROOT / "studio" / "install_manifest.py").read_text(encoding = "utf-8")
|
||||
assert 'NO_TORCH_TRUTHY: Tuple[str, ...] = ("1", "true", "yes", "on")' in manifest
|
||||
assert "install_manifest.NO_TORCH_TRUTHY" in STACK_PY.read_text(encoding = "utf-8")
|
||||
|
||||
|
||||
class TestAmdBnbFloorParity:
|
||||
"""bitsandbytes <= 0.49.2 NaNs at 4-bit decode shape on every AMD GPU; the ROCm
|
||||
4-bit GEMV fix (bnb #1887) first ships on PyPI in 0.50.0. The `amd` extra,
|
||||
install.sh and the Studio stack resolve bitsandbytes independently, so all three
|
||||
must carry the same floor or an unreachable pre-release wheel silently reinstates
|
||||
the broken range."""
|
||||
|
||||
FLOOR = "0.50.0"
|
||||
PYPROJECT = REPO_ROOT / "pyproject.toml"
|
||||
|
||||
def test_amd_extra_floor(self):
|
||||
text = self.PYPROJECT.read_text(encoding = "utf-8")
|
||||
amd = re.search(r"^amd = \[(.*?)^\]", text, re.S | re.M)
|
||||
assert amd, "pyproject.toml must define an `amd` extra"
|
||||
specs = re.findall(r'"(bitsandbytes[^"]*)"', amd.group(1))
|
||||
assert specs, "the amd extra must pin bitsandbytes"
|
||||
for spec in specs:
|
||||
assert spec.startswith(
|
||||
f"bitsandbytes>={self.FLOOR}"
|
||||
), f"amd extra bitsandbytes floor must be >={self.FLOOR}, got {spec!r}"
|
||||
|
||||
def test_install_sh_pypi_fallback_floor(self):
|
||||
text = INSTALL_SH.read_text(encoding = "utf-8")
|
||||
assert (
|
||||
f'_BNB_ROCM_PYPI_FALLBACK="bitsandbytes>={self.FLOOR}"' in text
|
||||
), f"install.sh _install_bnb_rocm PyPI fallback must floor at {self.FLOOR}"
|
||||
|
||||
def test_stack_py_pypi_fallback_floor(self):
|
||||
text = STACK_PY.read_text(encoding = "utf-8")
|
||||
assert (
|
||||
f'_BNB_ROCM_PYPI_FALLBACK = "bitsandbytes>={self.FLOOR}"' in text
|
||||
), f"install_python_stack.py PyPI fallback must floor at {self.FLOOR}"
|
||||
|
||||
def test_no_installer_still_allows_the_broken_range(self):
|
||||
for path in (INSTALL_SH, INSTALL_PS1, SETUP_PS1, STACK_PY, self.PYPROJECT):
|
||||
text = path.read_text(encoding = "utf-8")
|
||||
for line in text.splitlines():
|
||||
if "bitsandbytes>=0.49" in line and not line.lstrip().startswith(("#", "//")):
|
||||
raise AssertionError(
|
||||
f"{path.name} still floors bitsandbytes in the broken ROCm range: {line.strip()!r}"
|
||||
)
|
||||
|
||||
def test_fallback_is_not_reported_as_broken(self):
|
||||
"""The fallback now installs the first fixed release, so neither installer
|
||||
may still call 4-bit decode broken on ROCm."""
|
||||
for path in (INSTALL_SH, STACK_PY):
|
||||
text = path.read_text(encoding = "utf-8")
|
||||
assert (
|
||||
"4-bit decode broken on ROCm" not in text
|
||||
), f"{path.name} still reports the repaired PyPI fallback as broken"
|
||||
assert (
|
||||
"4-bit decode will be broken on ROCm" not in text
|
||||
), f"{path.name} still reports the repaired PyPI fallback as broken"
|
||||
|
||||
def test_aarch64_is_not_told_it_has_a_rocm_backend(self):
|
||||
"""bitsandbytes ships no ROCm kernels in its aarch64 wheel at any version, so
|
||||
neither installer may hand aarch64 the x86_64 "carries the ROCm 4-bit fix"
|
||||
message, and both must warn that 4-bit needs a source build there."""
|
||||
sh = INSTALL_SH.read_text(encoding = "utf-8")
|
||||
assert "_bnb_rocm_arch_has_binary()" in sh
|
||||
assert "_warn_bnb_no_rocm_binary()" in sh
|
||||
assert (
|
||||
sh.count("_warn_bnb_no_rocm_binary\n") >= 2
|
||||
), "install.sh must warn on aarch64 after both the pre-release and the fallback install"
|
||||
py = STACK_PY.read_text(encoding = "utf-8")
|
||||
assert "def _bnb_rocm_arch_has_binary(" in py
|
||||
assert "_bnb_rocm_arch_has_binary()" in py
|
||||
for text, name in ((sh, "install.sh"), (py, "install_python_stack.py")):
|
||||
assert (
|
||||
"4-bit QLoRA needs a source build" in text
|
||||
), f"{name} must tell aarch64 users 4-bit needs a source build"
|
||||
|
|
|
|||
|
|
@ -3157,12 +3157,35 @@ class TestInstallBnbWindowsRocm:
|
|||
assert result is False
|
||||
assert "BNB_ROCM_VERSION" not in os.environ
|
||||
|
||||
def test_no_op_when_win_amd64_url_missing(self):
|
||||
"""Should be silent no-op if win_amd64 key absent from _BNB_ROCM_PRERELEASE_URLS."""
|
||||
def test_falls_back_to_pypi_when_win_amd64_url_missing(self):
|
||||
"""No win_amd64 pre-release wheel must not mean no bitsandbytes: PyPI
|
||||
>=0.50.0 ships libbitsandbytes_rocm{714,72}.dll, so it is a real ROCm build."""
|
||||
with patch.object(stack_mod, "_BNB_ROCM_PRERELEASE_URLS", {}):
|
||||
with patch.object(stack_mod, "pip_install_try") as mock_pip:
|
||||
with patch.object(stack_mod, "pip_install_try", return_value = True) as mock_pip:
|
||||
stack_mod._install_bnb_windows_rocm()
|
||||
mock_pip.assert_not_called()
|
||||
assert mock_pip.call_count == 1
|
||||
assert stack_mod._BNB_ROCM_PYPI_FALLBACK in mock_pip.call_args.args
|
||||
|
||||
def test_falls_back_to_pypi_when_prerelease_install_fails(self):
|
||||
"""A blocked GitHub pre-release URL must fall through to the PyPI floor rather
|
||||
than leaving Windows ROCm with no working bitsandbytes."""
|
||||
with patch.object(stack_mod, "pip_install_try", side_effect = [False, True]) as mock_pip:
|
||||
with patch.object(stack_mod, "_detect_bnb_rocm_dll_ver", return_value = "72"):
|
||||
result = stack_mod._install_bnb_windows_rocm()
|
||||
assert result is True
|
||||
assert mock_pip.call_count == 2
|
||||
assert "win_amd64" in str(mock_pip.call_args_list[0])
|
||||
assert stack_mod._BNB_ROCM_PYPI_FALLBACK in mock_pip.call_args_list[1].args
|
||||
|
||||
def test_returns_false_only_when_both_paths_fail(self):
|
||||
"""Both the pre-release wheel and the PyPI fallback must fail before the
|
||||
helper reports failure."""
|
||||
with patch.dict(os.environ, {}, clear = False):
|
||||
os.environ.pop("BNB_ROCM_VERSION", None)
|
||||
with patch.object(stack_mod, "pip_install_try", return_value = False) as mock_pip:
|
||||
result = stack_mod._install_bnb_windows_rocm()
|
||||
assert result is False
|
||||
assert mock_pip.call_count == 2
|
||||
|
||||
def test_sets_bnb_rocm_version_from_detected_dll(self):
|
||||
"""BNB_ROCM_VERSION is set from the DLL detected after install."""
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue