Skip to content
Holden Salomon edited this page Jun 14, 2026 · 11 revisions

Setup Guide

Prerequisites

  • Immich v1.106+ with face recognition enabled and people tagged
  • Frigate v0.16+
  • Docker with the appropriate GPU runtime (optional but strongly recommended)

1. Get your Immich API key

  1. Open Immich → Account SettingsAPI Keys
  2. Click New API Key, give it a name (e.g. winnow), copy the key

2. Get your Frigate URL

This is the base URL of your Frigate instance, e.g. http://192.168.1.10:5000.


3. Choose an image tag

Tag Arch Acceleration
:latest amd64 NVIDIA CUDA 12.8 · requires NVIDIA Container Toolkit · 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 · ~300 MB smaller · no GPU required

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 to a directory on your host:

mkdir winnow && cd winnow
curl -O https://raw.githubusercontent.com/sudolulo/winnow/main/compose.yml

Create a .env file with your values:

IMMICH_URL=http://192.168.1.10:2283
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 should be stored:

volumes:
  - /your/path/to/models:/models
  - /your/path/to/data:/app/data
  - /your/path/to/output:/app/frigate_train

These directories will be created automatically by Docker if they don't exist.

Start it:

docker compose up -d

Logs:

docker compose logs -f winnow

5. First run

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.


6. Scheduling

CRON_SCHEDULE controls both the run schedule and container lifetime:

CRON_SCHEDULE Behaviour
(unset) Run once on startup, then exit
(empty string) Stay alive; trigger manually with docker exec -it winnow winnow
Cron expression Run on startup, then repeat on schedule

Example — every Sunday at 3 AM:

CRON_SCHEDULE=0 3 * * 0

In scheduled mode the process (and loaded model) stays resident between runs, so each subsequent run starts immediately without re-loading the model.


GPU passthrough

NVIDIA

Include the deploy block in your compose.yml (present in the example) and ensure the NVIDIA Container Toolkit is installed on your host:

deploy:
  resources:
    reservations:
      devices:
        - driver: nvidia
          count: all
          capabilities: [gpu]

Verify GPU access:

docker run --rm --gpus all nvidia/cuda:12.8.1-base-ubuntu22.04 nvidia-smi

AMD (ROCm)

Use image: ghcr.io/sudoludo/winnow:rocm and replace the deploy: block with:

devices:
  - /dev/kfd
  - /dev/dri
group_add:
  - video
  - render

Intel Arc / iGPU

Use image: ghcr.io/sudoludo/winnow:intel and replace the deploy: block with:

devices:
  - /dev/dri
group_add:
  - render
environment:
  - OPENVINO_DEVICE=GPU   # omit to run OpenVINO inference on CPU (default)

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 (optimised AVX512 kernels). This is not the iGPU — it runs on the CPU itself but is meaningfully faster than standard CPUExecutionProvider.

Debugging

Set VERBOSE=true in your .env to enable DEBUG-level output on the console. The log file always captures DEBUG regardless of this setting:

# log file is written to the output volume (frigate_train mount)
docker exec winnow cat /app/frigate_train/winnow.log

Environment Variables

Connection

Variable Default Description
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

Mode & Strategy

Variable Default Description
STRATEGY adaptive adaptive — embedding-based diversity selection, stops when candidates become redundant; standard — fixed 30 images; broad — fixed 100 images. auto is a legacy alias for adaptive
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)

People Filtering

Variable Default Description
ONLY_PEOPLE (unset) Comma-separated whitelist — process only these people
SKIP_PEOPLE (unset) Comma-separated list — skip these people
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

GPU & Models

Variable Default Description
FORCE_CPU false Disable GPU — fall back to CPU for all inference
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)
DATA_DIR data Path for embedding cache and upload tracker database (winnow_tracker.db)
INSIGHTFACE_HOME (system) InsightFace model cache path (Buffalo_L)

Output

Variable Default Description
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)

Variable Default Description
DRY_RUN false Preview selection without downloading or uploading
RETRY_REJECTED false Re-attempt assets previously rejected by Frigate
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

Variable Default Description
CRON_SCHEDULE (unset) Unset = run once and exit; empty string = stay alive; cron expression = scheduled

Clone this wiki locally