Reinforcement Learning强化学习系列之四:时序差分TD

引言

前面一篇讲的是蒙特卡洛的强化学习方法,蒙特卡罗强化学习算法通过考虑采样轨迹,克服了模型未知给策略估计造成的困难,不过蒙特卡罗方法有一个缺点,就是每次需要采样完一个轨迹之后才能更新策略。蒙特卡洛方法没有充分利用学习任务的MDP结构,而时序差分学习方法Temporal Difference(TD)就充分利用了MDP结构,效率比MC要高,这篇文章介绍一下TD算法

Sarsa算法

Sarsa的算法如下:
这里写图片描述
Sarsa算法是on-policy方法,其原始策略和更新策略是一致的,而其更新策略和MC不一样的是其策略更新不需要采样一个完整的轨迹,在执行完一个动作后就可以更新其值函数。

Q-learning算法

这里写图片描述
Q-learning算法则是一个off-policy的方法,其原始策略和值函数更新策略不一致,同样的也不需要进行采样一个轨迹进行策略更新,和Sarsa算法不一样的是,Q-learning在更新值函数的时候使用的是贪心策略,而不是 ϵ ϵ -greedy策略。

两者的区别

为了比较Sarsa算法和Q-learning算法的不同,我们使用一个具体的问题进行展示。问题描述如下:


这里写图片描述
如上图所示,有一个12*4的格子,从左下角开始走,走的方向可以是上下左右(不能超过方格),走到右下角为终点,游戏结束,其中在最下面的一行有10个被标记了的区域,一旦走到这个区域,将会回到原点并继续游戏。


游戏分析:
1. 用户走到被标记区域的reward值为-100,其余的区域reward值为-1
2. 游戏的状态为用户的两个坐标x,y

由此可以规划这个游戏的场景Environment:以开始点S建立坐标,开始点设置为(0,0),x轴坐标向右,y轴坐标向上。代码构建如下:

class CliffEnvironment(object):

    def __init__(self):
        self.width=12
        self.height=4
        self.move=[[0,1],[0,-1],[-1,0],[1,0]] #up,down,left,right
        self.nA=4
        self._reset()



    def _reset(self):
        self.x=0
        self.y=0
        self.end_x=11
        self.end_y=0
        self.done=False



    def observation(self):
        return tuple((self.x,self.y)),self.done
    def clip(self,x,y):
        x = max(x,0)
        x = min(x,self.width-1)
        y = max(y,0)
        y = min(y,self.height-1)
        return x,y
    def _step(self,action):
        self.done = False
        self.x+=self.move[action][0]
        self.y+=self.move[action][1]
        self.x,self.y=self.clip(self.x,self.y)

        if self.x>=1 and self.x<=10 and self.y==0:
            reward=-100
            self._reset()
        elif self.x==self.width-1 and self.y==0:
            reward=0
            self.is_destination=True
            self.done=True
        else:
            reward=-1
        return tuple((self.x,self.y)),reward,self.done

其中_step表示的是根据action走一步,_reset是还原开始的布局,observation返回当前的状态。

Sarsa算法

使用Sarsa算法来更新策略的代码如下:

def sarsa(env,episode_nums,discount_factor=1.0, alpha=0.5,epsilon=0.1):

    env = CliffEnvironment()
    Q = defaultdict(lambda:np.zeros(env.nA))
    rewards=[]

    for i_episode in range(1,1+episode_nums):

        if i_episode % 1000 == 0:
            print("\rEpisode {}/{}.".format(i_episode, episode_nums))
            sys.stdout.flush()

        env._reset()
        state,done = env.observation()
        A= epsilon_greedy_policy(Q,state,env.nA)
        probs = A
        action = np.random.choice(np.arange(env.nA),p=probs)
        sum_reward=0.0

        while not done:
            new_state,reward,done = env._step(action)

            if done:
                Q[state][action]=Q[state][action]+alpha*(reward+discount_factor*0.0-Q[state][action])
                break
            else:
                new_A =  epsilon_greedy_policy(Q,new_state,env.nA)
                probs = new_A
                new_action = np.random.choice(np.arange(env.nA),p=probs)
                Q[state][action]=Q[state][action]+alpha*(reward+discount_factor*Q[new_state][new_action]-Q[state][action])
                state = new_state
                action=new_action
            sum_reward+=reward
        rewards.append(sum_reward)
    return Q,rewards

其中原始策略和Q[state][action]更新策略都使用的是 ϵ ϵ -greedy算法,在迭代1000次之后,我们得到的更新策略是:

right right right right right right right right right right right down  
up    up    up    up    up    up    right up    up    right right down  
up    left  up    up    right up    up    up    left  up    right down  
up    up    up    up    up    up    up    up    up    up    up    up    

其中up表示向上,down表示向下走,left和right分别表示左右,可以看出来的是Sarsa算法得到的策略是一条最安全的路,也就是最开始的图中的“safe path”,我们迭代10次Sarsa算法,每次Sarsa算法使用1000个episode,对10次迭代的每个episode的reward取均值,并按照每隔10个episode采样值然后绘制其reward图:
这里写图片描述

Q-learning算法

使用Q-learning更新算法的代码如下:

def Q_learning(env,episode_nums,discount_factor=1.0, alpha=0.5,epsilon=0.1):

    env = CliffEnvironment()
    Q = defaultdict(lambda:np.zeros(env.nA))
    rewards=[]

    for i_episode in range(1,1+episode_nums):

        if i_episode % 1000 == 0:
            print("\rEpisode {}/{}.".format(i_episode, episode_nums))
            sys.stdout.flush()

        env._reset()
        state,done = env.observation()

        sum_reward=0.0

        while not done:

            A= epsilon_greedy_policy(Q,state,env.nA)
            probs = A
            action = np.random.choice(np.arange(env.nA),p=probs)
            new_state,reward,done = env._step(action)



            if done:
                Q[state][action]=Q[state][action]+alpha*(reward+discount_factor*0.0-Q[state][action])
                break
            else:
                new_action = greedy_policy(Q,new_state)
                Q[state][action]=Q[state][action]+alpha*(reward+discount_factor*Q[new_state][new_action]-Q[state][action])
                state = new_state
            sum_reward+=reward
        rewards.append(sum_reward)
    return Q,rewards

可以看出,Q-learning原始策略是 ϵ ϵ -greedy策略,而更新值函数中使用的是贪心策略,显然Q-learning是一个off-policy算法。和Sarsa算法一样,我们迭代1000个episode后得到其策略:

up    right right right right right right right down  right down  down  
down  right right right right down  right down  right right right down  
right right right right right right right right right right right down  
up    up    up    up    up    up    up    up    up    up    up    up    

得到的策略和最开始的图中的“optimal path”一致,也就是说Q-learning偏向选择最优的策略,但是有时候Q-learning会陷入到被标记的区域中,这个可以从Q-leanring的返回reward值看出,绘制图的方法和Sarsa算法中保持一致,得到的图是:
这里写图片描述
从图中可以看出的是,Q-learning的reward值相比sarsa算法是偏低的,原因是Q-learning在选择最优策略的时候偶尔会陷入陷阱得到-100的reward值(由于原始策略存在 ϵ ϵ -greedy方法)。

尽管Q-learning实际上是在学习最优策略的价值,但它的在线表现要比学习迂回策略的Sarsa差。当然如果 ϵ ϵ 逐渐变小的话,两种方法都能最后收敛到最优策略。

本文所有代码可以在这里找到

  • 7
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值