-
-
Notifications
You must be signed in to change notification settings - Fork 6.3k
Pin bitsandbytes to continuous-release_main on ROCm (4-bit decode fix) #4954
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
86f5aad
aa9fbe6
9619c4d
924f0d1
ef4dfe2
63d296c
03b7761
d5342be
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -94,6 +94,43 @@ run_install_cmd() { | |||||||||||||||||||||||||||||||||||||||||||||||
| return $_rc | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| # Install bitsandbytes on AMD ROCm hosts. Prefers the continuous-release_main | ||||||||||||||||||||||||||||||||||||||||||||||||
| # wheel from the bnb GitHub release so we pick up the CDNA/RDNA 4-bit GEMV | ||||||||||||||||||||||||||||||||||||||||||||||||
| # fix in PR #1887 (merged 2026-03-09, post-0.49.2). The GEMV kernel in | ||||||||||||||||||||||||||||||||||||||||||||||||
| # bitsandbytes <= 0.49.2 produces NaN at decode-shape (seq_len=1) on every | ||||||||||||||||||||||||||||||||||||||||||||||||
| # ROCm target -- CDNA (gfx90a/gfx942/gfx950 = MI210/MI300X/MI350) via a | ||||||||||||||||||||||||||||||||||||||||||||||||
| # broken blocksize=32/64 warp64 kernel, RDNA (gfx1100-1103/gfx1150-1152) | ||||||||||||||||||||||||||||||||||||||||||||||||
| # via a compile-time warp-size dispatch bug -- so autoregressive generation | ||||||||||||||||||||||||||||||||||||||||||||||||
| # is broken even though training passes. Falls back to PyPI >=0.49.1 when | ||||||||||||||||||||||||||||||||||||||||||||||||
| # the pre-release URL is unreachable (offline installs, firewalled hosts, | ||||||||||||||||||||||||||||||||||||||||||||||||
| # unknown architectures). Drop the pre-release pin once bnb cuts a 0.50+ | ||||||||||||||||||||||||||||||||||||||||||||||||
| # tag on PyPI. | ||||||||||||||||||||||||||||||||||||||||||||||||
| _install_bnb_rocm() { | ||||||||||||||||||||||||||||||||||||||||||||||||
| _label="$1" | ||||||||||||||||||||||||||||||||||||||||||||||||
| _venv_py="$2" | ||||||||||||||||||||||||||||||||||||||||||||||||
| case "$_ARCH" in | ||||||||||||||||||||||||||||||||||||||||||||||||
| x86_64|amd64) | ||||||||||||||||||||||||||||||||||||||||||||||||
| _bnb_whl_url="https://github.com/bitsandbytes-foundation/bitsandbytes/releases/download/continuous-release_main/bitsandbytes-1.33.7.preview-py3-none-manylinux_2_24_x86_64.whl" | ||||||||||||||||||||||||||||||||||||||||||||||||
| ;; | ||||||||||||||||||||||||||||||||||||||||||||||||
| aarch64|arm64) | ||||||||||||||||||||||||||||||||||||||||||||||||
| _bnb_whl_url="https://github.com/bitsandbytes-foundation/bitsandbytes/releases/download/continuous-release_main/bitsandbytes-1.33.7.preview-py3-none-manylinux_2_24_aarch64.whl" | ||||||||||||||||||||||||||||||||||||||||||||||||
| ;; | ||||||||||||||||||||||||||||||||||||||||||||||||
| *) | ||||||||||||||||||||||||||||||||||||||||||||||||
| _bnb_whl_url="" | ||||||||||||||||||||||||||||||||||||||||||||||||
| ;; | ||||||||||||||||||||||||||||||||||||||||||||||||
| esac | ||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+104
to
+114
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To improve maintainability and reduce duplication, you could define a base URL for the wheel and append the architecture-specific part. This would make it easier to update the pinned version in the future.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||
| if [ -n "$_bnb_whl_url" ]; then | ||||||||||||||||||||||||||||||||||||||||||||||||
| substep "installing bitsandbytes for AMD ROCm (pre-release main, bnb PR #1887 GEMV fix)..." | ||||||||||||||||||||||||||||||||||||||||||||||||
| if run_install_cmd "$_label (pre-release)" uv pip install --python "$_venv_py" \ | ||||||||||||||||||||||||||||||||||||||||||||||||
| --force-reinstall --no-cache-dir --no-deps "$_bnb_whl_url"; then | ||||||||||||||||||||||||||||||||||||||||||||||||
| return 0 | ||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||
| substep "[WARN] bnb pre-release wheel unreachable; falling back to PyPI >=0.49.1 (4-bit decode will be broken on ROCm -- use 16-bit instead)" "$C_WARN" | ||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||
| run_install_cmd "$_label (pypi fallback)" uv pip install --python "$_venv_py" \ | ||||||||||||||||||||||||||||||||||||||||||||||||
| --force-reinstall --no-cache-dir --no-deps "bitsandbytes>=0.49.1" | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| if [ "$_next_is_package" = true ]; then | ||||||||||||||||||||||||||||||||||||||||||||||||
| echo "❌ ERROR: --package requires an argument." >&2 | ||||||||||||||||||||||||||||||||||||||||||||||||
| exit 1 | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -1296,8 +1333,7 @@ if [ "$_MIGRATED" = true ]; then | |||||||||||||||||||||||||||||||||||||||||||||||
| if [ "$SKIP_TORCH" = false ]; then | ||||||||||||||||||||||||||||||||||||||||||||||||
| case "$TORCH_INDEX_URL" in | ||||||||||||||||||||||||||||||||||||||||||||||||
| */rocm*) | ||||||||||||||||||||||||||||||||||||||||||||||||
| substep "installing bitsandbytes for AMD ROCm..." | ||||||||||||||||||||||||||||||||||||||||||||||||
| run_install_cmd "install bitsandbytes (AMD)" uv pip install --python "$_VENV_PY" --force-reinstall --no-cache-dir --no-deps "bitsandbytes>=0.49.1" | ||||||||||||||||||||||||||||||||||||||||||||||||
| _install_bnb_rocm "install bitsandbytes (AMD)" "$_VENV_PY" | ||||||||||||||||||||||||||||||||||||||||||||||||
| # Repair ROCm torch if overwritten during migrated install | ||||||||||||||||||||||||||||||||||||||||||||||||
| _has_hip=$("$_VENV_PY" -c "import torch; print(getattr(torch.version,'hip','') or '')" 2>/dev/null || true) | ||||||||||||||||||||||||||||||||||||||||||||||||
| if [ -z "$_has_hip" ]; then | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -1437,8 +1473,7 @@ elif [ -n "$TORCH_INDEX_URL" ]; then | |||||||||||||||||||||||||||||||||||||||||||||||
| if [ "$SKIP_TORCH" = false ]; then | ||||||||||||||||||||||||||||||||||||||||||||||||
| case "$TORCH_INDEX_URL" in | ||||||||||||||||||||||||||||||||||||||||||||||||
| */rocm*) | ||||||||||||||||||||||||||||||||||||||||||||||||
| substep "installing bitsandbytes for AMD ROCm..." | ||||||||||||||||||||||||||||||||||||||||||||||||
| run_install_cmd "install bitsandbytes (AMD)" uv pip install --python "$_VENV_PY" --force-reinstall --no-cache-dir --no-deps "bitsandbytes>=0.49.1" | ||||||||||||||||||||||||||||||||||||||||||||||||
| _install_bnb_rocm "install bitsandbytes (AMD)" "$_VENV_PY" | ||||||||||||||||||||||||||||||||||||||||||||||||
| ;; | ||||||||||||||||||||||||||||||||||||||||||||||||
| esac | ||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -43,6 +43,41 @@ | |
| } | ||
| _PYTORCH_WHL_BASE = "https://download.pytorch.org/whl" | ||
|
|
||
| # bitsandbytes continuous-release_main wheels. bnb <= 0.49.2 ships with a | ||
| # broken 4-bit GEMV kernel on every ROCm target: CDNA (gfx90a / gfx942 / | ||
| # gfx950) via a broken blocksize=32/64 warp64 kernel, and RDNA3/3.5 | ||
| # (gfx1100-1103 / gfx1150-1152) via a compile-time warp-size dispatch bug. | ||
| # At decode shape (seq_len=1) the GEMV returns NaN, so autoregressive | ||
| # generation is broken even though training passes. bnb commit 713a3b8 | ||
| # ("[ROCm] Enable blocksize 32 4-bit quantization and GEMV kernels on AMD | ||
| # CDNA", PR #1887, merged 2026-03-09) fixes both bugs but has not shipped | ||
| # to PyPI yet. Pin to the continuous-release_main wheels so ROCm users | ||
| # get correct 4-bit decode on install. Drop the pin once bnb cuts a | ||
| # 0.50+ tag on PyPI. | ||
| _BNB_ROCM_PRERELEASE_URLS: dict[str, str] = { | ||
| "x86_64": ( | ||
| "https://github.com/bitsandbytes-foundation/bitsandbytes/releases/" | ||
| "download/continuous-release_main/" | ||
| "bitsandbytes-1.33.7.preview-py3-none-manylinux_2_24_x86_64.whl" | ||
| ), | ||
| "aarch64": ( | ||
| "https://github.com/bitsandbytes-foundation/bitsandbytes/releases/" | ||
| "download/continuous-release_main/" | ||
| "bitsandbytes-1.33.7.preview-py3-none-manylinux_2_24_aarch64.whl" | ||
|
Comment on lines
+53
to
+58
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similar to the shell script, these URLs hardcode the |
||
| ), | ||
| } | ||
|
Comment on lines
+49
to
+60
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To improve maintainability, you could define the base URL and wheel filename as constants. This avoids repeating the long URL string and makes future version updates easier. _BNB_BASE_URL = (
"https://github.com/bitsandbytes-foundation/bitsandbytes/releases/"
"download/continuous-release_main"
)
_BNB_WHEEL_TEMPLATE = "bitsandbytes-1.33.7.preview-py3-none-manylinux_2_24_{arch}.whl"
_BNB_ROCM_PRERELEASE_URLS: dict[str, str] = {
"x86_64": f"{_BNB_BASE_URL}/{_BNB_WHEEL_TEMPLATE.format(arch='x86_64')}",
"aarch64": f"{_BNB_BASE_URL}/{_BNB_WHEEL_TEMPLATE.format(arch='aarch64')}",
} |
||
| _BNB_ROCM_PYPI_FALLBACK = "bitsandbytes>=0.49.1" | ||
|
|
||
|
|
||
| def _bnb_rocm_prerelease_url() -> str | None: | ||
| """Return the continuous-release_main bnb wheel URL for the current | ||
| architecture, or None when no pre-release wheel is available. | ||
| Normalises amd64/arm64 aliases to x86_64/aarch64. | ||
| """ | ||
| arch = platform.machine().lower() | ||
| arch = {"amd64": "x86_64", "arm64": "aarch64"}.get(arch, arch) | ||
| return _BNB_ROCM_PRERELEASE_URLS.get(arch) | ||
|
|
||
|
|
||
| def _detect_rocm_version() -> tuple[int, int] | None: | ||
| """Return (major, minor) of the installed ROCm stack, or None.""" | ||
|
|
@@ -290,15 +325,42 @@ def _ensure_rocm_torch() -> None: | |
| # runtime is older than any published torch wheel. Uses | ||
| # --force-reinstall so an existing CPU/CUDA bitsandbytes is replaced | ||
| # by the AMD build during upgrades. | ||
| # | ||
| # Prefer the continuous-release_main wheel, which contains the CDNA | ||
| # and RDNA 4-bit GEMV fix (bnb PR #1887, merged 2026-03-09, post-0.49.2). | ||
| # Without that fix, autoregressive decode on every ROCm GPU produces | ||
| # NaN at seq_len=1 and generation returns gibberish or crashes in | ||
| # torch.multinomial. Falls back to PyPI >=0.49.1 on unknown architectures | ||
| # or when the pre-release URL is unreachable (offline / firewalled hosts). | ||
| if rocm_torch_ready: | ||
| pip_install( | ||
| "bitsandbytes (AMD)", | ||
| "--force-reinstall", | ||
| "--no-cache-dir", | ||
| "--no-deps", | ||
| "bitsandbytes>=0.49.1", | ||
| constrain = False, | ||
| ) | ||
| _bnb_url = _bnb_rocm_prerelease_url() | ||
| _bnb_installed = False | ||
| if _bnb_url is not None: | ||
| _bnb_installed = pip_install_try( | ||
| "bitsandbytes (AMD, pre-release main)", | ||
| "--force-reinstall", | ||
| "--no-cache-dir", | ||
| "--no-deps", | ||
| _bnb_url, | ||
| constrain = False, | ||
| ) | ||
| if not _bnb_installed: | ||
| print( | ||
| _red( | ||
| " bnb pre-release wheel unreachable; falling back " | ||
| "to PyPI (4-bit decode will be broken on ROCm -- " | ||
| "use 16-bit instead)" | ||
| ) | ||
| ) | ||
| if not _bnb_installed: | ||
| pip_install( | ||
| "bitsandbytes (AMD)", | ||
| "--force-reinstall", | ||
| "--no-cache-dir", | ||
| "--no-deps", | ||
| _BNB_ROCM_PYPI_FALLBACK, | ||
| constrain = False, | ||
| ) | ||
|
|
||
|
|
||
| def _infer_no_torch() -> bool: | ||
|
|
@@ -593,6 +655,38 @@ def _build_uv_cmd(args: tuple[str, ...]) -> list[str]: | |
| return cmd | ||
|
|
||
|
|
||
| def pip_install_try( | ||
| label: str, | ||
| *args: str, | ||
| constrain: bool = True, | ||
| ) -> bool: | ||
| """Try to install with pip/uv. Returns True on success, False on failure | ||
| (without raising or exiting). For optional install attempts with a | ||
| follow-up fallback, such as the bnb ROCm pre-release wheel. | ||
| """ | ||
| constraint_args: list[str] = [] | ||
| if constrain and CONSTRAINTS.is_file(): | ||
| constraint_args = ["-c", str(CONSTRAINTS)] | ||
|
|
||
| if USE_UV: | ||
| cmd = _build_uv_cmd(args) + constraint_args | ||
| else: | ||
| cmd = _build_pip_cmd(args) + constraint_args | ||
|
|
||
| if VERBOSE: | ||
| _step(_LABEL, f"{label}...", _dim) | ||
| result = subprocess.run( | ||
| cmd, | ||
| stdout = subprocess.PIPE, | ||
| stderr = subprocess.STDOUT, | ||
| ) | ||
| if result.returncode == 0: | ||
| return True | ||
| if VERBOSE and result.stdout: | ||
| print(result.stdout.decode(errors = "replace")) | ||
| return False | ||
|
Comment on lines
+638
to
+666
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The def pip_install_try(
label: str,
*args: str,
constrain: bool = True,
) -> bool:
"""Try to install with pip/uv. Returns True on success, False on failure
(without raising or exiting). For optional install attempts with a
follow-up fallback, such as the bnb ROCm pre-release wheel.
"""
constraint_args: list[str] = []
if constrain and CONSTRAINTS.is_file():
constraint_args = ["-c", str(CONSTRAINTS)]
if USE_UV:
cmd = _build_uv_cmd(args) + constraint_args
else:
cmd = _build_pip_cmd(args) + constraint_args
if VERBOSE:
_step(_LABEL, f"{label}...", _dim)
result = subprocess.run(
cmd,
stdout = subprocess.PIPE,
stderr = subprocess.STDOUT,
)
if result.returncode == 0:
return True
if VERBOSE and result.stdout:
_safe_print(result.stdout.decode(errors = "replace"))
return False |
||
|
|
||
|
|
||
| def pip_install( | ||
| label: str, | ||
| *args: str, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The wheel URLs contain a hardcoded version number (
1.33.7.preview). If the upstreambitsandbytesproject updates the version number in theircontinuous-release_maintag, these URLs will return a 404 error, breaking the installer for ROCm users. Consider if there is a way to resolve the latest asset URL dynamically or ensure the version number remains stable.