Gym中Taxi-V2出租车调度的时序差分学习(SARSA)

时序差分更新汲取了动态规划方法中“自益”的思想,用现有价值更新价值估计,不需要等到回合结束也可以更新价值估计。所以时序差分更新可以用于回合制任务,也可用于连续制任务。

虽然这个出租车调度环境的SARSA算法例子属于离散非连续状态的,但是也可以某种程度上巩固一下之前在莫烦大佬那里学的Q-learning与SARSA知识,为之后的的学习奠定基础。

初始化环境

import gym
import pandas as pd
import numpy as np
import matplotlib.pyplot  as plt

env = gym.make('Taxi-v2')
state = env.reset()        # 初始化环境
taxirow, taxicol, passloc, destidx = env.unwrapped.decode(state)     # decode state to get position of taxi and passenger
print ('出租车位置 = {}'.format((taxirow,taxicol)))
print ('乘客位置 = {}'.format(passloc))
print ('乘客目的地 = {}'.format(destidx))
env.render()        # 渲染可视化,显示当前局势
env.step(1)        # 走一步

初始化结果

小矩形为出租车,RGBY为四个接客地点

这个坏境的观测是[0-500)的值,出租车的5x5位置;pass_loc乘客位置共有5个,即四个位置等待的状态+在车上的状态;destination有4个,表示目的地,全部状态总数是(5x5)x5x4=500,我调出了出租车坏境的源代码,下图一目了然


出租车500个状态的定义方式

定义类并初始化

class SARSAAGENT:
    def __init__(self,env,gamma = 0.9, learning_rate = 0.1, epsilon = .01):
        self.gamma = gamma
        self.learning_rate = learning_rate    #学习率
        self.epsilon = epsilon
        self.action_n = env.action_space.n
        self.q = np.zeros((env.observation_space.n, env.action_space.n))    #初始化大小为500*6的q表  

ϵ-贪婪算法

强化学习本质上是exploit&explore的过程,那么这两者的概率是怎么决定呢?
设置ϵ=0.1,那么就表示有10%的概率会进行“探索”操作,而90%会进行“利用”操作


image

贪心策略

    def decide(self,state):
        if np.random.uniform()>self.epsilon:        #贪心策略
            action = self.q[state].argmax()        #在q表中state中选择可以获得最大值的action
        else:
            action = np.random.randint(self.action_n)
        return action

    def learn(self, state, action, reward, state_, done, action_):
        u = reward + self.gamma*self.q[state_, action_]* (1-done)        #计算回报估计值
        td_error = u - self.q[state, action]                    #计算通过动作估计与当前已知表的差值
        self.q[state, action] += self.learning_rate*td_error  #更新价值

至此我们agent的定义就完成了,这里用到的是SARSA算法,即用下一步的action计算回报的估计值。下一步的action_是实实在在根据原有的q表做过的,正因为如此这种算法更加保守。

u = reward + self.gamma*self.q[state_, action_]* (1-done)

这里的reward在Taxi-V2环境中定义的是,出租车完成任务可以得到20个奖励(收到车费),每次试图移动一格算作-1奖励(有点像汽车在路上跑烧油的感觉),当乘客不在拉客位置上或者车没开到目的地就让乘客下车时,获得-10奖励(乘客差评)。

智能体与环境的交互

def play_sarsa(env,agent,train = False, render = False):
    episode_reward = 0
    observation = env.reset()       # 获得初始状态
action = agent.decide(observation)
    while True:
        if render:
            env.render()
        state_, reward, done,_ = env.step(action)
        episode_reward += reward
        action_ = agent.decide(state_)
        if train:
            agent.learn(observation,action,reward,state_,done,action_)
        if done:
            break
        observation, action = state_, action_       #将下一步的状态和动作变成当前状态
    return episode_reward

训练

episodes = 2000
episode_rewards = []
for episode in range (episodes):
    episode_reward = play_sarsa(env, agent, train = True)
    episode_rewards.append(episode_reward)
plt.plot(episode_rewards)
print(pd.DataFrame(agent.q))

单次训练得到的值是episode_reward,将每次训练的奖励都放在episode_rewards中,得到训练episodes次数的奖励值。

训练结果


可以看出总体的rewards在训练2500次以上后就收敛到-10左右,说明司机能很快的接到乘客并送到目的地。

状态价值函数&动作价值函数

对《强化学习》第一章的基本概念又忘掉了不少,现在重新复习一下

状态价值函数
动作价值函数

两者的区别在于是否做了动作a,而且两者可以互相表示。

状态价值函数可以这样理解:在当前状态下,采取不同的动作时有不同的概率,即概率pi,对q进行加权求和,即为状态价值函数v。值得注意的是,这里的q就是当前状态的动作价值函数。

动作价值函数可以这样理解:在当前状态价值v(s)下,采取的动作是确定的,但是跳转到下一状态s’和奖励r是不确定的,有转移概率Pr,此时的动作价值函数,即(当前动作确定奖励r+折扣因子gamma未确定的下一步状态s'带来的状态价值v(s'))转移概率Pr

以一个吃饭吃饱问题来说明情况
动力系统:s状态a动作下得到的r与s'对应关系



状态-->>动作,这里的策略pi是当前状态到动作的转移概率



状态价值函数和动作价值函数的值可由下式表示

学习的其他知识

如果seed中数字一样,则生成同一个随机数
若通过当前时间为seed起始数,可以产生近似完全随机的数字

random.seed( 10 )
print ("Random number with seed 10 : {}".format( random.random()))
random.seed(time.time())
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容