五子棋AI边缘试探

开头声明:

关于机器学习方面的代码是完全复制自:AlphaZero实战:从零学下五子棋(附代码)-知乎,我就是用qt写了一个简易的GUI,然后花了60+块大洋租了一台阿里云的服务器,跑了3K轮的19*19棋盘下的人工智能。

初来乍到,仔细研究了MIT许可证的限制具体应如何执行,但如有侵权还望指正。

起因

作为一个大一的新生老油条,这学期选了唯一的一个院级选修课,作为这门课的大作业之一,想做点高端的,又没什么技术,所以只能去“抄”了。而做出一个类似于AlphaZero一样的人工智能是我自从其打败柯洁以来的想法,一直都没有下决心,所以这次就捎带脚了。

经过

代码找到了Github-AlphaZero_Gomoku,原版提供了一个简单的CUI方便人机对战,在两天苦读人工智能相关代码无果(我太菜了)之后,只能去研究一下封装类的接口,然后写个GUI(按照要求)包装一下。

GUI

本着“学就学点有用的”的大原则,我查看了一下几个比较经典的GUI库,觉得PyQt还是很有潜力的,毕竟这几年来出了好几个版本,依旧在更新,网上反应也不错,不想tk一样好多坑,就选了PyQt。

随便找了个教程,随便粘过来一个空白窗口的代码,F5,一次通过,窗口映入眼帘,不错。教程地址:PyQt5教程

PyQt的整体需要自己敲代码的部分就是继承了一个QT的类,在这个类里面定义各种函数,就相当于监听各种事件,当然也可以定义一些正常的函数用来自己用。

__init__的过程中主要用来声明各种类里面的需要用到的变量,然后调用真正的initUI函数进行窗口的渲染。

由于五子棋的棋盘,我决定使用画布进行绘制,所以在initUI中声明了窗口的大小之后,标题内容之后,使用self.show()然后会调用paintEvent函数。由于之后需要频繁的画线,所以就直接把画棋盘声明为一个单独的函数。

1
2
3
4
5
6
qp = QPainter()
qp.begin(self)
qp.setPen(QPen(QColor(130, 130, 130)))
qp.setBrush(QBrush(QColor(130, 130, 130), Qt.SolidPattern))
qp.drawRect(0, 0, (self.weight+2) *
self.everyLine, (self.height+2)*self.everyLine)

创建画笔 设置画笔(边框) 设置笔刷(填充) 画一个方框

当然还有画圆,画线,画点的方法,不再赘述。

后来一个可以点击的棋盘就这样诞生了。

人工智能模块调用

经过几个小时的阅读,原项目中的架构大概是这样的:

结构图

MCTSPlayer中有着标准的接口,便于Game进行调用大致有几个

  1. set_player_ind 设置玩家编号
  2. reset_player 重置玩家状态
  3. get_action 取你下在哪里

这下我就遇到了一个严重的问题,因为我需要在这个函数运行结束之后返回人下在哪里了,然而GUi又是事件驱动的,只有点击之后方法才会被调用。经过一番百度之后,我进行了下面几个尝试:

关于调用问题的解决

协程——yield/send 以及 async/await (失败)

这两个方式看似非常美好,但是遗憾的是,get_action的调用是在Game中,而且我并不能在get_action中调用一个函数等待一个还没运行的函数的执行。在大量的尝试都宣告失败之后,放弃这个方法。

线程切换——greenlet (成功?)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from greenlet import greenlet

def test1():
print 12
gr2.switch()
print 34

def test2():
print 56
gr1.switch()
print 78

gr1 = greenlet(test1)
gr2 = greenlet(test2)
gr1.switch()

在这个简单的例子中我们可以看到 test1执行了一般就通过gr2.switch()去执行test2,当test2中执行gr1.switch()还会从之前gr2.switch()离开的地方继续运行。这样我就有了一个大胆的想法。

GUI画完之后调用AI,AI请求落子的时候调回来GUI处理用户操作,再调回AI返回落子信息。

这是一个不完美的解决方案,因为在线程从GUI切换到AI的时候,GUI就会处于一种无法响应的状态。只要不在不能落子的时候点击棋盘是看不出来的。

多线程+线程间通信 (未尝试)

这个也是我当时的想法,但是由于时间比较紧张就没有考虑,以后处理吧。

模型训练

光有枪没有蛋肯定是不行的。在原来的代码里,作者十分良心的写了5种价值网络的写法,在这里我研究了一下TF的表示无法理解之后,就直接采用了原版使用的Theano and Lasagne作为基础的实现版本。

因为训练基于AlphaZero的理论,所以不需要外界提供数据。这就是所谓的:“两个萌新通过随机落子日夜切磋,两周之后终成大师。”的故事吧。当然我没有Google一样强大的TPU进行计算,两周肯定远远不够,再加上我开始的时候就剩下一周了,emmmmm

经过5天的训练,现在训练到3K轮了,基本已经直到连5个棋可以赢的地步,但是还不知道如何去下套,去劫杀。但是也懂得好多套路。现在的损失刚刚讲到二点几,可能还是需要自己训练一下吧。回望500轮那个智障的AI,连怎么赢都不知道,现在已经这样了,还是挺有意思的。

最终结果:

一个下棋的gif

结果

写这个文章的目的就是在正式开始写实验报告的时候有点13数,顺便记录一下自己的工作。就是这样。Githu仓库