Deep Deterministic Policy Gradient簡稱DDPG。它是在DPG的基礎上,爲了提升神經網絡的穩定性,而參考DQN的實現方式提出的。DDPG創建兩個網絡,一個target網絡,一個eval網絡,同時使用經驗回放機制。Deep,其含義主要就是使用經驗池和雙網絡結構來促進神經網絡可以有效學習。git
雙網絡結構的網絡參數是每隔必定間隔時間從eval網絡複製到target網絡的。傳統的DQN一般採用的是一種被稱爲'hard'模式的target-net網絡參數更新,即每隔必定的步數就將eval-net中的網絡參數賦值過去,而在DDPG中,能夠採用另外一種'soft'模式的target-net網絡參數更新,即每一步都對target-net網絡中的參數更新一點點,這種參數更新方式通過試驗代表能夠大大的提升學習的穩定性。github
DDPG主要的關鍵點有如下幾個:算法
DDPG對actor不直接計算損失而是使用criric對actor的損失,能夠這樣理解:actor的目的是儘可能獲得一個高Q值的action,所以actor的損失能夠簡單的理解爲獲得的反饋Q值越大損失越小,獲得的反饋Q值越小損失越大。數組
actor(θ)中action對參數的梯度爲da/dθ,critic中Q對action的梯度dq/da,最後獲得的Q值對actor(θ)的梯度公式就爲-(dq/da * da/dθ)(負數的緣由是優化器的方向爲最小化loss而咱們的目的是最大化Q值)網絡
DDPG代碼能夠參考https://github.com/MorvanZhou/Reinforcement-learning-with-tensorflow/blob/master/contents/9_Deep_Deterministic_Policy_Gradient_DDPG/DDPG.py的實現。 dom
一、定義超參數函數
咱們首先定義網絡中的超參數,好比經驗池的大小,兩個網絡的學習率等等:學習
MAX_EPISODES = 200 MAX_EP_STEPS = 200 LR_A = 0.001 # learning rate for actor LR_C = 0.002 # learning rate for critic GAMMA = 0.9 # reward discount TAU = 0.01 # soft replacement MEMORY_CAPACITY = 10000 BATCH_SIZE = 32 RENDER = False ENV_NAME = 'Pendulum-v0'
二、定義網絡輸入優化
咱們須要定義的placeholder包括當前的狀態S,下一時刻的狀態S',以及對應的獎勵R,而動做A由Actor獲得,所以不須要再定義:ui
self.S = tf.placeholder(tf.float32, [None, s_dim], 's') self.S_ = tf.placeholder(tf.float32, [None, s_dim], 's_') self.R = tf.placeholder(tf.float32, [None, 1], 'r')
三、構建兩個網絡
兩個網絡都是兩層全連接的神經網絡,Actor輸出一個具體的動做,而Critic網絡輸出一個具體的Q值
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)
四、soft模式參數更新
能夠看到,咱們這裏進行的是soft模式的參數更新,每次在原來target-net參數的基礎上,改變一丟丟,增長一點點eval-net的參數信息。
# networks parameters self.ae_params = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope='Actor/eval') self.at_params = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope='Actor/target') self.ce_params = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope='Critic/eval') self.ct_params = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope='Critic/target') # target net replacement self.soft_replace = [[tf.assign(ta, (1 - TAU) * ta + TAU * ea), tf.assign(tc, (1 - TAU) * tc + TAU * ec)] for ta, ea, tc, ec in zip(self.at_params, self.ae_params, self.ct_params, self.ce_params)]
五、定義兩個網絡的損失
actor network的更新也很簡單,首先咱們須要critic network對動做a的導數,其中a是由actor network根據狀態s估計出來的。
先根據actor network估計出action,再用critic network的輸出q對估計出來的action求導。
而後咱們把獲得的這部分梯度,和actor network的輸出對actor network的權重求導的梯度,相乘就能獲得最後的梯度
關於兩個網絡的損失,咱們以前已經詳細介紹過了,這裏只是對剛纔思路的一個代碼實現。
q_target = self.R + GAMMA * q_ # in the feed_dic for the td_error, the self.a should change to actions in memory 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)
六、學習
咱們首先要從經驗池中取出一個batch的數據,而後訓練咱們的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_})
七、存儲經驗
將s,a,r,s_存儲到內存數組。
def store_transition(self, s, a, r, s_): transition = np.hstack((s, a, [r], s_)) index = self.pointer % MEMORY_CAPACITY # replace the old memory with new memory self.memory[index, :] = transition