fix: no-torch install deps without pulling torch transitively (#4650)

Use --no-deps for ALL packages (unsloth, unsloth-zoo, and runtime deps)
since the current PyPI metadata for unsloth still declares torch as a
hard dependency. Runtime deps (typer, pydantic, safetensors,
transformers, etc.) are installed from no-torch-runtime.txt with
--no-deps to prevent transitive torch resolution from accelerate, peft,
trl, and sentence-transformers.

no-torch-runtime.txt now includes unsloth's own direct deps (typer,
pydantic, pyyaml, nest-asyncio) since --no-deps skips those too.

install.sh installs no-torch-runtime.txt directly (via helper function
_find_no_torch_runtime). install.ps1 does the same via
Find-NoTorchRuntimeFile. SKIP_STUDIO_BASE stays at 1 to avoid setup.sh
fast-path issues.

install_python_stack.py NO_TORCH branch does the same for unsloth
studio update, using package_name instead of hardcoded "unsloth".
This commit is contained in:
Daniel Han 2026-03-27 05:19:26 -07:00 committed by GitHub
commit eacaf6827c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 85 additions and 26 deletions

View file

@ -663,14 +663,29 @@ shell.Run cmd, 0, False
# CUDA wheels. Missing dependencies (transformers, trl, peft, etc.)
# are still pulled in because they are new, not upgrades.
#
# ── Helper: find no-torch-runtime.txt ──
function Find-NoTorchRuntimeFile {
if ($StudioLocalInstall -and (Test-Path (Join-Path $RepoRoot "studio\backend\requirements\no-torch-runtime.txt"))) {
return Join-Path $RepoRoot "studio\backend\requirements\no-torch-runtime.txt"
}
$installed = Get-ChildItem -Path $VenvDir -Recurse -Filter "no-torch-runtime.txt" -ErrorAction SilentlyContinue |
Where-Object { $_.FullName -like "*studio*backend*requirements*no-torch-runtime.txt" } |
Select-Object -ExpandProperty FullName -First 1
return $installed
}
if ($_Migrated) {
# Migrated env: force-reinstall unsloth+unsloth-zoo to ensure clean state
# in the new venv location, while preserving existing torch/CUDA
Write-Host "==> Upgrading unsloth in migrated environment..."
if ($SkipTorch) {
# No-torch: install packages without deps to avoid pulling torch.
# Runtime deps are installed by install_python_stack.py via no-torch-runtime.txt.
# No-torch: install unsloth + unsloth-zoo with --no-deps, then
# runtime deps (typer, safetensors, transformers, etc.) with --no-deps.
uv pip install --python $VenvPython --no-deps --reinstall-package unsloth --reinstall-package unsloth-zoo "unsloth>=2026.3.14" unsloth-zoo
$NoTorchReq = Find-NoTorchRuntimeFile
if ($NoTorchReq) {
uv pip install --python $VenvPython --no-deps -r $NoTorchReq
}
} else {
uv pip install --python $VenvPython --reinstall-package unsloth --reinstall-package unsloth-zoo "unsloth>=2026.3.14" unsloth-zoo
}
@ -692,9 +707,13 @@ shell.Run cmd, 0, False
Write-Host "==> Installing unsloth (this may take a few minutes)..."
if ($SkipTorch) {
# No-torch: install packages without deps to avoid pulling torch.
# Runtime deps are installed by install_python_stack.py via no-torch-runtime.txt.
# No-torch: install unsloth + unsloth-zoo with --no-deps, then
# runtime deps (typer, safetensors, transformers, etc.) with --no-deps.
uv pip install --python $VenvPython --no-deps --upgrade-package unsloth --upgrade-package unsloth-zoo "unsloth>=2026.3.14" unsloth-zoo
$NoTorchReq = Find-NoTorchRuntimeFile
if ($NoTorchReq) {
uv pip install --python $VenvPython --no-deps -r $NoTorchReq
}
if ($StudioLocalInstall) {
Write-Host "==> Overlaying local repo (editable)..."
uv pip install --python $VenvPython -e $RepoRoot --no-deps
@ -735,9 +754,8 @@ shell.Run cmd, 0, False
return
}
# Tell setup.ps1 to skip base package installation (install.ps1 already did it)
# When no-torch, don't skip base so install_python_stack installs
# no-torch-runtime.txt (the runtime deps that --no-deps skipped).
$env:SKIP_STUDIO_BASE = if ($SkipTorch) { "0" } else { "1" }
# Tell setup.ps1 to skip base package installation (install.ps1 already did it)
$env:SKIP_STUDIO_BASE = "1"
$env:STUDIO_PACKAGE_NAME = $PackageName
$env:UNSLOTH_NO_TORCH = if ($SkipTorch) { "true" } else { "false" }
if ($StudioLocalInstall) {

View file

@ -891,6 +891,21 @@ fi
# ── Resolve repo root (for --local installs) ──
_REPO_ROOT="$(cd "$(dirname "$0" 2>/dev/null || echo ".")" && pwd)"
# ── Helper: find no-torch-runtime.txt (local repo or site-packages) ──
_find_no_torch_runtime() {
# Check local repo first (for --local installs)
if [ -f "$_REPO_ROOT/studio/backend/requirements/no-torch-runtime.txt" ]; then
echo "$_REPO_ROOT/studio/backend/requirements/no-torch-runtime.txt"
return
fi
# Check inside installed package
_rt=$(find "$VENV_DIR" -path "*/studio/backend/requirements/no-torch-runtime.txt" -print -quit 2>/dev/null || echo "")
if [ -n "$_rt" ]; then
echo "$_rt"
return
fi
}
# ── Detect GPU and choose PyTorch index URL ──
# Mirrors Get-TorchIndexUrl in install.ps1.
# On CPU-only machines this returns the cpu index, avoiding the solver
@ -947,12 +962,17 @@ if [ "$_MIGRATED" = true ]; then
# in the new venv location, while preserving existing torch/CUDA
echo "==> Upgrading unsloth in migrated environment..."
if [ "$SKIP_TORCH" = true ]; then
# No-torch: install packages without deps to avoid pulling torch.
# Runtime deps (safetensors, transformers, etc.) are installed by
# install_python_stack.py via no-torch-runtime.txt.
# No-torch: install unsloth + unsloth-zoo with --no-deps (current
# PyPI metadata still declares torch as a hard dep), then install
# runtime deps (typer, safetensors, transformers, etc.) with --no-deps
# to prevent transitive torch resolution.
uv pip install --python "$_VENV_PY" --no-deps \
--reinstall-package unsloth --reinstall-package unsloth-zoo \
"unsloth>=2026.3.14" unsloth-zoo
_NO_TORCH_RT="$(_find_no_torch_runtime)"
if [ -n "$_NO_TORCH_RT" ]; then
uv pip install --python "$_VENV_PY" --no-deps -r "$_NO_TORCH_RT"
fi
else
uv pip install --python "$_VENV_PY" \
--reinstall-package unsloth --reinstall-package unsloth-zoo \
@ -974,11 +994,15 @@ elif [ -n "$TORCH_INDEX_URL" ]; then
# Fresh: Step 2 - install unsloth, preserving pre-installed torch
echo "==> Installing unsloth (this may take a few minutes)..."
if [ "$SKIP_TORCH" = true ]; then
# No-torch: install packages without deps to avoid pulling torch.
# Runtime deps are installed by install_python_stack.py via no-torch-runtime.txt.
# No-torch: install unsloth + unsloth-zoo with --no-deps, then
# runtime deps (typer, safetensors, transformers, etc.) with --no-deps.
uv pip install --python "$_VENV_PY" --no-deps \
--upgrade-package unsloth --upgrade-package unsloth-zoo \
"unsloth>=2026.3.14" unsloth-zoo
_NO_TORCH_RT="$(_find_no_torch_runtime)"
if [ -n "$_NO_TORCH_RT" ]; then
uv pip install --python "$_VENV_PY" --no-deps -r "$_NO_TORCH_RT"
fi
if [ "$STUDIO_LOCAL_INSTALL" = true ]; then
echo "==> Overlaying local repo (editable)..."
uv pip install --python "$_VENV_PY" -e "$_REPO_ROOT" --no-deps
@ -1036,21 +1060,15 @@ if [ -n "$VENV_ABS_BIN" ]; then
fi
echo "==> Running unsloth setup..."
# When no-torch, don't skip base so install_python_stack installs
# no-torch-runtime.txt (the runtime deps that --no-deps skipped).
_SKIP_BASE=1
if [ "$SKIP_TORCH" = true ]; then
_SKIP_BASE=0
fi
if [ "$STUDIO_LOCAL_INSTALL" = true ]; then
SKIP_STUDIO_BASE="$_SKIP_BASE" \
SKIP_STUDIO_BASE=1 \
STUDIO_PACKAGE_NAME="$PACKAGE_NAME" \
STUDIO_LOCAL_INSTALL=1 \
STUDIO_LOCAL_REPO="$_REPO_ROOT" \
UNSLOTH_NO_TORCH="$SKIP_TORCH" \
bash "$SETUP_SH" </dev/null
else
SKIP_STUDIO_BASE="$_SKIP_BASE" \
SKIP_STUDIO_BASE=1 \
STUDIO_PACKAGE_NAME="$PACKAGE_NAME" \
UNSLOTH_NO_TORCH="$SKIP_TORCH" \
bash "$SETUP_SH" </dev/null

View file

@ -1,7 +1,18 @@
# Runtime dependencies for no-torch (GGUF-only) mode.
# These are normally pulled in transitively by unsloth-zoo, but
# --no-deps skips them to avoid torch. Install these explicitly.
# Mirrors the [huggingfacenotorch] extras from pyproject.toml.
# Installed with --no-deps to prevent transitive torch resolution
# from packages like accelerate, peft, trl, sentence-transformers.
#
# Includes unsloth's own direct deps (typer, pydantic, pyyaml,
# nest-asyncio) since unsloth is also installed with --no-deps
# (current PyPI metadata still declares torch as a hard dep).
# unsloth direct deps (from pyproject.toml [project].dependencies)
typer
pydantic
pyyaml
nest-asyncio
# HF ecosystem (from [huggingfacenotorch] extras in pyproject.toml)
wheel>=0.42.0
packaging
numpy

View file

@ -462,13 +462,25 @@ def install_python_stack() -> int:
if skip_base:
print(_green(f"{package_name} already installed — skipping base packages"))
elif NO_TORCH:
# No-torch mode: unsloth + unsloth-zoo are already installed with
# --no-deps by install.sh/install.ps1. Install the runtime deps
# (safetensors, transformers, datasets, etc.) from no-torch-runtime.txt.
# No-torch update path: install unsloth + unsloth-zoo with --no-deps
# (current PyPI metadata still declares torch as a hard dep), then
# runtime deps with --no-deps (avoids transitive torch).
_progress("base packages (no torch)")
pip_install(
f"Updating {package_name} + unsloth-zoo (no-torch mode)",
"--no-cache-dir",
"--no-deps",
"--upgrade-package",
package_name,
"--upgrade-package",
"unsloth-zoo",
package_name,
"unsloth-zoo",
)
pip_install(
"Installing no-torch runtime deps",
"--no-cache-dir",
"--no-deps",
req = REQ_ROOT / "no-torch-runtime.txt",
)
if local_repo: