實用深度強化學習實現技術
強化學習(RL)是一種通過智能體與環境交互來學習最優決策的機器學習范式。而深度強化學習(DRL)則將深度學習技術引入RL領域,利用深度神經網絡強大的函數擬合能力來處理高維觀察空間,取得了顯著的成功。本章我們將重點介紹一種經典的DRL算法:Q-Learning及其變體,探討其背后的原理、實現技巧以及代表性應用。
1. 價值函數與Q-Learning原理
在介紹Q-Learning之前,我們先來回顧一下強化學習中的一些基本概念。
1.1 馬爾可夫決策過程
馬爾可夫決策過程(MDP)提供了一個標準的RL問題數學框架。一個MDP由一個五元組 M = ? S , A , P , R , γ ? \mathcal{M}=\langle\mathcal{S},\mathcal{A},\mathcal{P},\mathcal{R},\gamma\rangle M=?S,A,P,R,γ? 定義,其中:
- 狀態空間 S \mathcal{S} S:表示智能體所處的環境狀態集合。
- 動作空間 A \mathcal{A} A:表示智能體可采取的動作集合。
- 轉移概率 P \mathcal{P} P: P ( s ′ ∣ s , a ) \mathcal{P}(s'|s,a) P(s′∣s,a) 表示在狀態 s s s 下執行動作 a a a 后轉移到狀態 s ′ s' s′ 的概率。
- 獎勵函數 R \mathcal{R} R: R ( s , a ) \mathcal{R}(s,a) R(s,a) 表示在狀態 s s s 下執行動作 a a a 后獲得的即時獎勵。
- 折扣因子 γ ∈ [ 0 , 1 ] \gamma\in[0,1] γ∈[0,1]:表示未來獎勵的折現程度,用于平衡即時獎勵和長期獎勵。
MDP的目標是尋找一個最優策略 π ? : S → A \pi^*:\mathcal{S}\rightarrow\mathcal{A} π?:S→A,使得智能體遵循該策略能獲得最大的累積獎勵:
π ? = arg ? max ? π E π [ ∑ t = 0 ∞ γ t r t ] \pi^* = \arg\max_{\pi} \mathbb{E}_{\pi}[\sum_{t=0}^{\infty} \gamma^t r_t] π?=argπmax?Eπ?[t=0∑∞?γtrt?]
其中 r t r_t rt? 表示在時刻 t t t 獲得的獎勵。
1.2 價值函數
為了評估一個狀態或者一個狀態-動作對的好壞,我們引入了價值函數的概念。在給定策略 π \pi π 的情況下,有兩種常見的價值函數定義:
-
狀態價值函數 V π ( s ) V^{\pi}(s) Vπ(s): 表示從狀態 s s s 開始,遵循策略 π \pi π 能獲得的期望累積獎勵。
V π ( s ) = E π [ ∑ k = 0 ∞ γ k r t + k ∣ s t = s ] V^{\pi}(s)=\mathbb{E}_{\pi}[\sum_{k=0}^{\infty}\gamma^k r_{t+k}|s_t=s] Vπ(s)=Eπ?[k=0∑∞?γkrt+k?∣st?=s] -
動作價值函數 Q π ( s , a ) Q^{\pi}(s,a) Qπ(s,a): 表示在狀態 s s s 下采取動作 a a a,并繼續遵循策略 π \pi π 能獲得的期望累積獎勵。
Q π ( s , a ) = E π [ ∑ k = 0 ∞ γ k r t + k ∣ s t = s , a t = a ] Q^{\pi}(s,a)=\mathbb{E}_{\pi}[\sum_{k=0}^{\infty}\gamma^k r_{t+k}|s_t=s,a_t=a] Qπ(s,a)=Eπ?[k=0∑∞?γkrt+k?∣st?=s,at?=a]
兩個價值函數之間滿足如下關系:
V π ( s ) = ∑ a ∈ A π ( a ∣ s ) Q π ( s , a ) V^{\pi}(s) = \sum_{a\in\mathcal{A}} \pi(a|s) Q^{\pi}(s,a) Vπ(s)=a∈A∑?π(a∣s)Qπ(s,a)
對于最優策略 π ? \pi^* π?,對應的狀態價值函數 V ? V^* V? 和動作價值函數 Q ? Q^* Q? 滿足貝爾曼最優方程:
V ? ( s ) = max ? a ∈ A Q ? ( s , a ) Q ? ( s , a ) = R ( s , a ) + γ ∑ s ′ ∈ S P ( s ′ ∣ s , a ) V ? ( s ′ ) = R ( s , a ) + γ ∑ s ′ ∈ S P ( s ′ ∣ s , a ) max ? a ′ ∈ A Q ? ( s ′ , a ′ ) \begin{aligned} V^*(s) &= \max_{a\in\mathcal{A}} Q^*(s,a) \\ Q^*(s,a) &= \mathcal{R}(s,a) + \gamma \sum_{s'\in\mathcal{S}} \mathcal{P}(s'|s,a) V^*(s')\\ &= \mathcal{R}(s,a) + \gamma \sum_{s'\in\mathcal{S}} \mathcal{P}(s'|s,a) \max_{a'\in\mathcal{A}} Q^*(s',a') \end{aligned} V?(s)Q?(s,a)?=a∈Amax?Q?(s,a)=R(s,a)+γs′∈S∑?P(s′∣s,a)V?(s′)=R(s,a)+γs′∈S∑?P(s′∣s,a)a′∈Amax?Q?(s′,a′)?
這兩個方程揭示了最優價值函數的遞歸結構,為我們后續推導Q-Learning算法奠定了理論基礎。如果我們能準確估計出 Q ? ( s , a ) Q^*(s,a) Q?(s,a),那么最優策略可以通過貪心法(greedy)直接得到:
π ? ( s ) = arg ? max ? a ∈ A Q ? ( s , a ) \pi^*(s) = \arg\max_{a\in\mathcal{A}} Q^*(s,a) π?(s)=arga∈Amax?Q?(s,a)
1.3 Q-Learning算法
Q-Learning是一種經典的值迭代(value iteration)算法,它直接估計最優動作價值函數 Q ? ( s , a ) Q^*(s,a) Q?(s,a),然后根據 Q ? Q^* Q? 得到最優策略。
傳統的Q-Learning使用一個表格(Q-table)來存儲每個狀態-動作對的Q值估計。初始時 Q ( s , a ) Q(s,a) Q(s,a) 可以被隨機初始化。在與環境交互的每個時間步,智能體根據當前的Q值貪心地選擇動作 a t a_t at?,觀察到獎勵 r t r_t rt? 和下一個狀態 s t + 1 s_{t+1} st+1?,然后通過如下的時序差分(TD)更新來優化Q值:
Q ( s t , a t ) ← Q ( s t , a t ) + α [ r t + γ max ? a Q ( s t + 1 , a ) ? Q ( s t , a t ) ] Q(s_t,a_t) \leftarrow Q(s_t,a_t) + \alpha[r_t + \gamma \max_{a} Q(s_{t+1},a) - Q(s_t,a_t)] Q(st?,at?)←Q(st?,at?)+α[rt?+γamax?Q(st+1?,a)?Q(st?,at?)]
其中 α ∈ ( 0 , 1 ] \alpha\in(0,1] α∈(0,1] 為學習率。這個更新過程可以被解釋為:用 r t + γ max ? a Q ( s t + 1 , a ) r_t + \gamma \max_{a} Q(s_{t+1},a) rt?+γmaxa?Q(st+1?,a) 作為 Q ( s t , a t ) Q(s_t,a_t) Q(st?,at?) 的目標值進行監督學習,使得 Q ( s t , a t ) Q(s_t,a_t) Q(st?,at?) 逼近它的真實值 Q ? ( s t , a t ) Q^*(s_t,a_t) Q?(st?,at?)。可以證明,在適當的條件下,Q-Learning最終會收斂到 Q ? Q^* Q?。
然而,當狀態空間和動作空間很大時,用表格存儲Q值是不現實的。這時,我們可以用一個參數化的函數 Q θ ( s , a ) Q_{\theta}(s,a) Qθ?(s,a) 來近似Q值,其中 θ \theta θ 為函數的參數。近年來,隨著深度學習的興起,使用深度神經網絡(DNN)作為Q函數的近似器得到了廣泛應用,這就是著名的DQN算法。
2. 深度Q網絡(DQN)
深度Q網絡(DQN)由[Mnih et al., 2013]提出,是將Q-Learning與深度學習結合的代表性算法。它使用一個卷積神經網絡(CNN)來擬合Q函數,并引入了兩個重要的技巧:經驗回放(experience replay)和目標網絡(target network),極大地提升了訓練的穩定性。
2.1 Q網絡結構
在DQN中,Q函數 Q θ ( s , a ) Q_{\theta}(s,a) Qθ?(s,a) 被參數化為一個CNN,它以狀態 s s s (通常是原始像素)為輸入,輸出各個動作 a a a 對應的Q值。Q網絡可以表示為:
Q θ ( s , ? ) = f θ ( s ) ∈ R ∣ A ∣ Q_{\theta}(s,\cdot) = f_{\theta}(s) \in \mathbb{R}^{|\mathcal{A}|} Qθ?(s,?)=fθ?(s)∈R∣A∣
其中 f θ f_{\theta} fθ? 為CNN的前向傳播函數。在實踐中,Q網絡的具體結構需要根據任務的特點來設計。
Q網絡的訓練目標是最小化TD誤差,即讓 Q θ ( s , a ) Q_{\theta}(s,a) Qθ?(s,a) 盡可能逼近貝爾曼最優方程的右側:
L ( θ ) = E ( s , a , r , s ′ ) ~ D [ ( r + γ max ? a ′ Q θ ? ( s ′ , a ′ ) ? Q θ ( s , a ) ) 2 ] \mathcal{L}(\theta) = \mathbb{E}_{(s,a,r,s')\sim \mathcal{D}} \left[ (r + \gamma \max_{a'} Q_{\theta^-}(s',a') - Q_{\theta}(s,a))^2 \right] L(θ)=E(s,a,r,s′)~D?[(r+γa′max?Qθ??(s′,a′)?Qθ?(s,a))2]
其中 D \mathcal{D} D 為經驗回放池, θ ? \theta^- θ? 為目標網絡的參數。接下來我們詳細介紹這兩個技巧。
2.2 經驗回放(Experience Replay)
在Q-Learning中,我們通常假設訓練數據 ( s , a , r , s ′ ) (s,a,r,s') (s,a,r,s′) 是獨立同分布的。但在實際的在線學習中,智能體往往是連續與環境交互的,產生一個狀態序列 { s 1 , s 2 , ? , s t , ? } \{s_1,s_2,\cdots,s_t,\cdots\} {s1?,s2?,?,st?,?},相鄰的狀態之間具有很強的相關性。如果直接用序列數據訓練神經網絡,會導致訓練過程不穩定,難以收斂。
經驗回放(ER)通過構建一個 經驗回放池 D \mathcal{D} D 來打破數據之間的相關性。具體來說,在每個時間步 t t t,智能體將當前的轉移樣本 ( s t , a t , r t , s t + 1 ) (s_t,a_t,r_t,s_{t+1}) (st?,at?,rt?,st+1?) 存入 D \mathcal{D} D。訓練時,從 D \mathcal{D} D 中隨機采樣一個批量(batch)的樣本來更新Q網絡參數。這個過程類似于監督學習,可以使用標準的優化算法如SGD、Adam等。
ER的優勢包括:
- 打破了樣本之間的相關性,使訓練更穩定。
- 樣本可以被多次使用,提高數據利用效率。
- 可以使用off-policy數據,如專家示范數據、歷史版本策略的數據等。
在實現中,經驗回放池 D \mathcal{D} D 通常被實現為一個固定大小的循環隊列。當 D \mathcal{D} D 被填滿時,新的樣本會覆蓋最老的樣本。一個常見的技巧是在初始探索階段,先不更新策略,只往 D \mathcal{D} D 中填充數據,直到收集到足夠的樣本才開始訓練。
2.3 目標網絡(Target Network)
Q-Learning本質上是一個回歸問題,即用 r + γ max ? a ′ Q θ ( s ′ , a ′ ) r + \gamma \max_{a'} Q_{\theta}(s',a') r+γmaxa′?Qθ?(s′,a′) 作為Q值 Q θ ( s , a ) Q_{\theta}(s,a) Qθ?(s,a) 的目標值。然而在DQN中,目標值本身也在隨著參數 θ \theta θ 的更新而變化,這就引入了一個不穩定的"移動目標"問題。
為了緩解這個問題,DQN引入了一個目標網絡 Q θ ? Q_{\theta^-} Qθ??,它的結構與Q網絡相同,但參數更新頻率較低。在計算TD目標值時使用目標網絡的輸出:
y = r + γ max ? a ′ Q θ ? ( s ′ , a ′ ) y = r + \gamma \max_{a'} Q_{\theta^-}(s',a') y=r+γa′max?Qθ??(s′,a′)
這使得目標值在一段時間內保持不變,類似于監督學習。目標網絡的參數 θ ? \theta^- θ? 每隔一定的時間步(如1000步)從Q網絡復制一次:
θ ? ← θ \theta^- \leftarrow \theta θ?←θ
或者采用軟更新的方式:
θ ? ← τ θ + ( 1 ? τ ) θ ? , τ ? 1 \theta^- \leftarrow \tau \theta + (1-\tau) \theta^-, \quad \tau \ll 1 θ?←τθ+(1?τ)θ?,τ?1
目標網絡的引入極大地提升了DQN的性能,成為了許多DRL算法的標準配置。
2.4 DQN算法
結合經驗回放和目標網絡,DQN的完整算法描述如下:
算法 DQN
初始化Q網絡參數 θ \theta θ, 目標網絡參數 θ ? ← θ \theta^- \leftarrow \theta θ?←θ
初始化經驗回放池 D \mathcal{D} D
for episode = 1 to M do:
初始化初始狀態 s 1 s_1 s1?
for t = 1 to T do:
根據 ? -greedy \epsilon\text{-greedy} ?-greedy 策略選擇動作 a t = { arg ? max ? a Q θ ( s t , a ) , with?prob.? 1 ? ? random?action , with?prob.? ? a_t=\begin{cases} \arg\max_a Q_{\theta}(s_t,a), & \text{with prob. } 1-\epsilon \\ \text{random action}, & \text{with prob. } \epsilon \end{cases} at?={argmaxa?Qθ?(st?,a),random?action,?with?prob.?1??with?prob.???
執行動作 a t a_t at?,觀察獎勵 r t r_t rt? 和下一狀態 s t + 1 s_{t+1} st+1?
將樣本 ( s t , a t , r t , s t + 1 ) (s_t,a_t,r_t,s_{t+1}) (st?,at?,rt?,st+1?) 存入 D \mathcal{D} D
從 D \mathcal{D} D 中隨機采樣一個批量的樣本 ( s , a , r , s ′ ) (s,a,r,s') (s,a,r,s′)
計算TD目標: y = { r , if? s ′ is?terminal r + γ max ? a ′ Q θ ? ( s ′ , a ′ ) , otherwise y=\begin{cases} r, & \text{if } s' \text{ is terminal}\\ r + \gamma \max_{a'} Q_{\theta^-}(s',a'), & \text{otherwise} \end{cases} y={r,r+γmaxa′?Qθ??(s′,a′),?if?s′?is?terminalotherwise?
最小化TD誤差: L ( θ ) = 1 N ∑ ( y ? Q θ ( s , a ) ) 2 \mathcal{L}(\theta)=\frac{1}{N}\sum(y-Q_{\theta}(s,a))^2 L(θ)=N1?∑(y?Qθ?(s,a))2
每隔C步更新目標網絡: θ ? ← θ \theta^- \leftarrow \theta θ?←θ
end for
end for
其中,超參數包括:
- M M M: 訓練的episode數
- T T T: 每個episode的最大時間步
- ? \epsilon ?: ? -greedy \epsilon\text{-greedy} ?-greedy 探索中選擇隨機動作的概率
- γ \gamma γ: 獎勵折扣因子
- C C C: 目標網絡更新頻率
- N N N: 批量大小(batch size)
DQN在Atari游戲上取得了超越人類的表現,證明了端到端深度強化學習的有效性,掀起了DRL研究的高潮。此后,各種DQN的改進變體不斷涌現,極大地推動了DRL技術的發展。
3. DQN變體與改進
盡管DQN取得了巨大成功,但它仍然存在一些問題,如過估計(overestimation)、采樣效率低、探索不足等。研究者針對這些問題提出了許多改進方法。本節我們介紹幾個代表性的DQN變體算法。
3.1 Double DQN
Q-Learning算法(包括DQN)存在一個固有的過估計問題。在計算TD目標值時,我們用 max ? a ′ Q ( s ′ , a ′ ) \max_{a'} Q(s',a') maxa′?Q(s′,a′) 來估計 max ? a ′ q ? ( s ′ , a ′ ) \max_{a'} q_*(s',a') maxa′?q??(s′,a′) ( q ? q_* q?? 表示真實的Q值)。然而,由于對 Q ( s ′ , a ′ ) Q(s',a') Q(s′,a′) 估計的誤差,這個最大化操作會導致Q值的過估計,使得學到的策略次優。
Double DQN(DDQN) [Van Hasselt et al., 2016]通過解耦動作選擇和動作評估來緩解過估計問題。具體來說,DDQN維護兩個Q網絡 Q θ 1 Q_{\theta_1} Qθ1?? 和 Q θ 2 Q_{\theta_2} Qθ2??,它們獨立學習、互為目標網絡。在計算TD目標時,一個網絡負責選擇動作,另一個網絡負責評估動作的值:
a ? = arg ? max ? a ′ Q θ 1 ( s ′ , a ′ ) y = r + γ Q θ 2 ( s ′ , a ? ) \begin{aligned} a^* &= \arg\max_{a'} Q_{\theta_1}(s',a') \\ y &= r + \gamma Q_{\theta_2}(s',a^*) \end{aligned} a?y?=arga′max?Qθ1??(s′,a′)=r+γQθ2??(s′,a?)?
這里動作選擇和評估使用了不同的Q網絡,從而減少了過估計。DDQN在Atari游戲上的表現優于DQN,成為了DRL領域的標配技術之一。
3.2 Prioritized Experience Replay
傳統的經驗回放對回放池 D \mathcal{D} D 中的樣本一視同仁,uniformly隨機采樣。然而直覺上,有些樣本可能比其他樣本更"重要",值得被多次采樣學習。
Prioritized Experience Replay(PER)[Schaul et al., 2016]基于這個想法,根據樣本的TD誤差來衡量其重要性,對 D \mathcal{D} D 中的樣本賦予不同的采樣概率。給定一個樣本 ( s , a , r , s ′ ) (s,a,r,s') (s,a,r,s′), 它的優先級定義為:
p = ∣ δ ∣ + ? p = |\delta| + \epsilon p=∣δ∣+?
其中 δ = r + γ max ? a ′ Q θ ? ( s ′ , a ′ ) ? Q θ ( s , a ) \delta=r+\gamma \max_{a'}Q_{\theta^-}(s',a')-Q_{\theta}(s,a) δ=r+γmaxa′?Qθ??(s′,a′)?Qθ?(s,a) 為TD誤差, ? \epsilon ? 是一個小的正常數,以確保每個樣本都有被采樣的可能。采樣概率正比于優先級:
P ( i ) = p i α ∑ j p j α P(i) = \frac{p_i^{\alpha}}{\sum_j p_j^{\alpha}} P(i)=∑j?pjα?piα??
其中 α \alpha α 控制了優先級的強度。當 α = 0 \alpha=0 α=0 時退化為uniform采樣。
為了校正優先級采樣引入的偏差,PER在更新Q網絡時對不同樣本引入了重要性權重(importance weight):
w i = ( 1 N ? 1 P ( i ) ) β w_i = (\frac{1}{N} \cdot \frac{1}{P(i)})^{\beta} wi?=(N1??P(i)1?)β
最小化加權的TD誤差:
L ( θ ) = 1 N ∑ w i ? ( y i ? Q θ ( s i , a i ) ) 2 \mathcal{L}(\theta) = \frac{1}{N}\sum w_i \cdot (y_i-Q_{\theta}(s_i,a_i))^2 L(θ)=N1?∑wi??(yi??Qθ?(si?,ai?))2
其中 β \beta β 控制了重要性權重的強度,從初始值 β 0 \beta_0 β0? 線性增加到1。
PER能更有效地利用樣本,在許多游戲上取得了sota的表現。此外它是一個通用的技術,可以和其他DRL算法結合,如DDQN、Dueling DQN等。
3.3 Dueling DQN
在許多RL任務中,狀態價值 V ( s ) V(s) V(s) 和狀態-動作價值 Q ( s , a ) Q(s,a) Q(s,a) 都包含有用的信息。標準的DQN只學習 Q ( s , a ) Q(s,a) Q(s,a),忽略了 V ( s ) V(s) V(s)。
Dueling DQN[Wang et al., 2016]通過將Q網絡分解為兩個流來顯式地學習 V ( s ) V(s) V(s) 和 A ( s , a ) A(s,a) A(s,a):
Q ( s , a ) = V ( s ) + A ( s , a ) Q(s,a) = V(s) + A(s,a) Q(s,a)=V(s)+A(s,a)
其中 V ( s ) V(s) V(s) 表示狀態價值, A ( s , a ) = Q ( s , a ) ? V ( s ) A(s,a)=Q(s,a)-V(s) A(s,a)=Q(s,a)?V(s) 稱為優勢函數(advantage function),表示動作 a a a 相對于狀態平均的優劣程度。網絡包含一個共享的卷積層,然后分為兩個獨立的全連接層,分別輸出 V ( s ) V(s) V(s) 和 A ( s , a ) A(s,a) A(s,a),最后組合成Q值。
實踐中為了保持恒等性,使用如下的組合方式:
Q ( s , a ) = V ( s ) + ( A ( s , a ) ? max ? a ′ A ( s , a ′ ) ) Q(s,a) = V(s) + (A(s,a)-\max_{a'} A(s,a')) Q(s,a)=V(s)+(A(s,a)?a′max?A(s,a′))
Dueling DQN在Atari游戲中有超過一半的任務上取得了優于DQN的表現。它也可以跟其他技術結合,如DDQN、PER等。
3.4 其他改進
除了上述經典變體,DQN還有許多其他的改進方法,如:
- Multi-step learning: 使用多步回報 ∑ k = 0 n γ k r t + k + γ n max ? a ′ Q θ ? ( s t + n , a ′ ) \sum_{k=0}^{n} \gamma^k r_{t+k} + \gamma^n \max_{a'}Q_{\theta^-}(s_{t+n},a') ∑k=0n?γkrt+k?+γnmaxa′?Qθ??(st+n?,a′) 作為目標值,權衡bias和variance。
- Distributional DQN: 學習值分布 Z ( s , a ) Z(s,a) Z(s,a) 而不是期望 Q ( s , a ) Q(s,a) Q(s,a),捕捉環境的隨機性。
- Noisy DQN: 在Q網絡中加入參數噪聲,自適應地調節探索。
- Rainbow: 將DDQN、PER、Dueling、Multi-step、Distributional、Noisy結合在統一的框架下。
這些改進極大地提升了Q學習的性能,推動了DRL在游戲、機器人、自然語言等領域的應用。但Q學習仍然有其局限性,如采樣效率不高、難以適用于連續動作空間等。為此,研究者探索了策略梯度、actor-critic等其他類型的DRL算法。
4. 從Atari到AlphaGo
DQN在Atari游戲中的成功彰顯了深度強化學習的威力,掀起了將DRL應用于各種領域的浪潮。本節我們簡要回顧幾個里程碑式的工作。
4.1 Atari Games
Atari 2600是一款經典的游戲機,包含數十個游戲。[Bellemare et al., 2013]基于這些游戲構建了Arcade Learning Environment(ALE),將其作為RL算法的測試平臺。玩家通過原始像素感知游戲狀態,用操縱桿控制角色的行動。
DQN首次在ALE上實現了超越人類的表現[Mnih et al., 2015],之后各種DQN改進算法紛紛在ALE上刷新紀錄[Hessel et al., 2018]。Atari游戲具有復雜的狀態空間和稀疏的獎勵信號,對探索提出了挑戰,因此成為了DRL算法的標準測試任務。
4.2 AlphaGo
圍棋是一種古老的棋類游戲,狀態空間和動作空間極其龐大,被認為是人工智能的巔峰挑戰。DeepMind提出的AlphaGo系列算法[Silver et al., 2016, 2017, 2018]將深度學習與蒙特卡洛樹搜索相結合,在圍棋上成功擊敗了人類頂尖高手。
AlphaGo使用深度卷積網絡來逼近策略網絡 p σ ( a ∣ s ) p_{\sigma}(a|s) pσ?(a∣s) 和價值網絡 v θ ( s ) v_{\theta}(s) vθ?(s),并用它們指導樹搜索,不斷完善估值和走法選擇。策略網絡通過監督學習人類專家棋譜和自對弈數據來訓練,價值網絡則類似DQN用TD learning來訓練。
AlphaGo證明了DRL可以在超大規模問題上取得成功,揭示了深度學習、強化學習、樹搜索、領域知識相結合的威力,被譽為人工智能發展的里程碑。
小結
我們深入探討了DRL中的Q學習方法,重點介紹了DQN及其變體。Q學習通過值迭代來逼近最優Q函數,再用Q函數生成最優策略,是一種簡潔有效的RL算法。DQN利用深度卷積網絡來泛化Q學習,并引入了經驗回放、目標網絡等技術來提高訓練穩定性。此后,各種改進技術如Double DQN、Prioritized replay、Dueling network等進一步提升了DQN的性能。
5. Q-Learning在連續控制中的應用
之前我們主要討論了Q-Learning在離散動作空間中的應用,如Atari游戲。但在實際應用如機器人控制中,動作空間往往是連續的。為了將Q-Learning擴展到連續動作空間,一個簡單的方法是將動作空間離散化。然而這會帶來維度災難,限制了策略的表達能力。
QT-Opt[Kalashnikov et al., 2018]提出一種適用于連續動作空間的Q-Learning變體,并將其應用于機器人抓取任務。QT-Opt用一個Q網絡 Q θ ( s , a ) Q_{\theta}(s,a) Qθ?(s,a) 來擬合Q值,其中狀態 s s s 為機器人攝像頭拍攝的RGB圖像,動作 a a a 為抓取位置在相機坐標系下的平移和轉動參數。
5.1 任務建模
QT-Opt將機器人抓取建模為一個MDP:
- 狀態 s s s: 俯視RGB相機圖像,不包括深度信息
- 動作 a a a: 末端執行器的4-DoF變換(3個平移自由度+1個轉動自由度)
- 獎勵 r r r: 如果目標物體被成功抓起,給予+1的稀疏獎勵,否則為0。成功的判定通過檢測物體是否離開桌面來自動完成。
- 折扣因子 γ \gamma γ: 令為1,只關注最終的抓取效果
在這個MDP中,狀態與真實環境存在偏差(沒有深度信息),獎勵函數也是稀疏的。這對Q-Learning算法提出了挑戰。
5.2 連續動作空間優化
QT-Opt使用Cross-Entropy Method(CEM)來處理連續動作空間上的優化問題。CEM是一種基于采樣的黑箱優化算法:
- 從一個高斯分布 N ( μ , Σ ) \mathcal{N}(\mu,\Sigma) N(μ,Σ) 中采樣N個動作 { a i } i = 1 N \{a_i\}_{i=1}^N {ai?}i=1N?
- 用Q網絡評估這些動作的Q值 { Q θ ( s , a i ) } i = 1 N \{Q_{\theta}(s,a_i)\}_{i=1}^N {Qθ?(s,ai?)}i=1N?
- 選出Q值最高的前K個動作,用它們更新高斯分布的均值和協方差
- 重復步驟1-3直到高斯分布收斂
CEM通過迭代優化一個采樣分布來逼近最優動作:
a ? ( s ) = arg ? max ? a Q θ ( s , a ) ≈ arg ? max ? a N ( μ ? , Σ ? ∣ μ ? , Σ ? ) a^*(s) = \arg\max_a Q_{\theta}(s,a) \approx \arg\max_a \mathcal{N}(\mu^*,\Sigma^*|\mu^*,\Sigma^*) a?(s)=argamax?Qθ?(s,a)≈argamax?N(μ?,Σ?∣μ?,Σ?)
相比隨機采樣,CEM能更有效地集中在高Q值區域進行采樣。QT-Opt將CEM嵌入到Q-Learning的訓練循環中,交替地更新Q網絡和最優化動作分布。
5.3 海量離線數據
QT-Opt充分利用了仿真和真實環境中收集的海量離線數據。這些數據來自之前的各種抓取策略,質量參差不齊。QT-Opt將所有數據匯總到一個巨大的離線經驗池中,供Q網絡訓練。
離線數據的優勢在于:
- 提高樣本利用效率,減少真實環境交互
- 匯聚多種策略探索出的數據,增加樣本多樣性
- 在仿真環境中預訓練,減少真實環境的磨合成本
QT-Opt表明,即使在沒有在線探索的情況下,也可以從大規模離線數據中學到一個魯棒的抓取策略。
5.4 實驗結果
QT-Opt在7個Kuka機械臂上進行了抓取實驗,總計收集了58萬次抓取樣本,其中48萬次來自仿真,10萬次來自真實機器人。所有樣本被匯總到一個離線經驗池中用于訓練。
測試時,QT-Opt在48個陌生物體上的平均成功率達到96%,超過了人類專家的表現。大規模的仿真和真實數據結合DRL算法,使得端到端地從視覺信息中學習抓取控制策略成為可能。QT-Opt為將DRL應用于真實世界機器人控制任務提供了新的思路。
小結
QT-Opt展示了Q-Learning在連續動作空間上的擴展及其在機器人抓取任務上的應用。為了處理連續動作空間,QT-Opt引入了交叉熵方法(CEM)來優化動作分布。此外,QT-Opt還利用了大規模的仿真和真實數據,通過離線學習來提高樣本效率。
基于視覺的機器人學習控制是一個極具挑戰性的任務,需要克服視覺和控制的雙重難題。QT-Opt的成功得益于:
- 用深度神經網絡將高維視覺信息映射到緊湊的狀態表征
- 通過離線學習充分利用多源異構的歷史數據
- 有效的連續動作空間優化算法如CEM
- 大規模分布式訓練系統和高效的數據管理
展望未來,視覺驅動的機器人學習控制仍有許多亟待解決的問題:
- 提高泛化能力,使策略能適應動態變化的環境
- 實現長期規劃能力,求解多階段復雜任務
- 確保安全性,避免意外碰撞和損壞
- 引入語言指令,實現人機交互和協作
- 提高策略的可解釋性,便于調試和優化
6. 代碼實戰
本章我們通過幾個具體的代碼示例,演示如何用Python和PyTorch實現DQN及其變體算法。
6.1 DQN
我們首先實現一個基本的DQN算法,并將其應用于CartPole游戲環境。
import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
import gym# Q網絡
class QNetwork(nn.Module):def __init__(self, state_dim, action_dim):super(QNetwork, self).__init__()self.fc1 = nn.Linear(state_dim, 64)self.fc2 = nn.Linear(64, 64)self.fc3 = nn.Linear(64, action_dim)def forward(self, x):x = torch.relu(self.fc1(x))x = torch.relu(self.fc2(x))x = self.fc3(x)return x# DQN智能體
class DQNAgent:def __init__(self, state_dim, action_dim):self.state_dim = state_dimself.action_dim = action_dimself.gamma = 0.95self.epsilon = 1.0self.epsilon_decay = 0.995self.epsilon_min = 0.01self.batch_size = 64self.train_start = 1000self.memory = []self.model = QNetwork(state_dim, action_dim)self.target_model = QNetwork(state_dim, action_dim)self.optimizer = optim.Adam(self.model.parameters())self.loss_fn = nn.MSELoss()def get_action(self, state):if np.random.rand() <= self.epsilon:return np.random.randint(self.action_dim)else:state = torch.tensor(state, dtype=torch.float32)q_value = self.model(state)action = q_value.argmax().item()return actiondef train_model(self):if len(self.memory) < self.train_start:returnbatch_data = np.random.choice(self.memory, self.batch_size, replace=False)states = torch.tensor(np.array([data[0] for data in batch_data]), dtype=torch.float32)actions = torch.tensor(np.array([data[1] for data in batch_data]), dtype=torch.int64)rewards = [data[2] for data in batch_data]next_states = torch.tensor(np.array([data[3] for data in batch_data]), dtype=torch.float32)dones = [data[4] for data in batch_data]# 計算當前狀態的Q值q_values = self.model(states).gather(1, actions.unsqueeze(1)).squeeze(1)# 計算下一狀態的最大Q值max_next_q_values = self.target_model(next_states).max(1)[0]max_next_q_values[dones] = 0.0max_next_q_values = max_next_q_values.detach()# 計算目標Q值target_q_values = rewards + self.gamma * max_next_q_valuestarget_q_values = target_q_values.to(torch.float32)# 更新Q網絡loss = self.loss_fn(q_values, target_q_values)self.optimizer.zero_grad()loss.backward()self.optimizer.step()if self.epsilon > self.epsilon_min:self.epsilon *= self.epsilon_decaydef update_target_model(self):self.target_model.load_state_dict(self.model.state_dict())if __name__ == "__main__":env = gym.make("CartPole-v1") agent = DQNAgent(state_dim=4, action_dim=2)for episode in range(1000):state = env.reset()episode_reward = 0done = Falsewhile not done:action = agent.get_action(state)next_state, reward, done, _ = env.step(action)agent.memory.append((state, action, reward, next_state, done))episode_reward += rewardstate = next_stateagent.train_model()if episode % 10 == 0:agent.update_target_model()print(f"Episode: {episode}, Reward: {episode_reward}, Epsilon: {agent.epsilon:.2f}")
這個示例代碼實現了一個基本的DQN算法,包括經驗回放、目標網絡、epsilon貪婪探索等。我們將其應用于CartPole環境,智能體通過DQN學習控制一根桿子保持平衡。代碼的主要組成部分有:
- QNetwork: 定義了一個簡單的MLP作為Q網絡,輸入狀態,輸出各個動作的Q值。
- DQNAgent: 實現了DQN算法的核心邏輯,包括經驗回放、模型訓練、目標網絡更新、動作選擇等。
- 訓練循環: 智能體與環境交互,將轉移樣本存入回放緩沖區,并進行Q網絡訓練。每隔一定episode更新目標網絡。
運行這個代碼,你可以看到智能體的性能隨著訓練不斷提高,最終能夠使桿子長時間保持平衡。你可以嘗試調整超參數如batch_size、learning_rate、epsilon_decay等,觀察它們對算法性能的影響。
6.2 Double DQN
下面我們在DQN的基礎上實現Double DQN算法,只需對calculate_target函數做少量修改:
def train_model(self):...# 計算下一狀態的最大Q值max_action = self.model(next_states).max(1)[1].unsqueeze(1)max_next_q_values = self.target_model(next_states).gather(1, max_action).squeeze(1)max_next_q_values[dones] = 0.0max_next_q_values = max_next_q_values.detach()...
相比DQN,Double DQN用Q網絡來選擇下一狀態的最優動作,再用目標網絡來評估該動作的Q值。這個簡單的改動可以顯著減少Q值的過估計問題,提高算法的穩定性和性能。你可以對比運行DQN和Double DQN,體會它們在訓練過程中的差異。
6.3 DQN with Prioritized Replay
接下來我們實現優先經驗回放(Prioritized Replay),為experience replay引入非均勻采樣,提高樣本利用效率。
首先定義一個概率分布類SumTree,用于管理樣本的優先級:
class SumTree:def __init__(self, capacity):self.capacity = capacityself.tree = np.zeros(2 * capacity - 1)self.data = np.zeros(capacity, dtype=object) self.size = 0self.ptr = 0def add(self, p, data):tree_idx = self.ptr + self.capacity - 1self.data[self.ptr] = dataself.update(tree_idx, p)self.ptr += 1if self.ptr >= self.capacity:self.ptr = 0self.size = min(self.size + 1, self.capacity)def update(self, tree_idx, p):change = p - self.tree[tree_idx]self.tree[tree_idx] = pwhile tree_idx != 0:tree_idx = (tree_idx - 1) // 2self.tree[tree_idx] += changedef get_leaf(self, v):parent_idx = 0while True:left_idx = 2 * parent_idx + 1right_idx = left_idx + 1if left_idx >= len(self.tree):leaf_idx = parent_idxbreakif v <= self.tree[left_idx]:parent_idx = left_idxelse:v -= self.tree[left_idx]parent_idx = right_idxdata_idx = leaf_idx - self.capacity + 1return leaf_idx, self.tree[leaf_idx], self.data[data_idx]@propertydef total_p(self):return self.tree[0]
然后修改DQNAgent,將普通的經驗回放替換為優先經驗回放:
class DQNAgent:def __init__(self, state_dim, action_dim):...self.alpha = 0.6self.beta = 0.4self.beta_increment = 0.001self.epsilon = 1e-6self.memory = SumTree(capacity=10000)...def store_transition(self, state, action, reward, next_state, done):transition = (state, action, reward, next_state, done)self.memory.add(self.max_priority, transition)def train_model(self):if self.memory.size < self.train_start:returnself.beta = min(1.0, self.beta + self.beta_increment)batch_idx, batch_priorities, batch_data = self.sample_batch()states = torch.tensor(np.array([data[0] for data in batch_data]), dtype=torch.float32)actions = torch.tensor(np.array([data[1] for data in batch_data]), dtype=torch.int64)rewards = [data[2] for data in batch_data]next_states = torch.tensor(np.array([data[3] for data in batch_data]), dtype=torch.float32)dones = [data[4] for data in batch_data]... # 計算Q值與目標Q值# 計算prioritiespriorities = (torch.abs(target_q_values - q_values) + self.epsilon).cpu().data.numpy()# 更新prioritiesfor i in range(self.batch_size):idx = batch_idx[i]self.memory.update(idx, priorities[i])def sample_batch(self):batch_idx = np.empty((self.batch_size,), dtype=np.int32)batch_priorities = np.empty((self.batch_size,), dtype=np.float32)batch_data = []segment = self.memory.total_p / self.batch_sizeself.max_priority = max(self.memory.tree[-self.memory.capacity:])p_sum = self.memory.tree[0]for i in range(self.batch_size):a = segment * ib = segment * (i + 1)upperbound = random.uniform(a, b)idx, p, data = self.memory.get_leaf(upperbound)batch_idx[i] = idxbatch_priorities[i] = p / p_sumbatch_data.append(data)batch_priorities /= p_sum # normalizebatch_weights = (p_sum * batch_priorities) ** (-self.beta)batch_weights /= batch_weights.max()return batch_idx, batch_priorities, batch_data
優先經驗回放的核心是SumTree數據結構,它以樹形結構組織樣本,樹節點存儲樣本priority的累加和,葉節點存儲樣本priority。這種結構能夠以O(logN)的復雜度實現權重采樣和priority更新。
DQNAgent的主要變化包括:
- store_transition: 將樣本存儲到SumTree中,優先級初始化為當前最大值
- train_model: 從SumTree中采樣一個batch,并根據TD誤差更新樣本的優先級
- sample_batch: 基于SumTree實現加權采樣,權重與優先級成正比
與普通的經驗回放相比,優先經驗回放能夠更頻繁地采樣到有信息量的樣本(如TD誤差大的樣本),從而加速訓練收斂。你可以通過調節alpha和beta系數來權衡優先級分布的陡峭程度。
6.4 Dueling DQN
最后我們來實現Dueling DQN,修改Q網絡的結構,顯式估計狀態值函數和優勢函數。
class DuelingQNetwork(nn.Module):def __init__(self, state_dim, action_dim):super(DuelingQNetwork, self).__init__()self.feature = nn.Sequential(nn.Linear(state_dim, 64),nn.ReLU(),nn.Linear(64, 64),nn.ReLU())self.advantage = nn.Sequential(nn.Linear(64, 64),nn.ReLU(),nn.Linear(64, action_dim))self.value = nn.Sequential(nn.Linear(64, 64),nn.ReLU(),nn.Linear(64, 1))def forward(self, x):feature = self.feature(x)advantage = self.advantage(feature)value = self.value(feature)q = value + advantage - advantage.mean()return q
將QNetwork替換為DuelingQNetwork,其他部分代碼保持不變即可。
Dueling網絡將Q函數分解為狀態值函數V(s)和優勢函數A(s,a),其中A(s,a)表示動作a相對于狀態s的平均優勢。這種分解使得網絡能夠學到更穩定、更健壯的值函數,提高策略的質量。你可以思考為什么Dueling架構能學到更優的策略。
總結
通過以上代碼示例,相信你已經掌握了DQN及其變體算法的核心思想和實現要點。這些示例代碼提供了一個可擴展的框架,你可以在此基礎上輕松實現其他DRL算法,或將它們應用到不同的環境任務中。
當然,實際應用還需要考慮諸多工程細節,如超參數調優、模型存儲、日志記錄、可視化分析等。這需要你在實踐中不斷摸索和積累。但只要掌握了DQN的核心原理,相信你一定能夠駕馭復雜的DRL系統,讓智能體學會從環境中汲取知識,實現智能決策。
讓我們以DQN為起點,一起探索DRL的精彩世界,用智能點亮未來!
7. 前沿探索
強化學習是一個蓬勃發展的研究領域,DQN的提出掀起了深度強化學習的浪潮。近年來,研究者們不斷探索DRL的新方法、新架構、新應用,取得了一系列令人矚目的成果。本章我們簡要介紹幾個有前景的研究方向,幫助讀者把握DRL的最新進展。
7.1 分層強化學習
現實世界中很多任務都具有層次結構,可以分解為多個子任務。例如做飯可以分解為采購食材、清洗切配、烹飪等步驟。標準的DRL算法通常學習一個扁平的策略,缺乏對任務內在結構的建模,難以應對復雜的長期規劃問題。
分層強化學習(Hierarchical RL)旨在學習多層次的策略,自底向上地解決子任務,再組合成整體的解決方案。一個代表性工作是Feudal Networks(FuNs)[Vezhnevets et al., 2017],它引入了君臣網絡結構,高層網絡設置子目標,低層網絡執行基本動作,實現了策略的分層抽象。這種分層結構使得智能體能夠學到更高效、更具可解釋性的策略。
分層強化學習讓智能體掌握了"分而治之"的解題思想,有望攻克現實世界中的復雜規劃難題。未來的一個重要方向是探索自適應的層次結構,讓智能體自主地發現任務的內在邏輯。
7.2 元強化學習
元學習(Meta Learning)的目標是學會如何學習,讓模型具備快速適應新任務的能力。將元學習思想引入強化學習,就得到了元強化學習(Meta RL)。
Model-Agnostic Meta-Learning(MAML)[Finn et al., 2017]是一個著名的元學習框架。它通過兩級優化來學習一個任務初始化參數,使其能在新任務上通過少量梯度下降快速適應。這種思想也被引入強化學習,稱之為Meta RL[Finn et al., 2017]。Meta RL旨在學習一個初始化策略,使其能在相似的MDP家族上快速適應。具體來說,它在一個分布的MDP上訓練,優化策略在新MDP上經過少量梯度下降后的累積回報。
Meta RL讓智能體具備了"學習轉移"的技能,可大大減少新環境中所需的數據量和訓練時間,提高學習的泛化能力。未來需進一步提高元策略的適應性和魯棒性,實現跨領域的知識遷移。
7.3 多智能體強化學習
很多實際應用如自動駕駛、智慧城市等,都涉及多個智能體的協作與博弈。將DRL拓展到多智能體場景,就得到了多智能體強化學習(Multi-Agent RL, MARL)。
經典的MARL算法如Independent Q-Learning(IQL)簡單地為每個智能體訓練一個獨立的Q網絡,缺乏對其他智能體行為的建模,難以學到協作策略。為此,研究者們提出了一系列協作感知(cooperation-aware)的MARL算法。其中Value Decomposition Networks(VDN)[Sunehag et al., 2017]假設聯合動作值函數可分解為各智能體值函數之和,從而將聯合Q學習簡化為分布式單智能體學習。QMIX[Rashid et al., 2018]進一步放寬了可加性約束,引入一個非線性混合網絡來組合各智能體的值函數,增強了值函數的表達能力。
多智能體學習讓智能體掌握了"協同合作"的能力,是應對復雜社會性任務的關鍵。未來的重點是提高算法的可擴展性和魯棒性,在面對大規模非穩態環境時,依然能學到有效的協作策略。
7.4 安全強化學習
在高風險領域如自動駕駛、醫療診斷部署DRL系統時,不僅要考慮性能,還要確保策略的安全性。讓智能體規避危險行為,一直是強化學習的難題。
安全強化學習(Safe RL)[Garc?a et al., 2015]旨在學習滿足安全約束的最優策略。一種常見做法是將約束建模為懲罰項,納入環境獎勵。但這種軟約束難以嚴格保證安全性。另一種思路是將安全判別器嵌入策略搜索過程[Dalal et al., 2018],引導智能體遠離危險狀態。但判別器的準確性依賴專家知識,且難以適應環境變化。
如何在保證安全的前提下,最大化任務性能,是一個亟待攻克的難題。未來需進一步完善安全理論與算法,在實踐中平衡安全性、樣本效率與計算效率,最終實現可信、可用、可靠的DRL系統。
展望未來
縱觀全書,我們系統地介紹了DRL的基本原理與核心算法,聚焦DQN及其變體,展示了DRL在游戲、機器人等領域的應用進展,探討了若干有前景的研究方向。DRL作為連接深度學習與強化學習的橋梁,大大拓展了智能系統的應用邊界,使之有能力直接從原始高維數據中學習復雜的策略,實現端到端的決策優化。
當前,DRL在解決現實世界復雜問題的道路上仍面臨諸多挑戰:
- 樣本效率:DRL需要大量的數據來學習值函數或策略,在很多實際任務中代價難以承受。元學習、遷移學習等技術有望緩解這一問題。
- 泛化能力:DRL模型在訓練環境中表現優異,但遷移到新環境后往往難以適應。增強學習(augmented learning)等方法通過數據增強來提高模型魯棒性。
- 安全可信:DRL系統缺乏可解釋性,難以驗證其安全性與正確性。將因果推理、邏輯規劃等符號化方法與DRL相結合,有望實現可解釋、可證明的策略學習。
- 工程實現:DRL涉及環境構建、神經網絡設計、分布式訓練等諸多工程問題。TensorFlow、PyTorch等深度學習框架對DRL的支持還不夠完善。
盡管道阻且長,但DRL作為通用人工智能的核心技術之一,正在深刻影響和重塑人類社會。智能助理、無人駕駛、智能醫療等領域已初見DRL的身影。隨著5G、物聯網、大數據等新一代信息技術的發展,DRL將迎來更廣闊的應用空間。DRL與多智能體系統、群體智能的結合,將開創性地模擬復雜社會系統,優化資源配置。DRL與知識圖譜、邏輯推理等符號AI技術的融合,將從數據驅動進化到知識驅動,實現更高層次的認知與規劃。