Policy Gradients 思维决策
学习资料:
- 全部代码
- 什么是 Policy Gradient 短视频
- 模拟视频效果Youtube, Youku
- 强化学习实战
- 论文 Policy gradient methods for reinforcement learning with function approximation.
接着上节内容, 我们来实现 RL_brain
的 PolicyGradient
部分, 这也是 RL 的大脑部分, 负责决策和思考.
要代码主结构¶
用基本的 Policy gradient 算法, 和之前的 value-based 算法看上去很类似.
初始化¶
初始化时, 我们需要给出这些参数, 并创建一个神经网络.
建立 Policy 神经网络¶
这次我们要建立的神经网络是这样的:
因为这是强化学习, 所以神经网络中并没有我们熟知的监督学习中的 y label. 取而代之的是我们选的 action.
这里有必要解释一下为什么我们使用的 loss= -log(prob)*vt
当做 loss, 因为下面有很多评论说这里不理解. 简单来说, 上面提到了两种形式来计算 neg_log_prob
, 这两种形式是一模一样的, 只是第二个是第一个的展开形式. 如果你仔细看第一个形式, 这不就是在神经网络分类问题中的 cross-entropy 嘛! 使用 softmax 和神经网络的最后一层 logits 输出和真实标签 (self.tf_acts
) 对比的误差. 并将神经网络的参数按照这个真实标签改进. 这显然和一个分类问题没有太多区别. 我们能将这个 neg_log_prob
理解成 cross-entropy 的分类误差. 分类问题中的标签是真实 x 对应的 y, 而我们 Policy gradient 中, x 是 state, y 就是它按照这个 x 所做的动作号码. 所以也可以理解成, 它按照 x 做的动作永远是对的 (出来的动作永远是正确标签), 它也永远会按照这个 正确标签
修改自己的参数. 可是事实却不是这样, 他的动作不一定都是 正确标签
, 这就是强化学习(Policy gradient)和监督学习(classification)的不同.
为了确保这个动作真的是 正确标签
, 我们的 loss 在原本的 cross-entropy 形式上乘以 vt
, 用 vt
来告诉这个 cross-entropy 算出来的梯度是不是一个值得信任的梯度. 如果 vt
小, 或者是负的, 就说明这个梯度下降是一个错误的方向, 我们应该向着另一个方向更新参数, 如果这个 vt
是正的, 或很大, vt
就会称赞 cross-entropy 出来的梯度, 并朝着这个方向梯度下降. 下面有一张从 karpathy 大神 网页上扣下来的图, 也正是阐述的这个思想.
而不明白为什么是 loss=-log(prob)*vt
而不是 loss=-prob*vt
的朋友们, 下面留言有很多问道这个问题. 原因是这里的 prob
是从 softmax 出来的, 而计算神经网络里的所有参数梯度, 使用到的就是 cross-entropy, 然后将这个梯度乘以 vt
来控制梯度下降的方向和力度. 而我上面使用 neg_log_prob
这个名字只是为了区分这不是真正意义上的 cross-entropy, 因为标签不是真标签. 我在下面提供一些扩展链接.
选行为¶
这个行为不再是用 Q value 来选定的, 而是用概率来选定. 即使不用 epsilon-greedy, 也具有一定的随机性.
存储回合¶
这一部很简单, 就是将这一步的 observation
, action
, reward
加到列表中去. 因为本回合完毕之后要清空列表, 然后存储下一回合的数据, 所以我们会在 learn()
当中进行清空列表的动作.
学习¶
本节的 learn()
很简单, 首先我们要对这回合的所有 reward
动动手脚, 使他变得更适合被学习. 第一就是随着时间推进, 用 gamma
衰减未来的 reward
, 然后为了一定程度上减小 policy gradient 回合 variance, 我们标准化回合的 state-action value 依据在 Andrej Karpathy 的 blog.
我们再来看看这个 discounted_ep_rs_norm
到底长什么样, 不知道大家还记不记得上节内容的这一段:
我们看看这一段的输出, vt
也就是 discounted_ep_rs_norm
, 看他是怎么样诱导我们的 gradient descent.
可以看出, 左边一段的 vt
有较高的值, 右边较低, 这就是 vt
在说:
请重视我这回合开始时的一系列动作, 因为前面一段时间杆子还没有掉下来. 而且请惩罚我之后的一系列动作, 因为后面的动作让杆子掉下来了
或者是
我每次都想让这个动作在下一次增加被做的可能性 (
grad(log(Policy))
), 但是增加可能性的这种做法是好还是坏呢? 这就要由 vt
告诉我了, 所以后段时间的 增加可能性
做法并没有被提倡, 而前段时间的 增加可能性
做法是被提倡的.
这样 vt
就能在这里 loss = tf.reduce_mean(log_prob * self.tf_vt)
诱导 gradient descent 朝着正确的方向发展了.
如果你玩了下 MountainCar
的模拟程序, 你会发现 MountainCar
模拟程序中的 vt
长这样:
这张图在说: 请重视我这回合最后的一系列动作, 因为这一系列动作让我爬上了山. 而且请惩罚我开始的一系列动作, 因为这些动作没能让我爬上山
.
也是通过这些 vt
来诱导梯度下降的方向.
最后是如何用算法实现对未来 reward 的衰减.
如果想一次性看到全部代码, 请去我的 Github