(这里是最终成品的 GitHub 地址)
(这里是本章用到的 GitHub 地址)
这一章我们会把神经网络这个框架完善,这一章结束后,一个能跑的、自由度相当高的神经网路就新鲜出炉了。Again,由于实现是比较重要的,所以我们先不管接口、只把功能弄出来。同时需要指出的是,我们会用到下一章才讲到的损失函数层(CostLayer)和Optimizers。这是因为如果应用 tensorflow 的话,这两者的实现都只是封装的活儿
为简洁,我们使用 tensorflow 来作为我们的算法核心,所以观众老爷们可能需要先知道 tensorflow 的一些基本知识。观众老爷们如果不想上官网的话可以去看我写的这个“Tensorflow 应用式入门教程” ( σ'ω')σ
现在我们已经有了一个整合了各个层和各层之间关联的结构,接下来要做的就是利用这个结构得到我们想要的东西。为此我们可以通过一张图来理解:
其中,结构内部的操作我们已经“分而治之”了,接下来要做就是根据结构外部的输入、产生一个我们想要的输出。这其实就是前向传导算法,我们定义一个函数来实现它:
定义完前传算法后,由于我们用的是 tensorflow,所以基本就已经把核心步骤做完了,剩下的基本只是封装的活儿。为此,需要给出一直以来都没有给出的、这个结构的初始化函数:
和
这里为什么要定义两个类呢?
事实上,如果仅仅实现朴素的功能、是没有必要分成两个类的。但是不知观众老爷是否还记得、我在第零章里面说过、我们的最终框架支持分形结构、也就是类似于这样的结构:
在这里,外面最大的黑框其实是一个 Layer,然后内部的蓝色框可以看成是一个小神经网络,每个小的神经网络则又是由若干个 Layer 堆叠而成的
我们自然不希望蓝色框代表的小神经网络拥有我们最终版的神经网络那么多的功能(因为那样会显得很臃肿),所以我们可以抽出一些基本的神经网络的功能来组成一个“基本类”,这个基本类在我们的实现中就叫做 NNBase
相对应的,完整版的神经网络就叫做 NNDist,它会继承 NNBase 并在其基础上多出一些功能
说明一下之前没出现过的变量:NNTiming 是一个我自己写的辅助计算函数耗时的小工具,在这里有相关的介绍
self._optimizers 记录的是结构用的 Optimizer,其定义下一章会讲到
self._tfx,self._tfy,self._cost,self._y_pred 和 self._train_step 都是应用 tensorflow 过程中所需要记录的变量,具体的用处会在用到的时候进行说明
接下来就可以来看训练我们模型的函数了:
(如果观众老爷们对 tensorflow 不太熟悉的话、可能看的会有些不知所以然,此时戳进 tensorflow 的官网或者戳进我这篇文章 ( σ'ω')σ)
可能聪明的观众老爷们已经发现了:这个 fit 函数就是拿来训练我们的模型的、其训练的原理是最小化模型的损失(损失的定义下一章会讲)。也就是说,如果我们想要根据训练样本 x,y 来训练出一个神经网络的话,只需要:
nn = NNDist()
nn.add(ReLU((x.shape[1], 24)))
nn.add(CrossEntropy((y.shape[1],)))
nn.fit(x, y, epoch=epoch)
就行了。这其实和现有的许多神经网络的框架长的差不多 ( σ'ω')σ
那么模型已经弄好了,接下来怎么评估这个模型呢?为此需要一个预测函数和一个评估函数:
该函数会根据输入 x 输出模型预估的类别向量。其中 self._get_prediction 的定义为:至于评估函数则如下定义:
该函数会根据输入的 x,y 打印出模型预估的准确率
以上,一个完整的神经网络结构就搭建完毕了,合共 116 行 Python 代码,大概算是一个不错的结果。稍微总结一下主要过程:实现前传算法
根据前传算法获得预测值和损失
最小化损失以训练模型,根据预测值来评估模型
我们用到了但还没讲的损失函数层(CostLayer)和Optimizers会在下一章讲,届时神经网络的朴素实现就告一段落了
希望观众老爷们能够喜欢~