使用JavaFx可视化训练损失
深度学习框架过于简化了实现神经网络的过程,有时很容易陷入抽象化学习的陷阱,认为你可以简单地堆叠任意的层并自动完成所有事情[1]。通过从头开始实现核心概念(如神经网络、卷积神经网络和循环神经网络的反向传播算法)来构建机器学习(ML)的坚实基础非常重要。花时间理解其推导过程,并尝试从头开始导出并在代码中从头开始实现它,看看你能否使其正常工作。你获得的知识将会保留,并且不会依赖于你决定后续学习的任何框架。在我的学习过程中,我认为知道发生了什么是有价值的,出于学术好奇心。在本文中,我向你展示了我在Java中纯手工实现的两层NN。
网络架构
下面是我们要在Java中实现的两层前馈神经网络的表示。我们将使用以下网络架构,但所有概念都可以扩展到任意数量的层和节点。
两层神经网络
我们要教我们的神经网络识别的模式是XOR运算。XOR运算符的真值表如下所示,其操作为y = x1 XOR x2
XOR表
一些背景数学知识
以下是上述神经网络架构的前向传播方程[2]。上标表示层,下标表示节点的索引。
第1部分:前向传播方程
向量化
我们所有人都使用for循环来执行大多数需要迭代长列表元素的任务。我相信,几乎所有阅读本文的人都是在高中或大学时编写了他们的第一个矩阵或向量乘法代码,并使用了for循环。for循环服务于编程社区长期稳定。但是,它带有一些负担,当处理大数据集(像在大数据时代中一样,有很多百万条记录)时,它的执行速度通常很慢[3]。
所以让我们向量化我们的方程。结合隐藏层节点的计算(首先忽略激活函数,稍后再回来)。
需要注意的是
-
增加节点数将增加我们的权重矩阵的行数。
-
增加特征数将增加矩阵的列数。
这是我的意思
例如,假设我们在隐藏层中添加了另一个节点。矩阵方程向下增长。
激活函数
我们需要激活函数来学习输入和目标输出之间的非线性复杂功能映射。从前一节中,我忽略了激活函数方程以进行简单的验证。我们将使用sigmoid激活函数。
第2部分:反向传播方程
为了直观地理解反向传播的工作原理,我将使用下面的图表来说明梯度计算,然后使用梯度下降来更新可学习参数w和b。为简单起见,我将使用单层神经网络(逻辑回归)。这个想法可以扩展到N层神经网络[2]。
我们将使用交叉熵损失来计算成本
导数。可以使用链式法则来完成。
计算损失函数对偏差的(db)导数。
更新方程
我们将使用梯度下降来对每一层进行参数更新,如下所示。
完整的Java代码
理解上述概念是理解此代码如何工作的关键部分。
np.java包含所有矩阵操作。
训练结果
下面是训练NN 4000次后的结果。我们可以清楚地看到(Prediction = [[0.01212, 0.9864, 0.986300, 0.01569]]),我们的网络已经成功地模拟了XOR运算。我们可以看到内部值被推到1,而外部值被推到0。
==============Cost = 0.1257569282040295Prediction = [[0.15935, 0.8900528, 0.88589, 0.0877284694]]。
.
.Cost = 0.015787269324306925Prediction = [[0.013838, 0.984561, 0.9844246, 0.0177971]]==============Cost = 0.013869971354598404Prediction = [[0.01212, 0.9864, 0.986300, 0.01569]]
结论
这不是一个高效的神经网络实现,但我的目的是传达对机器学习概念的直观理解,并有能力将它们转化为代码。
你觉得这篇文章有帮助吗?你发现了什么错误吗?(可能是因为这是我的第一篇文章,英语不是我的母语。)你有什么意见/评论吗?请在下面留言。
参考资料
[1] https://medium.com/@karpathy/yes-you-should-understand-backprop-e2f06eab496b
评论(0)