[轉載]Reinforcement Learning:Sarsa和Q-learning

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差。當然如果ϵϵ逐漸變小的話,兩種方法都能最後收斂到最優策略。

本文所有代碼可以在這裏找到


————————————————
版權聲明:本文爲CSDN博主「luchi007」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/u010223750/article/details/78955807

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章