学习自李宏毅与蘑菇书。蘑菇书链接:蘑菇书 EasyRL (datawhalechina.github.io)
搭配李宏毅的强化学习课程使用最佳。
这篇博文内容结合了自己的理解,不可避免地会存在不当,欢迎指正。
# 情景定义
智能体 Actor
、环境 Environment
与奖励 Reward
。在后面的内容中,你都可以将智能体理解为玩游戏的机器人,将环境理解为游戏主机,奖励理解为机器人玩游戏干掉怪兽得到的分数。
# 策略梯度算法(Policy gradient Algorithm)
智能体通常作为 Actor
,在 策略 不断调整与指引下使得其在环境重获取到最大的奖励。策略在具体的实现上,现代强化学习通常用网络替代之。在前面的比喻中,你可以将策略理解为机器人取得高分的方法和手段。
# 符号定义
符号 | 释义 |
---|
t | 同一时间下的某个状态 |
T | 某个轨迹下的所有状态数 |
at | 某个状态下智能体的动作 |
st | 某个状态下的环境 |
θ | 智能体的策略模型参数 |
rt | 某个状态下智能体采取动作后的奖励 |
τi | 某次轨迹:所有状态的环境与动作的组合。\tau=\ |
p | 概率 |
R | 总奖励 |
# 手推策略梯度公式
给定智能体 Actor
的参数θ,可以计算轨迹τ 的发生的概率:
pθ(τ)=p(s1)pθ(a1∣s1)p(s2∣s1,a1)pθ(a2∣s2)p(s3∣s2,a2)⋯=p(s1)t=1∏Tpθ(at∣st)p(st+1∣st,at)(1.1)
pθ(a1∣s1) 是策略里面的网络参数θ 决定的、观察到环境s1 后采取的动作概率。因此策略网络的输出是一个分布,是智能体采取动作的概率分布。p(s2∣s1,a1) 是环境根据前一个环境的状态和智能体的动作给出的下一个环境状态,通常是环境内部的规则决定。
一个轨迹τ 会在某个时刻终止,其内部的每一个st 和at 的组合均能够产生对应的奖励rt。所以,所有的组合能够得到一个关于这个轨迹的总奖励R(τ)。
我们的目的就是要调整策略网络的参数θ 使得总奖励R(τ) 越大越好。因此,R(τ) 是一个随机的变量,我们可以计算R(τ):
R(τ)=t=1∑Trtpt(rt∣st,at)(1.2)
当策略参数θ 给定,那么在这组参数上一定有一个关于轨迹的分布pθ(τ),智能体的多次尝试都是一个轨迹。对于所有的轨迹τi,存在总奖励Rθ 的期望值为:
Rθ=τ∑R(τ)pθ(τ)=Eτ∼pθ(τ)[R(τ)](1.3)
为了让 期望奖励 越大越好,要进行 梯度上升 。所以要计算期望奖励关于策略参数θ 的梯度:
∇Rθ=τ∑R(τ)∇pθ(τ)∵∇f(x)=f(x)∇logf(x)(不难证得)∴pθ(τ)∇pθ(τ)=∇logpθ(τ)
因此有:
∇Rθ=τ∑R(τ)pθ(τ)pθ(τ)∇pθ(τ)=τ∑R(τ)pθ(τ)∇logpθ(τ)=Eτ∼pθ(τ)[R(τ)∇logpθ(τ)]
但是在实际上,我们是无法直接和准确地求期望值Eτ∼pθ(τ)[R(τ)∇logpθ(τ)] 的。但是我们可以通过采样 N
个τ,然后计算R(τ)∇logpθ(τ) 的 N
个和,来近似地得到这个期望:
∇Rθ=Eτ∼pθ(τ)[R(τ)∇logpθ(τ)]≈N1n=1∑NR(τn)∇logpθ(τn)=N1n=1∑Nt=1∑TnR(τn)∇logpθ(atn∣stn)(1.4)
得到最后一行的原因,是因为∇logpθ(τn) 可以被展开:
∇logpθ(τn)=∇(logp(s1)+t=1∑Tlogpθ(at∣st)+t=1∑Tlogp(st+1∣st,at))=∇logp(s1)+∇t=1∑Tlogpθ(at∣st)+∇t=1∑Tlogp(st+1∣st,at)
因为,p(s1) 和p(st+1∣st,at) 来自环境,与智能体的策略参数θ 无关,因此第一项和第三项为 0,原式化简:
=∇t=1∑Tlogpθ(at∣st)=t=1∑T∇logpθ(at∣st)
# 训练思路
现在整理一下思路。在给出一个初始策略参数θ 的情况下,经过训练,我们要得到一个不错的策略参数θ,使得智能体在多个轨迹下得到的总奖励Rθ 最大化。如何优化这个θ 呢?我们可以通过梯度上升法优化这个θ,使得当st 状态下执行at 导致R(τ) 增大时增加在st 下执行at 的概率,反之减小这个概率:
θ←θ+η∇Rθ(1.5)
根据公式 1.4 和公式 1.5,我们知道优化θ 的关键在于求出∇Rθ,与∇Rθ 有关的是stn、atn 和τn。所以我们要采集这些数据:
τ1:(s11,a11)R(τ1)(s21,a21)R(τ1)(s31,a31)R(τ1)⋮⋮τ2:(s12,a12)R(τ2)(s22,a22)R(τ2)(s32,a32)R(τ2)⋮⋮
τ 的采集量是人为设定的,采集完一次后,会获得多组τ 的数据,然后使用公式 1.4 和公式 1.5 一次性更新模型:
![image]()
# 直观理解
如何直观理解公式 1.4?既然我们要通过求出∇Rθ 来得到θ 的更新值,就不得不依赖反向传播得到梯度。你可以想象这样一个场景:智能体在玩一个游戏,控制一个飞机射击外星人,它的策略θ 是智能体内部的网络 NN
( Neural Network
),在游戏过程中保持不变(游戏过程就是在采样若干组轨迹的 s
, a
, R
($$\tau$$) 对),智能体看到场景s,送给策略网络 NN
计算出要做的动作a 的概率。如,向左移动的概率,向右移动的概率,开火的概率,所以这本质上是一个分类问题。
![]()
通常在训练过程中,我们需要智能体根据当前场景做出的动作是人为指定的,也就是说对于某个轨迹τ 的一个特定的s 有个 Ground-Truth
,这个 Ground-Truth
就是在这个特定场景应该做出的动作a。比如,在某个场景st 下,我们想要智能体向左,于是标签就是 [1, 0, 0]
。智能体将st 作为策略网络θ 的输入,估计出向左的概率要尽可能接近 1,即pθ(at∣st) 要尽可能接近 1。
所以,在采样过程中,大量的stn 计算出大量的pθ(at∣st),那么根据每个st 的标签,就能够计算一个交叉熵损失( cross entropy loss
),最小化交叉熵损失就是在最大化似然:
Loss=−t=1∑Tyiy^iMin(Loss)=Min(−t=1∑Tyiy^i)=Max(t=1∑Tyipθ(at∣st))∵yi是常数1∴Min(Loss)=Max(t=1∑Tpθ(at∣st))=Max(t=1∑Tlogpθ(at∣st))
所以,在训练过程中,最小化交叉熵损失,实际上在最大化某个轨迹的预测值的和。观察上面的式子,有没有发现在最小化损失,实际上在最大化∇Rθ。
在计算出损失后,通过反向传播,可以直接计算出∇Rθ 的值,因此就能更新参数θ 了。
# 实现上的一些技巧
# 添加基线
我们总是希望,对于某一给定的状态s 采取动作a 后,整场游戏τ 获得的奖励是正的,我们就增加(s,a) 的概率。如果这个给定的状态s 采取的动作a 使得最后整场游戏τ 的奖励是负的,我们就减小(s,a) 的概率。
理想情况是这样,现实是虽然这些动作对整场游戏τ 的奖励贡献有大有小,但整场游戏下来的奖励总是非负的,有的动作采取后得到了 20 分,有的动作采取后得到 0 分。这种情况下,一场游戏的奖励R(τ) 总是正的,最低也只是 0,而且要求提升贡献度大的动作的概率,降低贡献度低的动作的概率。
另外一个现实是,由于本质上一个轨迹τ 只是在轨迹空间pθ(τ) 的一个采样,所以采样的数量较少时,一些动作可能未被采样到。那么相较于其他被采样到的动作而言,这个未被采样到的动作的概率就会被下降。这并不意味着这个未被采样到的动作贡献更小,仅仅只是未被采样到而已。相反,贡献度低的动作因为奖励总是正的、经常被采样到,所以概率提升地比未被采样、但贡献度高的动作幅度大。这就导致了不公平的出现。
![image]()
奖励总是正的,就会导致丈量动作的贡献度相较于奖励有正有负而更加困难。除此之外,还引出了概率提升膨胀的问题,未被采样到的动作的概率不升反降,而其他采样到的动作因为奖励总是正的而概率得到很大幅度的提升。
为了解决这个问题,可以把奖励减去一个基线 b
:
∇Rθ≈N1n=1∑Nt=1∑Tn(R(τn)−b)∇logpθ(atn∣stn)(1.5)
此时总奖励就是R(τn)−b。我们可以令b≈E[R(τ)],也就是说,我们在训练中不断地将R(τ) 的值记录下来,然后不断地记录R(τ) 的平均值,将这个平均值当作b 来使用。这样一来,总奖励R(τn)−b 就会有正有负。
# 分配合适的分数
观察公式 1.5,只要在同一场游戏里(同一轨迹),所有的动作 - 状态对都要使用同样的奖励权重进行加权。也就是说,对于(a11,s11),(a21,s21),(a31,s31),...,(aT1,sT1) 都使用R(τ1)−b 进行加权,当n=2 时同理。
这是不公平的,在蘑菇书中结合例子解释的非常深入浅出。简单来说就是,一场游戏的结果是好的,并不意味着每一个采取的动作都是好的。相反,若是整场游戏的结果不好,并不代表每一个动作都是不好的。
一种解决办法是,计算某个动作状态对的奖励权重时,不把整场游戏的奖励加起来,而是只计算从这个动作执行以后到整场游戏结束时得到的奖励。这样做是因为这个动作执行之前发生的事情是与这个动作没有关系的,所以执行当前这个动作之前所获得的所有奖励都不能算作是当前这个动作的贡献。将执行这个动作后获得所有奖励加起来,才算做这个动作真正的贡献。
![image]()
比如,这张图(sa,a1) 的权重是(+5+0−2)=+3,(sb,a2) 的权重是(+0−2)=−2。即使是第二场游戏也是如此规律。
于是,重写公式 1.5:
∇Rθ≈N1n=1∑Nt=1∑Tn(t′=t∑Tnrt′n−b)∇logpθ(atn∣stn)(1.6)
原来的权重是整场游戏的奖励的总和,现在改成从某个时刻t 开始,假设这个动作是在开t 始执行的,从t 一直到游戏结束所有奖励的总和才能代表这个动作的好坏。
进一步,我们可以为未来的奖励做折扣,继续改写公式 1.6:
∇Rθ≈N1n=1∑Nt=1∑Tn(t′=t∑Tnγt′−trt′n−b)∇logpθ(atn∣stn)(1.7)
为什么为未来时刻的奖励乘一个系数做折扣?因为当前时刻动作对下一时刻影响较大,但是随着时间推移,到某一时刻t 时所受那个动作影响就越来越小。可以取系数γ=0.9或0.99∈[0,1]。例如,假设游戏有两个回合,我们在游戏的第二回合的某一个 st 执行at 得到 + 1 分,在st+1 执行at+1 得到 + 3 分,在st+2 执行at+2 得到−5 分,第二回合结束。at 的分数应该是:1+γ×3+γ2×(−5)。
# 优势函数与评论员
观察公式 1.7。事实上,b 通常是一个网络估计出来的,是一个网络的输出。而∑t′=tTnγt′−trt′n−b 这一项通常简写为Aθ(st,at),被称为优势函数。此时,公式 1.7 又可以写成:
∇Rθ=Eτ∼pθ(τ)[R(τ)∇logpθ(τ)]≈N1n=1∑Nt=1∑TnAθ(st,at)∇logpθ(atn∣stn)(1.8)
这个优势函数也通常可以被一个网络估计出来,这个网络被称为评论员。优势函数的意义是,在某个特定状态st 下采取动作at,相较于其他可能执行的动作,at 有多好。这个优势函数作为权重反映了动作相对的好,而不是绝对的好。
# 近端策略优化算法(PPO)
# On Policy to Off Policy
# 深度 Q 网络