Недавно я работал над механизмом рекомендаций по изображениям, который должен был основываться на наборе данных, содержащем детали взаимодействия пользователей с изображениями, то есть, каким пользователям понравилось конкретное изображение. О ванильном подходе к этому я рассказал в этом посте. В этой статье я собираюсь обсудить, как Approximate KNN работает с ANNoy.

ANNoy — это библиотека Python, созданная людьми из Spotify, которая обеспечивает абстракцию над базовой реализацией ANN. Основная идея ANNoy или любых других приближенных ближайших соседей состоит в том, чтобы индексировать точки обучающих данных в форме, в которой они могут быть эффективно доступны для поиска. Например, в случае ANNoy используются случайные проекции для создания гиперплоскостей, которые используются для определения области, в которой существует одна или несколько точек. Поиск нужно выполнять только в пределах этого региона. Чтобы узнать больше о том, как работает ИНС, перейдите по этой ссылке.

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

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

В дополнение к этому мы собрали еще пару переменных:

  • item_id_set: это набор всех уникальных значений item_id. Мы будем использовать это для подготовки векторов на следующем шаге.
  • backup_df: как следует из названия, это должно действовать как резервная копия наших исходных данных.

Также следует отметить, что мы ограничили количество комбинаций пользователей и элементов до 2000, чтобы контролировать размерность.

На следующем шаге мы преобразуем приведенную выше форму данных в векторную форму:

Приведенный выше фрагмент кода преобразует набор данных в следующую векторную форму:

selection_vector содержит 1 для значений item_id, которые «понравились» пользователю, и 0 для значений item_id, на которые пользователь не отреагировал.

Вектор выбора здесь имеет более 10000 измерений, что делает работу с ним очень непрактичной. Следовательно, следующим шагом будет уменьшение размерности этих векторов. Есть несколько способов добиться этого, но, поскольку наши векторы очень разрежены, SVD или Singular Value Decomposition кажутся наиболее подходящими. Чтобы узнать больше о том, что такое SVD и как он работает, пожалуйста, перейдите по этой ссылке.

Приведенный выше фрагмент кода уменьшает количество измерений с более чем 10000 до 40 и оставляет нам что-то вроде следующего:

После того, как мы проверили размерность, давайте начнем с инициализации индекса ANNoy:

Приведенный выше фрагмент кода выполняет следующие действия:

  • Инициализирует AnnoyIndex с 40 измерениями, т. е. числом измерений в наших уменьшенных векторах.
  • Добавляет комбинацию всех user_id и векторов в индекс
  • Строит лес из 20 деревьев для облегчения ИНС.
  • Сохраняет индекс в файл с именем behance.ann.

Следующим шагом будет получение n ближайших соседей:

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

  1. Перейдите к нашему резервному фрейму данных, который мы создали на первом шаге.
  2. Получить список вещей, которые понравились ближайшим соседям
  3. Удалите любой item_id, который уже понравился текущему пользователю
  4. Вернуть список рекомендаций item_id

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