Как создать рекомендательную систему машинного обучения с помощью TensorFlow и HarperDB


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

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

Введение в рекомендательные системы

Рекомендательные системы — это самый распространенный тип машинного обучения. Мы взаимодействуем с ними повсеместно, и они стали движущей силой того, как мы изучаем новый контент. И хотя некоторые из них не столь совершенны, даже самые незначительные из них намного превосходят предыдущие методы поиска новых вещей.

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

Все эти методы работали, но они ограничивали нас. Мы могли по-настоящему исследовать только тот контент, который был доступен в данной системе — например, канал предварительного просмотра, радиостанция, полки книжного магазина. Но сейчас, особенно сегодня, существует гораздо больше контента. Поэтому вместо того, чтобы выбирать из ограниченных вариантов, представленных в разделе «Бестселлеры» в книжном магазине, как найти новый контент, основанный на индивидуальных интересах?

Рекомендательные системы!

Что такое рекомендательная система? Как они работают?

Рекомендательные системы — это именно то, чем они кажутся; это система, которая дает рекомендации. Вы даете ей представление о том, что вам нравится, и она направляет вас в сторону других вещей, которые могут вам понравиться.

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

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

Сложность возникает из-за меняющегося характера контента. Как новая песня, книга или продукт могут попасть в результаты работы рекомендательной системы?

Использование машинного обучения

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

Здесь на помощь приходит машинное обучение. Используя такие библиотеки, как TensorFlow Recommenders с моделями Keras, легко сформировать данные таким образом, чтобы можно было рассматривать и сравнивать элементы и пользователей в многомерной перспективе. Качественные характеристики, такие как категории товаров и атрибуты профиля пользователя, могут быть отображены в математические понятия, которые могут быть количественно сопоставлены друг с другом, что в конечном итоге позволит получить новые знания и лучшие рекомендации.

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

Рекомендатели HarperDB

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

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

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

HarperDB Song Recommender

Github repo: HarperDB/song-recommender

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

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

Есть хорошая подгруппа этих данных под названием The Echo Nest Taste Profile Subset, которая представляет собой список пользователей, песен и количества воспроизведений. Каждая строка данных содержит идентификатор пользователя, идентификатор песни и количество воспроизведений. Именно эти данные мы использовали для построения модели в данном проекте.

Обучение модели

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

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

Вторая башня — это башня кандидатов. В данном случае это пользователи в наборе данных.

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

Чтобы посмотреть на специфику обучения, вот блокнот обучения.

Основные шаги следующие:

  1. Найти самые воспроизводимые песни для каждого пользователя
  2. Создать пару запрос/кандидат из трех песен и пользователя ([songs], user).
  3. Постройте две модели и настройте метрики TFRS для обучения
  4. Введите запрос/кандидатскую пару в модель.
  5. Когда обучение будет завершено, создайте новую модель, которая объединит две вышеупомянутые.
  6. Примените метод BruteForce для извлечения наилучшего кандидата, предоставленного на вход.

Генерация данных

# create a dictionary of inputs and outputs
dataset = {'songs': [], 'user': []}
for user, songs in users_songs.items():
    for _ in range(len(songs) * 5):
        # randomly select n_songsns_in from the user's isbns
        selected_songs = np.random.choice(songs, n_songs_in)
        # add them to the inputs
        dataset['songs'].append(selected_songs)
        # add the user to the output
        dataset['user'].append(user)

Войдите в полноэкранный режим Выйти из полноэкранного режима

Построение моделей

# create the query and candidate models
n_embedding_dimensions = 24

## QUERY
songs_in_in = tf.keras.Input(shape=(n_songs_in))
songs_in_emb = tf.keras.layers.Embedding(n_songs+1, n_embedding_dimensions)(songs_in_in)
songs_in_emb_avg = tf.keras.layers.AveragePooling1D(pool_size=3)(songs_in_emb)
query = tf.keras.layers.Flatten()(songs_in_emb_avg)
query_model = tf.keras.Model(inputs=songs_in_in, outputs=query)

## CANDIDATE
user_in = tf.keras.Input(shape=(1))
user_emb = tf.keras.layers.Embedding(n_users+1, n_embedding_dimensions)(user_in)
candidate = tf.keras.layers.Flatten()(user_emb)
candidate_model = tf.keras.Model(inputs=user_in, outputs=candidate)
Войти в полноэкранный режим Выход из полноэкранного режима

Создание задачи TensorFlow Recommenders Task

# TFRS TASK SETUP
candidates = dataset.batch(128).map(lambda x: candidate_model(x['user']))
metrics = tfrs.metrics.FactorizedTopK(candidates=candidates)
task = tfrs.tasks.Retrieval(metrics=metrics)


## TFRS MODEL CLASS
class Model(tfrs.Model):
    def __init__(self, query_model, candidate_model):
        super().__init__()
        self._query_model = query_model
        self._candidate_model = candidate_model
        self._task = task

    def compute_loss(self, features, training=False):
        query_embedding = self._query_model(features['songs'])
        candidate_embedding = self._candidate_model(features['user'])
        return self._task(query_embedding, candidate_embedding)

## COMPILE AND TRAIN MODEL
model = Model(query_model, candidate_model)
# load model weights - this is to resume training
# model._query_model.load_weights(weights_dir.format('query'))
# model._candidate_model.load_weights(weights_dir.format('candidate'))

model.compile(optimizer=tf.keras.optimizers.Adagrad(learning_rate=0.1))
model.fit(dataset.repeat().shuffle(300_000).batch(4096), steps_per_epoch=50, epochs=30, verbose=1)
Войти в полноэкранный режим Выйти из полноэкранного режима

Развертывание модели

Чтобы развернуть эту модель, последним шагом в приведенном выше блокноте является преобразование ее в TensorFlowJS.

После этого мы добавляем ее в каталог Custom Function вместе с логикой в файле recommend.js, который преобразует три любимые песни пользователя в тензоры, предоставляемые модели.

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

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

Создание входного тензора и получение результатов

 if (!this.model) {
   const modelPath = path.join(__dirname, '../', 'tfjs-model', 'model.json');
   this.model = await tf.loadGraphModel(`file://${modelPath}`);
 }

 const inputTensor = tf.tensor([songIdxs], [1, 3], 'int32')
 const results = this.model.execute(inputTensor)
 const r0 = await results[0].data()
Вход в полноэкранный режим Выход из полноэкранного режима

Книжный рекомендатель HarperDB

Github repo: HarperDB/book-recommender

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

На Kaggle есть набор данных, включающий список пользователей, книг и оценок для около 250 000 различных наименований.

Обучение модели

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

Первая башня — это башня запросов. В данном случае это три книги, которые пользователь оценил высоко (5 и выше из 10).

Вторая башня — это башня кандидатов. В данном случае это пользователи в наборе данных.

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

Чтобы посмотреть на специфику обучения, вот блокнот обучения.

Основные шаги следующие:

  1. Найти книги с наивысшим рейтингом для каждого пользователя
  2. Создать пару запрос/кандидат из трех книг и пользователя ([books], user).
  3. Построить две модели и настроить метрики TFRS для обучения
  4. Введите пару запрос/кандидат в модель.
  5. Когда обучение будет завершено, создайте новую модель, которая объединит две вышеупомянутые.
  6. Примените метод BruteForce для извлечения наилучшего кандидата, предоставленного на вход.

Генерация данных

# create a dictionary of inputs and outputs
dataset = {'isbns': [], 'user': []}
for user_id, isbns in user_isbns.items():
    # use 5x the number of isbns gathered for the user
    # this ensures a larger amount of training data
    for _ in range(len(isbns) * 5):
        # randomly select n_isbns_in from the user's isbns
        selected_isbns = np.random.choice(isbns, n_isbns_in)
        # add them to the inputs
        dataset['isbns'].append(selected_isbns)
        # add the user to the output
        dataset['user'].append(user_idxs[user_id])


Войдите в полноэкранный режим Выйти из полноэкранного режима

Построение моделей

# create the query and candidate models
n_embedding_dimensions = 24

## QUERY
isbns_in_in = tf.keras.Input(shape=(n_isbns_in))
isbns_in_emb = tf.keras.layers.Embedding(n_isbns+1, n_embedding_dimensions)(isbns_in_in)
isbns_in_emb_avg = tf.keras.layers.AveragePooling1D(pool_size=3)(isbns_in_emb)
query = tf.keras.layers.Flatten()(isbns_in_emb_avg)
query_model = tf.keras.Model(inputs=isbns_in_in, outputs=query)

## CANDIDATE
isbns_out_in = tf.keras.Input(shape=(1))
isbns_out_emb = tf.keras.layers.Embedding(n_users+1, n_embedding_dimensions)(isbns_out_in)
candidate = tf.keras.layers.Flatten()(isbns_out_emb)
candidate_model = tf.keras.Model(inputs=isbns_out_in, outputs=candidate)

Войти в полноэкранный режим Выход из полноэкранного режима

Создание задачи TensorFlow Recommenders Task

# TFRS TASK SETUP
candidates = dataset.batch(128).map(lambda x: candidate_model(x['user']))
metrics = tfrs.metrics.FactorizedTopK(candidates=candidates)
task = tfrs.tasks.Retrieval(metrics=metrics)


## TFRS MODEL CLASS
class Model(tfrs.Model):
    def __init__(self, query_model, candidate_model):
        super().__init__()
        self._query_model = query_model
        self._candidate_model = candidate_model
        self._task = task

    def compute_loss(self, features, training=False):
        query_embedding = self._query_model(features['isbns'])
        candidate_embedding = self._candidate_model(features['user'])
        return self._task(query_embedding, candidate_embedding)

## COMPILE AND TRAIN MODEL
model = Model(query_model, candidate_model)
# load model weights - this is to resume training
# model._query_model.load_weights(weights_dir.format('query'))
# model._candidate_model.load_weights(weights_dir.format('candidate'))

model.compile(optimizer=tf.keras.optimizers.Adagrad(learning_rate=0.1))
model.fit(dataset.repeat().shuffle(300_000).batch(4096), steps_per_epoch=50, epochs=30, verbose=1)

Войти в полноэкранный режим Выйти из полноэкранного режима

Создание задачи сравнения методом перебора

# create the index model to lookup the best candidate match for a query
index = tfrs.layers.factorized_top_k.BruteForce(model._query_model)
index.index_from_dataset(
    tf.data.Dataset.zip((
      dataset.map(lambda x: x['user']).batch(100),
      dataset.batch(100).map(lambda x: model._candidate_model(x['user']))
    ))
)
for features in dataset.shuffle(2000).batch(1).take(1):
    print('isbns', features['isbns'])
    scores, users = index(features['isbns'])
    print('recommended users', users)
Войти в полноэкранный режим Выйти из полноэкранного режима

Развертывание модели

Чтобы развернуть эту модель, последним шагом в приведенном выше блокноте является преобразование ее в TensorFlowJS.

Оттуда мы добавляем его в каталог Custom Function вместе с логикой в recommend.js, которая преобразует три любимые книги пользователя в тензоры, предоставляемые модели.

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

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

Подведение итогов

Вот как можно создать систему рекомендаций с помощью пользовательских функций HarperDB.

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

Запустите экземпляр HarperDB с Custom Functions, где вы можете получить одну из этих репозиториев и получить рекомендации по новым песням и книгам, которые стоит посмотреть. Если вы получите интересный результат, который вам понравится, пожалуйста, дайте нам знать!

Спасибо за чтение,

-Кевин

Оцените статью
devanswers.ru
Добавить комментарий