RL中的Q-learning在拿奖杯游戏的表现
强化学习与Q-learning
随着知识的学习AI的面纱也被慢慢揭开,强化学习的详细解释其他blog上有详尽的入门解释。但是文章的主题是这方面,就说一说我的理解,下面的描述可能更针对对RL已经有一定了解的群体。总的来说就是对问题进行建模,对policy,value,q值,environment进行不同程度上的构建,然后经过不同算法的训练更新比如(时序差分,蒙特卡洛),其核心思想是bellman方程,最后经过收敛判断得出结果。当然对于大型的问题有更加复杂的解法,价值函数逼近,策略函数逼近等等。大一些的应用的问题代码量多,模型建立更加复杂(这里指数学模型,而不是RL里的model),但万变不离其中。当然后人是站在前面巨人的肩膀之上的,后面的创新肯定会搭高人类知识的阶梯。
下面再八股式地介绍一下Q-learning:
首先Q-learning可以被视为离轨策略的时序学习,下面解释一下什么是同轨学习和离轨学习
目标策略:用来学习并成为最优策略
行动策略:用来智能体的行动样本
同轨学习:目标策略和行动策略在同一个训练模型中产生
离轨学习:目标策略和行动策略不在同一个模型中产生,行动策略可能会单独产生
对于行动策略单独产生的迭代,由于与问题相关性更低,收敛的速度会更长,但效果在同等情况下会更好
下面是Q-learning算法
算法参数:步长α∈(0,1],取很小的ε>0
对所有的s∈S,a∈A(s),初始化Q(s,a),其中Q(终止状态) = 0
对每幕:
初始化S
对幕中的每一步循环:
使用从Q得到的策略(ε-greedy),在S处选择A
执行A,观察到R和S‘
Q(S,A) <-- Q(S,A) + α[R+γmax{Q(S',A)} - Q(S,A)]
S <-- S'
直到S是终止状态
现在提出问题,为什么Q-learning是离轨策略?找了一些资料,网上貌似没有解答,个人认为是Q值的迭代中的max选择,这就是自己产生了行动策略,与模型无关。
直观来看,S,A,S’和A‘的动作关系如下图
在下面的奖杯游戏中马上就可以看到形象的例子:
拿奖杯游戏与建模
游戏和文章的灵感思路是从这里引出的,因为感觉这篇文章的博主讲的不是很清楚,关键部分跳过且感觉代码是copy的(没有冒犯的意思)。花了一些时间学习,看懂了模型和代码,想在此基础上再进一步,所以也吃水不忘挖井人。下面的一些图会引用原文章的示意图。
状态从上到下从左到右进行编号,我们的目标是从左下角(蓝色的点出发)花最小的代价走到终点,即红色的地方
黑色的state=5是障碍物,无法通过;绿色的state=7是骷髅,到达了会有负奖励。白色格子的路就是通道。
只有两个最终状态会有奖励reward,分别是+和-1.其他时候奖励都是0.
根据算法,我们要初始化状态矩阵s,q值矩阵qtable,还有一些参数
然后设定总的迭代次数,将上面的Q-learning伪代码实现。每次迭代中,我们都让代理人(agent)从state = 8出发,根据ε-greedy选择动作,再贪心地根据Q(S,A) <-- Q(S,A) + α[R+γmax{Q(S’,A)} - Q(S,A)]公式来更新当前的Q值,直到走到最终状态(最终状态包括3和7);依次重复以上动作,直至迭代完设定的次数。(当然我们可以根据q值变化大小的绝对上限来终止循环,为了简单还是设置了迭代次数)
下面是对代码的剖析:
代码分析
笔者在源码的基础上,加上了详细的注释,请食用
代码只要依次粘贴到python的一个文件中,运行即可,因为篇幅原因,笔者最后就不再重新整合到一起占用篇幅了
如果读者都嫌整合到一起复制粘贴麻烦,直接私聊我,我给你发源文件。
首先进行导包操作,设置好随机数以备后面的使用
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as patches # 图形类
plt.xkcd() # 设置画图风格(漫画)
np.random.seed(2022) # 随机数种子
定义一个代理人agent类,由他在环境中不断从状态中采取动作再到下一个动作,一直学习下去循环往复,直到迭代结束得出最终结果。
首先定义全局变量,最终状态terminal state
初始化变量,定义选择动作函数,和对Q值进行更新的learn函数
class Agent:
terminal_states = (3, 7) # 终止状态
# 3对应奖杯的位置,7对应骷髅的位置,从上往下,从左往右的顺序数,且从0开始
def __init__(self, num_actions, num_states, exp_rate=0.2, lr=0.1, gamma=0.9):
self.num_actions = num_actions
self.num_states = num_states
self.exp_rate = exp_rate
self.lr = lr
self.gamma = gamma
self.q_table = np.zeros((self.num_states, self.num_actions))
def choose_action(self, state): # ε-greedy
# choose action with most expected value
if np.random.uniform(0, 1) <= self.exp_rate: # 如果随机数小于exp_rate
action = np.random.choice(self.num_actions) # 在动作集中随机选择一个动作
else:
# greedy action, choose the agent with highest q
# if there are multiple max, we randomly choose one
qs = self.q_table[state, :] # 取出动作状态值函数
action = np.random.choice(np.where(qs == qs.max())[0])
return action
def learn(self, s, a, r, s_):
# s状态,a动作,r即时奖励,s_演化的下一个动作
q_old = self.q_table[s, a]
if s_ not in self.terminal_states:
q_new = r + self.gamma * self.q_table[s_, :].max() # Q-learning取最大的动作状态值
else:
q_new = r
# update
self.q_table[s, a] += self.lr * (q_new - q_old)
然后定义环境(网格世界)
定义坐标和状态的互相转化函数
设置好rewards矩阵,qtabel矩阵
然后定义了状态转移的get_transition_model函数,之后的状态转移就根据这个transition model进行转移
reset函数用来重置每幕中的agent位