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

Визуально они кажутся похожими, но изображенные на них предметы совершенно не связаны между собой. Этот контраст демонстрирует как возможности, так и присущие поиску по изображениям недостатки.
Все изображения, использованные в этой статье, взяты из нашей внутренней базы данных, которую мы используем для экспериментов и тестирования.
Один из вариантов использования поиска по изображениям — обнаружение дубликатов товаров. Хотя заголовки и описания товаров, безусловно, могут использоваться для поиска дубликатов, в некоторых объявлениях названия товаров немного (или даже полностью) отличаются, но используются одни и те же изображения. Выявление таких объявлений также очень важно.
Поскольку платформы электронной коммерции обычно предлагают миллионы товаров, нам необходимы эффективные инструменты и методы для выполнения любого типа поиска в больших масштабах.
В этой статье я покажу, как создать базу данных векторных представлений изображений и выполнять поиск в этой базе данных. Я также подробно объясню как преимущества, так и ограничения векторного поиска изображений.
Вот примерный план статьи:
- Преобразование изображений в векторные представления: преобразование визуальных данных в доступные для поиска векторные представления.
- Создание коллекции Milvus: Настройте коллекцию Milvus, которая является основной логической единицей организации данных в векторной базе данных Milvus.
- Выполните поиск изображений: найдите целевые изображения в этой коллекции.
- Интерпретация результатов: Рассмотрите несколько примеров и проанализируйте результаты поиска.
Начнём с получения векторов.
Преобразование изображений в векторные.
Первый шаг — преобразование изображений в векторы, которые представляют собой числовые значения визуальных данных. Размер вектора имеет решающее значение, и оптимальный размер зависит от приложения. Чаще всего выбираются векторы длиной 128, 512 или 768 измерений. Увеличение размера позволяет получить больше информации и ожидать более точных результатов, но это происходит за счет увеличения объема памяти и, возможно, большей задержки при поиске.
Нам нужна модель встраивания для преобразования изображений в векторы. Мы можем обучить собственную модель, но существует несколько готовых моделей, как бесплатных, так и платных.
Например, следующий блок кода берет изображение JPEG и преобразует его в 512-мерный вектор, используя модель clip-ViT-B-32 с открытым исходным кодом.
from PIL import Image from sentence_transformers import SentenceTransformer sku_image = Image.open("sample_image.jpeg") model = SentenceTransformer('clip-ViT-B-32') image_vector = model.encode(sku_image) type(image_vector), image_vector.shape (numpy.ndarray, (512,))
Переменная image_vector представляет собой массив Numpy размером 512.
Создать коллекцию Milvus
Milvus — это векторная база данных, а коллекция в Milvus представляет собой двумерную таблицу с фиксированным количеством столбцов и строк. Каждый столбец представляет собой поле, а каждая строка — объект, в нашем случае — изображение.
Мы создадим коллекцию с двумя полями: полем идентификатора (например, артикулом товара) и соответствующим векторным полем для изображения этого артикула.
Существует несколько способов создания коллекции и взаимодействия с ней. Я предпочитаю использовать Python, когда это возможно, поэтому воспользуюсь модулем pymilvus .
Первый шаг — создание объекта клиента. Это способ подключения к вашей векторной базе данных в Milvus.
from pymilvus import MilvusClient, DataType client = MilvusClient(uri="http://....") # your milvus db uri
Затем мы определяем схему для нашей коллекции:
schema = client.create_schema(auto_id=False, enable_dynamic_field=True) # Add fields to schema schema.add_field(field_name="sku_id", datatype=DataType.VARCHAR, max_length=512, is_primary=True) schema.add_field(field_name="image_vector", datatype=DataType.FLOAT_VECTOR, dim=512)
Схема содержит два поля: sku_id и image_vector .
Затем мы можем создать коллекцию, используя метод create_collection :
collection_name = "test_collection" client.create_collection( collection_name=collection_name, schema=schema, index_params=index_params )
Теперь мы можем добавить индекс к нашим полям. Индекс имеет решающее значение для коллекции Milvus или любой векторной базы данных. Он ускоряет поиск и уменьшает задержку запросов, особенно при работе с большими векторными наборами данных.
Один из способов добавить индекс — использовать функцию create_index .
index_params = client.prepare_index_params() # index for the image vector index_params.add_index( field_name="image_vector", index_name="image_vector_idx", index_type="IVF_FLAT", metric_type="COSINE", # Using COSINE similarity (common for images). Can also be L2 or IP. ) # index for "sku_id" (primary key) index_params.add_index( field_name="sku_id", index_name="sku_id_idx", index_type="INVERTED" ) collection_name = "test_collection" client.create_index( collection_name=collection_name, index_params=index_params )
На заключительном этапе мы загружаем коллекцию и проверяем ее статус.
client.load_collection(collection_name=collection_name) # check load status res = client.get_load_state( collection_name=collection_name ) print(res) {'state': }
Мы создали коллекцию, но в данный момент она пуста. Чтобы убедиться в успешном создании новой коллекции, мы можем вывести список всех коллекций в базе данных, используя метод list_collections .
client.list_collections() ['test_collection']
Следующий шаг — вставка объектов (например, артикулов и векторных изображений).
Вставить сущности
Теперь мы можем загружать данные в нашу коллекцию. Для этого данные должны быть отформатированы как словарь, где ключи соответствуют именам полей коллекции. Затем мы можем использовать список таких словарей для одновременной вставки нескольких сущностей.
У меня есть векторные данные, хранящиеся в DataFrame Pandas, как показано ниже:

Мы можем использовать метод to_dict для преобразования этого DataFrame в список словарей, где каждый словарь представляет собой сущность в нашей коллекции.
df.to_dict(orient="records") [{'sku_id': 'HBCV00009LIR5S', 'image_vector': array([ 0.1206549 , 0.00597879, -0.07224327, 0.02327867, -0.09490156, 0.02150885, 0.10642719, -0.10139938, 0.03159734, 0.05613545, -0.07615539, -0.15523671, -0.10006154, 0.05045145, 0.07733533, -0.03749327, -0.02301577, 0.13337888, 0.00096778, 0.05047926, ...
Получив список всех сущностей в виде словарей, мы можем использовать метод insert для загрузки сущностей в нашу коллекцию:
# convert dataframe to a list of dictionaries data = df.to_dict(orient="records") # insert data into collection res = client.insert( collection_name=collection_name, data=data ) print(res) {'insert_count': 10000, 'ids': ['HBCV00009LIR5S', 'HBCV00001U46VH' ...]
Мы только что загрузили 10000 сущностей, но коллекции обычно содержат гораздо больше данных (например, несколько миллионов сущностей). Мы не можем загрузить миллионы векторов одновременно. В таких случаях мы можем разделить данные на пакеты, а затем загружать их в коллекцию последовательно. Например, приведенный ниже цикл for перебирает весь DataFrame и вставляет 10000 сущностей за пакет.
batch_size = 10000 for i in range(0, len(df), batch_size): data = df.iloc[i:i+batch_size,].to_dict(orient="records") res = client.insert( collection_name=collection_name, data=data )
Теперь у нас есть коллекция с артикулами и векторными данными. Следующий шаг — поиск изображений в этой коллекции.
Выполните поиск изображений
Для поиска изображения нам сначала нужно преобразовать его в вектор того же размера, что и векторы, хранящиеся в нашей коллекции.
Milvus предлагает различные методы поиска, такие как базовый поиск, поиск по диапазону, гибридный поиск. Мы выполним базовый поиск, который на самом деле является поиском приблизительного ближайшего соседа (ANN). Он находит подмножество векторных представлений на основе вектора запроса, используемого в поиске, сравнивает вектор запроса с векторами в подмножестве и возвращает наиболее похожие результаты.
Следующий блок кода считывает изображение в формате JPEG, преобразует его в вектор, используя ту же модель, что и при создании коллекции, а затем ищет этот вектор изображения в коллекции.
collection_name = "test_collection" model = SentenceTransformer('clip-ViT-B-32') search_image = Image.open("image_to_search.jpeg") search_image_vector = model.encode(search_image) res = client.search( collection_name=collection_name, anns_field="image_vector", data=[search_image_vector], limit=3, search_params={"metric_type": "COSINE"} )
Параметр anns_field задает векторное поле, которое будет использоваться в поиске. Затем мы передаем вектор целевого изображения параметру data . Параметр limit указывает Milvus, сколько результатов нужно вернуть (например, 3 возвращает 3 наиболее похожих вектора в коллекции).
Результатом работы метода search является список словарей следующего вида:
print(res[0]) [{'my_id': 'HBCV0000BLJIBF', 'distance': 0.9814613848423661, 'entity': {}} {'my_id': 'HBCV00003Z49OT', 'distance': 0.9504563808441162, 'entity': {}} {'my_id': 'HBCV0000DCK7ML', 'distance': 0.9104360342025757, 'entity': {}}]
Проверка результатов
Поиск изображений с использованием векторной графики очень эффективен и точен. Если в коллекции есть точно такое же изображение (или очень похожее), вы практически гарантированно его найдете.
В приведенных ниже примерах изображение слева — это то, которое искалось, а остальные изображения — это верхние результаты поиска.
Те же изображения
В приведенных ниже примерах в коллекции встречается несколько одинаковых изображений, и векторный поиск смог их обнаружить.


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


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

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


Поиск изображений в векторной базе данных очень полезен во многих случаях. Мы можем легко обнаружить идентичные изображения, а также изображения со схожим визуальным оформлением. Однако, как показано в приведенном выше примере, визуальное сходство не всегда указывает на то, что продукты одинаковы или даже связаны между собой.
Еще один недостаток поиска по изображениям на платформах электронной коммерции заключается в том, что совершенно разные товары могут иметь одно и то же изображение. Например, возьмем смартфоны: многие разные модели внешне выглядят почти одинаково. Полагаться исключительно на поиск по изображениям без дополнительного контекста, такого как название товара или название модели, легко может привести к вводящим в заблуждение результатам.
Одним из решений для преодоления вышеупомянутых недостатков поиска по изображениям может стать внедрение гибридного поиска, который объединяет векторные представления изображений и текста. Гибридный поиск гарантирует, что результаты будут не только визуально похожими, но и концептуально точными.
В следующей статье я пошагово объясню, как создать коллекцию Milvus с несколькими векторными полями и выполнить гибридный поиск. Мы также протестируем этот подход, используя те же примеры из этой статьи, чтобы увидеть, как гибридный поиск отсеивает нерелевантные результаты поиска.
Спасибо за прочтение! Пожалуйста, сообщите мне, если у вас есть какие-либо замечания.
Сонер Йылдырым Посмотреть все магазины Сонер Йылдырым
Источник: towardsdatascience.com
Оцените материал:
Похожие записи
Проблема: сохранять и пересылать ответы ChatGpt
02.11.2025
Microsoft решила проблему кэширования шейдеров при помощи Advanced Shader Delivery
22.08.2025
Радикальный взгляд Карло Ровелли на реальность
31.10.2025Присоединяйтесь и подпишитесь на рассылку самых свежих новостей по Email
Получайте свежие новости и идеи на почту. Без спама — только самое интересное.
Нажимая «Подписаться», вы соглашаетесь с политикой конфиденциальности.
