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

Задача: Название пошло от "одноруких бандитов". Так называли игровые автоматы с ручками-рычагами, потянув за которые можно получить выигрыш. Таких автоматов много, но вы заранее не знаете, какой автомат дает наибольший выигрыш. Проблема "многоруких бандитов" заключается в том, чтобы найти автомат с максимальным выигрышем с минимальными потерями.

В нашем случае бандитами являются стратегии предсказания цен, а выигрыш - какая-то целевая метрика (маржа, например)

Как нам сравнивать эффективность стратегий? $$ R_{opt} - \text{оптимальная награда} \\ R_{strategy} - \text{награда за выбранную нами стратегию} \\ \mathrm{regret} = R_{opt} - R_{strategy} - \text{недополученная прибыль/метрика} $$

Ниже мы построим класс Стратегий и затем рассмотрим 2 популярных стратегии: $\varepsilon$-жадную и UCB (Upper Conifidence Bound)

Базовый класс стратегии будет сожержать следующие атрибуты n_arms - количество ручек для "дерганья", n_iters - количество доступных итераций, arms_states - пространство состояний ручек, arms_actions - пространство действий для ручек.

Тажке этот базовый класс будет содержать метод flush() для обновления стратегии, метод update_reward() - функция для оновления стратегии, где учитываются действия и получаемые награды, и метод choose_arm() для непосредственно выбора "ручки бандита", которую мы оставим нереализованной, с условием обязательной реализации для классов-потомков с помощью NotImplementedError

$\varepsilon$-жадная стратегия

Первой мы рассмотрим $\varepsilon$-жадную стратегию, в основе которого лежил простой принцип - всегда выбираем "ручку", которая дает наибольшую награду. Стратегии различаются в том, как мы исследуем среду.

Стратегия имеет единственный параметр: $\varepsilon$ - вероятность выбора не лучшей "ручки", а случайной для исследования среды. Можно в принципе уменьшать эту вероятность со временем ($\varepsilon$-decreasing).

Давайте посмотрим на соответствующий класс:

Он имеет единственный параметр - вероятность выбора случайно ручки - eps

Вторая стратегия называется UCB1 - оптимизация с исзпользованием знаний об неопределенности. Строится оптимистическое предположение о том, насколько хорош желаемый результат для каждого действия. Дальше выбирается действие с наибольшим предполагаемым выигрышем. Если же наше предположение оказалось неверным, то наша оценка уменьшается и мы переключаемся на другое действие. Но если же выбор был сделан верным, то наше значение величины $\mathrm{regret}$ будет мало. Таким образом мы уравновешиваем одновременно изучение бандитов и их эксплуатацию.

Основным вопрос является как раз задание этого оптимистичного прогноза - верхней доверительной гранциы (UCB). Для решения этой задачи на помощь приходит неравенство Чернова-Хёфдинга). Мы не будем сильно углубляться в теорию. Скажем лишь, что этот процесс детерминирован, а ручка определяется с помощью следующего критерия: $$ \mathrm{arm} = \mathrm{argmax}_{j} (\overline{x_j} + \sqrt{\frac{2\log{n}}{n_j}}) $$ Здесь $\overline{x_j}$ - средный выигрыш $j$-ой ручки и отвечает за эксплуатацию, а $\sqrt{\frac{2\log{n}}{n_j}}$ - отвечается за доверительный интервал, то есть разведку. $n_j$ - количество действий с $j$-ой ручки, а $n$ - суммарное количество итераций ($n = \sum_j n_j$)

В домашнем задании необходимо будет реализовать класс Thompson семплирования по Томпсону (см. прошлый урок).

Теперь же напишем класс среды. Мы будем использовать среду с случайными величинами Берунлли.

Теперь определим класс "бандитов". Основная задача класса - принять в себя среду и стратегию. В этом классе также содержится метод action(). Он выбирает ручку бандита изходя из стратегии, и дальше изходя их результата (награды) мы обновляем нашу стратегию

Напишем еще одну функцию calculate_regret() в которой будем считать наш $\mathrm{regret}$ в зависимости от среды env и стратегии strategy. В ней мы перезагружаем сратегии и бандитов, и на каждой итерации смотрим награду, смотрим оптимальную награду и записываем их в массив $\mathrm{regret}$-ов.

Определим нашу среду со следующими вероятностями: [0.3, 0.5, 0.7]. Также мы сделали 3 $\varepsilon$-жадных стратегии и UCB-стратегию

И посчитаем для каждый их этих стратегий $\mathrm{regret}$-ы

Теперь давайте построим график неколько $\mathrm{regret}$-ов (чем ниже, тем лучше)

Мы рассмотрели 2 достаточно популярные частотные стратегии: Upper Confidence Bound (UCB) и $\varepsilon$-жадную

Contextual bandits

Для знакомства с констекстуальными бандитами мы будем использовать 2 библиотеки. Установим ее

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

Сложность возникает, когда данные генерируются итеративно следующим образом: На каждой итерации мир/env создает наблюдение, состоящее из набора ковариат $X$ фиксированной размерности ($X$ - некоторое описание шагов, в которые был сделан выбор, и неекоторое описание действий), вектора вознаграждения $R$, который является стохастическим, но тоже зависит от ковариатов), $m$ - количество "ручек".

Аген должен выбрать "руку" или "метку" для наблюдения среди набора "ручек". В ответ среда показывает нам награду за выбранную ручку. Цель состоит в том, чтобы создать стратегию, которая миксимизирует вознаграждение, получаемое агентом. Ручки могут со временем пропадать или могут появляться новые.

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

Будем использовать "игрушечную" задачу, в который нам известна награда за все действия, чтобы познакомиться с методом

В данном случаем мы работаем с 2-мя группами клиентов. Каждый клиент описывается 2-мя характеристиками: H, ARPU

У нас есть клиенты (cutomers) и награды (rewards) которые представляют собой вектор из 3 возможных значений. По сути это 3 акции, которая компания может предложить. Первая - лучше всего подходит первой группе, третья лучше всего подходит второй группе, а вторая акция не является оптимально ни для одной из 2х групп.

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

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

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

Посмотрим на наших сгенерированных покупателей customers

Ну и посмотрим на награды rewards

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

Мы будем использовать линейную модель LinearBandits из space_bandits

Давайте теперь для модели построим разделяющую прямую, котоаря дели 2 облака покупателей, на основании моделирования

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

Есть один интересный момент: в регионах где нет или очень мало покупателей (сэмплов) модель может рекоммендовать полхую рекламу (2 стратегия) так как она не знает, что для того региона эта модель не походит

Давайте теперь посмотрим на Бандитов, моделирующих награду с помощью нейронной сети NeuralBandits

Как раз на картинке виден тот эффект "рекоммендации плохой для всех стратегии"

Есть еще одна библиотека для работы с контекстуальными бандитами

В целом она тоже очень популярная, но единственное ограничение это то, что награда может моделироваться только как дискретная и принимать значение только {0,1}. В целом такая библиотека тоже модет быть полезной для динамического ценообразования.