Q L e a r n i n g Q\;Learning QLearning
申明
这里是对 Q L e a r n i n g Q\;Learning QLearning算法的一些总结,主要是基于莫烦python教学视频,以及关于阅读其他博客的总结,所有引用都会加上出处。
伪代码
步骤如下:
1.初始化一个
Q
(
s
,
a
)
Q(s,a)
Q(s,a)的表格
2.在每个回合都对
Q
(
s
,
a
)
Q(s,a)
Q(s,a)进行如下更新
从状态0开始
如果未达到截止状态:
2.1选择一个策略
a
a
a
2.2得到采取策略
a
a
a对应的奖励
r
r
r和到达的下一状态
s
′
s^{'}
s′
2.3更新
Q
(
s
,
a
)
Q(s,a)
Q(s,a)
2.4当前状态变为
s
′
s^{'}
s′
说明
- 在2.1中采用 ε − g r e e d y \varepsilon - greedy ε−greedy方法选择策略,如 ε = \varepsilon= ε= 0.9,则按照90%的概率利用最优Q值选择行为,10%的概率随机选择行为。
- 在2.3中,更新函数还可以等价写为
Q ( s , a ) ← ( 1 − α ) Q ( s , a ) + α [ r + γ m a x a ′ Q ( s ′ , a ′ ) ] Q(s,a)←\color{red}{(1-\alpha)Q(s,a)}+\color{green}{ \alpha[r+\gamma max_{a^{'}}Q(s^{'},a{'})]} Q(s,a)←(1−α)Q(s,a)+α[r+γmaxa′Q(s′,a′)] (1)
其中红色的部分是已经存在于Q表中的估计值,绿色的部分是现实中马上获得的奖励和下一个状态的价值[1]。 - 公式(1)中 α \alpha α是学习率,决定了新获得样本信息覆盖之前掌握到的信息比率,通常设为比较小的值,保证学习过程的稳定,同时确保收敛性, α \alpha α越大,原来训练结果的保留就越少。
- 公式(1)中
γ
m
a
x
a
′
Q
(
s
′
,
a
′
)
\gamma max_{a^{'}}Q(s^{'},a{'})
γmaxa′Q(s′,a′)是贝尔曼方程,该方程式
Q
L
e
a
r
n
i
n
g
QLearning
QLearning的重要基石,表示在下一个状态
s
′
s^{'}
s′下采取某个动作可获得的最大价值。我们可以把他拆开来看:
其中, γ \gamma γ即衰减系数discount factor,这个参数决定了未来奖励在学习中的重要性,可以看出,如果 γ = 0 \gamma = 0 γ=0,模型将学习不到任何未来的奖励信息,变得短视,只关注当前的利益;如果 γ > = 1 \gamma>=1 γ>=1,期望价值被不断累加并没有衰减,这样期望价值可能会发散。 γ \gamma γ一般设为一个比1稍微小的数[2]。 - 到这里需要提醒大家, Q l e a r n i n g Qlearning Qlearning中的决策 a a a 的选择完全基于 Q Q Q表中的最大值所对应的动作,在2.1中动作的选择已经完成,并已经确定出下一个状态 s ′ s^{'} s′。2.3中通过贝尔曼方程更新 Q Q Q表的操作只对之后的决策起作用,这里 a ′ a^{'} a′不一定会是下一个状态所执行的动作, a ′ a^{'} a′在 Q l e a r n i n g Qlearning Qlearning中实际并没有发挥作用,所以说 Q l e a r n i n g Qlearning Qlearning是离线学习。(对应着在线学习Sarsa)
例子
该例子来源于莫烦的课程[3]
题目描述
在-----T中寻找T的位置,随机产生在-的位置,到达T即为成功。
代码
import numpy as np
import pandas as pd
import time
np.random.seed(2) #产生伪随机数列
# 公共变量
N_STATES = 6 # the length of the 1dimen
ACTIONS = [0,1] # available actions left:0 right:1
EPSILON = 0.9 # greedy police
ALPHA = 0.1 # learning rate
LAMBDA = 0.9 # discount factor
MAX_EPISODES = 13 # maximum episodes 这里只训练13次
FRESH_TIME = 0.3 #fresh time for one move
def build_q_table(n_states, actions):
table = pd.DataFrame(
np.zeros((n_states, len(actions))), #q_table initial values
columns = actions, #actions's name
)
#print(table)
return table
def choose_action(state, q_table):
#This is how to choose an action
state_actions = q_table.iloc[state,:]
if(np.random.uniform() > EPSILON) or (state_actions.all()==0): #act non-greedy
action_name = np.random.choice(ACTIONS)
else: #act greedy
action_name = state_actions.argmax()
return action_name
def get_env_feedback(S,A):
#This is how agent will interact with the environment
if A== 1: #move right
if S == N_STATES -2: #terminate
S_ = 'terminal' #S_表示下一个状态
R = 1
else:
S_ = S + 1
R = 0
else:
R = 0
if S == 0:
S_ = S #reach the wall
else:
S_ = S - 1
return S_,R
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)
def rl():
#main part of RL loop
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) #take action & get next state
q_predict = q_table.iloc[S,A]
if S_ != 'terminal':
q_target = R + LAMBDA * q_table.iloc[S_, :].max()
else:
q_target = R #next state is terminal
is_terminated = True #terminate this episode
q_table.iloc[S, A] += ALPHA * (q_target - q_predict) #update
S = S_ #move to next state
update_env(S, episode, step_counter+1)
step_counter += 1
return q_table
if __name__ == "__main__":
q_table = rl()
print('\r\nQ-table:\n')
print(q_table)
说明
之前教程里的代码在取dataframe中元素时用的是q_table.ix(),该用法在新版pandas中不兼容,这里我采用了q_table.iloc(数字,数字),并把列坐标[‘left’,‘right’]改成了[0,1]以适应iloc的用法。