Часть 1: Определение среды, поиск оптимальной политики с помощью итераций значений и введение Q-Learning

Резюме

В этой статье я представлю новый проект, который пытается помочь тем, кто изучает обучение с подкреплением, путем полного определения и решения простой задачи в записной книжке Python. Среда и основные методы будут объяснены в этой статье, а весь код опубликован на Kaggle по ссылке ниже. Кроме того, я создал записную книжку «Мета», которую можно легко разветвлять и которая содержит только определенную среду, чтобы другие могли попробовать, адаптировать и применить свой собственный код.



Контекст

Когда я впервые начал изучать обучение с подкреплением, я сразу начал копировать онлайн-руководства и проекты, но обнаружил, что теряюсь и сбиваюсь с толку. «Почему результаты показывают это? Что делает этот параметр? Что окружающая среда действует таким образом? » вот некоторые из вопросов, которые я начал задавать себе. И только после того, как я сделал шаг назад и начал с основ полного понимания того, как определяется вероятностная среда, и создания небольшого примера, который я мог решить на бумаге, все стало иметь больше смысла. Однако мне было трудно найти среды, в которых я мог бы применить свои знания, которые не нужно было импортировать из внешних источников.

Поэтому я поставил перед собой задачу:

Могу ли я полностью определить и найти оптимальные действия для среды задач, полностью автономных в записной книжке Python?

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

Этап 1: определение среды

Задание

Проще говоря, я хочу знать, как лучше всего выбросить лист бумаги в корзину (мусорное ведро) из любого места в комнате. Я могу бросать бумагу в любом направлении или двигаться по одному шагу за раз.

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

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

Например, на изображении ниже у нас есть три человека, обозначенные A, B и C. Оба игрока A и B бросают в правильном направлении, но человек A находится ближе, чем B, и поэтому у него будет более высокая вероятность попадания.

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

Чтобы создать среду на Python, мы преобразуем диаграмму в двумерные измерения значений x и y и используем математику пеленга для вычисления брошенных углов. Мы использовали нормализованные целочисленные значения x и y, поэтому они должны быть ограничены -10 и 10.

Вероятность окружающей среды

Вероятность успешного броска зависит от расстояния и направления, в котором он был брошен. Следовательно, нам нужно рассчитать две меры:

  • Расстояние, на котором текущая позиция находится от корзины
  • Разница между углом, под которым была брошена бумага, и истинным направлением в корзину

Измерение расстояния
Как показано на графике выше, положение человека A установлено равным (-5, -5). Это их текущее состояние, и их расстояние от корзины можно рассчитать с помощью меры евклидова расстояния:

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

Поскольку мы зафиксировали наши двумерные измерения между (-10, 10), максимально возможное расстояние, на котором может находиться человек, составляет sqrt {(100) + (100)} = sqrt {200} от корзины. Следовательно, наша оценка расстояния для человека A:

Направление

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

Следовательно, первый бросок отклоняется от истинного направления на 5 градусов, а второй - на 15 градусов.

Если учесть, что хорошие броски ограничены 45 градусами по обе стороны от фактического направления (т.е. не в неправильном направлении), то мы можем использовать следующее, чтобы вычислить, насколько хорошо это выбранное направление. Любое направление, выходящее за пределы 45 градусов, даст отрицательное значение и будет сопоставлено с вероятностью 0:

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

Расчет вероятности

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

Создание обобщенной функции вероятности

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

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

Это показано на диаграмме ниже, где мы обобщили все тригонометрические вычисления на основе относительного положения человека по отношению к корзине:

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

Затем мы вычисляем азимут от человека к мусорному ведру, следуя предыдущему рисунку, и вычисляем оценку в пределах диапазона +/- 45 градусов. Броски, наиболее близкие к истинному пеленгу, получают больше очков, в то время как дальние броски получают меньше очков, все, что больше 45 градусов (или меньше -45 градусов), является отрицательным, а затем устанавливается нулевое значение вероятности.

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

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

Мы пересчитываем предыдущие примеры и получаем те же результаты, что и ожидалось.

Построение вероятностей для каждого состояния

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

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

Например, вероятность того, что бумага будет брошена под углом 180 градусов (на юг) для каждого положения x / y, показана ниже.

Анимированный график для всех направлений броска

Чтобы продемонстрировать это дальше, мы можем перебрать несколько направлений броска и создать интерактивную анимацию. Код становится немного сложным, и вы всегда можете просто использовать предыдущий фрагмент кода и вручную изменить параметр «throw_direction», чтобы исследовать различные позиции. Однако это помогает исследовать вероятности и может быть найдено в записной книжке Kaggle.



Этап 2: поиск оптимальной политики для среды, вероятности которой известны

Модельные методы

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

Итерация значений начинается с произвольной функции V0 и использует следующие уравнения, чтобы получить функции для k + 1 этапов, чтобы перейти от функций для k этапов (https://artint.info/html/ArtInt_227.html).

Расчет действий MOVE довольно прост, потому что я определил гарантированную вероятность успеха перемещения (равную 1). Следовательно, значение Q, например, действия (1,1) из состояния (-5, -5) равно:

Q ((- 5, -5), MOVE (1,1)) = 1 * (R ((- 5, -5), (1,1), (- 4, -4)) + гамма * V ( -4, -4)))

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

Q ((- 5, -5), (1,1)) = 1 * (0 + гамма * 0) = 0

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

Q ((- 5, -5), БРОСИТЬ (50)) =

0,444 * (R ((- 5, -5), (50), bin) + гамма * V (bin +))) +

(1–0,444) * (R ((- 5, -5), (50), bin) + гамма * V (bin-)))

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

Q ((- 5, -5), БРОСИТЬ (50)) =

0,444 * (0 + гамма * 1) +

(1–0,444) * (0 + гамма * 1) = 0,3552–0,4448 = -0,0896

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

После вычисления каждого Q (s, a) для всех состояний и действий значение каждого состояния, V (s), обновляется как максимальное значение Q для этого состояния. Процесс повторяется взад и вперед, пока результаты не сойдутся.

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

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

Улучшение визуализации оптимальной политики

Хотя диаграмма показывает, является ли оптимальным действием бросок или движение, она не показывает нам, в каком направлении они находятся. Поэтому мы сопоставим каждое оптимальное действие с вектором u и v и будем использовать их для создания графика колчана ( Https://matplotlib.org/api/_as_gen/matplotlib.axes.Axes.quiver.html).

Мы определяем масштаб стрелок и используем его для определения горизонтальной составляющей, обозначенной u. Для движущихся действий мы просто умножаем движение в направлении x на этот коэффициент, а для направления броска мы перемещаемся на 1 единицу влево или вправо (с учетом отсутствия горизонтального движения на 0 или 180 градусов и отсутствия вертикального движения на 90 или 270 градусов). .

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

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

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

Этап 3: поиск оптимальной политики с помощью обучения с подкреплением, где вероятности скрыты

Алгоритм Q-обучения

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

Во-первых, давайте попробуем найти оптимальное действие, если человек начинает в фиксированном положении, а корзина фиксируется на (0,0), как и раньше.

Мы будем применять Q-обучение и инициализировать все пары состояние-действие значением 0 и использовать правило обновления:

Мы даем алгоритму выбор: бросить в любом направлении на 360 градусов (на целый градус) или переместиться в любую позицию, окружающую текущую. Таким образом, есть 8 мест, куда он может перемещаться: север, северо-восток, восток и т. Д.

Когда он решает бросить бумагу, он получит либо положительную награду +1, либо отрицательную -1 в зависимости от того, попадет ли она в корзину или нет, и эпизод закончится.

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

Псевдокод Q-Learning

Сначала, как и раньше, инициализируем Q-таблицу произвольными значениями 0.

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

Каждый эпизод заканчивается естественным образом, если брошен лист бумаги, действие, выполняемое алгоритмом, определяется процедурой выбора эпсилон-жадного действия, при которой действие выбирается случайным образом с эпсилон-вероятностью и жадно (текущий максимум) в противном случае. Чтобы немного сбалансировать случайный выбор между действиями движения или броска (так как есть только 8 действий движения, но 360 действий броска), я решил дать алгоритму шанс 50/50 движения или броска, а затем впоследствии выберет действие случайным образом из них.

Как и раньше, действие случайного движения не может выходить за пределы комнаты, и, обнаружив, мы обновляем текущий Q (s, a) в зависимости от максимального Q (s ’, a) для всех возможных последующих действий. Например, если мы перейдем от -9, -9 к -8, -8, Q ((-9, -9), (1,1)) будет обновляться в соответствии с максимумом Q ((-8, -8 ), а) для всех возможных действий, в том числе и бросковых.

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

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

Мы проанализируем влияние различных параметров в следующем сообщении, а пока просто представим некоторые произвольные варианты выбора параметров:
- num_episodes = 100
- alpha = 0.5
- гамма = 0,5
- epsilon = 0,2
- max_actions = 1000
- pos_terminal_reward = 1
- neg_terminal_reward = -1

Запустив алгоритм с этими параметрами 10 раз, мы производим следующее «оптимальное» действие для состояний -5, -5:

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

Заключение

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

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

Если у вас есть какие-либо вопросы, не стесняйтесь оставлять комментарии ниже или на страницах Kaggle.

Спасибо

Фил