Грабли CV-поиска потерянных животных в проекте «Найди друга»
Как мы строили similarity search для потерянных животных: почему ушли от классификации, зачем учили модель на метках и окрасе и где ошибаются push-совпадения.

«А если собаку найдут грязной и похудевшей — ваша модель скажет, что это другая собака?»
Этот вопрос хорошо описал задачу в проекте «Найди друга». Пользователь загружает фото потерянного или найденного питомца, система превращает изображение в вектор и ищет похожие анкеты через cosine similarity и ANN. Дальше — push-уведомление, если совпадение попадает в заданный радиус.
Звучит аккуратно, пока не начинаешь смотреть на реальные фото. Один и тот же пёс на домашнем снимке, после недели на улице и под дождём — это три разных визуальных объекта для наивной модели. Ниже — грабли, на которые легко наступить в такой задаче.
Грабля 1. Учить модель как классификатор пород
Первая понятная мысль: определить породу, окрас, размер, потом искать среди похожих. Для каталога пород это нормально. Для поиска конкретного животного — плохо.
Потерянная собака редко приходит в систему как «лабрадор, жёлтый, без особенностей». У неё может быть белое пятно на груди, надорванное ухо, асимметричная маска на морде. У кошки — полосы на лапах, форма пятна у носа, редкий окрас. Именно эти детали часто важнее породы.
Поэтому мы не делали задачу классификации. Модель должна была не отвечать «кто это по классу», а раскладывать фотографии в векторное пространство так, чтобы похожие животные оказывались рядом. Запрос выглядит так:
- фото животного;
- эмбеддинг изображения;
- поиск ближайших соседей через cosine similarity / ANN;
- проверка совпадений с учётом географии.
Такой подход лучше ложится на реальность: в базе могут быть метисы, животные без точной породы, разные ракурсы и фотографии с телефона. Класс «похожая дворняга» нам не нужен. Нужны ближайшие визуальные кандидаты.
Грабля 2. Считать чистое фото эталоном
Самое неприятное в датасете — он должен быть похож на жизнь, а не на выставку животных. Потерянный питомец может похудеть, испачкаться, попасть в кадр вечером, стоять боком, частично закрыться травой или поводком.
Если учить модель только на аккуратных фотографиях, она начинает переоценивать состояние шерсти, освещение и ракурс. Для человека это шум: «да, пёс грязный, но пятно на морде то же». Для модели без подготовки грязь легко становится новым признаком.
Мы собирали обучение вокруг специфичных признаков: породы, окрасы, уникальные метки. Отдельно учитывали трансформации, которые случаются с животным после пропажи: вес, грязь, изменение внешнего вида. Цель была не сделать красивое сравнение двух одинаковых снимков, а не потерять совпадение, когда фото «до» и «после» выглядят как из разных историй.
Живая деталь: в обсуждениях больше всего спорили не про ANN, а про то, что считать устойчивым признаком. Окрас — вроде да. Но мокрая тёмная шерсть внезапно ломает уверенность. Метка на морде — сильнее. Форма пятна — ещё сильнее, если её видно.
Грабля 3. Отправлять push по любому похожему фото
Similarity search даёт кандидатов, но не гарантирует, что перед нами тот самый питомец. Особенно если район плотный, пользователей много, а похожих животных в базе достаточно.
В проекте было 50 000+ пользователей, и уведомления нельзя было превращать в шум. Если пуш приходит слишком часто, человек перестаёт на него реагировать. Если фильтр слишком жёсткий — можно пропустить нужное совпадение.
Поэтому совпадение завязали не только на визуальную близость, но и на радиус. Модель ищет похожие анкеты, дальше система проверяет географию и уже после этого отправляет push. ANN здесь нужен для скорости поиска по векторам, cosine similarity — для ранжирования похожести, радиус — для отсечения визуально похожих, но бессмысленных с точки зрения поиска вариантов.
Компромисс получился инженерный: не пытаться угадать владельца одним скором. Сначала быстро сузить кандидатов по картинке, потом отфильтровать по месту, затем показать человеку совпадение. Именно этот путь дал сотни воссоединённых питомцев, а не красивую демку с двумя совпадающими фотографиями.
Следующий слой, который в таких системах хочется проверять отдельно, — как меняется качество пушей при росте базы и плотности объявлений в одном районе.