Q-learning算法
最近在学强化学习,看了不少的教程,还是觉得莫烦大神的强化学习教程写的不错。所以,特意仔细研究莫烦的RL代码。在这贴上自己的理解。 莫烦RL教程:https://morvanzhou.github.io/tutorials/machine-learning/reinforcement-learning/ 代码:https://github.com/MorvanZhou/Reinforcement-learning-with-tensorflow/tree/master/contents
1.Q-learning算法的决策
Q-learning算法是如何决策的呢? 原来Q-learning算法会生成一个Q表,agent每一次要采取的action,都会根据当前agent的state去Q表中查找奖励(reward)最高的动作。 就这样,agent每次采取动作都去Q表中查找.以此来决策agent的下一步的action。
2.Q-learning算法的更新
假如有如下的Q表
-a1a2
s1-21s2-42
现在agent在s1状态,根据前文说的算法决策方法Q(s1,a1) < Q(s1,a2),所以接下来会采取a2这个动作,并到达s2状态。 我们来更新Q表。接下来的我们没有在实际中采取任何动作,而是想想自己在S2状态下采取的动作,分别看看在S2状态下哪个动作的Q值最大。 比如说Q(s2,a2) > Q(s2,a1),所以把大的Q(s2,a2)乘一个gamma并加上到达s2时的奖励R,把这个作为现实中Q(s1,a2)的值。也就是 ‘Q现实’。 Q现实 = R + γ*maxQ(s2) 之前的根据Q表得到的Q(s1,a2)是Q表估计的值,也就是‘Q估计’。 Q估计 = Q(s1,a2) 有了 Q现实 和 Q估计,就可以更新Q(s1,a2)。
Q(s1,a2) = Q(s1,a2) + α * (Q现实 - Q估计)
但时刻记住, 我们虽然用 maxQ(s2) 估算了一下 s2 状态, 但还没有在 s2 做出任何的行为, s2 的行为决策要等到更新完了以后再重新另外做. 这就是 off-policy 的 Q learning 是如何决策和学习优化决策的过程.
3.Q-learning整体算法
[站外图片上传中…(image-6af5ac-1563434302631)] 这一张图概括了我们之前所有的内容. 这也是 Q learning 的算法, 每次更新我们都用到了 Q 现实和 Q 估计, 而且 Q learning 的迷人之处就是 在 Q(s1, a2) 现实 中, 也包含了一个 Q(s2) 的最大估计值, 将对下一步的衰减的最大估计和当前所得到的奖励当成这一步的现实, 很奇妙吧. 最后我们来说说这套算法中一些参数的意义. Epsilon greedy 是用在决策上的一种策略, 比如 epsilon = 0.9 时, 就说明有90% 的情况我会按照 Q 表的最优值选择行为, 10% 的时间使用随机选行为. alpha是学习率, 来决定这次的误差有多少是要被学习的, alpha是一个小于1 的数. gamma 是对未来 reward 的衰减值。
4.探索者小游戏——代码实现
会用 tabular Q-learning 的方法实现一个小例子, 例子的环境是一个一维世界, 在世界的右边有宝藏, 探索者只要得到宝藏尝到了甜头, 然后以后就记住了得到宝藏的方法, 这就是他用强化学习所学习到的行为.
-o---T
# T 就是宝藏的位置, o 是探索者的位置
4.1模块和参数
import numpy
as np
import pandas
as pd
import time
N_STATES
= 6
ACTIONS
= ['left', 'right']
EPSILON
= 0.9
ALPHA
= 0.1
GAMMA
= 0.9
MAX_EPISODES
= 13
FRESH_TIME
= 0.3
4.2创建Q表
def build_q_table(n_states
, actions
):
table
= pd
.DataFrame
(
np
.zeros
((n_states
, len(actions
))),
columns
=actions
,
)
return table
4.3动作的选择
def choose_action(state
, q_table
):
state_actions
= q_table
.iloc
[state
, :]
''' np.random.uniform(low=0.0, high=1.0, size=None) 随机数'''
if (np
.random
.uniform
() > EPSILON
) or ((state_actions
== 0).all()):
action_name
= np
.random
.choice
(ACTIONS
)
else:
action_name
= state_actions
.idxmax
()
return action_name
4.4环境的反馈
def get_env_feedback(S
, A
):
if A
== 'right':
if S
== N_STATES
- 2:
S_
= 'terminal'
R
= 1
else:
S_
= S
+ 1
R
= 0
else:
R
= 0
if S
== 0:
S_
= S
else:
S_
= S
- 1
return S_
, R
4.5游戏环境更新
def update_env(S
, episode
, step_counter
):
env_list
= ['-']*(N_STATES
-1) + ['T']
if S
== 'terminal':
interaction
= 'Episode %s: total_steps = %s' % (episode
+1, step_counter
)
print('\r{}'.format(interaction
), end
='')
time
.sleep
(2)
print('\r ', end
='')
else:
env_list
[S
] = 'o'
interaction
= ''.join
(env_list
)
print('\r{}'.format(interaction
), end
='')
time
.sleep
(FRESH_TIME
)
4.6Q-learning算法核心
def rl():
q_table
= build_q_table
(N_STATES
, ACTIONS
)
for episode
in range(MAX_EPISODES
):
step_counter
= 0
S
= 0
is_terminated
= False
update_env
(S
, episode
, step_counter
)
while not is_terminated
:
A
= choose_action
(S
, q_table
)
S_
, R
= get_env_feedback
(S
, A
)
q_predict
= q_table
.loc
[S
, A
]
if S_
!= 'terminal':
q_target
= R
+ GAMMA
* q_table
.iloc
[S_
, :].max()
else:
q_target
= R
is_terminated
= True
q_table
.loc
[S
, A
] += ALPHA
* (q_target
- q_predict
)
S
= S_
update_env
(S
, episode
, step_counter
+1)
step_counter
+= 1
return q_table
4.7主函数
if __name__
== "__main__":
q_table
= rl
()
print('\r\nQ-table:\n')
print(q_table
)
5.迷宫小游戏——代码实现
说说一个更具体的例子. 让探索者学会走迷宫. 黄色的是天堂 (reward 1), 黑色的地狱 (reward -1). 大多数 RL 是由 reward 导向的, 所以定义 reward 是 RL 中比较重要的一点.
[站外图片上传中…(image-fd9598-1563434302632)]
5.1Q-learning算法实现
import numpy
as np
import pandas
as pd
class QLearningTable:
def __init__(self
, actions
, learning_rate
=0.01, reward_decay
=0.9, e_greedy
=0.9):
self
.actions
= actions
self
.lr
= learning_rate
self
.gamma
= reward_decay
self
.epsilon
= e_greedy
self
.q_table
= pd
.DataFrame
(columns
=self
.actions
, dtype
=np
.float64
)
def choose_action(self
, observation
):
self
.check_state_exist
(observation
)
if np
.random
.uniform
() < self
.epsilon
:
state_action
= self
.q_table
.loc
[observation
, :]
'''
这一行不好理解。np.max(state_action) 选出state_action中的最大值。
state_action == np.max(state_action) 对应数据是否与max相等,返回bool值。True or False
state_action[state_action == np.max(state_action) 筛选出最大值,可能是一个,也可能是两个
之后随机挑选最大值的动作。(只有一个则就是它,如果max有多个数值相同,则随机挑选)
'''
action
= np
.random
.choice
(state_action
[state_action
== np
.max(state_action
)].index
)
else:
action
= np
.random
.choice
(self
.actions
)
return action
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()
else:
q_target
= r
self
.q_table
.loc
[s
, a
] += self
.lr
* (q_target
- q_predict
)
def check_state_exist(self
, state
):
if state
not in self
.q_table
.index
:
self
.q_table
= self
.q_table
.append
(
pd
.Series
(
[0]*len(self
.actions
),
index
=self
.q_table
.columns
,
name
=state
,
)
)
这一段把Q-learning算法整合为一个类。
5.2主函数
from maze_env
import Maze
from RL_brain
import QLearningTable
def update():
for episode
in range(100):
observation
= env
.reset
()
while True:
env
.render
()
action
= RL
.choose_action
(str(observation
))
observation_
, reward
, done
= env
.step
(action
)
RL
.learn
(str(observation
), action
, reward
, str(observation_
))
observation
= observation_
if done
:
break
print('game over')
env
.destroy
()
if __name__
== "__main__":
env
= Maze
()
RL
= QLearningTable
(actions
=list(range(env
.n_actions
)))
env
.after
(100, update
)
env
.mainloop
()