2018 年,Google 用 AlphaGo 神经网络击败了 GO 冠军,引发了巨大轰动。新的优秀开源机器学习库陆续出现,并利用家用 GPU 来加速训练过程。
我决定在 Abak 上尝试这条路,但刚开始时,我几乎连神经网络是什么都不太清楚。我在大学时期(1996 年)曾经有过一点点冲动想试试,但当时缺少数据、GPU 和明确目标,所以很难推进。而且从数学角度看,神经网络是一个相当沉重的主题,你还需要大量灵感。
经过大量高强度、近乎痴迷的研究后,我终于能够构建出一个模型,并让它开始学习。
站在巨人的肩膀上,我最初想向 Gerald Tesauro 博士学习——他在 90 年代开发了 TD-Gammon。据我所记得,那是强化学习算法第一次真正实用化的实现。
但由于 Abak 是一个二维游戏,我无法直接使用现成模型,只能开发自己的模型。我决定把部分算法的输出作为模型的一部分,作为专家信息,让神经网络更容易学习。说实话,我当时感觉自己像是在作弊。
下面是 Backgammon 模型与 Abak 模型之间的对比。
Backgammon 中广泛使用的 TD 模型描述的是列。对于棋盘上的每一列,会使用 4 个输入来描述它。
- 无棋子:[0,0,0,0]
- 一枚棋子:[1,0,0,0]
- 两枚棋子:[1,1,0,0],
- 三枚棋子:[1,1,1,0]
- 超过三枚棋子:[1,1,1,1].
它总共有 28 组这样的输入(棋盘每列一组)来分别表示双方,因此总输入数为 28*2*4,另外再加上一些用于统计中栏棋子的输入。遗憾的是,我现在是凭记忆在写,这些细节未必完全准确。
Abak 的模型非常不同。它描述的是棋子,而每枚棋子都有一组特征。在较新的版本中,我又补充了一个简化版的棋盘描述来作为辅助,不过效果并没有惊艳到哪里去,但这些特征仍然保留着。
这个游戏描述模型由四部分组成 [477 inputs]:
- 棋子描述 (14x30):描述包括棋子的统计信息、距离、高度等。它不包含职业,因为职业由其在模型中的位置继承。
- 队伍状态 (4x2):对某些棋子或状态特征进行计数。
- 强度地图 (24x2)。
- 游戏状态:下一手由谁掷骰!(1)。
你可以在下面查看该模型的完整说明。
版本:
1.- Python Cumpy (TD-V1).
这个 AI 的第一个版本是在纯 Python 中使用 Cumpy 训练的。Cumpy 是一个类似 Numpy、但运行在 GPU 上的库。我想从头学习,所以尽管我曾经用 Tensorflow 试过一阵子,我最后还是决定赤膊上阵(好吧,其实是配备了很棒的 Python + Cumpy 组合)。
特性:
- 一个网络,用于估计 0 号队伍赢得比赛的概率。
- 不了解点数。
- 没有“下一手由谁掷骰”标记。
- 没有强度地图
- 一层隐藏层,使用 sigmoid 激活函数。
- 训练了 45.000 局后,击败了我之前那个使用专家信息(GOAFI)编写的 AI。
- 学习了 4.500.000 局。并且对 GOFAI 的胜率达到了 75%。
- 它上线服役了 2 年。
2.- Tensorflow (TD-V2).
我对 Version 1 最大的痛点在于:由于训练时没有加入“下一手由谁掷骰”标记,它并不擅长计算胜率。不知为何,神经网络在选择好走法时结果其实相当不错,但从数学上看并不一致。Version 2 修复了这个问题,并新增了一个网络,用于计算比赛以 1、2 或 3 分结束的概率。
这次我选择 Tensorflow 来训练新模型,因为我想学一个框架,而且我找到了一个非常好的起步示例。
特性:
- 一个网络,用来计算 0 号队伍赢得比赛的概率。
- 一个网络,用来计算比赛以 1、2 或 3 分结束的概率。
- 包含新的强度地图。
- 两层隐藏层,使用不同的激活函数:隐藏层用 Leaky RELU,输出层用 sigmoid。
- 只用了 12.000 局,就能以 50% 的概率击败 TD-V1。
- 学习了 350.000 局后,对 TD-V1 的胜率达到 80%。
3.- Version 3:暂停中。
在选择最佳走法的决策最后一公里,还有一个简单算法会寻找最佳 Equity [%W*%p1+%W*%p2+%W*%p3]。
它会根据比赛目标、每位玩家获胜所需分数以及翻倍骰数值,对网络输出施加不同权重。
我想做一个能够处理这件事的 NN。那将会是 V3。目前尚未开发。
Abak 的神经网络模型:
棋子描述(14 inputs x 30 checkers):
- 到家的距离 x/25
- 上方棋子数量 x/4
- 下方棋子数量 x/4
- 是否在中栏上 [0,1]
- 是否已在家中 [0,1]
- 是否安全(at distance = 0)。 [0,1]
- 是否与另一枚棋子共同构成封锁 [0,1]
- 是否会被 druid 困住 [0,1]
- 是否已被 druid 困住 [0,1]
- 是否正在困住别人(此输入只对每个 druid 生效) [0,1]
- 在近区(前方 6 个位置)被击中的风险 [0..1]
- 在远区(前方 12 个位置)被击中的风险 [0..1]
- 被 druid 困住的风险 [0..1]
- 移动机会 [0..1]
每个队伍的游戏相关输入 (4x2):
- 中栏上的棋子数量。 x/15
- 安全棋子的数量。 x/15
- 所有棋子都已回家。 [0,1]
- 安全棋子 0 的数量。 [0,1]
强度地图:(24*2):
最后,是一张力量地图,类似 Tessauros 博士为 Backgammon 提出的模型,但更简化。对于每个位置和每个队伍,它都有一个介于 0 和 1 之间的数字,用来表示该封锁有多强:
- 0.0如果为空。
- 0.1如果有一枚棋子。
- 0.5如果那枚棋子是 guard。
- 1.0如果有两枚或更多棋子。