
2.4 从头开始使用Python编写FFNN
为了创建我们的网络,我们将创建一个类,它与第1章为感知器创建的类相似。与面向对象编程(OOP)所规定的相反,我们不会利用先前创建的感知器类,而使用更为方便的权重矩阵。
我们的目标是使用代码展示如何实现我们刚刚说的理论。因此,解决方案将非常适合于我们的用例。我们知道网络将分为三层,输入大小将为2,并且知道隐藏层中神经元的数量:


由于我们决定使用sigmoid作为激活函数,这里可以将其添加为外部函数。同样,我们知道需要计算导数,因为我们正在使用SGD。因此,我们将其实现为另一种方法。通过使用上述公式,实现变得非常简单:

然后,我们用一个函数来计算前向传递,而另一个函数用于反向传递。我们将使用输入和权重之间的点积来计算输出,然后将所有内容通过sigmoid传递:

前向传播也是我们将用于预测的内容,但是我们将创建别名,因为在此任务中最常用的名称是predict:

反向传播中最重要的概念是误差的反向传播,从而调整权重并减少误差。我们在backward方法中实现此函数。为此,我们从输出开始,计算预测值与实际输出之间的误差。这将用于计算在更新权重时使用的delta。在所有层中,我们将神经元的输出用作输入,将其通过sigmoid的导数,然后乘以误差和步长(也称为学习率):


在就每个数据点训练模型时,我们将进行两次传递,前向一次,反向一次。因此,我们的fit方法将如下所示:

现在,神经网络已经准备就绪,可以用于我们的任务了。我们还需要一个训练集和一个测试集:

现在可以如下训练网络:

我们将验证算法的性能,如下所示:


1 000个epoch后的MSE小于0.01,这是一个相当不错的结果。我们通过使用ROC曲线下面积(Area Under the Curve,AUC)来衡量性能,该指标衡量了预测情况的好坏。如果AUC超过0.99,我们相信会有极少的错误,但是该模型仍然运行良好。
也可以使用混淆矩阵来验证性能。这种情况下,我们必须设定阈值以区分预测一个标签或另一个标签。由于结果之间有很大的差距,因此将阈值设为0.5可能比较合适:

我们会得到一个不错的结果,可通过下列的混淆矩阵进行检测。

通过可视化聚类结果,我们可以清楚地知道误差在哪里,如图2-16所示。

图 2-16