docs: full wiki update for v0.4.10 — remove object mode, sync defaults, add duplicate people docs

2026-06-14 17:57:31 +00:00
parent d09569f4d0
commit 80892477fb
5 changed files with 94 additions and 98 deletions
+14 -41
@@ -1,6 +1,6 @@
# Benchmarks
Inference latency and throughput for winnow's two embedding models, measured on real hardware. Run with the `scripts/benchmark.py` script (included in the repo).
Inference latency and throughput for InsightFace Buffalo_L, measured on real hardware. Run with `scripts/benchmark.py` (included in the repo).
---
@@ -8,7 +8,6 @@ Inference latency and throughput for winnow's two embedding models, measured on
| | |
| :-- | :-- |
| **CPU** | AMD / Intel (see per-run notes) |
| **GPU** | NVIDIA GeForce RTX 2070 SUPER |
| **Driver** | 570.172.08 |
| **Container CUDA** | 12.8.1 |
@@ -16,9 +15,9 @@ Inference latency and throughput for winnow's two embedding models, measured on
---
## InsightFace Buffalo_L — face mode
## InsightFace Buffalo_L
Detection (RetinaFace det_10g) + ArcFace embedding (w600k_r50) on a 640×640 image. This is the pipeline winnow runs for every face crop it evaluates.
Detection (RetinaFace det_10g) + ArcFace embedding (w600k_r50) on a 640×640 image. This is the pipeline winnow runs for every face crop it evaluates during diversity selection and for crop alignment during upload.
### RTX 2070 SUPER
@@ -27,61 +26,35 @@ Detection (RetinaFace det_10g) + ArcFace embedding (w600k_r50) on a 640×640 ima
| GPU (`FORCE_CPU=false`) | 2.5 s | 12.8 ms | 78.3 img/s |
| CPU (`FORCE_CPU=true`) | 4.3 s | 102 ms | 9.8 img/s |
**GPU is 8× faster than CPU** for InsightFace (12.8 ms vs 102 ms median).
### Notes
- Latency measured over 30 runs after 5 warmup iterations.
- Input: 640×640 synthetic image. The detection network processes the full input regardless of whether faces are found; timing is representative of real-world single-image throughput.
- 320×320 input: CPU 101 ms, GPU 13.4 ms — detection runtime is dominated by fixed model overhead, not image size at these resolutions.
- GPU is **8× faster** than CPU for InsightFace (12.8 ms vs 102 ms).
- 320×320 input: CPU 101 ms, GPU 13.4 ms — runtime is dominated by fixed model overhead, not image size at these resolutions.
---
## SigLIP ViT-B/16 — object mode
## Practical impact
`google/siglip-base-patch16-224` — 224×224 Vision Transformer used for object-mode diversity selection. Supports batched inference; GPU benefit scales with batch size.
For a diversity pool of 500 candidates (typical for a well-tagged person):
### RTX 2070 SUPER
| Mode | Embedding phase | Notes |
| :-- | --: | :-- |
| GPU | ~6 s | 500 images × 12.8 ms |
| CPU | ~51 s | 500 images × 102 ms |
#### GPU (`FORCE_CPU=false`)
| Batch | ms/batch | ms/img | img/s | p95/img |
| --: | --: | --: | --: | --: |
| 1 | 13.1 | 13.13 | 76.1 | 14.2 |
| 4 | 24.4 | 6.10 | 163.9 | 6.2 |
| 8 | 45.4 | 5.67 | 176.3 | 5.7 |
| 16 | 87.7 | 5.48 | 182.4 | 5.5 |
| 32 | 171.5 | 5.36 | 186.6 | 5.4 |
#### CPU (`FORCE_CPU=true`)
| Batch | ms/batch | ms/img | img/s | p95/img |
| --: | --: | --: | --: | --: |
| 1 | 216 | 216 | 4.6 | 243 |
| 4 | 757 | 189 | 5.3 | 192 |
| 8 | 1450 | 181 | 5.5 | 202 |
| 16 | 2846 | 178 | 5.6 | 188 |
| 32 | 5683 | 178 | 5.6 | 188 |
Model load: **16.1 s** (CPU; first load, no cache)
CPU batching saturates quickly — throughput barely improves past batch 4 (~5.5 img/s ceiling). GPU shows 33× speedup at batch 32 (186 img/s vs 5.6 img/s).
For large libraries with 3000-candidate pools (the internal cap), GPU reduces the diversity phase from ~5 min to ~38 s.
---
## Running the benchmark
```bash
# Inside the container — GPU mode:
# Inside a running container — GPU mode:
docker exec winnow python /app/scripts/benchmark.py
# CPU-only mode:
docker exec -e FORCE_CPU=true winnow python /app/scripts/benchmark.py
# Or directly with docker run:
docker run --rm --gpus all \
--entrypoint /app/.venv/bin/python \
-v /your/models:/insightface \
-e INSIGHTFACE_HOME=/insightface \
ghcr.io/sudolulo/winnow:latest \
/app/scripts/benchmark.py
```
+18 -15
@@ -2,13 +2,15 @@
## Does winnow modify my Immich library?
No. winnow only reads from Immich (assets, people, face bounding boxes). It never writes back to Immich or deletes anything.
No — with one exception. winnow only reads from Immich (assets, people, face bounding boxes). It never writes back to Immich or deletes anything, unless you set `MERGE_DUPLICATE_PEOPLE=true`, which permanently merges duplicate person records inside Immich. That setting is `false` by default.
---
## How many images should I upload to Frigate?
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`).
The `auto` strategy decides this for you — it keeps selecting until adding more images would be redundant. In practice this is usually 10–40 per person. You can cap it with `MAX_AUTO_IMAGES` (default `20`).
The default is intentionally conservative. The goal is for winnow to **supplement** a training set that should be primarily built from manually-curated images — photos you took specifically for recognition, in controlled conditions, uploaded directly through Frigate's UI. winnow is for the people you can't do that for: faces in your library you want Frigate to recognise but don't have dedicated training photos for.
When winnow reaches the cap on subsequent runs, `QUALITY_REPLACEMENT=true` (default) lets it improve the training set rather than stalling:
@@ -21,22 +23,15 @@ Quality and diversity matter far more than volume. 30 well-spread images outperf
---
## What's the difference between face mode and object mode?
- **Face mode**: Extracts and aligns face crops, uploads them directly to Frigate's face training API. This is for teaching Frigate to recognize specific people.
- **Object mode**: Runs YOLO detection on full images and saves crops of a target class (dog, cat, car, etc.) to disk. Frigate has no API for object training data, so you place them manually.
---
## Can I run it without Frigate?
Yes — in object mode, `FRIGATE_URL` is not used and crops are saved to the output volume. In face mode you need Frigate to receive the uploads, but you can use `DRY_RUN=true` to preview selection without uploading.
You can use `DRY_RUN=true` to preview selection without uploading. But winnow's purpose is uploading to Frigate — without `FRIGATE_URL` set, it will select images and skip the upload step.
---
## 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 pipeline for the full breakdown.
winnow computes a 512-dim ArcFace embedding for each candidate image (what the face actually looks like — angle, lighting, expression). It then clusters those embeddings with K-Medoids and picks representatives that are maximally spread across the embedding space using Farthest Point Sampling. It stops when the next-most-different image is already close enough to something already selected. See the README pipeline for the full breakdown.
---
@@ -46,13 +41,21 @@ Yes. By default it processes every named person in your Immich library. Use `ONL
---
## Immich shows two entries for the same person — will winnow process them both?
By default winnow warns about duplicates (same name on multiple person records), keeps only the one with the most assets, and skips the rest. This is safe but means winnow only sees part of that person's photo pool.
Set `MERGE_DUPLICATE_PEOPLE=true` to permanently merge duplicate groups inside Immich before processing — the person with the most assets absorbs the others. **This modifies Immich and cannot be undone.** Only enable it after you've verified the duplicates are actually the same person.
---
## What GPU is needed?
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.
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`. InsightFace Buffalo_L fits comfortably in 2 GB VRAM.
CPU mode works but is significantly slower — typically tens of seconds per person instead of under a second on GPU.
CPU mode works but is significantly slower — about 8–10× vs GPU for InsightFace (see [[Benchmarks]]). For large libraries or frequent scheduled runs, a GPU makes a noticeable difference.
**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.
**CPU memory:** Set a container memory limit of at least **2 GB** (`mem_limit: 2g`). The model uses roughly 600 MB–1 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.
@@ -71,4 +74,4 @@ docker compose pull
docker compose up -d
```
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.
The `latest`, `cpu`, `rocm`, and `intel` tags on GHCR always point to the latest release. Versioned tags (e.g. `ghcr.io/sudolulo/winnow:v0.4.10`) are also published for each release and are useful for pinning to a known-good version.
+3 -4
@@ -1,15 +1,15 @@
# winnow
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).
winnow pulls photos from [Immich](https://immich.app), selects diverse high-quality subsets using AI embeddings (InsightFace Buffalo_L / ArcFace), and delivers them as training data for [Frigate](https://frigate.video)'s face recognition.
It runs fully headless in Docker, is configured entirely through environment variables, and can run on a schedule.
The goal is to fill the gap where you don't have manually-curated training photos. winnow mines your existing Immich library for the most diverse spread of real-world appearances and keeps the Frigate training set fresh as your library grows.
> **winnow only touches files it uploaded.** Faces added to Frigate manually through its UI are never deleted, replaced, or modified — not by quality replacement, not by `RESET_PERSON`, not by stale cleanup. If you have a curated training set, it is safe.
## Pages
- [[Setup]] — installation, Docker Compose configuration, GPU passthrough, environment variables
- [[Benchmarks]] — GPU vs CPU inference latency and throughput (InsightFace, SigLIP)
- [[Benchmarks]] — GPU vs CPU inference latency and throughput (InsightFace)
- [[Troubleshooting]] — common failures and fixes
- [[FAQ]] — frequently asked questions
@@ -18,4 +18,3 @@ It runs fully headless in Docker, is configured entirely through environment var
- [GitHub Repository](https://github.com/sudolulo/winnow)
- [CHANGELOG](https://github.com/sudolulo/winnow/blob/main/CHANGELOG.md)
- [compose.yml](https://github.com/sudolulo/winnow/blob/main/compose.yml)
- [.env.example](https://github.com/sudolulo/winnow/blob/main/.env.example)
+30 -28
@@ -3,7 +3,7 @@
## Prerequisites
- [Immich](https://immich.app) v1.106+ with face recognition enabled and people tagged
- [Frigate](https://frigate.video) v0.16+ (face mode only)
- [Frigate](https://frigate.video) v0.16+
- Docker with the appropriate GPU runtime (optional but strongly recommended)
---
@@ -17,7 +17,7 @@
## 2. Get your Frigate URL
This is the base URL of your Frigate instance, e.g. `http://192.168.1.10:5000`. Only needed for face mode — omit it entirely if you're using object mode.
This is the base URL of your Frigate instance, e.g. `http://192.168.1.10:5000`.
---
@@ -28,24 +28,22 @@ This is the base URL of your Frigate instance, e.g. `http://192.168.1.10:5000`.
| `:latest` | amd64 | NVIDIA CUDA 12.8 · requires [NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html) · minimum driver 570 |
| `: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 |
| `:cpu` | amd64 + arm64 | CPU only · ~300 MB smaller · no GPU required |
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.
Use `:cpu` if your host has no supported GPU. **Set a container memory limit of at least 2 GB** (`mem_limit: 2g`) — the InsightFace model needs roughly 600 MB–1 GB.
---
## 4. Deploy with Docker Compose
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:
Copy [`compose.yml`](https://github.com/sudolulo/winnow/blob/main/compose.yml) to a directory on your host:
```bash
mkdir winnow && cd winnow
curl -O https://raw.githubusercontent.com/sudolulo/winnow/main/compose.yml
curl -O https://raw.githubusercontent.com/sudolulo/winnow/main/.env.example
cp .env.example .env
```
Edit `.env` with your values:
Create a `.env` file with your values:
```bash
IMMICH_URL=http://192.168.1.10:2283
@@ -53,7 +51,7 @@ API_KEY=your-immich-api-key
FRIGATE_URL=http://192.168.1.10:5000
```
Edit the volume paths in `compose.yml` to point to directories on your host where models, cache, and output crops should be stored:
Edit the volume paths in `compose.yml` to point to directories on your host where models, cache, and output should be stored:
```yaml
volumes:
@@ -80,7 +78,7 @@ docker compose logs -f winnow
## 5. First run
On the first run, winnow downloads the embedding models (~1–2 GB) from HuggingFace and InsightFace. This happens once — subsequent runs use the cached models from your mounted volume and start immediately.
On the first run, winnow downloads InsightFace Buffalo_L (~300 MB) if it isn't already cached in the models volume. Subsequent runs start immediately using the cached model.
---
@@ -100,7 +98,7 @@ Example — every Sunday at 3 AM:
CRON_SCHEDULE=0 3 * * 0
```
In scheduled mode the process (and loaded models) stays resident between runs, so each subsequent run starts immediately without re-loading models.
In scheduled mode the process (and loaded model) stays resident between runs, so each subsequent run starts immediately without re-loading the model.
---
@@ -127,7 +125,7 @@ docker run --rm --gpus all nvidia/cuda:12.8.1-base-ubuntu22.04 nvidia-smi
### AMD (ROCm)
Use `image: ghcr.io/sudolulo/winnow:rocm` and replace the `deploy:` block with:
Use `image: ghcr.io/sudoludo/winnow:rocm` and replace the `deploy:` block with:
```yaml
devices:
@@ -140,7 +138,7 @@ group_add:
### Intel Arc / iGPU
Use `image: ghcr.io/sudolulo/winnow:intel` and replace the `deploy:` block with:
Use `image: ghcr.io/sudoludo/winnow:intel` and replace the `deploy:` block with:
```yaml
devices:
@@ -153,9 +151,7 @@ environment:
`OPENVINO_DEVICE` selects the compute device within the OpenVINO runtime:
- `GPU` — Intel iGPU or Arc GPU (requires `/dev/dri` passthrough)
- `CPU` *(default)* — CPU cores, via OpenVINO's CPU plugin which uses AVX512 and multi-threading. This is *not* the iGPU — it runs on the CPU itself, but OpenVINO's optimised kernels are meaningfully faster than standard CPUExecutionProvider.
Use `CPU` if you want OpenVINO's faster CPU path without passing through the GPU device.
- `CPU` *(default)* — CPU cores via OpenVINO's CPU plugin (optimised AVX512 kernels). This is *not* the iGPU — it runs on the CPU itself but is meaningfully faster than standard CPUExecutionProvider.
---
@@ -178,16 +174,14 @@ docker exec winnow cat /app/frigate_train/winnow.log
| :--- | :--- | :--- |
| `IMMICH_URL` | *(required)* | Full URL to your Immich instance |
| `API_KEY` | *(required)* | Immich API key |
| `FRIGATE_URL` | *(unset)* | Frigate base URL — required for face upload; omit for object mode only |
| `FRIGATE_URL` | *(unset)* | Frigate base URL — required for face upload |
### Mode & Strategy
| Variable | Default | Description |
| :--- | :--- | :--- |
| `TRAINING_MODE` | `face` | `face` — upload crops to Frigate; `object` — save crops to disk |
| `STRATEGY` | `auto` | `auto` (embedding-based adaptive), `standard` (30 images), `broad` (100 images) |
| `LIMIT` | *(unset)* | Exact image count — overrides `STRATEGY` |
| `OBJECT_CLASS` | `dog` | Target class for object mode (any YOLO class: `dog`, `cat`, `car`, etc.) |
| `LIMIT` | *(unset)* | Exact image count — overrides `STRATEGY` preset |
| `AUTO_MODE` | *(auto)* | Force non-interactive mode in a terminal; auto-detected otherwise |
| `VERBOSE` | `false` | Enable DEBUG-level console output (log file is always DEBUG) |
@@ -197,23 +191,31 @@ docker exec winnow cat /app/frigate_train/winnow.log
| :--- | :--- | :--- |
| `ONLY_PEOPLE` | *(unset)* | Comma-separated whitelist — process only these people |
| `SKIP_PEOPLE` | *(unset)* | Comma-separated list — skip these people |
| `MIN_FACE_COUNT` | `0` | Skip people with fewer than N tagged assets in Immich |
| `MIN_FACE_COUNT` | `3` | Skip people with fewer than N tagged assets in Immich |
| `YEARS_FILTER` | `10` | Ignore images older than N years |
| `MERGE_DUPLICATE_PEOPLE` | `false` | When Immich has multiple person records with the same name (a common side-effect of face clustering), winnow warns and processes only the largest. Set `true` to permanently merge duplicates in Immich instead. **This modifies Immich and cannot be undone** — only enable once you've verified the duplicates are the same person. |
### Image Quality
| Variable | Default | Description |
| :--- | :--- | :--- |
| `MAX_AUTO_IMAGES` | `20` | Maximum training images per person winnow will manage in Frigate. Conservative default so winnow supplements — not dominates — a training set that should be primarily built from manually curated images |
| `QUALITY_REPLACEMENT` | `true` | When at cap, swap a weaker tracked image for a better candidate. With Frigate scoring active, targets the most redundant image (highest pre-upload recognize score); otherwise uses blur score. Never touches manually added Frigate files. Set `false` to skip people at cap |
#### Advanced Tuning *(calibrated — do not adjust)*
The following variables control quality thresholds that are pre-calibrated for Frigate's ArcFace requirements. Changing them may cause image quality issues. **Support will not be provided for problems caused by non-default values.**
| Variable | Default | Description |
| :--- | :--- | :--- |
| `ENABLE_FRIGATE_SCORES` | `true` | Call Frigate's recognize endpoint pre-upload to store diversity scores used for quality replacement. Adds ~200 ms per upload. Disable to use blur-score replacement only |
| `FRIGATE_SCORE_CEILING` | *(unset)* | Below-cap novelty gate. Unset (default): dynamic — skips candidates whose Frigate score exceeds the most-redundant tracked file's score, accounting for manually-added images. `0`: disabled. Positive value (e.g. `0.85`): fixed hard ceiling. Requires `ENABLE_FRIGATE_SCORES=true` and at least one prior run |
| `MIN_FACE_WIDTH` | `90` | Minimum face crop width in pixels |
| `FACE_MARGIN` | `0.15` | Padding around bounding box crop (fraction of face size) |
| `ENABLE_FACE_ALIGNMENT` | `true` | Align to ArcFace 112×112 format using facial landmarks |
| `USE_FULL_RESOLUTION` | `true` | Download full-resolution originals rather than preview thumbnails |
| `MIN_CONFIDENCE` | `0.7` | Minimum Immich face detection confidence |
| `BLUR_THRESHOLD` | `120.0` | Laplacian variance threshold — higher rejects more blur |
| `MAX_AUTO_IMAGES` | `80` | Maximum training images per person in Frigate |
| `QUALITY_REPLACEMENT` | `true` | When at cap, swap a weaker tracked image for a better candidate. With Frigate scoring active, targets the most redundant image (highest recognize score); otherwise uses blur score. Never touches manually added Frigate files. Set `false` to skip people at cap |
| `FRIGATE_SCORE_CEILING` | `0.0` | Skip uploads whose pre-upload Frigate recognize score exceeds this value — they are already well-covered. `0` disables; requires at least one prior run to have scores |
| `ENABLE_FRIGATE_SCORES` | `true` | Call Frigate's recognize endpoint pre-upload to store diversity scores used for quality replacement. Adds ~200 ms per upload. Disable to use blur-score replacement only |
### GPU & Models
@@ -223,14 +225,13 @@ docker exec winnow cat /app/frigate_train/winnow.log
| `OPENVINO_DEVICE` | `CPU` | Intel variant only: `GPU` = iGPU/Arc (requires `/dev/dri`); `CPU` = OpenVINO CPU plugin (optimised CPU kernels, not the iGPU) |
| `ENABLE_CACHE` | `true` | Cache computed embeddings to disk (speeds up re-runs on the same library) |
| `CACHE_DIR` | `.if_cache` | Path for embedding cache and upload tracker files |
| `HF_HOME` | *(system)* | HuggingFace model cache path (SigLIP) |
| `INSIGHTFACE_HOME` | *(system)* | InsightFace model cache path (Buffalo_L) |
### Output
| Variable | Default | Description |
| :--- | :--- | :--- |
| `OUTPUT_DIR` | `./frigate_train` | Directory for object-mode crops and the `winnow.log` file. In Docker, set this via the volume mount instead |
| `OUTPUT_DIR` | `./frigate_train` | Directory where face crops are staged before upload and where `winnow.log` is written. In Docker, set this via the volume mount instead |
### Tracker Overrides *(one-shot — remove after use)*
@@ -238,7 +239,8 @@ docker exec winnow cat /app/frigate_train/winnow.log
| :--- | :--- | :--- |
| `DRY_RUN` | `false` | Preview selection without downloading or uploading |
| `RETRY_REJECTED` | `false` | Re-attempt assets previously rejected by Frigate |
| `RESET_PERSON` | *(unset)* | Clear upload history for one person and delete their winnow-managed Frigate training files so the next run starts fresh. Manually added Frigate files are never touched |
| `RESET_PERSON` | *(unset)* | Set to a person's name to clear their upload history and delete their winnow-managed Frigate training files so the next run starts fresh. Set to `*` to reset all tracked people at once. Manually added Frigate files are never touched |
| `TRACE_CROP_SIZE` | *(unset)* | Debug: print all tracked crops whose width or height matches this pixel value, then exit |
### Scheduling
+29 -10
@@ -35,7 +35,7 @@ docker exec winnow cat /app/frigate_train/winnow.log
- Make sure Immich has completed face recognition and you have named people in your library
- `YEARS_FILTER` defaults to 10 years — increase it if your tagged photos are older
- `MIN_FACE_COUNT` skips people with few photos — lower or remove it
- `MIN_FACE_COUNT` (default `3`) skips people with few photos — lower or remove it
---
@@ -47,12 +47,12 @@ docker exec winnow cat /app/frigate_train/winnow.log
---
## Models fail to download
## Model fails to download
winnow downloads InsightFace and HuggingFace (SigLIP) models on first run.
winnow downloads InsightFace Buffalo_L (~300 MB) on first run if it isn't already cached.
- Ensure the container has internet access
- Confirm the model volume is mounted and writable
- Confirm the models volume is mounted and writable (`/models` inside the container)
- If behind a proxy, set `HTTP_PROXY` / `HTTPS_PROXY` env vars
---
@@ -61,9 +61,9 @@ winnow downloads InsightFace and HuggingFace (SigLIP) models on first run.
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.
Everything works on CPU but embedding computation is slower — about 8–10× vs GPU for InsightFace (see [[Benchmarks]]).
**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.
**Memory:** Set a minimum container memory limit of **2 GB** (`mem_limit: 2g`).
---
@@ -85,7 +85,7 @@ Everything works on CPU but embedding computation is slower — typically tens o
Expected (GPU working): `['CUDAExecutionProvider', 'CPUExecutionProvider', ...]`
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 caused `onnxruntime-gpu` to be silently overwritten. Update to fix it:
3. **If only CPU providers appear even though `nvidia-smi` works**, you may be running an older image with a packaging bug. Update:
```bash
docker compose pull && docker compose up -d
```
@@ -104,9 +104,10 @@ Everything works on CPU but embedding computation is slower — typically tens o
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))"
docker exec winnow /app/.venv/bin/python3 -c \
"import onnxruntime as ort; print(ort.get_available_providers())"
```
ROCm exposes itself as CUDA in PyTorch — `True` here means ROCm is working.
Expected: `['ROCmExecutionProvider', 'CPUExecutionProvider']`
### Intel Arc / iGPU
@@ -129,7 +130,7 @@ Everything works on CPU but embedding computation is slower — typically tens o
---
## Set `VERBOSE=true` and check startup logs
## Check startup logs for provider selection
winnow logs `ONNX providers available: [...]` and the selected execution provider at DEBUG level on every start. Enable verbose mode and inspect the log:
@@ -159,8 +160,26 @@ Remove this after one run. It deletes winnow-managed Frigate training files for
---
## Duplicate person warning at startup
If winnow prints a warning like:
```
⚠ Duplicate person names detected in Immich:
John → 2 people: abc12345… (47 assets), def67890… (12 assets)
Processing largest only (47 assets). Skipping 1 smaller duplicate(s)...
```
Immich has created separate person records for the same individual (a common side-effect of its face clustering). By default winnow processes only the largest and skips the rest.
To permanently merge them inside Immich, set `MERGE_DUPLICATE_PEOPLE=true` for one run. The person with the most assets absorbs the others. **This modifies Immich and cannot be undone** — only do this after verifying the duplicates are the same person.
---
## Image quality issues
The quality thresholds are pre-calibrated for Frigate's ArcFace requirements. **Support will not be provided for problems caused by non-default values.** That said, if you understand the tradeoffs:
- **Selected images are too blurry**: Raise `BLUR_THRESHOLD` (default `120.0`) — e.g. `200` requires sharper images
- **Too many images rejected for blur**: Lower `BLUR_THRESHOLD` — e.g. `80` accepts blurrier images
- **Too many images rejected for small face size**: Lower `MIN_FACE_WIDTH` (default `90`) — e.g. `50` accepts smaller face crops