Перейти к содержанию
Публикация AiManual

EmbeddingGemma 2 для поиска текста на скриншотах: эксперимент с 3003 изображениями

Разбор эксперимента: EmbeddingGemma 2 (330 МБ в Q8, 768 dim) проиндексировала 3003 скриншота за 510 секунд на RX 7900GRE через llama.cpp. Что показали косинусны

Коротко

Что будет в материале

  1. 01

    Что проверяли и что получилось: короткий ответ

  2. 02

    Как устроен пайплайн: от скриншотов до векторной БД

  3. 03

    Скорость и железо: сколько занимает индексация на RX 7900GRE

  4. 04

    Как формулировать запросы: почему текст побеждает визуальные признаки

Что проверяли и что получилось: короткий ответ

EmbeddingGemma 2 в квантовании Q8 занимает около 330 МБ и выдаёт эмбеддинги размерности 768. Этого достаточно для семантического поиска текста внутри изображений: автор эксперимента проиндексировал 3003 скриншота и получил работающую систему поиска по смыслу запроса. Его собственная оценка: для такого размера и такой размерности модель вполне пригодна.

Замеры: 3003 файла ушли в базу за 510,10 секунды, скорость 5,887 изображения в секунду при батче 8. Модель работала через llama.cpp на видеокарте RX 7900GRE с бэкендом Vulkan, векторы складывались в локальную векторную БД. Полный отчёт с логами и примерами запросов опубликован в r/LocalLLaMA.

Ограничения всплыли сразу. Текст в запросе перевешивает визуальные признаки, формулировки приходится подбирать вручную (blond и blonde модель различает), а сами тесты автор называет ненаучными: один набор данных, 3003 скриншота одной сюжетной линии. Цифры ниже читайте как предварительные ориентиры, а не как бенчмарк.

Как устроен пайплайн: от скриншотов до векторной БД

Цепочка короткая: скриншот попадает в модель, модель отдаёт вектор, вектор ложится в базу, поиск считает косинусную близость между вектором запроса и векторами картинок. Вся обработка шла локально, без облачных API и внешних сервисов.

Роль llama.cpp и локальной векторной БД

llama.cpp в этой схеме работает рантаймом: он загружает EmbeddingGemma 2, принимает изображения и возвращает числовые представления. Векторная БД хранит результат и отвечает за сравнение векторов. В логах видно открытие базы с 3003 записями, что совпадает с размером набора.

Конкретную СУБД автор не называет, так что заменить её можно на любую с поддержкой косинусной близости. Два технических условия из источника: контекст ограничен 4096 токенами, а все эмбеддинги должны иметь одинаковую размерность, иначе сравнивать их бессмысленно.

EmbeddingGemma 2 строит эмбеддинги изображений целиком, но в эксперименте искали именно текст внутри картинки, а не визуальную сцену. Это важное различие: если вам нужно находить «фото, где человек стоит у окна», логика запросов и ожидания от качества будут другими.

Что именно индексировали: 3003 скриншота визуальной новеллы

Набор собрали из скриншотов визуальной новеллы Hanasaki Work Spring, одна сюжетная линия, 3003 изображения. Ещё 3078 скриншотов Irotoridori no Hikari уже лежали в базе, но в этот замер не входили.

Датасет перекошен: примерно 90% изображений содержат блондинку. Для поиска по визуальным признакам это плохая новость. Признак, который присутствует почти везде, ничего не различает, и любой запрос про внешность будет выдавать примерно весь архив.

Скорость и железо: сколько занимает индексация на RX 7900GRE

Индексация 3003 новых и изменённых файлов заняла 510,10 секунды при батче 8 и прогрессе 376/376 за 08:30. Итоговая скорость: 5,887 изображения в секунду. Замер сделан на одной карте RX 7900GRE через Vulkan, и это единственный прогон, а не серия.

Сам файл модели весит около 330 МБ, поэтому узкое место здесь не объём видеопамяти. Веса влезают в любую карту с несколькими гигабайтами VRAM, а время уходит на подготовку изображений и батчевую обработку.

Почему Vulkan, а не ROCm

Автор выбрал Vulkan по бытовой причине: собирать llama.cpp под ROCm ему показалось утомительным, и он прямо написал об этом в комментарии к посту. Данных о том, быстрее ROCm или медленнее на этой задаче, в источнике нет, поэтому делать выводы о разнице бэкендов не на чем.

Практический вывод скромный: Vulkan остаётся рабочим путём для запуска llama.cpp на AMD, если не хочется возиться со сборкой. Это выбор одного пользователя на одной карте. Если строите локальный сервер на AMD и хотите посмотреть, как выглядят другие сборки на этом железе, полезен отдельный разбор запуска DeepSeek-V4-Flash на двух Radeon AI PRO R9700, там видны типичные ограничения и подводные камни стека.

Как оценить время индексации для своего набора

Арифметика простая: время в секундах примерно равно числу изображений, делённому на 5,9. Прикидка для разных объёмов на том же железе:

ИзображенийОжидаемое время
1 000около 170 с (3 минуты)
10 000около 1 700 с (28 минут)
100 000около 17 000 с (4,7 часа)

Это линейная экстраполяция с одного замера. На другой карте, другом бэкенде и другом размере батча цифры сдвинутся, иногда заметно. Для первой оценки порядка величины методика годится, для планирования SLA нет.

Как формулировать запросы: почему текст побеждает визуальные признаки

Главный вывод эксперимента: текстовые признаки в запросе весят больше визуальных. В логах это видно на числах косинусной близости. Запрос «image with blonde girl» дал 0.68208 (прирост +0.00250), а «image with blonde girl making >< expression» дал 0.70416 (+0.00340). Рядом в том же прогоне запрос с диалогом без описания внешности («삼각건이 머리에 얹어졌다») показал 0.75960, то есть выше, чем вариант с визуальным уточнением.

Автор формулирует это так: текст доминирует над визуальными чертами, и иногда добавление визуального признака вредит близости. Причину он не установил. Две гипотезы из источника: текст информационно плотнее, либо сказывается ограниченность маленькой модели.

Пример с «blond» и «blonde»: почему формулировка важна

Модель требует аккуратных формулировок. Разница между blond и blonde для неё значима, как минимум для английского и корейского. Автор связывает чувствительность с ограничениями малой языковой модели или размерности эмбеддингов, точного ответа у него нет.

Что делать на практике: перебирать формы слова и не считать один неудачный запрос приговором всей системе. Одна морфологическая вариация может дать разницу в близости, сопоставимую с разницей между хорошим и плохим запросом.

Когда визуальные признаки помогают, а когда вредят

В тестовом наборе около 90% кадров содержат блондинку, поэтому описание внешности почти не различает результаты. Добавляйте визуальные уточнения, только если признак действительно редок в вашем архиве: цвет волос, униформа или конкретный предмет на фоне сработают там, где таких изображений единицы.

Второй эффект сильнее. Наличие конкретного слова в изображении перебивает остальной текст запроса. Слово «삼각건» встречается всего в 2 изображениях из 3003, и близость по нему: 0.69251 для запроса из одного слова, 0.72881 для «삼각건» плюс «머리», 0.71156 для полного предложения. Наращивание контекста не даёт монотонного роста: два слова лучше одного, полное предложение хуже двух слов. Ищите по словам, которые реально присутствуют на картинке, тогда лишние слова меньше размывают результат.

Кросс-языковой поиск: английский и корейский на одном изображении

Для изображения 38.jpg корейский запрос «삼각건이 머리에 얹어졌다» дал косинусную близость 0.71156 (+0.00810). Английский перевод «triangular cloth hat was place on top of head» на том же изображении дал 0.62414 (+0.00015). Разрыв почти в 0.09, и он стабильно не в пользу перевода.

Смысл между языками модель переносит частично, но с заметной потерей точности. Автор связывает просадку с размером модели. Для поиска по корейскому контенту корейский запрос остаётся основным инструментом, английский годится как вспомогательный.

Что это значит для мультиязычных архивов

Если контент на языке A, запрос на языке A даёт более высокую близость, чем перевод на язык B. Вывод не в том, что модель «понимает» язык, а в том, что перенос смысла работает с потерями. Для смешанных архивов разумно хранить запросы на языке источника или дублировать формулировки на двух языках и объединять выдачу.

Ограничения эксперимента: почему выводы предварительные

Автор прямо предупреждает: тесты не научные, проведены на нескольких наборах, а конкретный замер сделан на 3003 скриншотах одной сюжетной линии Hanasaki Work Spring. Эту оговорку он приводит в самом посте, и её нельзя выкидывать при чтении цифр.

  • Метрика одна: косинусная близость на нескольких запросах. Precision и recall по размеченной выборке не считались.
  • Значения вроде 0.71156 и 0.62414 — единичные замеры на одном изображении, а не статистика по корпусу.
  • Около 90% набора содержат блондинку, что обнуляет пользу визуальных признаков и мешает переносить выводы на разнородные архивы.
  • Причина доминирования текста над визуальными чертами не установлена, есть только две гипотезы.
  • Стек узкий: Vulkan вместо ROCm, контекст 4096 токенов, требование одинаковой размерности эмбеддингов.

На ваш кейс переносится порядок величин по скорости и общая логика «текст в запросе важнее описания сцены». Точные значения близости переносить бессмысленно.

Кому подходит EmbeddingGemma 2 и что выбрать вместо неё

Плюсы понятны: 330 МБ в Q8, размерность 768, индексация тысяч изображений за минуты на потребительской карте, полностью локальная схема. Минусы тоже конкретны: ограниченная точность на визуальных запросах, слабый перенос между языками, чувствительность к формулировке.

Модель подойдёт для локального поиска по тексту на скриншотах, для архивов с явными текстовыми подписями и для быстрого прототипа, который нужно собрать без серьёзных затрат по железу. Не стоит рассчитывать на неё там, где нужен поиск по внешности или сцене, и там, где требуется высокая точность на мультиязычных данных.

Когда проще OCR плюс текстовый поиск

Если цель — найти текст на скриншоте, связка OCR с обычным текстовым поиском даст более предсказуемый результат: вы получаете явные строки, которые можно проверять глазами, и не зависите от того, как модель сжала картинку в 768 чисел. Мультимодальные эмбеддинги выигрывают, когда важен и текст, и визуальный контекст одновременно.

Критерий выбора простой: посмотрите, что несёт смысл в ваших изображениях. Если 90% информации в тексте, начинайте с OCR. Сравнение OCR-моделей с замерами CER и WER, включая TrOCR и PaddleOCR, есть в отдельном разборе по запуску OCR в браузере.

Чек-лист перед запуском на своём наборе

  1. Оцените долю повторяющихся визуальных признаков. Если один типаж встречается в большинстве кадров, визуальные уточнения в запросе работать не будут.
  2. Проверьте, есть ли в изображениях текст, по которому вообще имеет смысл искать.
  3. Прикиньте время индексации по формуле «число изображений / 5,9» и добавьте запас на другое железо.
  4. Готовьте запросы на языке контента, английский держите как второй вариант.
  5. Заложите перебор формулировок: blond и blonde, синонимы, другая длина фразы.
  6. Считайте метрики на своей размеченной выборке, а не доверяйте одному красивому значению близости.

Стартовать стоит с небольшого среза своего архива: пара сотен изображений, десяток запросов, ручная проверка топ-5 выдачи. Если попадания есть, масштабируйте индексацию. Если нет, дешевле сразу развернуться в сторону OCR или более крупной мультимодальной модели эмбеддингов, чем чинить запросы к модели на 330 МБ.

Подписаться на канал