junxiaosong / AlphaZero_Gomoku

An implementation of the AlphaZero algorithm for Gomoku (also called Gobang or Five in a Row)
MIT License
3.28k stars 964 forks source link

MCTS最终得出的行为%pi的问题 #24

Open xiaoyangzai opened 6 years ago

xiaoyangzai commented 6 years ago

在敲你的代码过程中遇到了两个问题,麻烦您给指导一下:

  1. 根据AlphaGo Zero论文中的描述,在MCTS的backup过程中,首先根据policy-value network得到叶子节点的p,v,之后使用v来更新各个树内节点的Q值。在你的代码中使用的是函数update_recursive(leaf_value),这其中的leaf_value应该就是论文中该叶子节点的v对吧?为什么在mcts_alphazero.py的66行和137行代码中该函数传递的是 负的leaf_value,而不是正的?是不是AlphaZero的backup方式与AlphaGo Zero不同呢?我在看AlphaZero论文的时候没有看到这些细节的东西,希望能够得到你的指点。
  2. 针对每个状态的MCTS结束的时候会输出一个策略%pi,根据AlphaGo Zero论文中的描述,最终这个策略的公式是跟行为的执行次数和temp有关的,对应的应该是你的代码中函数softmax完成的功能,这个函数化简的结果确实是论文中的公式,但是为什么要减去最大值,即probs = np.exp(x - np.max(x)),而不是直接按照论文给出的公式计算各个行为的概率呢?
  3. 在selfplay时候,AlphaGo Zero论文中给行为增加noise中使用Dir(0.03)分布,而代码中使用的参数值为0.3,不知道这块怎么理解?
  4. 我看了AlphaGo Zero和AlphaZero的论文,还是没有明白这两个方法的区别,能否满烦你给指点指点!! 拜托了!!!!!!谢谢你的分享!
junxiaosong commented 6 years ago
  1. 按照我个人的理解,在MCTS里,一个node的Q-value确实是和这个node对应的局面评估值相反的,因为一个node的Q-value是给它的父节点选择分支的时候用的,所以这个Q-value是从node的父节点对应的player的视角来看的,node从自身角度看当前局面很好的话那么从父节点的角度看那个局面就很不好,因为两者是对手关系。
  2. 这边减去最大值只是为了数值计算的稳定性,其实减不减最大值在数学上都是等价的,因为分子分母都会同时变化。
  3. 按照AlphaZero论文里的描述,这个Dir中的参数的选择一般和每一步可能的动作数成反比,围棋里平均下来每一步可行动作可能有200,而我们现在的小棋盘五子棋平均下来每一步可行动作就几十个,所以这边用了0.3
  4. 两者确实区别不大的,最大的区别在于AlphaGo Zero里self-play数据由历史最优policy生成,然后用这个数据不停的训练另外的一个policy,并定期通过对战评估当前训练的policy和最优policy的优劣,如果当前训练的policy对最优policy胜率超过55%,则更新最优policy;而AlphaZero里只维护一个policy网络,self-play数据由这个网络生成,用于不停的训练更新这个网络,整体流程更加简单了
xiaoyangzai commented 6 years ago

非常非常感谢你的指教,我今天再次详细看了一下蒙特卡洛搜索树的知识,有了一个新的认识:蒙特卡洛树搜索分为选择,模拟或者评估,反向更新,最后最终在返回root下访问最多的move; 我之前一直认为在选择阶段,使用树内的策略即a = argmax(Q + U),而经过仔细研究之后发现,在两人对弈游戏的MCTS的选择阶段是两个竞争对手相互选择最优的行为,那么在选择阶段选择行为的时候,是否应该根据不同对手的视角选择最优行为,并且更新树内节点的Q值也是不同的选手更新的方式不一样,即update_recursive(-leaf_value);如果是按照不同选手来更新Q值的话,那么每次选择阶段选择行为时采用a = argmax(Q + U)策略即可得到两个竞争对手各自的最优行为,因为节点的Q值是根据相应的选手来更新的。

如果说我的想法是对的话,那么在反向更新阶段,应该根据选手的视角传递正的leaf_value或负的leaf_value来更新搜索树内各个选手对应做出选择的节点中的Q,获胜选手的节点+leaf_value,失败的选手的节点-leaf_value,那么代码中是否应该判断一下某个节点是对手的还是自己的节点来更新Q值呢? 另外就是在AlphaZero论文中没有提到这些东西,是不是我的那块理解错了?

最近这段时间看到这块的内容都没有人可以问,真是非常感谢你的指教!!!!

junxiaosong commented 6 years ago

对的,MCTS在搜索的时候其实也是Minimax的思想,双方交替的选择对自己最有利的(或者说对对方最不利的),但因为我们在选择步骤统一用的a = argmax(Q + U),所以我们在更新Q的时候就需要考虑视角的问题,不过在双方对弈的过程中,视角是交替的,所以这边没有显式的去判断某个节点时对手的还是自己的,只是在反向更新的时候一层一层交替取反了。

KelleyYin commented 6 years ago

@junxiaosong 非常感谢你的解答。我想问几个问题: 第一,mcts用在棋类游戏,会有对手之间的竞争。我现在改变了应用场景,没有对手,那么update_recursive(-leaf_value)是不是就可以改成update_recursive(leaf_value)? 第二,self-play 往往需要花费大量时间,我们是不是可以用分布式来加速呢?比如,多进程加速模拟。

junxiaosong commented 6 years ago

@KelleyYin 我不确定在你的应用场景是不是可以直接用leaf_value,还是建议你在理解MCTS的基础上灵活处理吧,反正都可以试的嘛。另外self-play可以分布式来加速的,DeepMind他们就用了5000个TPU来生成self-play数据