Pytorch踩坑

前几天用Pytorch实现one-step的Actor-Critic算法的时候,遇到了坑,这里记录一下。

因为看的几版pytorch实现的Actor-Critic,代码风格都不是很符合个人习惯。因此,参照莫凡的tensorflow版Actor-Critic的网络结构,自己动手实现了一版Actor-Critci算法的demo。
具体的算法参考的是强化学习神作,Sutton的Rienforcement Learning: An Introduction 2nd中的第13章中的one-step Actor-Critic算法的伪代码。

为了和tensorflow版的代码进行对比,我把pytorch版本的网络结构设置的和tensorflow版本的结构一样,然后,对于网络参数的初始化,使用了相同的分布初始化权重,设置了相同的偏置。同时,包括学习速率$\alpha$和折扣因子$\gamma$的设置也保持一致。但是,最后两个模型的性能却差距巨大。

经过反复的检查以及向同学请教了关于tensorflow的一些知识(笔者对于tensorflow实在是不熟悉)之后,终于找到了两个导致这一诡异现象的BUG。

  1. optim.Adam()优化器重复初始化。

首先是第一点,这个BUG的原因是由于Adam算法本身的计算公式导致的。由于Adam算法是一种自适应学习率的优化算法,因此在整个优化的过程中,Adam需要更新记录优化器本身的两个参数。

具体的,Adam的计算公式如下:
$$m_t=\beta_1m_{t-1}+(1-\beta_1)g_t \\
v_t=\beta_2v_{t-1}+(1-\beta_2)g_t^2$$
其中,$g_t$是参数的梯度,$m_t$和$v_t$初始化为0向量,因此,需要进行偏差校正;
$$\hat m_t=\frac{m_t}{1-\beta_1^t} \\
\hat v_t=\frac{v_t}{1-\beta_2^t}$$
所以,最后Adam方法的梯度更新公式即为:
$$\theta_{t+1}=\theta_t-\frac{\eta}{\sqrt{\hat v_t}+\epsilon}\hat m_t$$
其中,$\beta_1=0.9,\ \beta_2=0.999,\ \epsilon=10^{-8},\ \eta=0.001$是超参数的建议取值。

所以,如果每次都重新初始化Adam优化器的话,最终的梯度更新公式就会变为$\theta_{t-1}=\theta_t-\eta$,梯度$g_t$被消掉了。所以,对于像Adam这种自适应学习率的优化器,只能在最开始的时候初始化一次。

  1. TD-error在反向传播中,Critic网络根据next state估计的next value是不能作为变量(Variable)参与计算的,应该是当作一个常量,在tensorflow中是一个占位符(placeholder),在pytorch中是一个require_grad=False的tensor。

解决的方法很简单:

1
2
3
4
#修改前
#TD_error = reward + gamma * next_value - value
#修改后
TD_error = reward + gamma * next_value.item() - value

以后遇到一些坑,也会记录在这里的。
<未完待续 To be continued>