本文內容源自百度強化學習 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:輸出動作的概率
- 這裏我們用 表示 policy 策略, 是神經網絡的參數,在 狀態下,做出 動作的概率
- 所以如果我們在一個狀態下只有 3 個動作,則可以表示爲:
- 這裏 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 :
-
從初始狀態出發,有不同的概率選擇動作
-
然後狀態發生變化(環境的隨機性,會導致環境的變化也是個概率分佈,即狀態轉移概率 )
-
在新的狀態下,再通過不同概率選擇動作
-
狀態繼續發生變化
- 這裏我們能夠優化的是智能體的選擇,而環境的隨機變化(狀態轉移概率)是客觀存在的,無法優化(控制)
-
不斷地交互,直到完成一個 episode(一局遊戲結束)
-
把這個 episode 中所有的連續的 s 變化 和 a 選擇串起來,就是一個 episode 的軌跡 Trajectory
-
軌跡:
軌跡的概率:
- 軌跡的每一步概率連乘即可:
軌跡的總 reward:
- 即每一步獲得的 reward 之和
我們和環境交互的軌跡可以有千千萬萬條,所以當我們跑了很多 episode ,獲得許多軌跡後,我們可以獲得 “期望回報”:
-
的期望回報:所有 episode 的平均回報
-
-
策略 下的期望回報就可以用來評價我們的策略優劣
難點:
- 無法窮舉所有的軌跡
- 無法獲得 “環境轉移概率”
解決方法:取近似值
- 這裏我們取得 N 條軌跡後(N足夠大),假設每條軌跡都是概率相等(隨機)
- 這個過程稱作:採樣(採樣 N 個 episode 來計算期望回報)
- 這樣就不需要知道 “環境轉移概率” 了
2.4 優化策略函數
我們可以用期望回報 來優化策略函數
-
在 DQN 中,我們的 loss 函數是來源於 目標 Q 和 預測 Q 之間的差別,我們希望優化過程是 預測 Q 不斷逼近 目標 Q,降低 loss(越小越好)
-
所以在 DQN 中,目標 Q 擔任的是一個正確的 label 指導
-
但是在 Policy 網絡中,沒有這樣一個 正確的 label 指導
-
所以需要用到
優化目標:
- 越大越好
- 這裏是一個梯度上升過程
策略梯度:
- 我們需要求解 對與 的梯度,用這個梯度去更新網絡
- 首先需要產生 N 條 episode 軌跡
- 每一條軌跡獲有一個總回報
- 獲得期望回報
- 然後求 對與 的導數
- 求導的過程中,可以約去不可知的 “環境轉移概率”
- 更新網絡後,讓分數高的軌跡概率可以更大
- 所以 loss 的公式前面要加上負號,這樣就可以讓梯度下降變成梯度上升
策略梯度公式推導過程:
三、採樣方式:REINFORCE
3.1 蒙特卡洛 MC 與 時序差分 TD
梯度策略分爲 蒙特卡洛 MC 與 時序差分 TD
- 蒙特卡洛:算法完成一個 episode,進行學習一次 learn()
- 完整運行一個 episode,我們可以知道每一步 step 的未來總收益
- 比如 :REINFORCE 算法(最簡單,經典)
- 時序差分:
- 每一個 step 都更新一次,更新頻率更高
- 使用 Q 函數來近似表示未來總收益
- 比如:Actor-Critic 算法
3.2 REINFORCE 算法
流程:
- 首先拿到每一步的收益
- 那自然可以計算出每一步的未來總收益
- 未來總收益,代表的是每一個動作的真正價值
- 這樣就可以把每一個 代入公式 去優化每一個 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 之間未來總收益有相關性:
所以在代碼實現上,是從後往前計算,先計算 ,再計算 ,依次進行
假設實際執行的動作 是 [0,1,0],計算得到的概率 是 [0.2,0.5,0.3],對每一個 action:
類比監督學習:
- 輸出的概率分佈要儘可能貼近真實的情況
- 比如手寫數字識別中,如果一個數字是 8,那網絡預測這個數字概率越高越好,比如 0.999 ,真實值 8 對應的是 1
- 通過迭代更新,希望識別 8 的時候,這個概率可以遠高於其他數字的概率
- 這裏我們使用交叉熵 Cross Entropy表示兩個概率分佈之間的差別
- 目標是縮小差距,即把 Loss 傳入優化器自動優化
Policy Gradient 中:
- 輸出預測行動的概率,和真實採用的概率做比較
- 真實採用的動作是隨機選擇的 action,並不代表正確的 action
- 所以前面要乘以一個累計回報 作爲對真實所採用的 action 的評價
- 越大,說明當前輸出的 action 是優質的,我們就越是希望預測概率向實際動作逼近
- 越小,說明當前輸出的 action 不好,所以 loss 的權重也更小,即不強求預測概率向該動作逼近
- 其中 ,代表實際執行的動作 (是 one-hot 向量,比如 [0,1,0] ), 代表神經網絡預測的動作概率(比如 [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