1. 从表格到参数函数逼近
当状态空间维数非常多或者存在连续维度时,使用表格型强化学习会遇到“维度爆炸”的问题。一种解决方案是舍弃状态行动
s
,
a
s,a
s,a与值
q
q
q的一一对应关系,而是使用函数
q
=
f
(
s
,
a
)
q=f(s,a)
q=f(s,a)的形式拟合状态与值的关系。这里就能引入机器学习模型和深度学习模型了。这种方法(主要是DQN)与传统Q-learning方法的区别主要在于策略函数发生了变化,新的贪婪策略变成了
arg
max
a
f
(
s
,
a
)
\arg \max_a f(s,a)
argmaxaf(s,a)。
注意在表格型方法中,每次评估状态值时,更新的只有当前状态的值,而在值函数模型中,更新的是函数参数
θ
\theta
θ,会导致所有状态的值都发生改变,因此更新规则需要做一下设计。
2. 基于梯度的方法
对问题进行采样,假设
(
s
t
i
,
a
t
i
)
,
G
t
i
(s^i_t,a^i_t),G^i_t
(sti,ati),Gti是时间
t
t
t的样本和样本对应计算出来的值。
首先来看蒙特卡洛的方法,也就是每一个样本都更新一次
θ
\theta
θ。假设第
i
i
i轮迭代时间t的样本参数估计值为
θ
t
i
\theta^i_t
θti,则下一个样本的目标是
min
θ
(
G
t
i
−
q
θ
(
s
t
i
,
a
t
i
)
)
2
\min_{\theta}(G^i_t-q_{\theta}(s^i_t,a_t^i))^2
minθ(Gti−qθ(sti,ati))2。在负梯度方向上更新,更新率为
α
\alpha
α。梯度更新公式为
Δ
θ
=
α
(
G
t
i
−
q
θ
t
i
(
s
t
,
a
t
i
)
)
∗
q
θ
t
i
′
(
s
t
,
a
t
i
)
\Delta\theta=\alpha(G^i_t-q_{\theta^i_t}(s_t,a_t^i))*q'_{\theta^i_t}(s_t,a_t^i)
Δθ=α(Gti−qθti(st,ati))∗qθti′(st,ati)。
基于SARSA的梯度更新公式为
Δ
θ
=
α
(
R
t
i
+
γ
q
θ
i
(
s
t
+
1
,
a
t
+
1
)
−
q
θ
t
i
(
s
t
,
a
t
)
)
∗
q
θ
t
i
′
(
s
t
,
a
t
)
\Delta\theta=\alpha(R^i_t+\gamma q_{\theta^{i}}(s_{t+1},a_{t+1})-q_{\theta^i_t}(s_t,a_t))*q'_{\theta^i_t}(s_t,a_t)
Δθ=α(Rti+γqθi(st+1,at+1)−qθti(st,at))∗qθti′(st,at);
基于Q-Learing的梯度更新公式为
Δ
θ
=
α
(
R
t
i
+
γ
max
a
q
θ
i
(
s
t
+
1
,
a
)
−
q
θ
t
i
(
s
t
,
a
t
)
)
∗
q
θ
t
i
′
(
s
t
,
a
t
)
\Delta\theta=\alpha(R^i_t+\gamma \max_{a} q_{\theta^{i}}(s_{t+1},a)-q_{\theta^i_t}(s_t,a_t))*q'_{\theta^i_t}(s_t,a_t)
Δθ=α(Rti+γmaxaqθi(st+1,a)−qθti(st,at))∗qθti′(st,at)。
当我们假设
q
θ
(
s
,
a
)
=
θ
ϕ
(
s
,
a
)
q_{\theta}(s,a)=\theta\phi(s,a)
qθ(s,a)=θϕ(s,a)时,称为线性逼近方法,可以直接计算梯度。否则称为非线性梯度法,最常见的是DQN方法。
3. DQN方法
DQN全程为Deep Q Network,其基础是Q-Learning,也就是异策略时间差分法,只是该用神经网络表示值函数,并使用神经网络的方法来更新参数。DQN要点如下:
- 异策略:分别使用Behavior Network(用于采样)和Target Network(用于计算 G G G、改进 π \pi π);解耦后能够减少每一轮迭代的波动对更新计算的影响。
- 时间差分:用下一时间的值函数来估计当前值函数的方法。将TD中的参数 θ \theta θ和值函数中的参数 θ \theta θ分开更新,减少数据关联问题。TD参数每隔固定步数更新为值函数的参数。此外,TD偏差越大的样本采样概率越高,为了纠正有偏估计,需要乘以一个重要性采样系数。
- 值函数结构:采用深度卷积网络(3个卷积层+2个全连接层)进行逼近。将值函数模型结构从 ∣ S ∣ × ∣ A ∣ → R |S|\times|A|\to R ∣S∣×∣A∣→R变为 ∣ S ∣ → R ∣ A ∣ |S|\to R^{|A|} ∣S∣→R∣A∣,方便使用神经网络训练。
- 回放缓存(Replay Buffer):采用回放缓存解决马氏链的时间关联问题,具体做法是将样本存储到size固定(比如100万)的数据库中,每次随机采样一批进行训练;超出size以后依次覆盖历史最久的数据。使用这种方法,每次训练的样本可以来自多次不同的交互序列,波动会减少很多。
在DQN的论文中解决Atari问题时,还有一些技巧,比如:每次训练数据是N帧画面而不是1帧,以保留动态信息;每次起始状态随机化(Random Start);参照人类的反应速度跳过一些帧(Frame-Skipping)。
4. DQN改进方法
Priority Replay Buffer(优先回放缓存)则用于改进样本效率,交互时表现越差的样本赋予的采样权重越大,这样能提高模型的学习效率。交互的效果用TD-error的函数表达,而采样过程使用线段树的方式来实现。
Dueling DQN将
q
(
s
,
a
)
q(s,a)
q(s,a)函数分解成
v
(
s
)
+
A
(
s
,
a
)
v(s)+A(s,a)
v(s)+A(s,a)两部分分别用神经网络估计,其好处是由于决策空间|A|常常远小于状态空间|S|,分解之后可以大大减少网络输出层的范围。具体实施时还要减去A的均值避免结果有偏:
v
(
s
)
+
A
(
s
,
a
)
−
Σ
a
A
(
s
,
a
)
/
∣
A
∣
v(s)+A(s,a)-\Sigma _aA(s,a)/|A|
v(s)+A(s,a)−ΣaA(s,a)/∣A∣
Learning from Demonstration的方法则预先准备好一些优秀的采样轨迹,避免冷启动的问题,这些采样数据永久保存在Replay Buffer中,并且在最开始的时候模型只接受这些优质采样轨迹的数据。
Rainbow方法是上述诸多改进方法的综合体,此外还用了诸如Distributional DQN、Noisy Network等方法。
5. Baseline的DQN例子
我们使用封装版本的stable-baselines,其语句非常类似sklearn:
import gym
from stable_baselines.deepq.policies import MlpPolicy
from stable_baselines import DQN
model = DQN(MlpPolicy,'CartPole-v1',verbose = 1).learn(25000)
obs = model.env.reset()
while True:
action, _states = model.predict(obs)
obs, rewards, dones, info = model.env.step(action)
model.env.render()
输出为:
Creating environment from the given name, wrapped in a DummyVecEnv.
--------------------------------------
| % time spent exploring | 27 |
| episodes | 100 |
| mean 100 episode reward | 18.7 |
| steps | 1848 |
--------------------------------------
--------------------------------------
| % time spent exploring | 2 |
| episodes | 200 |
| mean 100 episode reward | 126 |
| steps | 14405 |
--------------------------------------
--------------------------------------
| % time spent exploring | 2 |
| episodes | 300 |
| mean 100 episode reward | 100 |
| steps | 24423 |
--------------------------------------
......