使用强化学习Sarsa编写迷宫智能体

Sarsa和Q-learning是两种经典的强化学习算法,它们在更新动作值函数时有一些重要的区别。

首先,Sarsa算法使用的是on-policy学习方法,即它在学习时使用当前策略选择的动作更新动作值函数。因此,Sarsa算法对当前策略的评估更加准确,但也可能导致过度探索。

相比之下,Q-learning使用的是off-policy学习方法,即它在学习时使用最优策略选择的动作更新动作值函数。因此,Q-learning算法的学习过程更加高效,但它可能会低估当前策略的价值。

另一个区别是,Sarsa算法在每次更新动作值函数时都需要选择一个新的动作,而Q-learning算法则会选择当前状态下的最优动作来更新动作值函数。这意味着Sarsa算法会更加注重探索,而Q-learning算法则更加注重利用。

综上所述,Sarsa算法更适合探索性任务,而Q-learning算法更适合利用性任务。同时,它们的选择也取决于具体的问题和环境。

话不多说,直接看代码

其实Sarsa和q-learning代码的差异比较小,对比之前写的q-learning就可以发现
首先,环境一样的

import numpy as np
import time
import tkinter as tk

#定义一些常量
UNIT=40
WIDTH=4
HIGHT=4

#环境也写在一个类中
class Maze0506(tk.Tk,object):
    def __init__(self):
        super(Maze0506, self).__init__()
        #动作空间
        self.action_space=['u','d','l','r']
        self.n_action=len(self.action_space)
        self.title('maze')
        #建立画布
        self.geometry('{0}x{1}'.format(HIGHT*UNIT,WIDTH*UNIT))
        self.build_maze()

    def build_maze(self):
        self.canvas=tk.Canvas(self,bg='white',height=HIGHT*UNIT,width=WIDTH*UNIT)
        #绘制线框
        for i in range(0,WIDTH*UNIT,UNIT):
            x0,y0,x1,y1=i,0,i,WIDTH*UNIT
            self.canvas.create_line(x0,y0,x1,y1)
        for j in range(0,HIGHT*UNIT,UNIT):
            x0,y0,x1,y1=0,j,HIGHT*UNIT,j
            self.canvas.create_line(x0,y0,x1,y1)

        #创建迷宫中的地狱
        hell_center1=np.array([100,20])
        self.hell1=self.canvas.create_rectangle(hell_center1[0]-15,hell_center1[1]-15,hell_center1[0]+15,hell_center1[1]+15,fill='black')
        hell_center2=np.array([20,100])
        self.hell2=self.canvas.create_rectangle(hell_center2[0]-15,hell_center2[1]-15,hell_center2[0]+15,hell_center2[1]+15,fill='green')

        #创建出口
        out_center=np.array([100,100])
        self.oval=self.canvas.create_oval(out_center[0]-15,out_center[1]-15,out_center[0]+15,out_center[1]+15,fill='yellow')

        #智能体
        origin=np.array([20,20])
        self.finder=self.canvas.create_rectangle(origin[0]-15,origin[1]-15,origin[0]+15,origin[1]+15,fill='red')

        self.canvas.pack()#一定不要忘记加括号

    #智能体探索步
    def step(self,action):
        s=self.canvas.coords(self.finder)#获取智能体当前的位置
        #由于移动的函数需要传递移动大小的参数,所以这里需要定义一个移动的基准距离
        base_action=np.array([0,0])
        #根据action来确定移动方向
        if action==0:
            if s[1]>UNIT:
                base_action[1]-=UNIT
        elif action==1:
            if s[1]<HIGHT*UNIT:
                base_action[1]+=UNIT
        elif action==2:
            if s[0]>UNIT:
                base_action[0]-=UNIT
        elif action==3:
            if s[0]<WIDTH*UNIT:
                base_action[0]+=UNIT

        #移动
        self.canvas.move(self.finder,base_action[0],base_action[1])
        #移动后记录新位置指标
        s_=self.canvas.coords(self.finder)

        #反馈奖励,terminal不是自己赋予的,而是判断出来的
        if s_==self.canvas.coords(self.oval):
            reward=1
            done=True
            s_='terminal'#结束了
        elif s_ in (self.canvas.coords(self.hell2),self.canvas.coords(self.hell1)):
            reward=-1
            done=True
            s_='terminal'
        else:
            reward=0
            done=False
        #这个学习函数不但传入的参数多,返回的结果也多
        return s_,reward,done

    #渲染函数
    def render(self):
        time.sleep(0.1)
        self.update()#这里的update应该是画布里的自动更新函数

    #重置函数,当一轮走完后,需要重置画布到最初状态
    def resets(self):
        #其实,就是删掉原先的Finder,再重新定义新的Finder
        self.update()
        time.sleep(0.5)
        #删掉搜索这
        self.canvas.delete(self.finder)
        #删掉后,再重新定义最初位置
        origin=np.array([20,20])
        self.finder=self.canvas.create_rectangle(origin[0]-15,origin[1]-15,origin[0]+15,origin[1]+15,fill='red')
        return self.canvas.coords(self.finder)

接下来是智能体,这里是有一点区别,主要在体现在learn中,learn的参数多了一个a_,即s_状态下经过策略选择的动作。然后直接使用Q(s_,a_)来更新Q表

import numpy as np
import pandas as pd

class Q_table:
    def __init__(self,actions,learning_rate=0.01,reward_decay=0.9,e_greedy=0.9):#除了更新方式学习不一样,其他都是一样的
        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.float64)

    #动作选择
    def choose_action(self,s,e):
        self.check_state_exist(s)
        #然后用贪婪即可
        if np.random.uniform()<e:
            s_actions=self.q_table.loc[s,:]
            action=np.random.choice(s_actions[s_actions==np.max(s_actions)].index)
        else:
            action=np.random.choice(self.actions)
        return action

    #学习,注意,sarsa的学习和q-learning不一样,其实是它多了一个参数
    def learn(self,s,a,r,s_,a_):
        self.check_state_exist(s_)
        q_predict=self.q_table.loc[s,a]
        if s_!='terminal':
            q_target=r+self.reward_decay*self.q_table.loc[s_,a_]#这里就选择确定的值
        else:
            q_target=r
        #更新
        self.q_table.loc[s,a]+=self.learning_rate*(q_target-q_predict)
        return self.q_table

    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))

然后就是运行智能体玩游戏,update函数也有一点变化

from environment0506 import Maze0506
from agent0506 import Q_table

def update():
    epison=0.9#之所以额外定义这个参数目的就是通过传参来动态改变它的值
    for i in range(10):
        s=env.resets()
        a=RL.choose_action(str(s),epison)
        while True:
            env.render()
            s_,r,done=env.step(a)
            #再根据新状态选新动作,
            a_=RL.choose_action(str(s_),epison)
            #然后一起传入学习函数
            q_table=RL.learn(str(s),a,r,str(s_),a_)
            s=s_
            a=a_
            if done:
                break
            epison+=0.05
    print("game over")
    q_table.to_csv('output.csv')
    env.destroy()




if __name__ == '__main__':
    env=Maze0506()
    RL=Q_table(actions=list(range(env.n_action)))#动态赋予动作
    env.after(10,update)
    env.mainloop()

OK了大家可以自行运行看一看性能表现,不过呢,游戏环境设置的并不复杂,无法体现出明显的区别,重在学习

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值