Conversation
…ts device
`uv sync` only worked on Windows: tool.uv.environments pinned the lockfile to
sys_platform == 'win32', so resolution aborted on macOS and on a Linux CUDA
host before any package was considered. Behind that pin sat five more
portability defects, each only visible once the previous one was fixed.
Packaging:
- drop the win32 environment pin; fork the resolution over win32/linux/darwin
so one lockfile serves Windows+CUDA, Linux+CUDA and macOS+MPS
- take torch/torchvision from the cu124 index on Windows and Linux only, and
from PyPI (the build carrying Metal support) on macOS
- raise requires-python to >=3.10: dearpygui 1.11.1 ships macOS arm64 wheels
for cp310+ only, and 3.9 is EOL
- bound numpy to <2. opencv-python 4.10.0.82 is built against the numpy 1.x
ABI, and on 3.10+ an unbounded numpy resolved to 2.x and broke `import cv2`
- mark pywin32 win32-only (it is never imported), drop pyopengl-accelerate
(no arm64 wheel, sdist fails to cythonize) and the pyqt5-qt5==5.15.2
override (that version has no arm64 wheel)
- tell hatchling the package directory is `yoru`; it could not infer it from
the distribution name `yoru_uv`, so `uv sync` failed to build the project
on every platform once the lock was regenerated
- the committed lock had drifted to a different manifest (root package
yoru/0.1.0, ultralytics==8.2.52), so `uv sync --locked` failed everywhere
and plain `uv sync` silently re-locked. Regenerated, and CI now guards it
Device selection: ultralytics never auto-selects MPS -- select_device("")
resolves CUDA then CPU -- so every Apple Silicon user silently trained and
inferred on the CPU. New yoru/libs/device.py resolves CUDA -> MPS -> CPU,
honours YORU_DEVICE, and degrades with a warning when a device is unavailable.
Both training scripts gained --device, the training GUI gained a selector, and
the inference wrappers now name the device on every predict call. torchvision
detection heads are excluded from the MPS default: they do not converge there
(loss diverges to 1e32 against 0.49 on CPU), so `auto` stays CUDA -> CPU and
MPS requires an explicit request.
Also: yoru/testing.py was a stub that wrote a b"dummy" checkpoint, so both
smoke tests passed in 0.19s and proved nothing -- they now drive the real
create_yaml_train -> train_ultralytics -> load_yolo_model round trip (21s).
tests/test_cuda.py skips instead of failing without an NVIDIA GPU.
app.py's config-creator used subprocess.CREATE_NEW_CONSOLE, which does not
exist off Windows. detection.py imported dearpygui but never used it.
First CI: uv sync + pytest on ubuntu/windows/macos, with `uv lock --check`.
Verified on macOS 26.5.2, Apple M5 (arm64), uv 0.11.14:
uv sync from the committed lock -> Python 3.10.19, torch 2.11.0 (MPS
available), torchvision 0.26.0, ultralytics 8.3.222, opencv 4.10.0,
numpy 1.24.4, dearpygui 1.11.1
pytest: 79 passed, 7 skipped
training via the exact argv train_GUI builds, --device auto -> "Apple MPS",
ultralytics confirms "MPS (Apple M5)"; 30 epochs on 400/100 frames of
test_data reached mAP50 0.974 / mAP50-95 0.692 in 672 s
inference through load_yolo_model over the test video: MPS and CPU return
identical detections (120 over 60 frames)
Windows and Linux are verified at the lockfile level only; both still need a
real `uv sync` on hardware.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…orrectly
The previous commit kept "auto" off MPS for the torchvision backends because
their detection heads diverged there. That turns out to be fixed upstream.
Measured on this machine with yoru/libs/train_torchvision.py, Faster R-CNN,
same dataset, one epoch:
torchvision 0.26.0 mps -> Avg Loss: inf
torchvision 0.29.0 mps -> 0.5047 / 0.4859 / 0.4218 (three runs)
torchvision 0.29.0 cpu -> 0.4883 / 0.4688 / 0.4861 (three runs)
So macOS now takes torchvision 0.29 or newer, and _resolve_device checks the
installed version instead of refusing MPS outright -- the conda environment can
still carry an older build, and that case keeps the CPU fallback and its
message.
Two things had to move to get there:
- override-dependencies = ["torch>=2.0"] replaced torchvision's own
"torch==2.14.0" requirement, so the first attempt locked torchvision 0.29.0
against torch 2.11.0. The override is dropped; nothing needed it.
- setuptools<70 then blocked torch 2.14, which wants >=77.0.3. The real
constraint is pkg_resources, removed in setuptools 81 and still imported by
eel -- which is what YORU.yml already documented -- so the bound is now <81,
matching it. Verified eel still imports.
Windows and Linux are untouched: both still resolve torch 2.6.0+cu124,
torchvision 0.21.0+cu124 and setuptools 69.5.1, byte-identical to 471d274.
macOS moves to torch 2.14.0 / torchvision 0.29.0 / setuptools 80.10.2, which
raises the macOS floor to 14 (Sonoma) since those torch wheels are macosx_14_0.
README updated accordingly.
Verified on macOS 26.5.2, Apple M5 (arm64):
uv sync --locked; pytest 79 passed, 7 skipped
torchvision --device auto -> mps, loss 0.5087 -> 0.3454 over two epochs
ultralytics --device auto -> "Apple MPS", torch 2.14.0, mAP50 0.753 at 3 epochs
inference via load_yolo_model: mps and cpu both return 120 detections
over 60 frames
both smoke tests still exercise real training and inference
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
rysk-t
marked this pull request as draft
September 4, 2026 05:44
The uv route now installs everything a Python environment can hold, so what is left are the pieces it cannot: a Chromium browser for the Eel launcher, an NVIDIA driver for CUDA, and the Xcode Command Line Tools on macOS. None of them were written down, and the uv section did not even say how to install uv. README gains a Prerequisites section covering all three, with what Eel actually looks for on each OS (Edge registers as msedge.exe and is not found; Safari is unsupported), the fact that the PyTorch wheels carry their own CUDA runtime so the toolkit is optional, and the arm64-only wheels and permission prompts that macOS brings. The uv section is promoted out of the conda quick install, gets the uv installation commands, and says to run from the repository root, since the launcher resolves web/ and config/ relatively. docs/install.md is restructured around the same prerequisites with both routes side by side, keeping the existing conda steps. Also records that YORU_DEVICE does not reach YOLOv5 inference, which loads through torch.hub and picks CUDA or CPU on its own. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G3rHpfKzAnmYkxhmvHKwiP
The PyTorch wheels ship the CUDA runtime themselves -- cudart, cuBLAS and cuDNN sit in torch/lib -- so neither route needs the toolkit installed. Verified on the Windows box: no nvcc on PATH and CUDA_PATH unset, yet torch.version.cuda is 12.4 and CUDA matmuls run. The cu118/cu121 choice in the conda steps therefore has to match the driver, not an installed toolkit. Also notes that the CUDA version nvidia-smi prints is the driver's ceiling rather than the version in use, which is the usual source of the confusion. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G3rHpfKzAnmYkxhmvHKwiP
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
uv synconly ever worked on Windows.tool.uv.environmentspinned the lockfile tosys_platform == 'win32', so resolution aborted on macOS and on a Linux CUDA host before a single package was considered — and behind that pin sat five more portability defects, each visible only once the previous one was fixed.Separately, ultralytics resolves an unnamed device CUDA → CPU and never auto-selects MPS. Since YORU had no device plumbing at all, every Apple Silicon user was silently training and inferring on the CPU.
Both are fixed. There is now CI, which would have caught the first one.
Packaging
requires-pythonto>=3.10. dearpygui 1.11.1 ships macOS arm64 wheels for cp310+ only, and 3.9 is EOL.<2. opencv-python 4.10.0.82 is built against the numpy 1.x ABI; on 3.10+ an unbounded numpy resolved to 2.x and brokeimport cv2.pywin32win32-only (it is never imported anywhere in the source), droppyopengl-accelerate(no arm64 wheel, sdist fails to cythonize) and thepyqt5-qt5==5.15.2override (that version has no arm64 wheel).yoru— it could not infer that from the distribution nameyoru_uv, souv syncfailed to build the project on every platform once the lock was regenerated.setuptools<70to<81. The real constraint ispkg_resources, removed in setuptools 81 and still imported by eel, which is whatYORU.ymlalready documented.The committed lock had drifted to a different manifest entirely (root package
yoru/0.1.0,ultralytics==8.2.52), souv sync --lockedfailed everywhere and plainuv syncsilently re-locked — nobody was installing the pinned versions. Regenerated, and CI now guards it.Device selection
New
yoru/libs/device.pyresolves CUDA → MPS → CPU, honours aYORU_DEVICEoverride, and degrades with a logged warning when a device is unavailable. Both training scripts gained--device, the training GUI gained a selector with a resolved-device readout, and the inference wrappers now name the device on every predict call.torchvision's detection heads needed care: before 0.29 they mis-train on MPS. Measured here on Faster R-CNN, same dataset, one epoch:
macOS is therefore pinned to torchvision 0.29+, and
_resolve_devicechecks the installed version rather than refusing MPS outright, since the conda environment can still carry an older build.Also fixed
yoru/testing.pywas a stub that wrote ab"dummy"checkpoint, so both smoke tests passed in 0.19 s and proved nothing. They now drive the realcreate_yaml_train→train_ultralytics→load_yolo_modelround trip.tests/test_cuda.pyhard-assertedtorch.cuda.is_available(), making the suite red on any machine without an NVIDIA GPU. It now skips.yoru/app.py's config-creator launcher usedsubprocess.CREATE_NEW_CONSOLE, which does not exist off Windows, and was the only GUI not going through the portable_launch_guihelper.yoru/libs/detection.pyimported dearpygui but never used it, making the detection module need a GUI toolkit for nothing.torch.has_mps.Documentation
The uv route installs everything a Python environment can hold, so what was left
undocumented were the pieces it cannot install. README gains a Prerequisites
section covering them:
chromemode, so Chrome or Chromium has to be findable (the
App Paths\chrome.exeregistry key on Windows,
Google Chrome.app/Chromium.app/mdfindonmacOS, four binary names on
PATHon Linux). Edge is Chromium-based butregisters as
msedge.exeand is not found; Safari is unsupported by Eel. Onlythe launcher needs it -- every other GUI is a native window.
toolkit is optional; what is required is a driver supporting CUDA 12.x
(527.41+ on Windows, 525.60.13+ on Linux).
xcode-select --installbeforeuv syncbecauseimguiandgeventhave no arm64 wheels and are compiled,and the Camera / Input Monitoring / Screen Recording prompts that appear on
first use.
The uv section is promoted out of the conda quick install, gains the uv
installation commands themselves, and says to run from the repository root,
since the launcher resolves
web/andconfig/relative to the workingdirectory.
docs/install.mdis restructured around the same prerequisites withboth routes side by side, keeping the existing conda steps.
Also recorded:
YORU_DEVICEdoes not reach YOLOv5 inference, which loadsthrough
torch.huband picks CUDA or CPU on its own.Compatibility
Windows and Linux resolve exactly as before — torch 2.6.0+cu124, torchvision 0.21.0+cu124, setuptools 69.5.1. Only the macOS fork moves.
The macOS floor is now 14 (Sonoma, Sept 2023), because torchvision 0.29 requires torch 2.14 whose macOS wheels target
macosx_14_0. Reverting that means giving up MPS training for the torchvision backends; YOLO training on MPS is unaffected either way.Verification
CI is green on ubuntu / windows / macos. On macOS 26.5.2, Apple M5 (arm64), uv 0.11.14:
uv sync --locked→ Python 3.10.19, torch 2.14.0, torchvision 0.29.0, ultralytics 8.3.222, opencv 4.10.0, numpy 1.24.4, dearpygui 1.11.1pytest→ 79 passed, 7 skippedtrain_GUIbuilds,--device auto→Device: Apple MPS; 30 epochs on 400/100 frames oftest_datareached mAP50 0.974 / mAP50-95 0.692load_yolo_modelover the test video: MPS and CPU return identical detectionsThe GitHub runners have no NVIDIA GPU, so a green Windows leg only proves the environment resolves, installs and imports. That gap is now closed on a real Windows box — Windows 11, RTX 4070 SUPER, uv 0.8.19:
uv lock --checkclean,uv sync --locked→ uv-managed CPython 3.10.18, torch 2.6.0+cu124, torchvision 0.21.0+cu124, ultralytics 8.3.229torch.cuda.is_available()→ True;resolve_device("auto")→cudauv run pytest→ 83 passed, 3 skippedtest_data/labeled_frames: training (64 train / 16 val, 1 epoch, CPU) writesbest.ptin 14 s, and inference throughload_yolo_modelconsumes itStill unexercised: the GUI device selector was import-checked only, on both platforms — no interactive run — and no closed-loop hardware (NI-DAQ / Arduino) was attached.