Дисклеймер: Автор перевода новичёк в ML/DS, поэтому открыт к любым правкам/дополнениям к статье
Содержание:
Что такое обучение с подкреплением?
Большинство из вас наверняка слышали о том, что искусственный интеллект научился самостоятельно играть в компьютерные игры. Очень популярным примером является компания Deepmind, которая попала в новости и захватила мир, когда ее программа AlphaGo победила чемпиона мира по игре в го из Южной Кореи в 2016 году.
Так в чем же секрет этого грандиозного прорыва? Придержите лошадей! Вы поймете это через пару минут.
Давайте рассмотрим аналогию с обучением собаки новым трюкам. В этом сценарии мы моделируем ситуацию, а собака пытается реагировать на нее по-разному. Если реакция собаки оказывается желаемой, мы поощряем ее кормом. В противном случае мы тем или иным способом даем понять, что ее реакция не является желаемой.
Теперь каждый раз, когда собака попадает в ту же ситуацию, она выполняет аналогичное действие с еще большим энтузиазмом, ожидая получить больше еды. По сути, она учится тому, что нужно делать, на основе положительного опыта. Точно так же она будет учиться тому, что не следует делать, когда сталкивается с негативным опытом.
Именно так работает Reinforcement Learning в широком смысле
Собака - это агент (agent), который подвергается воздействию нашего окружения (environment). Средой можно считать ваш дом и вас.
Возникающие ситуации аналогичны состоянию (state). Примером состояния может быть то, что ваша собака стоит, а вы используете определенное слово в определенном тоне в вашей гостиной.
Наш агент реагирует, выполняя действие по переходу из одного состояния в другое. Например, ваша собака переходит из состояния "стоять" в состояние "бег", чтобы поймать палку.
После перехода она может получить награду (reward) или наказание (penalty). Вы даете лакомство в качестве награды или просто говорите "Нет" в качестве наказания.
Policy - это стратегия выбора действия при определенном состоянии в расчете на лучший результат.
А если собрать все это вместе...
Задача Reinforcement Learning (RL) - это обучение агента, который взаимодействует с окружением. Агент переходит между различными сценариями окружения, называемыми состояниями, выполняя действия. Действия, в свою очередь, приносят вознаграждение, которое может быть положительным, отрицательным или нулевым.
Единственная цель агента - максимизировать понятие кумулятивного вознаграждения за эпизод, то есть все, что происходит между начальным и конечным состоянием, где мы определяем вознаграждение, соответствующее задачам, которые мы хотим решить.
Таким образом, мы подталкиваем агента к выполнению определенных действий, предоставляя ему положительное вознаграждение, и к отказу от других действий, предоставляя отрицательное вознаграждение. Так агент учится разрабатывать стратегию или политику.
RL - одна из трех основных парадигм машинного обучения, наряду с контролируемым и неконтролируемым обучением.
Два важных моментов, на которые стоит обратить внимание...
Жадность не всегда помогает
Есть вещи, которые легко сделать для мгновенного удовлетворения, а есть те, которые приносят долгосрочное вознаграждение. Цель состоит в том, чтобы не быть жадным, ища только быстрые немедленные вознаграждения, а оптимизировать их для получения максимального вознаграждения в течение всего обучения.Последовательность имеет значение в обучении с подкреплением
Вознаграждение агента зависит не только от текущего состояния, но и от всей истории состояний. В отличие от контролируемого и неконтролируемого обучения, здесь важно время.
В некотором смысле RL - это наука о принятии оптимальных решений на основе опыта. Если разложить все по полочкам, то процесс включает в себя следующие простые шаги:
Наблюдение за окружающей средой
Принятие решения о том, как действовать, используя определенную стратегию
Действовать соответственно
Получение вознаграждения или наказания
Учиться на опыте и совершенствовать стратегию
Итерация до тех пор, пока не будет найдена оптимальная стратегия
Возвращаясь к AlphaGo...
AlphaGo - это классический пример RL-агента, который научился играть в игру Го, чтобы максимизировать свое вознаграждение. В этом уроке мы рассмотрим RL на примере разработки агента, который будет самостоятельно учиться играть в игру в автоматическом режиме.
RL не ограничивается только играми! Оно используется для управления портфелями акций и финансами, для создания человекоподобных роботов, для производства и управления запасами, для разработки агентов ИИ общего назначения и т. д...
Разработка самоуправляемого автомобиля с нуля (Smart Cab)
Давайте разработаем симуляцию самодвижущегося такси (Smart Cab). Основная цель - продемонстрировать в упрощенной среде, как можно использовать методы RL для разработки эффективного и безопасного подхода к решению этой проблемы.
Задача Smart Cab - подобрать пассажира в одном месте и высадить его в другом. О чем мы хотим, чтобы позаботился наш Smart Cab:
Высадите пассажира в нужном месте.
Экономьте время пассажира, отводя на посадку минимум времени.
Позаботьтесь о безопасности пассажира и соблюдении правил дорожного движения.
При моделировании RL-решения этой проблемы необходимо учитывать различные аспекты: вознаграждения, состояния и действия.
1. Награды (Rewards)
Поскольку агент (воображаемый водитель) мотивирован на вознаграждение и собирается научиться управлять кабиной методом проб и ошибок, нам необходимо определить вознаграждение и/или наказание и их величину соответственно. Вот несколько моментов, которые следует рассмотреть:
Агент должен получать большое положительное вознаграждение за успешную высадку, поскольку такое поведение очень желательно.
Агент должен быть наказан, если он пытается высадить пассажира в неправильном месте.
-
Агент должен получать слегка отрицательное вознаграждение за то, что не добирается до места назначения после каждого временного шага.
"Слегка" отрицательное, потому что мы бы предпочли, чтобы наш агент добирался с опозданием, а не делал неверные движения, пытаясь добраться до места назначения как можно быстрее.
2. Пространство состояний (State Space)
В RL агент встречает состояние, а затем предпринимает действия в соответствии с состоянием, в котором он находится.
Пространство состояний - это множество всех возможных ситуаций, в которых может оказаться наше такси. Состояние должно содержать полезную информацию, необходимую агенту для совершения правильного действия.
Допустим, у нас есть тренировочная площадка для Smart Cab, где мы учим его перевозить людей на парковке в четыре разных места (R, G, Y, B):
Предположим, что Smart Cab - единственный автомобиль на этой парковке. Мы можем разбить стоянку на сетку 5x5, что даст нам 25 возможных мест расположения такси. Эти 25 мест - одна часть нашего пространства состояний. Текущее состояние местоположения нашего такси - (3, 1).
Есть 4 места, где мы можем взять и высадить пассажира: R, G, Y, B или [(0,0), (0,4), (4,0), (4,3)]
в координатах (row, col). Наш пассажир находится в месте Y и хочет отправиться в место R.
Если у нас есть 1 дополнительное состояние пассажира, находящегося в такси, мы можем взять все комбинации местоположений пассажиров и местоположений пунктов назначения, чтобы получить общее количество состояний для нашей среды такси; есть 4 пункта назначения и пять (4+1) местоположений пассажиров.
Таким образом, наше окружение такси имеет 5×5×5×4=500 возможных состояний. (Расположение такси - 5×5, расположение пассажира - 5, расположение пункта назначения - 4)
3. Пространство действия (Action Space)
Пространство действий - это множество всех действий, которые наш агент может предпринять в данном состоянии. Агент встречает одно из 500 состояний и выполняет действие. В нашем случае это может быть движение в определенном направлении или решение подобрать/высадить пассажира.
Другими словами, у нас есть шесть возможных действий:
south
north
east
west
pickup
(подбор пассажира)dropoff
(высадка пассажира)
На иллюстрации выше такси не может выполнять определенные действия в определенных состояниях из-за стен. В коде окружения мы предусмотрим штраф -1 за каждое столкновение со стеной, что приведет к увеличению штрафов и заставит такси подумать о том, чтобы обойти стену.
К счастью, в OpenAI Gym есть именно такая среда, которая уже создана для нас.
OpenAI Gym предоставляет различные игровые среды, которые мы можем подключить к нашему коду и протестировать агента. Библиотека позаботится об API для предоставления всей необходимой агенту информации, такой как возможные действия, счет и текущее состояние. Нам нужно сосредоточиться только на алгоритмической части для нашего агента.
Мы будем использовать среду Gym под названием Taxi-V2
, из которой взяты все детали, описанные выше.
Интерфейс Gym
Сначала нам нужно установить gym
. Выполнение следующего кода должно сработать:
!pip install cmake 'gym[atari]' scipy
После установки мы можем загрузить игровое окружение и визуализировать его внешний вид:
import gym
env = gym.make("Taxi-v2").env
env.render()
Основным интерфейсом gym является env, который представляет собой унифицированный интерфейс окружения.
Ниже перечислены методы env
, с которыми мы столкнемся в коде.
env.reset
: Сбрасывает окружение и возвращает случайное начальное состояние.
env.step(action)
: Перемещает окружение на один временной шаг. Возвращает:
observation: Наблюдения за окружающей средой
reward: Принесло ли ваше действие пользу или нет
done: Показывает, успешно ли мы подобрали и высадили пассажира, также называется одним эпизодом
info: Дополнительная информация, такая как производительность и задержка, для целей отладки
env.render
: Рендерит один кадр окружения (полезно для визуализации окружения)
Вот наша реструктурированная постановка задачи (из документации Gym):
Есть 4 места (обозначенные разными буквами), и наша задача - забрать пассажира в одном месте и высадить его в другом. За успешную посадку мы получаем +20 очков и теряем по 1 очку за каждый временной шаг. За незаконные действия по подбору и высадке пассажиров начисляется 10 очков штрафа.
Давайте подробнее рассмотрим окружение...
env.reset() # сбросить окружение на новое, случайное состояние
env.render()
print("Action Space {}".format(env.action_space))
print("State Space {}".format(env.observation_space))
Action Space Discrete(6)
State Space Discrete(500)
Заполненный квадрат представляет такси, которое имеет желтый цвет без пассажира и зеленый с пассажиром.
Вертикальная черта ('|') обозначает стену, которую такси не может пересечь.
R, G, Y, B - это возможные места подбора/высадки пассажиров. Синяя буква обозначает текущее место подбора пассажиров, а фиолетовая - место назначения.
У нас есть пространство действий (Action Space) размером 6 и пространство состояний (State Space) размером 500. RL учится выбирать номер действия из возможных действий 0-5, где:
0-south
1-north
2-east
3-west
4-pickup
5-dropoff
RL изучает отображения состояний на оптимальное действие, которое нужно выполнить в этом состоянии, путем исследования, т.е. агент исследует окружающую среду и предпринимает действия, основанные на вознаграждении, определенном в этой среде.
Оптимальное действие для каждого состояния - это действие, которое имеет наибольшее кумулятивное долгосрочное вознаграждение.
Вернемся к нашей иллюстрации...
Давайте возьмем нашу иллюстрацию, закодируем ее состояние и передадим окружению для рендеринга в gym
. Вспомним, что наше такси находится в строке 3, столбце 1, наш пассажир - в месте 2, а пункт назначения - в месте 0. Используя метод кодирования состояния Taxi-V2
, мы можем сделать следующее:
state = env.encode(3, 1, 2, 0)
#(строка такси, столбец такси, индекс пассажира, индекс пункта назначения)
print("State:", state)
env.s = state
env.render()
State: 328
Мы используем координаты нашей иллюстрации, чтобы сгенерировать число, соответствующее состоянию между 0 и 499, что для состояния нашей иллюстрации оказывается 328.
Затем мы можем установить состояние окружения вручную с помощью env.env.s
, используя это закодированное число. Вы можете поиграть с числами и увидите, как перемещаются такси, пассажир и пункт назначения.
Таблица вознаграждений
При создании среды Taxi
создается начальная таблица вознаграждений, которая называется P
. Мы можем представить ее как матрицу, в которой количество состояний - это строки, а количество действий - столбцы, то есть матрица состояний × матрица действий.
Поскольку каждое состояние находится в этой матрице, мы можем видеть значения вознаграждения по умолчанию, присвоенные состоянию нашей иллюстрации:
env.P[328]
Вывод элемента:
{0: [(1.0, 428, -1, False)],
1: [(1.0, 228, -1, False)],
2: [(1.0, 348, -1, False)],
3: [(1.0, 328, -1, False)],
4: [(1.0, 328, -10, False)],
5: [(1.0, 328, -10, False)]}
Этот словарь имеет структуру {action: [(probability, nextstate, reward, done)]}
.
Следует отметить несколько моментов:
0-5 соответствует действиям (south, north, east, west, pickup, dropoff), которые такси может выполнить в текущем состоянии.
В этой среде
probability
всегда равна 1.0.nextstate
- это состояние, в котором мы окажемся, если выполним действие по данному индексу словаря.Все действия по перемещению имеют награду -1, а действия по pickup/dropoff имеют награду -10 в этом конкретном состоянии. Если мы находимся в состоянии, когда у такси есть пассажир, и оно находится на вершине нужного пункта назначения, мы получим награду 20 за действие высадки (5).
done
используется для того, чтобы сообщить нам, что мы успешно высадили пассажира в нужном месте. Каждый успешный высаженный пассажир - это конец эпизода.
Обратите внимание, что если бы наш агент выбрал действие два (2) в этом состоянии, он бы отправился на восток, врезавшись в стену. Исходный код сделал невозможным реальное перемещение такси через стену, поэтому, если такси выберет это действие, оно просто будет продолжать начислять штрафы -1, что влияет на долгосрочную награду.
Реализация Q-Learning на Python
Мы будем использовать простой алгоритм RL под названием Q-learning, который даст нашему агенту немного памяти.
У автора оригинала есть отдельная статья по Q-learning
Обучение агента
Сначала мы инициализируем Q-table матрицей 500×6500×6, состоящей из нулей:
import numpy as np
q_table = np.zeros([env.observation_space.n, env.action_space.n])
Теперь мы можем создать алгоритм обучения, который будет обновлять эту Q-table по мере того, как агент будет исследовать окружающую среду в течение тысяч эпизодов.
%%time
"""Training the agent"""
import random
from IPython.display import clear_output
# Hyperparameters
alpha = 0.1
gamma = 0.6
epsilon = 0.1
# For plotting metrics
all_epochs = []
all_penalties = []
for i in range(1, 100001):
state = env.reset()
epochs, penalties, reward, = 0, 0, 0
done = False
while not done:
if random.uniform(0, 1) < epsilon:
action = env.action_space.sample() # Explore action space
else:
action = np.argmax(q_table[state]) # Exploit learned values
next_state, reward, done, info = env.step(action)
old_value = q_table[state, action]
next_max = np.max(q_table[next_state])
new_value = (1 - alpha) * old_value + alpha * (reward + gamma * next_max)
q_table[state, action] = new_value
if reward == -10:
penalties += 1
state = next_state
epochs += 1
if i % 100 == 0:
clear_output(wait=True)
print(f"Episode: {i}")
print("Training finished.\n")
В первой части while not done
мы решаем, выбрать ли случайное действие или использовать уже вычисленные Q-value. Для этого используется значение epsilon
и сравнивается с функцией random.uniform(0, 1)
, которая возвращает произвольное число от 0 до 1.
Мы выполняем выбранное действие в окружении, чтобы получить next_state
и reward
от выполнения действия. После этого мы вычисляем максимальное Q-value для действий, соответствующих next_state
, и с его помощью можем легко обновить наше Q-value до new_q_value
Вывод результата:
Episode: 100000
Training finished.
Wall time: 30.6 s
Теперь, когда Q-table создана на основе 100 000 эпизодов, давайте посмотрим, каковы Q-value в состоянии нашей иллюстрации:
q_table[328]
Вывод:
array([ -2.30108105, -1.97092096, -2.30357004, -2.20591839,
-10.3607344 , -8.5583017 ])
Максимальное Q-value - "north" (-1,971), так что похоже, что Q-learning эффективно научилось наилучшему действию, которое следует предпринять в состоянии нашей иллюстрации!
Оценка агента
Пришло время оценить работу нашего агента...
"""Evaluate agent's performance after Q-learning"""
total_epochs, total_penalties = 0, 0
episodes = 100
for _ in range(episodes):
state = env.reset()
epochs, penalties, reward = 0, 0, 0
done = False
while not done:
action = np.argmax(q_table[state])
state, reward, done, info = env.step(action)
if reward == -10:
penalties += 1
epochs += 1
total_penalties += penalties
total_epochs += epochs
print(f"Results after {episodes} episodes:")
print(f"Average timesteps per episode: {total_epochs / episodes}")
print(f"Average penalties per episode: {total_penalties / episodes}")
Вывод результата:
Results after 100 episodes:
Average timesteps per episode: 12.3
Average penalties per episode: 0.0
Мы видим, что производительность агента значительно улучшилась, и он не понес никаких штрафов, что означает, что он выполнил правильные действия по посадке/высадке 100 различных пассажиров.
Сравнение нашего агента Q-Learning с агентом без RL
Давайте посмотрим, насколько лучше наше решение Q-learning по сравнению с агентом, просто делающим случайные ходы.
У автора оригинала есть статья и о реализации без RL
При Q-learning агент сначала совершает ошибки во время исследования, но после того, как он достаточно изучил вопрос, он может действовать разумно, максимизируя вознаграждение, делая умные ходы.
Мы оцениваем наших агентов по следующим показателям,
Среднее количество штрафов за эпизод (чем меньше, тем лучше)
Среднее количество временных шагов за ход (чем меньше, тем лучше)
Среднее количество наград за ход (чем выше, тем лучше)
Похоже, наш агент Q-Learning справился с задачей!
Настройка гиперпараметров
Значения alpha, gamma, и epsilon были основаны в основном на интуиции и пробных вариантах, но есть и более эффективные способы получения хороших значений.
В идеале, все три значения должны уменьшаться со временем, потому что по мере обучения агент создает более устойчивые суждения. Поэтому крайне важно играть и экспериментировать с гиперпараметрами.
Заключение
Отлично! Мы начали с понимания Reinforcement Learning с помощью реальных аналогий. Затем мы погрузились в основы обучения с усилением и сформулировали задачу о самоуправляемом такси как задачу обучения с усилением, используя OpenAI's Gym на python
, чтобы предоставить нам соответствующую среду, в которой мы можем разработать нашего агента и оценить его.
Затем мы заметили, насколько ужасен был наш агент без использования какого-либо алгоритма для игры, поэтому мы приступили к реализации алгоритма Q-Learning с нуля. Производительность агента значительно улучшилась после внедрения Q-Learning.
Q-Learning - один из самых простых алгоритмов Reinforcement Learning. Однако проблема Q-Learning заключается в том, что когда количество состояний в среде становится очень большим, становится трудно реализовать их с помощью Q-table, так как ее размер становится очень и очень большим.
Современные методы используют глубокие нейронные сети вместо Q-таблицы (Deep Reinforcement Learning). Нейронная сеть получает информацию о состоянии и действиях на входной слой и учится выдавать правильные действия с течением времени.
Если вы хотите продолжить работу над этим проектом и сделать его лучше, вот несколько вещей, которые вы можете добавить -
Превратите этот код в модуль функций, которые могут использовать несколько окружений
Настройте альфу, гамму и/или эпсилон, используя распад по эпизодам
Реализуйте сеточный поиск для выявления наилучших гиперпараметров
Оказывается, Reinforcement Learning - это тип машинного обучения, который жаждет данных даже больше, чем Supervised Learning. Получить достаточно данных для алгоритмов Reinforcement Learning очень сложно.
— Andrew N
atomlib
Сравнение фрагмента «Вознаграждение». Слева — перевод от сайта DeepL, справа — то, что в публикации.
Интересные особенности:
«Reward-motivated» как у DeepL, так и в публикации переведено как «мотивирован на вознаграждение». «Яндекс Переводчик» выдаёт «заинтересован в вознаграждении», гуглевский — «мотивирован вознаграждением».
Это не единственная характерная особенность. Как яндексовский, так и гуглевский машинные переводчики даже без дополнительного контекста правильно понимают слово «cab» как «такси». Как публикация, так и DeepL совершают одинаковую ошибку: «кабина».
При этом вручную такую ошибку совершить — странное дело, потому что в остальном текст рассказывает про такси.
Из пяти абзацев и заголовка полностью (дословно) совпали три. В двух случаях разница на уровне одного слова, в одном случае — нескольких слов. Разница незначительная, без смены смысла, на уровне перефразирования.
Аналогичное сравнение для раздела «Заключение». Я здесь специально выбираю разделы, где поменьше вставок кода, чтобы не было переносов строк.
Ситуация ровно та же: совпадают целые абзацы. Если изменения есть, то либо ненужные (по всему тексту и в заголовке было «Reinforcement Learning», а теперь несуществующий термин «обучение с усилением») или на уровне перефразирования («с помощью распада» → «используя распад»).
Кстати, зачем оглавление из 12 пунктов статье на 10 минут чтения?
В целом огорчает не потенциальный машинный перевод, а другое:
Перевод выполнен без желания ознакомиться с темой. В «Википедии» статью «Обучение с подкреплением» создали в 2008 году. Почему в переводе осталось «Reinforcement Learning»?
Не думаю, что сейчас возможны дебаты или переживания, устоялось написание на русском языке или нет. Если хочется для справки дать написание на английском языке, то это делается в квадратных скобках где-то при первом употреблении и с пометкой «прим. пер.».
Если по поводу технических терминов ещё можно поспорить, то имена людей всегда пишутся кириллицей. Если тяжело и есть сомнения, нужно хотя бы попытаться это сделать, но оставить в первом употреблении оригинальное написание в квадратных скобках.
В данном случае попался Эндрю Ын — человек чрезвычайно известный. Написание его имени кириллицей устаканилось и вылезает при первом запросе в любой поисковой машине.
Подобные наспех выполненные переводы ради рекламы собственного канала в «Телеграме» убивают потенциальные переводы получше. Если кто-то захочет перевести по-человечески, то он, как полагается, проверит существующие переводы и увидит этот. Затем этот кто-то подумает: «Не, уже сделали, возьму что-то ещё». А если и сделает, то в комменты к нему придут и скажут: «Гляди, уже есть, зачем ты нам тут опять это притащил?»
Ну ладно хоть, что в данном случае вы взялись за какой-то вялый и неинтересный текст на заезженную тему.