迷你AlphaGo的完整实现

第一时间关注程序猿(媛)身边的故事

PyTorch(http://pytorch.org/)是一个人工神经网络开发库,利用PyTorch可以让机器实现人工神经网络,完成人工智能应用。PyTorch是最简单、最灵活的人工神经网络库之一。

人工神经网络就是由人工神经元组成的网络,而人工神经元是对输入进行线性组合再进行非线性操作。在确定人工神经网络的结构后,通过优化,为人工神经元内的权重设置合适的值,就可以发挥人工神经网络强大的功能。那么,如何让计算机实现人工神经元、搭建人工神经网络,并选择合适的权重呢?这就需要人工神经网络的开发软件来帮忙。PyTorch就是一种人工神经网络的开发软件。

在开发人工神经网络的过程中,PyTorch可以帮助我们做以下事情。

q确定人工神经网络的结构:我们只要告诉PyTorch神经网络中神经元的个数、每个神经元是什么样的(比如输入、输出、非线性函数),以及各神经元的连接方式,PyTorch就可以让计算机构建出这个人工神经网络的结构。

q确定人工神经元的权重值:只要告诉PyTorch什么样的权重值比较好,PyTorch就可以帮助我们找到合适的权重值。

q处理输入和输出:此外,PyTorch还可以和其他库合作,协助处理人工神经网络的输入和输出,把人工神经网络的计算结果展示出来。

有了人工神经网络开发工具PyTorch,我们不再需要编写复杂的代码去实现人工神经元,或是漫无目的地寻找合适的权重值。借助PyTorch,只需要一句话,就可以指定某些神经网络连接关系;只需要一句话,就可以指定神经元使用的非线性函数。而且,我们不需要手动为每个神经元寻找合适的权重。

PyTorch不仅简单好用,而且完全免费。PyTorch的源代码是完全公开的,你可以在https://github.com/pytorch/pytorch上找到所有的实现代码。

来看一个用PyTorch实现的完整应用。在这一节中你会看到一些使用PyTorch的Python语句。也许你不会Python,或是没有安装运行Python的软件,这都没有关系。本书后续的章节会详细介绍软件安装、Python编写和PyTorch的使用。本节只是希望你能对PyTorch的用法有个初步的了解。

1. 迷你AlphaGo介绍

本节一起来看一个小程序“迷你AlphaGo”。这个小程序完成了下面的功能:有一个连续可导的函数,它有4个输入,前3个输入是,第4个输入是,它能返回一个实数。我们并不清楚函数的具体形式。我们的目标就是对任意的,找到合适的,使得函数的值最大。用数学语言表示,就是给定函数,求解

这个问题可以用图2-2表示。图中标有问号“?”的方框就是我们想要求解的关系。

这个应用之所以称为“迷你AlphaGo”,是因为这个问题和AlphaGo试图解决的问题非常相似。如果我们把前三个输入看作围棋的当前局势,把看作下一步要下的棋,把函数看作胜率函数,那么这个问题就相当于在给定局势的情况下,找到最优的下棋策略,使得胜率最大(当然,AlphaGo实际比这个复杂得多,例如实际可选的下棋位置只是离散的几个网格交叉点,胜率函数不能非常容易地评估出来等。所以本节的例子只是AlphaGo的一个简化版本)。

“迷你AlphaGo”问题可以用人工神经网络求解。求解思路如下:用一个人工神经网络来代替从到的关系。通过设计人工神经网络的结构、确定合适的参数,使得这个人工神经网络可以实现从到的关系。值得一提的是,由于不知道函数的具体形式,所以也不知道从到的最优关系的形式。实际上,从到的关系甚至可能没有显式表达式。这再一次体现了人工神经网络的强大之处:我们不需要知道解答的形式,只需要搭建人工神经网络;我们不需要告诉机器神经网络中神经元的权重都是多少,PyTorch可以帮助找到神经元的权重。在完成神经网络的搭建、选取合适的权重后,这个人工神经网络就能够实现“迷你AlphaGo”的全部功能。

2. 迷你AlphaGo的完整实现

在这一节我们来看一个基于PyTorch的迷你AlphaGo的完整实现。完整实现分为4个部分。

q确定神经网络结构。这个部分确定神经网络中有几个神经元,神经元之间是怎么连接的。

q构造测试函数。这个部分确定要针对哪个函数来选择人工神经元的权重。显然,函数不同,设置的权重值就不同。

q设置人工神经元的权重值。根据测试函数,让PyTorch自动设置合适的神经元权重值。完成这步后,神经网络就完全确定了。

q测试人工神经网络的效果。这步验证之前实现的人工神经网络能够很好地完成“迷你AlphaGo”的功能。

接下来依次来看这四部分的完整代码。将这四部分完整代码依次拼接在一起,就得到了完整的程序(而不需要再添加其他任何代码)。代码下载地址参见本书前言部分。

注意:如果你觉得这些代码难以理解,请不用担心。这里只是希望你有一个初步的概念。本书的后续章节会逐步介绍如何理解或编写这些代码。等你读完本书,你也能写出这样的代码。

首先来看第一部分代码。如代码清单2-1所示,这部分代码的主要功能是确定神经网络的结构。具体而言,以“import”和“from”开头的第1行代码告诉计算机我要用PyTorch了,让机器做好准备。接下来用一个序列构造神经网络。在这个序列中,有表示连接的Linear类,也有表示非线性运算的ReLU类。在这个序列中一共有3个Linear类实例,说明这个神经网络有3层。第一个Linear类实例用参数3和8构造,这两个参数说明每个神经元都有3个输入,一共有8个神经元。这个序列中有两个ReLU类实例,也就是说,其中两个层的神经元的非线性函数都是。

你可能会有疑问:为什么这个神经网络的最后一层没有使用非线性函数?这是因为,我们希望将要制作的“迷你AlphaGo”应用既能输出的结果,也能输出的结果。如果在最后的输出中设置了,那就不可能输出的结果。因此这里最后一层的神经元没有使用非线性函数。

代码清单2-1神经网络结构搭建代码

from torch.nnimport Linear, ReLU, Sequential

net =Sequential(

Linear(3, 8), #第1层有8个神经元

ReLU(), #第1层神经元的非线性函数是max(·,0)

Linear(8, 8), #第2层有8个神经元

ReLU(), #第2层的神经元的非线性函数是max(·,0)

Linear(8, 1), #第3层有1个神经元

)

接下来看第二部分代码。在这部分中,将定义函数。当然,这个函数的形式可以是任意的,而且神经网络不需要知道这个函数的具体形式。但是,神经网络权重的确定和函数有关。函数不同,神经网络就需要不同的权重值。因此,给出函数是有必要的。这部分代码如代码清单2-2所示。这里的代码需要用到一些PyTorch的编程知识,我们目前只需要知道这段代码定义了函数

其中,

代码清单2-2函数的定义

defg(x, y):

x0, x1, x2 = x[:, 0] ** 0, x[:, 1] ** 1,x[:, 2] ** 2

y0 = y[:, 0]

return (x0 + x1 + x2) * y0 - y0 * y0 - x0 *x1 * x2

接下来看第三部分代码。这部分代码见代码清单2-3。在这部分代码中,在PyTorch的帮助下为神经网络中的每个神经元找到合适的权重。在这段代码中,我们没有显式地为每个神经元指定权重值,而是使用了一个优化器。代码第3行构造了优化器optimizer。这个优化器每次可以改良所有权重值,但是这个改良不是一步到位的。我们需要让优化器反复改良很多次,才能让神经网络的所有权重都合适。在这段代码中以“for”开头的语句说明整个过程需要循环很多次(实际上是1000次),而后面缩进的语句都是要循环的内容。在循环的内容中,我们需要告诉优化器每次改良的依据是什么。因此后面缩进的代码先告诉优化器改良的依据,然后通过“optimizer.step()”语句完成权重的改良。完成循环后,神经网络中所有的权重值就都比较合适了。这时候我们说训练好了人工神经网络。

代码清单2-3使用优化器确定神经元的权重值

importtorch from torch.optim import Adam

optimizer= Adam(net.parameters())

forstep in range(1000):

optimizer.zero_grad()

x = torch.randn(1000, 3)

y = net(x)

outputs = g(x, y)

loss = -torch.sum(outputs)

loss.backward()

optimizer.step()

if step % 100 == 0:

print ('第{}次迭代损失={}'.format(step, loss))

那么,实现好的人工神经网络是不是正确完成了“迷你AlphaGo”的任务目标呢?第四部分的代码就来验证。这部分代码见代码清单2-4。这部分的代码又可以细分为三小部分。

生成测试数据。随机生成一些数据作为输入,我们将看到人工神经网络是不是能很好地计算出对应的。生成的输入数据被以“print”开头的语句输出在电脑屏幕上。

调用人工神经网络,看看在给定输入下神经网络的输出是什么。神经网络的输出和对应的函数的值被打印了出来。

计算理论最优结果作为参考。这部分并没有用到人工神经网络,只是用这个结果和神经网络的输出做比较。如果的具体形式为

,那么这个g实际上是一个关于y的二次函数,它的开口向下。利用二次函数的知识,可以知道,这个二次函数在

处取到最大值。因此,理论上的最佳输出为

这部分代码将理论上的最佳输出和最佳

输出对应的函数g的值打印了出来。

代码清单2-4验证生成的人工神经网络

#生成测试数据

x_test= torch.randn(2, 3)

print('测试输入:{}'.format(x_test))

#查看神经网络的计算结果

y_test= net(x_test)

print('人工神经网络计算结果:{}'.format(y_test))

print('g的值:{}'.format(g(x_test, y_test)))

#根据理论计算参考答案

defargmax_g(x):

x0, x1, x2 = x[:, 0] ** 0, x[:, 1] ** 1,x[:, 2] ** 2

return 0.5 * (x0 + x1 + x2)[:, None]

yref_test= argmax_g(x_test)

print('理论最优值:{}'.format(yref_test))

print('g的值:{}'.format(g(x_test, yref_test)))

由于第四部分验证代码的输入是随机确定的,所以每次运行的输入和输出都不一样。下面给出某次运行结果:

测试输入: tensor([[0.2487, 0.3399, -0.4967],

[ 1.0140, 0.1038, -0.1002]])

人工神经网络计算结果: tensor([[0.8289],

[ 0.4975]])

g的值: tensor([0.5442, 0.3056])

理论最优值: tensor([[0.7933],

[ 0.5569]])

g的值: tensor([0.5455, 0.3091])

比较神经网络的输出结果和理论计算结果,可以断定,我们的人工神经网络已经正确地输出了最优结果,实现了“迷你AlphaGo”的功能。

——节选自《神经网络与PyTorch实战》,作者:肖智清

  • 发表于:
  • 原文链接:https://kuaibao.qq.com/s/20180825A0EZ2V00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券