对应:Stanford CS234 Lecture 15(Monte Carlo Tree Search, AlphaGo) 配套代码:
code/lecture14/(只需 numpy) 预计阅读时间:3.5 小时
0. 本讲导航
0.1 本讲要回答的问题
当世界的规则完全已知,但状态多到无法枚举时,怎样做出高质量的决策?
2016 年 3 月,AlphaGo 以 4:1 击败世界顶尖棋手李世石。在此之前,很多人认为计算机下围棋达到人类顶尖水平还需要十年。围棋的规则极其简单,模型完全已知——但它约有 个合法局面,比宇宙中的原子数还多得多。第 2 讲的动态规划需要遍历所有状态,完全不可能。
这一讲讲述 AlphaGo 背后的两个关键思想:
- 只为当前局面做规划:不求全局的最优策略,只在当前局面附近向前搜索。
- 有选择地搜索:用模拟来评估局面,用 UCB(第 11 讲!)决定搜索树往哪里生长——这就是蒙特卡洛树搜索(MCTS)。
然后我们会看到 AlphaGo Zero / AlphaZero 如何把 MCTS 与深度学习、自我对弈结合起来:网络提供直觉,搜索提供深思熟虑,自我对弈让两者互相提升。
0.2 学完本讲,你应该能够
- 区分全局规划(动态规划)与前向搜索;描述极小极大、negamax、α-β 剪枝。
- 解释为什么有限深度搜索需要评估函数,以及它的代价。
- 解释平坦蒙特卡洛的系统性偏差,以及”树”如何解决它。
- 完整描述 MCTS 的四个步骤和 UCT 的树策略。
- 描述 AlphaGo、AlphaGo Zero、AlphaZero 的演化,写出 PUCT 公式和 AlphaZero 的训练目标。
- 用策略迭代的观点解释”自我对弈 + MCTS”为什么能不断变强。
0.3 先修知识
| 知识点 | 用在哪里 | 最低要求 |
|---|---|---|
| 第 2 讲:动态规划、策略迭代 | 第 1、6 节 | 必须 |
| 第 3 讲:蒙特卡洛评估 | 第 2 节 | 必须 |
| 第 6 讲:策略梯度 | 第 5 节(AlphaGo) | 了解即可 |
| 第 8 讲:行为克隆、DAgger | 第 6 节 | 了解即可 |
| 第 11 讲:UCB | 第 3 节 | 必须 |
| 递归 | 第 1 节 | 知道”函数调用自己”即可 |
0.4 本讲地图
第1节 前向搜索:博弈树、极小极大、α-β 剪枝、有限深度 + 评估函数
│
第2节 蒙特卡洛评估:随机走子;平坦蒙特卡洛的偏差
│
第3节 蒙特卡洛树搜索:四个步骤;UCT;为什么"树"很关键
│
第4节 MCTS 的实验与实践细节
│
第5节 AlphaGo → AlphaGo Zero → AlphaZero → MuZero
│
第6节 为什么自我对弈 + 搜索能不断变强:策略迭代的视角
0.5 本讲的实验平台:井字棋
围棋太大,没法验证一个搜索算法”下得对不对”。井字棋只有 4520 个未结束的局面,可以用极小极大精确地算出每个局面的最优着法——给了我们一个”标准答案”。评测时主要使用 3191 个关键局面:至少有一步会让结果变差的局面(其余局面怎么下都一样)。算法与围棋中用的完全相同,只是规模小得多。代码见 tictactoe.py。
1. 前向搜索
1.1 从全局规划到前向搜索
第 2 讲的动态规划计算所有状态的价值。但下棋时,我们只关心”当前这个局面该怎么走”。
前向搜索:从当前状态出发,把”我走这步、对手走那步、我再走……”展开成一棵树,从叶子往回算出每一步的价值。只涉及从当前状态能到达的状态,这比全部状态少得多——但仍然随深度指数增长。
1.2 极小极大与 negamax
两人零和博弈中,我想最大化我的结果,对手想最小化它:
negamax 写法把两者统一:从”轮到走棋的一方”的角度定义价值,对手的好就是我的坏:
这就是第 2 讲的贝尔曼最优方程在双人博弈中的形式(没有折扣,奖励只在终局出现)。
代码 01_minimax_search.py 演示 1–2:
- 井字棋的完整博弈树有 549,946 个节点、255,168 局不同的对局;但不同的未结束局面只有 4,520 个——同一个局面可以由不同的走棋顺序到达。记忆化(国际象棋程序中叫”置换表”)能省下一百多倍的计算。
- 空棋盘的价值是 0:双方完美下棋是和棋。
- 一个局面(X 在 0、8,O 在 4,轮到 O):走边(1、3、5、7)和棋,走角(2、6)会输——走角之后,X 可以一步同时制造两个威胁(“双杀”)。这种”看起来很自然、其实会输”的着法,需要往前看好几步才能发现。
1.3 α-β 剪枝
思想:维护一个窗口 —— 是”我已经确定能拿到的最好结果”, 是”对手已经确定能把我压到的最坏结果”。如果某个分支的价值已经 ,对手绝不会让棋局走到这里,剩下的着法不用看了。
演示 3:结果与极小极大完全相同,但只访问了 18,297 个节点(按编号顺序)或 7,275 个节点(按”中心、角、边”的顺序),而完整的树有 549,946 个。着法顺序越好,剪掉的越多;最理想时,同样的计算量能搜索大约两倍的深度。1997 年击败卡斯帕罗夫的”深蓝”,核心就是 α-β 搜索 + 人工设计的评估函数。
1.4 有限深度 + 评估函数
即使有剪枝,完整搜索围棋仍然不可能。常用的办法:只往前看 步,到达深度限制时用一个评估函数估计局面的价值——这正是价值函数的近似。
演示 4:用一个简单的人工评估函数(按每条线上双方棋子的情况打分),在 3191 个关键局面上:
| 深度 | 选到最优着法的比例 | 从空棋盘搜索的节点数 |
|---|---|---|
| 1 | 96.1% | 9 |
| 2 | 96.8% | 81 |
| 3 | 98.2% | 585 |
| 4 | 99.2% | 3,609 |
| 5 | 99.6% | 18,729 |
| 9(完整) | 100.0% | 549,945 |
- 看得越深越好,但节点数指数增长(每深一层乘以 5~9)。
- 这个评估函数设计得不错,深度 1 就有 96%——好的评估函数能大大减少所需的搜索。
两个出路,正是本讲的两个主题:
- 不要平均地展开每个分支,把计算集中在有希望的着法上——MCTS;
- 用更好的评估函数,看得浅一些也能判断准确——从数据中学出来的价值网络。
围棋的困难在于:人们设计不出好的评估函数(局面的好坏很难用规则描述),而且分支因子太大(每步约 250 种选择)。这就是在 AlphaGo 之前,围棋程序长期停留在业余水平的原因。
2. 蒙特卡洛评估
2.1 随机走子
没有评估函数怎么办?第 3 讲的蒙特卡洛思想:从这个局面开始,双方随机落子直到终局,看谁赢。重复很多次,赢的比例就是一个(有噪声的)局面评估。
它完全不需要领域知识,只需要能模拟游戏。2006 年前后,基于随机模拟的围棋程序首次在 9×9 棋盘上取得突破。
2.2 平坦蒙特卡洛与它的偏差
平坦蒙特卡洛:对根节点的每个着法,各做若干次随机走子,选平均得分最高的着法。
代码 02_mcts_uct.py 演示 1,还是 1.2 节那个局面(O 必须走边):
| 方法 | 模拟次数 | 选择 |
|---|---|---|
| 平坦蒙特卡洛 | 100 | 2(输棋) |
| 平坦蒙特卡洛 | 1,000 | 2(输棋) |
| 平坦蒙特卡洛 | 10,000 | 2(输棋) |
| MCTS | 100 | 5(和棋) |
| MCTS | 1,000 | 5(和棋) |
| MCTS | 10,000 | 7(和棋) |
平坦蒙特卡洛系统性地选择了会输的角,模拟再多也纠正不了。原因:它评估的是”O 走这步之后,双方都随机下”的胜率。在随机对局中,占角看起来很好——因为随机的 X 很少能找到那步”双杀”。它假设对手随机下,而真正的对手不会。
这是一种偏差,不是随机误差,所以模拟再多也无济于事。
3. 蒙特卡洛树搜索
3.1 四个步骤
MCTS 逐步构建一棵搜索树。每次模拟重复以下四步:
- 选择(Selection):从根节点出发,在已经展开的树中,按”树策略”一路往下选,直到遇到一个还有没试过的着法的节点。
- 扩展(Expansion):在这个节点上选一个没试过的着法,给树加一个新节点。
- 模拟(Simulation):从新节点出发,双方随机落子直到终局(“走子策略”,rollout policy)。
- 回传(Backup):把胜负沿着刚才的路径传回根节点,更新每个节点的访问次数 和总得分 。
模拟足够多次后,选根节点下访问次数最多的着法。代码见 mcts.py。
3.2 UCT:把 UCB 用在树上
树策略怎么选?每个节点处的选择,本身就是一个多臂老虎机问题:几个着法,价值未知,每次模拟相当于”拉一次臂”。Kocsis & Szepesvári (2006) 直接用了第 11 讲的 UCB:
这就是 UCT(Upper Confidence bounds applied to Trees)。每个节点记录”走到这个节点的那一方”的平均得分,所以父节点挑选子节点时,挑的正是对自己最有利的那个——双方都在用 UCB 最大化自己的得分。
3.3 为什么”树”很关键?
- 不对称的生长:UCB 把模拟集中在有希望的着法上,树在好棋的方向上长得很深,在坏棋的方向上只浅浅地看几眼。这正是有限深度搜索(平均地展开每个分支)所缺少的。
- 对手也”认真下棋”:在树的内部,对手的着法也由 UCB 选择——对手会很快找到最好的应对。在 2.2 节的例子中,O 走角之后,X 那一层很快发现了”双杀”,O 走角的分支的平均得分随之大幅下降。评估从”对手随机下”逐渐变成”对手认真下”,平坦蒙特卡洛的偏差因此被消除。
- 随时可停(anytime):任何时候停下来,都能给出当前最好的着法;时间越多,下得越好。
理论保证(Kocsis & Szepesvári, 2006):模拟次数趋于无穷时,UCT 在根节点选错着法的概率趋于 0,价值估计收敛到极小极大值。
3.4 收敛是慢的
演示 2:空棋盘上,MCTS 对 X 每个第一步的平均得分(真实值全是 0 = 和棋):
| 模拟次数 | 中心(4) | 角(0) | 边(1) |
|---|---|---|---|
| 100 | +0.619 | +0.333 | −0.200 |
| 1,000 | +0.420 | +0.228 | +0.200 |
| 10,000 | +0.312 | +0.195 | +0.127 |
| 100,000 | +0.067 | +0.039 | +0.040 |
模拟少时,估计值反映的是”接近随机对局”的胜率(先手在随机对局中占很大优势)。模拟越多,树越深,估计值逐渐靠近真实值 0。收敛很慢,因为平均得分包含了早期那些”随便下”的模拟。但选着法看的是访问次数,而访问次数会很快集中到好棋上——下得对,比估得准来得早。
4. MCTS 的实验与实践细节
4.1 下得对不对?
演示 3:1000 个关键局面上选到最优着法的比例:
| 模拟次数 | MCTS(UCT,) | 平坦蒙特卡洛 |
|---|---|---|
| 10 | 83.1% | 78.6% |
| 30 | 94.5% | 89.8% |
| 100 | 98.6% | 94.5% |
| 300 | 99.6% | 95.5% |
| 1,000 | 99.9% | 95.7% |
| 3,000 | 100.0% | 95.7% |
MCTS 趋近 100%;平坦蒙特卡洛停在 95.7%——系统性偏差。
4.2 实战
演示 4:MCTS 执 X、执 O 各 100 盘:
| MCTS 模拟次数 | 对手 | MCTS 胜 | 和 | MCTS 负 |
|---|---|---|---|---|
| 10 | 完美 | 0 | 51 | 149 |
| 10 | 随机 | 155 | 22 | 23 |
| 100 | 完美 | 0 | 155 | 45 |
| 100 | 随机 | 187 | 10 | 3 |
| 1,000 | 完美 | 0 | 197 | 3 |
| 1,000 | 随机 | 188 | 12 | 0 |
对完美对手,“不输”就是满分;1000 次模拟时,200 盘只输了 3 盘。
4.3 探索常数
演示 5(每步 100 次模拟):
| 0 | 0.25 | 0.5 | 1.0 | 1.4 | 4 | 10 | 30 | 100 | |
|---|---|---|---|---|---|---|---|---|---|
| 正确率 | 93.0% | 96.4% | 97.1% | 98.2% | 98.2% | 98.2% | 96.3% | 94.0% | 80.2% |
- :纯贪心,某个着法早期运气好就一直被选——和老虎机中的贪心”卡住”一样。
- 在 0.5~4 之间效果差不多:在井字棋上,UCT 对 不太敏感。
- 很大时明显变差:探索项压倒了平均得分,模拟几乎被平均分配,树长不深;而且访问次数几乎一样时,“选访问最多的”就接近随机了。
4.4 其他实践细节
- 最终选择:通常选访问次数最多的着法(最”稳健”),而不是平均得分最高的(可能只被访问了几次、运气好)。
- 走子策略的质量很重要:随机走子引入偏差;更聪明的走子(比如”能赢就赢、该堵就堵”)能显著改善评估(练习 5)。AlphaGo 的第一版用一个从人类棋谱中学到的快速走子策略。
- 树的复用:走了一步之后,对应子树的统计量可以保留给下一步继续用。
- 并行化:多个线程同时做模拟,用”虚拟损失”避免它们都挤到同一条路径上。
5. AlphaGo → AlphaGo Zero → AlphaZero → MuZero
5.1 AlphaGo(Silver et al., 2016)
AlphaGo 把 MCTS 与深度神经网络结合:
- 监督学习的策略网络 :在 3000 万个人类棋谱的局面上做行为克隆(第 8 讲),预测”人类高手会怎么走”,准确率约 57%。
- 强化学习的策略网络 :从 出发,通过自我对弈 + 策略梯度(第 6 讲的 REINFORCE!)继续提升。
- 价值网络 :用 自我对弈产生的局面和最终胜负,回归”这个局面的胜率”。
- MCTS:用策略网络的输出作为着法的先验,引导搜索;叶子节点的评估 = 价值网络与快速走子结果的加权平均。
5.2 AlphaGo Zero(Silver et al., 2017)
“Zero”意味着不使用任何人类棋谱,从随机下棋开始完全靠自我对弈学习。它还做了大幅简化:
- 一个网络(残差网络)同时输出策略 和价值 :;
- 不再做随机走子:叶子节点直接用 评估;
- 训练目标完全来自 MCTS:
其中 是 MCTS 在局面 上的访问次数分布, 是这盘棋的最终结果。
它在 3 天的训练后以 100:0 击败了击败李世石的 AlphaGo 版本。
5.3 PUCT:带先验的 UCB
AlphaGo 系列的树策略不是 UCT,而是 PUCT:
与 UCT 的区别:
- 先验 (策略网络的输出)决定了每个着法的探索奖励有多大——“直觉”认为好的着法先看、多看,明显的坏棋几乎不看。围棋每步约 250 种选择,没有先验,每个着法都要先试一次,搜索根本长不深。
- 探索项是 ,而不是 。
- 自我对弈时,在根节点的先验上混入 Dirichlet 噪声 ,保证即使网络”很确定”,也会探索其他着法——又一次是探索!
5.4 AlphaZero 与 MuZero
- AlphaZero(Silver et al., 2018):同一个算法,不做任何针对性的修改,分别在国际象棋、日本将棋、围棋上达到超越所有已有程序的水平。它证明了”自我对弈 + MCTS + 深度网络”是一个通用的方法。
- MuZero(Schrittwieser et al., 2020):连游戏规则都不需要——它学习一个模型,在学到的模型里做 MCTS。这把本讲的”已知模型的规划”推广到了”学到的模型的规划”,也就是下一讲的基于模型的强化学习。MuZero 在 Atari 游戏上也取得了当时最好的结果。
5.5 实验:AlphaZero 的骨架
代码 03_alphazero_lite.py 实现了 AlphaZero 的完整训练循环:PUCT 搜索、自我对弈(带 Dirichlet 噪声)、用访问分布训练策略、用胜负训练价值。唯一的简化:为了只用 numpy、并看清每个数字,“网络”是一张查找表(每个局面各存一组策略和一个价值)。
演示 1:训练过程(每轮 50 盘自我对弈,每步 64 次 PUCT 模拟):
| 轮次 | 累计对局 | 见过的局面 | 价值误差* | 只用策略在见过的关键局面上的正确率 | 对完美对手输的盘数(只用策略 / PUCT 16 次) |
|---|---|---|---|---|---|
| 0 | 0 | 0 | — | — | 83 / 80 |
| 1 | 50 | 229 | 0.299 | 91.3% | 48 / 69 |
| 5 | 250 | 571 | 0.043 | 93.0% | 27 / 32 |
| 10 | 500 | 764 | 0.037 | 94.8% | 30 / 40 |
| 20 | 1000 | 973 | 0.023 | 95.9% | 13 / 39 |
| 40 | 2000 | 1199 | 0.022 | 97.8% | 17 / 19 |
(* 训练 ≥ 10 次的局面上,价值与极小极大真实值之差的绝对值的平均;对局各 100 盘。)
- 价值误差迅速降到很小:自我对弈的胜负结果教会了它”这个局面会怎样”。
- **只用策略(完全不搜索)**的水平大幅提高:策略的训练目标是搜索后的访问分布,它把搜索的结论”蒸馏”成了直觉。
- 对局成绩不是单调的(100 盘的随机波动不小),而且训练后仍会输一些棋:完美对手会把棋局带到自我对弈中从没出现过的局面,查找表在那里一无所知。
演示 2:直觉让搜索更高效(关键局面上选到最优着法的比例):
自我对弈中见过的关键局面(829 个);只用训练后的策略、不搜索:97.8%
| 模拟次数 | PUCT + 训练后的表 | PUCT + 没训练的表 | UCT(随机走子) |
|---|---|---|---|
| 4 | 89.6% | 47.0% | 48.3% |
| 16 | 96.0% | 72.5% | 74.7% |
| 64 | 98.4% | 92.5% | 93.4% |
| 256 | 99.8% | 97.8% | 98.3% |
自我对弈中没见过的关键局面(2362 个);只用训练后的策略:40.8%
| 模拟次数 | PUCT + 训练后的表 | PUCT + 没训练的表 | UCT(随机走子) |
|---|---|---|---|
| 4 | 68.1% | 66.4% | 59.8% |
| 16 | 91.3% | 89.5% | 93.4% |
| 64 | 98.3% | 98.2% | 98.5% |
| 256 | 99.9% | 99.7% | 99.8% |
- 见过的局面:训练后的表让搜索高效得多——4 次模拟的正确率就远高于没训练的表和 UCT。先验告诉搜索”先看哪几步”,价值代替了粗糙的随机走子。
- 搜索次数很少时,搜索反而不如直接用策略(4、16 次时低于 97.8%):只有几次访问时,“访问最多”是一个很粗糙的信号。模拟够多(64、256)时,搜索才超过策略。这就是 AlphaZero 每步要做几百上千次模拟的原因:搜索要足够深,才能改进直觉。
- 没见过的局面:训练后的表和没训练的表几乎一样——查找表不能泛化。真正的 AlphaZero 用神经网络,从见过的局面中学到的模式能泛化到从没见过的局面。围棋的局面多到自我对弈永远不可能见全,泛化是一切的前提。
演示 3:没见过的关键局面中,84.6% 已经”分出胜负”(见过的只有 46.1%)。自我对弈的双方都在认真下棋,没见过的局面大多要有一方先下出明显的错着才会出现。这类局面往往是”一步杀”或”必须堵”,靠搜索很容易解决。自我对弈把学习集中在高水平对局会遇到的局面上——这也是训练时需要 Dirichlet 噪声和开局随机性的原因:让自我对弈见识更多样的局面。
6. 为什么自我对弈 + 搜索能不断变强?
6.1 策略迭代的视角
回忆第 2 讲的策略迭代:
- 策略评估:计算当前策略的价值;
- 策略改进:根据价值贪心地改进策略。
AlphaZero 的循环正是近似的策略迭代:
| 策略迭代 | AlphaZero |
|---|---|
| 当前策略 | 网络的策略头 |
| 策略改进: | MCTS:以 为先验、 为评估做搜索,得到更强的访问分布 |
| 策略评估: | 用 自我对弈,用胜负 训练价值头 |
| 用 替换 | 训练策略头去模仿 |
MCTS 是一个”策略改进算子”:给它一个策略和价值,它输出一个更强的策略(演示 2:搜索够多时,正确率高于策略本身)。网络再去学习这个更强的策略,下一轮的搜索从更好的起点出发……如此循环。
6.2 模仿学习的视角
从第 8 讲的角度看:MCTS 是专家,网络是学习者,策略的训练就是行为克隆。而且训练数据来自网络自己的自我对弈——学习者访问的状态分布,这正是 DAgger 的思想:在学习者自己会遇到的状态上,向专家请教。不同的是,这里的”专家”不是人,而是”学习者 + 搜索”——学习者越强,专家也越强。这被称为专家迭代(Expert Iteration,Anthony et al., 2017)。
6.3 超越棋类
“学到的直觉 + 搜索”这个组合远不止用于下棋:
- AlphaTensor(2022):把”找更快的矩阵乘法算法”变成一个游戏,用 AlphaZero 式的方法发现了新的算法;
- AlphaDev(2023):发现了更快的排序程序,已被合并进 C++ 标准库;
- 大语言模型的推理:在”推理步骤”上做树搜索,用学到的价值模型评估中间步骤——第 16 讲会继续讨论。
7. 本讲总结
7.1 核心概念清单
- 前向搜索:只为当前状态规划,展开博弈树;不需要遍历所有状态,但树随深度指数增长。
- 极小极大 / negamax:;记忆化合并相同局面。
- α-β 剪枝:结果不变,跳过不可能影响决策的分支;着法顺序越好剪得越多。
- 有限深度 + 评估函数:看得越深越好,代价指数增长;好的评估函数能减少所需的搜索。
- 蒙特卡洛评估:随机走子到终局,不需要领域知识。
- 平坦蒙特卡洛的偏差:假设双方随机下,系统性地误判,模拟再多也纠正不了。
- MCTS:选择、扩展、模拟、回传;不对称地生长;随时可停。
- UCT:每个节点都是一个老虎机,用 UCB 选择;树让对手也”认真下棋”,收敛到极小极大值。
- AlphaGo:人类棋谱的行为克隆 + 策略梯度自我对弈 + 价值网络 + MCTS。
- AlphaGo Zero / AlphaZero:无人类数据;一个网络输出 ;PUCT;损失 。
- 自我对弈为什么有效:MCTS 是策略改进算子,网络训练是策略评估与蒸馏——近似的策略迭代 / 专家迭代。
- 泛化:神经网络能把学到的东西推广到没见过的局面,这是在巨大状态空间中成功的前提。
7.2 公式速查表
| 名称 | 公式 |
|---|---|
| negamax | |
| UCT | |
| PUCT | |
| 根节点噪声 | |
| 访问分布 | |
| AlphaZero 损失 |
7.3 中英术语对照表
| 中文 | 英文 | 中文 | 英文 |
|---|---|---|---|
| 前向搜索 | Forward search | 博弈树 | Game tree |
| 极小极大 | Minimax | 负极大 | Negamax |
| α-β 剪枝 | Alpha-beta pruning | 置换表 / 记忆化 | Transposition table / memoization |
| 评估函数 | Evaluation function | 随机走子 | Rollout / playout |
| 平坦蒙特卡洛 | Flat Monte Carlo | 蒙特卡洛树搜索 | Monte Carlo Tree Search (MCTS) |
| 树策略 | Tree policy | 走子策略 | Rollout / default policy |
| 选择、扩展、模拟、回传 | Selection, expansion, simulation, backup | 随时可停 | Anytime |
| UCT | Upper Confidence bounds applied to Trees | PUCT | Predictor + UCT |
| 策略网络 / 价值网络 | Policy network / value network | 自我对弈 | Self-play |
| 专家迭代 | Expert iteration | 策略改进算子 | Policy improvement operator |
8. 练习题
练习 1(negamax):用 negamax 的思路,手工计算下面这个局面(轮到 X)的价值:
X O X
O O X
_ X O
参考答案
只剩一个空位(左下角,编号 6)。X 走 6 之后,棋盘下满,检查所有的线:没有三连(第一列 X O X、第三行 X X O、对角线 2-4-6 为 X O X……),是和棋,价值 0。所以这个局面的价值是 0。
练习 2(α-β 剪枝):为什么着法顺序会影响 α-β 剪枝的效率?如果每次都能先看到最好的着法,会发生什么?
参考答案
剪枝发生在”已经找到一个足够好的着法,使得对手不会让棋局走到这里”的时候。如果先看到最好的着法, 很早就变得很大,后面的着法只要发现”对手有一个应对能把我压到 以下”就能立刻停止——需要看的节点最少。理论上,完美的着法顺序能把需要访问的节点数从 降到约 ,相当于同样的计算量能搜索两倍的深度。这也是为什么好的着法排序(比如用上一轮搜索的结果、或者一个策略网络)如此重要。
练习 3(平坦蒙特卡洛):用自己的话解释:为什么平坦蒙特卡洛在 2.2 节的例子中,模拟再多也会选错?这种错误属于偏差还是方差?
参考答案
平坦蒙特卡洛估计的是”我走这步之后,双方随机下”的期望结果,模拟次数越多,这个估计越准——但它估计的量本身就不是我们关心的量(“对手认真下时”的结果)。随机的 X 很少走出”双杀”,所以 O 走角看起来还不错。这是偏差:估计量收敛到了一个错误的值,增加样本只能减小方差,不能减小偏差。MCTS 让对手在树中也按 UCB 认真选着法,才消除了这个偏差。
练习 4(UCT 与老虎机):在 MCTS 的每个节点上用 UCB 选择,与第 11 讲的老虎机有什么不同?(提示:每个”臂”的奖励分布是固定的吗?)
参考答案
老虎机中每个臂的奖励分布是固定的。而在 MCTS 中,一个子节点的”奖励”取决于它下面的子树中的选择——随着子树中的搜索不断改进(对手越来越”认真”),这个子节点的平均得分会变化(演示 2 中价值估计从 +0.6 一路降到接近 0)。所以每个节点面对的是一个非平稳的老虎机。这正是 UCT 的理论分析比 UCB 更复杂的原因(Kocsis & Szepesvári 需要处理奖励的”漂移”),也是它收敛较慢的原因之一。
练习 5(动手)★:把 mcts.py 中的随机走子换成”能一步赢就赢;否则如果对手能一步赢就堵;否则随机”。平坦蒙特卡洛在 2.2 节的局面上还会选错吗?它在关键局面上的正确率能达到 100% 吗?
参考答案
实测:换成这种走子策略后,平坦蒙特卡洛在这个局面上给两个角的评分都是 −1.0(O 走角后,X 按”该堵就堵”的规则堵住 O 的斜线,恰好形成双杀),能正确地选择走边。在 1000 个关键局面上的正确率从 95.7% 提高到约 98.5%(100 次模拟 98.3%,1000 次 98.7%),但仍然达不到 100%——更聪明的走子策略减小了偏差,但只要走子不是完美的,偏差就不会消失。同样的走子策略下,MCTS 在 100 次模拟时就达到 99.7%。这说明走子策略的质量很重要(AlphaGo 第一版专门训练了快速走子网络),而树搜索能在此基础上进一步消除剩余的偏差。
练习 6(AlphaZero 的损失):AlphaZero 的策略目标为什么是 MCTS 的访问分布 ,而不是”实际走的那一步”(独热向量)?
参考答案
访问分布包含了更多信息:不只是”哪步最好”,还有”其他着法有多好”(第二好的着法也被访问了很多次,说明它也不错)。这种”软目标”让网络学到更丰富的偏好,训练更稳定,也更容易泛化。此外,实际走的那一步可能是按温度随机选的(开局阶段),不一定代表搜索的最佳判断。这与知识蒸馏中”用教师模型的软概率训练学生模型”是同一个道理。
练习 7(策略迭代):用 6.1 节的对应关系解释:如果 MCTS 的模拟次数太少(比如 4 次),AlphaZero 的训练会出现什么问题?结合演示 2 的结果。
参考答案
策略迭代能不断改进的前提是”策略改进”这一步真的产生了更好的策略。演示 2 显示,4 次或 16 次模拟的 PUCT 在见过的局面上正确率(89.6%、96.0%)低于策略本身(97.8%)——搜索没有改进策略,反而让它变差了。如果用这样的访问分布做训练目标,网络就会去模仿一个比自己还差的”专家”,训练会停滞甚至退化。所以训练时每步的模拟次数必须足够多,让搜索确实比网络更强(AlphaGo Zero 自我对弈时每步 1600 次模拟)。
练习 8(思考题):MCTS 需要一个模拟器(能从任意状态出发模拟未来)。在哪些 RL 问题中这个要求可以满足,哪些不能?MuZero 是怎样绕开这个要求的?
参考答案
棋类游戏、电子游戏(能保存和读取状态)、某些物理仿真器可以满足;真实世界中的机器人、医疗、推荐系统通常不行——你不能把真实的病人”回退”到昨天,再试另一种治疗。MuZero 的做法是学习一个模型:学一个表示函数把观察编码成隐状态,一个动力学函数预测”做了动作之后的隐状态和奖励”,一个预测函数输出策略和价值;然后在这个学到的模型中做 MCTS。它不需要模型能还原真实的观察,只需要模型对规划有用的量(奖励、价值、策略)预测准确。这就是下一讲”基于模型的 RL”的一个代表。
9. 延伸阅读
- CS234 Spring 2024 Lecture 15 录像与课件。
- Browne et al. (2012),A Survey of Monte Carlo Tree Search Methods:MCTS 的全面综述。
- Kocsis & Szepesvári (2006),Bandit Based Monte-Carlo Planning:UCT 的原始论文。
- Silver et al. (2016),Mastering the Game of Go with Deep Neural Networks and Tree Search(AlphaGo)。
- Silver et al. (2017),Mastering the Game of Go without Human Knowledge(AlphaGo Zero)。
- Silver et al. (2018),A General Reinforcement Learning Algorithm that Masters Chess, Shogi, and Go through Self-Play(AlphaZero)。
- Schrittwieser et al. (2020),Mastering Atari, Go, Chess and Shogi by Planning with a Learned Model(MuZero)。
- Anthony, Tian & Barber (2017),Thinking Fast and Slow with Deep Learning and Tree Search(专家迭代)。
- Russell & Norvig,Artificial Intelligence: A Modern Approach,第 5 章(对抗搜索)。
10. 下一讲预告
本讲假设模型已知(游戏规则)。MuZero 已经暗示了下一步:如果模型未知,能不能先学一个模型,再在模型里规划?
下一讲是基于模型的强化学习:
- Dyna 架构:用真实经验学习模型,再用模型生成”想象的经验”来加速学习——样本效率能提高多少?
- 模型误差:模型不完美时,在模型里规划会发生什么?为什么”想象”走得越远,误差越大(复合误差)?
- 环境变化时,模型会过时——怎样发现并纠正?
- 世界模型、MuZero 与现代的基于模型的方法。
下一讲之前,建议你:跑通 code/lecture14/ 下的 3 个脚本,完成练习 1、3、4、6,并尝试练习 5。