最近自己写这个五子棋的强化学习AI遇到了很多困难,而且在如何使用训练结果来指导蒙特卡洛搜索方面遇到了障碍。又重新回看了这个AlphaZero-Gomuku项目的源码,从中学到了很多东西,以及许多遇到的问题的具体解决方案。啊啊啊,好后悔,应该早点回去看的。(当然,源码还是有一些地方没有看明白)
在之前写过的博文面向初学者的蒙特卡洛树搜索MCTS详解及其实现中,我们已经讲了如何基于UCB进行探索和利用,以及蒙特卡洛搜索的四个基本操作——选择,扩展,模拟和反向传播。下面一个问题就是如何利用我们预先训练的神经网络来指导蒙特卡洛的搜索了。
我们再次回顾UCB公式:
在上述公式中,vi代表的是蒙特卡洛搜索的平均价值。C是一个常数,N是其父节点的访问次数,ni是当前节点的访问次数。显然vi,对应的就是critic输出的value的平均值,而C我们可以把其看作当前情况下输出的action probability,也就是一个prior p。另外,在AlphaGoZero的论文中,对N没有取log。因此最后公式变为:
UCB = vi + C*prior_p*sqrt(N/ni+1)。我们依然保留了一个C作为常数。
理解一下这个公式的含义,当我们还未进行任何尝试的时候,UCB=prior_p,优先探索概率高的地方,随着探索的进行,我们的探索会越来越接近真实的情况。至于为什么公式要这么改,我也不知道~。
下面看一下源码中的实现:
get_value这个函数返回的是UCB值
def get_value(self, c_puct):
"""Calculate and return the value for this node.
It is a combination of leaf evaluations Q, and this node's prior
adjusted for its visit count, u.
c_puct: a number in (0, inf) controlling the relative impact of
value Q, and prior probability P, on this node's score.
"""
self._u = (c_puct * self._P *
np.sqrt(self._parent._n_visits) / (1 + self._n_visits))
return self._Q + self._u
value的值是蒙特卡洛搜索所有value的的平均值
def update(self, leaf_value):
"""Update node values from leaf evaluation.
leaf_value: the value of subtree evaluation from the current player's
perspective.
"""
# Count visit.
self._n_visits += 1
# Update Q, a running average of values for all visits.
self._Q += 1.0*(leaf_value - self._Q) / self._n_visits