Большие языковые модели и векторные базы данных для рекомендаций новостей

Улучшение рекомендаций новостей с помощью больших языковых моделей и векторных баз данных

Фото Roman Kraft на Unsplash

Превращение LLMs в производственные среды с помощью Sentence Transformers и Qdrant

Большие языковые модели (LLMs) вызвали шум в машинном обучении с недавними релизами инструментов генеративного искусственного интеллекта, таких как Chat-GPT, Bard и другие подобные. Одна из основных идей за этими решениями – вычисление числового представления неструктурированных данных (таких как тексты и изображения) и поиск сходства между этими представлениями.

Однако перенос всех этих концепций в производственную среду имеет свои собственные проблемы машинного обучения:

  • Как быстро генерировать эти представления?
  • Как хранить их в правильной базе данных?
  • Как быстро вычислять сходства для производственных сред?

В этой статье я представлю два решения с открытым исходным кодом, которые стремятся решить эти вопросы:

  • Sentence Transformers [1]: техника генерации вложений на основе текстовой информации и;
  • Qdrant: векторная база данных, способная хранить вложения и предоставлять простой интерфейс для их запроса.

Эти инструменты применяются к набору данных NPR [2], набору данных рекомендаций новостного портала (открыто доступный на Kaggle), который был создан для поддержки научного сообщества в разработке алгоритмов рекомендаций. В конце статьи вы увидите, как:

  • Генерировать вложения новостей с помощью Sentence Transformers
  • Хранить вложения с помощью Qdrant
  • Запрашивать вложения для рекомендации новостных статей

Весь код для этой статьи доступен на Github.

1. Генерация вложений с помощью Sentence Transformers

Прежде всего, нам нужно найти способ преобразовать входные данные в векторы, которые мы назовем вложениями (если вы хотите глубже изучить концепцию вложений, рекомендую статью Boykis’ article What Are Embeddings? [3]).

Итак, давайте посмотрим, какие данные мы можем использовать из набора данных NPR:

import pandas as pddf = pd.read_parquet("articles.parquet")df.tail()
Выборка данных от NPR (изображение, сгенерированное автором)

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

Процесс генерации вложений (изображение автора)

Итак, после того, как мы определим текстовые функции из наших входных данных, нам нужно создать модель вложений для генерации числового представления. К счастью для нас, существуют веб-сайты, такие как HuggingFace, где вы можете найти заранее обученные модели, подходящие для конкретных языков или задач. В нашем примере мы можем использовать модель neuralmind/bert-base-portuguese-cased, которая была обучена на бразильском португальском для следующих задач:

  • Распознавание именованных сущностей
  • Схожесть предложений
  • Распознавание текстовой эвиденции

С точки зрения кода, вот так мы переводим процесс генерации вложений:

from sentence_transformers import SentenceTransformermodel_name = "neuralmind/bert-base-portuguese-cased"encoder = SentenceTransformer(model_name_or_path=model_name)title = """ Парагвайцы отправляются к урнам в эту воскресенье (30 числа) чтобы выбрать нового президента"""sentence = titlesentence_embedding = encoder.encode(sentence)print (sentence_embedding)# вывод: np.array([-0.2875876, 0.0356041, 0.31462672, 0.06252239, ...])

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

Мы можем применить тот же процесс ко всем другим статьям в наборе данных NPR:

def generate_item_sentence(item: pd.Series, text_columns=["title"]) -> str:    return ' '.join([item[column] for column in text_columns])df["sentence"] = df.apply(generate_item_sentence, axis=1)df["sentence_embedding"] = df["sentence"].apply(encoder.encode)

Примечание: имейте в виду, что этот процесс может занять некоторое время в зависимости от мощности вашего компьютера.

Когда у нас есть вложения для всех новостных статей, давайте определим стратегию хранения их.

2. Хранение вложений

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

Существует несколько программных продуктов для векторных баз данных, решающих данную задачу, но я в этой статье использую Qdrant, который является решением с открытым исходным кодом с доступными интерфейсами API для популярных языков программирования, таких как Python, Go и Typescript. Для лучшего сравнения между этими векторными базами данных ознакомьтесь с этой статьей [4].

Настройка Qdrant

Для работы со всеми операциями Qdrant нам нужно создать объект-клиента, который указывает на векторную базу данных. Qdrant позволяет создать бесплатный тарифный план для тестирования удаленного подключения к базе данных, но для простоты я создам и сохраню базу данных локально:

from qdrant_client import QdrantClientclient = QdrantClient(path="./qdrant_data")

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

from qdrant_client import modelsfrom qdrant_client.http.models import Distance, VectorParamsclient.create_collection(    collection_name = "news-articles",    vectors_config = models.VectorParams(        size = encoder.get_sentence_embedding_dimension(),        distance = models.Distance.COSINE,    ),)print (client.get_collections())# вывод: CollectionsResponse(collections=[CollectionDescription(name='news-articles')])

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

Генерация точек-векторов

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

  • id: идентификатор вектора (в случае NPR это newsId)
  • vector: одномерный массив, представляющий вектор (сгенерированный моделью вложений)
  • payload: словарь, содержащий любую другую существенную метаданные, которые затем можно использовать для запроса векторов в коллекции (в случае NPR – заголовок, содержание и теги статьи)
from qdrant_client.http.models import PointStructmetadata_columns = df.drop(["newsId", "sentence", "sentence_embedding"], axis=1).columnsdef create_vector_point(item:pd.Series) -> PointStruct:    """Преобразование векторов в PointStruct"""    return PointStruct(        id = item["newsId"],        vector = item["sentence_embedding"].tolist(),        payload = {            field: item[field]            for field in metadata_columns            if (str(item[field]) not in ['None', 'nan'])        }    )points = df.apply(create_vector_point, axis=1).tolist()

Загрузка векторов

Наконец, после того как все элементы превращены в структуры точек, мы можем загрузить их порциями в базу данных:

CHUNK_SIZE = 500n_chunks = np.ceil(len(points)/CHUNK_SIZE)for i, points_chunk in enumerate(np.array_split(points, n_chunks)):    client.upsert(        collection_name="news-articles",        wait=True,        points=points_chunk.tolist()    )

3. Поиск векторов

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

  • Текстовый запрос
  • ID вектора

3.1 Поиск векторов с помощью входного вектора

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

Поскольку все операции в векторной базе данных выполняются с помощью … ВЕКТОРОВ, нам сначала нужно преобразовать текстовый запрос пользователя в вектор, чтобы мы могли найти похожие элементы на основе этого запроса. Напомним, что мы использовали Sentence Transformers для кодирования текстовых данных в эмбеддинги, поэтому мы можем использовать тот же самый кодировщик для создания числового представления вводного текста пользователя.

Поскольку в NPR содержатся новостные статьи, допустим, что пользователь ввел “Дональд Трамп” для изучения выборов в США:

query_text = "Дональд Трамп"query_vector = encoder.encode(query_text).tolist()print (query_vector)# выход: [-0.048, -0.120, 0.695, ...]

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

from qdrant_client.models import Filterfrom qdrant_client.http import modelsclient.search(    collection_name="news-articles",    query_vector=query_vector,    with_payload=["newsId", "title", "topics"],    query_filter=None)

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

После выполнения этой операции, вот сгенерированные заголовки результатов (переведенные на английский для лучшего понимания):

  • Входное предложение: Дональд Трамп
  • Результат 1: Парагвайцы идут на выборы в эту воскресенье (30) для выбора нового президента
  • Результат 2: Голосующие считают, что Байден и Трамп не должны участвовать в 2024 году, показывает опрос Reuters/Ipsos
  • Результат 3: Писатель обвиняет Трампа в сексуальных домогательствах в 1990-х годах
  • Результат 4: Майк Пенс, бывший вице-президент Дональда Трампа, дает показания в суде, что может осложнить положение бывшего президента

Похоже, что помимо новостей, связанных с самим Трампом, модель вставки также смогла представить темы, связанные с президентскими выборами. Обратите внимание, что в первом результате нет прямой ссылки на входной термин “Дональд Трамп”, кроме президентских выборов.

Также я опустил параметры query_filter. Это очень полезный инструмент, если вы хотите задать условие, которому должен удовлетворять результат. Например, в новостном портале часто важно фильтровать только самые свежие статьи (скажем, с последних 7 дней). Поэтому вы можете искать новостные статьи, удовлетворяющие минимальной временной метке публикации.

Примечание: в контексте рекомендации новостей существует несколько аспектов, требующих внимания, таких как справедливость и разнообразие. Это открытая тема для дискуссии, но если вас интересует этот вопрос, ознакомьтесь с материалами из семинара NORMalize.

3.2 Поиск векторов с помощью ID входного вектора

Наконец, мы можем попросить векторную базу данных “рекомендовать” элементы, которые ближе к некоторым желаемым идентификаторам векторов, но далеко от нежелательных идентификаторов векторов. Желаемые и нежелательные идентификаторы называются положительными и отрицательными примерами соответственно, и они рассматриваются как семена для рекомендации.

Например, предположим, у нас есть следующий положительный идентификатор:

seed_id = '8bc22460-532c-449b-ad71-28dd86790ca2'# название (переведено): 'Узнайте, почему Джо Байден объявил о своей кандидатуре на повторные выборы в этот вторник'

Затем мы можем запросить элементы, похожие на этот пример:

client.recommend(    collection_name="news-articles",    positive=[seed_id],    negative=None,    with_payload=["newsId", "title", "topics"])

После выполнения этой операции, вот переведенные заголовки вывода:

  • Входной элемент: Узнайте, почему Джо Байден объявил о своей кандидатуре на повторные выборы в этот вторник
  • Вывод 1: Байден объявляет о своем намерении участвовать в повторных выборах
  • Вывод 2: США: 4 причины, по которым Байден решил участвовать в повторных выборах
  • Вывод 3: Исследование Reuters/Ipsos: избиратели считают, что Байден и Трамп не должны участвовать в выборах 2024 года
  • Вывод 4: Ошибка советника Байдена, которая вызвала сомнения о возможном втором правительстве после выборов

Заключение

Эта статья демонстрирует, как комбинировать LLM и векторные базы данных для предоставления рекомендаций. В частности, Sentence Transformers использовались для генерации числовых представлений (вложений) из текстовых новостных статей в наборе данных NPR. После вычисления этих вложений они могут заполнять векторную базу данных, такую ​​как Qdrant, которая облегчает запросы векторов на основе нескольких стратегий.

После примеров в этой статье можно сделать множество улучшений, таких как:

  • тестирование других моделей вложений
  • тестирование других метрик расстояния
  • тестирование других векторных баз данных
  • использование компилируемых языков программирования, таких как Go, для более высокой производительности
  • создание API для предоставления рекомендаций

Другими словами, возникает множество идей для улучшения машинного обучения инженерии рекомендаций с использованием LLM. Если у вас есть идеи об этих улучшениях, не стесняйтесь прислать мне сообщение здесь 🙂

Обо мне

Я являюсь старшим специалистом по обработке данных в компании Globo, бразильской медиатехнологической компании. Работая в команде по рекомендациям компании, я работаю в окружении удивительной и талантливой команды, которая приложила много усилий для предоставления персонализированного контента миллионам пользователей через цифровые продукты, такие как G1, GE, Globoplay и многие другие. Эта статья не могла бы быть возможной без их неоценимых знаний.

Ссылки

[1] N. reimers и I. Gurevych, Sentence-BERT: представление предложений с использованием Siamese BERT-Networks (2019), Ассоциация вычислительной лингвистики.

[2] J. Pinho, J. Silva и L. Figueiredo, NPR: набор данных для рекомендации новостного портала (2023), Конференция ACM по рекомендательным системам

[3] V. Boykis, Что такое вложения?, персональный блог

[4] M. Ali, Топ-5 векторных баз данных (2023), блог DataCamp