Update wiki: ROCm/Intel setup, correct log path, versioned tags, object mode
+9
-5
@@ -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.
|
||||
|
||||
+1
-1
@@ -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.
|
||||
|
||||
|
||||
+57
-12
@@ -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
|
||||
```
|
||||
|
||||
+56
-11
@@ -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"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user