本文涉及的修改后源码请见:spinningup/spinup/algos/pytorch/sac at master · BITcsy/spinningup · GitHub. 中spinup/algos/pytorch/sac 下的修改内容。
1. spinning up环境配置
参考OpenAI Spinning Up 教程环境安装详解(包括mujoco-py + gym) - 知乎,一定要注意,因为spinning up过于古老了,所以最好是用conda搞一个干净的环境从头安装,而且必须使用python3.6来安装,不然各种跑不起来。我暂时不需要mojoco环境,先不考虑装了。
过程中,pip install安装高频失败,设置了以下pip的源:ubuntu下的pip镜像源设置办法(亲测好用)_ubuntu配置pip源_偏颇怪人的博客-CSDN博客
安装时,一直卡在opencv-python whl卡了半个小时,不过最后还是安装成功了。
在sac算法里,把env配置为Pendulum-v0 (原代码里用的是HalfCheetah-v2环境,不过我没有安装mojoco,考虑到这里面的原始sac算法支持的是连续性action,所以就用了Pendulum-v0),运行成功。
2. PendulumEnv-v0环境
因为spinningup推荐用是比较老的gym版本0.15.3,使用v0而不是v1,具体代码可以查gym源码里的tag Tags · openai/gym · GitHub。这个环境是一个一阶倒立摆,可以对一个杆施加扭矩,使其能稳定向上。
obs:theta, theta_dot
action: torque
step: 杆的动力学方程
reward = -cost ,cost是类似于最优控制的式子:theta^2 + 0.1*theta_dot^2 + 0.001 * torque ^2
3. SAC原理及代码
4.1 基本原理
原文:
Soft Actor-Critic:Off-Policy Maximum Entropy Deep Reinforcement Learning with a Stochastic Actor
Soft Actor-Critic Algorithms and Applications
入门版(论文中的基本公式都涵盖了,可以当作工具书来查公式):强化学习之SAC(soft actor-critic)算法_sac算法_王又又upupup的博客-CSDN博客
进阶版(关于理解和原理讲了很多,特别是为该算法叫soft,有比较深入的解释):最前沿:深度解读Soft Actor-Critic 算法 - 知乎
理论部分看上面的参考资料足够了。
4.2 spinning up代码
代码结构:loss计算,update,get_action这些都比较清楚,看源码即可GitHub - BITcsy/spinningup: An educational resource to help anyone learn deep reinforcement learning.我在spinning up的源码基础上增加了存gif的功能 + 用已有模型测试功能。分析源码,SAC的几个特性的体现:
- off-policy:整体探索过程还是用replay buffer存数,然后训练时在buffer里sample样本去学习。
- stochastic:在core.py里,actor的定义SquashedGaussianMLPActor是\( \mu \) 和 \( \sigma \) 的表示方法,在推理过程中,用确定状态\( \mu \)就好。
class SquashedGaussianMLPActor(nn.Module): def __init__(self, obs_dim, act_dim, hidden_sizes, activation, act_limit): super().__init__() self.net = mlp([obs_dim] + list(hidden_sizes), activation, activation) self.mu_layer = nn.Linear(hidden_sizes[-1], act_dim) self.log_std_layer = nn.Linear(hidden_sizes[-1], act_dim) self.act_limit = act_limit def forward(self, obs, deterministic=False, with_logprob=True): net_out = self.net(obs) mu = self.mu_layer(net_out) log_std = self.log_std_layer(net_out) log_std = torch.clamp(log_std, LOG_STD_MIN, LOG_STD_MAX) std = torch.exp(log_std) # Pre-squash distribution and sample pi_distribution = Normal(mu, std) if deterministic: # Only used for evaluating policy at test time. pi_action = mu else: pi_action = pi_distribution.rsample() if with_logprob: # Compute logprob from Gaussian, and then apply correction for Tanh squashing. # NOTE: The correction formula is a little bit magic. To get an understanding # of where it comes from, check out the original SAC paper (arXiv 1801.01290) # and look in appendix C. This is a more numerically-stable equivalent to Eq 21. # Try deriving it yourself as a (very difficult) exercise. :) logp_pi = pi_distribution.log_prob(pi_action).sum(axis=-1) logp_pi -= (2*(np.log(2) - pi_action - F.softplus(-2*pi_action))).sum(axis=1) else: logp_pi = None pi_action = torch.tanh(pi_action) pi_action = self.act_limit * pi_action return pi_action, logp_pi
- Logger:utils里自带了logger系统,可以通过plot来画图。EpochLogger,会在每个epoch结束时计算关键变量的平均值、最大值这些量,存在data文件夹下的progress.txt里,这个文件里的变量都可以画。EpRet指reward相关统计量,Q1、Q2为Q值,Pi为,还有loss Pi和loss Q。看了下Loss、LogPi都是收敛变小的,Q是变大的(对应于reward变大)。
python spinup/utils/plot.py --value=AverageTestEpRet
-
代码用了Double Q技巧
4. 实验结果
用PendulumEnv-v0 + spinning up原生的SAC的超参数,直接就搞定了(应该是因为这个环境太简单了)。Actor,Critic的Loss曲线(每个epoch平均),及Reward测试曲线如下,从reward上看训练的还不够好,当然RL训练本身因为样本的随机性,还是会有些震荡的,最后模型在Env是有效的。
场景的测试效果如下: