強化學習入門(四)策略梯度方法 Policy Gradient 求解強化學習問題

本文內容源自百度強化學習 7 日入門課程學習整理
感謝百度 PARL 團隊李科澆老師的課程講解

一、回顧 Value-based 和 Policy-based

1.1 基本概念

在這裏插入圖片描述

  • 基於價值

    • 優化策略價值函數,即 Q 的函數
    • 優化好了以後,直接選取最優路徑即可
    • 如:Sarsa,Q-learning,DQN
  • 基於策略

    • 不依賴於價值函數
    • 一個策略走到底,看最後的總收益來決定該動作的好壞
    • 如:Policy Gradient

1.2 區別

在這裏插入圖片描述
區別點一:

  • Value-based:神經網絡輸入狀態 S,輸出 Q,優化的也是 Q 函數
    • 動作的輸出要看最大的 Q 值,所以是間接輸出動作
  • Policy-based:輸入狀態 S,輸出動作 A

在這裏插入圖片描述
區別點二:

  • Value-based:先優化 Q 函數

    • 優化到最優的時候,Q 表固定
    • 根據 Q 表得到最優動作
    • 所以動作選擇是固定的,即確定性策略
  • Policy-based:輸出動作的概率

    • 這裏我們用 πθ(atst)π_θ(a_t|s_t) 表示 policy 策略,θθ 是神經網絡的參數,在 sts_t 狀態下,做出 ata_t 動作的概率
    • 所以如果我們在一個狀態下只有 3 個動作,則可以表示爲:

    π(a1s,θ)=p(a1,s)=0.3π(a2s,θ)=p(a2,s)=0.5π(a3s,θ)=p(a3,s)=0.2 π(a_1|s,θ) = p(a_1,s)=0.3 \\ π(a_2|s,θ) = p(a_2,s)=0.5 \\ π(a_3|s,θ) = p(a_3,s)=0.2

    • 這裏 3 個動作的概率相加爲 1
    • 輸出動作的時候,是根據概率進行隨機採樣,即概率越高採用這個動作的可能性越高(並不是一定採用概率最高的動作)
    • 舉例:這種隨機策略適合於 “剪刀石頭布” 這樣隨機性很大的遊戲(DQN就不行,因爲是確定性策略),最後優化可能 3 種動作都是 33.33% 的概率
    • 爲了輸出概率,那自然神經網絡的輸出層用的是 “softmax” 激活函數
      在這裏插入圖片描述

二、Policy Gradient 算法

2.1 隨機策略中的 softmax 函數

softmax 的作用,就是把輸出映射到 0~1 的區間內,並使得所有的輸出相加等於 1,於是就可以等同於不同選擇的概率了

  • 常常用於分類任務

計算方法:

  • 每個輸出值求一個自然對數
  • 然後除以所有輸出的自然對數的和

在這裏插入圖片描述
例如:在打乒乓球遊戲中

  • 輸入的是遊戲圖像(像素矩陣)
  • 輸出的是動作選擇概率(向上 88%,向下 12%,停留不動 0%),向量形式:[0.88, 0.12, 0]
  • 然後根據概率隨機挑選動作

2.2 一局遊戲 episode

在這裏插入圖片描述
當我們選擇一個動作以後,其實並不知道動作的優劣,而只有最終遊戲結束得到結果的時候,我們才能反推之前的動作優劣

  • 每一個 episode 中,agent 不斷和環境交互,輸出動作,直到該 episode 結束
  • 然後開啓另一個 episode

在這裏插入圖片描述

優化策略的目的:讓 “每一個” episode 的 “總的” reward 儘可能大

  • 單個 episode 有很多 step 組成,每個 step 會獲得 reward
  • 所有 episode 總的 reward 希望最大
  • 所以怎麼去量化我的優化目標就是個難點!

2.3 軌跡的期望回報

在這裏插入圖片描述
軌跡 Trajectory :

  • 從初始狀態出發,有不同的概率選擇動作

  • 然後狀態發生變化(環境的隨機性,會導致環境的變化也是個概率分佈,即狀態轉移概率 p(ss,a)p(s'|s,a)

  • 在新的狀態下,再通過不同概率選擇動作

  • 狀態繼續發生變化

    • 這裏我們能夠優化的是智能體的選擇,而環境的隨機變化(狀態轉移概率)是客觀存在的,無法優化(控制)
  • 不斷地交互,直到完成一個 episode(一局遊戲結束)

  • 把這個 episode 中所有的連續的 s 變化 和 a 選擇串起來,就是一個 episode 的軌跡 Trajectory

  • 軌跡:τ = {s1,a1,s2,a2,...sT,aT}τ\ =\ \{s_1,a_1,s_2,a_2,...s_T,a_T\}

軌跡的概率:

  • 軌跡的每一步概率連乘即可:
  • pθ(τ) = p(s1)πθ(a1s1)p(s2s1,a1)πθ(a1s1)p(s2s1,a1)...p_θ(τ)\ = \ p(s_1)π_θ(a_1|s_1)p(s_2|s_1,a_1)π_θ(a_1|s_1)p(s_2|s_1,a_1)...

軌跡的總 reward:

  • 即每一步獲得的 reward 之和
  • R(τ) = t=1TrtR(τ)\ = \ \sum_{t=1}^Tr_t

我們和環境交互的軌跡可以有千千萬萬條,所以當我們跑了很多 episode ,獲得許多軌跡後,我們可以獲得 “期望回報”:

  • πθ(as)π_θ(a|s) 的期望回報:所有 episode 的平均回報

  • Rθ = τR(τ)pθ(τ)\overline{R_θ}\ =\ \sum_{τ}R(τ)p_θ(τ)

  • 策略 πθ(as)π_θ(a|s) 下的期望回報就可以用來評價我們的策略優劣

難點:

  • 無法窮舉所有的軌跡
  • 無法獲得 “環境轉移概率”

解決方法:取近似值

  • Rθ = τR(τ)pθ(τ)  1Nn=1NR(τ)\overline{R_θ}\ =\ \sum_{τ}R(τ)p_θ(τ)\ \approx\ {1\over N}\sum_{n=1}^NR(τ)
  • 這裏我們取得 N 條軌跡後(N足夠大),假設每條軌跡都是概率相等(隨機)
  • 這個過程稱作:採樣(採樣 N 個 episode 來計算期望回報)
  • 這樣就不需要知道 “環境轉移概率” 了

2.4 優化策略函數

我們可以用期望回報 Rθ\overline{R_θ} 來優化策略函數 πθ(s,a)π_θ(s,a)

  • 在 DQN 中,我們的 loss 函數是來源於 目標 Q 和 預測 Q 之間的差別,我們希望優化過程是 預測 Q 不斷逼近 目標 Q,降低 loss(越小越好)

  • 所以在 DQN 中,目標 Q 擔任的是一個正確的 label 指導

  • 但是在 Policy 網絡中,沒有這樣一個 正確的 label 指導

  • 所以需要用到 Rθ\overline{R_θ}

在這裏插入圖片描述

優化目標:

  • J(θ) = RθJ(θ)\ =\ \overline{R_θ} 越大越好
  • 這裏是一個梯度上升過程

在這裏插入圖片描述

策略梯度:

  • 我們需要求解 Rθ\overline{R_θ} 對與 θθ 的梯度,用這個梯度去更新網絡
  • 首先需要產生 N 條 episode 軌跡
  • 每一條軌跡獲有一個總回報 R(τ)R(τ)
  • 獲得期望回報 Rθ\overline{R_θ}
  • 然後求 Rθ\overline{R_θ} 對與 θθ 的導數
  • Rθ  1Nn=1Nt=1TnR(τn)logπθ(atnstn)\triangledown \overline{R_θ}\ \approx\ {1\over N}\sum_{n=1}^N\sum_{t=1}^{T_n}R(τ^n)\triangledown \logπ_θ(a_t^n|s_t^n)
  • 求導的過程中,可以約去不可知的 “環境轉移概率”
  • 更新網絡後,讓分數高的軌跡概率可以更大
  • 所以 loss 的公式前面要加上負號,這樣就可以讓梯度下降變成梯度上升
  • Loss=R(τ)logπθ(atst)Loss = -R(τ)\log π_θ(a_t|s_t)

策略梯度公式推導過程:
在這裏插入圖片描述

三、採樣方式:REINFORCE

3.1 蒙特卡洛 MC 與 時序差分 TD

在這裏插入圖片描述
梯度策略分爲 蒙特卡洛 MC 與 時序差分 TD

  • 蒙特卡洛:算法完成一個 episode,進行學習一次 learn()
    • 完整運行一個 episode,我們可以知道每一步 step 的未來總收益 GtG_t
    • 比如 :REINFORCE 算法(最簡單,經典)
  • 時序差分:
    • 每一個 step 都更新一次,更新頻率更高
    • 使用 Q 函數來近似表示未來總收益
    • 比如:Actor-Critic 算法

3.2 REINFORCE 算法

在這裏插入圖片描述
流程:

  • 首先拿到每一步的收益 [r1,r2,r3...rT][r_1, r_2,r_3...r_T]
  • 那自然可以計算出每一步的未來總收益 [G1,G2,G3...GT][G_1,G_2,G_3...G_T]
  • 未來總收益,代表的是每一個動作的真正價值
  • 這樣就可以把每一個 GtG_t 代入公式 Rθ  1Nn=1Nt=1TnGtnlogπθ(atnstn)\triangledown \overline{R_θ}\ \approx\ {1\over N}\sum_{n=1}^N\sum_{t=1}^{T_n}G_t^n\triangledown \logπ_θ(a_t^n|s_t^n) 去優化每一個 action 的輸出
def calc_reward_to_go(reward_list, gamma=1.0):
    for i in range(len(reward_list) - 2, -1, -1):
        # G_t = r_t + γ·r_t+1 + ... = r_t + γ·G_t+1
        reward_list[i] += gamma * reward_list[i + 1]  # Gt
    return np.array(reward_list)

這裏的代碼就是把每一步的收益,轉成每一步的未來總收益

連續的 step 之間未來總收益有相關性:Gt = t=k+1Tγkt1rt = rt + γGt+1G_t\ = \ \sum_{t=k+1}^Tγ^{k-t-1}r_t\ =\ r_t\ +\ γG_{t+1}

所以在代碼實現上,是從後往前計算,先計算 GTG_T,再計算 GT1G_{T-1},依次進行

假設實際執行的動作 ata_t 是 [0,1,0],計算得到的概率 π(as,θ)π(a|s,θ) 是 [0.2,0.5,0.3],對每一個 action:Loss=Gt  [0,1,0]  log[0.2,0.5,0.3]Loss = -G_t\ ·\ [0,1,0]\ ·\ \log[0.2,0.5,0.3]

在這裏插入圖片描述

類比監督學習:

  • 輸出的概率分佈要儘可能貼近真實的情況
  • 比如手寫數字識別中,如果一個數字是 8,那網絡預測這個數字概率越高越好,比如 0.999 ,真實值 8 對應的是 1
  • 通過迭代更新,希望識別 8 的時候,這個概率可以遠高於其他數字的概率
  • 這裏我們使用交叉熵 Cross Entropy表示兩個概率分佈之間的差別
  • 目標是縮小差距,即把 Loss 傳入優化器自動優化

在這裏插入圖片描述

Policy Gradient 中:

  • 輸出預測行動的概率,和真實採用的概率做比較
  • 真實採用的動作是隨機選擇的 action,並不代表正確的 action
  • 所以前面要乘以一個累計回報 GtG_t 作爲對真實所採用的 action 的評價
  • GtG_t 越大,說明當前輸出的 action 是優質的,我們就越是希望預測概率向實際動作逼近
  • GtG_t 越小,說明當前輸出的 action 不好,所以 loss 的權重也更小,即不強求預測概率向該動作逼近
  • Loss=R(Pleft  log(Pleft) + Pstill  log(Pstill) + Pright  log(Pright))Loss = -R(P'_{left}\ * \ \log (P_{left})\ +\ P'_{still}\ *\ log(P_{still})\ +\ P'_{right}\ *\ \log(P_{right}))
  • 其中 R=GtR=G_tPP'代表實際執行的動作 ata_t(是 one-hot 向量,比如 [0,1,0] ),PP 代表神經網絡預測的動作概率(比如 [0.5, 0.3, 0.2] )
  • 由於我們可以拿到 episode 的整個軌跡,所以可以對這個 episode 中每一個 action 都計算一個 Loss
  • 累加所有的 Loss,然後讓優化器去優化
    在這裏插入圖片描述
    def learn(self, obs, action, reward): # 輸入的就是獲得的軌跡,reward代表未來總收益
        """ 用policy gradient 算法更新policy model
        """
        act_prob = self.model(obs)  # 獲取輸出動作概率(由神經網絡預測得到)
        # log_prob = layers.cross_entropy(act_prob, action) # 交叉熵
        log_prob = layers.reduce_sum(
            -1.0 * layers.log(act_prob) * layers.one_hot(
                action, act_prob.shape[1]),
            dim=1)
        cost = log_prob * reward # 乘的是當前 action 的未來總收益
        cost = layers.reduce_mean(cost) # 所有 step 要取均值

        optimizer = fluid.optimizer.Adam(self.lr)
        optimizer.minimize(cost)
        return cost

在這裏插入圖片描述
REINFORCE 流程圖:

  • 首先要有一個 Policy Model 來輸出動作概率
  • 用 sample() 函數得到具體的動作
  • 動作和環境交互,得到 reward
  • 一個 episode 運行完,得到軌跡數據(包含 3 個 list:S,a,G)
  • 執行 learn() 函數,用軌跡數據構造 loss 函數(該部分可以進行抽取封裝)
  • loss 函數放入優化器進行優化

在這裏插入圖片描述
PARL 中的 Policy Gradient 算法:

分成了 model,algorithm,agent 三個類

  • model 定義網絡結構
  • algorithm 預測動作輸出,構造 loss 函數,實現 learn() 函數
  • agent 實現執行動作,和環境交互,獲取環境數據

四、數據處理技巧

4.1 簡單場景的圖片預處理

在這裏插入圖片描述

  • 把圖片轉爲灰度
  • resize 到 80 * 80 * 1 的形狀
  • 最後把圖片轉爲 1 維向量

比如在 Pong 的乒乓球遊戲環境中:

# Pong 圖片預處理
def preprocess(image):
    """ 預處理 210x160x3 uint8 frame into 6400 (80x80) 1維 float vector """
    image = image[35:195] # 裁剪
    image = image[::2,::2,0] # 下采樣,縮放2倍
    image[image == 144] = 0 # 擦除背景 (background type 1)
    image[image == 109] = 0 # 擦除背景 (background type 2)
    image[image != 0] = 1 # 轉爲灰度圖,除了黑色外其他都是白色
    return image.astype(np.float).ravel()

當然我們也可以用 CNN 網絡,但是對於簡單圖像的環境,其實也可以這樣處理,就不用 CNN 網絡了

4.2 使用衰減 reward 並 normalize reward

因爲有些遊戲一個 episode 的時間很長,比如乒乓球遊戲 Pong,一方拿到 21 分遊戲才結束,所以整個過程有非常多的 step

所以要設計一個衰減因子,不需要考慮太長時間以後的收益,一般會設置爲 0.99

另外需要對一個 episode 拿到的收益做 normalize,讓我們獲取的收益有正有負,基本在原點兩側均衡分佈

通常這種歸一化的做法是爲了加速訓練,對於 action 的快速收斂更有效果

# 根據一個episode的每個step的reward列表,計算每一個Step的Gt
def calc_reward_to_go(reward_list, gamma=0.99):
    """calculate discounted reward"""
    reward_arr = np.array(reward_list)
    for i in range(len(reward_arr) - 2, -1, -1):
        # G_t = r_t + γ·r_t+1 + ... = r_t + γ·G_t+1
        reward_arr[i] += gamma * reward_arr[i + 1]
    # normalize episode rewards
    reward_arr -= np.mean(reward_arr)
    reward_arr /= np.std(reward_arr)
    return reward_arr

五、Policy Gradient 代碼詳解

強化學習算法 Policy Gradient 解決 CartPole 問題,代碼逐條詳解

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