1 Q Learning算法
Q更新公式:
∈-greedy策略
在Q Learning的更新过程中,每一步都要根据当前的state以及Q函数确定一个合适的行动action。这里有一个如何平衡“经验”和“探索”的问题。如果完全按照经验行动,即每次都在Q(state, :)中选择对应值最大的action,那么很有可能一直局限在已有经验中,难以发现更具价值的新的行为。但如果智能体只专注于探索新的行为,即完全随机地行动,又可能因为大多数行动都没有价值,导致学习Q函数的速度很慢。
一种比较简单的平衡“经验”和“探索”的方法是采用∈-greedy策略选择合适的行动。事先设置一个较小的∈值(如∈=0.1),智能体有1-∈的概率根据学习到的Q函数(已有经验)行动,剩下∈的概率智能体会随机行动,用于探索新的经验。例如,∈=0.1时,在90%的情况下,智能体直接选择使得Q(state, action)最大的action,剩下10%的情况,随机选择一个action。
2 SARSA(state-action-reward-state-action)
off-policy和on-policy
强化学习中的方法可以分为off-policy和on-policy两类。Q Learning算法是一个经典的off-policy方法,而SARSA算法则是on-policy方法。那么,如何理解这里的off-policy和on-policy呢?
在Q Learning中,Q函数的更新和Q[new_state, :].max()有关。在Q[new_state, :]中选出使得Q函数最大的动作,以此来更新Q函数。设这个动作为max_action。注意,智能体实际有可能并不会执行max_action。因为在下一个过程中是根据epsilon-greedy方法来选择策略的,有可能选择max_action,也有可能并不会选到max_action。而SARSA算法则不同,它用Q[new_state, new_action]结合奖励等信息更新Q函数。之后,在下一次循环时,智能体必然会执行new_action。
说Q Learning是一种off-policy算法,是指它在更新Q函数时使用的动作(max_action)可能并不会被智能体用到。又称SARSA是一种on-policy方法,是指它在更新Q函数时使用的动作(new_action)一定会被智能体所采用。这也是on-policy方法和off-policy方法的主要区别。
3 Q Learning和SARSA对比
相比Q Learning算法,SARSA算法更“胆小”。Q Learning算法会使用Q[new_state, :].max()来更新Q值,换句话说,它考虑的是新状态下可以获得的最大奖励,而不去考虑新状态会带来的风险。因此,Q Learning算法会更加的激进。相比之下,SARSA算法只是使用Q[new_state, new_action]来更新Q值。在此处的迷宫问题中,SARSA算法会考虑到接近陷阱可能带来的负收益,因此更倾向于待在原地不动,从而更加难以找到“宝藏”.
4 python 实现
q-learning
from __future__ import print_function
import numpy as np
import time
from env import Env
EPSILON = 0.1
ALPHA = 0.1
GAMMA = 0.9
MAX_STEP = 30
np.random.seed(0)
def epsilon_greedy(Q, state):
if (np.random.uniform() > 1 - EPSILON) or ((Q[state, :] == 0).all()):
action = np.random.randint(0, 4) # 0~3
else:
action = Q[state, :].argmax()
return action
e = Env()
Q = np.zeros((e.state_num, 4))
for i in range(200):
e = Env()
while (e.is_end is False) and (e.step < MAX_STEP):
action = epsilon_greedy(Q, e.present_state)
state = e.present_state
reward = e.interact(action)
new_state = e.present_state
Q[state, action] = (1 - ALPHA) * Q[state, action] + \
ALPHA * (reward + GAMMA * Q[new_state, :].max())
e.print_map()
time.sleep(0.1)
print('Episode:', i, 'Total Step:', e.step, 'Total Reward:', e.total_reward)
time.sleep(2)
SARSA
from __future__ import print_function
import numpy as np
import time
from env import Env
EPSILON = 0.1
ALPHA = 0.1
GAMMA = 0.9
MAX_STEP = 50
np.random.seed(1)
def epsilon_greedy(Q, state):
if (np.random.uniform() > 1 - EPSILON) or ((Q[state, :] == 0).all()):
action = np.random.randint(0, 4) # 0~3
else:
action = Q[state, :].argmax()
return action
e = Env()
Q = np.zeros((e.state_num, 4))
for i in range(200):
e = Env()
action = epsilon_greedy(Q, e.present_state)
while (e.is_end is False) and (e.step < MAX_STEP):
state = e.present_state
reward = e.interact(action)
new_state = e.present_state
new_action = epsilon_greedy(Q, e.present_state)
Q[state, action] = (1 - ALPHA) * Q[state, action] + \
ALPHA * (reward + GAMMA * Q[new_state, new_action])
action = new_action
e.print_map()
time.sleep(0.1)
print('Episode:', i, 'Total Step:', e.step, 'Total Reward:', e.total_reward)
time.sleep(2)