引言(Introduction)#
在之前的 Q-Learning 算法中,我们使用一个矩阵(Q-Table)来记录每个状态动作对 ( s , a ) (s,a) ( s , a ) 的价值。
这种方法有两个致命局限:
内存限制 :如果状态空间很大(例如围棋 10 170 10^{170} 1 0 170 ),表格根本存不下。这被称为维度灾难 (Curse of Dimensionality) 。
泛化能力差 :对于没见过的状态,表格无法给出估计,而在连续状态空间中,几乎很难遇到完全一样的状态。
为了解决这个问题,我们引入函数拟合 (Function Approximation) 。深度Q网络 (Deep Q-Network, DQN) 使用一个神经网络 Q ω ( s , a ) Q_\omega(s, a) Q ω ( s , a ) 来近似 Q ∗ ( s , a ) Q^*(s, a) Q ∗ ( s , a ) ,输入状态 s s s ,输出所有离散动作的 Q 值。
深度 Q 网络 (DQN)#
核心定义#
在 DQN 中,我们使用参数为 ω \omega ω 的神经网络来拟合动作价值函数。
输入 :状态 s s s (例如游戏的屏幕像素)。
输出 :每个动作 a ∈ A a \in \mathcal{A} a ∈ A 对应的价值 Q ( s , a ) Q(s,a) Q ( s , a ) 。
损失函数#
类似于 Q-Learning,我们希望神经网络的输出逼近 TD Target。
对于一条数据 ( s i , a i , r i , s i ′ ) (s_i, a_i, r_i, s_i^\prime) ( s i , a i , r i , s i ′ ) ,目标是最小化均方误差:
J ( ω ) = 1 2 N ∑ i = 1 N [ Q ω ( s i , a i ) ⏟ 预测值 − ( r i + γ max a ′ Q ω ( s i ′ , a ′ ) ) ⏟ TD Target ] 2 J(\omega)=\frac{1}{2N}\sum_{i=1}^{N}\left[ \underbrace{Q_\omega(s_i,a_i)}_{\text{预测值}} - \underbrace{\left(r_i+\gamma \max_{a^\prime}Q_\omega(s_i^\prime,a^\prime)\right)}_{\text{TD Target}} \right]^2 J ( ω ) = 2 N 1 i = 1 ∑ N 预测值 Q ω ( s i , a i ) − TD Target ( r i + γ a ′ max Q ω ( s i ′ , a ′ ) ) 2
然而,直接这样训练是不稳定的。DQN 引入了两大“法宝”来解决这个问题。
创新一:经验回放 (Experience Replay)#
在一般的监督学习中,我们假设训练数据是独立同分布 (i.i.d) 的。但在强化学习中,智能体采集的数据是序列相关的(现在的状态依赖于上一秒的状态)。
做法 :
维护一个回放缓冲区 (Replay Buffer) R \mathcal{R} R 。
智能体与环境交互,将产生的数据 ( s t , a t , r t , s t + 1 ) (s_t, a_t, r_t, s_{t+1}) ( s t , a t , r t , s t + 1 ) 存入缓冲区。
训练时,从缓冲区中随机采样 一个批次 (Batch) 的数据进行梯度下降。
作用 :
打破相关性 :随机采样消除了数据之间的时间相关性,满足独立同分布假设,稳定网络训练。
提高样本效率 :一条经验数据可以被多次采样利用,而不是用完即弃。
创新二:目标网络 (Target Network)#
在原版 Q-Learning 中,TD Target 的计算也依赖于当前网络参数 ω \omega ω :
y i = r i + γ max a ′ Q ω ( s i ′ , a ′ ) y_i = r_i + \gamma \max_{a'} Q_\omega(s'_i, a') y i = r i + γ a ′ max Q ω ( s i ′ , a ′ )
这就好比“在射箭的同时,靶子也在动”。更新 ω \omega ω 会同时改变预测值和目标值,容易导致震荡发散。
做法 :
引入一个结构相同但参数独立的目标网络 (Target Network) ,参数记为 ω − \omega^- ω − 。
计算目标值时使用 ω − \omega^- ω − ,更新网络时优化 ω \omega ω 。
y i = r i + γ max a ′ Q ω − ( s i ′ , a ′ ) y_i = r_i + \gamma \max_{a'} Q_{\omega^-}(s'_i, a') y i = r i + γ a ′ max Q ω − ( s i ′ , a ′ )
更新规则 :
训练网络 ω \omega ω :每个 step 都进行梯度下降更新。
目标网络 ω − \omega^- ω − :每隔 C C C 步(例如 1000 步),将 ω \omega ω 的值复制给 ω − \omega^- ω − (ω − ← ω \omega^- \leftarrow \omega ω − ← ω )。
💡 直觉 :固定住靶子一会儿,让射手(训练网络)安心瞄准,等射手练好了,再把靶子挪到新的位置。
DQN 算法伪代码#
∙ Initialize main network Q ω and target network Q ω − with weights ω ∙ Initialize replay buffer R ∙ For episode e = 1 → E do : ∙ Initialize state s ∙ For step t = 1 → T do : ∙ Select action a using ϵ -greedy based on Q ω ( s ) ∙ Execute a , observe r , s ′ ∙ Store transition ( s , a , r , s ′ ) in R ∙ If ∣ R ∣ > batch_size : ∙ Sample batch { ( s i , a i , r i , s i ′ ) } i = 1 N from R ∙ Calculate targets: y i = r i + γ max a ′ Q ω − ( s i ′ , a ′ ) ∙ Update ω by minimizing 1 N ∑ ( Q ω ( s i , a i ) − y i ) 2 ∙ Every C steps: ω − ← ω ∙ s ← s ′ ∙ End For ∙ End For \begin{aligned}
& \bullet \; \text{Initialize main network } Q_\omega \text{ and target network } Q_{\omega^-} \text{ with weights } \omega \\
& \bullet \; \text{Initialize replay buffer } \mathcal{R} \\
& \bullet \; \textbf{For } \text{episode } e = 1 \to E \textbf{ do}: \\
& \bullet \qquad \text{Initialize state } s \\
& \bullet \qquad \textbf{For } \text{step } t = 1 \to T \textbf{ do}: \\
& \bullet \qquad \qquad \text{Select action } a \text{ using } \epsilon\text{-greedy based on } Q_\omega(s) \\
& \bullet \qquad \qquad \text{Execute } a, \text{ observe } r, s' \\
& \bullet \qquad \qquad \text{Store transition } (s, a, r, s') \text{ in } \mathcal{R} \\
& \bullet \qquad \qquad \textbf{If } |\mathcal{R}| > \text{batch\_size}: \\
& \bullet \qquad \qquad \qquad \text{Sample batch } \{(s_i, a_i, r_i, s'_i)\}_{i=1}^N \text{ from } \mathcal{R} \\
& \bullet \qquad \qquad \qquad \text{Calculate targets: } y_i = r_i + \gamma \max_{a'} Q_{\omega^-}(s'_i, a') \\
& \bullet \qquad \qquad \qquad \text{Update } \omega \text{ by minimizing } \frac{1}{N}\sum (Q_\omega(s_i, a_i) - y_i)^2 \\
& \bullet \qquad \qquad \qquad \textbf{Every } C \text{ steps: } \omega^- \leftarrow \omega \\
& \bullet \qquad \qquad s \leftarrow s' \\
& \bullet \qquad \textbf{End For} \\
& \bullet \; \textbf{End For}
\end{aligned} ∙ Initialize main network Q ω and target network Q ω − with weights ω ∙ Initialize replay buffer R ∙ For episode e = 1 → E do : ∙ Initialize state s ∙ For step t = 1 → T do : ∙ Select action a using ϵ -greedy based on Q ω ( s ) ∙ Execute a , observe r , s ′ ∙ Store transition ( s , a , r , s ′ ) in R ∙ If ∣ R ∣ > batch_size : ∙ Sample batch {( s i , a i , r i , s i ′ ) } i = 1 N from R ∙ Calculate targets: y i = r i + γ a ′ max Q ω − ( s i ′ , a ′ ) ∙ Update ω by minimizing N 1 ∑ ( Q ω ( s i , a i ) − y i ) 2 ∙ Every C steps: ω − ← ω ∙ s ← s ′ ∙ End For ∙ End For
进阶 1:Double DQN#
问题:过高估计 (Overestimation)#
DQN 在计算目标值时使用了 max \max max 操作:y i = r + γ max a ′ Q ( s ′ , a ′ ) y_i = r + \gamma \max_{a'} Q(s', a') y i = r + γ max a ′ Q ( s ′ , a ′ ) 。
由于神经网络本身存在估计误差,max \max max 操作倾向于选择那些被高估 的值。这种最大化偏差 (Maximization Bias) 会导致 Q 值普遍偏大,影响策略学习。
解决方案#
解耦选择与评估 。
选择动作 :使用当前网络 Q ω Q_\omega Q ω 来决定哪个动作最好(即 argmax)。
评估价值 :使用目标网络 Q ω − Q_{\omega^-} Q ω − 来计算那个动作的价值。
Double DQN 目标公式 :
y i = r i + γ Q ω − ( s i ′ , argmax a ′ Q ω ( s i ′ , a ′ ) ) y_i = r_i + \gamma Q_{\omega^-}(s'_i, \underset{a'}{\operatorname{argmax}} Q_\omega(s'_i, a')) y i = r i + γ Q ω − ( s i ′ , a ′ argmax Q ω ( s i ′ , a ′ ))
进阶 2:Dueling DQN#
核心思想#
在很多状态下,状态本身的价值 比选择什么动作 更重要。
例如:在赛车游戏中,如果前面是死胡同(状态差),无论你向左转还是向右转(动作),价值都很低。
Dueling DQN 改变了网络结构,将 Q 值分解为两部分:
状态价值函数 (Value Function) V ( s ) V(s) V ( s ) :仅与状态有关。
优势函数 (Advantage Function) A ( s , a ) A(s,a) A ( s , a ) :与动作有关,表示动作 a a 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 )
可辨识性问题 (Identifiability)#
如果直接用 V + A V+A V + A ,网络会出现唯一性问题(V V V 加 10,A A A 减 10,总和 Q Q Q 不变)。为了让 V V V 和 A A A 能被唯一确定,我们需要强行约束 A A A 的某种性质。
聚合公式 (Aggregation) :
通常让优势函数 A A A 对于某个状态的均值为 0,或者最大值为 0。
Q ( s , a ; θ , α , β ) = V ( s ; θ , β ) + ( A ( s , a ; θ , α ) − 1 ∣ A ∣ ∑ a ′ A ( s , a ′ ; θ , α ) ) Q(s,a;\theta,\alpha,\beta)=V(s;\theta,\beta) + \left( A(s,a;\theta,\alpha) - \frac{1}{|\mathcal{A}|}\sum_{a^\prime}A(s,a^\prime;\theta,\alpha) \right) Q ( s , a ; θ , α , β ) = V ( s ; θ , β ) + ( A ( s , a ; θ , α ) − ∣ A ∣ 1 a ′ ∑ A ( s , a ′ ; θ , α ) )
或者:
Q ( s , a ; θ , α , β ) = V ( s ; θ , β ) + ( A ( s , a ; θ , α ) − max a ′ A ( s , a ′ ; θ , α ) ) Q(s,a;\theta,\alpha,\beta)=V(s;\theta,\beta) + \left( A(s,a;\theta,\alpha) - \max_{a^\prime}A(s,a^\prime;\theta,\alpha) \right) Q ( s , a ; θ , α , β ) = V ( s ; θ , β ) + ( A ( s , a ; θ , α ) − a ′ max A ( s , a ′ ; θ , α ) )
优点 :
在动作对环境影响不大的状态下,能更快地学习状态价值 V V V 。
极大地提高了训练效率和稳定性。