当前位置: 首页 > 工具软件 > PPO > 使用案例 >

强化学习之 PPO 算法

卫宁
2023-12-01
简述 PPO
        PPO 算法是一种基于策略的、使用两个神经网络的强化学习算法。通过将“智体”当前
的“状态”输入神经网络,最终会得到相应的“动作”和“奖励”,再根据“动作”来更新
“智体”的状态,根据包含有“奖励”和“动作”的目标函数,运用梯度上升来更新神经网
络中的权重参数,从而能得到使得总体奖励值更大的“动作”判断。
月球飞船降落
        本文根据 gym 来跑强化学习,在该游戏中,“状态”与“奖励”的更新都使用 gym 内部
封装的函数来实行,所以我们只需要考虑“状态”→“神经网络”→“动作”就行了。
        下载 gym 的步骤如下:
                pip install gym
                pip install box2d box2d-kengz --user
如果在 cmd 下安装不成功,建议在 Anaconda 中安装
神经网络
         PPO 算法需要使用到两个神经网络,其中一个网络我们命名为“actor_net ”,“状态”就是通过“actor_net ”做出了采取什么动作的判断;另一个网络我们叫它“critic_net”,进入这个网络的也是“状态”,但通过这个网络得到的是一个值“value”,具体作用我们后面会详述。正如前面所说,“状态”通过“actor_net ”会得到“动作”,然后根据 gym 自带的函数会返回给我们新的“状态”以及“奖励”;“状态”通过“critic_net”会得到一个“value”。 这里得到的“动作”是经过 softmax 后得到的一个概率值,再经过采样后会得到相应动作的索引值。将“状态”输入神经网络是一个“智体”与环境不断交互产生数据的阶段,这也是强化学习里数据的来源,要注意的有交互并不等于有训练。
数学公式
        在深度强化学习中,我们的最终目的就是要尽可能地让得到的总的奖励最大。但是,在
PPO 算法中我们的目标函数求出的并不是“奖励”的期望,而是求“奖励”期望。
        公式如下:
        期望就是把概率和求出的值相乘,目的是求出一个较为平均的数。在强化学习中,“状态”时刻都在变化,即使是同样权重参数,也可能得到不同的判断,如果只是求单一状态下奖励的最大值,无法得到理想的效果。所以 PPO 算法将目标函数设为求奖励的期望值,这样可以一个较为总体的结果。
        再根据大数定律,我们可以把目标函数直接看成每一次的“动作”与“奖励”相乘结果的求和求平均值,公式如下:这里求出的“动作”其实是实行该动作的概率值。
我们再来说说“奖励”。
我们并不是使用直接得到的“奖励”进行参数的更新。我们前面有提到“
critic_net ”网
络会得到一个“
value ”,这时候我们要做的是拿“奖励”减去“
value ”得到一个新的值,我
们用来参与训练的便是这个新的到的值。
因为在一般的交互过程中,很难会有奖励值为负,也就是惩罚产生,这样显然是不利于
训练流程的。同时,加大惩罚,可以让“智体”不断探索发现能带来更大奖励值的“动作”。
actor_net ”负责产生“动作”,从而产生“奖励”和新的“状态”。而产生用于调整“奖
励”的“
value ”值,就是“
critic_net ”任务。
参数更新
我们前面已经得到了求期望的公式,但这个公式并不是我们要使用的目标函数,我们还
要进行一些加工,最终得到了如下函数:
该式子求出了目标函数的梯度,最终我们可能根据梯度上升的思想来更新参数。
这里要注意的是,我们是根据每一次的“状态”、“动作”和“奖励”来更新参数,因此
必须要把每一次交互的数据记录下来,等参数更新之后再删除。
Of policy Off policy
        PPO 算法里的 policy 就是使用的神经网络, Of policy 就是有经过神经网络, Off policy
是不经过神经网络。
假设我们设定,在飞船降落月球的过程中,一次降落最多产生 300 次动作,而最多可以
降落 1000 次,这样的话“智体”就会与环境交互 30 万次。
前面有提到,参数的更新需要用到全部的数据,然后删除。但是,如果一整个流程就更
新了这么一次参数,不仅慢而且浪费。因为 PPO 算法采用了两个“智体”,也就是两套参数,
其中一套我们成为“打工人”钻进神经网络,不断与环境交互产生数据。另一个我们成为“大
少爷”,平时就呆着不动,等到交互达到一定次数时,比如我们可以设为 400 次,这个看我
们自己,“打工人”将自己收集到的数据传递给“大少爷”,“大少爷”就根据前面的公式进 行参数更新。
因为是用了别的“智体”代替自己与环境交互,所以这个代替的“智体”与本来的“智
体”差异绝对不能太大,不然最终结果会有偏差。这里的差异,主要看的是判断出“动作”
的差异,因此,可以用以下代码来做一个限制:
surr1 = ratios * advantages
surr2 = torch.clamp(ratios, 1-self.eps_clip, 1+self.eps_clip) * advantages
Surr1 就是直接求两个“智体”所得值得比例, surr2 则是加了一个限制,如果将 eps_clip
设为 0.2 ,意思就是比值差异不能超过 0.2 。求出两个 surr ,然后取它们中得最小值,再加一
个负号,这就是我们用到的损失函数,也是之前目标函数加工后得来的。
 类似资料: