English translation is not available yet. Showing Russian content.

Как вы делаете RAG для изображений (image retrieval without text)?

Краткий тезис

RAG для изображений без текста строится на мультимодальных эмбеддингах, чаще всего с помощью модели CLIP, которая переводит и изображения, и текст в единое векторное пространство. Все изображения индексируются в векторной БД (FAISS, Pinecone). Запрос может быть как текстовым описанием, так и другим изображением — его эмбеддинг вычисляется той же моделью, после чего выполняется поиск по косинусной близости. Для мультимодального RAG (текст + изображения) применяется reranking|late fusion — объединение результатов двух независимых retrieval-каналов.


1. Термин: Image Retrieval без текста

Image retrieval — задача поиска изображений, релевантных запросу. Классический подход требует текстовых меток или аннотаций. «Без текста» означает, что у самих изображений в базе нет текстовых описаний — только визуальное содержание. Решение — использовать мультимодальные эмбеддинги, которые кодируют и изображения, и текст в общее пространство, позволяя сравнивать их напрямую.

Ключевая идея: если модель обучена совмещать модальности (например, CLIP), то эмбеддинг изображения и эмбеддинг текстового запроса будут близки, если изображение соответствует запросу. Таким образом, retrieval возможен без единого слова в базе изображений.


2. Модель CLIP: основа современного image retrieval

CLIP (Contrastive Language-Image Pre-training) — модель от OpenAI, обученная на 400 млн пар (изображение, текст) с использованием контрастивной потери (contrastive loss). Она состоит из двух энкодеров: Image Encoder (обычно ViT или ResNet) и Text Encoder (Transformer). На выходе — нормализованные векторы фиксированной размерности (например, 512 или 768).

Принцип работы

  • Для каждой пары (изображение, текст) в батче считается косинусная близость между эмбеддингами.
  • Модель учится увеличивать близость для правильных пар и уменьшать для неправильных (InfoNCE loss).
  • После обучения эмбеддинги разных модальностей выровнены: изображение кота и текст «кот» имеют похожие векторы.

Почему CLIP подходит для image retrieval без текста:

  • Эмбеддинги изображений можно вычислить один раз и сохранить.
  • Запрос может быть текстом (например, «красная машина») — его эмбеддинг сравнивается с эмбеддингами изображений.
  • Запрос может быть другим изображением — его эмбеддинг вычисляется Image Encoder'ом, и поиск идёт среди эмбеддингов изображений (image-to-image retrieval).

3. Индексация изображений в векторной БД

Процесс подготовки базы изображений:

  1. Извлечение эмбеддингов каждое изображение прогоняется через Image Encoder CLIP (или другую мультимодальную модель). Получаем вектор фиксированной размерности.
  2. Нормализация эмбеддинги нормализуются (L2-норма), чтобы косинусная близость равнялась скалярному произведению.
  3. Загрузка в векторную БД используется FAISS (Facebook AI Similarity Search), Pinecone, Weaviate или Milvus. Для больших коллекций применяется ANN (Approximate Nearest Neighbors)индексы типа IVF, HNSW, PQ.
  4. Метаданные: вместе с эмбеддингом хранятся ссылка на файл, возможно, теги или дата создания — для пост-фильтрации.

Пример кода (FAISS):

import torch
import clip
import faiss
import numpy as np

model, preprocess = clip.load("ViT-B/32")
device = "cuda"

# Загружаем изображения, получаем эмбеддинги
image_embeddings = []
for img_path in image_paths:
    image = preprocess(Image.open(img_path)).unsqueeze(0).to(device)
    with torch.no_grad():
        emb = model.encode_image(image).cpu().numpy()
    image_embeddings.append(emb)

image_embeddings = np.vstack(image_embeddings).astype('float32')
faiss.normalize_L2(image_embeddings)

# Строим индекс
index = faiss.IndexFlatIP(image_embeddings.shape[1])  # Inner Product = cosine similarity
index.add(image_embeddings)

# Сохраняем
faiss.write_index(index, "image_index.faiss")

4. Retrieval: текстовый запрос

Если пользователь вводит текст (например, «закат на море»):

  1. Текст кодируется Text Encoder'ом CLIP → получаем вектор запроса.
  2. Вектор нормализуется.
  3. Выполняется поиск в FAISS: index.search(query_vector, k=10).
  4. Возвращаются top-k изображений с наибольшей косинусной близостью.

Важно модель CLIP обучена на естественном языке, поэтому запросы лучше формулировать как описания, а не отдельные слова. Например, вместо «кошка» лучше «фотография кошки, сидящей на подоконнике».


5. Retrieval: запрос-изображение (image-to-image)

Когда пользователь загружает изображение и хочет найти похожие:

  1. Изображение-запрос кодируется Image Encoder'ом CLIP.
  2. Полученный эмбеддинг сравнивается со всеми эмбеддингами в базе (косинусная близость).
  3. Возвращаются наиболее похожие изображения.

Этот сценарий часто используется в системах поиска по визуальному сходству (например, поиск товаров по фото). CLIP здесь работает как visual backbone, но можно использовать и специализированные модели (например, DINOv2), которые дают более чистые визуальные признаки без текстового выравнивания. Однако CLIP удобен тем, что единая модель работает и для текстовых, и для визуальных запросов.


6. Ранжирование и пост-обработка

После получения top-k кандидатов можно применить дополнительные этапы:

  • Re-ranking использовать более тяжёлую модель (например, ViT-L/14 CLIP или даже мультимодальный LLM) для переоценки близости.
  • Фильтрация по метаданным если известны дата, автор, категория — отсеять неподходящие.
  • Deduplication удалить дубликаты (почти одинаковые изображения).
  • Query expansion: для текстового запроса можно сгенерировать несколько синонимов, усреднить эмбеддинги (или объединить результаты).

Пример re-ranking с помощью косинусной близости на более точной модели:

# После первого прохода (быстрый индекс) берём top-100
# Пересчитываем эмбеддинги через более качественный энкодер
fine_model, _ = clip.load("ViT-L/14")
# ... пересчёт и сортировка

7. Мультимодальный RAG: объединение текста и изображений

Часто требуется RAG-система, которая работает и с текстовыми документами, и с изображениями. Возможны две стратегии:

СтратегияОписаниеПлюсыМинусы
Early fusionЭмбеддинги текста и изображений объединяются в одном векторном пространстве (например, через CLIP) и хранятся в одной БД.Простота, единый поискПотеря специфики модальностей, сложность с разными размерностями
Late fusionДва независимых retrieval: текстовый (через text embeddings) и визуальный (через image embeddings). Результаты объединяются (ранжирование, конкатенация).Каждый канал оптимизирован под свою модальность, гибкостьДва индекса, больше latency

Late fusion — более распространённый подход в production. Этапы:

  1. Текстовый запрос идёт в текстовый индекс (например, на основе Sentence-BERT).
  2. Тот же запрос (или его часть) идёт в визуальный индекс (CLIP image embeddings).
  3. Результаты объединяются: можно взять top-k из каждого канала и перемешать, или использовать weighted sum scores.

Пример кода (псевдо):

text_results = text_index.search(text_emb, k=5)
image_results = image_index.search(text_emb, k=5)  # text_emb от CLIP
combined = merge(text_results, image_results, weights=[0.7, 0.3])

8. Проблемы и ограничения

  • Domain shift CLIP обучен на интернет-данных, может плохо работать на специфических доменах (медицина, спутниковые снимки). Решение — fine-tune CLIP на своих данных.
  • Размер эмбеддинга для миллионов изображений хранение векторов (512 float32 = 2KB на изображение) может быть затратным. Используют Product Quantization (PQ) для сжатия.
  • Скорость ANN-индексы (HNSW) дают субсекундный поиск для 10M+ векторов, но требуют настройки параметров.
  • Качество эмбеддингов CLIP не идеален для тонких визуальных различий (например, разные породы собак). Альтернативы: SigLIP, OpenCLIP, BLIP-2.
  • Отсутствие текстовых меток если нужно искать по конкретным атрибутам (например, «фото с красным автомобилем 2020 года»), CLIP может не справиться — требуется fine-tuning или добавление метаданных.

9. Альтернативы CLIP

МодельОсобенностьКогда использовать
DINOv2Self-supervised, только визуальные признакиЧистый image-to-image поиск, без текстовых запросов
BLIP-2Мультимодальный encoder-decoder, лучше понимает сложные запросыКогда нужен высококачественный retrieval + генерация
SigLIPАналогичен CLIP, но с сигмоидной loss, часто лучшеЕсли CLIP даёт плохие результаты
ImageBindШестимодальная модель (изображение, текст, аудио, глубина и др.)Мультимодальные запросы (например, «найди изображение, похожее на этот звук»)

Пет-проект для закрепления

Задача Создать сервис поиска изображений по текстовому описанию (image retrieval without text) на основе CLIP и FAISS.

Инструменты

  • Python, PyTorch, CLIP (openai/clip-vit-base-patch32)
  • FAISS (faiss-cpu или faiss-gpu)
  • Streamlit (интерфейс)
  • Датасет: Unsplash Lite (25k изображений) или собственные фото

Шаги:

  1. Скачать датасет изображений (например, Unsplash Lite).
  2. Написать скрипт для извлечения эмбеддингов через CLIP (использовать батчи, GPU).
  3. Нормализовать эмбеддинги и построить FAISS индекс (IndexFlatIP для точности или HNSW для скорости).
  4. Создать Streamlit-приложение: поле ввода текста, кнопка поиска, вывод top-5 изображений с косинусной близостью.
  5. Добавить возможность загрузить своё изображение для image-to-image поиска.
  6. (Опционально) Реализовать re-ranking через ViT-L/14.
  7. Оценить качество: вручную проверить 20 запросов, посчитать HR@5.

Ожидаемый результат Работающий веб-интерфейс, который по тексту «закат в горах» показывает релевантные фото, а по загруженному изображению кота — похожих котов.


Связь с другими вопросами

ВопросТема
1Проектирование RAG-системы
5Оценка качества retrieval
7Уменьшение latency
10Self-RAG
540Мультимодальные эмбеддинги
542Agentic RAG с изображениями

Навигация