最近看了下莫烦强化学习的入门视频,有个地方一直不太理解,即QLearning和Sarah的区别在哪。直接研究了一下他的代码,下面整理一下
1 QLearning
QLearning是“表里不一”型。它取能使下一个状态s’最大的Q值(和对应的action),即maxQ(s’,a’)作为真实值,Q(s,a)作为估计值,使用上图类似梯度下降的方法对Q(s,a)进行更新。但它在下一步实际采取的action,不一定上述用于更新Q(s,a)的action。
2 Sarsa
Sarsa是“言行一致”型,它取Q(s’,a’)作为真实值,Q(s,a)作为估计值,使用上图类似梯度下降的方法对Q(s,a)进行更新。而且它在下一步实际采取的action,就是它上述用于更新Q(s,a)的action。
3 max(Q(s’,a’))和Q(s’,a’)的区别
QLearning是取的max(Q(s’,a’))作为真实值,对Q(s,a)进行更新,而Sarsa是取Q(s’,a’)进行更新。但对比过下面的代码后,我发现其实Sarsa所取的Q(s’,a’),其实也和QLearning一样,都是max(Q(s’,a’)),都是基于greedy的方法,取能够使得Q值最大的action。
但区别是QLearning只用这个action对Qtable进行更新,却不一定下一步真的会采取到这个action,它要看更新之后的情况是怎么样的(下一次while True循环),再判断采取哪一个action,所以说它是“表里不一”型。
而Sarsa不仅用这个action对Qtable进行更新,而且下一步真的还是用到这个action,所以说它是“言行一致”型。
# QLearning的choose_action和Sarsa的choose_action,完全一模一样
# QLearning的choose_action
class QLearningTable:
def __init__(self, actions, learning_rate=0.01, reward_decay=0.9, e_greedy=0.9):
省略
def choose_action(self, observation):
self.check_state_exist(observation)
# action selection
if np.random.uniform() < self.epsilon:
# choose best action
state_action = self.q_table.loc[observation, :]
# some actions may have the same value, randomly choose on in these actions
action = np.random.choice(state_action[state_action == np.max(state_action)].index)
else:
# choose random action
action = np.random.choice(self.actions)
return action
# Sarsa的choose_action
class RL(object):
def __init__(self, action_space, learning_rate=0.01, reward_decay=0.9, e_greedy=0.9):
省略
def check_state_exist(self, state):
省略
def choose_action(self, observation):
self.check_state_exist(observation)
# action selection
if np.random.rand() < self.epsilon:
# choose best action
state_action = self.q_table.loc[observation, :]
# some actions may have the same value, randomly choose on in these actions
action = np.random.choice(state_action[state_action == np.max(state_action)].index)
else:
# choose random action
action = np.random.choice(self.actions)
return action
4 Qtable的update过程
接下来看下两种方法具体更新Qtable的过程
4.1 Sarsa
在Sarsa的代码中,learn的时候输入了5个参数,s,a,r,s_,a_
4.1.1 选择a_
a_是s_通过choose_action这一函数生成的,会进入Qtable,选出s_所在行的action选择中,Q值最大的一个,选出来就是a_
4.1.2 更新Qtable
将a_也丢进去learn函数里更新Qtable
4.1.3 为下一次循环的s和a赋值
更新完Qtable后,把输出的s_和a_分别赋值为下一个新的s和a,继续while循环
正是这一步体现出,在Sarsa中,用于更新Qtable的a_,与下一个新的a,都是同一个,即“它在下一步实际采取的action,就是它上述用于更新Q(s,a)的action”,所谓言行一致
# Sarsa的update
def update():
for episode in range(100):
# initial observation
observation = env.reset()
# RL choose action based on observation
action = RL.choose_action(str(observation))
while True:
# fresh env
env.render()
# RL take action and get next observation and reward
observation_, reward, done = env.step(action)
# RL choose action based on next observation
action_ = RL.choose_action(str(observation_))
# RL learn from this transition (s, a, r, s, a) ==> Sarsa
RL.learn(str(observation), action, reward, str(observation_), action_)
# swap observation and action
observation = observation_
action = action_
# break while loop when end of this episode
if done:
break
4.2 QLearning
在QLearning的代码中,learn的时候只输入了4个参数,少了一个a_
4.2.1 更新Qtable
learn的过程中,会把s_丢进去Qtable,获得s_所在行最大的Q值及对应的a_,进行梯度下降,对Qtable进行更新
4.2.2 为下一次循环的s赋值
更新完Qtable后,把输出的s_赋值为下一个新的s,继续while循环。这里并没有像Sarsa一样,输出一个a_,并把a_赋值为a。而是等到下一次while True循环中,把赋值过的新s丢进去得到新a,这个新的a,和上一次while True中,更新Qtable的a_,不一定是同一个,因为Qtable已经变了
正是这一步体现出,在QLearning中,用于更新Qtable的a_,与下一个新的a,不一定是同一个,即“QLearning只用这个action对Qtable进行更新,却不一定下一步真的会采取到这个action,它要看更新之后的情况是怎么样的(下一次while True循环),再判断采取哪一个action”,所谓表里不一
# QLearning的update过程
def update():
for episode in range(100):
# initial observation
observation = env.reset()
while True:
# fresh env
env.render()
# RL choose action based on observation
action = RL.choose_action(str(observation))
# RL take action and get next observation and reward
observation_, reward, done = env.step(action)
# RL learn from this transition
RL.learn(str(observation), action, reward, str(observation_))
# swap observation
observation = observation_
# break while loop when end of this episode
if done:
break
# QLearning的learn过程
class QLearningTable:
def __init__(self, actions, learning_rate=0.01, reward_decay=0.9, e_greedy=0.9):
省略
def choose_action(self, observation):
省略
def learn(self, s, a, r, s_):
self.check_state_exist(s_)
q_predict = self.q_table.loc[s, a]
if s_ != 'terminal':
q_target = r + self.gamma * self.q_table.loc[s_, :].max() # next state is not terminal
else:
q_target = r # next state is terminal
self.q_table.loc[s, a] += self.lr * (q_target - q_predict) # update
def check_state_exist(self, state):
省略
5 总结
代码参考:
1.https://github.com/MorvanZhou/Reinforcement-learning-with-tensorflow/blob/master/contents/2_Q_Learning_maze/run_this.py
2.https://github.com/MorvanZhou/Reinforcement-learning-with-tensorflow/blob/master/contents/3_Sarsa_maze/run_this.py
文章参考:
1.https://blog.csdn.net/linyijiong/article/details/81607691
2.https://zhuanlan.zhihu.com/p/46850008
3.https://www.jianshu.com/p/91fbc682fb3e