運籌優化學習18:馬爾科夫決策過程與動態規劃 (手算及Matlab源碼剖析)

目錄

1 基本概念

2 馬爾科夫決策過程理論

2.1 馬爾科夫過程(Markov process / Markov Chain)

2.1.1 狀態空間分析:

2.1.2 轉移矩陣描述

2.2 馬爾科夫獎勵過程(Markov Reward Process)

2.2.1 不同任務的獎勵及回報值計算方法

2.2.2 衰減因子  的分析

2.2.3 馬爾科夫獎勵過程的值函數及計算示例

2.3 馬爾科夫決策過程(Marlov Decision Process)

2.3.1 策略

2.3.2 狀態價值函數與狀態動作價值函數

3 動態規劃算法求解MDP

3.1 預測與控制

3.2 求解算法梳理

4 值迭代與策略迭代手算及Matlab代碼

4.1 簡單粗暴的值迭代方法--求解Small Gridworld例子

4.1.1 理論部分

4.1.1 手解過程及自己總結

4.1.2 Matlab的計算結果實現

4.1.3 Matlab部分解算結果展示:

4.2 策略迭代算法

4.2.1 手算示例分析

4.2.2 策略迭代的Matlab實現

4.2.3 運行結果展示

參考資料:


寫在前面的話

  • 本文爲筆者自學馬爾科夫過程的新的總結,難免存在疏漏和錯誤之處;
  • 寫作本文的目的是爲想學習馬爾科夫決策過程的小夥伴提供一些參考
  • 本文的撰寫也借鑑了許多優秀的知乎及CSDN博客文章,感謝他們,但是本文在借鑑他們成果的基礎上,做了自己的一些改編,不合適之處,歡迎高人批評指正。
  • 由於本人也是初學,旨在對問題概念及原理做最爲直白的理解,確保初學者無痛入門
  • 如後期自己發現有疏漏之處,也會自行不斷地進行更新和完善

1 基本概念

在無監督數據、只有獎勵信號;獎勵可能是即時的也可能是延遲的;當前行爲影響後續狀態的收益;時間是一個必須要考慮的因素。強化學習是通過個體與環境的不斷交互和反饋積累起對環境的感知,進而一步步的增強自己對環境的認識而儘快的實現自己的目的

R_{t} 表示個體在 t 時刻的獎勵,強化學習的目標就是獲得最大化的獎勵

  • 序列決策:通過一系列的行爲得到決策收益,有時候會放棄短期利益追求長期效益
  • 個體(agent):行動的實際實施者,用於接收信號並做出決定。個體在環境狀態 S_{t} 採用動作 A_{t} 得到收益 R_{t+1} 
  • 環境(Environment):接收一個動作 A_{t}, 環境狀態變成S_{t+1},反饋給個體一個收益R_{t+1}
  • 行動(action):個體施加在行動中的動作
  • 狀態(state):環境接受個體agent的action後,反饋給agent的環境狀態,同時還會附加一個獎勵reward

  • 歷史:狀態、動作和收益的序列
  • 馬爾科夫性:P(S_{t+1}|S_{t})=P(S_{t+1}|S_{t},S_{t-1}, ..., S_{1}),忽略歷史信息,當前狀態可以決定未來
  • 策略:狀態到行爲的映射
  • 價值函數:未來獎勵的預測,評價當前狀態的好壞。當個體面臨幾種不同的狀態時,他會根據value值來評估不同狀態的收益情況,指定相應的策略;也就是說,價值函數是基於某一策略而言的。
    • 對於某一策略\pi,其價值函數可表示爲v_{\pi}(s)=E_{\pi}(R_{t+1}+\gamma R_{t+2}+\gamma^{3} R_{t+3}+... | s_{t}=s )
  • 模型:對模擬環境與個體交互機制的描述,模型包含兩個部分:
    • 狀態之間的轉移概率 P_{ss'}^{a}=P[{S_{t+1} | S_{t}=s,S_{t+1}=s',A_{t}=a}] 
    • 狀態轉移的收益 R_{s}^{a}=E(R_{t+1} | S_{t}=s, A_{t} = a)
    • 注意:模型僅對於個體來說的,模型對個體來說也不是必須的;考慮環境的實際規劃狀態的研究稱爲環境動力學
  • 學習與規劃:學習是在初始階段對環境一無所知的時候,通過與環境的不斷交互,建立起相應的行爲策略;規劃是在個體對環境已經瞭解後,利用建立的模型模擬與環境的交互,從而繼續改進所建立的策略。
  • 探索和利用:個體從未知環境中找到一個比較好的策略,有失敗的風險;利用則是從已有的策略中選擇一個比較好的策略,或許會早熟。比如:你會選擇一個新餐廳吃飯 (探索) 還是去你之前去過的餐廳 (利用) 呢?

2 馬爾科夫決策過程理論

馬爾科夫過程基本描述:

  • 馬爾科夫性:P(S_{t+1}|S_{t})=P(S_{t+1}|S_{t},S_{t-1}, ..., S_{1})
  • 狀態轉移概率:P_{ss'}^{a}=P[{S_{t+1} | S_{t}=s,S_{t+1}=s',A_{t}=a}];顯然從在任意時刻 t 從當前狀態轉移到其他狀態的概率之和爲1

2.1 馬爾科夫過程(Markov process / Markov Chain)

無記憶過程,包含兩個基本要素:<S,P>,其中的 S 表示有限個狀態集合,P 表示這些狀態之間的轉移概率

馬爾科夫鏈的基本示例

 

上圖模擬了包含S= {Facebook, Class1, Class2, Class3, Pub, Pass,Sleep}七種狀態的馬爾科夫狀態空間,其中圓形狀態表示個體所處的狀態,方形狀態Sleep表示終止狀態;不同狀態之間的連線上的數值表示這些狀態之間的轉移概率,箭頭表示狀態轉移的方向。

2.1.1 狀態空間分析:

  • 個體從Class1開始,他有0.5的概率,轉移到Class2;也有可能0.5的概率,轉移到Facebook狀態;
    • 當個體從狀態Class1轉移到狀態Facebook時,他有0.9的概率,繼續刷Facebook;也有0.1的概率回到Class;
    • 當個體從狀態Class1轉移到狀態Class2時,他有0.2的概率會因課程太難退出,即Sleep;有0.8的概率,轉到Class3;
      • 當個體從狀態Class2轉移到狀態Class3時,他有0.6的概率通過考試,然後退出;有0.4的概率,去圖書館查資料學習;
        • 如果他去圖書館查資料學習,有0.4的概率返回Class1;有0.4的概率,返回Class2;有0.2的概率,返回Class1

思維導圖展示:

學生上課馬爾科夫過程思維導圖演示

2.1.2 轉移矩陣描述

學生選課馬爾科夫轉移矩陣
  Class1 Class2 Class3 Facebook Pub Pass Sleep
Class1   0.5   0.5      
Class2     0.8       0.2
Class3         0.4 0.6  
Pub 0.2 0.4 0.4        
Facebook 0.9     0.1      
Pass             1
Sleep             1

上圖和表解釋了馬爾科夫過程的兩個基本要素:狀態空間和狀態轉移矩陣,下面介紹馬爾科夫獎勵過程。

2.2 馬爾科夫獎勵過程(Markov Reward Process)

在馬爾科夫過程的基礎上,加入了獎勵R;構成形如<S,P,R,\gamma>的馬爾科夫獎勵過程;對其四元組的解釋如下:

  • S:馬爾科夫的狀態空間
  • P:馬爾科夫的狀態轉移概率矩陣
  • R:馬爾科夫過程的獎勵函數
  • \gamma:獎勵衰減因子,位於[0, 1]之間;傳達的信息是,隨着狀態的遷移,當前狀態的影響在衰減

2.2.1 不同任務的獎勵及回報值計算方法

注意:

  • 我們將每個狀態的即時收益,定義爲獎勵R_{t};而將對某一個片段的評價,定義爲回報G_{t}
  • 短期的叫收益,長期的叫回報,區分開來,以免混淆

( 1 ) 回合制任務(episodic task)

存在一個終止狀態,並且所有的獎勵會在這個終止狀態及其之前結算

( 2 ) 連續任務(continuing task)

不存在一個終止狀態,即原則上可以永久地運行下去,這類任務的獎勵是分散地分佈在這個連續的一連串的時刻中的

其中衰減率(discount factor)  \gamma 滿足 0 \leq \gamma \leq 1 。這樣的定義也很好理解,相比於更遠的收益,我們會更加偏好臨近的收益,因此對於離得較近的收益權重更高。

2.2.2 衰減因子 \gamma 的分析

分析性描述:

  • 我們對未來的把握是逐漸衰減的,一般的情況下,我們更關心短時間的獎勵
  • 加入衰減因子之後,我們就可通過該參數來調節長時間的回報
  • 衰減因子是MDP和MRP長期回報值有界的保證

2.2.3 馬爾科夫獎勵過程的值函數及計算示例

v(s) & = E(G_{t} | S_{t}=s) \\ &= E(R_{t+1} + \gamma R_{t+2} + \gamma^{2} R_{t+3} + ... | S_{t}=s) \\ &= E(R_{t+1} + \gamma * (R_{t+2} + \gamma R_{t+3} + ...) | S_{t}=s) \\ &= E(R_{t+1} + \gamma * v(S_{t+1})) | S_{t}=s)

價值函數表示了狀態s和狀態S_{t+1}之間的迭代關係,也反應了短期獎勵與長期回報之間的關係

如果我們知道狀態轉移矩陣P,那麼式子可轉化爲:

v(s) & = R_{t+3} + ...) | S_{t}=s) \\ &= E(R_{t+1} + \gamma * v(S_{t+1})) | S_{t}=s) \\& = E(R_{t+1} | S_{t}=s) + \gamma * E(v(S_{t+1} | S_{t} = s)) \\& = R(s) + \gamma * \sum_{s' \in S} (P_{ss'} v(s'))

下面是一個例子:

值函數的計算示例

2.3 馬爾科夫決策過程(Marlov Decision Process)

在馬爾科夫獎勵過程的基礎上,我們又加入了行動集合,構成 <S,A,P,R,\gamma> 五元組和策略 \pi 形式的馬爾科夫決策過程

幾點討論:

  1. MP和MRP我們作爲一個觀察者,觀察狀態的變化來計算回報值;而在MDP中,我們引入了決策,通過改變狀態轉移的流程,獲得最大化的回報
  2. 我們對MDP的獎勵變成了對<s,a>的獎勵,即通過動作來控制狀態的轉移

2.3.1 策略

  • 策略給出了在每個狀態下我們應該採取的行動,我們可以把這個策略記做 \pi (a|s),它表示在狀態s下採取行動 a 的概率
  • 給定狀態下的動作概率的集合,這些所有的概率的加總起來,和值爲1。
  • 策略是對agent行爲的全部描述,一旦策略確定智能體的行爲也將確定。
  • 策略是基於馬爾科夫狀態,是時間穩定的,只與狀態有關,而與時間無關
  • 如果給定策略 \pi,MDP將會退化爲MRP問題

  • 當策略確定時,對應的是一組動作集合;當策略隨機時,對應的是一組動作分佈集合

如果我們可以計算出每個狀態或者採取某個行動之後收益,那麼我們每次行動就只需要採取收益較大的行動或者採取能夠到達收益較大狀態的行動。這就是策略迭代的核心所在。

2.3.2 狀態價值函數與狀態動作價值函數

兩個狀態價值函數對應兩個貝爾曼方程,對應值迭代和策略迭代算法,兩個公式的用途不同,千萬不能混淆。

(1) 狀態價值函數(V_{\pi}(s),state value function)

v_{\pi}(s) \\ = E_{\pi}(G_{t} | S_{t} = s) \\ = E_{\pi}(R_{t+1} + \gamma * v_{\pi}(S_{t+1}) | S_{t} = s)

在當前狀態s一直採用策略\pi,能夠產生的期望收益

個人觀點:

  • 如果你只給出一個策略,使用值迭代算法更新至值函數收斂,你將得到了這個策略下的最優決策,這樣的計算模式只涉及到上式的前兩行部分;因爲只有一個策略,所有的\pi (a|s)就是確定的。
  • 上面公式的通俗解釋是,我在狀態 s 處以概率 \pi (a|s) 採取行動 a,採取行動 a 之後,狀態 s 能夠以概率 p(s',r | s,a) 轉移到狀態 s' 。 
  • 對於策略 \pi ,我們可以定義如下貝爾曼方程:

(2) 狀態動作價值函數(Q_{\pi}(s,a), action value function)

q_{\pi}(s,a) \\ = E_{\pi}(G_{t} | S_{t} = s, A_{t}=a) \\ = E_{\pi}(R_{t+1} + \gamma * q_{\pi}(S_{t+1},A_{t+1}) | S_{t} = s, A_{t}=a)

當前狀態s,如果採用行動a,接下來採用策略\pi,能夠產生的期望收益

  • 如果我們我們能夠求得某策略下的價值函數,我們就可以對該策略進行評估
  • 如果我們能夠得到最優狀態的價值函數,我們就可以得到最優策略

(3) 狀態值函數與狀態動作值函數區別與聯繫分析

  • 狀態價值函數,策略是確定的;而狀態動作價值函數,採取某個行動之後,選擇不同的策略能夠得到的預期收益
  • 狀態價值函數,對應於值迭代算法;行動價值函數,對應策略迭代算法

聯繫:

  • 兩個函數的最終目的都是要得到最優的期望收益,用【殊途同歸】一詞描述最爲合適

 

  

 一個計算的示例

\upsilon\left(s_4\right)=0.5*\left(1+0.2*\left(-1.3\right)+0.4*2.7+0.4*7.4\right)+0.5*10=7.39

 

3 動態規劃算法求解MDP

動態表示研究的過程是具有時序特徵,規劃是一種優化策略;所以動態規劃是指將研究問題分解成許多個子問題,通過不斷的求解子問題一步一步遞歸得到原問題的解決方案。

對於我們研究的馬爾科夫過程,由于貝爾曼方程的存在,使其具備使用動態規劃求解的基本特徵;不過要想使用動態規劃來求解MDP的話,MDP必須具有明確的模型,事先知道完全的信息。【根據狀態和行動的價值函數,計算每個狀態的最優策略,最後串起來】

3.1 預測與控制

  • 預測是求解給定策略下的價值函數的過程
  • 控制是找到一個策略以獲得最大化的收益,即從所有的可能策略中選擇最優的價值函數和最優策略

MDP的動態規劃算法的主體思路爲:先給一個策略,預測出他的最優值函數;然後在使用控制策略,得到最優策略

策略迭代方法:要進行策略迭代,首先要進行策略評估,也就是評估一下目前的幾個選擇的好壞,因爲只有你當前的選擇好了,你才更可能做出整體上比較好的選擇;在DS的視頻中,提出了“one step look ahead”理念,就是說我計算當前值函數的時候,要使用到上一個值函數的數據來構建;

3.2 求解算法梳理

(1) 策略評估

概念:評估一個給定的策略,屬於預測的範疇

計算公式:

說明:一次迭代內,狀態s的價值等於前一次迭代該狀態的即時獎勵與所有s的下一個可能狀態s' 的價值與其概率乘積的和

(2) 策略改善

採取那個(些)使得狀態價值得到最大的行爲,進行策略更新。

  1.   考慮一個確定的策略: a=\pi_{s}
  2. 通過貪婪計算優化策略:\pi'(s) = argmax_{a \in A}q_{\pi}(s|a)  
  3. 這會用1步迭代改善狀態s的q值,即在當前策略下,狀態s在動作π’(s)下得到的q值等於當前策略下狀態s所有可能動作得到的q值中的最大值。這個值一般不小於使用當前策略得到的行爲所的得出的q值,因而也就是該狀態的狀態價值。
  4. 如果q值不再改善,則在某一狀態下,遵循當前策略採取的行爲得到的q值將會是最優策略下所能得到的最大q值,上述表示就滿足了Bellman最優方程,說明當前策略下的狀態價值就是最優狀態價值。
  5. 因而此時的策略就是最優策略。 

(3) 策略迭代

在當前策略上迭代計算 v 值,再根據 v 值貪婪地更新策略,如此反覆多次,最終得到最優策略 \pi^{*} 和最優狀態價值函數 V^{*}  

策略迭代算法流程示意圖

 

(4) 價值迭代

概念:從初始狀態價值開始同步迭代計算,最終收斂,整個過程中沒有遵循任何策略。

公式定理:

說明:與策略迭代不同,在值迭代過程中,算法不會給出明確的策略,迭代過程其間得到的價值函數,不對應任何策略;價值迭代雖然不需要策略參與,但仍然需要知道狀態之間的轉移概率,也就是需要知道模型。

4 值迭代與策略迭代手算及Matlab代碼

4.1 簡單粗暴的值迭代方法--求解Small Gridworld例子

值迭代算法流程圖

4.1.1 理論部分

一個4×4的小網格世界,左上角和右下角是目的地

每個格子行動方向爲上下左右,每走一步reward-1

求一個在每個狀態都能以最少步數到達目的地的最優行動策略。

解決思路:我們從最開始的隨機(1/4)策略開始,對其進行policy evaluation, 然後進行policy iteration by acting greedy

4.1.1 手解過程及自己總結

展示k=2到k=3的計算過程:

0 = 【第一行第一個格子】

這是結束的位置,應該保持不動

-2.375 =

   【第一行的第二個格子】
+    0.25 * (-1 + 1 * (-1.7))

     上【-0.675】
+    0.25 * (-1 + 1 * (0))

     左【-0.25】
+    0.25 * (-1 + 1 * (-2)) 

    下【-0.75】
+    0.25 * (-1 + 1 * (-2)) 

    右【-0.75】

-2.875 =

   【第一行的第三個格子】
+    0.25 * (-1 + 1 * (-2))

  上【-0.75】
+    0.25 * (-1 + 1 * (-1.7)) 

   左【-0.625】
+    0.25 * (-1 + 1 * (-2))

    下【-0.75】
+    0.25 * (-1 + 1 * (-2))

    右【-0.75】

-3.0 =

      【第一行的第四個格子】
+    0.25 * (-1 + 1 * (-2))

   上【-0.75】
+    0.25 * (-1 + 1 * (-2)) 

   左【-0.75】
+    0.25 * (-1 + 1 * (-2))

    下【-0.75】
+    0.25 * (-1 + 1 * (-2))

    右【-0.75】

-2.425 =

【第二行第一列】
+    0.25 * (-1 + 1 * (0))

上【-0】
+    0.25 * (-1 + 1 * (-1.7))

    左【-0.625】
+    0.25 * (-1 + 1 * (-2))

    下【-0.75】
+    0.25 * (-1 + 1 * (-2)) 

   右【-0.75】

-2.75 =【第二行第二列】
+    0.25 * (-1 + 1 * (-1.7)) 上【-0.625】
+    0.25 * (-1 + 1 * (-1.7))    左【-0.625】
+    0.25 * (-1 + 1 * (-2))    下【-0.75】
+    0.25 * (-1 + 1 * (-2))    右【-0.75】
-3.0 = 【第二行第三列】
+    0.25 * (-1 + 1 * (-2)) 上【-0.75】
+    0.25 * (-1 + 1 * (-2))    左【-0.75】
+    0.25 * (-1 + 1 * (-2))    下【-0.75】
+    0.25 * (-1 + 1 * (-2))    右【-0.75】
-2.875 = 【第二行第四列】
+    0.25 * (-1 + 1 * (-2)) 上【-0.75】
+    0.25 * (-1 + 1 * (-2))    左【-0.75】
+    0.25 * (-1 + 1 * (-1.7))    下【-0.625】
+    0.25 * (-1 + 1 * (-2))    右【-0.75】
-2.875 =【第三行第一列】
+    0.25 * (-1 + 1 * (-1.7)) 上【-0.625】
+    0.25 * (-1 + 1 * (-2))    左【-0.75】
+    0.25 * (-1 + 1 * (-2))    下【-0.75】
+    0.25 * (-1 + 1 * (-2))    右【-0.75】
-3.0 =【第三行第二列】
+    0.25 * (-1 + 1 * (-2)) 上【-0.75】
+    0.25 * (-1 + 1 * (-2))    左【-0.75】
+    0.25 * (-1 + 1 * (-2))    下【-0.75】
+    0.25 * (-1 + 1 * (-2))    右【-0.75】
-2.75 = 【第三行第三列】
+    0.25 * (-1 + 1 * (-2)) 上【-0.75】
+    0.25 * (-1 + 1 * (-2))    左【-0.75】
+    0.25 * (-1 + 1 * (-1.7))    下【-0.625】
+    0.25 * (-1 + 1 * (-1.7))    右【-0.625】
-2.375 = 【第三行第四列】
+    0.25 * (-1 + 1 * (-2)) 上【-0.75】
+    0.25 * (-1 + 1 * (-2))    左【-0.75】
+    0.25 * (-1 + 1 * (-0))    下【-0.25】
+    0.25 * (-1 + 1 * (-1.7))    右【-0.625】
-3.0 =【第四行第一列】
+    0.25 * (-1 + 1 * (-2)) 上【-0.625】
+    0.25 * (-1 + 1 * (-2))    左【-0.75】
+    0.25 * (-1 + 1 * (-2))    下【-0.75】
+    0.25 * (-1 + 1 * (-2))    右【-0.75】
-2.875 =【第四行第二列】
+    0.25 * (-1 + 1 * (-2)) 上【-0.75】
+    0.25 * (-1 + 1 * (-2))    左【-0.75】
+    0.25 * (-1 + 1 * (-2))    下【-0.75】
+    0.25 * (-1 + 1 * (-1.7))    右【-0.625】
-2.375 = 【第四行第三列】
+    0.25 * (-1 + 1 * (-2)) 上【-0.75】
+    0.25 * (-1 + 1 * (-2))    左【-0.75】
+    0.25 * (-1 + 1 * (-1.7))    下【-0.625】
+    0.25 * (-1 + 1 * (0))    右【-0.25】
-0 = 【第四行第四列】

通用的總結(k+1步的計算是從k步的值矩陣中取值來計算):

某個格子的值 = 0.25 * (即時獎勵[-1]  +  折扣因子[1] * k步矩陣上方的值)    【上】
                      + 0.25 * (即時獎勵[-1]  +  折扣因子[1] * k步矩陣左方的值)    【左】 
                      + 0.25 * (即時獎勵[-1]  +  折扣因子[1] * k步矩陣下方的值)    【下】
                      + 0.25 * (即時獎勵[-1]  +  折扣因子[1] * k步矩陣右方的值)    【右】

4.1.2 Matlab的計算結果實現

程序設計思路爲:

  1. 構建gridRow * gridCol大小的圖形
  2. 初始化值函數,並定義當前值函數和上一步值函數;初始化折扣因子、即時獎勵、終止閾值、策略概率
  3. 按照前一部分總結的規律,依照【上->左->下->右】的順序,迭代更新值函數;注:程序將邊界點和內點分開計算
  4. 判斷更新後的值函數與上一步的值函數是否滿足終止閾值;若是返回,得到收斂的值函數;否則繼續迭代
clc;clear;
%初始化格網的行數
girdRow = 4;
gridCol = 4;
%初始化值函數、當前值函數和上一期值函數
v = zeros(girdRow,gridCol);
v_cur = v;
v_before = v;
%折扣因子
gamma = 1;
%即時獎勵
reward = -1;
%策略概率
policyPossibility = 0.25;
%終止閾值:兩次的值函數差值小於給定閾值,認爲得到了最優的值函數
theta = 0.00001;

%迭代變量
iter = 0;
while true  
    %迭代變量遞增1
    iter = iter + 1;
    %遍歷所有的格子
    for i = 1:girdRow
        for j = 1:gridCol
            %第一行的第一個格子
            if(i == 1 && j == 1)
                v_cur(i,j) = v_before(i,j);
            end
            
            %第一行其他格子
            if(i == 1 && j ~= 1)
                if (j ~= gridCol)
                    %上左下右
                    v_cur(i,j) =  policyPossibility * (reward + gamma * v_before(i,j)) ...
                    + policyPossibility * (reward + gamma * v_before(i,j-1)) ...
                    + policyPossibility * (reward + gamma * v_before(i+1,j)) ...
                    + policyPossibility * (reward + gamma * v_before(i, j+1));
                else
                    v_cur(i,j) =  policyPossibility * (reward + gamma * v_before(i,j)) ...
                    + policyPossibility * (reward + gamma * v_before(i,j-1)) ...
                    + policyPossibility * (reward + gamma * v_before(i+1,j)) ...
                    + policyPossibility * (reward + gamma * v_before(i, j));
                end
            end
            %第1列其他格子
            if (j == 1 && i ~= 1)
                 if (i ~= girdRow)
                    v_cur(i,j) =  policyPossibility * (reward + gamma * v_before(i-1,j)) ...
                    + policyPossibility * (reward + gamma * v_before(i,j)) ...
                    + policyPossibility * (reward + gamma * v_before(i+1,j)) ...
                    + policyPossibility * (reward + gamma * v_before(i, j+1));
                else
                    v_cur(i,j) =  policyPossibility * (reward + gamma * v_before(i-1,j)) ...
                    + policyPossibility * (reward + gamma * v_before(i,j)) ...
                    + policyPossibility * (reward + gamma * v_before(i,j)) ...
                    + policyPossibility * (reward + gamma * v_before(i,j+1));
                 end              
            end
            %第4列非首行格子
            if (j == gridCol && i ~= 1)
                 if (i ~= gridCol)
                    v_cur(i,j) =  policyPossibility * (reward + gamma * v_before(i-1,j)) ...
                    + policyPossibility * (reward + gamma * v_before(i,j-1)) ...
                    + policyPossibility * (reward + gamma * v_before(i+1,j)) ...
                    + policyPossibility * (reward + gamma * v_before(i, j));
                else
                    v_cur(i,j) =  0;
                 end              
            end
            %第4行非首列格子
            if (i == girdRow && j ~= 1 && j ~= gridCol)
                v_cur(i,j) =  policyPossibility * (reward + gamma * v_before(i-1,j)) ...
                    + policyPossibility * (reward + gamma * v_before(i,j-1)) ...
                    + policyPossibility * (reward + gamma * v_before(i,j)) ...
                    + policyPossibility * (reward + gamma * v_before(i, j+1));
            end
            
            %非邊界行的計算
            if (i~= 1 && i ~= girdRow && j ~= gridCol && j ~= 1)
                v_cur(i,j) =  policyPossibility * (reward + gamma * v_before(i-1,j)) ...
                    + policyPossibility * (reward + gamma * v_before(i,j-1)) ...
                    + policyPossibility * (reward + gamma * v_before(i+1,j)) ...
                    + policyPossibility * (reward + gamma * v_before(i, j+1));
            end
        end
    end
    disp(sprintf('第%d次的解算結果爲:',iter))
    v_cur %輸出當前值函數
    if (max(abs(v_cur(:)-v_before(:))) < theta)
        break;
    else
        v_before = v_cur;
    end
end

4.1.3 Matlab部分解算結果展示:

算法在設定的閾值內迭代了215次,最終輸出的收斂結果爲:

4.2 策略迭代算法

即使我們得到最優的值函數,我們還需要將其轉化爲具體的策略,而通過上面的例子我們的發現k=3與k=10的值函數不同,但對應的策略是完全相同的。故可以說我們僅需要迭代三次就得到了最優的策略,我們後面做的工作其實是無用功。

詳細分析我們的值迭代的思路,發現我們自始至終沿用的都是均勻概率分佈的策略;如果我們能在搜索的過程中根據值函數來更新策略,我們將有可能更快的得到想要的結果。正是基於這樣的想法,我們的策略迭代算法就產生,其原理是這樣的【自己悟的,專業人士勿噴】:

  1. 首先我們隨機初始化一個策略,我們沿着這個策略進行值函數迭代,如果值函數發生變化,說明還沒有得到最優的值函數,需要繼續迭代,此時我們並不是直接對得到的值函數進行操作,而是根據值函數反應的信息,進行策略更新
  2. 然後,使用更新後的策略,進行值函數的更新;如此往復,直到我們的值函數收斂或策略不再發生變化時,我們研究問題的滿意解,甚至是最優解。
策略迭代流程圖

插播別人的一段分析:僞代碼的第3行表示策略改進,即固定價值函數,得到其最優策略;僞代碼第4行的策略評估,即固定策略,得到其價值函數。

改進策略迭代流程圖

改進策略迭代的分析:

  1. m_{t}=1時,相當於只有一個策略,改進策略迭代算法等同於值迭代算法。結合策略評估的定義,我們僅在一個固定策略下,得到了其價值函數,也就是我們只做了一次策略評估。
  2. m_{t}=\infty時,改進策略迭代算法等同於策略迭代算法。
  3. 改進策略迭代是值迭代算法與策略迭代算法的統一,目的都是爲了找到最優的行動策略

4.2.1 手算示例分析

專業的公式我也看不懂,搞不明白,自己就發揮一下我的笨蛋大腦,寫下下面這個部分,如有錯誤,歡迎指正。

再來分析之前出現的這個圖,經過k=1的迭代,發現了新的策略:

  • 比如第2行第1列的格子,其上左下右的值分別爲-2.0、-2.0、-1.7、0.0,顯然最大值函數對應方向爲當前格子的上方;
  • 以第2行第2列的格子,其上左下右的值分別爲-1.7、-1.7、-2.0、-2.0,出現了兩個最大值,即上方和左方
  • 以第2行第3列的格子,其上左下右的值均爲-2.0,出現了四個最大值

於是我就猜想,我們是不是可以做如下策略變換:

  • (row = 2,col = 1)處的策略,由\pi = \{0.25,0.25,0.25,0.25\}變成\pi = \{1,0,0,0\}
  • (row=2,col=2)處的策略,由\pi = \{0.25,0.25,0.25,0.25\}變成\pi = \{0.5,0.5,0,0\}
  • (row=2,col=3)處的策略,由\pi = \{0.25,0.25,0.25,0.25\}保持不變

由此,對於k=2,我們得到新的策略集PI:

{0,0,0,0} {0,1,0,0} {0,1,0,0} {0.25,0.25,0.25,0.25}
{1,0,0,0} {0.5,0.5,0,0} {0.25,0.25,0.25,0.25} {0,0,1,0}
{1,0,0,0} {0.25,0.25,0.25,0.25} {0,0,0.5,0.5} {0,0,1,0}
{0.25,0.25,0.25,0.25} {0,0,0,1} {0,0,0,1} {0,0,0,0}

基於更新後的策略,我們計算新的值函數,

0

-1

= 1 * ((-1) + 1 * (0))【左】

-2.7 

=    1 * ((-1) + 1 * (-1.7))【左】

-3.0
=    0.25 * (-1 + 1 * (-2))  【上】
+    0.25 * (-1 + 1 * (-2))  【左】
+    0.25 * (-1 + 1 * (-2))  【下】
+    0.25 * (-1 + 1 * (-2))  【右】

-1

= 1 * ((-1) + 1 * (0))【上】

-2.7
=    0.5 * (-1 + 1 * (-1.7)) 【上】
+    0.5 * (-1 + 1 * (-1.7)) 【左】
-3.0 
=    0.25 * (-1 + 1 * (-2)) 【上】
+    0.25 * (-1 + 1 * (-2)) 【左】
+    0.25 * (-1 + 1 * (-2))  【下】
+    0.25 * (-1 + 1 * (-2))  【右】

-2.7

=     1 * (-1 + 1 * (-1.7))【下】

-2.7

= 1 * (-1 + 1 * (-1.7))【上】

-3.0 
=    0.25 * (-1 + 1 * (-2)) 【上】
+    0.25 * (-1 + 1 * (-2)) 【左】
+    0.25 * (-1 + 1 * (-2))  【下】
+    0.25 * (-1 + 1 * (-2))  【右】
-2.7
=    0.5 * (-1 + 1 * (-1.7)) 【上】
+    0.5 * (-1 + 1 * (-1.7)) 【左】
-1 = 1 * ((-1) + 1 * (0))【下】
-3.0 
=    0.25 * (-1 + 1 * (-2)) 【上】
+    0.25 * (-1 + 1 * (-2)) 【左】
+    0.25 * (-1 + 1 * (-2)) 【下】
+    0.25 * (-1 + 1 * (-2)) 【右】

-2.7 

=    1 * ((-1) + 1 * (-1.7))【右】

-1

= 1 * ((-1) + 1 * (0))【右】

0

這樣我們就得到了新的值函數,再由新的值函數進行策略更新,得到了下邊的策略集:

{0,0,0,0} {0,1,0,0} {0,1,0,0} {0,0.5,0.5,0}
{1,0,0,0} {0.5,0.5,0,0} {0.25,0.25,0.25,0.25} {0,0,1,0}
{1,0,0,0} {0.25,0.25,0.25,0.25} {0,0,0.5,0.5} {0,0,1,0}
{0.5,0,0,0.5} {0,0,0,1} {0,0,0,1} {0,0,0,0}

發現更新後的新策略居然跟之前的一樣,是不是很神奇;這樣我們就一路貪心的找到了最優策略。

這裏還存在一個疑問,爲啥在第2行第3列和第3行的第2列的策略不是四個方向呢?大神畫的圖,咱也不敢質疑,有高人可以解惑的不勝榮幸。

爲什麼要這麼做能?我在想通過值函數我已經判斷了某些方向的迭代預期是比較差的,我們就可以從中間選擇那些好的讓他去迭代呀;在我們的問題中,如果出現一個好的方向,我們以後就奔着這個好的方向去了;如果出現多個好的方向,我們也不知道那個方向更好,那就等概率的往這些方向去唄,反正走着走着,我們的美好生活就來了。

4.2.2 策略迭代的Matlab實現

基於上面的分析,我開發了Matlab程序,代碼如下:

設計到三個函數:

函數名 功能
valueToPolicy 根據值函數進行策略更新[使用負無窮-inf表示了跳出邊界的行爲]
singleVI 根據策略進行值函數更新
getOptState 給定某一狀態的行爲值函數,得到最優行爲

狀態最優行爲更新

function policy = getOptState(actionVal)
policy = zeros(length(actionVal),1);
maxValue = max(actionVal);
prob = 1 / sum(actionVal(:) == maxValue);
for i = 1:length(actionVal)
    if(actionVal(i) == maxValue)
        policy(i) = prob;
    end
end
end

策略更新函數

%根據值函數更新策略
function policy = valueToPolicy(value)
rowCnts = size(value,1);
colCnts = size(value,2);
tmpPolicyFlag = zeros(rowCnts * colCnts, 4);
%定義極小數值M,將那些預跳出網絡的操作設置爲該值
M = -inf;
for row = 1:rowCnts
    for col = 1:colCnts
        %第一行
        if(row == 1)
             %第一行的第一個格子【上左下右】
            if(col == 1)
                tmpPolicyFlag((row - 1) * colCnts + col,:) = getOptState([value(row, col), value(row, col), value(row+1, col), value(row, col+1)]);
            elseif(col < colCnts)
                tmpPolicyFlag((row - 1) * colCnts + col,:) = getOptState([M, value(row, col-1), value(row+1, col), value(row, col+1)]);
            else
                tmpPolicyFlag((row - 1) * colCnts + col,:) = getOptState([M, value(row, col-1), value(row+1, col), M]);
            end          
        end
       %最後一個格子
       if(col == colCnts && row == rowCnts)
            tmpPolicyFlag((row - 1) * colCnts + col,:) = getOptState([value(row-1, col), value(row, col-1), value(row, col), value(row, col)]);
       end
        %第一列非首行
        if(col == 1 && row ~= 1)
            if(row ~= rowCnts)
             tmpPolicyFlag((row - 1) * colCnts + col,:) = getOptState([value(row-1, col), M, value(row+1, col), value(row, col+1)]);
            else
               tmpPolicyFlag((row - 1) * colCnts + col,:) = getOptState([value(row-1, col), M, M, value(row, col+1)]); 
            end
        end
        
        %最後一列非尾行
        if(col == colCnts && row ~= 1 && row ~= rowCnts)
             tmpPolicyFlag((row - 1) * colCnts + col,:) = getOptState([value(row-1, col), value(row, col-1), value(row+1, col), M]);
        end
        %最後一行掐頭去尾
        if(row == rowCnts && col ~= colCnts && col ~= 1)
           tmpPolicyFlag((row - 1) * colCnts + col,:) = getOptState([value(row-1, col), value(row, col-1), M, value(row, col+1)]);
        end
        %非邊界行
        if(row ~= rowCnts && row ~= 1 && col ~= colCnts && col ~= 1)
           tmpPolicyFlag((row - 1) * colCnts + col,:) = getOptState([value(row-1, col), value(row, col-1), value(row+1, col), value(row, col+1)]);
        end
    end
%輸出更新之後的策略   
policy = tmpPolicyFlag;
end

值函數更新

function [v_cur] = singleVI(v_before, policy, gamma, reward, gridRow, gridCol)
v_cur = v_before;
%遍歷所有的格子
    for i = 1:gridRow
        for j = 1:gridCol
            %第一行的第一個格子
            if(i == 1 && j == 1)
                v_cur(i,j) = v_before(i,j);
            end
            
            %第一行其他格子
            if(i == 1 && j ~= 1)
                if (j ~= gridCol)
                    %上左下右
                    v_cur(i,j) =  policy((i-1) * gridCol + j, 1) * (reward + gamma * v_before(i,j)) ...
                    + policy((i-1) * gridCol + j,2) * (reward + gamma * v_before(i,j-1)) ...
                    + policy((i-1) * gridCol + j,3) * (reward + gamma * v_before(i+1,j)) ...
                    + policy((i-1) * gridCol + j,4) * (reward + gamma * v_before(i, j+1));
                else
                    v_cur(i,j) =  policy((i-1) * gridCol + j,1) * (reward + gamma * v_before(i,j)) ...
                    + policy((i-1) * gridCol + j,2) * (reward + gamma * v_before(i,j-1)) ...
                    + policy((i-1) * gridCol + j,3) * (reward + gamma * v_before(i+1,j)) ...
                    + policy((i-1) * gridCol + j,4) * (reward + gamma * v_before(i, j));
                end
            end
            %第1列其他格子
            if (j == 1 && i ~= 1)
                 if (i ~= gridRow)
                    v_cur(i,j) =  policy((i-1) * gridCol + j,1) * (reward + gamma * v_before(i-1,j)) ...
                    + policy((i-1) * gridCol + j,2) * (reward + gamma * v_before(i,j)) ...
                    + policy((i-1) * gridCol + j,3) * (reward + gamma * v_before(i+1,j)) ...
                    + policy((i-1) * gridCol + j,4) * (reward + gamma * v_before(i, j+1));
                else
                    v_cur(i,j) =  policy((i-1) * gridCol + j,1) * (reward + gamma * v_before(i-1,j)) ...
                    + policy((i-1) * gridCol + j,2) * (reward + gamma * v_before(i,j)) ...
                    + policy((i-1) * gridCol + j,3) * (reward + gamma * v_before(i,j)) ...
                    + policy((i-1) * gridCol + j,4) * (reward + gamma * v_before(i,j+1));
                 end              
            end
            %第4列非首行格子
            if (j == gridRow && i ~= 1)
                 if (i ~= gridCol)
                    v_cur(i,j) =  policy((i-1) * gridCol + j,1) * (reward + gamma * v_before(i-1,j)) ...
                    + policy((i-1) * gridCol + j,2) * (reward + gamma * v_before(i,j-1)) ...
                    + policy((i-1) * gridCol + j,3) * (reward + gamma * v_before(i+1,j)) ...
                    + policy((i-1) * gridCol + j,4) * (reward + gamma * v_before(i, j));
                else
                    v_cur(i,j) =  0;
                 end              
            end
            %第4行非首列格子
            if (i == gridRow && j ~= 1 && j ~= gridCol)
                v_cur(i,j) =  policy((i-1) * gridCol + j,1) * (reward + gamma * v_before(i-1,j)) ...
                    + policy((i-1) * gridCol + j,2) * (reward + gamma * v_before(i,j-1)) ...
                    + policy((i-1) * gridCol + j,3) * (reward + gamma * v_before(i,j)) ...
                    + policy((i-1) * gridCol + j,4) * (reward + gamma * v_before(i, j+1));
            end
            
            %非邊界行的計算
            if (i~= 1 && i ~= gridRow && j ~= gridCol && j ~= 1)
                v_cur(i,j) =  policy((i-1) * gridCol + j,1) * (reward + gamma * v_before(i-1,j)) ...
                    + policy((i-1) * gridCol + j,2) * (reward + gamma * v_before(i,j-1)) ...
                    + policy((i-1) * gridCol + j,3) * (reward + gamma * v_before(i+1,j)) ...
                    + policy((i-1) * gridCol + j,4) * (reward + gamma * v_before(i, j+1));
            end
        end
    end

end

主測試程序:值函數全部初始化爲0,策略爲各方向爲0.25

clc;clear;
%初始化格網的行數
gridRow = 4;
gridCol = 4;
%初始化值函數、當前值函數和上一期值函數
v = zeros(gridRow,gridCol);
v_cur = v;
v_before = v;
%折扣因子
gamma = 1;
%即時獎勵
reward = -1;
%定義1-2-3-4來表示行爲方向,上左下右
action_direct = [1,2,3,4];
%定義初始策略
policy = [0.25,0.25,0.25,0.25;  0.25,0.25,0.25,0.25;    0.25,0.25,0.25,0.25;    0.25,0.25,0.25,0.25;
          0.25,0.25,0.25,0.25;  0.25,0.25,0.25,0.25;    0.25,0.25,0.25,0.25;    0.25,0.25,0.25,0.25;
          0.25,0.25,0.25,0.25;  0.25,0.25,0.25,0.25;    0.25,0.25,0.25,0.25;     0.25,0.25,0.25,0.25;
          0.25,0.25,0.25,0.25;  0.25,0.25,0.25,0.25;    0.25,0.25,0.25,0.25;     0.25,0.25,0.25,0.25];
value = [0,0,0,0; 0,0,0,0;  0,0,0,0; 0,0,0,0];
%初始值和策略
oldValue = value;
oldPolicy = policy;
%最終值和策略
finalPolicy = policy;
finalValue = value;
%循環迭代
iter = 0;
while(1)   
    iter = iter + 1;
    newValue = singleVI(oldValue,oldPolicy,gamma, reward, gridRow,gridCol);
    newPolicy = valueToPolicy(newValue);
    if(newPolicy == oldPolicy)
        fprintf('第%d次的解算結果爲:',iter)
        finalPolicy = newPolicy;
        finalValue = newValue;
        break;
    end
    oldPolicy = newPolicy;
    oldValue = newValue;
end

finalPolicy
finalValue

4.2.3 運行結果展示

第3次的解算結果爲:
finalPolicy =

                       0.5                       0.5                         0                         0
                         0                         1                         0                         0
                         0                         1                         0                         0
                         0                       0.5                       0.5                         0
                         1                         0                         0                         0
                       0.5                       0.5                         0                         0
                      0.25                      0.25                      0.25                      0.25
                         0                         0                         1                         0
                         1                         0                         0                         0
                      0.25                      0.25                      0.25                      0.25
                         0                         0                       0.5                       0.5
                         0                         0                         1                         0
                       0.5                         0                         0                       0.5
                         0                         0                         0                         1
                         0                         0                         0                         1
                         0                         0                       0.5                       0.5


finalValue =

     0    -1    -2    -3
    -1    -2    -3    -2
    -2    -3    -2    -1
    -3    -2    -1     0

 

可知,進行了3次迭代我們邊找了最優策略,終點的兩個0.5可以忽略,我們按照其餘非0元素所在的位置,按照上左下右的順序,既可以解析出每個狀態的最優行爲策略。

 

參考資料:


如果喜歡我的分享,可關注以下兩個公衆帳號

發佈了162 篇原創文章 · 獲贊 53 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章