Это исходный отчёт фазы как есть — со всеми таблицами и методикой. Живая версия: 🔍 Поиск по фото.
Фаза 1: ML Immich на NAS (поиск по фото, лица, OCR)
Прогон: 18 октября 2026
Хост: UGREEN DXP4800 Pro, i3-1315U, 32 GB, iGPU Intel RPL-U (Xe-LP, 64 EU)
Что меряли: как быстро и в каком объёме памяти ML-контейнер Immich считает поиск по фото, лица и текст на CPU и на iGPU (OpenVINO), и даёт ли iGPU то же качество.
Коротко
- Модель по умолчанию в Immich (
ViT-B-32__openai) русских запросов не понимает. Recall на русских подписях 1.0 из 100 (уровень случайного угадывания), на английских 61.2. Модель поиска нужно сменить на мультиязычную. - iGPU через OpenVINO в 2.4–7 раз быстрее CPU, качество то же. У
ViT-B-16-SigLIP2recall на русском 85.50 на iGPU и 85.43 на CPU. - Рекомендуемая модель поиска —
ViT-B-16-SigLIP2__webli. На iGPU 24 фото/с (на CPU 5.7), поисковый запрос 21 ms (на CPU 62 ms), до ~2.3 GiB RAM. 50 тыс. фото проиндексируются примерно за 35 минут на iGPU или за 2.5 часа на CPU. - Максимум качества —
ViT-SO400M-16-SigLIP2-256__webli: R@1 на русском 74.2 против 69.7, но 5 фото/с, ~2.8 ч на 50 тыс. фото и до 6.7 GiB. Только с iGPU. - Лица:
buffalo_l(по умолчанию) — 32 фото/с на iGPU и 6.6 на CPU. Работает на обоих устройствах. - Русский текст на фото читает только
ESLAV__PP-OCRv5_mobile: 96% слов против ~18% у остальных моделей. Но в v3.3.3 эта модель не запускается на OpenVINO (HTTP 500), а модель OCR по умолчанию (PP-OCRv5_mobile) кириллицу не читает.
Как мерили
- Образы:
ghcr.io/immich-app/immich-machine-learning:v3.3.3(CPU) и:v3.3.3-openvino(iGPU через/dev/dri). Контейнер запускается отдельно, без самого Immich: клиент обращается к его/predictтак же, как это делает сервер Immich. Архив не подключался. - Данные: Crossmodal-3600 — 3600 фото (медиана 640×480, ~90 KB), у каждого подписи на 36 языках, включая русский. Immich отправляет в ML превью до 1440px, так что на реальной библиотеке декодирование JPEG займёт немного больше.
- Скорость: для каждой модели и каждого устройства:
- отдельный «подготовительный» запуск скачивает модель (для OpenVINO ещё и компилирует её под iGPU);
- затем свежий процесс: первый запрос, 200 фото последовательно, те же 200 фото по 2 параллельных запроса (Immich по умолчанию запускает Smart Search с concurrency 2), 200 русских текстовых запросов.
- Память: пик контейнера по
docker statsраз в 2 с плюс прирост «used» на хосте. Буферы iGPU могут не учитываться в контейнере. - Качество: Immich публикует recall своих моделей (docs), поэтому весь каталог мы не перепроверяли. Контрольный прогон text→image на всех 3600 фото с русскими и английскими подписями проверяет две вещи: что наш замер сходится с таблицей Immich и что iGPU (fp16) не портит качество по сравнению с CPU.
- Ограничения: у каждого контейнера
--memory 20g, запуски идут по одному, остальные сервисы NAS работают как обычно. - Отступление от плана: крупные модели (от SO400M-16-256 и больше) на CPU мерили на 50 фото вместо 200. Задержка там стабильная, а 1–3.7 с на фото и так исключают CPU для библиотеки. Память потом перемерили отдельным коротким проходом (
*_mem), который учитывает RSS (веса через mmap) и буферы iGPU. - Русский OCR: 40 синтетических фото вывесок с известным текстом (
make_ocr_signs.py, оценка —ocr_eval.py). - Воспроизведение:
- на NAS:
run_one.sh(один прогон),run_matrix.sh→run_matrix_rest.sh(матрица),run_memory_pass.sh,run_ocr_eval.sh; - клиенты:
immich_bench.py,ocr_eval.py; - сырые результаты лежат в
raw/, таблицы ниже генерируетpython3 make_report.py.
- на NAS:
CLIP: скорость и память
Фото — медиана последовательного запроса (ms) и пропускная способность при 2 параллельных запросах (фото/с), как у задачи Smart Search в Immich по умолчанию. Текст — медиана одного поискового запроса на русском. «Индекс 50k» — оценка времени на 50,000 фото при этой пропускной способности. Recall — из документации Immich (не наш замер). RAM — пик памяти: максимум из RSS процессов контейнера (видит веса, прочитанные через mmap) и docker stats (видит буферы iGPU).
| Модель | Recall en / ru (Immich) | CPU фото ms | CPU фото/с | iGPU фото ms | iGPU фото/с | Ускорение | Текст ms CPU / iGPU | RAM CPU / iGPU, GiB | Индекс 50k на iGPU |
|---|---|---|---|---|---|---|---|---|---|
ViT-B-32__openai |
69.90 / — | 62.1 | 20.2 | 28.4 | 48.7 | 2.4× | 36.2 / 16.2 | 0.7 / 1.2 | 17 мин |
XLM-Roberta-Base-ViT-B-32__laion5b_s13b_b90k |
76.91 / 76.44 | 62.1 | 20.2 | 28.3 | 48.8 | 2.4× | 72.8 / 22.0 | 1.3 / 1.7 | 17 мин |
ViT-B-32-SigLIP2-256__webli |
82.28 / 78.06 | 77.0 | 15.6 | 27.8 | 50.8 | 3.3× | 62.2 / 19.4 | 1.4 / 2.2 | 16 мин |
ViT-B-16-SigLIP2__webli |
84.86 / 80.91 | 206.6 | 5.7 | 49.5 | 23.9 | 4.2× | 62.2 / 21.4 | 1.0 / 2.3 | 35 мин |
ViT-B-16-SigLIP-i18n-256__webli |
79.78 / 79.35 | 269.2 | 4.2 | 55.4 | 21.1 | 5.0× | 60.4 / 18.1 | 0.8 / 1.8 | 39 мин |
nllb-clip-base-siglip__v1 |
80.16 / 78.91 | 640.3 | 1.8 | 103.1 | 10.7 | 5.9× | 118.2 / 31.3 | 1.2 / 2.9 | 1.3 ч |
ViT-L-16-SigLIP2-256__webli |
85.03 / 83.11 | 899.5 | 1.2 | 153.4 | 6.9 | 5.7× | 206.6 / 46.5 | 2.8 / 4.3 | 2.0 ч |
ViT-SO400M-14-SigLIP2__webli |
85.53 / 83.50 | 1200.3 | 0.9 | 210.8 | 4.9 | 5.4× | 266.7 / 60.9 | 3.8 / 6.3 | 2.8 ч |
ViT-SO400M-16-SigLIP2-256__webli |
85.62 / 83.90 | 1234.0 | 0.9 | 208.8 | 5.0 | 5.3× | 285.2 / 60.9 | 3.8 / 6.7 | 2.8 ч |
ViT-L-16-SigLIP2-384__webli |
85.47 / 83.69 | 2148.9 | 0.5 | 291.9 | 3.5 | 7.0× | 206.6 / 46.5 | 3.0 / 4.9 | 4.0 ч |
nllb-clip-large-siglip__mrl |
83.23 / 83.31 | 3720.0 | 0.3 | 1217.9 | 0.8 | 2.9× | 378.9 / 89.3 | 4.1 / 7.1 | 16.8 ч |
XLM-Roberta-Large-ViT-H-14__frozen_laion5b_s13b_b90k |
82.43 / 82.69 | 1823.2 | 0.6 | 267.2 | 3.7 | 5.8× | 242.1 / 60.5 | 4.4 / 3.8 | 3.8 ч |
ViT-SO400M-16-SigLIP2-384__webli |
85.99 / 84.54 | 2970.6 | 0.4 | 453.2 | 2.2 | 6.1× | 268.5 / 60.9 | 4.3 / 5.9 | 6.2 ч |
CLIP: контрольный recall на Crossmodal-3600 (наш замер)
Text→image по всем 3600 фото; recall = среднее R@1, R@5, R@10. Immich усредняет ещё XTD-10/Flickr30k, поэтому точного совпадения ждать не стоит; важен порядок моделей и совпадение CPU с iGPU.
| Модель | Устройство | ru R@1 / R@5 / R@10 | ru среднее | en среднее | Immich ru / en |
|---|---|---|---|---|---|
ViT-B-32__openai |
iGPU | 0.44 / 1.17 / 1.5 | 1.04 | 61.16 | — / 69.90 |
ViT-B-16-SigLIP2__webli |
CPU | 69.53 / 91.35 / 95.42 | 85.43 | 77.33 | 80.91 / 84.86 |
ViT-B-16-SigLIP2__webli |
iGPU | 69.74 / 91.35 / 95.42 | 85.5 | 77.31 | 80.91 / 84.86 |
ViT-SO400M-16-SigLIP2-256__webli |
iGPU | 74.15 / 92.49 / 96.24 | 87.63 | 76.97 | 83.90 / 85.62 |
Лица
Детекция + эмбеддинг всех найденных лиц за один запрос, minScore 0.7 (по умолчанию в Immich).
| Модель | CPU фото ms | CPU фото/с | iGPU фото ms | iGPU фото/с | RAM CPU / iGPU, GiB | Результат на 200 фото |
|---|---|---|---|---|---|---|
buffalo_s |
28.6 | 52.8 | 12.7 | 109.9 | 0.5 / 0.4 | 45 лиц на 20 фото |
buffalo_m |
71.6 | 17.1 | 19.2 | 64.9 | 0.6 / 1.5 | 58 лиц на 22 фото |
buffalo_l |
155.2 | 6.6 | 34.1 | 32.2 | 0.8 / 1.5 | 69 лиц на 25 фото |
antelopev2 |
156.0 | 5.9 | 34.4 | 29.3 | 0.8 / 1.9 | 69 лиц на 25 фото |
OCR
Детекция + распознавание текста, настройки Immich по умолчанию (maxResolution 736). На фото из Crossmodal-3600 текста мало, поэтому это скорость «типичного» фото, а не скана документа.
| Модель | CPU фото ms | CPU фото/с | iGPU фото ms | iGPU фото/с | RAM CPU / iGPU, GiB | Результат на 200 фото |
|---|---|---|---|---|---|---|
PP-OCRv5_mobile |
76.2 | 16.5 | 29.9 | 44.4 | 0.6 / 2.4 | 84 строк на 32 фото |
ESLAV__PP-OCRv5_mobile |
75.4 | 17.4 | — | — | 0.6 / 0.4 | 84 строк на 32 фото |
PP-OCRv5_server |
938.4 | 1.2 | 320.5 | 3.0 | 1.3 / 5.4 | 200 строк на 42 фото |
PP-OCRv6_small |
93.4 | 12.9 | 54.3 | 25.0 | 0.6 / 2.6 | 119 строк на 47 фото |
OCR: русский текст (синтетические вывески)
40 «фото» вывесок и надписей с известным текстом (make_ocr_signs.py: 7 шрифтов, поворот, размытие, JPEG). Слова — доля слов эталона, найденных в распознанном тексте; CER — по всему тексту. Время — медиана на фото.
| Модель | Слова найдены, % | CER, % | CPU ms | iGPU ms |
|---|---|---|---|---|
PP-OCRv5_mobile |
19.0 | 87.2 | 217 | 56 |
ESLAV__PP-OCRv5_mobile |
96.2 | 4.2 | 186 | не запускается |
PP-OCRv5_server |
18.1 | 89.6 | 2396 | 760 |
PP-OCRv6_small |
18.1 | 91.3 | 247 | 76 |
Выводы и рекомендации
Что видно в цифрах
- Чем больше модель, тем сильнее помогает iGPU. На маленьких ViT-B-32 выигрыш 2.4–3.3×: там заметную долю времени занимают HTTP и декодирование JPEG. На ViT-L/SO400M выигрыш 5–7×. Исключение —
nllb-clip-large-siglip__mrl: даже на iGPU 0.8 фото/с (~17 ч на 50 тыс. фото), его брать не стоит. - Recall на русском у SigLIP2 идёт почти вровень с английским, а на Crossmodal-3600 даже выше. По нашему замеру у
ViT-B-16-SigLIP285.5 на русском против 77.3 на английском. Это свойство самих подписей в датасете (их писали носители каждого языка независимо), а не преимущество русского. Порядок моделей совпадает с таблицей Immich. - Разрыв между B-16 и SO400M на русском — 4.5 пункта R@1 (69.7 → 74.2). На R@10 разрыва почти нет (95.4 → 96.2): нужное фото и так почти всегда попадает в первую десятку, большая модель чаще ставит его первым.
- Поисковый запрос (текстовый энкодер) быстрый у всех моделей, 16–90 ms на iGPU и 36–380 ms на CPU, то есть поиск в интерфейсе будет мгновенным. Дорого стоит только индексация новых фото.
- OCR:
PP-OCRv5_mobile,PP-OCRv5_serverиPP-OCRv6_smallна кириллице выдают в основном цифры и латиницу (~18% слов).ESLAV__PP-OCRv5_mobileчитает русский почти без ошибок (CER 4.2%). На OpenVINO его модель распознавания не конвертируется (ошибка вывода размерностей в Concat/Conv,raw/openvino_ocr_ESLAV__PP-OCRv5_mobile_speed.prep.log). Похожего открытого issue в Immich не нашлось.
Как настроить Immich
Вариант A — CPU-образ, всё работает (для старта рекомендую его):
immich-machine-learning:release(CPU);- поиск —
ViT-B-16-SigLIP2__webli, лица —buffalo_l, OCR —ESLAV__PP-OCRv5_mobile; - первичная индексация 50 тыс. фото ≈ 2.5 ч (поиск) + 2.1 ч (лица) + ~0.8 ч (OCR), за одну ночь; дальше новые фото считаются по мере загрузки;
- поиск — 62 ms на запрос, RAM ≈ 1 + 0.8 + 0.6 GiB, пока модели загружены.
Вариант B — iGPU, быстрее и с более сильной моделью поиска:
- образ
immich-machine-learning:release-openvino,/dev/driпроброшен в контейнер; - поиск —
ViT-B-16-SigLIP2__webli(~35 мин на 50 тыс.) илиViT-SO400M-16-SigLIP2-256__webli(~2.8 ч, лучше на русском); - для русского OCR — обходной путь: второй ML-контейнер на CPU и в настройках Immich список URL
[openvino, cpu]. По коду сервера (machine-learning.repository.ts) при HTTP 500 Immich помечает URL нездоровым и повторяет запрос на следующем, так что OCR уйдёт на CPU. Это вывод из чтения кода, вживую не проверено. Побочный эффект: пока идёт OCR-задача, часть запросов поиска и лиц тоже может уходить на CPU, до следующей проверки доступности.
В любом варианте:
- сменить модель поиска с ViT-B-32__openai до первой индексации;
- держать MACHINE_LEARNING_MODEL_TTL по умолчанию (модели выгружаются через 5 минут простоя), тогда память занята только во время индексации.
Ограничения
- Фото в тесте мельче реальных. В Crossmodal-3600 медиана 640×480, а Immich отправляет превью до 1440px. Декодирование JPEG на реальных фото добавит единицы миллисекунд; на больших моделях это незаметно, на ViT-B-32 разница будет видна.
- Recall мерили на чужом датасете, а не на вашем архиве. Семейные фото, старые сканы и подписи вида «бабушка на даче» — другой домен. Порядок моделей, скорее всего, сохранится, абсолютные цифры — нет.
- Память — оценка сверху по опросу раз в 2 с. Буферы iGPU учитываются через cgroup приблизительно.
- Лица проверены только по скорости. Качество кластеризации (насколько верно Immich группирует одного человека) этот тест не меряет.