用Python走迷宫|Q-Learning|强化学习

简介: 用Q-learning实现走迷宫。

Q-Learning走迷宫

上文中我们了解了Q-Learning算法的思想,基于这种思想我们可以实现很多有趣的功能和小demo,本文让我们通过Q-Learning算法来实现用计算机来走迷宫。

原理简述

我们先从一个比较高端的例子说起,AlphaGo大家都听说过,其实在AlphaGo的训练过程中就使用了Q-Learning的思想,对于机器下错棋和下对棋的时候给予一定的惩罚和奖励,当经过无数次的训练之后,机器自然就会直接向着奖励前进,直接选择对的位置进行下棋,久而久之在各种场景下都能选择对的位置下棋的机器人就能够把人类打败了。

再回到我们今天要讲的例子上来,走迷宫和下棋的原理其实类似,我们要走的路无非就是两种:顺畅的路和有障碍的路,那我们要做的事也就很明了了,当触碰到障碍的时候给予一定的惩罚,走了正确的路时给予一定的奖励,这样经过不断的训练,机器就应该能够知道该如何”走迷宫“了。我们要走的迷宫示意图如下:

在这里插入图片描述

代码实现

构建画布

我们首先要做的就是来构建画布并且画出迷宫,Python中Tkinter就是一个很好的画图工具(相对于其他的库来说,该库运行快,且不容易卡死)

构建画布的时候,我们除了需要构建基本的图形和迷宫,还需要实现行动的方式,对于简单的迷宫来说,我们只需要设定“上下左右”的行动方式就可以了,如果走到了黑块就得到-1的惩罚并结束回合,走到黄块得到1的奖励并结束回合。其余的解释放在代码注释中,画布代码如下:

# coding: utf-8
import sys
import time
import numpy as np
if sys.version_info.major == 2:
    import Tkinter as tk
else:
    import tkinter as tk


class Maze(tk.Tk, object):
    UNIT = 40  # 像素
    MAZE_H = 6  # 网格高度
    MAZE_W = 6  # 网格宽度

    def __init__(self):
        super(Maze, self).__init__()
        self.action_space = ['U', 'D', 'L', 'R']
        self.n_actions = len(self.action_space)
        self.title('迷宫')
        self.geometry('{0}x{1}'.format(self.MAZE_H * self.UNIT,
                                       self.MAZE_W * self.UNIT))
        self._build_maze()

    # 画矩形
    # x y 格坐标
    # color 颜色
    def _draw_rect(self, x, y, color):
        center = self.UNIT / 2
        w = center - 5
        x_ = self.UNIT * x + center
        y_ = self.UNIT * y + center
        return self.canvas.create_rectangle(x_ - w,
                                            y_ - w,
                                            x_ + w,
                                            y_ + w,
                                            fill=color)

    # 初始化迷宫
    def _build_maze(self):
        h = self.MAZE_H * self.UNIT
        w = self.MAZE_W * self.UNIT
        # 初始化画布
        self.canvas = tk.Canvas(self, bg='white', height=h, width=w)
        # 画线
        for c in range(0, w, self.UNIT):
            self.canvas.create_line(c, 0, c, h)
        for r in range(0, h, self.UNIT):
            self.canvas.create_line(0, r, w, r)

        # 陷阱
        self.hells = [
            self._draw_rect(3, 2, 'black'),
            self._draw_rect(3, 3, 'black'),
            self._draw_rect(3, 4, 'black'),
            self._draw_rect(3, 5, 'black'),
            self._draw_rect(4, 5, 'black'),
            self._draw_rect(1, 0, 'black'),
            self._draw_rect(1, 1, 'black'),
            self._draw_rect(1, 2, 'black'),
            self._draw_rect(1, 4, 'black'),
            self._draw_rect(1, 5, 'black')
        ]
        self.hell_coords = []
        for hell in self.hells:
            self.hell_coords.append(self.canvas.coords(hell))

        # 奖励
        self.oval = self._draw_rect(4, 5, 'yellow')
        # 玩家对象
        self.rect = self._draw_rect(0, 0, 'red')

        self.canvas.pack()  #执行画

    # 重新初始化(用于撞到黑块后重新开始)
    def reset(self):
        self.update()
        time.sleep(0.5)
        self.canvas.delete(self.rect)
        self.rect = self._draw_rect(0, 0, 'red')
        self.old_s = None
        #返回 玩家矩形的坐标 [5.0, 5.0, 35.0, 35.0]
        return self.canvas.coords(self.rect)

    # 走下一步
    def step(self, action):
        s = self.canvas.coords(self.rect)
        base_action = np.array([0, 0])
        if action == 0:  # up
            if s[1] > self.UNIT:
                base_action[1] -= self.UNIT
        elif action == 1:  # down
            if s[1] < (self.MAZE_H - 1) * self.UNIT:
                base_action[1] += self.UNIT
        elif action == 2:  # right
            if s[0] < (self.MAZE_W - 1) * self.UNIT:
                base_action[0] += self.UNIT
        elif action == 3:  # left
            if s[0] > self.UNIT:
                base_action[0] -= self.UNIT

        # 根据策略移动红块
        self.canvas.move(self.rect, base_action[0], base_action[1])
        s_ = self.canvas.coords(self.rect)

        # 判断是否得到奖励或惩罚
        done = False
        if s_ == self.canvas.coords(self.oval):
            reward = 1
            done = True
        elif s_ in self.hell_coords:
            reward = -1
            done = True
        #elif base_action.sum() == 0:
        #    reward = -1
        else:
            reward = 0

        self.old_s = s
        return s_, reward, done

    def render(self):
        time.sleep(0.01)
        self.update()

实现算法

实现算法的过程就是按照我们上一文中所说到的Q-Learning的算法运行方式来进行,代码实现如下:

# coding: utf-8
import pandas as pd
import numpy as np


class q_learning_model_maze:
    def __init__(self,
                 actions,
                 learning_rate=0.01,
                 reward_decay=0.9,
                 e_greedy=0.99):
        self.actions = actions
        self.learning_rate = learning_rate
        self.reward_decay = reward_decay
        self.e_greedy = e_greedy
        self.q_table = pd.DataFrame(columns=actions, dtype=np.float32)

    # 检查状态是否存在
    def check_state_exist(self, state):
        if state not in self.q_table.index:
            self.q_table = self.q_table.append(
                pd.Series(
                    [0] * len(self.actions),
                    index=self.q_table.columns,
                    name=state,
                ))

    # 选择动作
    def choose_action(self, s):
        self.check_state_exist(s)
        if np.random.uniform() < self.e_greedy:

            state_action = self.q_table.loc[s, :]
            state_action = state_action.reindex(
                np.random.permutation(
                    state_action.index))  # 防止相同列值时取第一个列,所以打乱列的顺序
            action = state_action.idxmax()
        else:
            action = np.random.choice(self.actions)
        return action

    # 更新q表
    def rl(self, s, a, r, s_):
        self.check_state_exist(s_)
        q_predict = self.q_table.loc[s, a]  # q估计
        if s_ != 'terminal':
            q_target = r + self.reward_decay * self.q_table.loc[
                s_, :].max()  # q现实
        else:
            q_target = r

        self.q_table.loc[s, a] += self.learning_rate * (q_target - q_predict)
        

训练

训练的时候我们需要做的就是选择状态并执行,最后把执行的结果更新到状态表中。

# coding: utf-8

def update():
    for episode in range(100):
        s = env.reset()
        while True:
            env.render()

            # 选择一个动作
            action = RL.choose_action(str(s))

            # 执行这个动作得到反馈(下一个状态s 奖励r 是否结束done)
            s_, r, done = env.step(action)

            # 更新状态表
            RL.rl(str(s), action, r, str(s_))

            s = s_

            if done:
                print(episode)
                break


if __name__ == "__main__":
    env = Maze()
    RL = q_learning_model_maze(actions=list(range(env.n_actions)))
    env.after(10, update)  # 设置10ms的延迟
    env.mainloop()
相关文章
|
7月前
|
机器学习/深度学习 算法 调度
基于多动作深度强化学习的柔性车间调度研究(Python代码实现)
基于多动作深度强化学习的柔性车间调度研究(Python代码实现)
353 1
|
7月前
|
机器学习/深度学习 算法 安全
【强化学习应用(八)】基于Q-learning的无人机物流路径规划研究(Python代码实现)
【强化学习应用(八)】基于Q-learning的无人机物流路径规划研究(Python代码实现)
531 6
|
8月前
|
机器学习/深度学习 算法 调度
【EI复现】基于深度强化学习的微能源网能量管理与优化策略研究(Python代码实现)
【EI复现】基于深度强化学习的微能源网能量管理与优化策略研究(Python代码实现)
331 0
|
机器学习/深度学习 算法 机器人
使用 Python TorchRL 进行多代理强化学习
本文详细介绍了如何使用TorchRL库解决多代理强化学习(MARL)问题,重点讨论了在多代理环境中应用近端策略优化(PPO)。通过使用VMAS模拟器,该文展示了如何在GPU上并行训练多机器人系统,使其在避免碰撞的同时到达目标。文章涵盖了依赖项安装、PPO原理、策略与评论家网络设计、数据收集及训练循环,并强调了TorchRL在简化开发流程、提升计算效率方面的优势。无论是集中式还是分布式评论家配置,TorchRL均能有效支持复杂的MARL研究与实践。
328 5
使用 Python TorchRL 进行多代理强化学习
|
9月前
|
XML 存储 Java
Python-docx编号列表解析:从XML迷宫到结构化数据的破局之道
本文深入解析了Word文档中自动编号的存储机制及解析难题,探讨了其在技术处理中的障碍,并通过三种实战方案对比,帮助开发者高效提取结构化数据。内容涵盖底层XML结构、常见问题解决方案及性能优化技巧,适用于合同条款、文档自动化处理等场景。
591 0
|
9月前
|
XML 存储 缓存
Python-docx编号列表解析:从XML迷宫到结构化数据的破局之道
Word文档中的自动编号功能虽便捷,却在技术处理时常成为障碍。本文深入解析Word文档的XML结构,揭示编号信息的存储机制,并提供多种基于Python的解决方案,涵盖跨平台解析、性能优化及固定模板处理,助力开发者突破编号解析难题,实现合同条款等内容的结构化提取与处理。
387 0
|
12月前
|
算法 数据可视化 Python
Python中利用遗传算法探索迷宫出路
本文探讨了如何利用Python和遗传算法解决迷宫问题。迷宫建模通过二维数组实现,0表示通路,1为墙壁,&#39;S&#39;和&#39;E&#39;分别代表起点与终点。遗传算法的核心包括个体编码(路径方向序列)、适应度函数(评估路径有效性)、选择、交叉和变异操作。通过迭代优化,算法逐步生成更优路径,最终找到从起点到终点的最佳解决方案。文末还展示了结果可视化方法及遗传算法的应用前景。
266 5
|
Python
"揭秘!Python如何运用神秘的正则表达式,轻松穿梭于网页迷宫,一键抓取隐藏链接?"
【8月更文挑战第21天】Python凭借其强大的编程能力,在数据抓取和网页解析领域表现出高效与灵活。通过结合requests库进行网页请求及正则表达式进行复杂文本模式匹配,可轻松提取网页信息。本示例展示如何使用Python和正则表达式解析网页链接。首先确保已安装requests库,可通过`pip install requests`安装。接着,利用requests获取网页内容,并使用正则表达式提取所有`&lt;a&gt;`标签的`href`属性。
288 0
|
机器学习/深度学习 算法 调度
【强化学习】基于深度强化学习的微能源网能量管理与优化策略研究【Python】
本项目基于深度Q网络(DQN)算法,通过学习预测负荷、可再生能源输出及分时电价等信息,实现微能源网的能量管理与优化。程序以能量总线模型为基础,结合强化学习理论,采用Python编写,注释清晰,复现效果佳。内容涵盖微能源网系统组成、Q学习算法原理及其实现,并提供训练奖励曲线、发电单元功率、电网交互功率和蓄电池调度等运行结果图表,便于对照文献学习与应用。
|
机器学习/深度学习 人工智能 算法
强化学习在游戏AI中的应用,从基本原理、优势、应用场景到具体实现方法,以及Python在其中的作用
本文探讨了强化学习在游戏AI中的应用,从基本原理、优势、应用场景到具体实现方法,以及Python在其中的作用,通过案例分析展示了其潜力,并讨论了面临的挑战及未来发展趋势。强化学习正为游戏AI带来新的可能性。
1388 4

推荐镜像

更多