每天学点算法->强化学习->Q_learning走迷宫

今天给大家分享如何用Q_learning算法来实现走迷宫,我们的红色方块会一次次的尝试不同的格子,直到落入黑格子,获得惩罚*1;或者走进黄格子,获得奖励*1为止。每一次游戏都会更新Q_table的权重,以实现红色方块下一次能够更加快速的找到黄格子。

本文参照了莫烦python的博客:https://morvanzhou.github.io/tutorials/machine-learning/reinforcement-learning/2-2-tabular-q1/

Q_learning的整个算法过程如下图,具体含义:

首先:初始化一个Q_table;

循环一定次数;

       在循环中根据奖励和action更新Q_table;

,这些在本文中都会以代码例子的形式表述。

每天学点算法->强化学习->Q_learning走迷宫_第1张图片

 

本文主要分为以下几大块:

一.主循环搭建

二.RL_brain选择动作&更新Q_table的实现

三.环境编写(代码)

 

一:主循环搭建

我们创建100次循环用来训练更新Q_table。

首先,初始化环境,获取红色方块的开始位置;核心代码:position=env.reset()

其次,我们根据Q_table中的在position位置走不同方向(即动作)reward,来选择reward最高的action;核心代码:action=RL.choose_action(str(position))

第三,我们让环境执行该action,获得环境的反馈:走进黑色各自-1,走进黄色格子+1,其他+0,更新我们的Q_table;核心代码:position_next,reward,done=env.step(action);RL.learn(str(position),action,reward,str(position_next))

最后,我们由于已经执行了action,即我们在当前position向某个方向走了一步,所以我们更新position=position_next

以下为主循环所有代码:

from maze_env import Maze
from RL_brain import QLearningTable

"""
循环更新Q_table

"""
def update():
    for episode in range(100):
        position=env.reset()

        while True:
            env.render()

            #选择执行的动作,条件为在q_table中奖励最大
            action=RL.choose_action(str(position))
            position_next,reward,done=env.step(action)

            #根据环境反馈的奖励reward更新q_table
            RL.learn(str(position),action,reward,str(position_next))

            position=position_next
            if done:
                print('--------episode:{0}-------'.format(episode))
                print(RL.q_table)
                break;
    
    print('game over')
    env.destroy()

if __name__=='__main__':
    env=Maze()
    RL=QLearningTable(actions=list(range(env.n_actions)))

    env.after(100,update)
    env.mainloop()

二.RL_brain选择动作&更新Q_table的实现

在RL_brain中:

首先,我们先创建一个空的Q_table;核心代码:self.q_table=pd.DataFrame(columns=self.actions,dtype=np.float64)

然后,我们实现主循环第二步中用到的,根据position选择奖励最大的action的方法:choose_action(self,positon),90%的概率我们按照Q_table的奖励来随机选择奖励最大的action;10%的概率我们随机选择一个action,这样可以是我们的红色方块探索更多的区域,以找到更短的路径找到黄色的方块

第三,我们实现更新Q_table的方法。根据Q_learning的整个算法过程,

Q_tabel.loc[positon,action]位置的奖励需要被更新为:Q_tabel.loc[positon,action]+=动作奖励+α*(γ理想奖励-实际奖励);

动作奖励 我们在主循环第三步中得到;

理想奖励 则=γ*执行该动作后获得的最大奖励=γ*q_table.loc[position_next,:].max()

实际奖励 则=红色方块执行action获得的Q_table中的奖励=q_table.loc[position,action]

第四,实现检查position在Q_table中是否存在的方法,不存在则append到q_table中,并用0填充各个action的reward;新增position如图所示:

每天学点算法->强化学习->Q_learning走迷宫_第2张图片

经过一次次的训练,我们的Q_table也会慢慢趋于稳定,此时红色方块就能很快的找到黄色方块了

训练一次:

每天学点算法->强化学习->Q_learning走迷宫_第3张图片

训练48次:

每天学点算法->强化学习->Q_learning走迷宫_第4张图片

训练100次:

每天学点算法->强化学习->Q_learning走迷宫_第5张图片

以下是QL_brain的全部代码:

"""
用于完成
    1.创建Q_table
    2.根据Q_table,选择动作
    3.根据环境反馈reward,action更新Q_table
"""
import numpy as np;
import pandas as pd;

class QLearningTable:
    def __init__(self,actions,learning_rate=0.01,reward_decay=0.9,e_greedy=0.9):
        self.actions=actions
        self.q_table=pd.DataFrame(columns=self.actions,dtype=np.float64)
        self.rl=learning_rate
        self.gamma=reward_decay
        self.epsilon=e_greedy

    """
    根据当前位置&状态表选择动作
    """
    def choose_action(self,position):
        self.check_state_exist(position)

        #90%的概率按q_table奖励选择
        #10%的概率随机选择
        if np.random.rand()

三.环境编写

环境编写这部分不想怎么讲,它是针对每个实际的事件个性化编写的,有兴趣可以看我代码的注释.

以下是环境全部代码:

import numpy as np
import time
import sys
if sys.version_info.major == 2:
    import Tkinter as tk
else:
    import tkinter as tk


UNIT = 40   # pixels
MAZE_H = 4  # grid height
MAZE_W = 4  # grid width


class Maze(tk.Tk, object):
    def __init__(self):
        super(Maze, self).__init__()
        self.action_space = ['u', 'd', 'l', 'r']
        self.n_actions = len(self.action_space)
        self.title('maze')
        self.geometry('{0}x{1}'.format(MAZE_H * UNIT, MAZE_H * UNIT))
        self._build_maze()

    def _build_maze(self):
        self.canvas = tk.Canvas(self, bg='white',
                           height=MAZE_H * UNIT,
                           width=MAZE_W * UNIT)

        # create grids
        for c in range(0, MAZE_W * UNIT, UNIT):
            x0, y0, x1, y1 = c, 0, c, MAZE_H * UNIT
            self.canvas.create_line(x0, y0, x1, y1)
        for r in range(0, MAZE_H * UNIT, UNIT):
            x0, y0, x1, y1 = 0, r, MAZE_H * UNIT, r
            self.canvas.create_line(x0, y0, x1, y1)

        # create origin
        origin = np.array([20, 20])

        #创建陷阱:黑色方块
        # hell
        hell1_center = origin + np.array([UNIT * 2, UNIT])
        self.hell1 = self.canvas.create_rectangle(
            hell1_center[0] - 15, hell1_center[1] - 15,
            hell1_center[0] + 15, hell1_center[1] + 15,
            fill='black')
        # hell
        hell2_center = origin + np.array([UNIT, UNIT * 2])
        self.hell2 = self.canvas.create_rectangle(
            hell2_center[0] - 15, hell2_center[1] - 15,
            hell2_center[0] + 15, hell2_center[1] + 15,
            fill='black')

        #创建目标,黄色方块
        # create oval
        oval_center = origin + UNIT * 2
        self.oval = self.canvas.create_oval(
            oval_center[0] - 15, oval_center[1] - 15,
            oval_center[0] + 15, oval_center[1] + 15,
            fill='yellow')

        #创建红色方块初始位置
        # create red rect
        self.rect = self.canvas.create_rectangle(
            origin[0] - 15, origin[1] - 15,
            origin[0] + 15, origin[1] + 15,
            fill='red')

        # pack all
        self.canvas.pack()

    def reset(self):
        self.update()
        time.sleep(0.5)
        self.canvas.delete(self.rect)
        origin = np.array([20, 20])
        self.rect = self.canvas.create_rectangle(
            origin[0] - 15, origin[1] - 15,
            origin[0] + 15, origin[1] + 15,
            fill='red')
        # return observation
        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] > UNIT:
                base_action[1] -= UNIT
        elif action == 1:   # down
            if s[1] < (MAZE_H - 1) * UNIT:
                base_action[1] += UNIT
        elif action == 2:   # right
            if s[0] < (MAZE_W - 1) * UNIT:
                base_action[0] += UNIT
        elif action == 3:   # left
            if s[0] > UNIT:
                base_action[0] -= UNIT

        self.canvas.move(self.rect, base_action[0], base_action[1])  # move agent

        s_ = self.canvas.coords(self.rect)  # next state


        #设定奖励;
        #黑色陷阱 -1
        #黄色目标 +1
        #其他位置 +0
        # reward function
        if s_ == self.canvas.coords(self.oval):
            reward = 1
            done = True
            s_ = 'terminal'
        elif s_ in [self.canvas.coords(self.hell1), self.canvas.coords(self.hell2)]:
            reward = -1
            done = True
            s_ = 'terminal'
        else:
            reward = 0
            done = False

        return s_, reward, done

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


def update():
    for t in range(10):
        s = env.reset()
        while True:
            env.render()
            a = 1
            s, r, done = env.step(a)
            if done:
                break

if __name__ == '__main__':
    env = Maze()
    env.after(100, update)
    env.mainloop()

 

你可能感兴趣的:(python,人工智能,机器学习,每天学点算法,强化学习)