Skip to content

[staging CI] unslothai/unsloth#7706 - #676

Open
danielhanchen wants to merge 14 commits into
mainfrom
pr-7706-ci
Open

[staging CI] unslothai/unsloth#7706#676
danielhanchen wants to merge 14 commits into
mainfrom
pr-7706-ci

Conversation

@danielhanchen

Copy link
Copy Markdown
Owner

Disposable CI run for unslothai#7706. Do not merge; closed after CI.

legobele and others added 14 commits July 31, 2026 14:27
The installer's GPU detection chain (NVIDIA -> AMD ROCm -> else)
has no Intel Arc/SYCL/XPU branch, so Intel Arc GPUs fall into the
"none (chat-only / GGUF)" branch and get CPU PyTorch despite
PyTorch publishing XPU wheels at download.pytorch.org/whl/xpu.

This adds:
- WMI-based Intel GPU detection (Arc, Iris, UHD, HD Graphics)
- Torch XPU availability check for migrated/upgraded environments
- An XPU PyTorch install path with the whl/xpu index
- CPU fallback with a pointer to the Intel oneAPI docs when XPU
  isn't available
- Updated messaging from "NVIDIA or AMD ROCm" to include Intel Arc

The XPU wheels ship their own oneAPI runtime (intel-sycl-rt et al.)
so no Intel oneAPI Base Toolkit is required for GPU training.

Tested on: Windows 11, Intel Arc 140V GPU (8GB), PyTorch 2.9.0+xpu

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
The XPU index selected during GPU detection was overwritten by
Get-TorchIndexUrl before the install branch read it, so Intel hosts still
got CPU PyTorch while being told XPU wheels were being installed.

- Move the XPU reroute after Get-TorchIndexUrl, and let an explicit pin win
- Detect via Get-CimInstance (Get-WmiObject is absent in PowerShell 7)
- Match only Arc / Data Center GPU, so UHD / HD / Iris Xe are not promised XPU
- Split Intel GPU present from XPU-capable so the CPU fallback hint works
- Bound the XPU torch trio like every other index (bare names resolved
  torch 2.13.0 + torchaudio 2.11.0 and pulled unsloth back to an old release)
- Clear the XPU state after a CPU fallback, mirroring the ROCm path
- Teach the index family, GPU branch and torch flavor helpers about xpu
install.ps1 now classifies an /xpu index leaf as family xpu / branch xpu, so
mirror the same two cases in _tauri_torch_index_family and _tauri_gpu_branch.
These feed the [TAURI:DIAG] line only, and a Linux user can already reach the
xpu index via UNSLOTH_TORCH_INDEX_FAMILY, where it previously reported
auto/unknown. Linux Intel auto-detection is not added here.
Comment and whitespace only, no code change.
- Run the Intel scan before the GPU report chain instead of inside its final
  else. A WMI-named-only AMD adapter set ROCmGpuLabel and took that chain, so a
  discrete Arc card next to an AMD CPU's integrated Radeon was never detected.
  The scan is gated on no usable NVIDIA or AMD, and the Intel branch ranks above
  the two AMD-present-but-unusable branches, so a usable AMD host is unaffected.
- Let a migrated env's torch veto the hardware match only when it is itself an
  XPU build. A CPU build reports torch.xpu.is_available() False for lacking XPU
  support, not for unsuitable hardware, and was blocking the CPU to XPU upgrade.
- Detect Intel in studio/setup.ps1 too. It only knew NVIDIA and AMD, so every
  successful Intel install printed none (chat-only / GGUF) right after
  install.ps1 reported a usable Arc GPU. Self-contained so studio update works.
- Reset $script:IsIntelXpu at the start of each invocation. Under the documented
  irm | iex path $script: is the caller's session scope, so a second run in the
  same session inherited a stale true, skipped the scan on a now-NVIDIA host and
  still rerouted to the xpu index. Reproduced in pwsh before fixing.
- Gate the Intel scan on whether AMD actually gets a wheel, not on whether an AMD
  arch was seen. An arch missing from the family map has no ROCm wheels and lands
  on CPU torch, so it must not outrank a usable Arc card. The map is hoisted above
  the scan and consumed unchanged by the AMD reroute.
- Select the XPU index in studio/setup.ps1, not just report it. Previously setup
  printed Intel GPU detected and then installed CPU torch, so studio update never
  migrated an Arc box off CPU. Adds a bounded XPU install with a CPU fallback,
  teaches the stale-venv check about +xpu, and mirrors the wheel-aware AMD gate so
  the two files agree instead of wiping the venv on every update.
- Force the dependency pass on an Arc host whose torch is not XPU-capable, the
  Intel counterpart of the existing AMD escape. Without it the fast up-to-date
  path skipped the install block, so the xpu index selection was never reached
  and a CPU venv never migrated.
- Confirm a working XPU runtime before treating an xpu venv as stale. If CIM is
  unavailable or returns an Intel name outside the Arc match, the expected tag
  fell through to cpu and a valid XPU environment was rebuilt and lost.
- Force-reinstall the XPU trio only when the installed wheel is not already
  +xpu, or the pin changed. It was unconditional, so a fresh install re-fetched
  multiple GB immediately and again on every update.
- Warn when torch.xpu.is_available() is false after installing XPU torch, naming
  the Intel driver floor. Otherwise the installer promised GPU training while
  unsloth raised NotImplementedError at import on a stale driver.
- Stop the detection probe vetoing the hardware match. Its cpu fallback could not
  displace the installed +xpu wheel, so it only mislabelled a capable GPU as
  unusable; the driver warning covers that case honestly, and setup.ps1 agrees.
…dbytes on the Intel path

install.sh: teach _torch_flavor_tag, _expected_torch_flavor_tag and
_torch_index_repairable about the xpu leaf. The diagnostic already reported
gpu_branch=xpu, but an xpu pin fell to the custom arm so a migrated env kept
its CPU wheel. The +xpu flavor arm is required alongside, otherwise a correct
2.10.0+xpu wheel reads as cpu and gets force-reinstalled every run.

install.ps1 / studio/setup.ps1: route every torch probe through a new bounded
Invoke-BoundedPythonProbe (ProcessStartInfo, both streams drained async,
WaitForExit, kill on timeout). A hanging Intel driver init is exactly what
these probes detect, and an unbounded one would hang the installer instead of
reaching the warning. Timeouts read as not-available. Get-InstalledTorchTag
now shares the helper rather than carrying a second copy of the pattern.

install.ps1: install bitsandbytes>=0.50.0 on the XPU path. unsloth's floor is
>=0.45.5, so a migrated venv keeps a pre-0.49 wheel with no XPU library and
4-bit QLoRA silently turns off. Same floor the AMD paths use, since <=0.49.2
NaNs at 4-bit decode and an Arc card can sit next to a Radeon.
… pin

studio/setup.ps1: `unsloth studio update` migrating a CPU venv to XPU replaced
only the torch trio. install_python_stack.py then upgrades unsloth and
unsloth-zoo alone, so an installed bitsandbytes 0.45.x kept satisfying the base
floor while carrying no Windows XPU kernels, and 4-bit QLoRA silently turned
off. Adds the same bitsandbytes>=0.50.0 --no-deps pass install.ps1 got, placed
after the stack so it is the last word, gated on $XpuIndexUrl (the CPU fallback
clears it, no-torch never sets it) and still inside the -not $SkipPythonDeps
block so the up-to-date escape does not reach it.

install.ps1: key the bitsandbytes pass off the index leaf instead of
$script:IsIntelXpu. An explicit UNSLOTH_TORCH_INDEX_FAMILY=xpu pin on a
non-Intel host skips the XPU branch but still installs the trio from the xpu
index, so torch is +xpu and needs the same floor. The CPU fallback rewrites
$TorchIndexUrl, so a failed XPU install reads as cpu and stays quiet.
Comment-only pass now that the review has settled: several blocks grew over
successive rounds and were restating the code or narrating the review. Net 36
lines removed, with the load-bearing facts kept -- why ProcessStartInfo rather
than the call operator, why both probe streams drain async, why the helper is
defined above the Intel scan, the 0.50.0 bitsandbytes floor and why not the
curated extra, and why PEP 440 means a migrated env can confirm but never veto
the Intel match.

Also records why the Studio bitsandbytes pass must stay above the
ErrorActionPreference restore: Fast-Install needs EAP=Continue or PS 5.1 turns
pip stderr into a terminating error.

No code tokens changed; verified with a PowerShell token-stream diff of
install.ps1 and setup.ps1, and by hand for install.sh.
… Triton shadowing XPU

studio/setup.ps1: the stale-venv flavor probe read StandardOutput.ReadToEnd()
before WaitForExit, so the timeout was unreachable and a wedged import torch
hung studio setup forever; stderr was never drained either. Routed through
Invoke-BoundedPythonProbe, which already drains both streams and kills on
timeout. A timeout now reads as unreadable flavor, so the venv rebuilds.

install.ps1 / studio/setup.ps1: bound the Win32_VideoController query and add a
registry fallback. -ErrorAction suppresses errors but bounds nothing, and
-OperationTimeoutSec is not enforced for the local COM session this uses, so a
degraded WMI repository blocks forever. install_llama_prebuilt.py already runs
this query out of process for the same reason and documents an Arc A770 being
misrouted by it. The registry class key answers in-process; it is the fallback
rather than the fast path because a stale driver config can outlive the
hardware, and here a false positive would install XPU torch on a host with no
Arc.

studio/setup.ps1: replace triton-windows with torch's own XPU triton after the
stack. Both distributions own the top-level triton package, sharing 151 paths
including __init__.py and _C/libtriton.pyd, so an in-place cu-to-xpu repair
leaves the CUDA build shadowing the XPU one. Removing it alone would delete the
shared files the XPU wheel overwrote, and unsloth declares triton-windows as a
win32 dependency so an earlier removal is reinstalled by the stack: uninstall
and reinstall, after the stack, only while triton-windows is present. The spec
is read from the installed torch, since the name changed from
pytorch-triton-xpu to triton-xpu in torch 2.10.
Comment-only pass over the previous commit's additions, which had not been
through one: 15 lines removed across the two bounded-scan headers, the two
registry-fallback headers and the Triton block.

Kept the facts that cost measurement: -OperationTimeoutSec not being enforced
for a local COM session, Ok being false on an empty answer because a Windows
host always has an adapter, the registry class key being fallback rather than
fast path here, the 151 shared Triton paths, and why the uninstall has to be
paired with a reinstall after the stack.

No code tokens changed; verified with a PowerShell token-stream diff of both
files, which also confirms the two helper copies stay identical.
…t strand the venv

The replacement uninstalled triton-windows and then installed the XPU triton
from the index. A failure between the two left the venv with a partially
deleted triton, since the uninstall drops the paths shared with the XPU
distribution, and the warning made that look like a skipped optional repair.

The uninstall cannot go last, because it removes the paths in triton-windows'
own record and those are the shared ones. So fetch first: pip download the
wheel, confirm one is actually on disk (exit 0 alone is not enough, an
sdist-only mirror satisfies that), and only then uninstall and install the
local file. A local wheel installs with the network refused, so nothing after
the destructive step depends on the index. A failed fetch leaves
triton-windows in place, which is the pre-existing shadowing rather than a
broken venv, and says so.

Past that point only disk or permissions can fail, so restore triton-windows
if the local install does, leaving a triton that imports. If both fail the
message is loud and carries the repair command, with the index URL redacted
since a mirror pin can carry a token.

pip only: uv has no pip download (astral-sh/uv#3163).
@gemini-code-assist

Copy link
Copy Markdown

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants