Spinning Up 研究笔记 (一) - VPG
解决报错
代码文件在 spinup/alogs/pytorch/vpg/vpg.py
. 我们尝试运行代码, 然后就报错了…
1 | ... |
嗯, 先看篇这篇文章解决. 然后再次运行, 又报错… 这次又是啥 ?!
1 | ... |
观察了一下, 于是直接粗暴的删掉这一行 (就是这么任性) . 再次运行, 还是报错 ???
1 | ... |
这个问题我弄了好久, 最后发现好像是环境的问题, 我们将参数中 env
的值 HalfCheetah-v2
改为 CartPole-v0
, 也就是
1 | parser.add_argument('--env', type=str, default='HalfCheetah-v2') |
改成
1 | parser.add_argument('--env', type=str, default='CartPole-v0') |
然后再次运行. 终于, 成功运行了, 这下能够愉快的开启我们的代码研究之旅了.
Vanilla Policy Gradient
伪代码
使用 $\text{GAE-Lambda}$ (广义优势估计) 来进行优势估计. 因此需要拟合价值函数 $V^{\pi}(s_t)$ , 进而计算策略梯度进行优化. 有关广义优势估计的文章在这.
代码详解
VPGBuffer
1 | """ |
从注释以及变量名中我们可以看出 VPGBuffer
是用来储存采样轨迹的各种信息的.
store
储存轨迹中的变量, 一个很简单的函数.
finish_path
结束一个 epoch 时调用的函数, 用之前储存的变量来计算 adv_buf
(广义优势) 与ret_buf
(回报).
self.adv_buf
计算广义优势估计.
last_val
的作用是方便计算 deltas
, 而 deltas
就是 $\{\delta_1^V,\delta_2^V,\delta_3^V,\dots\}$ . (见广义优势估计)
其中计算优势时调用了一个重要的函数 core.discount_cumsum
这个函数在 core.poy
中有定义. 注释如下
1 | """ |
确实很 magic
. 而由于输入是 deltas
与 self.gamma * self.lam
而由注释看出计算的其实就是广义优势估计 $ \hat{A}_t^{\mathrm{GAE}(\gamma,\lambda)}$ .
self.ret_buf
计算有折损状态函数 $V^{\pi,\gamma}(s_t)$.
VPG
注释中已经详细介绍了参数的意义和作用. 中间有很多保存变量, 多线程的东西, 我们都略过, 只讲算法主体部分.
ac
1 | ac = actor_critic(env.observation_space, env.action_space, **ac_kwargs) |
由 actor_critic
对象生成, actor_critic
是对象 core.MLPActorCritic
, 该对象在 core.py
中被定义, 由其从 torch.nn.Module
继承可知这是个神经网络.
1 | class MLPActorCritic(nn.Module): |
self.pi
与 self.v
分别是动作函数与价值函数.
其中出现了判断 action_space
是 Box
还是 Discrete
类型的代码. Box
与 Discrete
都是 Space
对象, 描述当前动作或环境. 其中 Box
表示多维连续空间, Discrete
表示一维离散空间. MLPGaussianActor
与 MLPCategoricalActor
都分别刻画了一个神经网络. 其输入 obs_dim
个数据, 输出 action_space.n
或者 action_space.shape[0]
个数据, 并且隐层由 hidden_sizes
指定.
总之, ac
是两个神经网络的集合, 一个是动作函数, 一个是价值函数.
var_counts
查看定义, 其计算的是神经网络变量的个数 (激活函数也算) .
compute_loss_pi
计算动作的损失, 对参数求导正是参数的梯度.
对参数求导后相当于用了广义优势估计 adv
来估计梯度.
compute_loss_v
计算价值的损失, 采用了均方误差.
从返回值为 ((ac.v(obs) - ret)**2).mean()
可以看出其拟合的是 ret
变量 (对应广义优势估计中的 $V^{\pi,\gamma}(s_t)$), 也就是状态函数 (有折损的).
update
一个函数, 是一次 epoch 后更新参数的过程, 其中先优化策略 (pi_optimizer
) , 然后依据 train_v_tiers
(每次 epoch 优化价值函数参数的次数) 多次优化价值函数 (vf_optimizer
) .
训练过程
先在环境中 “走” 出一个 epoch (一个 epoch 的交互数 (interaction) 由 steps_per_epoch
指定), 然后调用 update
函数优化.