2.1 从“人机大战”谈NumPy模块的妙用
2016年3月15日,谷歌公司开发的人工智能机器AlphaGo以总比分4 : 1战胜围棋世界冠军李世石,轰动世界的“人机大战”落下帷幕。这让机器学习得到了受关注的“砝码”,但事实上,早在20世纪50年代,人工智能便开始向人类发起挑战。当时来自IBM工程研究组的萨缪尔(Samuel)开发出一款跳棋程序,该程序能够在与人对弈的过程中,不断累积经验以提升棋艺。但不管是跳棋,还是围棋的“人机大战”,人工智能发展的核心动力——机器学习一直被推动着向前迈进。为了让读者更好地理解机器学习,这里就从棋类入手介绍一下机器学习需要什么样的思维方式。
中国象棋有着悠久的历史,由于用具简单、趣味性强,成为流传极为广泛的棋类游戏。对中国象棋的“人机大战”的分析在这里拉开了序幕。
中国象棋棋盘的初始状态如图2.1所示。
图2.1 中国象棋棋盘的初始状态
当棋盘中的一个棋子被移动时,我们需要解决的问题就是如何标记一个棋子已被移动。比如这里把棋子“炮”移动了一下,如图2.2所示。
其实这张棋盘有点像二维坐标系,有x轴和y轴。“炮”的移动就是“炮”的坐标由某一个值变成了另一个值。如果把棋盘的左下角作为坐标原点,“车”“马”等棋子在横轴的每一个单位点上,“炮”的移动就可以表示为从坐标点(7,2)移动到坐标点(4,2),如图2.3所示。
图2.2 中国象棋棋盘“炮”被移动后的状态
图2.3 中国象棋棋盘“炮”被移动后棋盘的坐标展示
接下来可以观察在二维坐标系上的每个棋子,它们都可以用两个数值构成的元组来标记,这两个数值分别代表x轴坐标和y轴坐标,同时又是从0开始的。这类似于Python数据类型中的列表的元素,由两个索引数字决定元素的位置,可以将之理解成二维列表。那么现在就有一个问题,如果把初始棋盘定义成一个二维列表,有棋子的地方定义成1,则初始棋盘列表可以定义成:
Init_chess_board= [[1,1,1,1,1,1,1,1,1], [0,0,0,0,0,0,0,0,0], [0,1,0,0,0,0,0,1,0], [1,0,1,0,1,0,1,0,1], [0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0], [1,0,1,0,1,0,1,0,1], [0,1,0,0,0,0,0,1,0], [0,0,0,0,0,0,0,0,0], [1,1,1,1,1,1,1,1,1]]
“炮”被移动后的棋盘列表可以定义成:
move_pao_chess_board= [[1,1,1,1,1,1,1,1,1], [0,0,0,0,0,0,0,0,0], [0,1,0,0,1,0,0,0,0], [1,0,1,0,1,0,1,0,1], [0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0], [1,0,1,0,1,0,1,0,1], [0,1,0,0,0,0,0,1,0], [0,0,0,0,0,0,0,0,0], [1,1,1,1,1,1,1,1,1]]
将这两个二维列表进行对比,可发现其实很多数据都是一样的,只有两个位置的数据发生了变化,一个是列表索引为[7][2]的位置数字由1变0,一个是列表索引为[4][2]的位置数字由0变1。能否让这两个列表相对应位置的数值直接进行相减操作,由移动后的列表减去移动前的列表后出现这样的结果?相减后变成1的部分就是棋子移动后的位置,相减后变成-1的部分就是棋子移动前的位置,形如下面的列表结果。
move_result=[[0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0], [0,0,0,0,1,0,0,-1,0], [0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0]]
从列表中的数值来看,这种对应位置做减法的列表中只有0、1和-1,分析问题的方法也变得简单。这需要一种新的数据类型来实现这样的运算。NumPy中的数组就是用来解决这一类问题的,可以将两个数组中对应位置的值进行相减操作,这样棋类游戏就可以用数组来表征了。
做完了某个棋子的移动表征之后,就要去确认到底移动的是“炮”,是“车”,还是“马”等棋子。因为NumPy数组是用来运算的,运算是发生在数值之间的,这样对棋子的表征就可以用数值来进行,不同的数值表征不同的棋子。如8可以表示“车”这个棋子,“7”可以表示“马”这个棋子,依次类推。这样如果相减为-8或者8就表示“车”的移动,相减为“7”或者“-7”则表示“马”的移动,等等,如图2.4所示。
图2.4 中国象棋棋盘“马”被移动后标记值的变化情况
可以看出,通过NumPy的数组就可以实现判断出哪一个棋子在移动。接下来需要判断这个移动是否是正确的,这就是算法。用算法去判断“马”的移动是不是走了“日”字,“象”的移动是不是走了“田”字,“车”的移动是不是在走直线,等等。如何做到这样的事情呢?这就需要一点点数据方面的知识和技巧。比如,把“车”原来的位置记作(x1, y1),把“车”后来的位置记作(x2, y2),“车”的移动是否正确可以用数学表达式(x2-x1)(y2-y1)=0来判断。不管“车”是横向运动还是纵向运动,移动后只要有一个差值为0就证明移动是正常的,如图2.5所示。
同理,“马”也可以用数学公式的方法来处理,如图2.6所示。
图2.5 中国象棋棋盘“车”的移动轨迹规律数学公式归纳
图2.6 中国象棋棋盘“马”的移动轨迹规律数学公式归纳
依据前后坐标对应值相减后的规律,就可以判断“车”“马”“相”等所有棋子的移动是否正确。有了这种走棋的判断,下一步就要实现对“人机大战”的机器学习的研究,也就是研究在人的大脑所操控的这一步走棋以后,计算机是如何动作的。计算机不会无中生有,它在下棋时需要大量的棋谱做保证,一般棋谱也都是文本,如“车五平八”“将五退一”“炮七平五”“马二进三”等这样的叙述。这些叙述就是在告诉人或计算机棋盘中的棋子如何移动,棋谱文本中的第一个字就是棋谱中的棋子,棋谱文本中的第二个字和第四个字就是“x轴”或“y轴”坐标值,“y轴”还是“x轴”具体的坐标值也是通过棋谱文本中的第三个字“进”“退”“平”等描述及中国象棋中某个棋子的走法相对应地推算出来的。这些大量的供计算机进行训练的棋谱就是计算机机器学习的根据,这个根据给它个名字,就是“训练集”。通过对这些棋谱“训练集”的学习训练,在最终与人对战的时候,参与对战的人每走一步,计算机就通过“训练集”及合适的预测算法推测出下一步自己的具体动作,从而完成“人机大战”的具体博弈过程。
从这个“人机大战”的分析过程可以看出,NumPy的数组是进行机器学习的至关重要的数据类型,海量的数据就是通过NumPy的数组来进行计算的。下面就来认识一下机器学习的工具模块NumPy。