Создание прототипа интеллектуальной поисковой системы
Вступление
Семантический поиск - это система поиска информации, которая фокусируется на значении предложений, а не на обычном сопоставлении ключевых слов. Несмотря на то, что для этой цели можно использовать множество встраиваемых текстов, их масштабирование для создания API с низкой задержкой, которые могут извлекать данные из огромной коллекции данных, редко обсуждается. В этой статье я расскажу, как реализовать минимальную семантическую поисковую систему, используя вложения предложений SOTA (преобразователь предложений) и FAISS.
Трансформаторы предложений
Это структура или набор моделей, которые дают плотное векторное представление предложений или абзацев. Эти модели представляют собой сети-преобразователи (BERT, RoBERTa и т. Д.), Которые настроены специально для задачи семантического текстового сходства, поскольку BERT не справляется с этими задачами. Ниже приведены характеристики различных моделей в тесте STS.
Мы видим, что модели преобразователей Sentence намного превосходят другие модели.
Но если вы посмотрите на таблицу лидеров по бумагам с кодом и GLUE, вы увидите много моделей выше 90. Так зачем нам трансформеры предложений ?.
Что ж, в этих моделях семантическое текстовое сходство рассматривается как задача регрессии. Это означает, что всякий раз, когда нам нужно рассчитать оценку сходства между двумя предложениями, нам нужно передать их вместе в модель, и модель выдает числовую оценку между ними. Хотя это хорошо работает для эталонного теста, оно плохо масштабируется для реального использования, и вот причины.
- Когда вам нужно выполнить поиск, скажем, в 10k документах, вам нужно будет выполнить 10k отдельных вычислений вывода, невозможно вычислить вложения отдельно и вычислить только косинусное сходство. См. Объяснение автора.
- Максимальная длина последовательности (общее количество слов / токенов, которые модель может принять за один проход) распределяется между двумя документами, что приводит к размыванию представлений из-за разбиения на фрагменты.
FAISS
Faiss - это библиотека на основе C ++, созданная Facebook AI с полной оболочкой на Python, для индексации векторизованных данных и выполнения эффективного поиска по ним. Faiss предлагает различные индексы, основанные на следующих факторах
- время поиска
- качество поиска
- память, используемая на индексный вектор
- Тренировочное время
- потребность во внешних данных для обучения без учителя
Таким образом, выбор правильного индекса будет компромиссом между этими факторами.
Загрузка модели и выполнение логического вывода для набора данных
Для начала установим и загрузим необходимые библиотеки.
!pip install faiss-cpu !pip install -U sentence-transformers import numpy as np import torch import os import pandas as pd import faiss import time from sentence_transformers import SentenceTransformer
Загрузка набора данных с миллионом точек данных
Я использовал набор данных из Kaggle, который содержит заголовки новостей, опубликованные за семнадцать лет.
df=pd.read_csv("abcnews-date-text.csv") data=df.headline_text.to_list()
Загрузка предварительно обученной модели и выполнение логического вывода
model = SentenceTransformer('distilbert-base-nli-mean-tokens') encoded_data = model.encode(data)
Индексирование набора данных
Мы можем выбрать различные варианты индексации в зависимости от нашего сценария использования, обратившись к руководству.
Определим индекс и добавим в него данные
index = faiss.IndexIDMap(faiss.IndexFlatIP(768)) index.add_with_ids(encoded_data, np.array(range(0, len(data))))
Сериализация индекса
faiss.write_index(index, 'abc_news')
Затем сериализованный индекс можно экспортировать на любой компьютер для размещения поисковой системы.
Десериализация индекса
index = faiss.read_index('abc_news')
Выполнение поиска семантического сходства
Давайте сначала создадим функцию-оболочку для поиска
def search(query): t=time.time() query_vector = model.encode([query]) k = 5 top_k = index.search(query_vector, k) print('totaltime: {}'.format(time.time()-t)) return [data[_id] for _id in top_k[1].tolist()[0]]
выполнение обыска
query=str(input()) results=search(query) print('results :') for result in results: print('\t',result)
Результаты на CPU
Теперь посмотрим на результаты поиска и время отклика.
1,5 секунды - это все, что требуется для выполнения интеллектуального поиска на основе значений в наборе данных из миллиона текстовых документов, используя только серверную часть ЦП.
Результаты на GPU
Во-первых, давайте удалим версию Faiss для процессора и переустановим версию для графического процессора.
!pip uninstall faiss-cpu !pip install faiss-gpu
Затем выполните ту же процедуру, но в конце переместите индекс в GPU.
res = faiss.StandardGpuResources() gpu_index = faiss.index_cpu_to_gpu(res, 0, index)
Теперь поместим это в функцию поиска и выполним поиск с помощью графического процессора.
Правильно, вы можете получить результаты в течение 0,02 секунды с помощью графического процессора (в этом эксперименте используется Tesla T4), что в 75 раз быстрее, чем серверная часть процессора.
Но почему я не могу просто сериализовать массив закодированных данных NumPy вместо их индексации и использовать косинусное сходство, если я могу подождать несколько секунд?
Поскольку NumPy не имеет встроенных функций сериализации, единственный способ - преобразовать его в JSON, а затем сохранить объект JSON, но тогда размер увеличится в пять раз. Например, миллион точек данных, закодированных в 768-мерное векторное пространство с нормальной индексацией, будет составлять около 3 ГБ, преобразование в JSON сделает его 15 ГБ, что обычная машина не может удержать в своей оперативной памяти. Таким образом, нам придется запускать миллион вычислений каждый раз, когда мы выполняем поиск, что непрактично.
Последние мысли
Это базовая реализация, и многое еще предстоит сделать как в части языковой модели, так и в части индексации. Существуют различные варианты индексации, из которых следует выбрать правильный в зависимости от варианта использования, размера данных и доступной вычислительной мощности. Кроме того, встраивание предложений, используемое здесь, просто доработано для некоторых общедоступных наборов данных, точная настройка их в наборе данных для конкретной предметной области улучшит встраивание и, следовательно, результаты поиска.
использованная литература
[1] Нильс Реймерс и Ирина Гуревич. « Делаем одноязычные вложения предложений многоязычными с помощью дистилляции знаний . arXiv (2020): 2004.09813.
[2] Джонсон, Джефф и Дуз, Маттис и Джей Гоу, Херв {е} . « Миллиардный поиск сходства с графическими процессорами » препринт arXiv arXiv: 1702.08734 .