Как стать автором
Обновить
36.52
Профи.ру
Быстрый поиск специалистов

Как мы подключили ML-модель, чтобы находить дизайны для маникюра, а она стала предлагать стрижки как у Мухаммеда Али

Уровень сложностиПростой
Время на прочтение5 мин
Количество просмотров625

История о том, как мы с командой сделали умный подбор картинок, а в процессе затестили русскоязычную модель RuCLIP и обсудили маникюр.

Привет! Это Олег Гасилин, SEO-специалист, и Саша Хуртин, разработчик. Мы работаем в Профи.ру и эту историю рассказали специально для блога компании.

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

Так вот, чтобы попадать в выдачу по максимальному количеству запросов, нужно искать все возможные пересечения с желаниями людей и с тем, как они их формулируют. Например, выдавать фотографии по запросу, когда люди ищут идеи для маникюра или ремонта. 

На Профи.ру — море снимков работ специалистов. И если они будут выпадать в поисковиках, то клиенты смогут находить и вдохновение, и мастеров. Для специалистов это шанс получить новых заказчиков, поэтому мы решили привлекать людей картинками.

Подключили ИИ, а он начал работать без смысла

Чтобы привлекать трафик картинками, начали собирать отдельные страницы с фотографиями по услугам. Например, по маникюру в базе Профи.ру много изображений с ноготочками. На первом этапе мы сделали всё максимально просто: подгружали случайные картинки по теме из базы. Вроде бы логично.

Но это только звучит хорошо, а в реальности — не норм. Пользователи, которые заходят за «вдохновением», не гуглят просто «маникюр». В запросах всегда есть нюансы: «бархатный маникюр», «маникюр френч», «маникюр в семь перпендикулярных линий в форме котёнка». И на все эти запросы сайт «Профи.ру» выдавал случайные фотографии, которые в точные потребности людей не попадали. 

Результат первой попытки: трафик вырос, а потом резко упал. Показатель отказов достиг 60%, и поисковики начали понижать страницы с фотками в выдаче. Стало ясно: случайные картинки не отвечают ожиданиям пользователей. 

Нужно показывать изображения, которые точно попадают в запросы. Но как это сделать? В базе Профи.ру — десятки миллионов картинок. Вручную отбирать их на страницы очень трудозатратно.

Мы вспомнили: когда специалисты загружают снимки, они иногда добавляют короткое текстовое пояснение. Например, подтягивают фотографию зелёных ногтей и пишут: «Ногти зелёные, десять штук, с золотой стрекозой». Возникла идея использовать эти описания для подбора картинок на страницы: сначала делать это вручную, затем масштабировать процесс, загружая описания в нейросеть, и в перспективе полностью автоматизировать подбор через API. Идея казалась перспективной, но выяснилось, что только у 30% фото есть хоть какие-то пояснения. Этого мало.

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

Результат второй попытки: модель начала честно генерировать описания — «красный френч», «матовый дизайн с блёстками». Страницы стали показывать действительно релевантные картинки. Время пользователей на странице выросло в два раза, а показатель отказов упал в три раза. 

Но был нюанс: GPT ошибался. На фото мог быть подарочный сертификат с иконкой руки, а модель уверенно писала: «Маникюр». Так бы дело с 20 тысячами картинок из базы не пошло.

Стало понятно, что решение не подходит. С одной стороны, GPT не всегда точно генерировал описания. С другой стороны, мы подбирали картинки по этим описаниям с помощью SEO-подхода, то есть искали по ключевым словам, как это делаем для текстов. Такой способ отлично работает с поисковиками: они тоже ориентируются на ключи. Но для изображений этого недостаточно: здесь важна именно смысловая релевантность, а не просто совпадение слов.

Подключили ML-модель

Чтобы решить задачу, мы пришли к векторизации. Не буду тут сильно погружаться, пройдусь по верхам. Представьте, что у каждого изображения и у каждого текста (например, названия услуги) есть своё уникальное «числовое лицо» — вектор фиксированной длины, обычно из 512 или 1 024 координат. Такой вектор создаётся при помощи нейросетей и ML-моделей, способных на входе принять данные — изображение, текст, видео — и на выходе выдать их эмбеддинг в виде набора чисел в N-мерном пространстве.

С этим вектором можно производить математические операции. Нас интересует косинусное сравнение, то есть вычисление того, насколько вектора сонаправленны. Если мы берём картинку и текст и их векторы «смотрят» в одном направлении — значит, картинка и текст описывают одно и то же. Так удобно сравнивать изображения с названиями услуг и находить смысловые соответствия, то есть сопоставлять не только по словам.

Для всей этой истории нужно было выбрать технологию и ML-модельку. Возникло три варианта выбора:

  • Между TypeScript или Python. На TypeScript у нас много компетенций, но Python лучше подходит для этих целей.

  • Между предобученной и нетренированной моделью. Обучать дорого, поэтому в приоритете была первая.

  • Между модельками, которые сравнивают данные, тексты и тексты с картинками. В идеале — сделать так, чтобы информацию не нужно было бы приводить к одному формату.

В итоге остановились на TypeScript и предобученной модели из семейства CLIP, которая умеет работать и с текстом, и с изображениями в одном векторном пространстве.

Затем пришла очередь выбирать конкретную модель семейства CLIP. Я сравнил две версии: англоязычную модельку Xenova/clip-vit-base-patch16, которая работает с картинками и английским языком, и русскоязычную модельку ai-forever/ruclip-vit-base-patch32-384, которая работает с картинками и русским языком. С Xenova всё было очень хорошо. На TypeScript она отлично работала через специальную библиотеку Transformer.js.

С русскоязычной моделью всё было не так гладко. RuClip нельзя запустить напрямую на TypeScript, и она не работает с библиотекой Transformer.js, поэтому пришлось конвертировать её в универсальный формат ONNX и пытаться запустить с помощью библиотеки onnxruntime-node. 

К сожалению, из-за особенностей архитектуры модели заставить её корректно работать на TypeScript так и не удалось. Поэтому в итоге остановились на модельке Xenova. 

И вот как всё это работает в продакшене:

  1. Считаем векторы картинок. Из базы файлов берём изображения, загоняем в модельку, с помощью визуальной части модели считаем вектор и сохраняем его в базу PostgreSQL с расширением pg_vector. Он позволяет работать с векторами, с индексами векторов и всем прочим.

  2. Берём названия услуг, переводим их на английский и, если нужно, немного адаптируем, чтобы они точнее описывали, какой визуал мы хотим подобрать для каждой услуги. Также загоняем в модельку Xenova, используем её текстовую часть. 

  3. Считаем вектор этого названия услуги и ищем в базе PostgreSQL векторы картинок, которые наиболее сонаправлены с нашим вектором. Поиск оптимизирован с помощью полноценного графового индекса hnsw. В итоге получаем подборку релевантных изображений к каждой услуге и сохраняем.

  4. Когда пользователь заходит на страницу, наш фронт сразу подгружает готовую выборку.

Результат третьей попытки очевиден. Что было до: случайные картинки на страницах, не всегда по теме. Что стало после векторизации: на страницах чётко то, что нужно. «Красный маникюр» действительно красный маникюр. Мы даже просили коллег-девушек оценить галереи. Они подтверждали: «Да, релевантность есть».

Были и забавные случаи, например «стрижка бокс». Модель иногда подставляла фото боксёров, включая Мухаммеда Али. Такое поведение — следствие того, что модель обучалась на открытых датасетах, где «бокс» — это и спорт, и стрижка. Мы доработали фильтры.

Сейчас продолжаем добавлять новые услуги, расширяем количество страниц. Модель работает на CPU, и обработка всех картинок (а их 20 миллионов) занимает много времени. Планируем перенести всё на GPU, тогда этот процесс сократится до пары дней.

А как бы вы решили задачу? Ждём ваши варианты в комментариях.

Теги:
Хабы:
-1
Комментарии1

Публикации

Информация

Сайт
profi.ru
Дата регистрации
Дата основания
2005
Численность
201–500 человек
Местоположение
Россия