24小时联系电话:15828505243

如何利用Java库学习神经网络

作为开发人员,我们习惯从用命令或函数的角度来思考问题。程序由任务组成,每个任务都包含一些编程结构。神经网络不同于这种编程方法,因为它加入了自动任务改进的概念,或者类似于大脑的学习和改进的能力。换句话说,神经网络在没有特定任务编程的情况下主动学习新的活动。

本教程不是教你从头开始编写神经网络的教程,而是介绍结合Java代码的神经网络。本文主要内容是首先介绍神经网络的发展从McCulloch和Pitt的神经元开始,然后通过Hebb的发现,实现了Rosenblatt的感知器来增强它,并说明了它为什么不能解决XOR问题。其次介绍了通过连接神经元,生成一个多层感知器,并通过应用反向传播算法进行学习,从而实现XOR问题的解决方案。最后在演示神经网络实现、训练算法和测试之后,介绍利用一些致力于深度学习的开源Java ML框架如Neuroph、Encog和Deeplearning4j来快速实现神经网络:

早期的人造神经元模型是由神经生理学家Warren McCulloch和逻辑学家Walter Pitts在1943年引入的。他们的论文名为“神经活动的逻辑微积分”,通常被认为是神经网络研究的开始。mcculloch - pitts神经元工作原理是对每一个输入输入1或0,其中1为真,0为假,然后给神经元分配一个二元阈值激活函数来计算神经元的输出。

 

image

该阈值给定一个实际值,比如1,如果阈值达到或超过阈值,则允许输出0或1。此外,为了表示AND函数,我们设置2.0的阈值,如下表所示: 

 

image

如果我们将阈值切换到1,那么这个方法也可以应用于OR函数。到目前为止,我们具有如表所示的典型的线性可分离数据,我们可以使用直线来划分数据。 然而,McCulloch-Pitts神经元有一些严重的局限性。它既不能解决“异或”功能(XOR)也不能解决不是线性分离的“排他性”功能(XNOR)。 唐纳德·赫布(Donald Hebb)提出下一次革命,他以关于Hebbian学习的理论而闻名。在他1949年出版的《行为的组织》一书中这样写道:

当细胞A的轴突足够接近细胞B,不断反复持续的激活细胞B,两个细胞之间就会产生生长过程或代谢变化,这样A的效率提高了,就像燃烧了细胞B一样”。

换句话说,当一个神经元不停地触发另一个神经元时,第一个神经元的轴突/连接就会形成突触小结,如果它们已经与第二个神经元连接,就会放大它们。Hebb不仅提出,当两个神经元一起点燃神经元之间的连接时,神经元之间的联系就会增强——这被称为神经元之间连接的权重——还提出这个活动是学习和记忆所必需的基本操作之一。因此必须改变McCulloch-Pitts神经元,以便为每个输入分配权重。 此外,相对于总阀值量,1的输入或多或少都被被赋予了权重。

后来,在1962年,由Frank Rosenblatt在他的《神经动力学原理》一书中定义并描述了感知器。这是一个神经元的模型,它可以通过输入的权重在Hebbean Sense 中学习,并为后来神经网络的发展奠定了基础。感知器学习使用随机权重初始化感知器,在激活后反复检查答案是否正确。如果不正确,神经网络可以从错误中学习并调整它的权重。

 

image

尽管感知器对原始McCulloch-Pitts神经元进行了许多改变,但感知器仍然局限于解决某些功能。1969年,Minsky与Seymour Papert,合著了” 感知器:计算几何的介绍”,在文章中攻击了感知器的局限性。文章中表明,感知器只能解决线性可分函数,并没有打破这点的限制。直到20世纪80年代以前,这方面的研究还很少。现在解决这些困难的方法之一就是建立神经网络。这些网络将人工神经元的输入与其他人工神经元的输出连接起来。因此,网络能够解决更困难的问题,但它们也会变得相当复杂。但感知器没有解决的XOR问题。如果我们仔细观察真值表,我们可以看到XOR函数变成等价于单个神经元可表示的OR和NOT AND函数。 
让我们再来看看真值表: 

 

image

但是我们可以将代表NOT和AND的两个神经元结合起来,并构建一个神经网络来解决类似于下图所示的XOR问题:

image

这个图表示多层感知器,它有一个输入层,一个隐藏层和一个输出层。神经元之间的连接与图片中没有显示的权重有关。与单一感知器类似,每个处理单元都有一个summing和激活组件。它看起来很简单,但我们也需要一个训练算法来调整各个层次的权重,并让它学习。通过简单的感知器,我们可以很容易地根据误差计算变化权重。从而训练多层感知器实现计算神经网络的整体错误。

1986年,Geoffrey Hinton,David Rumelhart和Ronald Williams发表了一篇论文,“通过反向传播错误学习表示”,描述了一个新的学习过程,反向传播。该过程反复调整网络中连接的权重,从而最小化网络实际输出向量和所需输出向量之间的差值。作为权重调整的结果,内部隐藏的单元(不是输入或输出的一部分)被用来表示重要的特征,并且这些单元通过交互捕获规律性任务。

现在我们已经能够编写使用Java学习XOR函数的多层感知器。这需要创建一些类,比如名为ProcessingUnit的神经元接口,连接类,一些更活跃的函数,以及一个能够学习的单层神经网络。在我的GitHub存储库中你可以在项目中找到这些接口和类。

其中NeuralNet类负责对层的构造和初始化。它还提供了训练和评估激活结果的功能。 如果运行NeuralNet类来解决典型的XOR问题,它将激活,评估结果,应用反向传播算法和输出训练结果。

如果你仔细查看代码,你会发现它在可重用性方面并不是非常灵活。如果我们将NeuralNet结构从训练部分分离出来,变成把各种学习算法应用在各种神经网络结构上,那就更好了。此外,我们想要更深入的学习结构和各种激活函数,则必须改变数据结构。因为到目前为止,只有一个隐藏层被定义。为了确保不产生任何bug,反向传播计算必须经过仔细的测试。一旦完成了所有的重构,我们就必须开始考虑深层神经网络的性能。

我想说的是,如果我们进行实际开发,那么首先需要看看现有的神经网络库。虽然从头开始实现神经网络有助于理解整个网络的细节,但是如果一个真实的解决方案必须从头开始实施,那么将要付出很大的努力。在本文中,我只选择了纯Java神经网络库。尽管Deeplearning4j得到了商业支持,但所有这些都是开源的。网上都有大量的参考文档和例子。其中Deeplearning4j也支持CUDA。维基百科也提供了一份关于各种语言的深度学习软件的综合列表。

如何使用神经网络库的示例也被包含在关于使用XOR NeuralNet的GitHub中。很明显,在开发中利用现成的函数库与自己编写java代码相比工作量要少很多。其中Neuroph是为数据集提供的API,它更容易初始化训练数据,学习规则的层次结构,进行神经网络串行化/持久性和反序列化,并带有GUI。Encog是一种先进的机器学习框架,支持多种高级算法,也支持规范化类和处理数据。然而,它的主要优势在于神经网络算法。Encog包含创建各种网络的类,以及支持这些神经网络的规范化和处理数据的支持类。Deeplearning4j是一个非常强大的库,支持多种算法,包括与Apache Hadoop和Spark集成的分布式并行版本。对于有经验的开发人员和软件架构师来说,这绝对是正确的选择。这里作为神经网络库的一部分提供了一个XOR示例。

想在要利用现有的众多神经网络库,开发人员需要熟悉各种各样的参数,从而让他们的神经网络进行学习。本文演示了一个非常简单的例子,它包含神经元和反向传播。然而,今天使用的许多人工神经网络仍然来使用mcculloch - pitts神经元和Rosenblatt感知器的早期版本。作为构建现代深层神经网络的基石,重要的是要理解神经元的根,并在库中利用好现成的神经元、层、激活函数和学习算法。