📱 Мобильное машинное обучение

Q-Learning в среде Frozen Lake в Android

Создайте Python-подобную среду и агента с помощью Kotlin

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

Q-обучение простое, потому что оно работает без нейронной сети (то, что с нейронной сетью, становится глубоким Q-обучением). Мы обновляем таблицу Q, которая служит картой для нашего агента, т. Е. Сообщает нашему агенту, какое действие выполнять в каком состоянии, чтобы получить максимальное вознаграждение.

Вы можете найти проект GitHub здесь:



Прежде чем мы начнем…

В этой статье предполагается, что читатели знакомы с такими терминами, как событие, действие, эпизод и вознаграждение в контексте обучения с подкреплением. Были бы полезны базовые знания Q-обучения. Впереди вы увидите реализацию среды Frozen Lake, которая очень похожа на Open AI’s Gym в Python.

Поскольку это проект Android, вы увидите гораздо больше кода в репозитории GitHub, чем в приведенных ниже фрагментах: код, который обновляет пользовательский интерфейс в качестве агента, выполняющего действие, не записывается во фрагментах кода. Кроме того, вы увидите Kotlin Coroutines в действии. Чтобы сосредоточиться только на части Q-обучения, я удалил эти строки (они присутствуют в репозитории GitHub) из приведенных ниже фрагментов, чтобы избежать путаницы и улучшить читаемость.

Итак, хватит оговорок! Вперед!

Создание среды замерзшего озера

Сначала мы взглянем на среду Frozen Lake, как указано в документации OpenAI’s Gym.

По сути, у нас есть начальная точка (обозначенная как S), конечная точка (G) или цель и четыре лунки. Итак, наша среда будет представлять собой матрицу 4 * 4 с этими состояниями. Но какие элементы (а точнее 16) мы должны оставить в этой матрице?

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

Итак, наша матрица будет выглядеть так:

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

Подождите, у меня вопрос…

«Если агент находится в первой ячейке от первой строки, он не может двигаться вверх или влево»

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

Теперь перейдем к коду. Обратите внимание: классы Matrix и MatrixOps, которые вы увидите, являются вспомогательными классами для обработки различных операций с матрицами. Я не буду публиковать здесь их код. Вы можете просмотреть эти классы здесь, в исходном коде.

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

См. Изображение ниже, чтобы понять положение различных состояний.

Также у нас есть индексы для наших четырех действий:

Затем мы создаем класс FrozenLakeEnv для хранения всех методов и переменных, необходимых агенту.

Переменные agentPosX и agentPosY представляют собой отправную точку для нашего агента. Это состояние (0, 0) в нашем envMatrix. Эти переменные будут обновляться по мере перемещения агента в среде.

Нам также понадобятся несколько вспомогательных методов:

  • actionSpaceSample(): похоже на то, что вы, возможно, видели в Python при использовании gym, т.е. gym.actionSpace.sample(). Таким образом, он возвращает случайное целое число из (0, 4), которое будет представлять действие.
  • reset(): сбрасывает среду. Это аналог метода env.reset() в Python. Позиция агента установлена ​​на (0, 0), которая представляет начальную позицию, то есть ячейку S.
  • getStateFromPos(): получает целое число из (0, 16), которое уникально для каждого состояния с учетом текущего положения агента.

  • getReward(): получает награду за действие, только что выполненное агентом. Он использует envMatrix, который мы создали ранее.

Подождите, у меня вопрос…

«Почему мы не используем положение агента (в координатах X и Y) в качестве состояний?»

Текущее состояние нам понадобится много раз, особенно при обновлении таблицы Q с помощью уравнения Беллмана. Наша таблица Q представляет собой матрицу размером 16 × 4, где 16 - это количество состояний, а 4 - количество действий. Чтобы обновить эту таблицу с помощью индексации, подобной Q [2, 3], нам потребуется целое число для каждого состояния. Таким образом, целое число для конкретного состояния также является индексом состояния в таблице Q 16 × 4.

Теперь самое интересное. Мы собираемся закодировать метод env.step(), который будет выполнять действие и возвращать новое состояние, а также вознаграждение.

Код для метода step:

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

Оператор if фактически отвечает на наш первый вопрос, т. Е. Проверяет правильность действий. Позвольте мне объяснить это. Если агент находится в позиции (0, 0) и выполняется ACTION_LEFT, агент, таким образом, должен иметь позицию (-1, 0), что мы не нужно. Вы заметите, что любые недопустимые действия приведут к координатам, которых нет в [ 0, 1, 2, 3 ], верно?

Поскольку мы не можем возвращать несколько значений из метода в Kotlin, мы будем использовать класс EnvOutput, в котором хранятся три значения: newState, reward и isTerminated.

В строке нет. 21, мы можем заметить, что значение isTerminated будет reward == -1.0. Помните, что при создании envMatrix награда -1 представляет собой дыру, которая указывает на конец эпизода.

Реализация алгоритма Q-Learning

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

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

Вот наш алгоритм:

α - скорость обучения, а γ - коэффициент дисконтирования. S - это состояние, которого агент достигнет, если будет выполнено действие a’. Вычисляется максимум всех значений Q для s ’ и a’. R (s, a) возвращает награду за действие a и в состоянии s.

«Может ли кто-нибудь дать мне интуитивное представление о скорости обучения и коэффициенте дисконтирования?»

Мы понимаем их важность с помощью простой техники. Попробуйте заменить 1 на α. Оба условия Q (s, a) сокращаются. Таким образом, теперь значения Q будут обновляться только с учетом текущего вознаграждения R (s, a) и максимального Q ’(s’, a ’). Итак, альфа контролирует, насколько мы должны зависеть от предыдущего значения Q для обновления текущего значения Q.

Аналогичным образом заменим 0 на γ. Я знаю, что в этом нет особого смысла, но мы ясно видим, что теперь агент не учитывает будущие значения Q. Таким образом, γ помогает нашему агенту выбрать подходящее действие для текущего состояния с учетом значений Q для s ’.

Итак, α и γ инициализируются в строках 4 и 7.

Чтобы понять следующую переменную (т.е. строку № 10), нам нужно сначала понять исследование и эксплуатацию.



Чтобы решить проблему со средой Frozen Lake, нашему агенту необходимо сначала изучить всю среду, чтобы он мог обновить таблицу Q, чтобы он не упал в одну из дыр.

Исследование

Мы хотим, чтобы наш агент выполнял случайные действия (иногда), чтобы он мог найти новые способы достижения цели G. Почему только случайные действия? Потому что, выполняя случайные действия в любом состоянии, агент может предпринять действие, не предписанное Q-таблицей.

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

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

Эксплуатация

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

Почему мы не можем просто исследовать или использовать окружающую среду?

Рассмотрим первый случай. Если наш агент только исследует среду, он вообще не слушает своего хозяина (опять же, таблицу Q)! В конце концов, он упадет в яму. Он определенно получит знания, но цель агента - не просто получить знания, но и использовать их для достижения цели.

Далее, если наш агент использует только свою среду, он просто перемещается в одном месте. Он никогда не узнает, что в позиции (3, 3) есть дыра.

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

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

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

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

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

Теперь идет самый важный фрагмент кода - реализация уравнения Беллмана для обновления таблицы Q.

  • В строке нет. 10, мы сбрасываем нашу среду, чтобы привести агента в исходное положение.
  • Из строки № 16-21, мы выбираем действие, используя жадную стратегию эпсилон.
  • Мы выполняем выбранное действие в окружении в строке № 24.
  • Обновите таблицу Q, используя уравнение Беллмана в строке № 27.
  • Разорвать петлю, если эпизод прерван (наш агент упал в яму). Это будет экземпляром 2-го эпизода. (Строки 34 и 35).

Вот и все, мы завершили внедрение агента обучения Q на Android! 🥳

Дальнейшее чтение

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

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

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

Если вы хотите внести свой вклад, отправляйтесь на наш призыв к участникам. Вы также можете подписаться на наши еженедельные информационные бюллетени (Deep Learning Weekly и Comet Newsletter), присоединиться к нам в » «Slack и подписаться на Comet в Twitter и LinkedIn для получения ресурсов, событий и гораздо больше, что поможет вам быстрее и лучше строить модели машинного обучения.