【强化学习】python 实现 q-learning 例二
本文作者:hhh5460
本文地址:https://www.cnblogs.com/hhh5460/p/10134855.html
问题情境
一个2*2的迷宫,一个入口,一个出口,还有一个陷阱。如图
(图片来源:https://jizhi.im/blog/post/intro_q_learning)
这是一个二维的问题,不过我们可以把这个降维,变为一维的问题。
感谢:https://jizhi.im/blog/post/intro_q_learning。网上看了无数文章,无数代码,都不得要领!直到看了这篇里面的三个矩阵:reward,transition_matrix,valid_actions才真正理解q-learning算法如何操作,如何实现!
Kaiser的代码先睹为快,绝对让你秒懂q-learning算法,当然我也做了部分润色:
import numpy as np
import random '''
2*2的迷宫
---------------
| 入口 | |
---------------
| 陷阱 | 出口 |
---------------
# 来源:https://jizhi.im/blog/post/intro_q_learning 每个格子是一个状态,此时都有上下左右停5个动作 任务:通过学习,找到一条通径
''' gamma = 0.7 # u, d, l, r, n
reward = np.array([( 0, -10, 0, -1, -1), #0,状态0
( 0, 10, -1, 0, -1), #
(-1, 0, 0, 10, -1), #
(-1, 0, -10, 0, 10)],#
dtype=[('u',float),('d',float),('l',float),('r',float),('n',float)]) q_matrix = np.zeros((4, ),
dtype=[('u',float),('d',float),('l',float),('r',float),('n',float)]) transition_matrix = np.array([(-1, 2, -1, 1, 0), # 如 state:0,action:'d' --> next_state:2
(-1, 3, 0, -1, 1),
( 0, -1, -1, 3, 2),
( 1, -1, 2, -1, 3)],
dtype=[('u',int),('d',int),('l',int),('r',int),('n',int)]) valid_actions = np.array([['d', 'r', 'n'], #0,状态0
['d', 'l', 'n'], #
['u', 'r', 'n'], #
['u', 'l', 'n']])# for i in range(1000):
current_state = 0
while current_state != 3:
current_action = random.choice(valid_actions[current_state]) # 只有探索,没有利用 next_state = transition_matrix[current_state][current_action]
next_reward = reward[current_state][current_action]
next_q_values = [q_matrix[next_state][next_action] for next_action in valid_actions[next_state]] #待取最大值 q_matrix[current_state][current_action] = next_reward + gamma * max(next_q_values) # 贝尔曼方程(不完整)
current_state = next_state print('Final Q-table:')
print(q_matrix)
0.相关参数
epsilon = 0.9 # 贪婪度 greedy
alpha = 0.1 # 学习率
gamma = 0.8 # 奖励递减值
1.状态集
探索者的状态,即其可到达的位置,有4个。所以定义
states = range(4) # 状态集,从0到3
那么,在某个状态下执行某个动作之后,到达的下一个状态如何确定呢?
def get_next_state(state, action):
'''对状态执行动作后,得到下一状态'''
#u,d,l,r,n = -2,+2,-1,+1,0
if state % 2 != 1 and action == 'r': # 除最后一列,皆可向右(+1)
next_state = state + 1
elif state % 2 != 0 and action == 'l': # 除最前一列,皆可向左(-1)
next_state = state -1
elif state // 2 != 1 and action == 'd': # 除最后一行,皆可向下(+2)
next_state = state + 2
elif state // 2 != 0 and action == 'u': # 除最前一行,皆可向上(-2)
next_state = state - 2
else:
next_state = state
return next_state
2.动作集
探索者处于每个状态时,可行的动作,只有上下左右4个。所以定义
actions = ['u', 'd', 'l', 'r'] # 动作集。上下左右,也可添加动作'n',表示停留
那么,在某个给定的状态(位置),其所有的合法动作如何确定呢?
def get_valid_actions(state):
'''取当前状态下的合法动作集合,与reward无关!'''
global actions # ['u','d','l','r','n'] valid_actions = set(actions)
if state % 2 == 1: # 最后一列,则
valid_actions = valid_actions - set(['r']) # 去掉向右的动作
if state % 2 == 0: # 最前一列,则
valid_actions = valid_actions - set(['l']) # 去掉向左
if state // 2 == 1: # 最后一行,则
valid_actions = valid_actions - set(['d']) # 去掉向下
if state // 2 == 0: # 最前一行,则
valid_actions = valid_actions - set(['u']) # 去掉向上
return list(valid_actions)
3.奖励集
探索者到达每个状态(位置)时,要有奖励。所以定义
rewards = [0,0,-10,10] # 奖励集。到达位置3(出口)奖励10,位置2(陷阱)奖励-10,其他皆为0
显然,取得某状态state下的奖励就很简单了:rewards[state] 。根据state,按图索骥即可,无需额外定义一个函数。
4.Q table
最重要。Q table是一种记录状态-行为值 (Q value) 的表。常见的q-table都是二维的,基本长下面这样:
(注意,也有3维的Q table)
所以定义
q_table = pd.DataFrame(data=[[0 for _ in actions] for _ in states],
index=states, columns=actions)
5.Q-learning算法
Q-learning算法的伪代码
Q value的更新是根据贝尔曼方程:
$$Q(s_t,a_t) \leftarrow Q(s_t,a_t) + \alpha[r_{t+1} + \lambda \max _{a} Q(s_{t+1}, a) - Q(s_t,a_t)] \tag {1}$$
好吧,是时候实现它了:
# 总共探索300次
for i in range(300):
# 0.从最左边的位置开始(不是必要的)
current_state = 0
#current_state = random.choice(states)
while current_state != states[-1]:
# 1.取当前状态下的合法动作中,随机(或贪婪)地选一个作为 当前动作
if (random.uniform(0,1) > epsilon) or ((q_table.ix[current_state] == 0).all()): # 探索
current_action = random.choice(get_valid_actions(current_state))
else:
current_action = q_table.ix[current_state].idxmax() # 利用(贪婪)
# 2.执行当前动作,得到下一个状态(位置)
next_state = get_next_state(current_state, current_action)
# 3.取下一个状态所有的Q value,待取其最大值
next_state_q_values = q_table.ix[next_state, get_valid_actions(next_state)]
# 4.根据贝尔曼方程,更新 Q table 中当前状态-动作对应的 Q value
q_table.ix[current_state, current_action] += alpha * (rewards[next_state] + gamma * next_state_q_values.max() - q_table.ix[current_state, current_action])
# 5.进入下一个状态(位置)
current_state = next_state print('\nq_table:')
print(q_table)
可以看到,与例一的代码一模一样,不差一字!
6.环境及其更新
这里的环境貌似必须用到GUI,有点麻烦;而在命令行下,我又不知如何实现。所以暂时算了,不搞了。
7.完整代码
'''
最简单的四个格子的迷宫
---------------
| start | |
---------------
| die | end |
--------------- 每个格子是一个状态,此时都有上下左右4个动作 作者:hhh5460
时间:20181217
''' import pandas as pd
import random epsilon = 0.9 # 贪婪度 greedy
alpha = 0.1 # 学习率
gamma = 0.8 # 奖励递减值 states = range(4) # 0, 1, 2, 3 四个状态
actions = list('udlr') # 上下左右 4个动作。还可添加动作'n',表示停留
rewards = [0,0,-10,10] # 奖励集。到达位置3(出口)奖励10,位置2(陷阱)奖励-10,其他皆为0 q_table = pd.DataFrame(data=[[0 for _ in actions] for _ in states],
index=states, columns=actions) def get_next_state(state, action):
'''对状态执行动作后,得到下一状态'''
#u,d,l,r,n = -2,+2,-1,+1,0
if state % 2 != 1 and action == 'r': # 除最后一列,皆可向右(+1)
next_state = state + 1
elif state % 2 != 0 and action == 'l': # 除最前一列,皆可向左(-1)
next_state = state -1
elif state // 2 != 1 and action == 'd': # 除最后一行,皆可向下(+2)
next_state = state + 2
elif state // 2 != 0 and action == 'u': # 除最前一行,皆可向上(-2)
next_state = state - 2
else:
next_state = state
return next_state def get_valid_actions(state):
'''取当前状态下的合法动作集合
global reward
valid_actions = reward.ix[state, reward.ix[state]!=0].index
return valid_actions
'''
# 与reward无关!
global actions
valid_actions = set(actions)
if state % 2 == 1: # 最后一列,则
valid_actions = valid_actions - set(['r']) # 无向右的动作
if state % 2 == 0: # 最前一列,则
valid_actions = valid_actions - set(['l']) # 无向左
if state // 2 == 1: # 最后一行,则
valid_actions = valid_actions - set(['d']) # 无向下
if state // 2 == 0: # 最前一行,则
valid_actions = valid_actions - set(['u']) # 无向上
return list(valid_actions) # 总共探索300次
for i in range(300):
# 0.从最左边的位置开始(不是必要的)
current_state = 0
#current_state = random.choice(states)
while current_state != states[-1]:
# 1.取当前状态下的合法动作中,随机(或贪婪)地选一个作为 当前动作
if (random.uniform(0,1) > epsilon) or ((q_table.ix[current_state] == 0).all()): # 探索
current_action = random.choice(get_valid_actions(current_state))
else:
current_action = q_table.ix[current_state].idxmax() # 利用(贪婪)
# 2.执行当前动作,得到下一个状态(位置)
next_state = get_next_state(current_state, current_action)
# 3.取下一个状态所有的Q value,待取其最大值
next_state_q_values = q_table.ix[next_state, get_valid_actions(next_state)]
# 4.根据贝尔曼方程,更新 Q table 中当前状态-动作对应的 Q value
q_table.ix[current_state, current_action] += alpha * (rewards[next_state] + gamma * next_state_q_values.max() - q_table.ix[current_state, current_action])
# 5.进入下一个状态(位置)
current_state = next_state print('\nq_table:')
print(q_table)
8.效果图
9.补充
又搞了一个numpy版本,比pandas版本的快了一个数量级!!代码如下
'''
最简单的四个格子的迷宫
---------------
| start | |
---------------
| die | end |
--------------- 每个格子是一个状态,此时都有上下左右停5个动作
''' # 作者:hhh5460
# 时间:20181218 import numpy as np epsilon = 0.9 # 贪婪度 greedy
alpha = 0.1 # 学习率
gamma = 0.8 # 奖励递减值 states = range(4) # 0, 1, 2, 3 四个状态
actions = list('udlrn') # 上下左右停 五个动作
rewards = [0,0,-10,10] # 奖励集。到达位置3(出口)奖励10,位置2(陷阱)奖励-10,其他皆为0 # 给numpy数组的列加标签,参考https://cloud.tencent.com/developer/ask/72790
q_table = np.zeros(shape=(4, ), # 坑二:这里不能是(4,5)!!
dtype=list(zip(actions, ['float']*5)))
#dtype=[('u',float),('d',float),('l',float),('r',float),('n',float)])
#dtype={'names':actions, 'formats':[float]*5}) def get_next_state(state, action):
'''对状态执行动作后,得到下一状态'''
#u,d,l,r,n = -2,+2,-1,+1,0
if state % 2 != 1 and action == 'r': # 除最后一列,皆可向右(+1)
next_state = state + 1
elif state % 2 != 0 and action == 'l': # 除最前一列,皆可向左(-1)
next_state = state -1
elif state // 2 != 1 and action == 'd': # 除最后一行,皆可向下(+2)
next_state = state + 2
elif state // 2 != 0 and action == 'u': # 除最前一行,皆可向上(-2)
next_state = state - 2
else:
next_state = state
return next_state def get_valid_actions(state):
'''取当前状态下的合法动作集合,与reward无关!'''
global actions # ['u','d','l','r','n'] valid_actions = set(actions)
if state % 2 == 1: # 最后一列,则
valid_actions = valid_actions - set(['r']) # 去掉向右的动作
if state % 2 == 0: # 最前一列,则
valid_actions = valid_actions - set(['l']) # 去掉向左
if state // 2 == 1: # 最后一行,则
valid_actions = valid_actions - set(['d']) # 去掉向下
if state // 2 == 0: # 最前一行,则
valid_actions = valid_actions - set(['u']) # 去掉向上
return list(valid_actions) for i in range(1000):
#current_state = states[0] # 固定
current_state = np.random.choice(states,1)[0]
while current_state != 3:
if (np.random.uniform() > epsilon) or ((np.array(list(q_table[current_state])) == 0).all()): # q_table[current_state]是numpy.void类型,只能这么操作!!
current_action = np.random.choice(get_valid_actions(current_state), 1)[0]
else:
current_action = actions[np.array(list(q_table[current_state])).argmax()] # q_table[current_state]是numpy.void类型,只能这么操作!!
next_state = get_next_state(current_state, current_action)
next_state_q_values = [q_table[next_state][action] for action in get_valid_actions(next_state)]
q_table[current_state][current_action] = rewards[next_state] + gamma * max(next_state_q_values)
current_state = next_state print('Final Q-table:')
print(q_table)
10.补充2:三维Q table实现!
经过不断的试验,终于撸出了一个三维版的Q table,代码如下!
'''
最简单的四个格子的迷宫
---------------
| start | |
---------------
| die | end |
--------------- 每个格子是一个状态,此时都有上下左右停5个动作
''' '''三维 Q table 版!!''' # 作者:hhh5460
# 时间:20181218 import numpy as np
import random # np.random.choice不能选二维元素! epsilon = 0.9 # 贪婪度 greedy
alpha = 0.1 # 学习率
gamma = 0.8 # 奖励递减值 states = [(0,0),(0,1),(1,0),(1,1)] #状态集,四个位置
actions = [(-1,0),(1,0),(0,-1),(0,1)] #动作集,上下左右
rewards = [[ 0., 0.], # 奖励集
[-10.,10.]] # q_table是三维的,注意把动作放在了第三维!
# 最里面的[0.,0.,0.,0.]表示某一个状态(格子)对应的四个动作“上下左右”的Q value
q_table = np.array([[[0.,0.,0.,0.],[0.,0.,0.,0.]],
[[0.,0.,0.,0.],[0.,0.,0.,0.]]]) def get_next_state(state, action):
'''对状态执行动作后,得到下一状态'''
if ((state[1] == 1 and action == (0,1)) or # 最后一列、向右
(state[1] == 0 and action == (0,-1)) or # 最前一列、向左
(state[0] == 1 and action == (1,0)) or # 最后一行、向下
(state[0] == 0 and action == (-1,0))): # 最前一行、向上
next_state = state
else:
next_state = (state[0] + action[0], state[1] + action[1])
return next_state def get_valid_actions(state):
'''取当前状态下的合法动作集合'''
valid_actions = []
if state[1] < 1: # 除最后一列,可向右
valid_actions.append((0,1))
if state[1] > 0: # 除最前一列,可向左(-1)
valid_actions.append((0,-1))
if state[0] < 1: # 除最后一行,可向下
valid_actions.append((1,0))
if state[0] > 0: # 除最前一行,可向上
valid_actions.append((-1,0))
return valid_actions # 总共探索300次
for i in range(1000):
# 0.从最左边的位置开始(不是必要的)
current_state = (0,0)
#current_state = random.choice(states)
#current_state = tuple(np.random.randint(2, size=2))
while current_state != states[-1]:
# 1.取当前状态下的合法动作中,随机(或贪婪)地选一个作为 当前动作
if (np.random.uniform() > epsilon) or ((q_table[current_state[0],current_state[1]] == 0).all()): # 探索
current_action = random.choice(get_valid_actions(current_state))
else:
current_action = actions[q_table[current_state[0],current_state[1]].argmax()] # 利用(贪婪)
# 2.执行当前动作,得到下一个状态(位置)
next_state = get_next_state(current_state, current_action)
# 3.取下一个状态所有的Q value,待取其最大值
next_state_q_values = [q_table[next_state[0],next_state[1],actions.index(action)] for action in get_valid_actions(next_state)]
# 4.根据贝尔曼方程,更新 Q table 中当前状态-动作对应的 Q value
q_table[current_state[0],current_state[1],actions.index(current_action)] += alpha * (rewards[next_state[0]][next_state[1]] + gamma * max(next_state_q_values) - q_table[current_state[0],current_state[1],actions.index(current_action)])
# 5.进入下一个状态(位置)
current_state = next_state print('\nq_table:')
print(q_table)
11.课后思考题
有缘看到此文的朋友,请尝试下实现更大规模的迷宫问题,评论交作业哦。迷宫如下:
(图片来源:https://jizhi.im/blog/post/intro_q_learning)
【强化学习】python 实现 q-learning 例二的更多相关文章
- 深度强化学习(DQN-Deep Q Network)之应用-Flappy Bird
深度强化学习(DQN-Deep Q Network)之应用-Flappy Bird 本文系作者原创,转载请注明出处:https://www.cnblogs.com/further-further-fu ...
- 机器学习之强化学习概览(Machine Learning for Humans: Reinforcement Learning)
声明:本文翻译自Vishal Maini在Medium平台上发布的<Machine Learning for Humans>的教程的<Part 5: Reinforcement Le ...
- 深度强化学习(Deep Reinforcement Learning)入门:RL base & DQN-DDPG-A3C introduction
转自https://zhuanlan.zhihu.com/p/25239682 过去的一段时间在深度强化学习领域投入了不少精力,工作中也在应用DRL解决业务问题.子曰:温故而知新,在进一步深入研究和应 ...
- 【转】【强化学习】Deep Q Network(DQN)算法详解
原文地址:https://blog.csdn.net/qq_30615903/article/details/80744083 DQN(Deep Q-Learning)是将深度学习deeplearni ...
- 廖雪峰网站:学习python函数—定义函数(二)
def my_abs(x): if x >= 0: return x else: return -x print(my_abs(-99)) # 空函数 def nop(): pass # 参数检 ...
- [Reinforcement Learning] 强化学习介绍
随着AlphaGo和AlphaZero的出现,强化学习相关算法在这几年引起了学术界和工业界的重视.最近也翻了很多强化学习的资料,有时间了还是得自己动脑筋整理一下. 强化学习定义 先借用维基百科上对强化 ...
- Deep Learning专栏--强化学习之从 Policy Gradient 到 A3C(3)
在之前的强化学习文章里,我们讲到了经典的MDP模型来描述强化学习,其解法包括value iteration和policy iteration,这类经典解法基于已知的转移概率矩阵P,而在实际应用中,我们 ...
- 深度强化学习(DRL)专栏(一)
目录: 1. 引言 专栏知识结构 从AlphaGo看深度强化学习 2. 强化学习基础知识 强化学习问题 马尔科夫决策过程 最优价值函数和贝尔曼方程 3. 有模型的强化学习方法 价值迭代 策略迭代 4. ...
- (转) 深度强化学习综述:从AlphaGo背后的力量到学习资源分享(附论文)
本文转自:http://mp.weixin.qq.com/s/aAHbybdbs_GtY8OyU6h5WA 专题 | 深度强化学习综述:从AlphaGo背后的力量到学习资源分享(附论文) 原创 201 ...
- 强化学习论文(Scalable agent alignment via reward modeling: a research direction)
原文地址: https://arxiv.org/pdf/1811.07871.pdf ======================================================== ...
随机推荐
- Flutter 相机定制
Flutter中与硬件相关的部分,一直都挺蛋疼的.方案基本上有两种,自己写,或者等出相关的库. 最近做的一个项目中,需要对相机做定制.有过相关模块开发经验的,就知道这种需求并不简单,况且是这种跨平台解 ...
- 监听软件异常崩溃并且保持日志--CrashHandler编写自己的异常捕获类
平时写代码,我们可能会抛出各种异常,这些异常有些是我们测试过程中发现进行解决的,但是也有一些异常是我们未知的,不论是代码的逻辑问题还是Android本身底层的一些bug,我们都需要及时了解并进行解决. ...
- springcloud 入门 7 (zuul路由网关)
Zuul简介: Zuul的主要功能是路由转发和过滤器.路由功能是微服务的一部分,比如/api/user转发到到user服务,/api/shop转发到到shop服务.zuul默认和Ribbon结合实现了 ...
- Python 文档学习
1.在命令行执行Python脚本(获取输入) import sys print(sys.argv[1]) 2.compile Python(编译Python) 编译后,生成的文件是.pyc,但是要知道 ...
- [20180614]删除bootstrap$记录无法启动2.txt
[20180614]删除bootstrap$记录无法启动2.txt --//前几天看链接http://www.xifenfei.com/2018/05/willfully-delete-bootstr ...
- MySQL重做日志相关
Ⅰ.事务的实现 这里我们先抛出答案,通过答案再展开分析 特性 实现 A(原子性) redo C(一致性) undo I(隔离性) lock D(持久性) redo/undo 本节针对redo展开分 ...
- [Compression] Hadoop 压缩
0. 说明 Hadoop 压缩介绍 && 压缩格式总结 && 压缩编解码器测试 1. 介绍 [文件压缩的好处] 文件压缩的好处如下: 减少存储文件所需要的磁盘空间 加速 ...
- 设置UITextView光标从起始位置开始
一.刚开始用的时候,我加载的UITextView一直是这种情况: 当我在ViewController中设置这个属性: self.automaticallyAdjustsScrollViewInsets ...
- 使用requests模块保存网络上的图片
import requests url = 'https://www.baidu.com/img/bd_logo1.png' r = requests.get(url=url) with open(' ...
- 通过SQL直接插入、修改ArcGIS SDE空间表中的数据
基于Arcgis Server 10.1 +Oracle 11g环境测试 ArcGIS SDE ? 1 2 INSERT INTO CAMERA_INFO(OBJECTID,ID,SHAPE) ...