強化學習組隊學習task02——馬爾可夫決策過程及表格型方法

李明朔發表於2020-10-23

一、馬爾科夫決策過程

馬爾科夫過程描述了強化學習的框架。在馬爾科夫過程中,環境是完全可以觀測的,但是很多時候環境裡面有些量是不可觀測的,但是這個部分觀測的問題也可以轉換成一個 MDP 的問題。

在介紹馬爾可夫決策過程之前,先梳理一下馬爾可夫鏈、馬爾可夫獎勵過程。這兩個過程是馬爾可夫決策過程的一個基礎。

1.馬爾科夫鏈

當一個狀態滿足馬爾科夫特徵時,要求未來的轉移只取決於現在的狀態,與過去無關。馬爾可夫性質是所有馬爾可夫過程的基礎。

下圖為一個馬爾科夫鏈示例:
在這裡插入圖片描述

這張圖中有七個狀態,這七個狀態不斷轉移,以s1為例:

  • s1有0.6的概率繼續存活在s1狀態
  • s1有0.4的概率轉換到s2

其餘節點與s1類似。我們可以用一個狀態轉移方程來描述這種狀態轉移,每一行描述了從一個節點到達所有其它節點的概率

在這裡插入圖片描述

2.馬爾科夫獎勵過程

馬爾可夫獎勵過程(Markov Reward Process, MRP) 是馬爾可夫鏈再加上了一個獎勵函式。

在 MRP 中,轉移矩陣跟它的這個狀態都是跟馬爾可夫鏈一樣的,多了一個獎勵函式(reward function) 。獎勵函式是一個期望,就是說當到達某一個狀態的時候,可以獲得多大的獎勵,然後這裡另外定義了一個 discount factor。

依舊以上面的馬爾科夫鏈為例,將獎勵加上,即到達每一個狀態時,都會得到一個獎勵。例如到達s1時,得到5的獎勵,到達s7時,得到10的獎勵,其他狀態沒有任何獎勵,所以我們可以用一個向量來表示這個獎勵。
在這裡插入圖片描述
一些概念:

  • horizon:它說明了同一個 episode 或者是整個一個軌跡的長度,它是由有限個步數決定的。
  • return:獎勵的逐步疊加,discount factor說明我們其實更希望得到現有的獎勵,未來的獎勵就要把它打折扣。
    在這裡插入圖片描述
  • 狀態價值函式:某一狀態的價值,可以看作關於 return 的期望。也可以看成是一個對未來可能獲得獎勵的當前價值的一個表現。
    在這裡插入圖片描述
  • discounted factor:折扣因子,折扣因子在狀態價值函式中扮演著重要作用,原因如下:
    • 馬爾可夫過程是帶環的,這個無窮的獎勵。
    • 希望儘可能快地得到獎勵
    • 設定為0時,只關心當前獎勵,設為1時,未來和當前獎勵一樣,可作為超引數

依舊以之前的馬爾科夫鏈為例,假設折扣係數為0.5,s1獎勵為5,s7獎勵為10,其餘為0
在這裡插入圖片描述
對於馬爾科夫鏈s4、s5、s6、s7,價值為0+0* 1/2+0* 1/4+10* 1/8=1.25
計算價值函式有如下方法:

(1)貝爾曼公式(Bellman equation)

Bellman Equation 定義了當前狀態與未來狀態的迭代關係,表示當前狀態的值函式可以通過下個狀態的值函式來計算。
在這裡插入圖片描述
第一部分為當前立刻可以得到的獎勵,第二部分是未來打了折扣的獎勵之和。

s’可看作未來的所有狀態,P(s’|s)指從當前狀態轉移到未來狀態的概率,V(S’)代表的是未來某一個狀態的價值,最後把未來的獎勵打折扣。

以矩陣形式表示價值函式:
在這裡插入圖片描述
在這裡插入圖片描述
得到的解析解:
在這裡插入圖片描述
需要注意的是,這種方法時間複雜度很高,只能求比較小的馬爾科夫價值。

(2)迭代法

迭代的方法就有幾種,比如說動態規劃的方法、也可以通過蒙特卡羅辦法,即通過取樣的辦法去計算它、另外可以通過 Temporal-Difference Learning 的辦法,這個 Temporal-Difference Learning 叫TD Leanring ,就是動態規劃和蒙特卡羅的一個結合。

蒙特卡羅辦法

下面是蒙特卡羅方法的虛擬碼

在這裡插入圖片描述
蒙特卡羅辦法的具體思想是當得到一個 MRP 後,從某一個狀態開始,隨機產生很多軌跡。產生了一個軌跡過後,就會得到一個獎勵,直接把它的 discounted 的獎勵算出來。算出來後就積累起來,當積累到一定的軌跡數量後,然後直接除以軌跡的數量,然後就會得到它的這個價值。

動態規劃方法

下面是動態規劃的虛擬碼:

在這裡插入圖片描述
動態規劃辦法通過一直去迭代 Bellman Equation,最後達到收斂。即最後更新的狀態跟上一個狀態變化並不大的時候,這個更新就可以停止,最終輸出最新的V(S’)。

3.馬爾科夫決策過程

馬爾可夫決策過程(Markov Decision Process) 多了一個 action ,其它的定義跟 MRP 都是類似的。狀態轉移也多了一個條件,就是採取的某一種行為會導致未來的狀態會不同。價值函式也多了一個條件,即當前的狀態以及你採取的行為會決定當前可能得到的獎勵多少。
在這裡插入圖片描述
在這裡插入圖片描述
MDP中的決策(policy):

  • Policy 定義了在某一個狀態應該採取什麼樣的行為
  • 知道當前狀態後,帶入 policy function,會得到一個決定採取什麼行動的概率或者直接輸出一個值
  • 決策函式:
    在這裡插入圖片描述
  • 概率函式是靜態的(stationary),不同時間採取的行為都是對 policy function 進行取樣。

MDP 跟 MRP 之間可以進行轉換。已知一個 MDP 和一個決策函式π的時候,可以把 MDP 轉換成MRP。在 MDP 裡面,轉移函式 是基於它當前狀態以及它當前的 action,現在已知 policy function,那麼可以直接把這個 action 進行加和,直接把這個 action 去掉,這樣就會得到一個類似於 MRP的獎勵函式。

MDP的價值函式

  • 狀態價值函式(state-value function):定義是跟 MRP 是類似,這個期望是基於採取的 policy,通過對 policy 進行取樣來得到一個期望,那麼就可以計算出它的這個價值函式。
    在這裡插入圖片描述

  • Q 函式(action-value function):定義的是在某一個狀態採取某一個行為,然後可能得到的 return 的一個期望。這裡期望其實也是基於 policy function。所以需要對這個 policy function 進行一個加和,最後得到它的這個價值。
    在這裡插入圖片描述

  • 對 Q 函式中的行為函式進行加和,就可以得到狀態價值函式。
    在這裡插入圖片描述

  • 通過貝爾曼公式,可以將狀態價值函式變換為Q函式
    在這裡插入圖片描述

  • Bellman Expectation Equation :對狀態-價值函式進行一個分解,得到類似於之前 MRP 的 Bellman Equation。定義了當前狀態跟未來狀態之間的一個關聯。
    在這裡插入圖片描述

  • Q 函式的 Bellman Expectation Equation:對於 Q 函式,也可以做類似的分解
    在這裡插入圖片描述

  • 當前時刻的 Q 函式跟未來時刻的 Q 函式之間的關聯
    在這裡插入圖片描述

  • 當前狀態的價值跟未來狀態價值之間的關聯
    在這裡插入圖片描述

  • policy evaluation:計算價值函式的過程,也可以理解成評估這個策略會得到多大的獎勵。

例子

在這裡插入圖片描述
假設環境裡面有兩種行為:往左走和往右走。獎勵函式是隻要達到s1,會有5的獎勵,達到s7,有10的獎勵,其餘無獎勵。對於如下的三種情況:

  1. 假設採取的策略是不管在任何狀態都是往左走,折扣因子是0。那麼對於 deterministic policy,最後估算出的價值函式是一致的。直接通過 Bellman Expectation Equation 不停地迭代,最後會收斂。收斂過後的值就是每一個狀態的價值。
  2. 假設採取的策略是不管在任何狀態都是往左走,折扣因子是 0.5,通過如下等式進行迭代,最後。就會得到它的狀態
    在這裡插入圖片描述
  3. 假設採取的策略是0.5 的概率往左走,有 0.5 的概率往右走,折扣因子是 0.5。開始的時候,可以初始化不同的V(S’)都會有一個值,那麼放到Bellman Expectation Equation去迭代,最後是v ,然後就會算出來。

4.馬爾科夫決策過程的決策評價

MDP 的Prediction 是給定一個 MDP 以及一個 policy ,去計算value function,就相當於每個狀態它的價值函式是多少,可以通過動態規劃去解決。

MDP是滿足動態規劃的要求的,在 Bellman Equation 裡可以把它分解成一個遞迴結構。當我們把它分解成一個遞迴結構時,如果我們的子問題子狀態能得到一個值,那麼它的未來狀態因為跟子狀態是直接相連的,也可以繼續推算出來,所以這個價值函式就可以儲存它以及重用它的最佳的解。

對於 policy evaluation問題,使用的方法是反覆迭代Bellman Expectation Backup直到收斂,Bellman Expectation Backup公式如下:
在這裡插入圖片描述
由於已經給定了這個函式的 policy function,那麼可以直接把它簡化成一個 MRP 的表達形式,就相當於我們把這個a去掉,如下式所示:
在這裡插入圖片描述

這樣它就只有價值函式跟轉移函式了。通過去迭代這個函式,我們也可以得到每個狀態的價值。因為不管是在 MRP 以及 MDP,價值函式包含的變數都是隻跟狀態有關,就相當於進入某一個狀態,未來可能得到多大的價值。

5.馬爾科夫決策過程的控制

MDP 的Control 是去尋找一個最佳的策略,它的 input 就是MDP,輸出是最佳價值函式(optimal valuefunction)以及最佳策略(optimal policy),可以通過動態規劃去解決。

最佳價值函式

搜尋一種 policy ,然後我們會得到每個狀態它的狀態值最大的一個情況, V*就是到達每一個狀態,它的值的極大化情況。
在這裡插入圖片描述

最佳策略

在出現上面的極大化情況是得到的策略。可能有多個最佳的 policy,多個 policy 可以取得相同的最佳價值。
在這裡插入圖片描述
尋找最佳的 policy可以通過對 Q 函式進行極大化,得到最佳價值。當所有東西都收斂後,因為 Q 函式是關於狀態跟動作的函式,所以對某一個狀態採取一個行為,然後可以使得這個 Q 函式最大化,那麼就這個行為就應該是最佳的行為。所以就可以直接提取出它的最佳策略。
在這裡插入圖片描述

Bellman Optimality Equation

整個 MDP 已經到達最佳的狀態時滿足Bellman Optimality Equation。當到達最佳狀態過後,對於 Q 值,取最大的 action 時候的那個值,直接等於最佳 value function。
在這裡插入圖片描述
將該式與Q函式結合就會得到 Q 函式之間的轉移
在這裡插入圖片描述

策略搜尋辦法

  1. 窮舉法:假設我們有有限多個狀態、有限多個行為可能性,每個狀態可以採取有限種行為的策略。把這些可能的policy窮舉一遍,然後算出每種策略的 value function,然後對比一下可以得到最佳策略。這種方法的缺點是非常沒有效率。
  2. policy iteration:這個方法主要有兩個步驟,這兩個步驟一直在迭代,直到收斂:
    1. policy evaluation:先保證 policy 不變,去估計當前的價值,即v函式。
      在這裡插入圖片描述

    2. policy improvement:取得 v 函式過後可以進一步推算出Q 函式。通過在得到的 Q 函式上面做一個貪心的搜尋,這樣就會進一步改進它的策略。
      在這裡插入圖片描述

  3. Value iteration:將 Bellman Optimality Equation 作為更新規則,不斷進行迭代直到收斂
    在這裡插入圖片描述
    在這裡插入圖片描述
    在進行價值迭代後可以通過下式得到最優決策
    在這裡插入圖片描述

二、表格型方法

1.Q表格與狀態價值

P函式和R函式: P函式反應的是狀態轉移的概率,即反應的環境的隨機性,R函式就是Reward function。但是我們通常處於一個未知的環境(即P函式和R函式是未知的)。

Q表格型表示方法: 表示形式是一種表格形式,其中橫座標為 action(agent)的行為,縱座標是環境的state,其對應著每一個時刻agent和環境的情況,並通過對應的reward反饋去做選擇。一般情況下,Q表格是一個已經訓練好的表格,不過,我們也可以每進行一步,就更新一下Q表格,然後用下一個狀態的Q值來更新這個狀態的Q值(即時序差分方法)。

時序差分(Temporal Difference): 步步更新。不用知道全域性,走一步看一步的做自身引導。即此時與下一時刻的價值函式差分(也可以理解是現實與預測值的差距)來近似代替蒙特卡洛中的完整價值。

採用時序差分法的強化學習可以分為兩類,一類是線上控制(On-policy Learning),即一直使用一個策略來更新價值函式和選擇新的動作,代表就是Sarsa。而另一類是離線控制(Off-policy Learning),會使用兩個控制策略,一個策略用於選擇新的動作,另一個策略用於更新價值函式,代表就是Q-Learning。

2.Sarsa演算法

在這裡插入圖片描述
Sarsa的思想是,如上圖從上到下,先基於當前狀態S,使用ϵ−貪婪法按一定概率選擇動作A,然後得到獎勵R,並更新進入新狀態S′,基於狀態S′,使用ϵ−貪婪法選擇A′(即線上選擇,仍然使用同樣的ϵ−貪婪)。演算法每次更新值函式需要知道前一步的狀態(state),前一步的動作(action)、獎勵(reward)、當前狀態(state)、將要執行的動作(action)。
在這裡插入圖片描述
演算法流程為:
在這裡插入圖片描述
建立一個Q Table來儲存狀態s和將會採取的所有動作a,Q(s,a)。在每個回合中,先隨機初始化第一個狀態,再對回合中的每一步都先從Q Table中使用ϵ−貪婪基於當前狀態 s (如果Q表沒有該狀態就建立s-a的行,且初始為全0)選擇動作 a,執行a,然後得到新的狀態s’和當前獎勵r,同時使用ϵ−貪婪得到在s’時的a’,直接利用a’更新表中Q(s,a)的值,繼續迴圈到終點。

程式碼實現:

class SarsaAgent(object):
    def __init__(self, obs_n, act_n, learning_rate=0.01, gamma=0.9, e_greed=0.1):
        self.act_n = act_n      # 動作維度,有幾個動作可選
        self.lr = learning_rate # 學習率
        self.gamma = gamma      # reward的衰減率
        self.epsilon = e_greed  # 按一定概率隨機選動作
        self.Q = np.zeros((obs_n, act_n))

    # 根據輸入觀察值,取樣輸出的動作值,帶探索
    def sample(self, obs):
        if np.random.uniform(0, 1) < (1.0 - self.epsilon): #根據table的Q值選動作
            action = self.predict(obs)
        else:
            action = np.random.choice(self.act_n) #有一定概率隨機探索選取一個動作
        return action

    # 根據輸入觀察值,預測輸出的動作值
    def predict(self, obs):
        Q_list = self.Q[obs, :]
        maxQ = np.max(Q_list)
        action_list = np.where(Q_list == maxQ)[0]  # maxQ可能對應多個action
        action = np.random.choice(action_list)
        return action

    # 學習方法,也就是更新Q-table的方法
    def learn(self, obs, action, reward, next_obs, next_action, done):
        """ on-policy
            obs: 互動前的obs, s_t
            action: 本次互動選擇的action, a_t
            reward: 本次動作獲得的獎勵r
            next_obs: 本次互動後的obs, s_t+1
            next_action: 根據當前Q表格, 針對next_obs會選擇的動作, a_t+1
            done: episode是否結束
        """
        predict_Q = self.Q[obs, action]
        if done:
            target_Q = reward # 沒有下一個狀態了
        else:
            target_Q = reward + self.gamma * self.Q[next_obs, next_action] # Sarsa
        self.Q[obs, action] += self.lr * (target_Q - predict_Q) # 修正q
def run_episode(env, agent, render=False):
    total_steps = 0 # 記錄每個episode走了多少step
    total_reward = 0

    obs = env.reset() # 重置環境, 重新開一局(即開始新的一個episode)
    action = agent.sample(obs) # 根據演算法選擇一個動作

    while True:
        next_obs, reward, done, _ = env.step(action) # 與環境進行一個互動
        next_action = agent.sample(next_obs) # 根據演算法選擇一個動作
        # 訓練 Sarsa 演算法
        agent.learn(obs, action, reward, next_obs, next_action, done)

        action = next_action
        obs = next_obs  # 儲存上一個觀察值
        total_reward += reward
        total_steps += 1 # 計算step數
        if render:
            env.render() #渲染新的一幀圖形
        if done:
            break
    return total_reward, total_steps

env = gym.make("CliffWalking-v0")  # 0 up, 1 right, 2 down, 3 left

# 建立一個agent例項,輸入超引數
agent = SarsaAgent(
        obs_n=env.observation_space.n,
        act_n=env.action_space.n,
        learning_rate=0.1,
        gamma=0.9,
        e_greed=0.1)


# 訓練500個episode,列印每個episode的分數
for episode in range(500):
    ep_reward, ep_steps = run_episode(env, agent, False)
    print('Episode %s: steps = %s , reward = %.1f' % (episode, ep_steps, ep_reward))

3.Q-learning演算法

在這裡插入圖片描述
Q-Learnig的思想就是,如上圖從上到下,先基於當前狀態S,使用ϵ−貪婪法按一定概率選擇動作A,然後得到獎勵R,並更新進入新狀態S′,基於狀態S′,直接使用貪婪法從所有的動作中選擇最優的A′(即離線選擇,不是用同樣的ϵ−貪婪)。
在這裡插入圖片描述
演算法流程為:
在這裡插入圖片描述
建立一個Q Table來儲存狀態s和將會採取的所有動作a,Q(s,a)。在每個回合中,先隨機初始化第一個狀態,再對回合中的每一步都先從Q Table中使用ϵ−貪婪基於當前狀態 s (如果Q表沒有該狀態就建立s-a的行,且初始為全0)選擇動作 a,執行a,然後得到新的狀態s’和當前獎勵r,同時更新表中Q(s,a)的值,繼續迴圈到終點。整個演算法就是一直不斷更新 Q table 裡的值,再根據更新值來判斷要在某個 state 採取怎樣的 action最好。

程式碼實現:

class QLearningAgent(object):
    def __init__(self, obs_n, act_n, learning_rate=0.01, gamma=0.9, e_greed=0.1):
        self.act_n = act_n      # 動作維度,有幾個動作可選
        self.lr = learning_rate # 學習率
        self.gamma = gamma      # reward的衰減率
        self.epsilon = e_greed  # 按一定概率隨機選動作
        self.Q = np.zeros((obs_n, act_n))

    # 根據輸入觀察值,取樣輸出的動作值,帶探索
    def sample(self, obs):
        if np.random.uniform(0, 1) < (1.0 - self.epsilon): #根據table的Q值選動作
            action = self.predict(obs)
        else:
            action = np.random.choice(self.act_n) #有一定概率隨機探索選取一個動作
        return action

    # 根據輸入觀察值,預測輸出的動作值
    def predict(self, obs):
        Q_list = self.Q[obs, :]
        maxQ = np.max(Q_list)
        action_list = np.where(Q_list == maxQ)[0]  # maxQ可能對應多個action
        action = np.random.choice(action_list)
        return action

    # 學習方法,也就是更新Q-table的方法
    def learn(self, obs, action, reward, next_obs, done):
        """ off-policy
            obs: 互動前的obs, s_t
            action: 本次互動選擇的action, a_t
            reward: 本次動作獲得的獎勵r
            next_obs: 本次互動後的obs, s_t+1
            done: episode是否結束
        """
        predict_Q = self.Q[obs, action]
        if done:
            target_Q = reward # 沒有下一個狀態了
        else:
            target_Q = reward + self.gamma * np.max(self.Q[next_obs, :]) # Q-learning
        self.Q[obs, action] += self.lr * (target_Q - predict_Q) # 修正q
def run_episode(env, agent, render=False):
    total_steps = 0 # 記錄每個episode走了多少step
    total_reward = 0

    obs = env.reset() # 重置環境, 重新開一局(即開始新的一個episode)

    while True:
        action = agent.sample(obs) # 根據演算法選擇一個動作
        next_obs, reward, done, _ = env.step(action) # 與環境進行一個互動
        # 訓練 Q-learning演算法
        agent.learn(obs, action, reward, next_obs, done)

        obs = next_obs  # 儲存上一個觀察值
        total_reward += reward
        total_steps += 1 # 計算step數
        if render:
            env.render() #渲染新的一幀圖形
        if done:
            break
    return total_reward, total_steps

env = gym.make("CliffWalking-v0")  # 0 up, 1 right, 2 down, 3 left

# 建立一個agent例項,輸入超引數
agent = QLearningAgent(
    obs_n=env.observation_space.n,
    act_n=env.action_space.n,
    learning_rate=0.1,
    gamma=0.9,
    e_greed=0.1)


# 訓練500個episode,列印每個episode的分數
for episode in range(500):
    ep_reward, ep_steps = run_episode(env, agent, False)
    print('Episode %s: steps = %s , reward = %.1f' % (episode, ep_steps, ep_reward))

4.on-policy與off-policy的區別

首先就判斷on-policy和off-policy就在於估計時所用的策略與更新時所用的策略是否為同一個策略。on-policy 在學習的過程中,只存在一種策略,比如Sarsa選了什麼動作來估計Q值就一定會用什麼動作來更新state,一定會執行該動作(會有貪婪率);而off-policy 在學習的過程中,有兩種不同的策略。第一個策略是我們希望學到一個最佳的目標策略,另外一個策略是探索環境的策略,比如Q-Learning,估Q值是一回事,但執行動作時一定是會選max的,即使用了兩套策略,屬於off-policy。

而之所以要叫on或off是因為,off-policy基本上都是要基於replay memory,即估計出的動作值肯定是最優的,但在生成策略的時候,卻選擇了價值最大的綜合memory的max Q 的action。而on-policy每次都是選擇最優的action。

Q-learning 演算法被提出的時間更早,Sarsa 演算法是 Q-learning 演算法的改進。

相關文章