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

Setup Guide

Prerequisites

  • Immich v1.106+ with face recognition enabled and people tagged
  • Frigate v0.16+ (face mode only)
  • 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. Only needed for face mode — omit it entirely if you're using object mode.


3. Choose an image tag

Tag Arch Acceleration
:latest amd64 + arm64 NVIDIA CUDA 12.8 (amd64) · 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 · ~2 GB 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.


4. Deploy with Docker Compose

Copy compose.yml and .env.example to a directory on your host:

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:

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 crops should be stored:

volumes:
  - /your/path/to/models:/models
  - /your/path/to/cache:/app/.if_cache
  - /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 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.


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 models) stays resident between runs, so each subsequent run starts immediately without re-loading models.


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:13.3.0-base-ubuntu22.04 nvidia-smi

AMD (ROCm)

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

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:

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 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.


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; omit for object mode only

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.)
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 0 Skip people with fewer than N tagged assets in Immich
YEARS_FILTER 10 Ignore images older than N years

Image Quality

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

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)
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

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) 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

Scheduling

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

Clone this wiki locally