From eb93dda4fc3501baacfdcaf575b6def4c1337626 Mon Sep 17 00:00:00 2001 From: billishyahao Date: Mon, 15 Sep 2025 16:33:42 +0000 Subject: [PATCH 01/10] add rocm dockerfile (cherry picked from commit 6d6ab6bfaf9daff14e79f26cef16649eec604e86) --- docker/Dockerfile.rocm | 50 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 docker/Dockerfile.rocm diff --git a/docker/Dockerfile.rocm b/docker/Dockerfile.rocm new file mode 100644 index 0000000000..f1dd91ab38 --- /dev/null +++ b/docker/Dockerfile.rocm @@ -0,0 +1,50 @@ +ARG BASE_DOCKER=rocm/vllm-dev:nightly_main_20250914 +FROM $BASE_DOCKER + +# ARG GPU_ARCH=gfx942 +WORKDIR /unsloth-workspace + +RUN apt update +RUN apt install -y zip unzip wget +RUN apt install -y build-essential cmake + +ARG COMPUTE_BACKEND="hip" +ARG BNB_ROCM_ARCHS="gfx942" +ARG BNB_COMMIT="4b0257482bef447106fcaada67d1c6d081fdc82f" +ARG BNB_REPO="https://github.com/bitsandbytes-foundation/bitsandbytes.git" + +RUN git clone --depth 1 ${BNB_REPO} bitsandbytes \ + && cd bitsandbytes \ + && git fetch --depth 1 origin ${BNB_COMMIT} \ + && git checkout ${BNB_COMMIT} \ + && rm -rf .git \ + && cmake -S . -B build \ + -DCOMPUTE_BACKEND=${COMPUTE_BACKEND} \ + -DBNB_ROCM_ARCH="${BNB_ROCM_ARCHS}" \ + && cmake --build build -j"$(nproc)" \ + && pip install -e . \ + && rm -rf build + +ARG UNSLOTH_REPO="https://github.com/unslothai/unsloth.git" +ARG UNSLOTH_BRANCH="main" + + +RUN git clone --branch ${UNSLOTH_BRANCH} --depth 1 ${UNSLOTH_REPO} unsloth \ + && cd unsloth \ + && rm -rf .git \ + && pip install -e . + + +ARG UNSLOTH_ZOO_REPO="https://github.com/unslothai/unsloth-zoo.git" +ARG UNSLOTH_ZOO_BRANCH="main" + +RUN git clone --branch ${UNSLOTH_ZOO_BRANCH} --depth 1 ${UNSLOTH_ZOO_REPO} unsloth-zoo \ + && cd unsloth-zoo \ + && rm -rf .git \ + && pip install -e . + + +# Display installed packages for verification +RUN pip show bitsandbytes || (echo "bitsandbytes not installed!" && exit 1) +RUN pip show unsloth || (echo "unsloth not installed!" && exit 1) +RUN pip show unsloth-zoo || (echo "unsloth-zoo not installed!" && exit 1) From 976cfedf31b7336618e8ceb3c46d09f39d6e223f Mon Sep 17 00:00:00 2001 From: Daniel Han Date: Thu, 16 Jul 2026 04:53:35 +0000 Subject: [PATCH 02/10] docker: tighten the ROCm Dockerfile layers Combine apt-get update/install into one RUN with --no-install-recommends and list cleanup (a cached standalone update layer goes stale for later installs), fetch only the pinned bitsandbytes commit instead of cloning the default branch first, and fold the three pip verification probes into a single layer. --- docker/Dockerfile.rocm | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/docker/Dockerfile.rocm b/docker/Dockerfile.rocm index f1dd91ab38..73d9e92555 100644 --- a/docker/Dockerfile.rocm +++ b/docker/Dockerfile.rocm @@ -4,19 +4,27 @@ FROM $BASE_DOCKER # ARG GPU_ARCH=gfx942 WORKDIR /unsloth-workspace -RUN apt update -RUN apt install -y zip unzip wget -RUN apt install -y build-essential cmake +# Single layer: apt-get update + install must share a RUN (a cached standalone +# update layer goes stale and later installs hit dead package indexes), and the +# list cleanup keeps the layer small. --no-install-recommends trims the image. +RUN apt-get update \ + && apt-get install -y --no-install-recommends zip unzip wget build-essential cmake \ + && rm -rf /var/lib/apt/lists/* ARG COMPUTE_BACKEND="hip" ARG BNB_ROCM_ARCHS="gfx942" ARG BNB_COMMIT="4b0257482bef447106fcaada67d1c6d081fdc82f" ARG BNB_REPO="https://github.com/bitsandbytes-foundation/bitsandbytes.git" -RUN git clone --depth 1 ${BNB_REPO} bitsandbytes \ +# Fetch ONLY the pinned commit (no default-branch clone first): GitHub allows +# fetching an arbitrary SHA, so init + fetch --depth 1 downloads the +# minimum needed for a reproducible build. +RUN mkdir bitsandbytes \ && cd bitsandbytes \ + && git init \ + && git remote add origin ${BNB_REPO} \ && git fetch --depth 1 origin ${BNB_COMMIT} \ - && git checkout ${BNB_COMMIT} \ + && git checkout FETCH_HEAD \ && rm -rf .git \ && cmake -S . -B build \ -DCOMPUTE_BACKEND=${COMPUTE_BACKEND} \ @@ -44,7 +52,7 @@ RUN git clone --branch ${UNSLOTH_ZOO_BRANCH} --depth 1 ${UNSLOTH_ZOO_REPO} unslo && pip install -e . -# Display installed packages for verification -RUN pip show bitsandbytes || (echo "bitsandbytes not installed!" && exit 1) -RUN pip show unsloth || (echo "unsloth not installed!" && exit 1) -RUN pip show unsloth-zoo || (echo "unsloth-zoo not installed!" && exit 1) +# Verify the stack landed -- one layer for all three probes. +RUN for pkg in bitsandbytes unsloth unsloth-zoo; do \ + pip show "$pkg" >/dev/null || { echo "$pkg not installed!"; exit 1; }; \ + done From abfe2b680cd8a7f2bb2fbec934c40fa22343b2ac Mon Sep 17 00:00:00 2001 From: Daniel Han Date: Sat, 18 Jul 2026 08:12:00 +0000 Subject: [PATCH 03/10] Tighten Dockerfile.rocm comments --- docker/Dockerfile.rocm | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/docker/Dockerfile.rocm b/docker/Dockerfile.rocm index 73d9e92555..4d78c00f60 100644 --- a/docker/Dockerfile.rocm +++ b/docker/Dockerfile.rocm @@ -4,9 +4,7 @@ FROM $BASE_DOCKER # ARG GPU_ARCH=gfx942 WORKDIR /unsloth-workspace -# Single layer: apt-get update + install must share a RUN (a cached standalone -# update layer goes stale and later installs hit dead package indexes), and the -# list cleanup keeps the layer small. --no-install-recommends trims the image. +# update + install share one RUN so the cached index can't go stale; cleanup keeps the layer small. RUN apt-get update \ && apt-get install -y --no-install-recommends zip unzip wget build-essential cmake \ && rm -rf /var/lib/apt/lists/* @@ -16,9 +14,7 @@ ARG BNB_ROCM_ARCHS="gfx942" ARG BNB_COMMIT="4b0257482bef447106fcaada67d1c6d081fdc82f" ARG BNB_REPO="https://github.com/bitsandbytes-foundation/bitsandbytes.git" -# Fetch ONLY the pinned commit (no default-branch clone first): GitHub allows -# fetching an arbitrary SHA, so init + fetch --depth 1 downloads the -# minimum needed for a reproducible build. +# Fetch only the pinned commit via init + shallow fetch: minimal, reproducible. RUN mkdir bitsandbytes \ && cd bitsandbytes \ && git init \ @@ -52,7 +48,7 @@ RUN git clone --branch ${UNSLOTH_ZOO_BRANCH} --depth 1 ${UNSLOTH_ZOO_REPO} unslo && pip install -e . -# Verify the stack landed -- one layer for all three probes. +# Verify all three installed. RUN for pkg in bitsandbytes unsloth unsloth-zoo; do \ pip show "$pkg" >/dev/null || { echo "$pkg not installed!"; exit 1; }; \ done From 66f912625d75134f04c48c74bfe024c5fa9c53f8 Mon Sep 17 00:00:00 2001 From: Daniel Han Date: Sat, 18 Jul 2026 13:09:44 +0000 Subject: [PATCH 04/10] docker: fix bnb GEMV floor and install the HF training stack in the ROCm image Two review items, both reproduced before fixing. The pinned bitsandbytes commit (0.48.0.dev0, 2025-09-15) predates bnb PR 1887, which enabled the 4-bit GEMV kernels on AMD CDNA; every build at or below 0.49.2 NaNs at the GEMV decode shape on AMD GPUs, the exact floor install.sh already enforces for its ROCm wheel. BNB_COMMIT now defaults to the PR 1887 merge commit (0.50.0.dev0), which carries the fix. The unsloth install used bare pip install -e ., which pulls only the CLI dependencies (typer, rich, pydantic, pyyaml, nest-asyncio); the pip show probe passed on metadata alone while transformers, trl, peft, datasets, and accelerate were all absent, so the image built green but could not train. It now installs the huggingfacenotorch extra, which delivers the full HF training stack without torch or torchvision so the ROCm torch in the vLLM base image is never clobbered by a PyPI CPU/CUDA build. --- docker/Dockerfile.rocm | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/docker/Dockerfile.rocm b/docker/Dockerfile.rocm index 4d78c00f60..22557bc182 100644 --- a/docker/Dockerfile.rocm +++ b/docker/Dockerfile.rocm @@ -11,7 +11,10 @@ RUN apt-get update \ ARG COMPUTE_BACKEND="hip" ARG BNB_ROCM_ARCHS="gfx942" -ARG BNB_COMMIT="4b0257482bef447106fcaada67d1c6d081fdc82f" +# Must be at or after bnb PR #1887 (merged as this commit, 0.50.0.dev0): earlier +# builds (<= 0.49.2) NaN at the 4-bit GEMV decode shape on every AMD GPU, the +# same floor install.sh enforces for its ROCm wheel. +ARG BNB_COMMIT="713a3b83e405d32449e1cb392e5e25985ab927c6" ARG BNB_REPO="https://github.com/bitsandbytes-foundation/bitsandbytes.git" # Fetch only the pinned commit via init + shallow fetch: minimal, reproducible. @@ -33,10 +36,14 @@ ARG UNSLOTH_REPO="https://github.com/unslothai/unsloth.git" ARG UNSLOTH_BRANCH="main" +# huggingfacenotorch pulls the full HF training stack (transformers, trl, peft, +# datasets, accelerate) without torch/torchvision, so the base image's ROCm +# torch is never clobbered by a PyPI CPU/CUDA build. Bare `-e .` installs only +# the CLI deps and the image cannot actually train. RUN git clone --branch ${UNSLOTH_BRANCH} --depth 1 ${UNSLOTH_REPO} unsloth \ && cd unsloth \ && rm -rf .git \ - && pip install -e . + && pip install -e '.[huggingfacenotorch]' ARG UNSLOTH_ZOO_REPO="https://github.com/unslothai/unsloth-zoo.git" From 0d9f617e6a703694bf21dc312386031e138c9049 Mon Sep 17 00:00:00 2001 From: Daniel Han Date: Sun, 19 Jul 2026 14:59:10 +0000 Subject: [PATCH 05/10] docker: tighten rocm dockerfile comments --- docker/Dockerfile.rocm | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/docker/Dockerfile.rocm b/docker/Dockerfile.rocm index 22557bc182..56a898d8a2 100644 --- a/docker/Dockerfile.rocm +++ b/docker/Dockerfile.rocm @@ -4,20 +4,18 @@ FROM $BASE_DOCKER # ARG GPU_ARCH=gfx942 WORKDIR /unsloth-workspace -# update + install share one RUN so the cached index can't go stale; cleanup keeps the layer small. +# Single RUN so the apt index can't go stale; cleanup keeps the layer small. RUN apt-get update \ && apt-get install -y --no-install-recommends zip unzip wget build-essential cmake \ && rm -rf /var/lib/apt/lists/* ARG COMPUTE_BACKEND="hip" ARG BNB_ROCM_ARCHS="gfx942" -# Must be at or after bnb PR #1887 (merged as this commit, 0.50.0.dev0): earlier -# builds (<= 0.49.2) NaN at the 4-bit GEMV decode shape on every AMD GPU, the -# same floor install.sh enforces for its ROCm wheel. +# bnb PR #1887 floor (0.50.0.dev0); earlier builds NaN at 4-bit GEMV decode on AMD. ARG BNB_COMMIT="713a3b83e405d32449e1cb392e5e25985ab927c6" ARG BNB_REPO="https://github.com/bitsandbytes-foundation/bitsandbytes.git" -# Fetch only the pinned commit via init + shallow fetch: minimal, reproducible. +# Shallow-fetch only the pinned commit. RUN mkdir bitsandbytes \ && cd bitsandbytes \ && git init \ @@ -36,10 +34,8 @@ ARG UNSLOTH_REPO="https://github.com/unslothai/unsloth.git" ARG UNSLOTH_BRANCH="main" -# huggingfacenotorch pulls the full HF training stack (transformers, trl, peft, -# datasets, accelerate) without torch/torchvision, so the base image's ROCm -# torch is never clobbered by a PyPI CPU/CUDA build. Bare `-e .` installs only -# the CLI deps and the image cannot actually train. +# huggingfacenotorch pulls the HF training stack without torch/torchvision, so +# the base image's ROCm torch survives; bare `-e .` can't train. RUN git clone --branch ${UNSLOTH_BRANCH} --depth 1 ${UNSLOTH_REPO} unsloth \ && cd unsloth \ && rm -rf .git \ From 4df46dcea2138db7a6f2e3d8a4fcbfbca6e01484 Mon Sep 17 00:00:00 2001 From: Daniel Han Date: Sun, 19 Jul 2026 15:36:33 +0000 Subject: [PATCH 06/10] tests: track the moved pass-through inheritance in the gguf order check Main moved the llama_extra_args pass-through inheritance out of the GGUF branch into _resolve_inherited_extra_args, which runs before it, so the source-order assertion's "if request.llama_extra_args is None" anchor no longer exists inside the branch and the check failed after the main merge. The test now asserts the same property in the current shape: inheritance before the GGUF branch (a carried --no-mmproj still shapes the hub guard's companion requirement), and marker, hub guard, unload in order within the branch. Full file passes (32 tests). --- studio/backend/tests/test_gguf_load_cache_reuse.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/studio/backend/tests/test_gguf_load_cache_reuse.py b/studio/backend/tests/test_gguf_load_cache_reuse.py index 15d91cd324..6e707f6c76 100644 --- a/studio/backend/tests/test_gguf_load_cache_reuse.py +++ b/studio/backend/tests/test_gguf_load_cache_reuse.py @@ -728,9 +728,11 @@ class TestLoadHubDownloadExclusion: source = (Path(__file__).resolve().parent.parent / "routes" / "inference.py").read_text() gguf_branch = source[source.index("if config.is_gguf:") :] + # Pass-through inheritance runs before the GGUF branch, so a carried + # --no-mmproj shapes the hub guard's companion requirement. + assert source.index("_resolve_inherited_extra_args(") < source.index("if config.is_gguf:") assert ( gguf_branch.index("enter_context(gguf_load_in_flight") - < gguf_branch.index("if request.llama_extra_args is None") < gguf_branch.index("_hub_download_blocks_gguf_load") < gguf_branch.index("unsloth_backend.unload_model") ) From a7aefe8848eef0cbca371e567d961a4db6259c40 Mon Sep 17 00:00:00 2001 From: Daniel Han Date: Sun, 19 Jul 2026 16:22:15 +0000 Subject: [PATCH 07/10] tests: anchor the inheritance order check on the call, not the definition source.index("_resolve_inherited_extra_args(") matched the function definition, which always precedes the endpoint, so the ordering assertion was vacuously true. Anchoring on "= _resolve_inherited_ extra_args(" pins the first call site inside the load endpoint (line 4505), which is the statement whose position relative to the GGUF branch the test is meant to guard. 32 tests pass. --- studio/backend/tests/test_gguf_load_cache_reuse.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/studio/backend/tests/test_gguf_load_cache_reuse.py b/studio/backend/tests/test_gguf_load_cache_reuse.py index 6e707f6c76..6c39f813b1 100644 --- a/studio/backend/tests/test_gguf_load_cache_reuse.py +++ b/studio/backend/tests/test_gguf_load_cache_reuse.py @@ -730,7 +730,7 @@ class TestLoadHubDownloadExclusion: # Pass-through inheritance runs before the GGUF branch, so a carried # --no-mmproj shapes the hub guard's companion requirement. - assert source.index("_resolve_inherited_extra_args(") < source.index("if config.is_gguf:") + assert source.index("= _resolve_inherited_extra_args(") < source.index("if config.is_gguf:") assert ( gguf_branch.index("enter_context(gguf_load_in_flight") < gguf_branch.index("_hub_download_blocks_gguf_load") From 5c6fb65fa10fe7761fdf36a2d49815924652675b Mon Sep 17 00:00:00 2001 From: Daniel Han Date: Mon, 20 Jul 2026 00:21:59 +0000 Subject: [PATCH 08/10] tests: align the gguf order test with main Main fixed the stale ordering assertion in PR 7252; adopting its version verbatim removes this file from the branch diff entirely and avoids a conflict on the next main merge. 32 tests pass. --- studio/backend/tests/test_gguf_load_cache_reuse.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/studio/backend/tests/test_gguf_load_cache_reuse.py b/studio/backend/tests/test_gguf_load_cache_reuse.py index 6c39f813b1..62596fcc8a 100644 --- a/studio/backend/tests/test_gguf_load_cache_reuse.py +++ b/studio/backend/tests/test_gguf_load_cache_reuse.py @@ -728,9 +728,11 @@ class TestLoadHubDownloadExclusion: source = (Path(__file__).resolve().parent.parent / "routes" / "inference.py").read_text() gguf_branch = source[source.index("if config.is_gguf:") :] - # Pass-through inheritance runs before the GGUF branch, so a carried - # --no-mmproj shapes the hub guard's companion requirement. - assert source.index("= _resolve_inherited_extra_args(") < source.index("if config.is_gguf:") + # The gguf_load_in_flight marker must be entered before the hub-download + # guard and the unload so a concurrent load can't race the download + # manager. The llama_extra_args inheritance that used to sit between the + # marker and the guard now runs in _guard_chat_load_against_training, ahead + # of the GGUF branch, so it is no longer a landmark inside this slice. assert ( gguf_branch.index("enter_context(gguf_load_in_flight") < gguf_branch.index("_hub_download_blocks_gguf_load") From 19de4695b88b558d78e7ae98d9df1a4288229b54 Mon Sep 17 00:00:00 2001 From: Daniel Han Date: Sun, 26 Jul 2026 15:41:45 +0000 Subject: [PATCH 09/10] Dockerfile.rocm: trim comments that restate the adjacent line Drop the commented-out GPU_ARCH arg, the shallow-fetch note, and the install verification banner, and fold the huggingfacenotorch note onto one line. The bitsandbytes commit pin note stays: it records the upstream 4-bit GEMV NaN behaviour on AMD. No build instruction changed. --- docker/Dockerfile.rocm | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/docker/Dockerfile.rocm b/docker/Dockerfile.rocm index 56a898d8a2..6281971002 100644 --- a/docker/Dockerfile.rocm +++ b/docker/Dockerfile.rocm @@ -1,7 +1,6 @@ ARG BASE_DOCKER=rocm/vllm-dev:nightly_main_20250914 FROM $BASE_DOCKER -# ARG GPU_ARCH=gfx942 WORKDIR /unsloth-workspace # Single RUN so the apt index can't go stale; cleanup keeps the layer small. @@ -15,7 +14,6 @@ ARG BNB_ROCM_ARCHS="gfx942" ARG BNB_COMMIT="713a3b83e405d32449e1cb392e5e25985ab927c6" ARG BNB_REPO="https://github.com/bitsandbytes-foundation/bitsandbytes.git" -# Shallow-fetch only the pinned commit. RUN mkdir bitsandbytes \ && cd bitsandbytes \ && git init \ @@ -34,8 +32,7 @@ ARG UNSLOTH_REPO="https://github.com/unslothai/unsloth.git" ARG UNSLOTH_BRANCH="main" -# huggingfacenotorch pulls the HF training stack without torch/torchvision, so -# the base image's ROCm torch survives; bare `-e .` can't train. +# huggingfacenotorch skips torch/torchvision so the base image's ROCm torch survives; bare `-e .` can't train. RUN git clone --branch ${UNSLOTH_BRANCH} --depth 1 ${UNSLOTH_REPO} unsloth \ && cd unsloth \ && rm -rf .git \ @@ -51,7 +48,6 @@ RUN git clone --branch ${UNSLOTH_ZOO_BRANCH} --depth 1 ${UNSLOTH_ZOO_REPO} unslo && pip install -e . -# Verify all three installed. RUN for pkg in bitsandbytes unsloth unsloth-zoo; do \ pip show "$pkg" >/dev/null || { echo "$pkg not installed!"; exit 1; }; \ done From ba209f8539c14893d49bf1206a756d3b707a8876 Mon Sep 17 00:00:00 2001 From: Daniel Han Date: Sun, 26 Jul 2026 16:07:28 +0000 Subject: [PATCH 10/10] docker: fix the ROCm bitsandbytes install and make the final check able to fail The image did not build. bitsandbytes pins scikit-build-core unbounded in build-system.requires, so the builder always resolves the newest release. 1.0.0 (2026-07-06) added a PEP 660 gate to the setuptools plugin backend that bitsandbytes uses, rejecting editable installs unless pyproject sets editable.mode = "inplace". The pin here is from March and predates upstream adding that line, so pip install -e . dies in prepare_metadata_for_build_editable with "setuptools editable installs require editable.mode = 'inplace'". Verified by version bisection in the image: 0.11.6 and 0.12.2 install cleanly, 1.0.0, 1.0.1 and 1.0.3 all fail. Install non-editable instead. Upstream's own install docs annotate the -e as being for bitsandbytes development and say to leave it out otherwise, and an editable checkout buys nothing in an image while tying the build to a scikit-build-core knob that keeps moving. CMakeLists writes the library straight into the package dir, so setuptools package-data ships exactly what cmake built: the installed libbitsandbytes_rocm64.so is md5 identical to the compiled one and its .hip_fatbin still holds a single gfx942 bundle. The verification step could not fail. pip show passes on dist-info alone, so a missing or unloadable HIP library left it green on precisely the broken image it exists to catch. Load the artifacts instead. bitsandbytes cannot self-report here: with no AMD GPU on the builder get_cuda_specs returns None, it loads libbitsandbytes_cpu.so and hands back a healthy BNBNativeLibrary even after the ROCm library is deleted, so the check globs for libbitsandbytes_rocm*.so beside the installed package and ctypes.CDLL loads it. unsloth_zoo raises NotImplementedError on import without a torch accelerator, so it and unsloth are resolved with importlib.util.find_spec rather than executed. Deleting the library now fails the check; the intact image passes. The amdgpu-arch warning at configure time is benign and left alone. It comes from hip-config-amd.cmake, pulled in by find_package(hipblas), and only governs --offload-arch on the hip::device interface for CXX sources. bitsandbytes links hip::host and compiles its kernels as HIP, taking the arch from CMAKE_HIP_ARCHITECTURES, which BNB_ROCM_ARCH sets before enable_language(HIP). The built library contains gfx942 and no gfx906. --- docker/Dockerfile.rocm | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/docker/Dockerfile.rocm b/docker/Dockerfile.rocm index 6281971002..0a03ddafa1 100644 --- a/docker/Dockerfile.rocm +++ b/docker/Dockerfile.rocm @@ -14,6 +14,10 @@ ARG BNB_ROCM_ARCHS="gfx942" ARG BNB_COMMIT="713a3b83e405d32449e1cb392e5e25985ab927c6" ARG BNB_REPO="https://github.com/bitsandbytes-foundation/bitsandbytes.git" +# Plain install, not `-e`: upstream reserves editable for bnb development, and +# scikit-build-core 1.0.0 rejects it unless pyproject opts into +# editable.mode = "inplace", which this pin predates. cmake already dropped the +# .so into the package dir, so setuptools package-data ships it as built. RUN mkdir bitsandbytes \ && cd bitsandbytes \ && git init \ @@ -25,7 +29,7 @@ RUN mkdir bitsandbytes \ -DCOMPUTE_BACKEND=${COMPUTE_BACKEND} \ -DBNB_ROCM_ARCH="${BNB_ROCM_ARCHS}" \ && cmake --build build -j"$(nproc)" \ - && pip install -e . \ + && pip install . \ && rm -rf build ARG UNSLOTH_REPO="https://github.com/unslothai/unsloth.git" @@ -48,6 +52,18 @@ RUN git clone --branch ${UNSLOTH_ZOO_BRANCH} --depth 1 ${UNSLOTH_ZOO_REPO} unslo && pip install -e . -RUN for pkg in bitsandbytes unsloth unsloth-zoo; do \ - pip show "$pkg" >/dev/null || { echo "$pkg not installed!"; exit 1; }; \ - done +# pip show reads dist-info only, so it stayed green on an image whose freshly +# compiled HIP library was missing. bitsandbytes is no help either: with no AMD +# GPU on the builder it falls back to libbitsandbytes_cpu.so and reports +# success, so load the ROCm library explicitly. unsloth_zoo refuses to import +# without a torch accelerator, so only resolve it and unsloth. +# Still uncaught: a wrong-arch build loads fine here and only fails once a +# 4-bit GEMV runs on real AMD silicon. +RUN python3 -c "import ctypes, importlib.util, pathlib; \ + import bitsandbytes; \ + pkg = pathlib.Path(bitsandbytes.__file__).parent; \ + libs = sorted(pkg.glob('libbitsandbytes*.so')); \ + assert any('_rocm' in so.name for so in libs), f'no libbitsandbytes_rocm*.so in {pkg}'; \ + [ctypes.CDLL(str(so)) for so in libs]; \ + missing = [m for m in ('unsloth', 'unsloth_zoo') if importlib.util.find_spec(m) is None]; \ + assert not missing, f'not importable: {missing}'"