机器学习:手撕 AlphaGo(一)

图 1-1: AphaGo 结构概览

1. 前言

AlphaGo 是一个非常经典的模型,不论从影响力还是模型设计上。它的技术迭代演进路径:AlphaGo,AlphaGoZero,AlphaZero,MuZero 更是十分精彩。相信有很多同学因为听了 AlphaGo 的故事对机器学习或者深度学习产生兴趣,致力投身于机器学习/深度学习的领域。本文尝试对 AlphaGo(即李世石版) 进行分析,看看当时在全世界范围内引起广泛关注的模型是如何设计的。同时我们也会对封面图进行解读,看看这张图里到底放生了什么故事。本文大致可以分为三个模块:

  1. 对计算机下围棋问题的分析和思考;

  2. 解释经典的 MCTS 思想;

  3. 介绍 AlphaGo 的算法内容。

文章比较长,祝有个精彩的旅程。

本文将尝试解释以下内容:

  • 了解计算机下围棋的问题

  • MCTS 的基本原理

  • Policy Network

  • Value Network

  • AlphaGo 中的 MCTS

2. 计算机下围棋的问题描述

围棋是一个两人博弈的游戏,每个围棋选手均想战胜对方,这是一种两个人的零和游戏,即下棋的最后一定有一个胜利者和失败者 (和棋情况先不考虑)。在计算机诞生的早期,作为计算机的先驱,比较感兴趣的是:在下棋方向,计算机何时取代人类。所有的棋类游戏,对于人类来说都是一个思维活动的过程,然而计算机是一堆电子元器件堆积的产物,一个自然的问题:在棋类游戏中,由电子元器件组成的计算机如何模拟由生物细胞组成的人的思维方式呢?

2.1 计算机棋类游戏发展简史

要回答这个问题,不得不先看看计算机棋类游戏的发展史。可能在此过程中,会遇到不少的熟人,可能会惊叹他们在棋类游戏中,也做出了如此了不起的工作,也许对于他们来说,思考这个问题只是平时娱乐的游戏。首先 1950 是 Claude Shannon(香农) 提出用 Tree search(树搜索) 方式解决棋类问题,这点很重要,将棋类问题建模为 Tree, 将人类的思维过程建模为 Tree 上搜索的过程,在此我们先概略的体会它的重要性,在后续 MCTS 中将会看到这一个思想精彩的延展。然后 1953 年 Alan Turing(艾伦·图灵) 写出第一个国际象棋程序,这人同时也是我们的“祖师爷”。然后 Arthur Samuel 在前人的基础上,写出第一个跳棋游戏的程序,下的比它的开发者还好, 与此同时各个棋类的计算机程序,在飞速的发展,在 1968 年写出第一个击败围棋新手的程序。

因为前人已经将棋类游戏建模为 Tree Search 问题,不同棋类规则不同,从而树的规模不同,计算机擅长快速计算,普通的台式机计算能力在 129GFLOPS。所以问题转化为: 在棋类游戏中,计算机利用它的快速计算能力在 Tree Search 任务上,如何战胜人类选手,即各种棋类中,人类的最强选手。在 1992 年在西洋双陆棋中,IBM 开发的程序 TD-Gammon 仅次于人类的最佳选手,但它探索了很多人类未走过的策略,最终导致双陆器玩法的进步。1996 年在跳棋领域,程序 Chinook 赢得了美国的锦标赛冠军。然后就是部分同学知道的 IBM 的 DeepBlue(深蓝) 击败当时国际象棋的世界冠军 Garry Kasparov。最后是 2016 年就是大家熟知的 AlphaGo 击败人类九段选手李世石,因为当年围棋积分排行榜第一是柯洁,所以 AlphaGo 不算真正的击败人类最强选手,于是在 2017 年 AlphaGo Master 在乌镇击败当时的世界冠军柯洁。相当于宣布,在所有的棋类游戏中,计算机战胜了人类。

图 2-2: DeepBlue 作者与国际象棋世界冠军握手

2.2 围棋的规则简述

据说在所有的棋类游戏中,围棋的规则最简单,但却是最难玩的棋类游戏。我们先初步看下围棋的主要规则,有助于后续理解围棋的复杂性,以及感受当初 Deepmind 面对问题的难度。

  • 围棋由 19 条横线和 19 条竖线组成的网格,共有 361 个交点,每个交点均是一个落子点,最开始时,棋盘上空无一子;

  • 一个选手执黑色棋子,一个选手执白色棋子,在棋盘上轮流下,且执黑色棋子的选手先行;

  • 当一片连续的同色的棋子完全被另外一种颜色的棋子包围时,这片连续棋子为“死棋”,将会被提走。如图 2-3c 所示,黑棋下在粉色区域,白色棋子将被提子;

  • 当围棋结束时,统计黑白双方各自占据的交点,占据交点数量多的一 方获胜,如图 2-3d, 白色棋子占据 9 个交点,黑色棋子占据 16 个交点, 黑色棋子胜;

以上我们介绍这些规则,已经可以在盘面上演绎出千变万化的局面。面对这千变万化的局面,如果让我们“解决计算机围棋选手战胜人类围棋选手的问题”,我们该从何下手?

图 2-3:围棋的主要规则

2.3 计算机模拟人下围棋问题的难度

2.3.1 遍历围棋 Tree

借用 Claude Shannon(香农) Tree search 的思想,我们来建模围棋的 Tree。首先 Tree 的每个节点是一个符合围棋规则的棋盘状态。顺此推理,Tree 的根节点是一个空的棋盘,如图 2-4 所示。一个节点 s 的子节点是: 在节点 s 状态下,对方棋子所有的落子可能。在图 2-4 的棋盘中,根节点的子节点有 16 个,即黑棋落在 16 个交点的任意一个点,都是根节点的一个子节点,只不过其中有些子节点是“送人头”,人类选手不下在相应的位置上罢了,所以在图 2-4 中只描述节点常出现的子节点,一颗实际 (列出所有可能)的围棋 Tree 要比图 2-4 的 Tree 大很多。Tree 的叶子节点则是一场对弈中的终止状态,即在一场对弈中已经分出胜负。

图 2-4: 一颗简单的围棋 Tree

现在我们有了一颗围棋 Tree, 每个从根节点到叶子节点的路径,都是一盘有胜负的对弈,这颗 Tree 枚举了围棋中任何一种状态下所有可能的落子情况。那么计算机在与人类选手对弈时,参考这颗围棋 Tree,选择对自己有利的位置下棋。这样计算机完全立于不败之地,我们似乎解决了“计算机围棋选手战胜人类围棋选手的问题”,似乎没有 AlphaGo 什么事了。但我们都知道事实是 AlphaGo 战胜了人类。计算机借助围棋 Tree 下赢人类的推演逻辑是正确的,那什么地方没考虑到,才导致 Tree search 的思想出现 60 年后,计算机围棋选手才战胜人类职业选手呢?

2.3.2 围棋 Tree 节点太多

首先第一点,这棵围棋 Tree 很庞大。在标准棋盘下(19*19=361),我们简单估算一下枚举所有落子状态的 Tree 的节点个数。假设一场对弈最后,棋盘上每个点上都有棋子, 在一个空棋盘上,黑子的落子可能有 361 种,在黑子落下后,白子有 360 种落子可能,然后黑子有 359 种落子可能,白子 358 种落子可能... 以此类推下去, 倒数第二手白子有两种落子可能,最后一手黑子只有一种落子可能。很明显这是一个阶乘,即所有节点个数最多为 361!个。阶乘是一个增长速率很恐怖的运算,恐怖到阶乘的计算器都不计算 5000 或者 10000 以上的数的阶乘, 如图 2-5,可能因为计算结果太大,对人类已经没有使用价值了吧。

图 2-5: 随机抽取的阶乘计算器

361! 的计算结果如图 2-5d 所示,用科学计数法表示1.43∗10^{768},目前性能稍好些的 CPU 主频在 3GHz 左右,我们假设 1hz 查看一个 Tree 的节点,遍历完所有节点需要的年数用科学计数法表示,在 10 的指数上,只是比节点个数少 17 次方而已。我们估计节点个数的方法比较粗暴,在引入围棋规则后,节点个数大约 10^{170} ,比我们粗暴的估计方法减少很多。但这个值依然大的无法遍历 Tree。

2.3.3 很难判断一个节点的好坏

第二点我们忽略的难点:在围棋下完前的某个节点状态,很难判断谁赢谁输。这点也是导致“遍历围棋 Tree 的思想”不能实现的关键因素之一。也许在看完章节 2.3.2 后, 有的同学会说,围棋只有 361 个落子点,所以我们不需要查看围棋 Tree 所有的节点,我们只需要遍历每个选中节点的子节点就行,这样最多只需要查看

\textstyle\sum_{i=1}^{361} i =65341

个节点,这个数值计算机可以很快算完。这个想法也是对的,在下棋时我们确实按照这个逻辑在 Tree 上搜索,只不过这个想法忽略的是:Tree search 过程需要比较节点 s 的所有子节点,然后在所有子节点中选择最有利于自己的子节点作为下一步的落子方案。因为针对围棋 Tree 上除叶子节点外任何一个单独的节点,我们不能判断输赢,即针对黑子 (或者白子) 判断不了当前局面的好坏。所以在落子前,必须先遍历围棋 Tree,由叶子节点向上,一层层计算出每个节点的值,这个节点值表示对黑子的有利程度,用于子节点比较时,找出最有利于自己的子节点。也许大家会好奇一个问题: 遍历围棋 Tree 时,如何计算每个节点的值?

2.3.4 计算围棋 Tree 中每个节点的值

在“遍历围棋 Tree 的思想”下,既然每个节点 s 有一个值 v(s) 用于节点之间比较,那么借助图 2-6 我们来理解如何精确计算围棋 Tree 各个节点的值。如图 2-6a, 假设我们有一颗 5 层的简化的围棋 Tree, 只有叶子节点能判断胜负,如果黑子胜标记为 +1,如果白字胜标记为 −1。黑白棋子交替行棋,最开始由黑子先行。黑白棋子均会参考这颗围棋 Tree 行棋,而且每步行棋对自己来说都是最优策略,在此情况下我们计算每个节点的值 v(s) 。根据我们的定义, v(s)  越大表示对黑子越有利, v(s) 越小表示对白子越有利。 v(s)  的定义如式 2.1:

可以从以下 3 个方面理解式 2.1:

  • 对于叶子节点 s,如果黑子胜, v(s) = +1,如果白子胜 v(s) = −1;

  • 对于非叶子节点 s, 若此轮到黑子行棋,为了让自己赢, v(s)  是所有子 节点中的最大值,行棋方案是最大值的子节点对应的动作 a;

  • 对于非叶子节点 s, 若此轮到白子行棋,为了让自己赢, v(s)  是所有子 节点中的最小值,行棋方案是最小值的子节点对应的动作 a;

因为围棋中不是黑子赢就是白子赢,所以黑子和白子计算   v(s)  的策略是相 反的。 根据公式 2.1 对 v(s)  的定义, 现在我们再来看看图 2-6a 中这颗 5 层的围 棋 Tree, 由下到上如何一层层计算节点的值 v(s)  。围棋 Tree 的第五层叶子 节点的值由黑子和白子的胜负自然得到;围棋 Tree 的第四层由白子行棋, 第四层中每个节点的值  v(s)  为子节点中的最小值,于是便得到图 2-6b 的结 果;围棋 Tree 的第三层由黑子行棋,第三层中每个节点的值  v(s)  为子节点中最大值,于是得到图 2-6c 的结果。第二层和第一层的节点依次类推计算, 便得到图 2-6d 的结果。这样我们便得到图 2-6 这颗 5 层的围棋 Tree 的所有 节点的值  v(s)  。参照这种计算方法,我们可以计算任何一颗围棋 Tree 的节 点值  v(s)  ,有了一颗围棋 Tree 完整的节点值,我们就可以在这颗 Tree 上 search 了。只可惜真正棋盘的围棋 Tree 的  v(s)  我们是计算不出来的。

图 2-6: 一颗围棋 Tree 节点值 v(s) 的计算过程

2.3.5 用近似求解代替精确求解

现在我们知道“遍历一颗围棋 Tree 的思想”为什么行不通了。那我们 是放弃还是继续攻克这个难题?针对个人讲,绝大多数人选择了放弃,只有 少部分人选择继续。针对全人类来讲,只要还有一个人在坚持探索计算机下 围棋,那么就等于没有放弃这个问题。AlphaGo 和 AlphaGo Zero 的出现, 也证明人类没有放弃这个问题,并且还解决了这个难题,让计算机围棋选手 战胜了人类围棋选手。继续回到我们的故事,在面临“遍历一颗围棋 Tree” 不现实的情况下,该如何继续我们的探索? 前辈们给出的答案: 我们不再追 求遍历一颗完整的围棋 Tree, 而是通过近似估计的方法,降低对围棋 Tree 深度和宽度的依赖。这种思想下最精彩的算法是 MCTS,我们在下一节将 详细介绍 MCTS,大家一起欣赏有关它的故事,看看这个算法是如何将“近 似解替代精确解的思想”发挥的淋漓尽致。

图 3-7: MCTS 概览

3. 团队介绍

「三翼鸟数字化技术平台-智慧设计团队」依托实体建模技术与人工智能技术打造面向家电的智能设计平台,为海尔特色的成套家电和智慧场景提供可视可触的虚拟现实体验。智慧设计团队提供全链路设计,涵盖概念化设计、深化设计、智能仿真、快速报价、模拟施工、快速出图、交易交付、设备检修等关键环节,为全屋家电设计提供一站式解决方案。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/262388.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

伽马校正:FPGA

参考资料: Tone Mapping 与 Gamma Correction - 知乎 (zhihu.com) Book_VIP: 《基于MATLAB与FPGA的图像处理教程》此书是业内第一本基于MATLAB与FPGA的图像处理教程,第一本真正结合理论及算法加速方案,在Matlab验证,以及在FPGA上…

CSS(五) -- 动效实现(立体盒子旋转-四方体+正六边)

一. 四面立体旋转 正方形旋转 小程序中 wxss中 <!-- 背景 --><view class"dragon"><!--旋转物体位置--><view class"dragon-position"><!--旋转 加透视 有立体的感觉--><view class"d-parent"><view …

【JVM】一、认识JVM

文章目录 1、虚拟机2、Java虚拟机3、JVM的整体结构4、Java代码的执行流程5、JVM的分类6、JVM的生命周期 1、虚拟机 虚拟机&#xff0c;Virtual Machine&#xff0c;一台虚拟的计算机&#xff0c;用来执行虚拟计算机指令。分为&#xff1a; 系统虚拟机&#xff1a;如VMware&am…

Bash 脚本学习

文章目录 1、脚本编程基础2. 变量2.1 参数变量的引用2.2 环境变量 3 条件判断语句3.1 if 语句3.1.1 语法3.1.2 案例 3.2 case 语句3.2.1 语法3.2.2 案例 3.3 判断参数说明 4 循环语句4.1 for 循环4.1.1 语法4.1.2 案例 4.2 while循环4.2.1 语法4.2.2 案例4. 3 循环总结 5. 函数…

7.串口通信uart编写思路及自定义协议

前言&#xff1a; 串口是很重要的&#xff0c;有许多模块通信接口就是串口&#xff0c;例如gps模块&#xff0c;蓝牙模块&#xff0c;wifi模块还有一些精度比较高的陀螺仪模块等等&#xff0c;所以学会了串口之后&#xff0c;这些听起来很牛批的模块都能够用起来了。此外&#…

RTP/RTCP/RTSP/SIP/SDP/RTMP对比

RTP&#xff08;Real-time Transport Protocol&#xff09;是一种用于实时传输音频和视频数据的协议。它位于传输层和应用层之间&#xff0c;主要负责对媒体数据进行分包、传输和定时。 RTCP&#xff08;Real-Time Control Protocol&#xff09;是 RTP 的控制协议&#xff0c;…

持续集成交付CICD:基于ArgoCD 的GitOps 自动化完成前端项目应用发布与回滚

目录 一、实验 1. 环境 2. K8S master节点部署Argo CD 3.基于ArgoCD 实现GitOps &#xff08;同步部署文件&#xff09; 4.基于ArgoCD 实现GitOps &#xff08;同步HELM文件&#xff09; 二、问题 1. ArgoCD 连接K8S集群状态为 Unknown 2.ArgoCD 创建application失败 …

03-JVM对象创建与内存分配机制深度剖析

文章目录 对象的创建对象创建的主要流程一、类加载检查二、分配内存划分内存的方法解决并发问题的方法 三、初始化零值四、设置对象头五、执行<init>方法 对象半初始化对象大小与指针压缩什么是java对象的指针压缩&#xff1f;为什么要进行指针压缩&#xff1f; 对象内存…

快速学习 webpack

目录 1. webpack基本概念 webpack能做什么&#xff1f; 2. webpack的使用步骤 2.1_webpack 更新打包 3. webpack的配置 3.1_打包流程图 3.2_案例-webpack隔行变色 3.3_插件-自动生成html文件 3.4_加载器 - 处理css文件问题 3.5_加载器 - 处理css文件 3.6_加载器 - 处…

【深入解析spring cloud gateway】12 gateway参数调优与分析

本节主要对网关主要的一些参数做一些解释说明&#xff0c;并用压测工具测试一下网关的接口&#xff0c;通过压测来验证参数配置是否合理 一、连接池参数 参数示例 spring:application:name: gatewaycloud:gateway:# http连接设置httpclient:# 全局的响应超时时间&#xff0c…

驱动开发的完善 --- 芯片手册导读 + I/O口操控代码的编写

在我上上节的博文中&#xff08;linux驱动的学习 & 驱动开发初识-CSDN博客&#xff09;&#xff1a; 我通过一个基本的字符设备驱动框架来测试了驱动的运行&#xff0c;但是在“pin4_open”和“pin4_write”这两个驱动函数的函数体里只写了一句内核打印的代码&#xff0c;作…

微软官方出品:GPT大模型编排工具,支持C#、Python等多个语言版本

随着ChatGPT的火热&#xff0c;基于大模型开发应用已经成为新的风口。虽然目前的大型模型已经具备相当高的智能水平&#xff0c;但它们仍然无法完全实现业务流程的自动化&#xff0c;从而达到用户的目标。 微软官方开源的Semantic Kernel的AI编排工具&#xff0c;就可以很好的…

【深度学习】注意力机制(七)Agent Attention

本文介绍Agent Attention注意力机制&#xff0c;Transformer中的Attention模块可以提取全局语义信息&#xff0c;但是计算量太大&#xff0c;Agent Attention是一种计算非常有效的Attention模块。 论文&#xff1a;Agent Attention: On the Integration of Softmax and Linear…

融资项目——vue之双向数据绑定

上一篇文章中使用的v-bind是单向绑定方法&#xff0c;即数据改变&#xff0c;网页相应的视图发生改变&#xff0c;但是网页视图发生改变其相关联的数据不会发生改变。但是双向数据绑定不同之处在于网页视图发生改变其相关联的数据也会发生改变。Vue可以使用v-model进行双向数据…

docker-compose安装Rocketmq总结,以及如何更换mq端口

默认你已经装好了docker哈 安装docker-compose sudo curl -L https://github.com/docker/compose/releases/download/1.25.1-rc1/docker-compose-uname -s-uname -m -o /usr/local/bin/docker-composechmod x /usr/local/bin/docker-composedocker-compose --version成功打印…

4.2 克隆

一&#xff0c;什么是克隆&#xff1f; 克隆是指通过共享缓冲区来复制内容&#xff08;例如&#xff0c;两个窗口共享相同的内容&#xff09;。 克隆可用于提高性能&#xff1a; 可以减少所需的更新次数。 你可以在多个显示器上显示内容&#xff0c;但只需要更新一个缓冲区…

C# 使用MSTest进行单元测试

目录 写在前面 代码实现 执行结果 写在前面 MSTest是微软官方提供的.NET平台下的单元测试框架&#xff1b;可使用DataRow属性来指定数据&#xff0c;驱动测试用例所用到的值&#xff0c;连续对每个数据化进行运行测试&#xff0c;也可以使用DynamicData 属性来指定数据&…

服务器数据恢复-服务器断电导致linux操作系统数据丢失的数据恢复案例

linux操作系统服务器数据恢复环境&#xff1a; 某品牌R730服务器MD3200系列存储&#xff0c;linux操作系统。 服务器故障&#xff1a; 机房意外断电导致服务器linux操作系统部分文件丢失。 服务器数据恢复过程&#xff1a; 1、将故障服务器连接到北亚企安数据恢复中心备份服务器…

vue3 组合式pinia的使用 案例

需求&#xff1a;用户登录时&#xff0c;结合session实现永久化存贮个人信息 import { computed, ref } from vue import { defineStore } from pinia import { logOn } from /service// sessionStorage的封装 import { SET_USER_TOKEN, STORAGE_GET, STORAGE_SET } from /util…

【PyTorch】代码学习

文章目录 直接定义nn.Sequential(), 然后append(),最后直接net(),少写很多forward&#xff0c;适合直连式网络 直接定义nn.Sequential(), 然后append(),最后直接net(),少写很多forward&#xff0c;适合直连式网络 代码来源&#xff1a;https://github.com/zshhans/MSD-Mixer/b…