Рубрики
Без рубрики

Tic-Tac-Toe с табличным Q-обучением

Простая реализация обучения подкрепления Q-таблицы для Tic-Tac-Toe в Python. Помечено Python, Tictactoe, Q quelening, алгоритмы.

В последней статье мы реализовали решатель Tic-Tac-Toe с использованием MiniMax. MiniMax отлично, но у него есть пара вопросов. Прежде всего, в то время как он не делает ошибки, он также не в полном объеме узоров, которые могут быть найдены в движениях противника. Во-вторых, MiniMax часто не практично. Исторически, в случае шахматных вариантов, которые болтали различные эвристики на вершине минимакса, были на самом деле довольно успешны. Эти стратегии были достаточно хороши, чтобы построить шахматные двигатели, которые могут победить даже лучших человеческих игроков в мире. Ибо пойти, ситуация была менее удовлетворительной: До прорыва Deepmind с Alphago в 2015 году лучший AIS использовал поиск деревьев Монте-Карло (MCTS), близкого двоюродного брата MiniMax. Такой AIS сумел оценить как довольно сильные любительские игроки, но они не были нигде рядом с победой профессионального человека.

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

В этой статье мы реализуем Усиление укрепления Используя Tabular Q-обучение для Tic-Tac-Toe, шаг к применению таких идей к нейронным сетям. Как обучение домашнего животного, обучение подкреплениями – о предоставлении стимулов постепенно формировать желаемое поведение. Основная идея таблиц Q-обучение Просто: мы создаем таблицу, состоящую из всех возможных состояний на одной оси и все возможные действия на другой оси. Каждая ячейка в этой таблице имеет значение Q. Q-значение говорит нам, является ли это хорошей идеей или не принимать соответствующие действия из текущего состояния. Высокое значение Q хорошее, а низкое значение Q плохое. Диаграмма ниже показывает основную компоновку Q-таблицы:

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

Как мы обновляем значения наших пар государств в Q-Table? Q-обучение определяет функцию, которая позволяет нам итеративно обновлять значения Q в таблице. Если мы в данном состоянии, и мы принимаем конкретные действия, уравнение ниже показывает, как мы обновляем соответствующее значение q:

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

В случае экспоненциального скользящего среднего мы получим новое значение х T + 1 и подать заявку α , ценность между 0 и 1 к этому. α Определяет, насколько сильно повлияет новое значение. Чем ближе это значение для 1 , тем более внимательно экспоненциальный скользящий средний просто отслеживает входящие данные. Мы настраиваем текущее среднее (до обновления) по 1-α и новое среднее становится суммой этих двух терминов. Например, если α это 0,1 новое значение будет способствовать 10% обновленного среднего, и все предыдущие значения в сочетании будут вносят вклад 90% . Благодаря функции, которая обновляет значение Q, это та же идея: мы получаем обновление для нашего Q-значение Q для заданного пары состояния/действия и применить α к этому. Затем мы применяем 1-α к существующему Q-значению. Новое значение Q становится суммой этих двух значений. На диаграмме ниже мы можем видеть, как условия в функции обновления Q-значения соответствуют условиям в экспоненциальном скользящем среднем:

Для случая Tic-Tac-Toe, мне кажется, что нам на самом деле не нужно использовать скользящие средние – мы, вероятно, могли бы просто добавить новые значения в текущее общее количество. Я думаю, что имеет смысл выбрать этот подход, когда есть большое количество обновлений: экспоненциальный скользящий средний более численно стабилен. Кроме того, если мы работаем в домене, где значение для пары состояния/действия может сочетаться со временем, этот подход также позволяет нам оценить недавнюю информацию о более старой информации.

Давайте рассмотрим условия в функции обновления более подробно. Слева, мы назначаем новое значение Q для данного состояния/действия действия. Если мы знаем Q-значение во времени т новое значение Q соответствует времени T + 1 Отказ Справаемся, мы принимаем текущее значение Q для этого пары состояния/действия во времени т и умножить это 1-α. , и мы добавляем его в входящее обновление для значения Q, масштабируемого по α , показано ниже:

  • Когда мы принимаем данное действие из определенного состояния, мы идем в следующее государство, S T + 1 Отказ Переход в это новое состояние может заработать нам награду. Это ценность R T в вышеуказанном уравнении.
  • Мы также смотрим на Q-значения для всех возможных действий из нового состояния, S T + 1. , что мы входим после того, как мы возьмем наше действие А т . Мы выбираем максимальное значение Q для этого следующего состояния и используем его для обновления нашего текущего значения Q. Идея состоит в том, что наше значение Q также будет зависеть от лучшего значения Q, которое мы можем получить из следующего состояния (который зависит от состояния после этого и так далее).
  • Мы можем настроить максимальное значение Q из следующего состояния с помощью фактора дисконтирования γ (Гамма), между 0 и 1 Отказ Если γ Низкий, это означает, что мы ценим немедленные награды, обозначаемые R T , через будущие награды, как характеризуется Q-значениями последующих государств.

Таким образом, мы обновляем q-значение для заданного пары состояния/действия, используя экспоненциальный скользящий средний. Входящее обновление получается путем балансировки награды, полученной в текущем состоянии и максимальное значение Q из следующего состояния.

Крестики-нолики

Для приготовления табличного агента Q-Value для воспроизведения TIC-TAC-TOE, мы будем использовать позиции для платы в качестве состояний, а движения играют в качестве действий. Мы определим Q-значение для каждого такого состояния/пары действий, которую мы сталкиваемся. Когда мы достигаем состояния конца игр, результат игры – награда, назначенная на ходу, который привел к этому результату. Затем мы можем работать через историю игры и обновить значение Q для каждого действия, предпринятое агентом Q-Table во время игры. Диаграмма ниже показывает образцовую тренировку, где все значения Q-значения начинаются в 0 Отказ Для иллюстрации мы будем использовать высокую α 0,9 :

Х это агент Q-Table, и он обучен против О Игрок, который просто играет случайным образом. С X’s Последний шаг приводит к победе, мы даем это действие награду на +1 . Q-значение становится 0 + α * 1 или 0,9 Отказ Теперь мы можем обновить предыдущее действие в истории игры. Поскольку этот шаг не заканчивается игрой, нет прямой награды. Кроме того, поскольку награды назначены только для последних действий, предпринятых агентом Q-Table, я считаю, что мы можем установить коэффициент дисконтирования, γ до 1 – То есть нет необходимости дальнейших скидок будущих наград. Максимальное значение Q для следующего состояния является 0,9 поэтому мы обновляем наше значение q до 0 + α * 0,9 или 0,81 Отказ Перейти одно государство дальше в истории, мы достигаем начальной позиции. Максимальное значение Q для следующего состояния является 0,81 поэтому наше новое значение Q для первого движения становится 0 + α * 0,81 или 0,729 (округлен до 0,73 на диаграмме). Для подготовки нашего агента Q-Table мы повторяем этот процесс со многими тренировочными играми.

Обратите внимание, что для агента Q-обучения, следующее государство, которое он видит, будет состоянием Совета после ответа противника (или государства в конце игре). Поскольку он не контролирует противника, проигрыватель Q-Table считает результатом его движения, чтобы быть тем, что происходит после того, как противник отвечает. В этом смысле «следующее государство» не является государством, которое следует за движением агента Q-Table – это состояние, которое является результатом последующего движения противника.

Эпсилон-жадность

Если мы просто обновим значения Q, используя существующие значения в таблице Q, это может создать цикл обратной связи, который усиливает q-значения, которые уже высоки. Чтобы смягчить эту проблему, один подход – использовать Эпсилон-жадный Стратегия (aka ε -greedy). Идея проста: мы устанавливаем ε Значение от 0 до 1. Перед выбором действия мы генерируем случайное число, а также между 0 и 1 (с равномерным распределением вероятностей). Если случайное число меньше, чем ε мы выбираем случайное движение. В противном случае мы выбираем шаг с использованием Q-таблицы. Другими словами, мы выбираем случайное движение с вероятностью ε и мы используем переход от Q-таблицы с вероятностью 1-ε : Выбор случайного движения называется Разведка , тогда как использование значения Q-таблицы называется эксплуатация Отказ

Выбор высокой ценности для ε скажи 0,9 , значит, мы будем играть случайно 90% времени. В примере кода мы начинаем с высокого ε ценность и постепенно уменьшить его на 0 Отказ Таким образом, мы делаем больше разведки в начале, попробовав все виды разных идей, а затем мы всё разлагаются на значения Q-таблицы позже. К концу обучения мы используем Q-таблицу исключительно.

Double-Q обучение

Q-обучение с одной таблицей, по-видимому, может вызвать чрезмерную оценку Q-значений. Похоже, что это произойдет, потому что, когда мы обновляем значение q для данного пары состояния/действия, мы используем одну и ту же Q-таблицу для получения максимального значения Q для следующего состояния – как мы видели в нашем Tic-Tac- Пример на примере расчета ранее. Чтобы ослабить эту муфту, двойное обучение Q вводит пару Q-таблиц. Если мы обновляем Q-значение для Q-Table А Затем мы получаем максимальное значение Q для следующего состояния из Q-Table B Отказ И наоборот, если мы обновляем Q-Table B , мы получаем максимальное значение Q для следующего состояния из Q-Table А Отказ Для справки см. Документы Двойное q-обучение и Глубокое укрепление обучения с двойным Q-обучением Отказ Я адаптировал псевдокод из бумаги на двойном q-обучении ниже:

Выше презренного кода Pseudo не предусматривает, как выбрано следующее действие. Вот что я делаю в моем коде Tic-Tac-Tole (из qtable.py ):

def choose_move_index(q_tables, board, epsilon):
    if epsilon > 0:
        random_value_from_0_to_1 = np.random.uniform()
        if random_value_from_0_to_1 < epsilon:
            return board.get_random_valid_move_index()

    move_q_value_pairs = get_move_average_q_value_pairs(q_tables, board)

    return max(move_q_value_pairs, key=lambda pair: pair[1])[0]

Мы используем Epsilon-Gredy, чтобы решить, сделать ли случайное движение. Если решение не игнорировать случайным образом, и мы используем двойное q-обучение, то мы получаем q-значения для этой позиции как в Q-таблицах, так и в среднем их.

Из псевдоперативного кода мы также можем увидеть действие (ARG) максимального значения Q из текущей таблицы, но тогда мы фактически используем значение Q, соответствующее этому действию, от другой Q-таблицы. Ниже приведен код, который выполняет обновления Q-Table для агента TIC-TAC-TOE (из qtable.py ):

def update_training_gameover(q_tables, move_history, q_table_player, board,
                             learning_rate, discount_factor):
    game_result_reward = get_game_result_value(q_table_player, board)

    # move history is in reverse-chronological order - last to first
    next_position, move_index = move_history[0]
    for q_table in q_tables:
        current_q_value = q_table.get_q_value(next_position, move_index)
        new_q_value = (((1 - learning_rate) * current_q_value)
                       + (learning_rate * discount_factor * game_result_reward))
        q_table.update_q_value(next_position, move_index, new_q_value)

    for (position, move_index) in list(move_history)[1:]:
        current_q_table, next_q_table = get_shuffled_q_tables(q_tables)

        max_next_move_index, _ = current_q_table.get_move_index_and_max_q_value(
            next_position)

        max_next_q_value = next_q_table.get_q_value(next_position,
                                                    max_next_move_index)

        current_q_value = current_q_table.get_q_value(position, move_index)
        new_q_value = (((1 - learning_rate) * current_q_value)
                       + (learning_rate * discount_factor * max_next_q_value))
        current_q_table.update_q_value(position, move_index, new_q_value)

        next_position = position

Для каждой позиции в данной истории игры мы начинаем с последнего шага, которую играет агент Q-Table и работать на пути назад. Поскольку мы знаем результат игры для последней позиции, мы используем это для обновления значения Q для обеих Q-таблиц. Оттуда мы случайным образом выбираем Q-Table для обновления, и получаем Q-значение для следующего состояния в игре, от его компаньона Q-Table. Код выше является универсальным – если есть только одна Q-таблица, она будет повторно использовать эту одну таблицу.

Согласно упомянутым выше документам, двойное исследование Q производит результаты, которые более стабильны и сходятся до более высоких баллов. Однако в реализации этого для моего игрока TIC-TAC-TAC я не нашел улучшения. На самом деле результаты, кажется, лучше используют один Q-таблица.

Результаты

Даже при этом простой тематическом исследовании TIC-TAC-TAC, уже есть честное количество сложности, участвующей в настройке этого алгоритма Tabular Q-обучения. Мы должны выбрать ценности вознаграждения за победы, рисовать и убытки. Выбор +1 Для победы 0 для ничьей и -1 Для потери, кажется, работают. Нам также необходимо выбрать начальные значения q по умолчанию. Я не играл с этим слишком много, но просто инициализация их к нейтральному 0 кажется хорошо.

Тогда мы должны выбрать значение для α (Уровень обучения), 𝛾 (фактор скидки), а ε (для эпсилон-жадного). Наконец, мы должны выбрать, какой противник для тренировки нашего агента по вопросам обучения против и сколько тренируемых игр для использования. Мне удалось получить то, что я надеюсь, что разумные результаты, используя 0,4 для α и 1 для γ (Поскольку мы получаем только награды только за пределы игровых государств). Я также запускаю агента с агрессивной разведкой, используя ε 0,7. Это значение уменьшается на 0,1 за каждые 10% тренировочных игр. После 7000 Учебные игры против противника, который просто выбирает воображение, эти параметры обычно производят результаты, которые хорошо обобщают разных противников, показанные ниже:

Эти результаты получаются из 1000 Игры играли против каждого из нескольких противников. Противники состоят из 1) игрока, который производит случайные движения; 2) рандомизированный игрок MiniMax (где случайное движение выбирается из нескольких «лучших движений» равного значения); 3) детерминированный MiniMax Player (где выбран первый «лучший ход»); 4) Еще один агент Q-Table. Приведенные выше результаты на самом деле даже лучше, чем для MiniMax: проигрыватель Q-Table не делает ошибки, как MiniMax, но у него больше побеждает против случайного игрока, чем MiniMax. Я был удивлен, что тренировка против агента, который играет случайно, было достаточно хорошему для игрока Q-Table, чтобы не ошиблись как рандомизированных, так и детерминированных противников MiniMax.

Хотя эти результаты хорошо выглядят хорошо, я заметил, что иногда тренинг, использующий эту конфигурацию, может дать плохие результаты, как О против рандомизированного игрока MiniMax. Проигрыватель Q-Table внезапно проигрывает о 40% из игр (и управляет ничьей для остальных). Я знаю, что Deepmind применил Q-обучение к нейронным сетям – они назвали эту DQN – Таким образом, эта очевидная тенденция к заложению – это то, что я надеюсь посмотреть на большее.

Обновление: после написания статьи о Tic-Tac-Toe с MCTS Мне пришло восполнить, чтобы попытаться повысить вознаграждение за розыгрыш для табличного Q-обучения (так как только розыгрыша возможна с идеальной игрой для обеих сторон). Я закричал награду на награду, натягивающуюся от 0,0 до 1,0 (так же, как выиграть). Похоже, что исправило проблему с несоответствием от одного тренировочного прогона к другому. Кажется, что уменьшает продление выигрыша против случайных, хотя и до того, как 95% как Х и вокруг 70% так как О (Оставшиеся игры – это ничья).

Ниже приведены результаты обучения игрока Q-Table против рандомизированного игрока MiniMax, со всеми другими параметрами проводится одинаково:

Эти результаты не так хороши. Этот агент не выигрывает столько игр против игрока, который делает случайные шаги. Что еще более важно, что он последовательно делает ошибки – то есть оно теряет довольно много игр против игрока, который делает случайные шаги. Это кажется особенно уязвимым, когда он играет как О , выиграв только 50% и потерять 22,7% его игр. Тот же агент тренировался против только случайных шагов, выигрывает 92,6% из этих игр. Я был удивлен, что эти результаты оказались заметно хуже всего по сравнению с агентом, который обучался против «тупер» противника. Я думаю, что причина может быть, что агент видит меньше различных состояний, даже с включенной стратегией эпсилон-жадней стратегии. Здесь только Q-Таблица имела 355 Позиции доступа в нем после тренировки (из 627 Общее количество позиций состои, за исключением стран и игрных состояний и принимая во внимание симметрию).

Код

Полный код доступен на Github ( qtable.py ):

NestedSoftware/Tictac.

Экспериментируя с различными методами для игры Tic-Tac-Toe

Демо-проект для разных подходов для игры TIC-TAC-TOE.

Код требует python 3, numpy и ptest.

Установить с помощью Pipenv:

  • Pipenv Shell.
  • Pipenv Установить --dev.

Обязательно установите Pythonpath к главному каталогу проекта:

  • В Windows Run путь
  • В Bash Run Исходный путь .sh.

Пробеги тесты и демонстрация:

  • Пробеги тесты: питиш
  • Запустите демонстрацию: python -m tictac.main.

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

Последние результаты:

C:\Dev\python\tictac>python -m tictac.main
Playing random vs random
-------------------------
x wins: 60.10%
o wins: 28.90%
draw  : 11.00%
Playing minimax not random vs minimax random
---------------------------------------------
x wins: 0.00%
o wins: 0.00%
draw  : 100.00%

Playing minimax random vs minimax not random:
---------------------------------------------
x wins: 0.00%
o wins: 0.00%
draw  : 100.00%

Связанный

  • Грунтовка нейронных сетей
  • Революционные нейронные сети: интуитивно понятный грунтовка
  • Экспоненциальная скользящая средняя на потоковых данных

использованная литература

Оригинал: “https://dev.to/nestedsoftware/tic-tac-toe-with-tabular-q-learning-1kdn”