深度强化学习笔记之PPO实现细节(2)

本文主要参考于Coding PPO from Scratch with PyTorch系列,但本文并不会像该系列一样手把手讲解全部的实现细节,只是记录一下自己在实现过程中遇到的一些问题和思考。

下图是采用Clipped Surrogate Objective的PPO伪代码,本文的代码实现主要根据它来实现。

1.构建目标函数

PPO算法的实现重点,就是为了得到上图中的两个目标函数。也就是说,我们只要可以构造出式(1)和式(2)作为损失函数,基本就实现了PPO。
θk+1=arg⁡max⁡θ1∣Dk∣T∑τ∈Dk∑t=0Tmin⁡(πθ(at∣st)πθk(at∣st)Aπθk(st,at),g(ϵ,Aπθk(st,at)))(1)\theta_{k+1}=\arg \max_{\theta} \frac{1}{|D_k|T} \sum_{\tau \in D_k}\sum^T_{t=0}\min \bigg( \frac{\pi_{\theta}(a_t|s_t)}{\pi_{\theta_k}(a_t|s_t)}A^{\pi_{\theta_k}}(s_t,a_t), \; g(\epsilon, A^{\pi_{\theta_k}}(s_t,a_t)) \bigg) \tag1 θk+1​=argθmax​∣Dk​∣T1​τ∈Dk​∑​t=0∑T​min(πθk​​(at​∣st​)πθ​(at​∣st​)​Aπθk​​(st​,at​),g(ϵ,Aπθk​​(st​,at​)))(1)

ϕk+1=arg⁡min⁡ϕ1∣Dk∣T∑τ∈Dk∑t=0T(Vϕ(st)−R^t)2(2)\phi_{k+1}=\arg \min_{\phi} \frac{1}{|D_k|T} \sum_{\tau \in D_k}\sum^T_{t=0} \Big( V_{\phi}(s_t)-\hat{R}_t \Big)^2 \tag2 ϕk+1​=argϕmin​∣Dk​∣T1​τ∈Dk​∑​t=0∑T​(Vϕ​(st​)−R^t​)2(2)

在上式中,k是最外一层的主循环,可以理解为训练一轮PPO的次数,也就是PPO的更新次数;DkD_kDk​表示第k轮得到的轨迹集合,也就是这一轮PPO的训练资料。

PPO算法会写成"actor-critic"的形式,在具体实现时,会采用两个神经网络分别作为actor和critic的参数形式。在上式中,θ\thetaθ表示actor的参数,ϕ\phiϕ表示critic的参数。在这里,πθ(at∣st)\pi_{\theta}(a_t|s_t)πθ​(at​∣st​)和Vϕ(st)V_{\phi}(s_t)Vϕ​(st​)就是两个网络模型,输入为sts_tst​。

# actor-critic model
actor_model = FeedForwardNN(obs_dim, action_dim)  # At
critic_model = FeedForwardNN(obs_dim, 1)  # V(St)

若要构建式(1)和(2),则需要知道以下5个函数值:

  • πθ(at∣st)\pi_{\theta}(a_t|s_t)πθ​(at​∣st​),πθk(at∣st)\pi_{\theta_k}(a_t|s_t)πθk​​(at​∣st​),Vϕ(st)V_{\phi}(s_t)Vϕ​(st​),Aπθk(st,at)A^{\pi_{\theta_k}}(s_t,a_t)Aπθk​​(st​,at​),R^t\hat{R}_tR^t​

1.1.Actor

actor本质上就是policy,遵循policy gradient的准则进行策略更新。

如果action是连续的,那么actor会输出一个action的均值(维度与action相同),以此构建一个多维正态分布;如果action是离散的,那么actor则会输出每一个action的概率,以此构建一个Categorical分布。critic则只输出一个标量(表示输入observation的价值)。

from gym.spaces import Box, Discrete
from torch.distributions import MultivariateNormal, Categorical## action连续: Box(low=-1, high=1, shape=(2, ))
act_mean = actor_model(obs)
# 创建一个多维正态分布
dist = MultivariateNormal(loc=act_mean, covariance_matrix=cov_mat)
# 从该正态分布中采样得到一个action
action = dist.sample()
# 计算这个action的log概率
log_prob = dist.log_prob(action)  # log(pi)## action离散: Discrete(4)
act_probs = actor_model(obs)
dist = Categorical(act_probs)
# 从Categorical中采样得到一个action
action = dist.sample()
# 计算这个action的log概率
log_prob = dist.log_prob(action)  # log(pi)

以上程序描述了根据actor的输出计算action的概率(πθ(at∣st)\pi_{\theta}(a_t|s_t)πθ​(at​∣st​))的常规方法。可以发现,它并不是直接把actor的输出作为动作概率值的,而是以此构建了一个概率分布,然后从这个分布中采样并计算相应的log概率值。这里有两个问题需要注意:

  • 为什么需要构建概率分布:为了平衡探索和利用的矛盾,作用与ϵ−greedy\epsilon-greedyϵ−greedy方法相同;

  • 为什么输出log概率值:log函数可以把乘除法变成加减法,计算更加简单。
    log⁡πθ(at∣st)πθk(at∣st)=log⁡πθ(at∣st)−log⁡πθk(at∣st)\log{\frac{\pi_{\theta}(a_t|s_t)}{\pi_{\theta_k}(a_t|s_t)}}= \log{\pi_{\theta}(a_t|s_t)}-\log{\pi_{\theta_k}(a_t|s_t)} logπθk​​(at​∣st​)πθ​(at​∣st​)​=logπθ​(at​∣st​)−logπθk​​(at​∣st​)

1.2.Critic

Vϕ(st)V_{\phi}(s_t)Vϕ​(st​)的计算方式比较简单,就是critic的输出,表示状态sts_tst​的价值,不需要其它处理。

V = critic_model(batch_obs).squeeze()

1.3.Advantage function

Sometimes in RL, we don’t need to describe how good an action is in an absolute sense, but only how much better it is than others on average. That is to say, we want to know the relative advantage of that action. We make this concept precise with the advantage function.

在policy gradient中,优势函数Aπθ(st,at)A^{\pi_{\theta}}(s_t,a_t)Aπθ​(st​,at​)十分重要。它可以描述基于一个策略πθ\pi_{\theta}πθ​,在状态sts_tst​采取一个特定动作ata_tat​的相对价值。数学形式可以表示为
Aπθ(st,at)=Qπθ(st,at)−V(st)A^{\pi_{\theta}}(s_t,a_t)=Q^{\pi_{\theta}}(s_t,a_t)-V(s_t) Aπθ​(st​,at​)=Qπθ​(st​,at​)−V(st​)
上式中,V(st)V(s_t)V(st​)可以用critic估计得到,Qπθ(st,at)Q^{\pi_{\theta}}(s_t,a_t)Qπθ​(st​,at​)可以用下式计算得到
Qπθ(st,at)=rt+γ⋅rt+1+...+γT−t⋅rT=rt+γ⋅(rt+1+...+γT−t−1⋅rT)=rt+γ⋅Qπθ(st+1,at+1)(3)\begin{aligned} Q^{\pi_{\theta}}(s_t,a_t)&=r_t+\gamma \cdot r_{t+1}+...+\gamma^{T-t} \cdot r_{T} \\ &=r_t+\gamma \cdot(r_{t+1}+...+\gamma^{T-t-1} \cdot r_{T}) \\ &=r_t+\gamma \cdot Q^{\pi_{\theta}}(s_{t+1},a_{t+1}) \tag3 \end{aligned} Qπθ​(st​,at​)​=rt​+γ⋅rt+1​+...+γT−t⋅rT​=rt​+γ⋅(rt+1​+...+γT−t−1⋅rT​)=rt​+γ⋅Qπθ​(st+1​,at+1​)​(3)
以下程序描述了如何计算Q值,输入是一个列表,其中的每一个元素都是一条完整的奖励序列(r1,...,rT)(r_1,...,r_T)(r1​,...,rT​)。根据式(3),在实际计算时,我们应该以从后向前的顺序计算Q值。

def compute_rtgs(self, batch_rews):"""Compute the Reward-To-Go of each timestep in a batch given the rewards.:param batch_rews: [[r_1,r_2,...,r_T], [], ..., []]:return:"""batch_rtgs = []# 因为batch_rtgs是以将新元素插入到起始位置的形式添加新元素的,# 所以这里需要反向列表来保持顺序的一致for ep_rews in reversed(batch_rews):discounted_reward = 0  # The discounted reward so far# 这里反向的原因源于式(3)for rew in reversed(ep_rews):discounted_reward = rew + discounted_reward * self.gamma# 在列表的起始位置插入元素batch_rtgs.insert(0, discounted_reward)  # Convert the rewards-to-go into a tensorbatch_rtgs = torch.tensor(batch_rtgs, dtype=torch.float).to(self.device)return batch_rtgs

1.4.R^t\hat{R}_tR^t​

在参考源码中,R^t\hat{R}_tR^t​的取值与Qπθ(st,at)Q^{\pi_{\theta}}(s_t,a_t)Qπθ​(st​,at​)相同。我不知道是否还有别的方法可以表示R^t\hat{R}_tR^t​。

2.收集数据

PPO会使用上一轮的actor(πθk\pi_{\theta_k}πθk​​)与环境互动来收集训练数据。那么,具体应该收集哪些数据呢?

根据前文内容,可以很容易的知道,我们收集的数据需要包含以下内容:

  • 状态序列(s1,s2,...,sT−1)(s_1,s_2,...,s_{T-1})(s1​,s2​,...,sT−1​);
  • 动作序列(a1,a2,...,aT−1)(a_1,a_2,...,a_{T-1})(a1​,a2​,...,aT−1​);
  • 奖励序列(r1,r2,...,rT−1)(r_1,r_2,...,r_{T-1})(r1​,r2​,...,rT−1​);

以上都只是一个episode的内容。实际上,我们会收集多个episode的数据,然后一起训练。
Dk:{(s11,a11,r11,...,sT1−11),...,(s1n,a1n,r1n,...,sTn−1n)}D_k: \Big\{(s^1_1,a^1_1,r^1_1,...,s^1_{T_1-1}), ..., (s^n_1,a^n_1,r^n_1,...,s^n_{T_n-1})\Big\} Dk​:{(s11​,a11​,r11​,...,sT1​−11​),...,(s1n​,a1n​,r1n​,...,sTn​−1n​)}
如此,一个batch的状态和动作数据可以表示为
state batch:{s11,s21,...,sT1−11,...,s1n,s2n,...,sTn−1n}action batch:{a11,a21,...,aT1−11,...,a1n,a2n,...,aTn−1n}reward-to-go batch:{g11,g21,...,gT1−11,...,g1n,g2n,...,gTn−1n}\begin{aligned} \text{state batch}&: \Big\{ s^1_1,s^1_2,...,s^1_{T_1-1},...,s^n_1,s^n_2,...,s^n_{T_n-1} \Big\} \\ \text{action batch}&: \Big\{ a^1_1,a^1_2,...,a^1_{T_1-1},...,a^n_1,a^n_2,...,a^n_{T_n-1} \Big\} \\ \text{reward-to-go batch}&: \Big\{ g^1_1,g^1_2,...,g^1_{T_1-1},...,g^n_1,g^n_2,...,g^n_{T_n-1} \Big\} \\ \end{aligned} state batchaction batchreward-to-go batch​:{s11​,s21​,...,sT1​−11​,...,s1n​,s2n​,...,sTn​−1n​}:{a11​,a21​,...,aT1​−11​,...,a1n​,a2n​,...,aTn​−1n​}:{g11​,g21​,...,gT1​−11​,...,g1n​,g2n​,...,gTn​−1n​}​

  • 假设动作是连续的,参数为θk\theta_kθk​的actor接受state batch的输入,可以得到一个action的平均值,然后以此构建一个多维正态分布,得到log⁡πθk(at∣st)\log{\pi_{\theta_k}(a_t|s_t)}logπθk​​(at​∣st​);
  • 参数为ϕk\phi_{k}ϕk​的critic接受state batch的输入,可以得到一个状态的评价值Vϕk(st)V_{\phi_k}(s_t)Vϕk​​(st​);
  • 根据式(3),可以由奖励序列计算得到reward-to-go batch,也就是Qπθ(st,at)Q^{\pi_{\theta}}(s_t,a_t)Qπθ​(st​,at​)和R^t\hat{R}_tR^t​。前者可以用于计算Aπθk(st,at)A^{\pi_{\theta_k}}(s_t,a_t)Aπθk​​(st​,at​)。

由此,我们已经得到了第k轮全部的训练资料。

# collect trajectories by the past actor
batch_obs, batch_acts, batch_log_probs, batch_rtgs, batch_lens = self.collect_trajectories()# Calculate advantage at k-th iteration
V, _ = self.evaluate(batch_obs, batch_acts)
A_k = batch_rtgs - V.detach()  # ALG STEP 5# update PPO
for _ in range(self.update_time_per_iteration):  # ALG STEP 6 & 7# Calculate V_phi and pi_theta(a_t | s_t)V, curr_log_probs = self.evaluate(batch_obs, batch_acts)# Calculate the ratio pi_theta(a_t | s_t) / pi_theta_k(a_t | s_t)ratios = torch.exp(curr_log_probs - batch_log_probs)# Calculate surrogate losses.surr1 = ratios * A_ksurr2 = torch.clamp(ratios, 1 - self.clip, 1 + self.clip) * A_kactor_loss = (-torch.min(surr1, surr2)).mean()critic_loss = torch.nn.MSELoss()(V, batch_rtgs)self.actor_optimizer.zero_grad()actor_loss.backward()self.actor_optimizer.step()self.critic_optimizer.zero_grad()critic_loss.backward()self.critic_optimizer.step()

以上程序描述了完整的PPO的更新过程。可以发现,对于一笔训练资料,PPO并不是更新一次就结束了,而是会连续更新多次。这样可以加快训练速度,至于为什么可以这么做可以参考李宏毅老师关于PPO的视频,这里就不在赘述。

深度强化学习笔记之PPO实现细节(2)相关推荐

  1. 【李宏毅深度强化学习笔记】6、Actor-Critic、A2C、A3C、Pathwise Derivative Policy Gradient

    [李宏毅深度强化学习笔记]1.策略梯度方法(Policy Gradient) [李宏毅深度强化学习笔记]2.Proximal Policy Optimization (PPO) 算法 [李宏毅深度强化 ...

  2. 【李宏毅深度强化学习笔记】3、Q-learning(Basic Idea)

    [李宏毅深度强化学习笔记]1.策略梯度方法(Policy Gradient) [李宏毅深度强化学习笔记]2.Proximal Policy Optimization (PPO) 算法 [李宏毅深度强化 ...

  3. 【李宏毅深度强化学习笔记】5、Q-learning用于连续动作 (NAF算法)

    [李宏毅深度强化学习笔记]1.策略梯度方法(Policy Gradient) [李宏毅深度强化学习笔记]2.Proximal Policy Optimization (PPO) 算法 [李宏毅深度强化 ...

  4. 深度强化学习笔记(二)——Q-learning学习与二维寻路demo实现

    深度强化学习笔记(二)--Q-learning学习与二维寻路demo实现 文章目录 深度强化学习笔记(二)--Q-learning学习与二维寻路demo实现 前言 理论 什么是Q-Learning 算 ...

  5. CNTK与深度强化学习笔记: Cart Pole游戏示例

    CNTK与深度强化学习笔记之二: Cart Pole游戏示例 前言 前面一篇文章,CNTK与深度强化学习笔记之一: 环境搭建和基本概念,非常概要的介绍了CNTK,深度强化学习和DQN的一些基本概念.这 ...

  6. 深度强化学习笔记02-马尔可夫链

    深度强化学习笔记02-马尔可夫链 这几天杂事比较多,看了一些相关内容,但是没有时间形成笔记,此笔记复制与datawhale的MDP一节,后期自己学习填补. MDP [外链图片转存失败,源站可能有防盗链 ...

  7. 深度强化学习之:PPO训练红白机1942

    本篇是深度强化学习动手系列文章,自MyEncyclopedia公众号文章深度强化学习之:DQN训练超级玛丽闯关发布后收到不少关注和反馈,这一期,让我们实现目前主流深度强化学习算法PPO来打另一个红白机 ...

  8. 强化学习笔记:PPO 【近端策略优化(Proximal Policy Optimization)】

    1 前言 我们回顾一下policy network: 强化学习笔记:Policy-based Approach_UQI-LIUWJ的博客-CSDN博客 它先去跟环境互动,搜集很多的 路径τ.根据它搜集 ...

  9. 【深度强化学习】(6) PPO 模型解析,附Pytorch完整代码

    大家好,今天和各位分享一下深度强化学习中的近端策略优化算法(proximal policy optimization,PPO),并借助 OpenAI 的 gym 环境完成一个小案例,完整代码可以从我的 ...

最新文章

  1. 如何用Python和深度神经网络识别图像?
  2. 树莓派安装samba共享文件
  3. (006) java后台开发之基本数据类型
  4. 网络钓鱼者钓到威胁情报公司的身上 黑客惨遭溯源
  5. 9.1-微操作命令的分析(学习笔记)
  6. Java 泛型(generics)
  7. Redis笔记(七):Redis应用场景
  8. 加解密算法、消息摘要、消息认证技术、数字签名与公钥证书
  9. python散点图密度颜色_Python实现彩色散点图绘制(利用色带对散点图进行颜色渲染)...
  10. JAVA利用google的zxing快速生成QRCode
  11. 如何获得CSDN下载积分
  12. 网络工程师考试视频教程
  13. 日常生活中使用计算机要注意事项有哪些,笔记本电脑日常使用注意事项以及保养技巧...
  14. 手游推广,经营一家游戏公司需要多少人?
  15. 一个中关村IT男的房奴心路(转载)
  16. 09 Softmax回归
  17. [无私分享]最新网盘资源搜索站点
  18. 有力度、有速度更有温度,亚马逊献上史上最长黑五狂欢季
  19. QQ文件传输攻击工具
  20. 华为虚拟服务器 vrm,安装虚拟化管理服务器-VRM

热门文章

  1. SqlBulkCopy与临时表、普通Sql操作配合使用
  2. 合肥学计算机的职业学校,合肥计算机专业专科学校排名
  3. 如何快速查找网线-寻线仪
  4. 北京某公司新产品研发项目管理内训圆满结束!
  5. 总结出了这份Alibaba(P5-P9)学习进阶路线图用劲耗时两年才得!
  6. 酷比魔方i7手写版linux网卡驱动,酷比魔方手写板安装Ubuntu 16.04
  7. Google Earth Engine(GEE)扩展——gee-blend(图层影像加载)
  8. sqlserver常用语法大全
  9. 【推荐架构day8】美团推荐算法的实践篇
  10. 计算机开机故障报错,笔记本电脑开机报错故障的原因及解决办法