Cypha / 国际象棋

产品演示

来下一盘国际象棋,对手是 Cypha

Cypha 从来没看过一盘棋。它是看着一个普通的国际象棋程序思考学会的 — 26,568 个局面,每一个都标上了那个程序自己对谁占优的判断 — 直到 Cypha 能自己给出这个判断。

你在下面对弈的就是它,在你的浏览器里跑,外面套一层浅搜索。它是能被赢的,而且它到今天还是下不过当初教它的那个程序。本页上的每一个数字,都出自产生这个页面所加载权重的那次训练。

测出来的,不是说出来的

下面的均方根误差(RMSE)是衡量一组猜测偏了多远的常用指标;它越小,模型离它的老师就越近。

留出集 R²
—
RMSE
—
局面数
—
对教师战绩
—

R² 是在模型拟合时从没见过的留出局面上算的。对局那一行是 Cypha 在搜索深度 2 对同样深度的教师引擎,开局随机,执先执后轮换。这四个数字描述的都是 蒸馏出来时的那个模型 — 它们是固定的,不是对你这一份副本的测量。

你这一份副本还在学。 Cypha 是在线学习的,所以下载结束时这个头并没有停止拟合。它对你走的每一步都是多出来的一对训练数据,棋盘下方那块面板显示的是你这份副本已经偏离发布版多远。
而它目前还没有让它下得更好。这是测出来的,不是假设的。 在 12 局自我对弈里,这项修正让头对自己搜索的误差降了下来:从 0.76 到 0.67 个兵 — 而冻结的那个头在一整局里会漂移变差 4.6% ,会学习的那个则变好 5.2% 。所以拟合是真的。但把一份在 1,119 个局面上训练过的副本拿去对阵发布版副本,深度 2 下 24 局,执先执后轮换,结果是 6 胜–7 负–11 和:打成平手。

这是预期中的结果,值得说出来而不是藏起来。信号来自模型自己的深度 2 搜索,而这比静态头自己的视野也深不了多少 — 学会跟自己保持一致,和变强不是一回事。相比它蒸馏时用的 26,568 个局面,一千个局面也什么都不算。老实的说法是:在线学习器能用,也确实在做它说的事;至于它会赢过发布版模型这个说法,还没有挣到。
大白话

一分钟说清这是什么

问题所在

每一种新的人工智能(AI)设计出场时,都带着一套它为什么应该管用的说法。读那套说法,说明不了它到底管不管用。国际象棋能了结这件事,因为答案不是看法问题:它要么下出合规而合理的棋,要么下不出,而你可以坐下来自己查验。

解决办法

一个普通的国际象棋程序靠往前搜索走法来判断局面。Cypha 被喂了 26,568 个这样的判断,然后拟合出一个公式来复现它们 — 一行数学,作用在描述棋盘的 388 个数字上。为了国际象棋,架构里什么都没加。变的只是喂进去的数字。

这是给谁用的

任何在掂量 Cypha、宁愿自己查验也不愿听人说的人。做机器学习的人,想亲眼看看一个模型在被使用的同时继续学习。还有任何单纯想下一盘的人 — 全部在你的浏览器里跑,你下的棋不会被发送到任何地方。

复制一个国际象棋引擎的判断,不等于学会了下棋。 本页没有任何地方声称它等于。余下的部分是这件事是怎么做的、每个数字是什么意思,以及这个设计做不到的四件事。

cypha::Cypha — 国际象棋头 学习中

点一个棋子,再点它要去的格子。合法的落点会标出来。

局面

正在加载模型…
正在取蒸馏出来的权重。
Cypha 评估值
—
节点数
—

Cypha 考虑过的走法

走法

从你身上学到的

这个深度下的等级分
—
正在使用的模型
深度 2
已学局面数
0
已下完的局数
0
相对发布版的漂移
0.00%
上一次修正
—

漂移 是权重向量相对于蒸馏版的改动幅度。 上一次修正 是静态头对它刚刚走出的那个局面判断错了多少,以兵为单位,对着它自己更深的搜索来衡量。

等级分 是一套内部天梯上的分数,不是国际象棋联合会(FIDE)的分级 — 对一个从没和有等级分的人类下过棋的东西,没有任何老实的办法给它安一个 FIDE 数字。参考引擎在深度 1 上锚定为 1000,其余全部由 210 盘棋按 Bradley-Terry 极大似然拟合出来,所以不依赖对局的先后顺序。实测天梯:参考引擎在深度 1–3 上是 1000 / 1171 / 1245,Cypha 是 798 / 1010 / 1161。Cypha 大约比蒸馏出它的那个引擎落后一个搜索深度,误差棒大致是 ±50,这就是 210 盘棋能买到的精度。

每一档棋力设置都保留 它自己的模型。在深度 1 下棋的头,修正目标是深度 1 的搜索;到了深度 3,目标就是另一个更好的搜索。把两者训练进同一个权重向量,只会让它们互相打架。切换棋力,计数器也跟着换。

这个评估函数是 388 个特征的一个 线性 函数。它自己没有搜索深度,没有开局库,也没有残局知识。赢它是意料之中的;有意思的地方在于,一个白化过的线性头居然真的能复现一个引擎的搜索评估 — 而且在你下棋的时候还一直在自我修正。
引擎、特征、蒸馏出来的权重和对弈程序全都在本地跑。没有任何东西被发送出去,除了几千字节的系数之外也不下载任何模型。你这份副本学到的东西留在你的浏览器里,归你所有,永远不会上传 — 所以别人的棋局动不了你的模型,你的也动不了别人的。
方法

一个引擎是怎么变成一个 Cypha 模型的

这就是知识蒸馏,用的组件和 Cypha 的其他每一个应用完全一样。架构里没有加任何专门为国际象棋准备的东西 — 只加了特征。

蒸馏链条:一个经过 perft 校验的参考引擎标注 26,568 个局面,这些局面变成 388 个特征,拟合成一个 9.4 千字节的 Cypha 头,留出集 R 平方达到 0.866
滑动查看完整示意图 →
是蒸馏,不是发现。 最后那个框里的每一个数字,都是由产生本页所加载权重的那次训练测出来的。
第 1 步

教师

一个 0x88 引擎,带完整的合法走法生成、子力与棋子位置评估、最有价值受害者 – 最无价值攻击者(MVV-LVA)排序,以及静止搜索。它对照包括 kiwipete 在内的五个标准 perft 局面验证过,所以在从它学到任何东西之前,规则就是可证明正确的。

第 2 步

数据

局面取自自我对弈,开局随机,还刻意加了噪声,这样这个集合覆盖的是真实棋局,而不是一条狭窄的变例。每个局面都用教师自己的搜索分数标注,并截断到 ±12 个兵,免得将杀分数占了主导。

第 3 步

特征

388 维:一个 384 宽的子力-格位占据差(6 种棋子 × 64 格),再加上双象、叠兵、机动性和棋局阶段。一律从轮到走棋一方的视角出发,所以一个权重向量黑白通用。

第 4 步

拟合

WorldPrior θ₀ 由 Welford 在线拟合,白化充当自然梯度的度量,归一化最小均方(LMS)权重更新,最小描述长度(MDL)衰减把权重拽回先验,还有一个按意外程度加权、比例为 Cypha 参考值 0.30 的回放缓冲区。

为什么这是一个公平的演示

干活的是架构,不是这个领域

第 4 步里的每一个组件都是真正的 Cypha 组件,干的也是它真正的活。这个 WorldPrior 就是那个在线高斯分布, Cypha 页面 上的二维分类器的决策面就是它给的。白化是把信息几何那条主张落到实处:更新沿着自然梯度走,而不是原始梯度。MDL 衰减则是把 Solomonoff 先验表达成一个收缩项。

为国际象棋改的是特征映射和头 — 用回归代替分类。这正是 Cypha README 关于一个类型做好几件工作的那个论点,放在一个答案毫不含糊的领域里检验:它要么下的是合法、说得过去的棋,要么不是。

这件事没有证明什么

老实说出来的局限

  • 它是线性的。 一个作用在棋子位置特征上的线性函数,表示不了王的安全、兵形之间的相互作用,也表示不了任何需要两个特征相乘的东西。它的天花板,和 Cypha README 里描述的异或(XOR)那个天花板是同一个。
  • 教师本身水平一般。 参考引擎是一个称职的经典搜索器,不是 Stockfish。把它蒸馏好,意思就是把一个水平一般的评估器复现得好。
  • 它自己没有搜索深度。 这里的棋力大部分来自外面那层 alpha-beta 包装,教师那边也完全一样。
  • 蒸馏不是发现。 Cypha 复现的是一个给它看过的评估函数。它不是从零学会下棋的,本页上也没有任何地方声称它是。
自己复现一遍: node tools/chess/perft.js 对着标准测试局面校验这个引擎,而 node tools/chess/train.js 用一个固定的随机种子从头重新生成模型。本页顶部那些数字是直接从那次运行产生的文件里读出来的。