強化學習(九)Deep Q-Learning進階之Nature DQN

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

    在強化學習(八)價值函式的近似表示與Deep Q-Learning中,我們講到了Deep Q-Learning(NIPS 2013)的演算法和程式碼,在這個演算法基礎上,有很多Deep Q-Learning(以下簡稱DQN)的改進版,今天我們來討論DQN的第一個改進版Nature DQN(NIPS 2015)。

    本章內容主要參考了ICML 2016的deep RL tutorial和Nature DQN的論文。

1. DQN(NIPS 2013)的問題

    在上一篇我們已經討論了DQN(NIPS 2013)的演算法原理和程式碼實現,雖然它可以訓練像CartPole這樣的簡單遊戲,但是有很多問題。這裡我們先討論第一個問題。

    注意到DQN(NIPS 2013)裡面,我們使用的目標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}$$

    這裡目標Q值的計算使用到了當前要訓練的Q網路引數來計算$Q(\phi(S'_j),A'_j,w)$,而實際上,我們又希望通過$y_j$來後續更新Q網路引數。這樣兩者迴圈依賴,迭代起來兩者的相關性就太強了。不利於演算法的收斂。

    因此,一個改進版的DQN: Nature DQN嘗試用兩個Q網路來減少目標Q值計算和要更新Q網路引數之間的依賴關係。下面我們來看看Nature DQN是怎麼做的。

2. Nature DQN的建模

    Nature DQN使用了兩個Q網路,一個當前Q網路$Q$用來選擇動作,更新模型引數,另一個目標Q網路$Q'$用於計算目標Q值。目標Q網路的網路引數不需要迭代更新,而是每隔一段時間從當前Q網路$Q$複製過來,即延時更新,這樣可以減少目標Q值和當前的Q值相關性。

    要注意的是,兩個Q網路的結構是一模一樣的。這樣才可以複製網路引數。

    Nature DQN和上一篇的DQN相比,除了用一個新的相同結構的目標Q網路來計算目標Q值以外,其餘部分基本是完全相同的。

3. Nature DQN的演算法流程

    下面我們來總結下Nature DQN的演算法流程, 基於DQN NIPS 2015:

    演算法輸入:迭代輪數$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\max_{a'}Q'(\phi(S'_j),A'_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$,通過神經網路的梯度反向傳播來更新Q網路的所有引數$w$

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

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

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

4. Nature DQN演算法例項

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

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

    這裡我們重點關注Nature DQN和上一節的NIPS 2013 DQN的程式碼的不同之處。

    首先是Q網路,上一篇的DQN是一個三層的神經網路,而這裡我們有兩個一樣的三層神經網路,一個是當前Q網路,一個是目標Q網路,網路的定義部分如下:

  def create_Q_network(self):
    # input layer
    self.state_input = tf.placeholder("float", [None, self.state_dim])
    # network weights
    with tf.variable_scope('current_net'):
        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])

        # hidden layers
        h_layer = tf.nn.relu(tf.matmul(self.state_input,W1) + b1)
        # Q Value layer
        self.Q_value = tf.matmul(h_layer,W2) + b2

    with tf.variable_scope('target_net'):
        W1t = self.weight_variable([self.state_dim,20])
        b1t = self.bias_variable([20])
        W2t = self.weight_variable([20,self.action_dim])
        b2t = self.bias_variable([self.action_dim])

        # hidden layers
        h_layer_t = tf.nn.relu(tf.matmul(self.state_input,W1t) + b1t)
        # Q Value layer
        self.target_Q_value = tf.matmul(h_layer,W2t) + b2t

    對於定期將目標Q網路的引數更新的程式碼如下面兩部分:

    t_params = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope='target_net')
    e_params = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope='current_net')

    with tf.variable_scope('soft_replacement'):
        self.target_replace_op = [tf.assign(t, e) for t, e in zip(t_params, e_params)]
  def update_target_q_network(self, episode):
    # update target Q netowrk
    if episode % REPLACE_TARGET_FREQ == 0:
        self.session.run(self.target_replace_op)
        #print('episode '+str(episode) +', target Q network params replaced!')

    此外,注意下我們計算目標Q值的部分,這裡使用的目標Q網路的引數,而不是當前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]))

    其餘部分基本和上一篇DQN的程式碼相同。這裡給出我跑的某一次的結果:

episode: 0 Evaluation Average Reward: 9.8
episode: 100 Evaluation Average Reward: 9.8
episode: 200 Evaluation Average Reward: 9.6
episode: 300 Evaluation Average Reward: 10.0
episode: 400 Evaluation Average Reward: 34.8
episode: 500 Evaluation Average Reward: 177.4
episode: 600 Evaluation Average Reward: 200.0
episode: 700 Evaluation Average Reward: 200.0
episode: 800 Evaluation Average Reward: 200.0
episode: 900 Evaluation Average Reward: 198.4
episode: 1000 Evaluation Average Reward: 200.0
episode: 1100 Evaluation Average Reward: 193.2
episode: 1200 Evaluation Average Reward: 200.0
episode: 1300 Evaluation Average Reward: 200.0
episode: 1400 Evaluation Average Reward: 200.0
episode: 1500 Evaluation Average Reward: 200.0
episode: 1600 Evaluation Average Reward: 200.0
episode: 1700 Evaluation Average Reward: 200.0
episode: 1800 Evaluation Average Reward: 200.0
episode: 1900 Evaluation Average Reward: 200.0
episode: 2000 Evaluation Average Reward: 200.0
episode: 2100 Evaluation Average Reward: 200.0
episode: 2200 Evaluation Average Reward: 200.0
episode: 2300 Evaluation Average Reward: 200.0
episode: 2400 Evaluation Average Reward: 200.0
episode: 2500 Evaluation Average Reward: 200.0
episode: 2600 Evaluation Average Reward: 200.0
episode: 2700 Evaluation Average Reward: 200.0
episode: 2800 Evaluation Average Reward: 200.0
episode: 2900 Evaluation Average Reward: 200.0

    注意,由於DQN不保證穩定的收斂,所以每次跑的結果會不同,如果你跑的結果後面仍然收斂的不好,可以把程式碼多跑幾次,選擇一個最好的訓練結果。

5. Nature DQN總結

    Nature DQN對DQN NIPS 2013做了相關性方面的改進,這個改進雖然不錯,但是仍然沒有解決DQN的 很多問題,比如:

    1) 目標Q值的計算是否準確?全部通過max Q來計算有沒有問題?

    2) 隨機取樣的方法好嗎?按道理不同樣本的重要性是不一樣的。

    3) Q值代表狀態,動作的價值,那麼單獨動作價值的評估會不會更準確?

    第一個問題對應的改進是Double DQN, 第二個問題的改進是Prioritised Replay DQN,第三個問題的改進是Dueling DQN,這三個DQN的改進版我們在下一篇來討論。

 

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

相關文章