Привет, Хабр!
Q-learning — это алгоритм обучения с подкреплением, который позволяет агенту оптимизировать свою стратегию действий в динамичной среде, стремясь максимизировать сумму будущих наград. Агент исследует среду, принимая решения, основанные на предыдущем опыте, а не на предварительной модели мира.
В этой статье мы и рассмотрим этот алгоритм.
Принцип работы
Агент выбирает действия на основе данных из Q-таблицы, в которой изначально все значения равны нулю и таким образом на каждом шаге....Стоп..что за Q-таблица?
Q-таблица представляет собой матрицу, где строки обозначают возможные состояния среды, а столбцы — возможные действия агента в этих состояниях. Значения в Q-таблице отражают ожидаемую суммарную награду за выполнение действия в данном состоянии и следование оптимальной политике впоследствии.
В начале обучения Q-таблица инициализируется нулями или случайными значениями. Это представляет начальное предположение о том, насколько хороши различные действия в различных состояниях.
После каждого шага агента Q-значения в таблице обновляются с использованием уравнения Беллмана (о нем чуть позже).
Агент выбирает действия, основываясь на значениях из Q-таблицы, часто с использованием ε-жадной стратегии, которая балансирует между исследованием новых действий и эксплуатацией уже известных действий с максимальным Q-значением.
Допустим, есть простая среда с четырьмя возможными состояниями S1, S2, S3, S4 и двумя возможными действиями A1, A2 в каждом состоянии. Q-таблица для этой среды выглядела бы примерно так:
Состояние/действие |
A1 |
A2 |
---|---|---|
S1 |
0.5 |
0.2 |
S2 |
0.1 |
-0.4 |
S3 |
-0.2 |
0.0 |
S4 |
0.6 |
0.3 |
Значения в таблице указывают на ожидаемую суммарную награду за выбор действия A1 или A2 в соответствующем состоянии. Например, значение 0.5 в ячейке S1, A1 означает, что ожидаемая суммарная награда за выбор действия A1 в состоянии S1 составляет 0.5. С течением времени, по мере обучения агента, эти значения будут обновляться, отражая полученный опыт и уточняя оценки ожидаемых наград.
Так вот...
На каждом шаге агент обновляет Q-таблицу, используя уравнение Беллмана, учитывая полученные награды.
Уравнение Беллмана используется для расчета Q-значений, которые представляют собой оценки качества или полезности выполнения определенного действия из конкретного состояния. Эти Q-значения затем используются для определения оптимальной стратегии агента, направленной на максимизацию общей ожидаемой награды.
Уравнение Беллмана для Q-значений может быть выражено как:
Где:
Q(s, a) — ожидаемое Q-значение состояния и действия,
r — немедленная награда, полученная после выполнения действия a из состояния s,
γ — коэффициент дисконтирования, который представляет собой важность будущих наград (обычно значение между 0 и 1),
А max и все то, что после него — максимальное Q-значение для всех возможных действий a' из следующего состояния s'.
Уравнение Беллмана по сути позволяет агенту учиться оценивать долгосрочные последствия своих действий, принимая во внимание текущую награду и ожидаемые будущие награды.
Таким образом можно рекурсивно раскрывать связь между Q-значениями текущих и будущих состояний.
Реализация алгоритма в Python
Первый пример с чистым нампаем, для задачи сетки 3x3:
import numpy as np
# инициализация Q-таблицы
Q = np.zeros([3, 3])
# параметры алгоритма
alpha = 0.1 # коэф. обучения
gamma = 0.9 # коэф. дисконтирования
epsilon = 0.1 # параметр исследования vs. эксплуатации
# основной цикл
for episode in range(1000): # колво эпизодов обучения
state = np.random.randint(0, 3) # стартовое состояние
while state != 2: # пока не достигнута цель
# выбор действия
if np.random.rand() < epsilon:
action = np.random.randint(0, 3) # случайное действие
else:
action = np.argmax(Q[state])
# переход в новое состояние и получение награды
new_state = action
reward = -1 if new_state != 2 else 0 # награда -1 за каждый шаг, 0 за достижение цели
# обновление Q-значения
Q[state, action] = (1 - alpha) * Q[state, action] + alpha * (reward + gamma * np.max(Q[new_state]))
state = new_state
print("Q-таблица:")
print(Q)
Q-таблица:
[[-0.6861894 -0.71757046 0. ]
[-0.74581342 -0.81469798 0. ]
[ 0. 0. 0. ]]
Q-learning для простой среды Gridworld:
import numpy as np
# Определение среды (Gridworld)
class Gridworld:
def __init__(self):
self.grid_size = (4, 4)
self.num_actions = 4
self.goal_state = (3, 3)
def reset(self):
self.agent_pos = (0, 0)
return self.agent_pos
def step(self, action):
if action == 0: # Вверх
self.agent_pos = (max(0, self.agent_pos[0] - 1), self.agent_pos[1])
elif action == 1: # Вниз
self.agent_pos = (min(self.grid_size[0] - 1, self.agent_pos[0] + 1), self.agent_pos[1])
elif action == 2: # Влево
self.agent_pos = (self.agent_pos[0], max(0, self.agent_pos[1] - 1))
elif action == 3: # Вправо
self.agent_pos = (self.agent_pos[0], min(self.grid_size[1] - 1, self.agent_pos[1] + 1))
reward = -1 if self.agent_pos != self.goal_state else 0
done = self.agent_pos == self.goal_state
return self.agent_pos, reward, done
# Инициализация Q-таблицы
Q = np.zeros((4, 4, 4))
# Параметры обучения
alpha = 0.1
gamma = 0.99
epsilon = 0.1
num_episodes = 1000
# Обучение
env = Gridworld()
for i in range(num_episodes):
state = env.reset()
done = False
while not done:
if np.random.rand() < epsilon:
action = np.random.randint(0, env.num_actions) # Случайное действие
else:
action = np.argmax(Q[state[0], state[1], :]) # Действие с максимальным Q-значением
next_state, reward, done = env.step(action)
Q[state[0], state[1], action] = (1 - alpha) * Q[state[0], state[1], action] + alpha * (reward + gamma * np.max(Q[next_state[0], next_state[1], :]))
state = next_state
print("Q-таблица:")
print(Q)
Q-таблица:
[[[-5.63733656 -4.90099172 -5.78723972 -4.90099167]
[-4.53658863 -3.9403968 -5.34673741 -3.94039681]
[-3.58282726 -2.97009883 -3.97937951 -2.97009888]
[-2.37438071 -1.98999995 -2.93539914 -2.21899042]]
[[-5.27339855 -3.9403967 -4.51348278 -3.94039674]
[-3.86562705 -2.97009964 -4.10058156 -2.97009964]
[-2.75481593 -1.98999997 -2.33378391 -1.98999997]
[-2.12960968 -1. -2.06496437 -1.56168583]]
[[-4.18589727 -2.97009877 -3.28672302 -2.97009878]
[-3.13003944 -1.98999995 -3.10226658 -1.98999994]
[-2.51335353 -1. -2.29706595 -1. ]
[-1.5997738 0. -1.40803817 -0.81469798]]
[[-2.87489189 -2.15624595 -2.15161794 -1.98999995]
[-1.23354402 -1.45941412 -2.08135222 -1. ]
[-1.25371027 -0.77123208 -1.45474141 0. ]
[ 0. 0. 0. 0. ]]]
Также часто реализуют через либу gym от OpenAI. Например с окружением taxi:
import gym
import numpy as np
env = gym.make('Taxi-v3')
alpha = 0.1
gamma = 0.99
epsilon = 0.1
# Q-таблица
num_states = env.observation_space.n
num_actions = env.action_space.n
Q = np.zeros((num_states, num_actions))
# обучение агента
num_episodes = 1000
for episode in range(num_episodes):
state = env.reset()
done = False
while not done:
# выбор действия
if np.random.rand() < epsilon:
action = env.action_space.sample() # случайное действие для исследования
else:
action = np.argmax(Q[state]) # действие с наивысшим Q-значением
# выполнение действия и получение награды
next_state, reward, done, _ = env.step(action)
# обновление Q-значения по уравнению Беллмана
Q[state, action] = (1 - alpha) * Q[state, action] + alpha * (reward + gamma * np.max(Q[next_state]))
# переход к следующему состоянию
state = next_state
print("Q-таблица:")
print(Q)
Q-таблица:
[[ 0. 0. 0. 0. 0. 0. ]
[-4.37743896 -4.30379883 -4.52970509 -4.37685397 1.29064633 -7.46319523]
[-1.66879694 -0.44507461 -2.07826517 -1.23688895 13.8078767 -2.43668637]
...
[-1.07785638 -0.74885187 -0.99551198 -0.99053731 -1. -1. ]
[-2.74269569 -2.73474617 -2.73781084 -2.76714114 -3.95870558 -4.68360176]
[-0.1999 -0.19 -0.1 6.47055995 -1.9 -1. ]]
На этом все. Напомню, что в рамках онлайн-курсов от экспертов OTUS вы сможете освоить практические инструменты работы с данными и не только. Также в календаре мероприятий вы можете зарегистрироваться на любой понравившийся бесплатный вебинар.