From 82244e09ae35565ab2298611d71f5f251c90f442 Mon Sep 17 00:00:00 2001 From: Holden Salomon Date: Sat, 13 Jun 2026 06:39:15 +0000 Subject: [PATCH] Update wiki: ROCm/Intel setup, correct log path, versioned tags, object mode --- FAQ.md | 14 ++++++---- Home.md | 2 +- Setup.md | 69 ++++++++++++++++++++++++++++++++++++++-------- Troubleshooting.md | 67 ++++++++++++++++++++++++++++++++++++-------- 4 files changed, 123 insertions(+), 29 deletions(-) diff --git a/FAQ.md b/FAQ.md index 588ea95..0e1cc88 100644 --- a/FAQ.md +++ b/FAQ.md @@ -10,6 +10,8 @@ No. winnow only reads from Immich (assets, people, face bounding boxes). It neve The `auto` strategy decides this for you — it keeps selecting until adding more images would be redundant. In practice this is usually 20–60 per person. You can cap it with `MAX_AUTO_IMAGES` (default 80). +When winnow reaches the cap on subsequent runs, `QUALITY_REPLACEMENT=true` (default) lets it swap out the lowest-scoring existing image if a better candidate is found — so the training set improves over time rather than stalling. Only images winnow uploaded are ever replaced; anything added manually through Frigate's UI is never touched. + Quality and diversity matter far more than volume. 30 well-spread images outperform 200 from the same week. --- @@ -29,7 +31,7 @@ Yes — in object mode, `FRIGATE_URL` is not used and crops are saved to the out ## How does auto-diversity mode work? -winnow computes a vector embedding for each candidate image (what the face/object actually looks like — angle, lighting, expression). It then clusters those embeddings and picks representatives that are maximally spread across the embedding space. It stops when the next-most-different image is already close to something already selected. See the README for the full pipeline. +winnow computes a vector embedding for each candidate image (what the face/object actually looks like — angle, lighting, expression). It then clusters those embeddings and picks representatives that are maximally spread across the embedding space. It stops when the next-most-different image is already close to something already selected. See the README pipeline for the full breakdown. --- @@ -41,11 +43,13 @@ Yes. By default it processes every named person in your Immich library. Use `ONL ## What GPU is needed? -Any NVIDIA GPU with CUDA 12.x support. The models (InsightFace Buffalo_L + SigLIP) fit comfortably in 4 GB VRAM. CPU mode works but is significantly slower — typically tens of seconds per person instead of under a second on GPU. +Any NVIDIA GPU with CUDA 12.x support works with `:latest`. AMD ROCm GPUs work with `:rocm`. Intel Arc and integrated GPUs work with `:intel`. The models (InsightFace Buffalo_L + SigLIP) fit comfortably in 4 GB VRAM. -**CPU memory:** If running without a GPU, set a container memory limit of at least **2 GB** (`mem_limit: 2g`). The models use roughly 1–1.5 GB and thumbnails are processed in bounded batches, so usage stays flat even for large libraries. Without a limit a large person library can trigger an OOM kill and restart loop. +CPU mode works but is significantly slower — typically tens of seconds per person instead of under a second on GPU. -ARM builds (linux/arm64) use CPU-only — CUDA is not available on ARM. +**CPU memory:** Set a container memory limit of at least **2 GB** (`mem_limit: 2g`). The models use roughly 1–1.5 GB and thumbnails are processed in bounded batches of 32, so usage stays flat regardless of library size. + +ARM builds (linux/arm64) are CPU-only — GPU variants are amd64 only. --- @@ -62,4 +66,4 @@ docker compose pull docker compose up -d ``` -The `latest` and `cpu` tags on GHCR track the `main` branch. Pinning to a specific version is recommended for stability, but winnow doesn't publish versioned image tags — `latest` / `cpu` are the stable release tags, and `dev` / `dev-cpu` are pre-release. +The `latest`, `cpu`, `rocm`, and `intel` tags on GHCR always point to the latest release. Versioned tags (e.g. `ghcr.io/sudolulo/winnow:v0.2.13`) are also published for each release and are useful for pinning to a known-good version. diff --git a/Home.md b/Home.md index e6c18b5..295ceca 100644 --- a/Home.md +++ b/Home.md @@ -1,6 +1,6 @@ # winnow -winnow pulls photos from [Immich](https://immich.app), selects diverse high-quality subsets using AI embeddings, and uploads them as face recognition training data to [Frigate](https://frigate.video). +winnow pulls photos from [Immich](https://immich.app), selects diverse high-quality subsets using AI embeddings, and delivers them as training data for [Frigate](https://frigate.video). It supports face recognition training (aligned crops uploaded directly to Frigate's API) and object classification training (YOLO-detected crops saved to disk). It runs fully headless in Docker, is configured entirely through environment variables, and can run on a schedule. diff --git a/Setup.md b/Setup.md index 21330f4..eff973d 100644 --- a/Setup.md +++ b/Setup.md @@ -4,7 +4,7 @@ - [Immich](https://immich.app) v1.106+ with face recognition enabled and people tagged - [Frigate](https://frigate.video) v0.16+ (face mode only) -- Docker with the NVIDIA container toolkit (optional but strongly recommended) +- Docker with the appropriate GPU runtime (optional but strongly recommended) --- @@ -23,16 +23,20 @@ This is the base URL of your Frigate instance, e.g. `http://192.168.1.10:5000`. ## 3. Choose an image tag -| Tag | Arch | GPU | Notes | -| :-- | :-- | :-- | :-- | -| `:latest` | amd64 + arm64 | CUDA 13.3 (amd64) | Requires NVIDIA Container Toolkit on amd64 | -| `:cpu` | amd64 | None | ~2 GB smaller; use if you have no NVIDIA GPU | +| Tag | Arch | Acceleration | +| :-- | :-- | :-- | +| `:latest` | amd64 + arm64 | NVIDIA CUDA 13.3 (amd64) · requires [NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html) | +| `:rocm` | amd64 | AMD ROCm · pass `/dev/kfd` + `/dev/dri` | +| `:intel` | amd64 | Intel Arc / iGPU via OpenVINO · pass `/dev/dri`, set `OPENVINO_DEVICE=GPU` | +| `:cpu` | amd64 + arm64 | CPU only · ~2 GB smaller · no GPU required | -Use `:cpu` if your host has no NVIDIA GPU — it skips the entire CUDA stack and runs InsightFace on CPU. **Set a container memory limit of at least 2 GB** (`mem_limit: 2g`) — the embedding models need roughly 1–1.5 GB and thumbnails are batched, but without a limit an OOM kill will restart the container mid-run. +Use `:cpu` if your host has no supported GPU — it skips the entire GPU stack. **Set a container memory limit of at least 2 GB** (`mem_limit: 2g`) — the embedding models need roughly 1–1.5 GB. + +--- ## 4. Deploy with Docker Compose -Copy [`compose.yml`](../compose.yml) and [`.env.example`](../.env.example) to a directory on your host: +Copy [`compose.yml`](https://github.com/sudolulo/winnow/blob/main/compose.yml) and [`.env.example`](https://github.com/sudolulo/winnow/blob/main/.env.example) to a directory on your host: ```bash mkdir winnow && cd winnow @@ -102,19 +106,60 @@ In scheduled mode the process (and loaded models) stays resident between runs, s ## GPU passthrough -To enable GPU acceleration, include the `deploy` block in `compose.yml` (already present in the example) and ensure the NVIDIA container toolkit is installed on your host: +### NVIDIA +Include the `deploy` block in your `compose.yml` (present in the example) and ensure the [NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html) is installed on your host: + +```yaml +deploy: + resources: + reservations: + devices: + - driver: nvidia + count: all + capabilities: [gpu] +``` + +Verify GPU access: ```bash -# Verify GPU is accessible to Docker docker run --rm --gpus all nvidia/cuda:13.3.0-base-ubuntu22.04 nvidia-smi ``` -CPU mode works without any GPU setup — set `FORCE_CPU=true` to disable GPU explicitly, or use the `:cpu` image tag which omits the CUDA base entirely (~2 GB smaller). +### AMD (ROCm) + +Use `image: ghcr.io/sudolulo/winnow:rocm` and replace the `deploy:` block with: + +```yaml +devices: + - /dev/kfd + - /dev/dri +group_add: + - video + - render +``` + +### Intel Arc / iGPU + +Use `image: ghcr.io/sudolulo/winnow:intel` and replace the `deploy:` block with: + +```yaml +devices: + - /dev/dri +group_add: + - render +environment: + - OPENVINO_DEVICE=GPU # omit to run OpenVINO inference on CPU (default) +``` + +Set `OPENVINO_DEVICE=GPU` to target the Intel GPU. Omitting it (or setting `CPU`) runs OpenVINO on CPU — useful if you want Intel's optimised runtime without GPU passthrough. + +--- ## Debugging -Set `VERBOSE=true` in your `.env` to enable DEBUG-level output on the console. The log file (`/app/winnow.log`) always captures DEBUG regardless of this setting — useful when diagnosing issues without a shell into the container: +Set `VERBOSE=true` in your `.env` to enable DEBUG-level output on the console. The log file always captures DEBUG regardless of this setting: ```bash -docker exec winnow cat /app/winnow.log +# log file is written to the output volume (frigate_train mount) +docker exec winnow cat /app/frigate_train/winnow.log ``` diff --git a/Troubleshooting.md b/Troubleshooting.md index dd90e2e..e5e1002 100644 --- a/Troubleshooting.md +++ b/Troubleshooting.md @@ -23,10 +23,10 @@ Your API key has been revoked or expired. Generate a new one in Immich → **Acc Set `VERBOSE=true` in `.env` (or pass `-e VERBOSE=true`) to enable DEBUG-level output on the console. Useful for tracing exactly which images are being fetched, filtered, and selected. -The log file at `/app/winnow.log` always captures DEBUG regardless of `VERBOSE`: +The log file always captures DEBUG regardless of `VERBOSE`. It is written to the output volume: ```bash -docker exec winnow cat /app/winnow.log +docker exec winnow cat /app/frigate_train/winnow.log ``` --- @@ -59,23 +59,23 @@ winnow downloads InsightFace and HuggingFace (SigLIP) models on first run. ## Running on CPU (no GPU) -Use the `:cpu` image tag (`ghcr.io/sudolulo/winnow:cpu`) which omits the CUDA base entirely. Or set `FORCE_CPU=true` with `:latest` to disable GPU at runtime. +Use the `:cpu` image tag (`ghcr.io/sudolulo/winnow:cpu`) which omits the GPU base entirely. Or set `FORCE_CPU=true` with any other tag to disable GPU at runtime. Everything works on CPU but embedding computation is slower — typically tens of seconds per person instead of under a second on GPU. -**Memory:** CPU mode requires more host RAM than GPU mode. Set a minimum container memory limit of **2 GB** (`mem_limit: 2g` in compose). If you have a large library — hundreds of images per person — allow more. Thumbnails are processed in bounded batches of 32 so peak RAM stays flat regardless of library size, but the embedding models themselves use roughly 1–1.5 GB. +**Memory:** Set a minimum container memory limit of **2 GB** (`mem_limit: 2g`). If you have a large library — hundreds of images per person — allow more. --- -## GPU not being used / "No GPU execution provider found" +## GPU not being used -If you have a GPU and the container is running but winnow reports no GPU provider: +### NVIDIA -1. **Confirm the GPU device is visible** inside the container: +1. **Confirm the GPU is visible** inside the container: ```bash docker exec winnow nvidia-smi ``` - If this fails, the container doesn't have GPU access — check the `deploy.resources.reservations.devices` block in `compose.yml` and that the NVIDIA container toolkit is installed on the host. + If this fails, the container doesn't have GPU access — check the `deploy.resources.reservations.devices` block in `compose.yml` and that the NVIDIA Container Toolkit is installed on the host. 2. **Check which ONNX providers are available**: ```bash @@ -83,14 +83,59 @@ If you have a GPU and the container is running but winnow reports no GPU provide "import onnxruntime as ort; ort.preload_dlls(cuda=True, cudnn=True); print(ort.get_available_providers())" ``` Expected (GPU working): `['CUDAExecutionProvider', 'CPUExecutionProvider', ...]` - GPU not working: `['AzureExecutionProvider', 'CPUExecutionProvider']` — only CPU providers listed. + GPU not working: only `['CPUExecutionProvider']` listed. -3. **If only CPU providers appear even though `nvidia-smi` works**, you may be running an image older than 0.2.11. A packaging bug in 0.2.10 caused the CPU `onnxruntime` package to silently overwrite `onnxruntime-gpu`, removing GPU support without any error. Update to `:latest` to fix it: +3. **If only CPU providers appear even though `nvidia-smi` works**, you may be running an image older than 0.2.11 — a packaging bug caused `onnxruntime-gpu` to be silently overwritten. Update to fix it: ```bash docker compose pull && docker compose up -d ``` -4. **Set `VERBOSE=true`** and check startup logs — winnow logs `ONNX providers available: [...]` at DEBUG level on every start. +### AMD (ROCm) + +1. **Confirm devices are passed through** — your `compose.yml` should have: + ```yaml + devices: + - /dev/kfd + - /dev/dri + group_add: + - video + - render + ``` + +2. **Verify ROCm sees the GPU**: + ```bash + docker exec winnow /app/.venv/bin/python3 -c "import torch; print(torch.cuda.is_available(), torch.cuda.get_device_name(0))" + ``` + ROCm exposes itself as CUDA in PyTorch — `True` here means ROCm is working. + +### Intel Arc / iGPU + +1. **Confirm the DRI device is passed through**: + ```yaml + devices: + - /dev/dri + group_add: + - render + ``` + +2. **Ensure `OPENVINO_DEVICE=GPU` is set** — without it, OpenVINO defaults to CPU even with device passthrough. + +3. **Verify OpenVINO sees the device**: + ```bash + docker exec winnow /app/.venv/bin/python3 -c \ + "from openvino.runtime import Core; print(Core().available_devices)" + ``` + Expected: `['CPU', 'GPU']`. If only `['CPU']` appears, the Level Zero / OpenCL runtime can't see the device — check group membership and device permissions. + +--- + +## Set `VERBOSE=true` and check startup logs + +winnow logs `ONNX providers available: [...]` and the selected execution provider at DEBUG level on every start. Enable verbose mode and inspect the log: + +```bash +docker exec winnow cat /app/frigate_train/winnow.log | grep -i "provider\|execution\|cuda\|rocm\|openvino" +``` ---