RL中的Q-learning在拿奖杯游戏的表现

  • 强化学习与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_actionsself.num_states = num_statesself.exp_rate = exp_rateself.lr = lrself.gamma = gammaself.q_table = np.zeros((self.num_states, self.num_actions))def choose_action(self, state):     # ε-greedy# choose action with most expected valueif np.random.uniform(0, 1) <= self.exp_rate:    # 如果随机数小于exp_rateaction = np.random.choice(self.num_actions)     # 在动作集中随机选择一个动作else:# greedy action, choose the agent with highest q# if there are multiple max, we randomly choose oneqs = self.q_table[state, :]     # 取出动作状态值函数action = np.random.choice(np.where(qs == qs.max())[0])return actiondef 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# updateself.q_table[s, a] += self.lr * (q_new - q_old)

然后定义环境(网格世界)
定义坐标和状态的互相转化函数
设置好rewards矩阵,qtabel矩阵
然后定义了状态转移的get_transition_model函数,之后的状态转移就根据这个transition model进行转移
reset函数用来重置每幕中的agent位置,即每次都从出发点开始学习
step函数将agent和GridWord函数进行了整合,将封装好的函数集合成了整体,以便在最后的大循环中可以直接调用

class GridWorld:terminal_states = (3, 7)    # 终止状态def __init__(self):"""Initialize the world with board data.0   0   0   1       1表示拿到奖杯0    2   0   -1      2表示障碍物无法通过0 0   0   0       -1表示遇见骷髅"""self.board = np.zeros((3, 4))self.board[1, 1] = 2self.board[0, 3] = 1self.board[1, 3] = -1self.num_rows, self.num_cols = self.board.shapeself.num_states = self.num_rows * self.num_colsself.num_actions = 4self.reward_table = self.get_reward_table()self.transition_model = self.get_transition_model()def get_state_from_pos(self, pos):"""Maps (x, y) position on the board to state index从位置坐标获得状态"""return pos[0] * self.num_cols + pos[1]def get_pos_from_state(self, state):"""Maps state index to (x, y) position on the board从状态获得位置坐标"""return state // self.num_cols, state % self.num_colsdef get_reward_table(self):"""Map each state to its corresponding reward.初始化 状态回报矩阵,state-rewrd matrix"""reward_table = np.zeros(self.num_states)for r in range(self.num_rows):for c in range(self.num_cols):s = self.get_state_from_pos((r, c))if s in self.terminal_states:reward_table[s] = self.board[r, c]return reward_tabledef get_transition_model(self, random_rate=.1):"""The transition_model describing the probability of environment going tonext state (s') given that we are currently at state (s) and take the action (a).P = P[s' | (s, a)]  当前状态s下采取行动a到达s'的概率"""transition_model = np.zeros((self.num_states, self.num_actions, self.num_states))   # 在当前状态下,采取行动,而可能又到达状态的概率for r in range(self.num_rows):for c in range(self.num_cols):s = self.get_state_from_pos((r, c))     # 获得当前状态possible_s_prime = np.zeros(self.num_actions)if self.board[r, c] == 0:for a in range(self.num_actions):new_r, new_c = r, cif a == 0:      # 向上走new_r = max(r - 1, 0)elif a == 1:    # 向右走new_c = min(c + 1, self.num_cols - 1)elif a == 2:    # 向下走new_r = min(r + 1, self.num_rows - 1)elif a == 3:    # 向左走new_c = max(c - 1, 0)if self.board[new_r, new_c] == 2:       # 如果撞到障碍物,原地不动new_r, new_c = r, cs_prime = self.get_state_from_pos((new_r, new_c))possible_s_prime[a] = s_primeelse:   # 如果是1、2、-1即不可以行走的地方,则原地不动possible_s_prime = np.ones(self.num_actions) * sfor a in range(self.num_actions):transition_model[s, a, int(possible_s_prime[a])] += 1 - random_ratetransition_model[s, a, int(possible_s_prime[(a + 1) % self.num_actions])] += random_rate / 2.0transition_model[s, a, int(possible_s_prime[(a - 1) % self.num_actions])] += random_rate / 2.0return transition_modeldef reset(self):start_pos = (2, 0)      # 从左下角出发self.cur_state = self.get_state_from_pos(start_pos)     # 当前状态self.epi_reward = 0return self.cur_statedef step(self, action):p = self.transition_model[self.cur_state, action]next_state = np.random.choice(self.num_states, p=p)     # 根据transition_model的权重选择下一个状态reward = self.reward_table[next_state]self.epi_reward += rewardself.cur_state = next_statedone = Falseif self.cur_state in self.terminal_states:done = Truereturn self.cur_state, reward, done, []     # 返回下一状态,奖励,是否结束和信息(为空)

展示运行的结果函数
这个与文章的内容没什么关系,但是可视化还是很重要的,没有什么难点
且注释都很详细

def show_world(env, agent, episode, show_state=False, show_q_table=True):fig_size = (12, 8)num_rows, num_cols = env.num_rows, env.num_colsfig, ax0 = plt.subplots(1, 1, figsize=fig_size)a_shift = [(0, 0.3), (0.4, 0), (0, -.4), (-.3, 0)]ax0.axis('off')     # 把横坐标关闭# plot the gridsfor i in range(num_cols + 1):   # 按列画线if i == 0 or i == num_cols:ax0.plot([i, i], [0, num_rows], color='black')else:ax0.plot([i, i], [0, num_rows], alpha=0.7,color='grey', linestyle='dashed')for i in range(num_rows + 1):   # 按行画线if i == 0 or i == num_rows:ax0.plot([0, num_cols], [i, i], color='black')else:ax0.plot([0, num_cols], [i, i], alpha=0.7,color='grey', linestyle='dashed')# plot the objects on the gridsfor i in range(num_rows):for j in range(num_cols):y = (num_rows - 1 - i)x = jif env.board[i, j] == 2:rect = patches.Rectangle((x, y), 1, 1, edgecolor='none', facecolor='black', alpha=0.6)ax0.add_patch(rect)elif env.board[i, j] == 1:rect = patches.Rectangle((x, y), 1, 1, edgecolor='none', facecolor='red', alpha=0.6)ax0.add_patch(rect)ax0.text(x + 0.4, y + 0.5, "r = +1")elif env.board[i, j] == -1:rect = patches.Rectangle((x, y), 1, 1, edgecolor='none', facecolor='green', alpha=0.6)ax0.add_patch(rect)ax0.text(x + 0.4, y + 0.5, "r = -1")else:# visualize the q tableif show_q_table:s = env.get_state_from_pos((i, j))qs = agent.q_table[s, :]for a in range(len(qs)):dx, dy = a_shift[a]c = 'k'q = qs[a]if q > 0:c = 'r'elif q < 0:c = 'g'ax0.text(x + dx + 0.3, y + dy + 0.5,"{:.2f}".format(qs[a]), c=c)if show_state:s = env.get_state_from_pos((i, j))ax0.text(x + 0.3, y + 0.1, "state = {}".format(str(s)))# draw the agenti, j = env.get_pos_from_state(env.cur_state)y = (num_rows - 1 - i)x = jax0.plot([x + 0.5], [y + 0.5], marker="o",linestyle='none', markersize=20, color='blue')ax0.set_title("episode: {}".format(str(episode)))plt.show(block=False)plt.pause(5)plt.close()

最后的使整个程序跑起来的代码如下

env = GridWorld()       # 初始化
agent = Agent(4, 4 * 3)
num_episodes = 31for i in range(1,num_episodes):state = env.reset()if not i % 10:show_world(env, agent, i)while True:action = agent.choose_action(state)     # 选择动作next_state, reward, done, info = env.step(action)agent.learn(state, action, reward, next_state)  # 学习--更新q值state = next_state# show_world(env, agent, i + 1)if done:break

运行结果

最后策略的制定:根据每个状态的,采取不同动作所能获得的q值最大的动作去做动作,直到走到结束状态。
代码中一共设置了30次迭代,最后学出从上面走到终点的策略。直观上也很容易理解,有人说从右边走也行啊,但是到state=6的时候有更有可能会走进骷髅中,这是我们不希望看到的,所以从上面走是最佳策略。

强化学习(RL)中的Q-learning在拿奖杯游戏的表现相关推荐

  1. 强化学习入门 : 一文入门强化学习 (Sarsa、Q learning、Monte-carlo learning、Deep-Q-Network等)

    最近博主在看强化学习的资料,找到这两个觉得特别适合入门,一个是"一文入门深度学习",一个是"莫烦PYTHON". 建议:看资料的时候可以多种资料一起参考,一边调 ...

  2. [强化学习实战]出租车调度-Q learning SARSA

    出租车调度-Q learning & SARSA 案例分析 实验环境使用 同策时序差分学习调度 异策时序差分调度 资格迹学习调度 结论 代码链接 案例分析 本节考虑Gym库里出租车调度问题(T ...

  3. 强化学习(六) - 连续空间中的强化学习(RL in Continuous Spaces)及相关实例

    强化学习(六) - 连续空间中的强化学习 6.1 连续空间中的强化学习 6.2 离散空间和连续空间 6.3 离散化 实例:小车上山 6.3.1 相关程序 6.3.2 程序注解 (1) 环境测试 (2) ...

  4. 强化学习RL学习笔记2-概述(2)

    强化学习笔记专栏传送 上一篇:强化学习RL学习笔记1-概述(1) 下一篇:强化学习RL学习笔记3-gym了解与coding实践 目录 强化学习笔记专栏传送 前言 Major Components of ...

  5. 分层强化学习综述:Hierarchical reinforcement learning: A comprehensive survey

    论文名称:Hierarchical reinforcement learning: A comprehensive survey 论文发表期刊:ACM Computing Surveys 期刊影响因子 ...

  6. 9个 强化学习现实生活中的应用

    "大多数人类和动物的学习可以说属于无监督学习.有人说,如果智能是一块蛋糕,那么无监督学习就是蛋糕,监督学习是锦上添花,强化学习是锦上添花." 这似乎很有趣,对吧? 强化学习是最接近 ...

  7. 强化学习 最前沿之Hierarchical reinforcement learning(一)

    强化学习-最前沿系列 深度强化学习作为当前发展最快的方向,可以说是百家争鸣的时代.针对特定问题,针对特定环境的文章也层出不穷.对于这么多的文章和方向,如果能撇一隅,往往也能够带来较多的启发. 本系列文 ...

  8. 深度强化学习之模仿学习(Imitation Learning)

      上一部分研究的是奖励稀疏的情况,本节的问题在于如果连奖励都没有应该怎么办,没有奖励的原因是,一方面在某些任务中很难定量的评价动作的好坏,如自动驾驶,撞死人和撞死动物的奖励肯定不同,但分别为多少却并 ...

  9. 主要内容: 本文提出了一种基于(ppo)的微电网最优调度方法。 该方法采用强化学习(RL)来学习调度策略,并积累相应的调度知识。 同时,引入ppo模型,将微电网调度策略动作从离散动作空间扩展到连续动作

    MATLAB代码:微电网 强化学习 关键词:微电网 强化学习 RL Reinforcement Learning 参考文档:<Optimal Scheduling of Microgrid Ba ...

最新文章

  1. 《计算机科学导论》一2.3 非位置化数字系统
  2. 关于微型计算机主板的描述错误的是,2016年9月计算机一级考试试题及答案「单选」...
  3. Build boost 1.66.0 with c++11
  4. codevs 1147 排座椅
  5. [FI] SAP 关于标准成本、计划成本、目标成本、实际成本
  6. 洛谷 P1309 瑞士轮 解题报告
  7. flash背景透明、置底、禁止放大 右键菜单
  8. 对属性可以赋值的位置
  9. RHEL/CentOS下编译安装Nginx
  10. Linux 块设备,Block Layer层架构演变
  11. goroutine调度详解,以及进程、线程、协程区别
  12. 让盘古分词支持最新的Lucene.Net 3.0.3
  13. linux下的screen工具配置(针对 string escape)
  14. 使用Ntdsutil.exe捕获系统状态数据
  15. IDEA中如何使用debug调试项目 一步一步详细教程
  16. ORACLE 8023学习总结
  17. ParticleDesigner 粒子编辑器使用
  18. 【报错】Cannot mix different versions of joi schemas(Postman)
  19. Android 屏幕旋转的处理
  20. 【SQL文档整理系列1】MySQL创建procedure(可以用来造测试数据)

热门文章

  1. 机器视觉工程师(实习岗)面经
  2. 从《龙之战》想起 前一段时间,和江浙地区的企业信息化CIO们聊天,也深刻
  3. 丽江古城历史悠久,古朴自然
  4. python统计中英文字符_如何统计文本中的中英文字符数?Python帮你解决
  5. Python 保存 网页上的图片
  6. 现实与理想(中国台湾大学彭明辉)
  7. 视频直播网站开发的最佳实践
  8. 维护异地恋的十大方法
  9. C语言 !! 的含义
  10. 开关电源布局布线总结