揭秘五子棋AI设备的炼成:wujian100 SoC助力人机对弈(下)

简介: 技术解码栏目:是面向开发者详细解读芯片开放社区(OCC)上关于处理器、芯片、基础软件平台、集成开发环境及应用开发平台的相关技术,方便开发者学习及快速上手,提升开发效率。

编辑语:

技术解码栏目:是面向开发者详细解读芯片开放社区(OCC)上关于处理器、芯片、基础软件平台、集成开发环境及应用开发平台的相关技术,方便开发者学习及快速上手,提升开发效率。

作者介绍

王松:复旦大学微电子学院2020级直博生

陈布:复旦大学微电子学院2019级硕士研究生


上期我们简单介绍了五子棋AI设备的开发过程,讲解了基于博弈树的五子棋AI算法的原理,今天我们就带大家深入了解该实战案例的开发过程。


本文将分为五子棋AI核心算法的硬件实现、软硬件协同仿真两部分内容,为大家详细阐述基于wujian100 SoC设计开发五子棋AI设备的过程。


一、五子棋AI核心算法的硬件实现

本次工作中,我们使用XILINX VIVADO HLS编写C++源程序,综合出硬件Verilog代码,封装成IP核,然后将其集成于wujian100 SoC平台之中。


1.1 极大极小值搜索算法的编程实现

代码主体本质上是一个递归函数,但由于递归函数无法被综合(因为可能出现无穷无尽的迭代,硬件上无法实现),在考虑到最大搜索深度不会超过4层(否则,搜索时间太长)的前提下,实例化4个相同的函数,以供层层调用。


编程思路如下:

  1. 第一步,假设我方(或者对方)落子,更新棋盘状态;
  2. 判断棋面输赢,如果已经输了或者赢了就没必要继续搜索下去了;
  3. 否则,遍历棋盘上可落子的位置,假设对方(或者我方)落子,进入下一层搜索;
  4. 得到上一步搜索返回的权值weight,更新下层上界max(或者下层下界min);
  5. 当前节点为MAX_Node时,如果max ≥ alpha(此处的max是在当前节点的子节点中已搜索出的最大值,在全部搜索完成前等价于当前节点的 α 值;此处的alpha是当前节点的父节点下的其它子节点中已搜索出的最小的 α 值,在全部搜索完成前等价为上层父节点的 β 值。即满足当前节点的α ≥ 父节点的β的条件),则可以直接返回至上一层,将当前节点及其子节点全部剪枝,即 α 剪枝;
  6. 当前节点为MIN_Node时,如果min ≤ beta(此处的min是在当前节点的子节点中已搜索出的最小值,在全部搜索完成前等价于当前节点的 β 值;此处的beta是当前节点的父节点下的其它子节点中已搜索出的最大的 β 值,在全部搜索完成前等价为上层父节点的 α 值。即满足当前节点的β ≤ 父节点的α的条件),则可以直接返回至上一层,将当前节点及其子节点全部剪枝,即 β 剪枝;
  7. 否则,返回已搜索出的下层节点中的最大值max(或者是最小值min);
  8. 搜索到限定层数之后,评估棋面,返回权值。


相关参数定义如下:

参数 定义
ChessBoard 用于存放棋盘状态的二维数组
BOARD_SIZE 棋盘规格,默认为15 × 15
x, y 当前节点的位置坐标
type 当前节点的类型(MAX_Node / MIN_Node
depth 搜索深度(从0开始,递归一次,数值加1)
alpha 当前节点的父节点下的其它子节点中已搜索出的最小的 α 值,即当前层的下界
beta 当前节点的父节点下的其它子节点中已搜索出的最大的 β 值,即当前层的上界


部分源代码如下:

1. for (j = 0; j < BOARD_SIZE; ++j) {
2. for (i = 0; i < BOARD_SIZE; ++i) {
3. if (ChessBoard[j][i] == EMPTY && canSearch(ChessBoard, i, j)) {
4. weight = minMax3(ChessBoard, i, j, nextType(type), depth + 1, min, max);
5. 
6. if (weight > max)
7. max = weight; // 更新下层上界
8. if (weight < min)
9. min = weight; // 更新下层下界
10. 
11. // alpha-beta
12. if (type == MAX_NODE) {
13. if (max >= alpha) {
14. ChessBoard[y][x] = EMPTY;
15. return max;
16. }
17. }
18. else {
19. if (min <= beta) {
20. ChessBoard[y][x] = EMPTY;
21. return min;
22. }
23. }
24. }
25. else
26. continue;
27. }
28. }
c++


1.2 五子棋IP核集成方法

设计完成五子棋IP核之后,将其集成到wujian100 SoC平台之中,用Vivado综合出网表,并生成bit流,下载到平头哥的XC7A-FPGA开发板中。


然后使用配套的CDK开发软件编写C程序,通过uart串口与计算机通信,与计算机端Python程序进行联合仿真。在此之前,有必要先简单介绍一下wujian100 SoC平台。


1.2.1 wujian100 SoC平台简介

wujian100_open是一个基于MCU的SoC平台,支持通过EDA工具进行前端仿真和制作FPGA进行测试,其硬件组成结构如下图所示:

image.gifimage.png


我们的IP核就是挂载于图中低速总线上的Dummy 0/1/2/3预留接口处。


1.2.2 平头哥 XC7A-FPGA开发板简介

平头哥开发的基于Xilinx Artix-7系列FPGA的开发板主要用于平头哥中低端CPU核的验证和评估,板上集成了Xilinx Artix-7 XC7A200T FPGA芯片。

image.gif

image.png

1.2.3 五子棋AI IP核设计

整个IP核的顶层采用了AXI-Stream协议进行数据传输,共存在三个接口:

参数 定义
control_in 控制端口
data_in 数据输入端口
data_out 数据输出端口

image.gif

image.png

对control_in写“0”会将棋盘复位,写“1”之后即开始通过数据加载模块data_in接收输入落子坐标,经过核心计算模块计算之后,通过数据输出模块data_out输出五子棋AI的落子坐标。

image.gif

image.png

我们这个IP是用Vivado HLS进行设计的,在整个程序中,对棋盘进行遍历和判断时用到了大量的for循环,Vivado HLS提供了一个流水线优化,我们对所有的循环进行了优化,综合之后得到以下Timing报告:

image.gif

image.png

预估最大时钟频率可达106.22 MHz,各类资源消耗如下图所示:image.gif

image.png

在这个IP核设计中并没有用到DMA,因为这里主要涉及到的位置为坐标,不涉及到大量的数据传输,所以,我们直接将其挂载到E902上,通过AHB转AXI的IP核相连接。


E902则是在接收到PC端落子坐标的信息后,把数据传输到IP核,IP核进行落子判断后,把数据返回给E902,E902再返回给PC。

image.gifimage.png

二、软硬件协同仿真

我们在使用Vivado HLS工具设计完成了五子棋AI的C++源程序之后,同时编写了C++测试程序,初步仿真算法程序的功能正确性。测试程序tb.cpp主模拟了四步落子输入:

1. int posx[4] = {7,7,8,8};
2. int posy[4] = {7,8,6,7};
c++


仿真结果如下:

1. 6  6 7 6 6 8 6 7


下图直观地反映了仿真时的博弈过程:

image.gifimage.png


从五子棋的常用战术来看,我们的五子棋AI算法的每一步“出招”都合乎预期,但是,这仅仅只能当做初步的仿真判断。


为了更准确地评估算法的智能水平,我们将IP核挂载在了wujian100 SoC平台上,并下载到FPGA开发板中,与计算机之间通过uart串口进行通信,分别使用CDK开发工具和Python完成联合仿真。


2.1 CDK C源程序

wujian100 开源项目中包含了一个uart的example程序,我们在此基础上编写完成CDK C源程序,程序的主要功能描述如下:

  • 通过串口接收计算机端Python程序发送过来的落子坐标或者是重开棋局信号reset;
  • 在接收到计算机端reset信号之后,通过往GB_CONTROL_IN_BADDR端口写“0”来重开棋局;
  • 在接收到计算机端落子坐标之后,将其发送给五子棋AI IP核;
  • 接收五子棋AI IP核返回的落子坐标,并将其发送给计算机。


(1)接收计算机端落子坐标的方法:

uart串口发送过来的数据是32位int型,但是uart在发送数据时是按一个byte接一个byte来的,先发送的是低8位数据,因此在接收的时候要将4个byte的数据拼接成一个32位数据:

1. static  uint8_t posPlayer[8] = {0}; // 数组存放的是连续接收到的8个字节的坐标数据
2. ...
3. x_tmp = posPlayer[3]<<24 | posPlayer[2]<<16 | posPlayer[1]<<8 | posPlayer[0];
4. y_tmp = posPlayer[7]<<24 | posPlayer[6]<<16 | posPlayer[5]<<8 | posPlayer[4];
5. x_pos = *(uint32_t *) & x_tmp; // 计算机落子横坐标
6. y_pos = *(uint32_t *) & y_tmp; // 计算机落子纵坐标
c


(2)复位棋局的方法:

将计算机端发送过来的坐标x, y都等于99作为复位本局游戏的reset信号(补充:如果x, y = 15, 15,表示硬件端AI先手落子,由IP核内部相应的函数控制):

1. if(x_pos == 99 && y_pos == 99) *(volatile uint32_t *) GB_CONTROL_IN_BADDR = 0x0;
c


(3)向IP核发送坐标点的方法:

先向GB_CONTROL_IN_BADDR写“1”,然后向GB_DATA_IN_BADDR写横坐标x,再向GB_DATA_IN_BADDR写纵坐标y。

1. *(volatile uint32_t *) GB_CONTROL_IN_BADDR   = 0x1;
2. *(volatile uint32_t *) GB_DATA_IN_BADDR  = x_pos;
3. *(volatile uint32_t *) GB_DATA_IN_BADDR  = y_pos;
c


(4)接收AI落子坐标的方法:

在向IP核和发送完坐标之后,C程序会等待IP核计算完成并返回落子坐标。

之前说过,IP核的数据传输方式是AXI Stream协议,我们将其valid信号接到了wujian100 SoC的中断引脚上。当IP核计算完成发回数据时,会触发MCU的中断,然后,在其中断服务程序go_bang_intr()中接收AI落子坐标,并通过串口发送到计算机端:

1. void go_bang_intr(void)
2. {
3. xy_result[0] = *(volatile uint32_t *) GB_DATA_OUT_BADDR;
4. xy_result[1] = *(volatile uint32_t *) GB_DATA_OUT_BADDR;
5. printf("%d\n", xy_result[1]);
6. printf("%d\n", xy_result[0]);
7. }
c


2.2 计算机端Python源程序

前面提到过,我们的五子棋AI算法只是五子棋游戏的核心算法,相应的控制程序是通过Python来编写的,为此,我们参考了以下项目中完整的Python五子棋游戏:


参考项目中同样使用Alpha-Beta剪枝算法实现了一个五子棋的AI,只不过其估值函数与我们的硬件AI有所不同。同时项目中还包含完整的人机交互界面,我们在其基础上修改源程序,实现Python端AI与硬件端AI的即时对战。


Python端AI的落子坐标将通过串口发送到FPGA开发板:

1. posPlayer = []
2. x, y = self.AI.findBestChess(self.map.map, self.player)
3. ...
4. posPlayer.append(struct.pack('<i', int(x)).hex())
5. posPlayer.append(struct.pack('<i', int(y)).hex())
6. tmp = "".join(posPlayer)
7. data_in = binascii.unhexlify(tmp)
8. ser.write(data_in) # 通过串口发送Python端落子坐标
python


然后,Python端将通过另一个线程来接收FPGA端通过串口发送回来的硬件端AI落子坐标:

1. posAI = []
2. ...
3. def Receiving():  # 接收函数
4. global posAI
5.  while True:   # 循环接收数据
6.    if ser.in_waiting:  # 当接收缓冲区中的数据不为零时,执行下面的代码
7.      strr = ser.read(ser.in_waiting).decode("gbk")
8.      posAI.append(strr)
9.    else:
10.       if threading_end_flag:
11.         break
python


游戏的画面显示以及游戏胜负的最终判断都是在计算机端通过Python程序来完成。


除此之外,我们也可以让硬件端AI与人类玩家对战,实现人机对战,只需将Python AI的落子坐标替换成人类玩家的落子坐标即可,具体方法不再赘述。


2.3 硬件端AI vs 软件端AI

至此,整个软硬件协同仿真的过程可以总结如下:

  • CDK C程序初始化五子棋AI IP核,等待接收计算机端Python AI落子坐标;
  • Python源程序初始化,通过串口向FPGA发送Python AI落子坐标;
  • FPGA端接收Python AI落子坐标,将其发送给硬件五子棋AI IP核;
  • FPGA端通过中断来接收五子棋AI IP核返回的落子坐标,将其通过串口发送给计算机,再次等待接收计算机端Python AI落子坐标。

image.gifimage.png


硬件端AI vs 软件端AI的记录如下图所示:image.gif



image.png

其中白方属于硬件端AI,黑方属于软件端AI,白方先手。利用timer不完全精确地记录双方运行时间后,得到以下加速比(双方AI算法不完全相同,仅作参考):

image.png

2.4 人机对战实验

由于五子棋AI使用的算法是相对固定的,两个AI的对战并不会产生多样性,因此,有必要考虑让我们的AI去与真正的人类对弈。


为此,我们特地用Python编写了一个Script,让我们的五子棋AI能够与QQ游戏大厅中广大的五子棋玩家对弈,同时记录数据(视频演示见本篇开头链接)。


在花费了两个星期的时间记录了700场对局之后,我们剔除了少部分步数不超过10步的对局,有效的对局数一共有673场,并统计了先手胜率和后手胜率,以及对局结束后总步数的分布情况,如下表所示:

先后手 场次 胜率
先手 333 84.08%
后手 340 70.00%
总共 673 76.97%


image.gifimage.png


上图是对局步数分布直方图 & 胜率分布折线图,从上图可以看出80%的对局步数都在50步以内,同时可以发现我们的AI的胜率随着对局步数的增加呈现出先下降后上升的趋势在对局步数处于80-89步之间的时候胜率降至最低——40.0%,在考虑到玩家水平差异后分析得出以下结论:

  • 大部分玩家与我们的AI“过不了几招”;
  • 在90回合以后,玩家们与我们的AI“纠缠“越久越难取胜;
  • 即使是高水平的玩家想要战胜我们的AI也并不容易,往往需要足够的回合数。


三、总结

我们使用Vivado HLS设计实现了基于Alpha-Beta剪枝算法的五子棋AI,并将其集成于wujian100 SoC之中,然后使用FPGA开发板通过串口与计算机相互通信完成软硬件协同仿真,仿真结果充分体现出了硬件加速的效果。


在此基础上,我们还编写脚本实现五子棋AI与广大线上玩家对弈,验证了五子棋AI的智能水平。




相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
Sqoop 企业级大数据迁移方案实战
Sqoop是一个用于在Hadoop和关系数据库服务器之间传输数据的工具。它用于从关系数据库(如MySQL,Oracle)导入数据到Hadoop HDFS,并从Hadoop文件系统导出到关系数据库。 本课程主要讲解了Sqoop的设计思想及原理、部署安装及配置、详细具体的使用方法技巧与实操案例、企业级任务管理等。结合日常工作实践,培养解决实际问题的能力。本课程由黑马程序员提供。
相关文章
|
4月前
|
存储 人工智能 C++
C++ 实现对战AI五子棋
C++ 实现对战AI五子棋
63 1
|
11月前
|
存储 人工智能 算法
五子棋简易AI算法1
基本思想 设置不同连接方式的权值并进行存储
264 1
|
3月前
|
存储 人工智能 自然语言处理
《百炼成金-大金融模型新篇章》––11.构建金融级AI原生的蓝图
百炼必定成金,新质生产力会催生新质劳动力,谨以此文抛砖引玉,希望与业内的各位朋友一同探讨如何积极拥抱并运用大模型技术,以应对和驾驭不断变化的市场环境,实现科技金融持续稳定的提质增效和创新发展,携手开启金融大模型未来新篇章。
121 4
|
1月前
|
机器学习/深度学习 人工智能 边缘计算
针对资源受限设备的 AI Native 应用轻量化微调技术
【8月更文第2天】随着人工智能(AI)技术的飞速发展,越来越多的应用程序开始在边缘计算和移动设备上部署机器学习模型。然而,这些设备通常具有有限的计算能力和存储空间。为了克服这些限制,本文将介绍一种针对资源受限设备的轻量化微调技术,旨在提高模型性能同时降低计算成本。
37 1
|
2月前
|
存储 人工智能 物联网
端侧设备AI代理优化框架问世,领域内准确率可达97%
【7月更文挑战第30天】新框架Octo-planner提升端侧AI代理效率与准确性至97%。此框架由Nexa AI等机构合作研发,采用&quot;Planner-Action&quot;模式,将AI代理任务划分为规划与执行两部分,利用&quot;Octopus&quot;及&quot;Phi-3 Mini&quot;模型分别处理。通过fine-tuning技术及GPT-4辅助,实现在资源受限设备上的高性能。更多细节见论文: https://arxiv.org/pdf/2406.18082
35 1
|
3月前
|
人工智能 自然语言处理 安全
《百炼成金-大金融模型新篇章》––10.金融级AI原生的六大要素(2)
百炼必定成金,新质生产力会催生新质劳动力,谨以此文抛砖引玉,希望与业内的各位朋友一同探讨如何积极拥抱并运用大模型技术,以应对和驾驭不断变化的市场环境,实现科技金融持续稳定的提质增效和创新发展,携手开启金融大模型未来新篇章。
|
3月前
|
人工智能 运维 搜索推荐
《百炼成金-大金融模型新篇章》––07.问题5:“杀手级通用大模型vs百花齐放专属大模型”,企业级AI应用的价值自证?
百炼必定成金,新质生产力会催生新质劳动力,谨以此文抛砖引玉,希望与业内的各位朋友一同探讨如何积极拥抱并运用大模型技术,以应对和驾驭不断变化的市场环境,实现科技金融持续稳定的提质增效和创新发展,携手开启金融大模型未来新篇章。
107 1
|
3月前
|
存储 人工智能 Kubernetes
《百炼成金-大金融模型新篇章》––10.金融级AI原生的六大要素(1)
百炼必定成金,新质生产力会催生新质劳动力,谨以此文抛砖引玉,希望与业内的各位朋友一同探讨如何积极拥抱并运用大模型技术,以应对和驾驭不断变化的市场环境,实现科技金融持续稳定的提质增效和创新发展,携手开启金融大模型未来新篇章。
|
3月前
|
机器学习/深度学习 数据采集 人工智能
AI 大模型在穿戴设备健康中的心率深度融合
AI 大模型在穿戴设备健康中的心率深度融合
48 0
|
4月前
|
存储 人工智能 C++
C++ 实现对战AI五子棋
C++ 实现对战AI五子棋