強化學習(十六) 深度確定性策略梯度(DDPG)

劉建平Pinard發表於2019-02-01

    在強化學習(十五) A3C中,我們討論了使用多執行緒的方法來解決Actor-Critic難收斂的問題,今天我們不使用多執行緒,而是使用和DDQN類似的方法:即經驗回放和雙網路的方法來改進Actor-Critic難收斂的問題,這個演算法就是是深度確定性策略梯度(Deep Deterministic Policy Gradient,以下簡稱DDPG)。

    本篇主要參考了DDPG的論文和ICML 2016的deep RL tutorial

1. 從隨機策略到確定性策略

    從DDPG這個名字看,它是由D(Deep)+D(Deterministic )+ PG(Policy Gradient)組成。PG(Policy Gradient)我們在強化學習(十三) 策略梯度(Policy Gradient)裡已經討論過。那什麼是確定性策略梯度(Deterministic Policy Gradient,以下簡稱DPG)呢?

    確定性策略是和隨機策略相對而言的,對於某一些動作集合來說,它可能是連續值,或者非常高維的離散值,這樣動作的空間維度極大。如果我們使用隨機策略,即像DQN一樣研究它所有的可能動作的概率,並計算各個可能的動作的價值的話,那需要的樣本量是非常大才可行的。於是有人就想出使用確定性策略來簡化這個問題。

    作為隨機策略,在相同的策略,在同一個狀態處,採用的動作是基於一個概率分佈的,即是不確定的。而確定性策略則決定簡單點,雖然在同一個狀態處,採用的動作概率不同,但是最大概率只有一個,如果我們只取最大概率的動作,去掉這個概率分佈,那麼就簡單多了。即作為確定性策略,相同的策略,在同一個狀態處,動作是唯一確定的,即策略變成$$\pi_{\theta}(s) = a$$

2. 從DPG到DDPG

    在看確定性策略梯度DPG前,我們看看基於Q值的隨機性策略梯度的梯度計算公式:$$\nabla_{\theta}J(\pi_{\theta}) = E_{s\sim\rho^{\pi}, a\sim\pi_{\theta}}[\nabla_{\theta}log \pi_{\theta}(s,a)Q_{\pi}(s,a)]$$

    其中狀態的取樣空間為$\rho^{\pi}$, $\nabla_{\theta}log \pi_{\theta}(s,a)$是分值函式,可見隨機性策略梯度需要在整個動作的空間$\pi_{\theta}$進行取樣。'

    而DPG基於Q值的確定性策略梯度的梯度計算公式是:$$\nabla_{\theta}J(\pi_{\theta}) = E_{s\sim\rho^{\pi}}[\nabla_{\theta} \pi_{\theta}(s)\nabla_{a}Q_{\pi}(s,a)|_{a=\pi_{\theta}(s)}]$$

    跟隨機策略梯度的式子相比,少了對動作的積分,多了回報Q函式對動作的導數。

    而從DPG到DDPG的過程,完全可以類比DQN到DDQN的過程。除了老生常談的經驗回放以外,我們有了雙網路,即當前網路和目標網路的概念。而由於現在我們本來就有Actor網路和Critic兩個網路,那麼雙網路後就變成了4個網路,分別是:Actor當前網路,Actor目標網路,Critic當前網路,Critic目標網路。2個Actor網路的結構相同,2個Critic網路的結構相同。那麼這4個網路的功能各自是什麼呢?

3. DDPG的原理

    DDPG有4個網路,在瞭解這4個網路的功能之前,我們先複習DDQN的兩個網路:當前Q網路和目標Q網路的作用。可以複習強化學習(十)Double DQN (DDQN)

    DDQN的當前Q網路負責對當前狀態$S$使用$\epsilon-$貪婪法選擇動作$A$,執行動作$A$,獲得新狀態$S'$和獎勵$R$,將樣本放入經驗回放池,對經驗回放池中取樣的下一狀態$S’$使用貪婪法選擇動作$A'$,供目標Q網路計算目標Q值,當目標Q網路計算出目標Q值後,當前Q網路會進行網路引數的更新,並定期把最新網路引數複製到目標Q網路。

    DDQN的目標Q網路則負責基於經驗回放池計算目標Q值,提供給當前Q網路用,目標Q網路會定期從當前Q網路複製最新網路引數。

    

    現在我們回到DDPG,作為DDPG,Critic當前網路,Critic目標網路和DDQN的當前Q網路,目標Q網路的功能定位基本類似,但是我們有自己的Actor策略網路,因此不需要$\epsilon-$貪婪法這樣的選擇方法,這部分DDQN的功能到了DDPG可以在Actor當前網路完成。而對經驗回放池中取樣的下一狀態$S'$使用貪婪法選擇動作$A'$,這部分工作由於用來估計目標Q值,因此可以放到Actor目標網路完成。

    基於經驗回放池和目標Actor網路提供的$S',A'$計算目標Q值的一部分,這部分由於是評估,因此還是放到Critic目標網路完成。而Critic目標網路計算出目標Q值一部分後,Critic當前網路會計算目標Q值,並進行網路引數的更新,並定期將網路引數複製到Critic目標網路。

    此外,Actor當前網路也會基於Critic目標網路計算出的目標Q值,進行網路引數的更新,並定期將網路引數複製到Actor目標網路。

 

    有了上面的思路,我們總結下DDPG 4個網路的功能定位:

    1. Actor當前網路:負責策略網路引數$\theta$的迭代更新,負責根據當前狀態$S$選擇當前動作$A$,用於和環境互動生成$S',R$。

    2. Actor目標網路:負責根據經驗回放池中取樣的下一狀態$S'$選擇最優下一動作$A'$。網路引數$\theta '$定期從$\theta$複製。

    3. Critic當前網路:負責價值網路引數$w$的迭代更新,負責計算負責計算當前Q值$Q(S,A,w)$。目標Q值$y_i = R+\gamma Q'(S',A',w')$

    4. Critic目標網路:負責計算目標Q值中的$Q'(S',A',w')$部分。網路引數$w'$定期從$w$複製。

    DDPG除了這4個網路結構,還用到了經驗回放,這部分用於計算目標Q值,和DQN沒有什麼區別,這裡就不展開了。

    此外,DDPG從當前網路到目標網路的複製和我們之前講到了DQN不一樣。回想DQN,我們是直接把將當前Q網路的引數複製到目標Q網路,即$w'=w$, DDPG這裡沒有使用這種硬更新,而是使用了軟更新,即每次引數只更新一點點,即:$$w' \gets \tau w+ (1-\tau)w'$$$$\theta' \gets \tau \theta+ (1-\tau)\theta'$$

    其中$\tau$是更新系數,一般取的比較小,比如0.1或者0.01這樣的值。

    同時,為了學習過程可以增加一些隨機性,增加學習的覆蓋,DDPG對選擇出來的動作$A$會增加一定的噪聲$\mathcal{N}$,即最終和環境互動的動作$A$的表示式是:$$A = \pi_{\theta}(S) + \mathcal{N}$$

    最後,我們來看看DDPG的損失函式。對於Critic當前網路,其損失函式和DQN是類似的,都是均方誤差,即:$$J(w) =\frac{1}{m}\sum\limits_{j=1}^m(y_j-Q(\phi(S_j),A_j,w))^2$$

    而對於 Actor當前網路,其損失函式就和之前講的PG,A3C不同了,這裡由於是確定性策略,原論文定義的損失梯度是:$$\nabla_J(\theta) = \frac{1}{m}\sum\limits_{j=1}^m[\nabla_{a}Q_(s_i,a_i,w)|_{s=s_i,a=\pi_{\theta}(s)}\nabla_{\theta} \pi_{\theta(s)}|_{s=s_i}]$$

    這個可以對應上我們第二節的確定性策略梯度,看起來比較麻煩,但是其實理解起來很簡單。假如對同一個狀態,我們輸出了兩個不同的動作$a_1$和$a_2$,從Critic當前網路得到了兩個反饋的Q值,分別是$Q_1,Q_2$,假設$Q_1>Q_2$,即採取動作1可以得到更多的獎勵,那麼策略梯度的思想是什麼呢,就是增加$a_1$的概率,降低$a_2$的概率,也就是說,Actor想要儘可能的得到更大的Q值。所以我們的Actor的損失可以簡單的理解為得到的反饋Q值越大損失越小,得到的反饋Q值越小損失越大,因此只要對狀態估計網路返回的Q值取個負號即可,即:$$J(\theta) =  -\frac{1}{m}\sum\limits_{j=1}^m Q_(s_i,a_i,w)$$

4. DDPG演算法流程

    這裡我們總結下DDPG的演算法流程

    輸入:Actor當前網路,Actor目標網路,Critic當前網路,Critic目標網路,引數分別為$\theta, \theta',w,w'$,衰減因子$\gamma$,  軟更新系數$\tau$,批量梯度下降的樣本數$m$,目標Q網路引數更新頻率$C$。最大迭代次數$T$。隨機噪音函式\mathcal{N}

    輸出:最優Actor當前網路引數$ \theta$,Critic當前網路引數$w$

    1. 隨機初始化$\theta,w$, $w' = w$,$\theta' = \theta$。清空經驗回放的集合$D$

    2. for i from 1 to T,進行迭代。

      a) 初始化$S$為當前狀態序列的第一個狀態, 拿到其特徵向量$\phi(S)$

      b) 在Actor當前網路基於狀態$S$得到動作$A =\pi_{\theta}(\phi(S)) + \mathcal{N} $

      c) 執行動作$A$,得到新狀態$S'$,獎勵$R$,是否終止狀態%is\_end$

      d) 將$\{\phi(S),A,R,\phi(S'),is\_end\}$這個五元組存入經驗回放集合$D$

      e) S=S'

      f) 從經驗回放集合$D$中取樣$m$個樣本$\{\phi(S_j),A_j,R_j,\phi(S'_j),is\_end_j\}, j=1,2.,,,m$,計算當前目標Q值$y_j$:$$y_j= \begin{cases} R_j& {is\_end_j\; is \;true}\\ R_j + \gamma Q'(\phi(S'_j),\pi_{ \theta'}(\phi(S'_j)),w')& {is\_end_j\; is \;false} \end{cases}$$

      g)  使用均方差損失函式$\frac{1}{m}\sum\limits_{j=1}^m(y_j-Q(\phi(S_j),A_j,w))^2$,通過神經網路的梯度反向傳播來更新Critic當前網路的所有引數$w$

      h)  使用$J(\theta) =  -\frac{1}{m}\sum\limits_{j=1}^m Q_(s_i,a_i,w)$,,通過神經網路的梯度反向傳播來更新Actor當前網路的所有引數$\theta$

      i) 如果T%C=1,則更新Critic目標網路和Actor目標網路引數:$$w' \gets \tau w+ (1-\tau)w'$$$$\theta' \gets \tau \theta+ (1-\tau)\theta'$$

      j) 如果$S'$是終止狀態,當前輪迭代完畢,否則轉到步驟b)

      以上就是DDPG演算法的主流程,要注意的是上面2.f中的$\pi_{ \theta'}(\phi(S'_j))$是通過Actor目標網路得到,而$Q'(\phi(S'_j),\pi_{ \theta'}(\phi(S'_j)),w')$則是通過Critic目標網路得到的。

5. DDPG例項

    這裡我們給出DDPG第一個演算法例項,程式碼主要參考自莫煩的Github程式碼。增加了測試模型效果的部分,優化了少量引數。程式碼詳見:https://github.com/ljpzzz/machinelearning/blob/master/reinforcement-learning/ddpg.py

    這裡我們沒有用之前的CartPole遊戲,因為它不是連續動作。我們使用了Pendulum-v0這個遊戲。目的是用最小的力矩使棒子豎起來,這個遊戲的詳細介紹參見這裡。輸入狀態是角度的sin,cos值,以及角速度。一共三個值。動作是一個連續的力矩值。

    兩個Actor網路和兩個Critic網路的定義參見:

    def _build_a(self, s, scope, trainable):
        with tf.variable_scope(scope):
            net = tf.layers.dense(s, 30, activation=tf.nn.relu, name='l1', trainable=trainable)
            a = tf.layers.dense(net, self.a_dim, activation=tf.nn.tanh, name='a', trainable=trainable)
            return tf.multiply(a, self.a_bound, name='scaled_a')

    def _build_c(self, s, a, scope, trainable):
        with tf.variable_scope(scope):
            n_l1 = 30
            w1_s = tf.get_variable('w1_s', [self.s_dim, n_l1], trainable=trainable)
            w1_a = tf.get_variable('w1_a', [self.a_dim, n_l1], trainable=trainable)
            b1 = tf.get_variable('b1', [1, n_l1], trainable=trainable)
            net = tf.nn.relu(tf.matmul(s, w1_s) + tf.matmul(a, w1_a) + b1)
            return tf.layers.dense(net, 1, trainable=trainable)  # Q(s,a)

    Actor當前網路和Critic當前網路損失函式的定義參見:

        td_error = tf.losses.mean_squared_error(labels=q_target, predictions=q)
        self.ctrain = tf.train.AdamOptimizer(LR_C).minimize(td_error, var_list=self.ce_params)

        a_loss = - tf.reduce_mean(q)    # maximize the q
        self.atrain = tf.train.AdamOptimizer(LR_A).minimize(a_loss, var_list=self.ae_params)

    Actor目標網路和Critic目標網路引數軟更新,Actor當前網路和Critic當前網路反向傳播更新部分的程式碼如下:

    def learn(self):
        # soft target replacement
        self.sess.run(self.soft_replace)

        indices = np.random.choice(MEMORY_CAPACITY, size=BATCH_SIZE)
        bt = self.memory[indices, :]
        bs = bt[:, :self.s_dim]
        ba = bt[:, self.s_dim: self.s_dim + self.a_dim]
        br = bt[:, -self.s_dim - 1: -self.s_dim]
        bs_ = bt[:, -self.s_dim:]

        self.sess.run(self.atrain, {self.S: bs})
        self.sess.run(self.ctrain, {self.S: bs, self.a: ba, self.R: br, self.S_: bs_})

    其餘的可以對照演算法和程式碼一起學習,應該比較容易理解。

6. DDPG總結

    DDPG參考了DDQN的演算法思想嗎,通過雙網路和經驗回放,加一些其他的優化,比較好的解決了Actor-Critic難收斂的問題。因此在實際產品中尤其是自動化相關的產品中用的比較多,是一個比較成熟的Actor-Critic演算法。

    到此,我們的Policy Based RL系列也討論完了,而在更早我們討論了Value Based RL系列,至此,我們還剩下Model Based RL沒有討論。後續我們討論Model Based RL的相關演算法。

 

(歡迎轉載,轉載請註明出處。歡迎溝通交流: liujianping-ok@163.com)

相關文章