
8.2 测试及分析计算结果
ANN_V1.py中权重初始化的源代码如下:

其中第2行代码weights表示权重,是一个3行1列的矩阵。
在Spyder中运行以上代码,运行结果如图8-10所示。

图8-10 权重初始值
图8-10中,[[–0.165 955 99], [0.440 648 99], [–0.999 771 25]]是一个矩阵,权重随机初始化的取值范围为[–1.0, 1.0)。如图8-11所示,盘古人工智能框架输入层只有2个神经元x1、x2,ANN_V1.py中的输入层有3个神经元x1、x2、x3,例如,X的第一行数据[0,0,1],第一个神经元是0,第二个神经元是0,第三个神经元是1。

图8-11 神经网络图
如果将weights=2×np.random.random((3,1))–1改为weights=np.random.random((3,1)),权重的取值范围为[0.0, 1.0),这时计算出的weights都为正值,运行结果如图8-12所示。

图8-12 权重都为正值
如果将weights=2×np.random.random((3,1))–1改为weights=np.random.random((3,1))–1,权重的取值范围为[–1.0, 0.0),这时计算出的权重都为负值,运行结果如图8-13所示。

图8-13 权重都为负值
在ANN_V1.py中将权重设置到一个合适的范围,权重随机初始化的取值范围为–1~1。
ANN_V1.py中矩阵点积运算的代码如下:

第2行代码np.dot是NumPy矩阵点积运算,包括2个输入参数,第1个输入参数是输入层数据(4×3的矩阵),第2个输入参数是权重(3×1的矩阵),点积运算的结果是4×1的矩阵。

如图8-14所示,输入层矩阵第一行的第一个元素和权重矩阵第一列的第一个元素相乘,输入层矩阵的第一行的第二个元素和权重矩阵第一列的第二个元素相乘,输入层矩阵的第一行的第三个元素和权重矩阵第一列的第三个元素相乘,然后将相乘的结果累加作为结果矩阵的第一行的第一个元素。其他元素的点积运算依此类推。

图8-14 矩阵点积运算
ANN_V1.py以矩阵方式构建一个神经网络,实现前向传播算法和反向传播算法;并预测输出结果。
ANN_V1.py中的代码如下:

第2行代码中的10 000是指10 000个时代,1个时代就是把所有训练集数据进行1次计算。
第6行代码是前向传播算法的过程。盘古人工智能框架中使用了5个for循环,每一行的元素和权重相乘使用1次循环,遍历所有的数据集又使用1次循环……;而ANN_V1.py使用了矩阵,仅用一个点积运算就实现了前向传播算法。
第8行代码计算误差,y是实际值,layer1是预测值,用实际值减去预测值得到误差值。
第11行代码将误差值乘以导数。nonlin函数的第二个参数是True,nonlin函数对Sigmoid激活函数进行求导计算。
第14行代码更新权重。layer0是3×4的矩阵,layer0.T矩阵转置运算以后变为4×3的矩阵,l1_delta矩阵是4×1的矩阵,二者进行点积运算变成3×1的矩阵,其和权重3×1的矩阵是一致的,所以可以进行矩阵的加法运算。
第18行代码,从输出结果来看,layer1就是我们的隐藏层,将隐藏层作为输出层,一次将所有的数据都计算出来,然后直接将layer1作为输出结果打印出来。
在Spyder中运行ANN_V1.py,运行结果如下:

经过1万次迭代后,预测值和真实值非常接近。如图8-15所示,ANN_V1.py构建的是神经网络,但这个神经网络太简单了,只有一个输入层和一个隐藏层,隐藏层的值就是输出层的结果,以后也可以循序渐进,加更多隐藏层。这个结果是我们期待的。

图8-15 ANN_V1.py神经网络结构图
ANN_V1.py一次将数据集所有的预测值打印出来,盘古人工智能框架是一次打印一个预测值。一次打印4个预测值,还是分别打印预测值,这个无关紧要,和理解神经网络框架的实际过程没什么关系。
ANN_V1.py的代码比盘古人工智能框架的简化得多,体现出矩阵的强大威力,矩阵的抽象就是极大地简化对数据集的循环操作。
ANN_V1.py代码中的np.random.seed(1)为了使每次的运行结果都一样,每次的随机值都是一样的,方便观察。再运行一次ANN_V1.py代码,结果还是一样。
