莫烦强化学习笔记整理(二)Q-learning
Q-leaning算法代码地址 link.
1、什么是Q-learning
(1) Q-learning决策
S1当前状态,A1为看电视行为,A2为写作业行为。
在S1状态时,凭借经验学习,A2行为的潜在奖励比A1要高,所以做A2行为,这个潜在奖励用Q值来表示。此时状态更新为S2,接下来继续选择Q值高的行为A2,状态到达S3,继续上面的决策过程。
状态 | 行为 | Q值 |
---|---|---|
S1 | A1 | -2 |
S1 | A2 | 1 |
S2 | A1 | -4 |
S2 | A2 | 2 |
(2)Q-learning更新
回到上面的过程,S1状态我们选择了A2行为并到达了状态S2,需要对Q值进行更新,即Q(S1,A2)。
Q(S1,A2)估计值=老Q(S1,A2)
Q(S1,A2)现实值=R+y*max{Q(S2,A1),Q(S2,A2)}
R为到达S2的奖励值,y(gamma)为衰减率。Q(S2,A1),Q(S2,A2)为S2状态下A1和A2行为的估计Q值,是未发生的、想象出来的。
差距=Q(S1,A2)现实值-Q(S1,A2)估计值
新Q(S1,A2)=老Q(S1,A2)+a*差距
a(alpha)为学习率,S2状态的行为决策要等到Q(S1,A2)更新完成之后再进行。
(3)Q-learning算法概述
图中用一个公式总结了Q值更新的规律。
Q learning 的迷人之处就是 在 Q(s1, a2) 现实 中, 包含了一个 Q(s2) 的最大估计值, 将对下一步的衰减的最大估计和当前所得到的奖励当成这一步的现实。
公式中一些参数的意义:
Epsilon greedy 是用在决策上的一种策略, 比如 epsilon = 0.9 时, 就说明有90% 的情况我会按照 Q 表的最优值选择行为, 10% 的时间使用随机选行为. alpha是学习率, 来决定这次的误差有多少是要被学习的, alpha是一个小于1 的数. gamma 是对未来 reward 的衰减值.
gamma = 1 时, 在 s1 看到的 Q 是未来没有任何衰变的奖励, 也就是能清楚地看到之后所有步的全部价值
gamma =0, 眼前的 reward, 只在乎最近的大奖励。
gamma 从 0 变到 1, 对远处的价值看得越清楚, 所以智能体渐渐变得有远见, 不仅仅只看眼前的利益, 也为自己的未来着想。
2、Q-leaning的一个小例子
用 tabular Q-learning 的方法实现一个小例子, 例子的环境是一个一维世界, 探索者O在世界的左边尽头,在世界的右边尽头有宝藏T, 世界是几个“-------”道路。探索者有向左走和向右走两种行为选择,第一次经过多次试错得到宝藏, 然后以后就记住了得到宝藏的方法, 即一直向右走,这就是他用强化学习所学习到的行为。
Q-learning 是一种记录行为值 (Q值) 的方法, 每种在一定状态的行为都会有一个值 Q(s, a), 行为 a 在 s 状态的值是 Q(s, a)。s 在上面的探索者游戏中, 是 o 所在的地点,每一个地点探索者都能做出两个行为 left/right, 这就是探索者的所有可行的 a。
如果在某个地点 s1, 探索者计算了他能有的两个行为, a1/a2=left/right, 计算结果是 Q(s1, a1) < Q(s1, a2), 那么探索者就会选择 right 这个行为. 这就是 Q learning 的行为选择简单规则。
最终效果
O经过多次尝试之后学会了直行向右,并打印Q表
代码实现和注释
(1)导入模块包并预设变量
Numpy、Pandas模块包基本的用法也可以参考莫烦的教程,教程链接:https://mofanpy.com/tutorials/data-manipulation/np-pd/
Time模块是用来控制动画速度的,可以进行时间有关的操作。
import numpy as np
import pandas as pd
import time
N_STATES = 6 # 1维世界的宽度
ACTIONS = ['left', 'right'] # 探索者的可用动作
EPSILON = 0.9 # 贪婪度 greedy
ALPHA = 0.1 # 学习率
GAMMA = 0.9 # 奖励递减值
MAX_EPISODES = 13 # 最大回合数
FRESH_TIME = 0.3 # 移动间隔时间
(2)初始化Q表并输出
对于 tabular Q learning, 要将所有的 Q values (行为值) 放在 q_table 中, 更新 q_table 也是在更新他的行为准则。q_table 的 index 是所有对应的 state (探索者位置), columns 是对应的 action (探索者行为)。
def build_q_table(n_states, actions):# 输入状态数和动作空间
table = pd.DataFrame(
np.zeros((n_states, len(actions))),
# q_table全0初始
columns=actions, # actions's name
)
print(table)
show table # 输出表格观察
return table
输出的初始Q表如下
q_table:
left right
0 0.0 0.0
1 0.0 0.0
2 0.0 0.0
3 0.0 0.0
4 0.0 0.0
5 0.0 0.0
(3)定义动作的随机性
在初始阶段, 随机的探索环境, 往往比固定的行为模式要好, EPSILON 就是用来控制贪婪程度的值. EPSILON 可以随着探索时间不断提升(越来越贪婪), 不过在这个例子中, 固定成 EPSILON = 0.9, 90% 的时间是选择最优策略, 10% 的时间来探索.
# 在某个 state 地点, 选择行为
def choose_action(state, q_table):
state_actions = q_table.iloc[state, :] # 选出这个 state 的所有 action 值
if (np.random.uniform() > EPSILON) or (state_actions.all() == 0): # 非贪婪 or 或者这个 state 还没有探索过
action_name = np.random.choice(ACTIONS)
else:
action_name = state_actions.argmax() # 贪婪模式
return action_name
(4)反馈奖励
做出行为后, 环境要给行为一个反馈, 反馈出下个S和 在上个 S做出A所得到的R,在这个小游戏中,只有当 o 移动到了 T, 探索者才会得到唯一的一个奖励, 奖励值 R=1, 其他情况都没有奖励。
def get_env_feedback(S, A):
# This is how agent will interact with the environment
if A == 'right': # 向右走
if S == N_STATES - 2: # terminate
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
(5) 环境更新
def update_env(S, episode, step_counter):
# This is how environment be updated
env_list = ['-']*(N_STATES-1) + ['T'] # '---------T' our environment
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)
(6)RL Q-leaning主循环
def rl():
q_table = build_q_table(N_STATES, ACTIONS) # 初始 q table
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 # terminate this episode
q_table.loc[S, A] += ALPHA * (q_target - q_predict) # q_table 更新
S = S_ # 探索者移动到下一个 state
update_env(S, episode, step_counter+1) # 环境更新
step_counter += 1
return q_table
s episode
q_table.loc[S, A] += ALPHA * (q_target - q_predict) # q_table 更新
S = S_ # 探索者移动到下一个 state
update_env(S, episode, step_counter+1) # 环境更新
step_counter += 1
return q_table
(7)模型训练和最终Q表输出
if __name__ == "__main__":
q_table = rl()
print('\r\nQ-table:\n')
print(q_table)
最终的Q表如下图所示