2024-08-25
这是学习我阅读若干在线 RL 教程所作的笔记,比较杂乱无章,不适合作为你的第一个 RL 教程阅读,如果想要找一个入门的 RL 教程推荐从头到尾阅读 OpenAI 的 Spinning Up
再贴一个叶哥的同类博文作为参照。
Model-free 的方法不会对环境进行建模。当然,为了训练,代码中至少是要某种程度上建模环境和回报的,但除了定义 reward function 外不对模型提供帮助。依据学习目标的不同,Model-Free 这个大类主要包括直接表示策略的策略梯度方法(包括各种改良,比如 PPO 算法)和模拟Q函数的 Q-Learning 类方法。因此,使用 PPO 的 RLHF 就是一个 Model-free 的方法。
Model-based 方法会利用环境的模型多步规划,推演思考几步后会发生什么。这个模型要么是预先定义的,要么是算法学习得到的。Model-based RL 算法比较驳杂没有明显的分类,最简单的 Model-based RL 就是 MPC Model-predictive control,每一步都向后看一个固定的时间窗口,依据模型计算出一个最优计划,然后采取计划当中的第一步。
Spinning-up 文档对 Off-policy 的定义是,训练的任何阶段收集到的数据都可以用来更新模型,比如 Q-Learning 就是一个 Off-policy 的算法。Q-Learning 中任何阶段收集到的数据都可以更新模型吗?是的,Deep Q-Network 中,就有一个 replay buffer 专门收集所有经历过的状态-行动-结果-下一个状态的元组 $(s_i,a_i,r_i,s_{i+1})$,然后每次更新参数都是从 replay buffer 中抽取一个 mini-batch,然后按照如下的 Loss 进行梯度下降,从而达成抽样回顾迄今训练过程中的全部经历的效果。
这个损失函数是 TD target - Q Value Estimation 的平方,注意这里 TD target 假设下个状态中采取最优行动: $$ (r_i + \gamma * \max_{a} Q(s_{i+1},a) - Q(s_i,a_i))^2 $$
Deep RL Course 对 Off-policy 的定义有些许不同,定义为训练时和测试时策略不同(或者说,用来更新参数和用来真正行动的策略不同)。这个定义下,Q-Learning 也是 Off-policy 的:它用 epsilon-greedy 策略来生成训练数据,而使用纯贪心策略来行动。
DQN的一个大问题是用来估计 TD Target 的 Q 函数恰好是我们需要学习的,是噪声大的。当我们更新了定义 Q 函数的网络,TD Target 也更新了,有人认为这是一个“追踪一个移动的目标”的问题。对此,一个改进是使用一个单独的网络Q'来估计 TD target,然后每隔若干回合把 Q' 赋值为Q。这个方法被称为 Double Q-Learning,其 loss 写为
$$ (r_i + \gamma * \max_{a} Q'(s_{i+1},a) - Q(s_i,a_i))^2 $$
Spinning-up 文档对 On-policy 的定义是模型更新只能利用以当前策略和环境交互收集到的数据。Deep RL Course 对 On-policy 的定义是训练和测试时使用相同的策略。策略梯度方法符合两个 On-policy 的定义。设 $\pi$ 是策略网络,$\theta$ 是策略网络的参数,$\tau$ 是轨迹,预期收益可以写成 $\Sigma_{\tau} P(\tau, \theta) R(\tau)$。策略梯度方法使用蒙特卡洛方法,利用几个采样得到的轨迹 $\tau$ 来估计预期收益关于 $\theta$ 的梯度——这是一个带重要性采样的蒙特卡洛求和,模型更新只用到了当前一步针对最新策略收集到的数据。
$$ \begin{align*} \nabla_{\theta} \Sigma_{\tau} P(\tau;\theta) R(\tau) &= \Sigma_{\tau} \nabla_{\theta} P(\tau;\theta) R(\tau) \\ &= \Sigma_{\tau} P(\tau;\theta) \frac{\nabla_{\theta}P(\tau;\theta)}{P(\tau;\theta)} R(\tau) \\ &= \Sigma_{\tau} P(\tau;\theta) \nabla_{\theta} \log(P(\tau;\theta)) R(\tau) \\ &= \frac{1}{m} \Sigma_{i=1}^m \nabla_{\theta} \log(P(\tau_i;\theta)) R(\tau_i) \end{align*} $$
其中 $\tau_i$ 必须是根据 $\pi(\theta)$ 行动从而采样到的轨迹。
事实上,由于策略梯度方法建模在状态 s 采取各个行动 $a_i$ 的概率 $p_i(s, a_i)$ ,所以 $P(\tau_i, \theta)$ 中与 $\theta$ 有关的项仅仅是各个 $\pi(s, a_i)$ 相乘,上面的梯度可以进一步化简为
$$ \frac{1}{m} * \Sigma_i^m \Sigma_t^T \nabla_{\theta} \log(p_i(s_t^{i}, a_t^{i}, \theta)) R(\tau^{i}) $$
把梯度算符去掉(微积分中的求“原函数”的操作),得到损失函数,该函数的关于模型参数梯度恰好等于预期收益关于模型参数的梯度
$$ \texttt{Loss} = \frac{1}{m} * \Sigma_i^m \Sigma_t^T \log(p_i(s_t^{i}, a_t^{i}, \theta)) R(\tau^{i}) $$
这个算法被称为 Reinforce。
Q:如果每条轨迹的回报都为正(比如游戏里的得分始终为正),是否意味着对于每一种 action 都会鼓励,或者说更新梯度来增加其概率?
A:的确。虽然每种 action 都被增加概率,但由于在每个状态下采用的 action 的概率需要归一化,增加采取一种 action 的概率就会降低采取其它 action 的概率。最终,与高回报相关联的 action 会胜出。
Q:关于梯度估计中需要对多个轨迹和每个轨迹中的所有时刻进行双重求和,之后才能求出梯度,能否改进?
A:首先,试着不用整条轨迹的 return 而用单步的 reward 来更新策略。要这样做,可以(为什么?)把 $R(\tau)$ 替换为单步采用指定行动带来的优势 (Advantage),即 A(s, a) = Q(s, a) - V(s),其中 V(s) 是当下策略在状态 s 的预期回报,Q(s, a)是当下策略在状态 s 且做出行动 a 的预期回报。
这一章主要是 Spinning Up 文档第三部分的笔记或翻译
ELGP (Expected Grad-Log-Prob) 引理,试翻译为概率对数梯度期望引理,是 Spinning up 文档推导出的一个常用结果。假设 $P_{\theta}(x)$ 是关于 $\theta$ 参数化的 x 的分布函数,则
$$ \begin{align*} 0 &= \nabla_{\theta} 1 \\ &= \nabla_{\theta} \int_x P_{\theta}(x) \\ &= \int_x \nabla_{\theta} P_{\theta}(x) \\ &= \int_x P_{\theta}(x) \nabla_{\theta} \log(P_{\theta}(x)) \\ &= E_{x\sim P_{\theta}} \nabla_{\theta} \log(P_{\theta}(x)) \\ \end{align*} $$
这是 Spinning Up 文档的一章,名字很有趣为 don't let the past distract you。仔细观察策略梯度算法中的梯度表述,其中特定状态下特定行动的概率因为整条轨迹的回报而增减:
$$ \nabla_{\theta} J = E_{\tau \sim \pi_{\theta}} \Sigma_{t=0}^T \nabla_{\theta} \log(\pi_{\theta} (a_t|s_t) R(\tau)) $$
然而,直观上,采取行动的概率不应该被达到当前状态之前得到的奖励(reward)而影响。
能否证明可以排除这些奖励?首先改变求期望、求和的顺序:
$$ \begin{align*} \nabla_{\theta} J &= E_{\tau \sim \pi_{\theta}} \Sigma_{t=0}^T \nabla_{\theta} \log(\pi_{\theta}(a_t|s_t) \Sigma_{t'=0}^T r(s_{t'},a_{t'})) \\ &= \Sigma_{t=0}^T \Sigma_{t'=0}^T E_{\tau} [\nabla_{\theta} \log(\pi_{\theta}(a_t|s_t)) * r(s_{t'},a_{t'})] \\ \texttt{Denote} X(t,t') &:= E_{\tau} [\nabla_{\theta} \log(\pi_{\theta}(a_t|s_t)) * r(s_{t'},a_{t'})] \end{align*} $$
仔细观察求和项 X(t,t')。假设 t > t',即获得奖励的时刻在当前时刻之前,则
$$ \begin{align*} X(t,t') &= E_{\tau=(s_0,a_0,...,s_{t'},a_{t'},...,s_t,a_t,...,s_T,a_T)} [\nabla_{\theta} \log(\pi_{\theta}(a_t|s_t)) * r(s_{t'},a_{t'})] \\ &\texttt{notice that the term does not depend on } s_{t+1}...a_T \\ &= E_{\tau=(s_0,a_0,...,s_{t'},a_{t'},...,s_t,a_t)} [\nabla_{\theta} \log(\pi_{\theta}(a_t|s_t)) * r(s_{t'},a_{t'})] \\ &= E_{\tau=(s_0,a_0,...,s_{t'},a_{t'},...,s_t)} E_{a_t|s_t} [\nabla_{\theta} \log(\pi_{\theta}(a_t|s_t)) * r(s_{t'},a_{t'})] \\ &= E_{\tau=(s_0,a_0,...,s_{t'},a_{t'},...,s_t)} [r(s_{t'},a_{t'}) * E_{a_t|s_t} [\nabla_{\theta} \log(\pi_{\theta}(a_t|s_t))] ] \\ &\texttt{using the ELGP lemma} \\ &= 0 \end{align*} $$
做这个证明的核心思想是将轨迹 $\tau$ 写成 (state, action, state, action, ...) 交替出现的形式,在求期望时,如果期望里面的式子与轨迹尾部的具体 state 和 action 无关,则可以将其消去,截断轨迹到我们感兴趣的部分(实际上是对这些我们不感兴趣的 state 和 action 求和,等于一)。当我们感兴趣的 action 到了轨迹末尾,依据 $P(\tau)$ 的表达式将其拆出去。
这说明了不予计算在 "当前时刻" 之前获得的奖励,估计的期望不变。这样的好处是,将更少的奖励纳入考虑(或者说加和的项少了一半),能够降低蒙特卡洛估计的方差。
沿着上面的思路继续思考,还能不能借助 ELGP 引理,进一步对梯度的估计作代数变形,从而进一步降低蒙特卡洛估计值的方差?
依据 ELGP 引理,实际上有如下二级结论:
$$ \begin{align*} E_{\tau} \nabla_{\theta} \pi_{\theta} (a_t|s_t) b(s_t) &= E_{\tau=(s_0,a_0,...,s_t,a_t)} \nabla_{\theta} \pi_{\theta} (a_t|s_t) b(s_t) \\ &= E_{\tau=(s_0,a_0,...,s_t)} b(s_t) E_{a_t|s_t} [\nabla_{\theta} \pi_{\theta} (a_t|s_t)] \\ &= 0 \end{align*} $$
所以梯度的估计可以变形为
$$ \nabla_{\theta} J = E_{\tau} [\Sigma_{t=0}^T \nabla_{\theta} \log(\pi_{\theta}(a_t|s_t)) * (\text{reward to go} - b(s_t)) ] \\ = E_{\tau} [ \Sigma_{t=0}^T \nabla_{\theta} \log(\pi_{\theta} (a_t|s_t)) \Phi_t] $$
直观含义为对每个选择的行动,用未来的奖励加上任意仅取决于当前状态的偏置来增减其概率,这个偏置 b 被称为 baseline (基线)。
选取基线为 on-policy 估值函数(定义见这里)直观上就是一个好的选择:这样影响行动概率的,不是未来的绝对回报,而是 关联到特定行动的实际回报 与 不指定行动的期望回报 的差值。
上个式子中的 $\Phi_t$ 还可以取成下面的结果,而不改变期望:
(变形1) On-Policy Action Value Function $Q(s_t, a_t)$,其定义见这里,证明见这里
(变形2) 因此,使用 Value Function $V(s_t)$ 作为 baseline,$\Phi_t$ 还可以是 Advantage Function $A(s_t,a_t) = Q(s_t, a_t) - V(s_t)$
Actor Critic 法是按照上一节第二个问答的思路进行的Reinforce算法的改进。改动的部分在于:需要同时建模估值 Q(s,a) 和策略 $\pi(s, a_i)$ ;我们使用单步的 Q(s,a) 而非整条轨迹估计出的 return 来更新策略(依据变形2)。
特别地,我们考察 Advantage Actor Critic 的参数更新方法:梯度为
$$ \nabla_{\theta} E[\log(\pi(s_t, a_t, \theta)) A(s_t, a_t)] $$
损失函数为
$$ E[\log(\pi(s_t, a_t, \theta)) A(s_t, a_t)] $$
将 log 概率替换为新策略和旧策略之间的比例函数 (ratio function):
$$ r_t(\theta) = \frac{\pi_{\theta}(a_t|s_t)} {\pi_{\theta_{old}}(a_t|s_t)} $$
损失函数就变成了目标函数
$$ E[r_t(\theta) A(s_t, a_t)] $$
对这个目标函数中的 $r_t(\theta)$ 进行截断,避免过大的策略变动,目标函数变为
$$ E[ \min( r_t(\theta) A(s_t,a_t), clip(r_t(\theta),1-\epsilon,1+\epsilon) A(s_t,a_t))] $$
之所以取 min,是为了提供对目标函数的悲观估计。例如,如果A>0,而 $r<1-\epsilon$,要返回更小的 $r*A$ 而非 $(1-\epsilon)*A$,此时虽然r在范围外,仍然更新策略,使得策略向 $[1-\epsilon, 1+\epsilon]$ 的范围靠拢。
SL 中的损失函数通常涉及采样 $x \sim P_{data}$,然后在这些样本上定义损失函数。$P_{data}$ 与模型参数无关。
RL,特别是策略梯度算法中,计算损失函数所依赖的数据点是依据最新策略采样得来的,与模型参数有关。
SL 中的损失函数通常(在测试数据上,或者训练数据上不考虑过拟合的条件下)是模型性能的体现。
RL,特别是策略梯度算法中,损失函数并不试图估计期望的 return,只不过是一个原函数,它关于模型参数的梯度恰好等于期望 return 的梯度。因此,不论将这个 "损失函数" 的值优化到多小,都不能得到任何关于模型性能的保证。
SL 中的方差-偏差权衡,一般指随着模型的复杂,模型的偏差减小,但输出更容易受到训练集中噪音的干扰,方差增加。
RL 中除了此关于模型复杂度的方差-偏差权衡之外,还有另一层与训练方法有关的权衡。
如果使用 Temporal Difference 时序差分类的训练方法,例如 Q-Learning 和 A2C Advantage Actor Critic 算法,对于 return 的估计是 Q 或 V 函数给出的。我们根据上一步的 Q 或 V 函数来计算梯度,进而更新参数(包括 Q 和 V 函数),这是一种自举法 Bootstrapping。
由于初始的 Q 和 V 是随机的,因此在训练开始时对 return 的估计是 bias 非常高的。
如果使用 Monte Carlo 类的训练方法,例如策略梯度,对于 return 的估计是完全通过和环境的(一整轮)交互得来的。这是一个蒙特卡洛采样,没有 bias,小样本数会导致高的方差。