Как создать мультимодальное приложение поиска с помощью Chroma?

Как разработать мультимодальное приложение для поиска с использованием Chroma?

Введение

Вы когда-нибудь задумывались, как наш сложный мозг обрабатывает мир? В то время как внутренние процессы мозга остаются загадкой, мы можем сравнить его с универсальной нейронной сетью. Благодаря электрохимическим сигналам, он обрабатывает различные типы данных – звук, видео, запахи, вкусы и осязание. С развитием искусственного интеллекта появляются многофункциональные модели, революционирующие возможности поиска. Эта инновация открывает новые возможности, повышая точность и актуальность поиска. Откройте захватывающий мир многофункционального поиска.

Цели обучения

  • Понять термин «многообразие в искусственном интеллекте».
  • Получить представление о модели OpenAI по обработке изображений и текста CLIP.
  • Узнать, что такое векторная база данных и кратко понять векторное индексирование.
  • Использовать CLIP и векторную базу данных Chroma для создания рекомендателя еды с интерфейсом Gradio.
  • Исследовать другие реальные примеры использования многофункционального поиска.

Эта статья была опубликована в рамках Data Science Blogathon.

Что такое многообразие в искусственном интеллекте?

Если вы зайдете в Google, вы узнаете, что многообразие означает вовлечение нескольких режимов или методов в процесс. В искусственном интеллекте многообразные модели – это нейронные сети, которые могут обрабатывать и понимать различные типы данных. Например, GPT-4 и Bard. Это модели, которые могут понимать тексты и изображения. Другими примерами могут быть автомобили Tesla, объединяющие визуальные и сенсорные данные для восприятия окружающей среды, а также Midjourney или Dalle, которые могут создавать изображения на основе текстовых описаний.

Контрастное предварительное обучение языком и изображением (CLIP)

CLIP – это многофункциональная нейронная сеть с открытым исходным кодом от OpenAI, обученная на большом наборе пар изображений и текста. Это обеспечивает возможность CLIP связывать визуальные концепции на изображениях с текстовыми описаниями. Модель CLIP может быть научена классифицировать широкий спектр изображений на основе человеческой речи без специального обучения.

Возможность нулевого примера CLIP сравнима с моделью GPT 3. Поэтому CLIP может использоваться для классификации изображений на любое множество категорий без необходимости обучения на этих конкретных категориях. Например, для классификации изображений собак и кошек нам просто нужно сравнить оценки логитов изображения с текстовым описанием “изображение собаки” или “изображение кошки”; Фотография кошки или собаки имеет больше шансов иметь более высокие оценки логитов с соответствующими текстовыми описаниями.

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

CLIP использует Vision Transformer (ViT) для изображений и модель текста для текстовых особенностей. Векторные кодировки проецируются на общее векторное пространство с одинаковыми размерностями. Скалярное произведение между ними используется в качестве показателя сходства для предсказания сходства между фрагментом текста и изображением. Другими словами, CLIP может классифицировать изображения в любой набор категорий без оптимизации для них. В этой статье мы реализуем CLIP программно.

Зачем нужны векторные базы данных?

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

На следующей иллюстрации показан упрощенный рабочий процесс векторной базы данных.

Нам потребуются специализированные модели встраивания, способные уловить скрытое семантическое значение данных. Модели различаются в зависимости от типов данных. Используйте модели изображений, такие как Resnet или Visual Transformers для обработки изображений. Для текстов используются модели текстов, такие как Ada и SentenceTransformers. Для кросс-модального взаимодействия используются мультимодальные модели, такие как Tortoise (текст в речь) и CLIP (текст в изображение). Эти модели будут использоваться для получения встраиваний входных данных. Векторные базы данных обычно имеют специальные реализации моделей встраивания, но мы также можем определить собственные модели для получения встраиваний и сохранения их в векторных хранилищах.

Индексирование

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

Некоторые популярные алгоритмы индексирования: HNSW (Hierarchical Navigable Small World), Quantizing Product, Inverted File System, Scalar Quantization и т. д. Из всех этих алгоритмов наиболее популярным и широко используемым в различных векторных базах данных является HNSW.

В этом приложении мы будем использовать базу данных Chroma Vector. Chroma – это открытая векторная база данных. Она позволяет быстро настроить клиент для сохранения и запроса векторов и связанных метаданных. Есть и другие подобные векторные хранилища, которые вы можете использовать, такие как Weaviate, Qdrant, Milvus и т. д.

Что такое Gradio?

Gradio, написанный на Python, направлен на быстрое создание веб-интерфейса для обмена моделями машинного обучения в качестве инструмента с открытым исходным кодом. Он позволяет нам создавать демонстрационный веб-интерфейс с использованием Python. Он обеспечивает гибкость в создании достойного прототипа для демонстрации моделей на backend.

Для получения дополнительной информации о создании см. эту статью.

Создание приложения

В этом разделе мы рассмотрим коды для создания простого приложения рекомендации ресторанного блюда с использованием Gradio, Chroma и CLIP. Chroma пока не поддерживает многомодальные модели. Поэтому это будет обходное решение.

Есть два способа использовать CLIP в вашем проекте. Либо реализация CLIP от OpenAI, либо реализация CLIP от Huggingface. В этом проекте мы будем использовать реализацию CLIP от OpenAI. Убедитесь, что у вас есть виртуальная среда с установленными следующими зависимостями.

import clip, torch\nfrom numpy import ndarray\nfrom typing import List\nfrom PIL import Image\nclass ClipEmbeddings:\n    def __init__(self, model_name: str = "ViT-B/32", device: str = "cpu"):\n        self.device = device  # Сохраняем указанное устройство для выполнения модели\n        self.model, self.preprocess = clip.load(model_name, self.device)\n\n    def __call__(self, docs: List[str]) -> List[ndarray]:\n        # Определяем метод, который принимает список путей к изображениям как входные данные\n        list_of_embeddings = []  # Создаем пустой список для хранения встроенных изображений\n        for image_path in docs:\n            image = Image.open(image_path)  # Открываем и загружаем изображение из указанного пути\n            image = image.resize((224, 224))  # Предварительно обрабатываем изображение и перемещаем его на указанное устройство\n            image_input = self.preprocess(image).unsqueeze(0).to(self.device)\n            with torch.no_grad():\n                # Вычисляем встраивания изображения с помощью модели CLIP и преобразуем их в массивы NumPy\n                embeddings = self.model.encode_image(image_input).cpu().detach().numpy()\n            list_of_embeddings.append(list(embeddings[0]))\n        return list_of_embeddings\n\n    def get_text_embeddings(self, text: str) -> List[ndarray]:\n        # Определяем метод, который принимает текстовую строку в качестве входных данных\n        text_token = clip.tokenize(text)  # Токенизируем входной текст\n        with torch.no_grad():\n            # Вычисляем текстовые встроенные вектора, используя модель CLIP и преобразуем их в массивы NumPy\n            text_embeddings = self.model.encode_text(text_token).cpu().detach().numpy()\n        return list(text_embeddings[0])

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

clip.available_models()['RN50', 'RN101', 'RN50x4', 'RN50x16', 'RN50x64', 'ViT-B/32', 'ViT-B/16', 'ViT-L/14', 'ViT-L/14@336px']

По умолчанию имя модели установлено как “ViT-B/32”. Вы можете передать любую другую модель по вашему желанию.

Метод __call__ принимает список путей к изображениям и возвращает список массивов numpy. Метод get_text_embeddings принимает входные данные в виде строки и возвращает список вложений.

Загрузка вложений

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

Но сначала создайте коллекцию Chroma.

import osfrom chromadb import Client, Settingsfrom clip_embeddings import ClipEmbeddingsfunctionfrom typing import Listef = ClipEmbeddingsfunction()client = Client(settings = Settings(is_persistent=True, persist_directory="./clip_chroma"))coll = client.get_or_create_collection(name = "clip", embedding_function = ef)

Мы импортировали ранее определенную функцию вложения и передали ее в качестве функции вложения по умолчанию для коллекции.

Теперь загрузите данные в базу данных.

coll.add(ids=[str(i) for i in range(len(img_list))],         documents = img_list, #пути к изображениям         metadatas = menu_description,# описание блюд         )

Вот и все. Теперь вы готовы приступить к созданию финальной части.

Приложение Gradio

Сначала создайте файл app.py, импортируйте следующие зависимости и инициируйте функцию вложения.

import gradio as grfrom chromadb import Client, Settingsfrom clip_embeddings import ClipEmbeddingsfunctionclient = Client(Settings(is_persistent=True, persist_directory="./clip_chroma"))ef = ClipEmbeddingsfunction()

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

with gr.Blocks() as demo:    with gr.Row():        with gr.Column():            query = gr.Textbox(placeholder = "Введите запрос")            gr.HTML("ИЛИ")            photo = gr.Image()            button = gr.UploadButton(label = "Загрузить файл", file_types=["image"])        with gr.Column():            gallery = gr.Gallery().style(                                     object_fit='contain',                                      height='auto',                                      preview=True                                  )

Теперь мы определим события-триггеры для приложения Gradio.

query.submit(        fn = retrieve_image_from_query,         inputs=[query],         outputs=        )    button.upload(        fn = show_img,         inputs=[button],        outputs = [photo]).\        then(            fn = retrieve_image_from_image,             inputs=[button],             outputs=            )

В вышеуказанном коде у нас есть события-триггеры. Мы обрабатываем текстовый запрос с помощью функции retrieve_image_from_query. Сначала мы отображаем изображения на объекте photo, а затем вызываем retrieve_image_from_image(), отображая результат на объекте Gallery.

Запустите файл app.py с помощью команды gradio и перейдите по локальному адресу, указанному в терминале.

Теперь мы определим фактические функции.

def retrieve_image_from_image(image):    # Получаем коллекцию с именем "clip", используя указанную функцию вложения (ef)    coll = client.get_collection(name="clip", embedding_function=ef)    # Извлекаем имя файла изображения    image = image.name    # Запрашиваем коллекцию, используя имя файла изображения в качестве текста запроса    result = coll.query(        query_texts=image,  # Используем имя файла изображения в качестве текста запроса        include=["documents", "metadatas"],  # Включаем документы и метаданные в результаты        n_results=4  # Указываем количество результатов для получения    )    # Получаем извлеченные документы и их метаданные    docs = result['documents'][0]    descs = result["metadatas"][0]    # Создаем список для хранения пар документов и соответствующих им метаданных    list_of_docs = []    # Перебираем извлеченные документы и метаданные    for doc, desc in zip(docs, descs):        # Добавляем в список кортеж, содержащий документ и его метаданные        list_of_docs.append((doc, list(desc.values())[0]))    # Возвращаем список пар документов и метаданных    return list_of_docs

У нас также есть другая функция для обработки текстовых запросов.

def retrieve_image_from_query(query: str):    # Получить коллекцию "clip" с использованием указанной функции встраивания (ef)    coll = client.get_collection(name="clip", embedding_function=ef)    # Получить текстовые встраивания для входного запроса с использованием функции встраивания (ef)    emb = ef.get_text_embeddings(text=query)    # Преобразовать текстовые встраивания в значения с плавающей запятой    emb = [float(i) for i in emb]    # Запросить коллекцию с использованием текстовых встраиваний    result = coll.query(        query_embeddings=emb,  # Использовать текстовые встраивания в качестве запроса        include=["documents", "metadatas"],  # Включить документы и метаданные в результаты        n_results=4  # Указать количество результатов для извлечения    )    # Получить извлеченные документы и их метаданные    docs = result['documents'][0]    descs = result["metadatas"][0]    # Создать список для хранения пар документов и соответствующих метаданных    list_of_docs = []    # Перебрать извлеченные документы и метаданные    for doc, desc in zip(docs, descs):        # Добавить кортеж, содержащий документ и его метаданные, в список        list_of_docs.append((doc, list(desc.values())[0]))    # Вернуть список пар документ-метаданные    return list_of_docs

Вместо передачи текстов напрямую в коде мы извлекли встраивания и затем передали их методу запроса Чомы.

Итак, вот полный код для app.py.

# Импортировать необходимые библиотекиimport gradio as grfrom chromadb import Client, Settingsfrom clip_embeddings import ClipEmbeddingsfunction# Инициализировать клиента chromadb с постоянным хранилищемclient = Client(Settings(is_persistent=True, persist_directory="./clip_chroma"))# Инициализировать функцию ClipEmbeddingsef = ClipEmbeddingsfunction()# Функция для получения изображений из текстового запросаdef retrieve_image_from_query(query: str):    # Получить коллекцию "clip" с указанной функцией встраивания    coll = client.get_collection(name="clip", embedding_function=ef)        # Получить текстовые встраивания для входного запроса    emb = ef.get_text_embeddings(text=query)    emb = [float(i) for i in emb]        # Запросить коллекцию для похожих документов    result = coll.query(        query_embeddings=emb,        include=["documents", "metadatas"],        n_results=4    )        # Извлечь документы и их метаданные    docs = result['documents'][0]    descs = result["metadatas"][0]    list_of_docs = []        # Объединить документы и описания в список    for doc, desc in zip(docs, descs):        list_of_docs.append((doc, list(desc.values())[0]))        return list_of_docs# Функция для получения изображений из загруженного изображенияdef retrieve_image_from_image(image):    # Получить коллекцию "clip" с указанной функцией встраивания    coll = client.get_collection(name="clip", embedding_function=ef)        # Получить имя загруженного изображения    image = image.name        # Запросить коллекцию с именем файла изображения    result = coll.query(        query_texts=image,        include=["documents", "metadatas"],        n_results=4    )        # Извлечь документы и их метаданные    docs = result['documents'][0]    descs = result["metadatas"][0]    list_of_docs = []        # Объединить документы и описания в список    for doc, desc in zip(docs, descs):        list_of_docs.append((doc, list(desc.values())[0]))        return list_of_docs# Функция для отображения изображенияdef show_img(image):    return image.name# Создать интерфейс с использованием блоковwith gr.Blocks() as demo:    with gr.Row():        with gr.Column():            # Текстовое поле для запроса            query = gr.Textbox(placeholder="Введите запрос")            gr.HTML("ИЛИ")            # Загрузка изображения через загрузку файла            photo = gr.Image()            button = gr.UploadButton(label="Загрузить файл", file_types=["image"])        with gr.Column():            # Отображение галереи изображений            gallery = gr.Gallery().style(                object_fit='contain',                height='auto',                preview=True            )    # Определить вход и выход для отправки запросов    query.submit(        fn=retrieve_image_from_query,        inputs=[query],        outputs=    )        # Определить вход и выход для загрузки изображения    button.upload(        fn=show_img,        inputs=[button],        outputs=[photo]).\        then(            fn=retrieve_image_from_image,            inputs=[button],            outputs=        )# Запустить интерфейс Gradio, если скрипт запущен как основная программаif __name__ == "__main__":    demo.launch()

Теперь запустите приложение, выполнив gadio app.py в терминале и перейдите по локальному адресу.

Репозиторий GitHub:  https://github.com/sunilkumardash9/multi-modal-search-app

Практические примеры использования

Мультимодальный поиск может иметь множество применений в различных отраслях.

  • Электронная коммерция: Мультимодальный поиск может улучшить опыт покупок для клиентов. Например, вы можете сфотографировать товар в физическом магазине и найти похожие продукты онлайн.
  • Здравоохранение: Он может помочь в диагностике заболеваний и поиске лечения. Врачи могут использовать изображение для поиска клинических исследований из медицинской базы данных.
  • Образование: Приложения для образования с мультимодальным поиском могут помочь студентам и профессорам быстрее находить соответствующие документы. Получение текстов на основе изображений и наоборот может сэкономить много времени.
  • Обслуживание клиентов: Мультимодальный поиск может помочь оптимизировать поиск ответов на запросы клиентов из базы знаний. Эти запросы могут содержать изображения или видео продуктов.

Заключение

Мультимодальный поиск будет революционным в будущем. Возможность взаимодействия в нескольких модальностях открывает новые возможности для роста. Поэтому этот статья описывает использование базы данных векторов Chroma и мультимодельной модели CLIP для создания базового приложения поиска. Так как Chroma-база данных не имеет “из коробки” поддержки мультимодельных моделей, мы создали пользовательский класс вложения CLIP для получения вложений изображений и объединили различные компоненты для создания приложения по поиску продуктов.

Ключевые моменты

  • В ИИ мультимодальность означает способность взаимодействия с несколькими типами коммуникации, такими как текст, изображение, аудио и видео.
  • CLIP – это модель совмещения изображений и текста, обученная на тысячах примеров изображений и текста с возможностью классификации “нулевого шага”.
  • Векторные базы данных предназначены для хранения, поиска и запроса высокоразмерных векторов.
  • Алгоритмы ANN – это движки, обеспечивающие работу Векторных Хранилищ. HNSW является одним из наиболее популярных и эффективных графических алгоритмов ANN.

Часто задаваемые вопросы

Медиа, показанное в этой статье, не принадлежит Analytics Vidhya и используется по решению автора.