【莫烦强化学习】视频笔记(二)3.Q_Learning算法实现走迷宫
程序员文章站
2023-11-01 14:07:46
第6节 Q学习实现走迷宫我们要实现的走迷宫的可视化界面像下面视频所展示的一样,红色的探索者要走到黄色圆圈所在的“” 通过强化学习学习走迷宫 ......
第6节 Q学习实现走迷宫
我们要实现的走迷宫的可视化界面像下图所展示的一样,红色的探索者要走到黄色圆圈所在的“宝藏”位置。黑色的地方是陷阱,如果走到陷阱,会得到-1的奖励值,如果到达“宝藏”所在区域,会得到+1的奖励值。
环境的编写是通过python自带的GUI模块tkinter
编写的,这里不详细介绍其用法,tkinter
教程链接:tkinter教程
6.1 Q-Learning类
这次要以class类的形式来编写Q-Learning中的功能函数,新建一个python文件,专门存放Q-Learning类,有初始化、选择动作、学习更新参数、查看状态是否存在四个模块。
初始化
设定学习中所需的参数,在类的构造函数中,传入参数,分别是:
- 动作空间:上、下、左、右
- 学习率:参数更新速度控制
- -衰减因子:对后来状态的重视程度
- 贪婪数:值越大,贪婪程度越大,随机性越小
- 初始Q表:建立表格,列名为四个动作空间名称字符串
import numpy as np
import pandas as pd
class QLearning:
def __init__(self, actions, learning_rate=0.01, reward_decay=0.9, e_greedy=0.9): # 初始换函数,后面是默认参数
self.actions = actions # 动作空间
self.lr = learning_rate # 学习率
self.gamma = reward_decay # 奖励衰减
self.epsilon = e_greedy # 贪婪度
self.q_table = pd.DataFrame(columns=self.actions, dtype=np.float64) # 初始Q表
检查状态是否存在
为什么会有这个函数?因为初始化时的表格是没有行的,表格的状态是动态增加的,出现过的状态才会添加到Q表中:
def check_state_exit(self, state): # 输入状态
if state not in self.q_table.index: # Q表中没有该状态
# 插入新的行,Q值初始化为0
self.q_table = self.q_table.append(pd.Series([0] * len(self.actions), index = self.q_table.columns, name = state))
选择动作
采用贪婪进行动作的选择,需要注意的是,当选择Q值最大的动作时,选出来的动作也有可能有多个,还要从这几个动作中再随机选出一个。
def choose_action(self, observation): # 根据当前的状态选择动作
self.check_state_exit(observation) # 检查状态是否存在,不存在添加到Q表中
if np.random.uniform() < self.epsilon: # 直接选择Q值最大的动作
state_action = self.q_table.loc[observation, :] # 选择对应的一行
# 由于Q值最大的动作也有可能有多个,我们需要对这些动作随机选择(乱序)
action = np.random.choice(state_action[state_action == np.max(state_action)].index)
else:
action = np.random.choice(self.actions) # 随机选择一个动作
return action
学习更新参数
直接根据伪代码,计算更新后的Q值,这里先计算了当前s、a对应的Q值(预测Q值),后计算了估计的Q值(实际Q值),根据公式更新Q表:
def learn(self, s, a, r, s_):
self.check_state_exit(s_) # 查看状态s_是否存在,s_是在选择动作之后与环境交互获得的下一状态
q_predict = self.q_table.loc[s, a] # 当前状态s和动作a对应的Q值
if s_ != 'terminal': # 若下一步不是终态
q_target = r + self.gamma * self.q_table.loc[s_, :].max() # 实估计的际Q值,用来更新的值
else:
q_target = r; # 否则直接为立即回报
self.q_table.loc[s, a] += self.lr * (q_target - q_predict) # 更新Q(s,a)
6.2 主循环
主循环进行的是整个伪代码的流程,代码如下:
注意: 这里的迷宫环境是tkinter
编写的,这里不详细说明环境的编写,涉及到的函数也不做解释。
from Qlearning import QLearning
from maze_env import Maze
def update(): # 更新主函数
for episode in range(100): # 玩游戏的局数
observation = env.reset() # 初始化环境
while True:
env.render() # 刷新图像
action = RL.choose_action(str(observation)) # 根据当前状态选择动作
observation_, reward, done = env.step(action) # 动作与环境交互,获得下一状态、奖励值和是否为终态的反馈
RL.learn(str(observation), action, reward, str(observation_)) # 更新Q表
observation = observation_ # 转移到下一状态
if done:
break
print('Game Over') # 一次游戏结束
env.destroy() # 关闭窗口
if __name__ == '__main__':
env = Maze() # 创建环境
RL = QLearning(actions=list(range(env.n_actions))) # Q学习类
env.after(100, update) # 100ms后调用函数
env.mainloop() # 开始可视化环境
本文地址:https://blog.csdn.net/cherreggy/article/details/107346398