Tensorflow基础教程6:深度强化学习(DRL)
強化學習 (Reinforcement learning,RL)強調如何基于環境而行動,以取得最大化的預期利益。結合了深度學習技術后的強化學習(Deep Reinforcement learning,DRL)更是如虎添翼。近年廣為人知的 AlphaGo 即是深度強化學習的典型應用。
可參考強化學習基礎以獲得強化學習的基礎知識。
這里,我們使用深度強化學習玩 CartPole(倒立擺)游戲。倒立擺是控制論中的經典問題,在這個游戲中,一根桿的底部與一個小車通過軸相連,而桿的重心在軸之上,因此是一個不穩定的系統。在重力的作用下,桿很容易倒下。而我們則需要控制小車在水平的軌道上進行左右運動,以使得桿一直保持豎直平衡狀態。
CartPole 游戲
我們使用 OpenAI 推出的 Gym 環境庫 中的 CartPole 游戲環境,可使用 pip install gym 進行安裝,具體安裝步驟和教程可參考 官方文檔 和 這里 。和 Gym 的交互過程很像是一個回合制游戲,我們首先獲得游戲的初始狀態(比如桿的初始角度和小車位置),然后在每個回合 t,我們都需要在當前可行的動作中選擇一個并交由 Gym 執行(比如向左或者向右推動小車,每個回合中二者只能擇一),Gym 在執行動作后,會返回動作執行后的下一個狀態和當前回合所獲得的獎勵值(比如我們選擇向左推動小車并執行后,小車位置更加偏左,而桿的角度更加偏右,Gym 將新的角度和位置返回給我們。而如果桿在這一回合仍沒有倒下,Gym 同時返回給我們一個小的正獎勵)。這個過程可以一直迭代下去,直到游戲終止(比如桿倒下了)。
在 Python 中,Gym 的基本調用方法如下:
import gym
env = gym.make('CartPole-v1') # 實例化一個游戲環境,參數為游戲名稱
state = env.reset() # 初始化環境,獲得初始狀態
while True:
env.render() # 對當前幀進行渲染,繪圖到屏幕
action = model.predict(state) # 假設我們有一個訓練好的模型,能夠通過當前狀態預測出這時應該進行的動作
next_state, reward, done, info = env.step(action) # 讓環境執行動作,獲得執行完動作的下一個狀態,動作的獎勵,游戲是否已結束以及額外信息
if done: # 如果游戲結束則退出循環
break
那么,我們的任務就是訓練出一個模型,能夠根據當前的狀態預測出應該進行的一個好的動作。粗略地說,一個好的動作應當能夠最大化整個游戲過程中獲得的獎勵之和,這也是強化學習的目標。以 CartPole 游戲為例,我們的目標是希望做出合適的動作使得桿一直不倒,即游戲交互的回合數盡可能地多。而回合每進行一次,我們都會獲得一個小的正獎勵,回合數越多則累積的獎勵值也越高。因此,我們最大化游戲過程中的獎勵之和與我們的最終目標是一致的。
以下代碼展示了如何使用深度強化學習中的 Deep Q-Learning 方法 [Mnih2013] 來訓練模型。首先,我們引入 TensorFlow、Gym 和一些常用庫,并定義一些模型超參數:
import tensorflow as tf
import numpy as np
import gym
import random
from collections import deque
num_episodes = 500 # 游戲訓練的總episode數量
num_exploration_episodes = 100 # 探索過程所占的episode數量
max_len_episode = 1000 # 每個episode的最大回合數
batch_size = 32 # 批次大小
learning_rate = 1e-3 # 學習率
gamma = 1. # 折扣因子
initial_epsilon = 1. # 探索起始時的探索率
final_epsilon = 0.01 # 探索終止時的探索率
然后,我們使用 tf.keras.Model 建立一個 Q 函數網絡(Q-network),用于擬合 Q Learning 中的 Q 函數。這里我們使用較簡單的多層全連接神經網絡進行擬合。該網絡輸入當前狀態,輸出各個動作下的 Q-value(CartPole 下為 2 維,即向左和向右推動小車)。
class QNetwork(tf.keras.Model):
def __init__(self):
super().__init__()
self.dense1 = tf.keras.layers.Dense(units=24, activation=tf.nn.relu)
self.dense2 = tf.keras.layers.Dense(units=24, activation=tf.nn.relu)
self.dense3 = tf.keras.layers.Dense(units=2)
def call(self, inputs):
x = self.dense1(inputs)
x = self.dense2(x)
x = self.dense3(x)
return x
def predict(self, inputs):
q_values = self(inputs)
return tf.argmax(q_values, axis=-1)
最后,我們在主程序中實現 Q Learning 算法。
if __name__ == '__main__':
env = gym.make('CartPole-v1') # 實例化一個游戲環境,參數為游戲名稱
model = QNetwork()
optimizer = tf.keras.optimizers.Adam(learning_rate=learning_rate)
replay_buffer = deque(maxlen=10000) # 使用一個 deque 作為 Q Learning 的經驗回放池
epsilon = initial_epsilon
for episode_id in range(num_episodes):
state = env.reset() # 初始化環境,獲得初始狀態
epsilon = max( # 計算當前探索率
initial_epsilon * (num_exploration_episodes - episode_id) / num_exploration_episodes,
final_epsilon)
for t in range(max_len_episode):
env.render() # 對當前幀進行渲染,繪圖到屏幕
if random.random() < epsilon: # epsilon-greedy 探索策略,以 epsilon 的概率選擇隨機動作
action = env.action_space.sample() # 選擇隨機動作(探索)
else:
action = model.predict(np.expand_dims(state, axis=0)).numpy() # 選擇模型計算出的 Q Value 最大的動作
action = action[0]
# 讓環境執行動作,獲得執行完動作的下一個狀態,動作的獎勵,游戲是否已結束以及額外信息
next_state, reward, done, info = env.step(action)
# 如果游戲Game Over,給予大的負獎勵
reward = -10. if done else reward
# 將(state, action, reward, next_state)的四元組(外加 done 標簽表示是否結束)放入經驗回放池
replay_buffer.append((state, action, reward, next_state, 1 if done else 0))
# 更新當前 state大連專業人流醫院 http://www.dlrlyy.net/
state = next_state
if done: # 游戲結束則退出本輪循環,進行下一個 episode
print("episode %d, epsilon %f, score %d" % (episode_id, epsilon, t))
break
if len(replay_buffer) >= batch_size:
# 從經驗回放池中隨機取一個批次的四元組,并分別轉換為 NumPy 數組
batch_state, batch_action, batch_reward, batch_next_state, batch_done = zip(
*random.sample(replay_buffer, batch_size))
batch_state, batch_reward, batch_next_state, batch_done =
[np.array(a, dtype=np.float32) for a in [batch_state, batch_reward, batch_next_state, batch_done]]
batch_action = np.array(batch_action, dtype=np.int32)
q_value = model(batch_next_state)
y = batch_reward + (gamma * tf.reduce_max(q_value, axis=1)) * (1 - batch_done) # 計算 y 值
with tf.GradientTape() as tape:
loss = tf.keras.losses.mean_squared_error( # 最小化 y 和 Q-value 的距離
y_true=y,
y_pred=tf.reduce_sum(model(batch_state) * tf.one_hot(batch_action, depth=2), axis=1)
)
grads = tape.gradient(loss, model.variables)
optimizer.apply_gradients(grads_and_vars=zip(grads, model.variables)) # 計算梯度并更新參數
對于不同的任務(或者說環境),我們需要根據任務的特點,設計不同的狀態以及采取合適的網絡來擬合 Q 函數。例如,如果我們考慮經典的打磚塊游戲(Gym 環境庫中的 Breakout-v0 ),每一次執行動作(擋板向左、向右或不動),都會返回一個 210 * 160 * 3 的 RGB 圖片,表示當前屏幕畫面。為了給打磚塊游戲這個任務設計合適的狀態表示,我們有以下分析:
磚塊的顏色信息并不是很重要,畫面轉換成灰度也不影響操作,因此可以去除狀態中的顏色信息(即將圖片轉為灰度表示);
小球移動的信息很重要,如果只知道單幀畫面而不知道小球往哪邊運動,即使是人也很難判斷擋板應當移動的方向。因此,必須在狀態中加入表征小球運動方向的信息。一個簡單的方式是將當前幀與前面幾幀的畫面進行疊加,得到一個 210 * 160 * X (X 為疊加幀數)的狀態表示;
每幀的分辨率不需要特別高,只要能大致表征方塊、小球和擋板的位置以做出決策即可,因此對于每幀的長寬可做適當壓縮。
而考慮到我們需要從圖像信息中提取特征,使用 CNN 作為擬合 Q 函數的網絡將更為適合。由此,將上面的 QNetwork 更換為 CNN 網絡,并對狀態做一些修改,即可用于玩一些簡單的視頻游戲。
總結
以上是生活随笔為你收集整理的Tensorflow基础教程6:深度强化学习(DRL)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 家庭wifi,如何组网最合适
- 下一篇: 三个路由器如何设置三个路由器如何加备用路