強化學習(十)Double DQN (DDQN)

劉建平Pinard發表於2018-10-12

    在強化學習(九)Deep Q-Learning進階之Nature DQN中,我們討論了Nature DQN的演算法流程,它通過使用兩個相同的神經網路,以解決資料樣本和網路訓練之前的相關性。但是還是有其他值得優化的點,文字就關注於Nature DQN的一個改進版本: Double DQN演算法(以下簡稱DDQN)。

    本章內容主要參考了ICML 2016的deep RL tutorial和DDQN的論文<Deep Reinforcement Learning with Double Q-learning>。

1. DQN的目標Q值計算問題

    在DDQN之前,基本上所有的目標Q值都是通過貪婪法直接得到的,無論是Q-Learning, DQN(NIPS 2013)還是 Nature DQN,都是如此。比如對於Nature DQN,雖然用了兩個Q網路並使用目標Q網路計算Q值,其第j個樣本的目標Q值的計算還是貪婪法得到的,計算入下式:$$y_j= \begin{cases} R_j& {is\_end_j\; is \;true}\\ R_j + \gamma\max_{a'}Q'(\phi(S'_j),A'_j,w') & {is\_end_j \;is\; false} \end{cases}$$

    使用max雖然可以快速讓Q值向可能的優化目標靠攏,但是很容易過猶不及,導致過度估計(Over Estimation),所謂過度估計就是最終我們得到的演算法模型有很大的偏差(bias)。為了解決這個問題, DDQN通過解耦目標Q值動作的選擇和目標Q值的計算這兩步,來達到消除過度估計的問題。

2. DDQN的演算法建模

    DDQN和Nature DQN一樣,也有一樣的兩個Q網路結構。在Nature DQN的基礎上,通過解耦目標Q值動作的選擇和目標Q值的計算這兩步,來消除過度估計的問題。

    在上一節裡,Nature DQN對於非終止狀態,其目標Q值的計算式子是:$$y_j= R_j + \gamma\max_{a'}Q'(\phi(S'_j),A'_j,w')$$

    在DDQN這裡,不再是直接在目標Q網路裡面找各個動作中最大Q值,而是先在當前Q網路中先找出最大Q值對應的動作,即$$a^{max}(S'_j, w) = \arg\max_{a'}Q(\phi(S'_j),a,w)$$

    然後利用這個選擇出來的動作$a^{max}(S'_j, w) $在目標網路裡面去計算目標Q值。即:$$y_j = R_j + \gamma Q'(\phi(S'_j),a^{max}(S'_j, w),w')$$

    綜合起來寫就是:$$y_j = R_j + \gamma Q'(\phi(S'_j),\arg\max_{a'}Q(\phi(S'_j),a,w),w')$$

    除了目標Q值的計算方式以外,DDQN演算法和Nature DQN的演算法流程完全相同。

 3. DDQN演算法流程

    這裡我們總結下DDQN的演算法流程,和Nature DQN的區別僅僅在步驟2.f中目標Q值的計算。

    演算法輸入:迭代輪數$T$,狀態特徵維度$n$, 動作集$A$, 步長$\alpha$,衰減因子$\gamma$, 探索率$\epsilon$, 當前Q網路$Q$,目標Q網路$Q'$, 批量梯度下降的樣本數$m$,目標Q網路引數更新頻率$C$。

    輸出:Q網路引數

    1. 隨機初始化所有的狀態和動作對應的價值$Q$.  隨機初始化當前Q網路的所有引數$w$,初始化目標Q網路$Q'$的引數$w' = w$。清空經驗回放的集合$D$。

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

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

      b) 在Q網路中使用$\phi(S)$作為輸入,得到Q網路的所有動作對應的Q值輸出。用$\epsilon-$貪婪法在當前Q值輸出中選擇對應的動作$A$

      c) 在狀態$S$執行當前動作$A$,得到新狀態$S'$對應的特徵向量$\phi(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),\arg\max_{a'}Q(\phi(S'_j),a,w),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$,通過神經網路的梯度反向傳播來更新Q網路的所有引數$w$

      h) 如果T%C=1,則更新目標Q網路引數$w'=w$

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

      注意,上述第二步的f步和g步的Q值計算也都需要通過Q網路計算得到。另外,實際應用中,為了演算法較好的收斂,探索率$\epsilon$需要隨著迭代的進行而變小。

4. DDQN演算法例項 

    下面我們用一個具體的例子來演示DQN的應用。仍然使用了OpenAI Gym中的CartPole-v0遊戲來作為我們演算法應用。CartPole-v0遊戲的介紹參見這裡。它比較簡單,基本要求就是控制下面的cart移動使連線在上面的pole保持垂直不倒。這個任務只有兩個離散動作,要麼向左用力,要麼向右用力。而state狀態就是這個cart的位置和速度, pole的角度和角速度,4維的特徵。堅持到200分的獎勵則為過關。

    完整的程式碼參見我的github: https://github.com/ljpzzz/machinelearning/blob/master/reinforcement-learning/ddqn.py

    這裡我們重點關注DDQN和上一節的Nature DQN的程式碼的不同之處。程式碼只有一個地方不一樣,就是計算目標Q值的時候,如下:

    # Step 2: calculate y
    y_batch = []
    current_Q_batch = self.Q_value.eval(feed_dict={self.state_input: next_state_batch})
    max_action_next = np.argmax(current_Q_batch, axis=1)
    target_Q_batch = self.target_Q_value.eval(feed_dict={self.state_input: next_state_batch})

    for i in range(0,BATCH_SIZE):
      done = minibatch[i][4]
      if done:
        y_batch.append(reward_batch[i])
      else :
        target_Q_value = target_Q_batch[i, max_action_next[i]]
        y_batch.append(reward_batch[i] + GAMMA * target_Q_value)

    而之前的Nature  DQN這裡的目標Q值計算是如下這樣的:

 # Step 2: calculate y
    y_batch = []
    Q_value_batch = self.target_Q_value.eval(feed_dict={self.state_input:next_state_batch})
    for i in range(0,BATCH_SIZE):
      done = minibatch[i][4]
      if done:
        y_batch.append(reward_batch[i])
      else :
        y_batch.append(reward_batch[i] + GAMMA * np.max(Q_value_batch[i]))

    除了上面這部分的區別,兩個演算法的程式碼完全相同。

5. DDQN小結

    DDQN演算法出來以後,取得了比較好的效果,因此得到了比較廣泛的應用。不過我們的DQN仍然有其他可以優化的點,如上一篇最後講到的: 隨機取樣的方法好嗎?按道理經驗回放裡不同樣本的重要性是不一樣的,TD誤差大的樣本重要程度應該高。針對這個問題,我們在下一節的Prioritised Replay DQN中討論。

 

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

相關文章