docker: pin xformers explicitly, forward the llama tag to the Studio build

The amd64 base install named the cu128-ampere-torch2110 extra, which does not
exist on main yet (the CUDA extras stop at torch2100): pip/uv only warn on an
unknown extra, so plain unsloth installed without xformers and the required-
package check failed the build. Both arches now take the plain huggingface
extra and amd64 pins xformers==0.0.35 explicitly in the same resolve (it
requires torch>=2.10 without an exact pin, pairing with the baked 2.11.0;
verified on PyPI, x86_64 wheels only, matching the arm64 exclusion). This
decouples the base image from the pending extras PR.

The Studio build now receives the SAME llama.cpp tag the base image baked:
Dockerfile.studio grows a LLAMA_PREBUILT_TAG arg exported as UNSLOTH_LLAMA_TAG
to install.sh (setup.sh honours it; the "latest" default is byte-identical to
setup.sh's own default for local builds), and the publish workflow forwards
the prepare job's resolved tag in the studio build-args. Without the pin a
dispatch override or an upstream release landing between the two jobs let the
no-GPU Studio build re-resolve "latest" and replace the pinned CUDA bundle.

The Studio venv-match assertion also needs installer support for torch 2.11
on the CUDA path; that lands in a separate installer PR and is now declared
as a merge-order dependency in the PR description (the publish workflow only
runs on main pushes, so nothing builds before both are merged).
This commit is contained in:
Daniel Han 2026-07-16 06:53:44 +00:00
commit 8fa588db2c
3 changed files with 26 additions and 19 deletions

View file

@ -438,14 +438,16 @@ jobs:
cache-from: type=gha,scope=studio-${{ matrix.platform }}
cache-to: type=gha,scope=studio-${{ matrix.platform }},mode=min
outputs: type=image,name=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=true
# Both refs are the SAME resolved shas the base build baked (prepare
# job), so the Studio tree + its zoo overlay match the base venv even
# if the branch moved mid-run. (Prose stays out of build-args --
# forwarded lines must be KEY=VALUE only.)
# All three pins are the SAME resolved values the base build baked
# (prepare job), so the Studio tree, its zoo overlay AND its llama.cpp
# bundle match the base image even if a branch or upstream release
# moved mid-run. (Prose stays out of build-args -- forwarded lines
# must be KEY=VALUE only.)
build-args: |
BASE_IMAGE=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ needs.merge.outputs.digest }}
UNSLOTH_STUDIO_REF=${{ needs.prepare.outputs.unsloth_ref }}
UNSLOTH_STUDIO_ZOO_REF=${{ needs.prepare.outputs.zoo_ref }}
LLAMA_PREBUILT_TAG=${{ needs.prepare.outputs.llama_tag }}
- name: Export digest
run: |

View file

@ -137,18 +137,15 @@ RUN python -m venv ${VENV} && ${VENV}/bin/pip install -U pip wheel setuptools
# Where torch's +cu128 wheels live, plus the xformers/cu128 URLs referenced
# by unsloth's `cu128onlytorch2110` extra.
#
# Why the extra is `cu128-ampere-torch2110` (not `cu128-torch2110-ampere`):
# The ordering is ampere-then-torch-ver (see the `cu*-ampere-torch2110`
# extras in unsloth's pyproject.toml). The torch2110 family pulls
# xformers 0.0.35, which does not pin torch and so pairs with the torch
# 2.11.0 line held below; the older torch2100 extra pins xformers 0.0.34 ->
# torch==2.10.0 and would conflict. Needs an unsloth that carries the
# torch2110 CUDA extras on main.
#
# Why arm64 uses a different extra:
# `cu128-ampere-torch2110` transitively pulls `cu128onlytorch2110` whose
# xformers wheel URL is hardcoded to manylinux_2_28_x86_64 (the aarch64
# wheel gap -- see header), so arm64 takes the plain `huggingface` extra.
# Why the plain `huggingface` extra plus an EXPLICIT xformers pin (amd64):
# The cu128 CUDA extras on main stop at the torch2100 family, which pins
# xformers 0.0.34 -> torch==2.10.0 and would conflict with the torch 2.11.0
# line held below; a not-yet-existing extra name would only WARN (pip/uv
# install plain unsloth) and silently drop xformers until the required-
# package check below failed the build. Pinning `xformers==0.0.35` directly
# (it does not pin torch, pairing with 2.11.0) keeps this build
# self-contained on today's main; arm64 stays xformers-less (no cu128
# aarch64 wheel -- see header).
#
# Why no `flash-attn` here:
# - FA3 is hard-refused on Blackwell (Dao-AILab/flash-attention#1810).
@ -161,17 +158,18 @@ ARG UNSLOTH_REF=main
ARG UNSLOTH_ZOO_REF=main
RUN set -eux \
&& case "${TARGETARCH:-amd64}" in \
amd64) UNSLOTH_EXTRA="cu128-ampere-torch2110" ;; \
arm64) UNSLOTH_EXTRA="huggingface" ;; \
amd64) UNSLOTH_EXTRA="huggingface"; XFORMERS_PIN="xformers==0.0.35" ;; \
arm64) UNSLOTH_EXTRA="huggingface"; XFORMERS_PIN="" ;; \
*) echo "ERROR: unsupported TARGETARCH=${TARGETARCH}" >&2; exit 1 ;; \
esac \
&& echo ">> TARGETARCH=${TARGETARCH:-amd64}, unsloth extra=[${UNSLOTH_EXTRA}]" \
&& echo ">> TARGETARCH=${TARGETARCH:-amd64}, unsloth extra=[${UNSLOTH_EXTRA}], xformers=[${XFORMERS_PIN}]" \
&& ${VENV}/bin/pip install uv \
&& ${VENV}/bin/uv pip install \
--python ${VENV}/bin/python \
--index-strategy unsafe-best-match \
--extra-index-url https://download.pytorch.org/whl/cu128 \
"torch==2.11.0" "torchvision==0.26.0" "torchaudio==2.11.0" \
${XFORMERS_PIN} \
"triton>=3.6.0" \
"bitsandbytes>=0.49.2,!=0.46.0,!=0.48.0" \
"unsloth_zoo @ git+https://github.com/unslothai/unsloth-zoo@${UNSLOTH_ZOO_REF}" \

View file

@ -60,6 +60,12 @@ ARG UNSLOTH_STUDIO_REF=main
# Studio builds, so the Studio backend runs the same zoo as the base image and
# the operator-requested ref instead of always tracking main.
ARG UNSLOTH_STUDIO_ZOO_REF=main
# The SAME llama.cpp tag the base image baked (the prepare job resolves it
# once). install.sh -> setup.sh honours UNSLOTH_LLAMA_TAG; without this pin a
# dispatch override, or an upstream release landing between the base and
# Studio jobs, lets the no-GPU Studio build re-resolve "latest" and replace
# the base's pinned CUDA bundle instead of reusing it.
ARG LLAMA_PREBUILT_TAG=latest
ARG TARGETARCH
# Services run as root in this revision (the base image is root-only by
@ -134,6 +140,7 @@ RUN set -eux \
&& UNSLOTH_STUDIO_HOME="${UNSLOTH_STUDIO_HOME}" \
UNSLOTH_TORCH_INDEX_FAMILY="${TORCH_FAMILY}" \
UNSLOTH_ZOO_REF="${UNSLOTH_STUDIO_ZOO_REF}" \
UNSLOTH_LLAMA_TAG="${LLAMA_PREBUILT_TAG}" \
UNSLOTH_PYTHON=3.12 \
bash install.sh --local \
# Fail loud unless the Studio venv torch EXACTLY matches the base venv