amd: raise the installer bitsandbytes fallback floors to 0.50.0

This commit is contained in:
Daniel Han 2026-07-28 22:09:01 +00:00
commit 2da5678c0c
3 changed files with 58 additions and 7 deletions

View file

@ -259,8 +259,10 @@ run_install_cmd_retry() {
# Install bitsandbytes on AMD ROCm hosts. Uses the continuous-release_main
# wheel for the ROCm 4-bit GEMV fix (bnb PR #1887, post-0.49.2); bnb <= 0.49.2
# NaNs at decode shape on every AMD GPU. Falls back to PyPI >=0.49.1 if the
# pre-release URL is unreachable. Drop the pin once bnb 0.50+ ships on PyPI.
# NaNs at decode shape on every AMD GPU. Falls back to PyPI >=0.50.0 if the
# pre-release URL is unreachable: 0.50.0 (2026-07-24) is the first PyPI release
# carrying that fix, and its manylinux x86_64 wheel ships the same
# libbitsandbytes_rocm{64,70,71,714,72}.so set as the pre-release.
_install_bnb_rocm() {
_label="$1"
_venv_py="$2"
@ -277,7 +279,8 @@ _install_bnb_rocm() {
esac
# uv rejects the continuous-release_main bitsandbytes wheel because the
# filename version (1.33.7rc0) does not match the embedded metadata version
# (0.50.0.dev0). pip accepts the mismatch, so bootstrap pip and use it.
# (0.50.x.dev0, whatever main is at). pip accepts the mismatch, so bootstrap
# pip and use it.
if ! "$_venv_py" -m pip --version >/dev/null 2>&1; then
if ! run_maybe_quiet "$_venv_py" -m ensurepip --upgrade; then
run_maybe_quiet uv pip install --python "$_venv_py" pip || \
@ -304,7 +307,7 @@ _install_bnb_rocm() {
substep "[WARN] bnb pre-release install failed; falling back to PyPI (4-bit decode broken on ROCm)" "$C_WARN"
fi
run_install_cmd "$_label (pypi fallback)" "$_venv_py" -m pip install \
--force-reinstall --no-cache-dir --no-deps "bitsandbytes>=0.49.1"
--force-reinstall --no-cache-dir --no-deps "bitsandbytes>=0.50.0"
}
if [ "$_next_is_package" = true ]; then

View file

@ -390,7 +390,8 @@ _GFX_TO_AMD_INDEX_ARCH: dict[str, str] = {
# bitsandbytes continuous-release_main wheels with the ROCm 4-bit GEMV fix
# (bnb PR #1887, post-0.49.2). bnb <= 0.49.2 NaNs at decode shape on every
# AMD GPU. Drop the pin once bnb 0.50+ ships on PyPI.
# AMD GPU. PyPI 0.50.0 (2026-07-24) is the first release carrying that fix, so
# _BNB_ROCM_PYPI_FALLBACK below is a safe floor when these URLs are unreachable.
_BNB_ROCM_PRERELEASE_URLS: dict[str, str] = {
"x86_64": (
"https://github.com/bitsandbytes-foundation/bitsandbytes/releases/"
@ -411,7 +412,8 @@ _BNB_ROCM_PRERELEASE_URLS: dict[str, str] = {
"bitsandbytes-1.33.7.preview-py3-none-win_amd64.whl"
),
}
_BNB_ROCM_PYPI_FALLBACK = "bitsandbytes>=0.49.1"
# Keep in step with the install.sh fallback (and the amd extra, once it lands here).
_BNB_ROCM_PYPI_FALLBACK = "bitsandbytes>=0.50.0"
def _bnb_rocm_prerelease_url() -> str | None:
@ -1182,7 +1184,7 @@ def _install_bnb_windows_rocm() -> bool:
The continuous-release wheel is intentionally mismatched: the filename
encodes 1.33.7.preview (parsed as 1.33.7rc0 by PEP 440) while the wheel
metadata reports 0.50.0.dev0. uv rejects this filename/metadata mismatch,
metadata reports 0.50.x.dev0. uv rejects this filename/metadata mismatch,
and bypassing it with UV_SKIP_WHEEL_FILENAME_CHECK still leaves uv mangling
the bitsandbytes install. Per the AMD install guide
(https://unsloth.ai/docs/get-started/install/amd/amd-hackathon) the wheel

View file

@ -818,3 +818,49 @@ class TestPipNoIndexScrubParity:
text = SETUP_PS1.read_text(encoding = "utf-8")
assert "'PIP_NO_INDEX'" in text
assert "'PIP_INDEX_URL'" in text
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 install.sh PyPI
fallback and the Studio stack fallback are the two ways a supported AMD flow
resolves bitsandbytes when the pre-release wheel URL is unreachable, so neither
may float back into the broken range."""
FLOOR = "0.50.0"
PYPROJECT = REPO_ROOT / "pyproject.toml"
def test_install_sh_pypi_fallback_floor(self):
text = INSTALL_SH.read_text(encoding = "utf-8")
assert f'"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_amd_extra_floor_when_present(self):
"""The amd extra is not on this branch yet (#7278). Assert it only once it is,
so the extra and the two installer fallbacks cannot drift apart later."""
text = self.PYPROJECT.read_text(encoding = "utf-8")
amd = re.search(r"^amd = \[(.*?)^\]", text, re.S | re.M)
if amd is None:
pytest.skip("pyproject.toml has no amd extra on this branch")
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_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}"
)