![神经网络设计与实现](https://wfqqreader-1252317822.image.myqcloud.com/cover/765/38894765/b_38894765.jpg)
2.4 从头开始使用Python编写FFNN
为了创建我们的网络,我们将创建一个类,它与第1章为感知器创建的类相似。与面向对象编程(OOP)所规定的相反,我们不会利用先前创建的感知器类,而使用更为方便的权重矩阵。
我们的目标是使用代码展示如何实现我们刚刚说的理论。因此,解决方案将非常适合于我们的用例。我们知道网络将分为三层,输入大小将为2,并且知道隐藏层中神经元的数量:
![](https://epubservercos.yuewen.com/96A46E/20422784308285606/epubprivate/OEBPS/Images/040-2-i.jpg?sign=1739601917-rNAaROHTj0aUH6LOcYQRBHgw1HDbhjlB-0-b2ffb3941c2879363e2d3b95c4e46b6a)
![](https://epubservercos.yuewen.com/96A46E/20422784308285606/epubprivate/OEBPS/Images/041-i.jpg?sign=1739601917-0t9AbGOPaOR7ZStQvPqFlF57HmlDlDmE-0-85bfc3656acbbabbced2241692061c54)
由于我们决定使用sigmoid作为激活函数,这里可以将其添加为外部函数。同样,我们知道需要计算导数,因为我们正在使用SGD。因此,我们将其实现为另一种方法。通过使用上述公式,实现变得非常简单:
![](https://epubservercos.yuewen.com/96A46E/20422784308285606/epubprivate/OEBPS/Images/041-2-i.jpg?sign=1739601917-tjRO884bD5TYf0SdwGpi53YEmbWGkFuu-0-2e09bd85c6f7c7d78a1c6093d345e988)
然后,我们用一个函数来计算前向传递,而另一个函数用于反向传递。我们将使用输入和权重之间的点积来计算输出,然后将所有内容通过sigmoid传递:
![](https://epubservercos.yuewen.com/96A46E/20422784308285606/epubprivate/OEBPS/Images/041-3-i.jpg?sign=1739601917-lkfwVILc5yBBii9vclNcgrN4HRNE51kZ-0-5a977f4dcd25b841f2448d8d9a7c5fe6)
前向传播也是我们将用于预测的内容,但是我们将创建别名,因为在此任务中最常用的名称是predict:
![](https://epubservercos.yuewen.com/96A46E/20422784308285606/epubprivate/OEBPS/Images/041-4-i.jpg?sign=1739601917-pmbUZjKt5b8rqsDy6hgoJbFSiDytiNLQ-0-6384c10ae3b9f2cdea0a18b124be7b55)
反向传播中最重要的概念是误差的反向传播,从而调整权重并减少误差。我们在backward方法中实现此函数。为此,我们从输出开始,计算预测值与实际输出之间的误差。这将用于计算在更新权重时使用的delta。在所有层中,我们将神经元的输出用作输入,将其通过sigmoid的导数,然后乘以误差和步长(也称为学习率):
![](https://epubservercos.yuewen.com/96A46E/20422784308285606/epubprivate/OEBPS/Images/041-5-i.jpg?sign=1739601917-v4UCe5Wll9EYq8o8gZYgf7w7ycL2Hsy3-0-e11c206a4714d779f0f13e5299dfc989)
![](https://epubservercos.yuewen.com/96A46E/20422784308285606/epubprivate/OEBPS/Images/042-i.jpg?sign=1739601917-11kiyGE1gnezhg7vU6S3jlr2XqD4qRbm-0-63d93c70274db95fba5fe04ff6c53c98)
在就每个数据点训练模型时,我们将进行两次传递,前向一次,反向一次。因此,我们的fit方法将如下所示:
![](https://epubservercos.yuewen.com/96A46E/20422784308285606/epubprivate/OEBPS/Images/042-2-i.jpg?sign=1739601917-OOBjXfWKeet0yhHSZPNGMTsWREmAuV9v-0-bfcc65a1c3d43429428518ba50e777a7)
现在,神经网络已经准备就绪,可以用于我们的任务了。我们还需要一个训练集和一个测试集:
![](https://epubservercos.yuewen.com/96A46E/20422784308285606/epubprivate/OEBPS/Images/042-3-i.jpg?sign=1739601917-COTWV8sWTjiBkinHejNap5Kp4IVXI928-0-7be3125912a268da7a7b59c80aa81dd8)
现在可以如下训练网络:
![](https://epubservercos.yuewen.com/96A46E/20422784308285606/epubprivate/OEBPS/Images/042-4-i.jpg?sign=1739601917-KKzJaaDPWIUm6qGfCEmsMK8Zb46M0enS-0-f782fd9c641e95c148894cada565fe55)
我们将验证算法的性能,如下所示:
![](https://epubservercos.yuewen.com/96A46E/20422784308285606/epubprivate/OEBPS/Images/042-5-i.jpg?sign=1739601917-NpqiZlxMAetOb4wWyHKdaJ5zS3vatR9g-0-672c32e22c736abf9bb1818cdfeb25d5)
![](https://epubservercos.yuewen.com/96A46E/20422784308285606/epubprivate/OEBPS/Images/043-i.jpg?sign=1739601917-u3qGZ96vPOzptkUAYu1w2aLkxQu0IpAu-0-ae3299b0b6fd7e6dabd3d02dca5d826c)
1 000个epoch后的MSE小于0.01,这是一个相当不错的结果。我们通过使用ROC曲线下面积(Area Under the Curve,AUC)来衡量性能,该指标衡量了预测情况的好坏。如果AUC超过0.99,我们相信会有极少的错误,但是该模型仍然运行良好。
也可以使用混淆矩阵来验证性能。这种情况下,我们必须设定阈值以区分预测一个标签或另一个标签。由于结果之间有很大的差距,因此将阈值设为0.5可能比较合适:
![](https://epubservercos.yuewen.com/96A46E/20422784308285606/epubprivate/OEBPS/Images/043-2-i.jpg?sign=1739601917-mmu2WIGqyxGImyJzbvaLImOkjBDM3x3s-0-4fdc57f166aaa06edd038e22f3748446)
我们会得到一个不错的结果,可通过下列的混淆矩阵进行检测。
![](https://epubservercos.yuewen.com/96A46E/20422784308285606/epubprivate/OEBPS/Images/043-3-i.jpg?sign=1739601917-BkPGZvPjOTq6lIp5QWcmgMMBDvYCy7Ca-0-63a5b7e6eabc56dd3a2e36a724eccd96)
通过可视化聚类结果,我们可以清楚地知道误差在哪里,如图2-16所示。
![](https://epubservercos.yuewen.com/96A46E/20422784308285606/epubprivate/OEBPS/Images/2-16.jpg?sign=1739601917-c0qBgD3pXs8V6dmTzglp8TRJZerApLQO-0-864ea0785fc8fadf3f9a7b7435f2218b)
图 2-16