強化學習(十三) 策略梯度(Policy Gradient)
在前面講到的DQN系列強化學習演算法中,我們主要對價值函式進行了近似表示,基於價值來學習。這種Value Based強化學習方法在很多領域都得到比較好的應用,但是Value Based強化學習方法也有很多侷限性,因此在另一些場景下我們需要其他的方法,比如本篇討論的策略梯度(Policy Gradient),它是Policy Based強化學習方法,基於策略來學習。
本文參考了Sutton的強化學習書第13章和策略梯度的論文。
1. Value Based強化學習方法的不足
DQN系列強化學習演算法主要的問題主要有三點。
第一點是對連續動作的處理能力不足。DQN之類的方法一般都是隻處理離散動作,無法處理連續動作。雖然有NAF DQN之類的變通方法,但是並不優雅。比如我們之前提到的經典的冰球世界(PuckWorld) 強化學習問題,具體的動態demo見
第二點是對受限狀態下的問題處理能力不足。在使用特徵來描述狀態空間中的某一個狀態時,有可能因為個體觀測的限制或者建模的侷限,導致真實環境下本來不同的兩個狀態卻再我們建模後擁有相同的特徵描述,進而很有可能導致我們的value Based方法無法得到最優解。此時使用Policy Based強化學習方法也很有效。
第三點是無法解決隨機策略問題。Value Based強化學習方法對應的最優策略通常是確定性策略,因為其是從眾多行為價值中選擇一個最大價值的行為,而有些問題的最優策略卻是隨機策略,這種情況下同樣是無法通過基於價值的學習來求解的。這時也可以考慮使用Policy Based強化學習方法。
由於上面這些原因,Value Based強化學習方法不能通吃所有的場景,我們需要新的解決上述類別問題的方法,比如Policy Based強化學習方法。
2. Policy Based強化學習方法引入
回想我們在alue Based強化學習方法裡,我們對價值函式進行了近似表示,引入了一個動作價值函式$\hat{q}$,這個函式由引數$w$描述,並接受狀態$s$與動作$a$作為輸入,計算後得到近似的動作價值,即:$$\hat{q}(s,a,w) \approx q_{\pi}(s,a)$$
在Policy Based強化學習方法下,我們取樣類似的思路,只不過這時我們對策略進行近似表示。此時策略$\pi$可以被被描述為一個包含引數$\theta$的函式,即:$$\pi_{\theta}(s,a) = P(a|s,\theta)\approx \pi(a|s)$$
將策略表示成一個連續的函式後,我們就可以用連續函式的優化方法來尋找最優的策略了。而最常用的方法就是梯度上升法了,那麼這個梯度對應的優化目標如何定義呢?
3. 策略梯度的優化目標
我們要用梯度上升來尋找最優的梯度,首先就要找到一個可以優化的函式目標。
最簡單的優化目標就是初始狀態收穫的期望,即優化目標為:$$J_1(\theta) = V_{\pi_{\theta}}(s_1) = \mathbb{E}_{\pi_{\theta}}(G_1) $$
但是有的問題是沒有明確的初始狀態的,那麼我們的優化目標可以定義平均價值,即:$$J_{avV}(\theta) =\sum\limits_sd_{\pi_{\theta}}(s)V_{\pi_{\theta}}(s)$$
其中,$d_{\pi_{\theta}}(s)$是基於策略$\pi_{\theta}$生成的馬爾科夫鏈關於狀態的靜態分佈。
或者定義為每一時間步的平均獎勵,即:$$J_{avR}(\theta) = =\sum\limits_sd_{\pi_{\theta}}(s) \sum\limits_a \pi_{\theta}(s,a) R_s^a$$
無論我們是採用$J_1,J_{avV}$還是$J_{avR}$來表示優化目標,最終對$\theta$求導的梯度都可以表示為:$$\nabla_{\theta} J(\theta) = \mathbb{E}_{\pi_{\theta}}[\nabla_{\theta}log \pi_{\theta}(s,a) Q_{\pi}(s,a)]$$
具體的證明過程這裡就不再列了,如果大家感興趣,可以去看策略梯度的論文的附錄1,裡面有詳細的證明。
當然我們還可以採用很多其他可能的優化目標來做梯度上升,此時我們的梯度式子裡面的$\nabla_{\theta}log \pi_{\theta}(s,a)$部分並不改變,變化的只是後面的$ Q_{\pi}(s,a)]$部分。對於$\nabla_{\theta}log \pi_{\theta}(s,a)$,我們一般稱為分值函式(score function)。
現在梯度的式子已經有了,後面剩下的就是策略函式$\pi_{\theta}(s,a)$的設計了。
4. 策略函式的設計
現在我們回頭看一下策略函式$ \pi_{\theta}(s,a) $的設計,在前面它一直是一個數學符號。
最常用的策略函式就是softmax策略函數了,它主要應用於離散空間中,softmax策略使用描述狀態和行為的特徵$\phi(s,a)$ 與引數$\theta$的線性組合來權衡一個行為發生的機率,即:$$\pi_{\theta}(s,a) = \frac{e^{\phi(s,a)^T\theta}}{\sum\limits_be^{\phi(s,b)^T\theta}}$$
則通過求導很容易求出對應的分值函式為:$$\nabla_{\theta}log \pi_{\theta}(s,a) = \phi(s,a) - \mathbb{E}_{\pi_{\theta}}[\phi(s,.)]$$
另一種高斯策略則是應用於連續行為空間的一種常用策略。該策略對應的行為從高斯分佈$ \mathbb{N(\phi(s)^T\theta, \sigma^2)}$中產生。高斯策略對應的分值函式求導可以得到為:$$\nabla_{\theta}log \pi_{\theta}(s,a) = = \frac{(a-\phi(s)^T\theta)\phi(s)}{\sigma^2}$$
有策略梯度的公式和策略函式,我們可以得到第一版的策略梯度演算法了。
5. 蒙特卡羅策略梯度reinforce演算法
這裡我們討論最簡單的策略梯度演算法,蒙特卡羅策略梯度reinforce演算法, 使用價值函式$v(s)$來近似代替策略梯度公式裡面的$Q_{\pi}(s,a)$。演算法的流程很簡單,如下所示:
輸入:N個蒙特卡羅完整序列,訓練步長$\alpha$
輸出:策略函式的引數$\theta$
1. for 每個蒙特卡羅序列:
a. 用蒙特卡羅法計算序列每個時間位置t的狀態價值$v_t$
b. 對序列每個時間位置t,使用梯度上升法,更新策略函式的引數$\theta$:$$\theta = \theta + \alpha \nabla_{\theta}log \pi_{\theta}(s_t,a_t) v_t$$
2. 返回策略函式的引數$\theta$
這裡的策略函式可以是softmax策略,高斯策略或者其他策略。
6. 策略梯度例項
這裡給出第5節的蒙特卡羅策略梯度reinforce演算法的一個例項。仍然使用了OpenAI Gym中的CartPole-v0遊戲來作為我們演算法應用。CartPole-v0遊戲的介紹參見這裡。它比較簡單,基本要求就是控制下面的cart移動使連線在上面的pole保持垂直不倒。這個任務只有兩個離散動作,要麼向左用力,要麼向右用力。而state狀態就是這個cart的位置和速度, pole的角度和角速度,4維的特徵。堅持到200分的獎勵則為過關。
完整的程式碼參見我的github:https://github.com/ljpzzz/machinelearning/blob/master/reinforcement-learning/policy_gradient.py
這裡我們採用softmax策略作為我們的策略函式,同時,softmax的前置部分,也就是我們的策略模型用一個三層的softmax神經網路來表示。這樣好處就是梯度的更新可以交給神經網路來做。
我們的softmax神經網路的結構如下,注意這個網路不是價值Q網路,而是策略網路:
def create_softmax_network(self): # network weights W1 = self.weight_variable([self.state_dim, 20]) b1 = self.bias_variable([20]) W2 = self.weight_variable([20, self.action_dim]) b2 = self.bias_variable([self.action_dim]) # input layer self.state_input = tf.placeholder("float", [None, self.state_dim]) self.tf_acts = tf.placeholder(tf.int32, [None, ], name="actions_num") self.tf_vt = tf.placeholder(tf.float32, [None, ], name="actions_value") # hidden layers h_layer = tf.nn.relu(tf.matmul(self.state_input, W1) + b1) # softmax layer self.softmax_input = tf.matmul(h_layer, W2) + b2 #softmax output self.all_act_prob = tf.nn.softmax(self.softmax_input, name='act_prob') self.neg_log_prob = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=self.softmax_input, labels=self.tf_acts) self.loss = tf.reduce_mean(self.neg_log_prob * self.tf_vt) # reward guided loss self.train_op = tf.train.AdamOptimizer(LEARNING_RATE).minimize(self.loss)
注意我們的損失函式是softmax交叉熵損失函式和狀態價值函式的乘積,這樣TensorFlow後面可以自動幫我們做梯度的迭代優化。
另一個要注意的點就是蒙特卡羅法裡面價值函式的計算,一般是從後向前算,這樣前面的價值的計算可以利用後面的價值作為中間結果,簡化計算,對應程式碼如下:
def learn(self): discounted_ep_rs = np.zeros_like(self.ep_rs) running_add = 0 for t in reversed(range(0, len(self.ep_rs))): running_add = running_add * GAMMA + self.ep_rs[t] discounted_ep_rs[t] = running_add discounted_ep_rs -= np.mean(discounted_ep_rs) discounted_ep_rs /= np.std(discounted_ep_rs)
其餘部分和之前的DQN的程式碼類似。
7. 策略梯度小結
策略梯度提供了和DQN之類的方法不同的新思路,但是我們上面的蒙特卡羅策略梯度reinforce演算法卻並不完美。由於是蒙特卡羅法,我們需要完全的序列樣本才能做演算法迭代,同時蒙特卡羅法使用收穫的期望來計算狀態價值,會導致行為有較多的變異性,我們的引數更新的方向很可能不是策略梯度的最優方向。
因此,Policy Based的強化學習方法還需要改進,注意到我們之前有Value Based強化學習方法,那麼兩者能不能結合起來一起使用呢?下一篇我們討論Policy Based+Value Based結合的策略梯度方法Actor-Critic。
(歡迎轉載,轉載請註明出處。歡迎溝通交流: [email protected])