Brainnet - 介绍一个声明式神经网络库






4.74/5 (110投票s)
本文旨在 (0) 介绍我们开发的声明式神经网络库 Brainnet (1) 演示神经网络编程的一些实际应用 (2) 让您对神经元、神经网络及其应用有一个公平的认识 (3) 介绍 BrainNet 库 - 一个开源库
目录
1. 概述
解决方案架构师:“我们有一个新项目。我们需要开发一个脑肿瘤识别系统。你觉得可以做吗?”
笨拙(又懒惰)的程序员:“不行。哦,可能可以吧——让我找找有没有现成的组件或库。”
![]() | 本系列文章最重要的目标是
BrainNet 目前并非商业标准库,仍处于 beta 阶段。但我希望将 BrainNet 呈献给开源社区——主要是为了
在此过程中,我还会解释如何开发一些很酷的神经网络应用程序。例如,即使在本介绍性文章中,您也将学会如何开发两个神经网络程序:
谁知道呢,也许这些文章会激发您产生一些新的概念,甚至改变我们看待世界的方式——总之,祝您好运,编程愉快!! |
1.1 系列文章导读
我计划写几篇关于神经网络和 BrainNet 神经网络库的文章。在本系列文章中,我将
- 提供关于如何在您的项目中使用此神经网络库的技巧。
- 用简单的英语解释到底什么是神经网络。
- 解释神经元和神经网络的概念。
- 介绍并解释 BrainNet 库的编程模型和设计。
- 介绍并解释 **Neural XML** (NXML),一种基于 XML 的编程语言(它是 BrainNet 库的一部分),用于创建、训练和运行神经网络。
总之,阅读完本系列文章后,您将
- 对神经元和神经网络有公平的认识
- 对智能系统有良好的概念
- 学会如何使用此神经网络库来完成您的项目。
- 了解如何开发一些很酷的神经网络程序
在讨论 BrainNet 库时,我们应该分析
我们可以用这个库做什么
- 这个问题的答案将让您充分理解如何在您的项目中使用该库。
库的内部结构或库的实际实现和设计
- 这个问题的答案将让您充分理解如何自己扩展库,并修改它以满足您的需求。
1.2 本文导读
这是本系列的第一篇文章。本文旨在回答第一个问题——我们可以用这个库做什么。在本文中,
- 我将为您提供对神经网络的非常高层次的概述。
- 我将解释如何在您的项目中实现神经网络逻辑。
此外,本文还将讨论如何使用 BrainNet 库开发两个应用程序,
- DigitalNeuralGate - 一个双输入神经网络数字门,可以训练以执行各种数字门的功能(如 XOR、AND、OR 等)。
- PatternDetector - 一个简单的手写/模式识别程序,可以分析图像以识别它。
未来的文章将提供更多细节——目前,我的目标是为完全不懂神经网络编程的人提供一个良好的基础。您可以在相关源代码 zip 文件中找到所有这些项目的源代码。
1.3 一些有趣的说明
现在,关于新兴趋势和未来计算,再说几句。
如今,**受生物启发的计算**项目越来越受欢迎。它们被用于各种领域,包括学习和识别系统、商业预测、数据挖掘、模式检测等。
本文是关于受生物启发的计算的文章系列的第一篇。我计划在未来的文章中讨论更多主题,如遗传算法、康威生命游戏等。我最重要的目标是提高编程社区对将这些不同技术和逻辑结合起来的可能性——以发明更准确的系统——的认识。当然,未来正朝着混合系统的方向发展。
对我而言,学习这些主题的主要灵感仅仅在于这些主题中的“自然”之美。我们都知道,大自然充满神秘,我们可以从大自然中学到很多东西,当我们可以(使用计算机)将这些关于大自然的知识转化为应用时,程序员就达到了艺术家的境界。就像艺术家从大自然中获得灵感一样,我相信科学家和程序员也可以以同样的方式获得直觉。如果您问一个诗人他如何写诗,他可能会说——“它来自我内心深处的一个安静的角落”。同样地——我相信——如果您问自己如何获得您一生中最精彩的编程逻辑或想法——您可能会说出同样的话。
|
2. 介绍 BrainNet 库 - 开发一个简单的神经网络数字门
即使不完全理解神经网络背后的理论,您也可以直接在您的项目中使用该库。在本节中,
- 我将解释一些关于神经网络的基本事实。
- 我们将开发一个简单的数字神经网络门——即一个具有两个输入和一个输出的门,可以训练以执行 AND 门、OR 门、XOR 门等各种门的功能。
2.1 一些非常基本的事实
在开始之前,您应该了解一些关于神经网络的基本事实。
- 神经网络由多个层组成。
- 每一层可以包含任意数量的神经元。
以下是关于神经网络结构的一些基本事实:
- 网络的第一个层称为输入层,我们在此应用输入。
- 最后一层称为输出层,我们在此获取输出。
- 神经网络可以在输入层和输出层之间包含任意数量的隐藏层。
- 在大多数神经网络模型中,一层中的一个神经元连接到下一层的所有神经元。
图:2-2-1 网络
例如,在上图中,N1 和 N2 是输入层的神经元,N3 和 N4 是隐藏层的神经元,N5 是输出层的神经元。我们将输入提供给 N1 和 N2。每一层的每个神经元都连接到下一层的所有神经元。根据每层的神经元数量,上面的网络可以称为 2-2-1 网络。
现在,关于训练的一些基本事实。
- 您可以通过提供输入和输出来训练神经网络。
- 网络将实际从输入和输出来学习——这将在后面详细解释。
- 训练完成后,您可以提供输入以获取输出。
2.2 使用 BrainNet 库开发一个 2-2-1 网络
现在我们将看到如何使用 BrainNet 库开发一个神经网络,该网络可以训练以执行数字门功能。我们将创建一个 2-2-1 网络——也就是说,一个具有两个输入神经元、两个隐藏层神经元和一个输出神经元的网络——正如上图所示。然后,我们将看到如何训练这个网络以执行各种双输入数字门的功能——例如 AND 门、OR 门、XOR 门等。
需要注意的重要一点是,我们可以训练同一个网络来学习各种门的功能。网络将从门的真值表中学习对给定输入应产生什么输出——经过多次训练。
注意:本项目包含在本文附带的源代码 zip 文件中。解压 zip 文件,在 Visual Studio.NET 中打开解决方案,将启动项目设置为“NeuralGate”并运行项目。
DigitalNeuralGate 类
要使用 BrainNet 库,您需要从您的项目创建对 BrainNet.NeuralFramework.Dll 库文件的引用。
让我们看一下 `DigitalNeuralGate` 类的代码。在类的构造函数中,我们基本上创建了一个神经网络,该网络在第一层有 2 个神经元,在隐藏层有 2 个神经元,在输出层有 1 个神经元。`Train` 函数将训练数据对象(包括输入和输出)传递给库的 `TrainNetwork` 函数。`Run` 函数将一个 ArrayList 作为输入传递给库的 `RunNetwork` 函数。
'Let us import the BrainNet framework
Imports BrainNet.NeuralFramework
'<summary> Our simple digital neural gate class </summary>
Public Class DigitalNeuralGate
'A variable to hold our network
Private network As BrainNet.NeuralFramework.INeuralNetwork
'<summary> This is the constructor. Here, we will create a
2-2-1 network </summary>
Public Sub New()
'Create the factory to create a Backward Propagation Neural Network
'Backward Propagation neural network is a commonly used neural
'network model
Dim factory As New BrainNet.NeuralFramework.BackPropNetworkFactory()
'This is an array list which holds the number of neurons in each layer
Dim layers As New ArrayList()
'We need 2 neurons in first layer
layers.Add(2)
'We need 2 neurons in the second layer (the second layer is the first
'hidden layer)
layers.Add(2)
'We need one neuron in the output layer
layers.Add(1)
'Provide the arraylist as the parameter, to create a network
network = factory.CreateNetwork(layers)
'Now, network holds a 2-2-1 neural network object in it.
End Sub
'<summary> This is the function for training the network using
'the brainnet library </summary>
Public Sub Train(ByVal input1 As Long, ByVal input2 As Long, _
ByVal output As Long)
'Create a training data object
Dim td As New TrainingData()
'Add inputs to the training data object
td.Inputs.Add(input1)
td.Inputs.Add(input2)
'Add expected output to the training data object
td.Outputs.Add(output)
'Train the network one time
network.TrainNetwork(td)
End Sub
'<summary>This is the function for running the network using the
'brainnet library </summary>
Public Function Run(ByVal input1 As Long, ByVal input2 As Long) As Double
'Declare an arraylist to provide as input to the Run method
Dim inputs As New ArrayList()
'Add the first input
inputs.Add(input1)
'Add the second input
inputs.Add(input2)
'Get the output, by calling the network's RunNetwork method
Dim outputs As ArrayList = network.RunNetwork(inputs)
'As we have only one neuron in the output layer,
'let us return its output
Return outputs(0)
End Function
End Class
代码是自解释的,并且有大量的注释。但是,这里还有一些其他要点。
Sub New() 中代码的解释 - 使用 BrainNet 库创建神经网络
您可以通过创建 `BrainNet.NeuralFramework.BackPropNetworkFactory` 类型的对象并调用工厂对象的 `CreateNetwork` 函数来创建网络。
- 请查看类的构造函数,我们使用 `BrainNet.NeuralFramework.BackPropNetworkFactory` 类型的工厂对象的 `CreateNetwork` 函数来创建我们的神经网络对象。
- 我们使用 ArrayList 作为输入,将每层的神经元数量提供给 `CreateNetwork` 函数。
- `CreateNetwork` 函数将返回 `BrainNet.NeuralFramework.INeuralNetwork` 类型的对象。
- 如果您想了解更多关于工厂模式(及其用法)的信息,阅读我关于设计模式的文章 [点击这里] 可能会有帮助。
Train() 函数中代码的解释
- 可以通过调用网络的 `TrainNetwork` 函数来进行训练。`TrainNetwork` 函数的输入是 `TrainingData` 对象。`TrainingData` 对象包含两个 ArrayList——Inputs 和 Outputs。
- TrainingData.Inputs 中的元素数量应与您输入层中的神经元数量完全匹配。
- TrainingData.Outputs 中的元素数量应与您输出层中的神经元数量完全匹配。
Run() 函数中代码的解释
- 在训练网络后,您可以调用网络的 `RunNetwork` 函数来运行它。Run 函数的输入参数是一个 ArrayList,其中包含输入层输入。同样,此 ArrayList 中的元素数量应与输入层中的神经元数量匹配。
- Run 函数将返回一个 ArrayList,其中包含输出值。此 ArrayList 中的元素数量将等于输出层中的元素数量。
用于测试我们 DigitalNeuralGate 类的用户界面
为了测试数字神经网络门,让我们创建一个简单的界面,该界面可以创建门、读取用于训练门的输入,并获取输出进行显示。
图:用于测试门的 UI
在这里,我们在窗体加载时创建一个 DigitalNeuralGate 的新对象(请参见源代码中的 Form Load 事件)。此外,用户可以通过单击“重置门”按钮来创建新的 DigitalNeuralGate。一开始,训练文本框中提供的真值表被初始化为匹配 XOR 门的真值表(希望您还记得简单的布尔代数)。但是,您可以通过单击链接来更改真值表,或者通过直接在文本框中输入来自定义真值表。运行项目并查看。
首先,通过单击“重置门”重置门,然后只需单击“运行网络”按钮并查看输出。输出不匹配真值表的输出。现在,我们可以使用真值表中的值来训练网络。单击“训练 1000 次”按钮,然后单击“运行网络”按钮。您可以看到输出越来越接近预期输出——也就是说,网络正在学习。执行此操作几次,观察准确性的提高。
要尝试不同的真值表,请单击“重置门”,更改真值表,然后根据需要重复上述步骤。
源代码包含在 zip 文件中。请打开它并查看项目。
TrainOnce 是一个简单的函数,它调用我们上面开发的门的 Train 函数。
'Train the network once, by using the inputs and output
Sub TrainOnce()
'Train the network using the training data, by passing
'inputs and outputs to the train function of the gate
'inp11, inp12, out1 etc are textbox names
gate.Train(CLng(Me.inp11.Text), CLng(Me.inp12.Text), CLng(Me.out1.Text))
gate.Train(CLng(Me.inp21.Text), CLng(Me.inp22.Text), CLng(Me.out2.Text))
gate.Train(CLng(Me.inp31.Text), CLng(Me.inp32.Text), CLng(Me.out3.Text))
gate.Train(CLng(Me.inp41.Text), CLng(Me.inp42.Text), CLng(Me.out4.Text))
End Sub
此函数处理“训练 1000 次”按钮的单击事件。它只是将上面的 TrainOnce 函数调用 1000 次。
'Train the network 1000 times
Private Sub cmdTrain1000_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles cmdTrain1000.Click
Dim i As Integer
Try
'Call the TrainOnce function 1000 times
For i = 0 To 1000
TrainOnce()
Next
Catch ex As Exception
MsgBox("Error. Check whether the input is valid - " + ex.Message)
End Try
End Sub
此函数处理“运行网络”按钮的单击事件,通过提供输入并设置输出到输出文本框来运行网络。
'Run the network to get the output, and show it in the text boxes
Private Sub cmdRun_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles cmdRun.Click
Try
'rout1, rinp11, rinp12 etc are textbox names
rout1.Text = gate.Run(CLng(Me.rinp11.Text), CLng(Me.rinp12.Text))
rout2.Text = gate.Run(CLng(Me.rinp21.Text), CLng(Me.rinp22.Text))
rout3.Text = gate.Run(CLng(Me.rinp31.Text), CLng(Me.rinp32.Text))
rout4.Text = gate.Run(CLng(Me.rinp41.Text), CLng(Me.rinp42.Text))
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
现在,我希望您已经注意到一个非常重要的事实。那就是
- 您没有更改 DigitalNeuralGate 中的任何算法,但 DigitalNeuralGate 在您用各种真值表对其进行训练时会产生几乎正确的输出。例如,AND、OR、XOR 等逻辑可以通过外部训练系统来执行,而不是更改系统内部。
|
在本节中,我们刚刚对 BrainNet 神经网络库的能力、简洁性和灵活性进行了非常抽象的概述。
2.3 保存和加载网络
BrainNet 提供对神经网络持久化的内置支持。例如,在上面的情况中,在训练完一个门之后,您可能需要保存其状态以便以后加载。为此,您可以使用 BrainNet 库中的 `NetworkSerializer` 类。
为了演示此功能,让我们向 DigitalNeuralGate 类添加两个函数。
'<summary>This is the function is for saving this gate to
'an xml file </summary>
Public Sub Save(ByVal file As String)
Dim ser As New BrainNet.NeuralFramework.NetworkSerializer()
ser.SaveNetwork(file, network)
End Sub
'<summary>This is the function is for loading this gate
'from an xml file </summary>
Public Sub Load(ByVal file As String)
Dim ser As New BrainNet.NeuralFramework.NetworkSerializer()
ser.LoadNetwork(file, network)
End Sub
`NetworkSerializer` 类中的 `SaveNetwork` 方法会将网络保存到指定路径,而 `LoadNetwork` 函数会将网络加载回来。
3. 开发图像/模式识别系统
在上面的示例中,我们使用 Brian Net 库开发了一个简单的应用程序——一个可以训练以执行任何数字门功能的双输入门。现在是时候做一些更令人兴奋和强大的事情了——使用 BrainNet 库开发一个模式/图像识别程序。我们向网络提供一组图像作为输入,以及与每个图像对应的 ASCII 字符——我们将检查当给定任意图像时网络是否可以预测一个字符。
令人惊讶的是,这个项目开发起来相当容易。这是因为 BrainNet 库提供了一些直接处理图像的功能。本项目将演示
- BrainNet 库对图像处理/识别和模式处理的内置支持。
- BrainNet 库中对使用训练队列的高级训练的内置支持。
在进行代码和解释之前,让我们看看应用程序实际做了什么。您可以在附件的 zip 文件中找到应用程序和源代码。在 Microsoft Visual Studio.NET 中加载解决方案,将启动项目设置为 PatternDetector,然后运行项目。
3.1 玩转模式识别程序
运行程序,您将看到模式识别对话框。该模式识别程序可以“学习”对应于位图(20 x 20 像素大小)的 ASCII 字符。
首先,您需要训练网络。要训练网络,请从“训练此网络”部分提供一些图像和相应的 ASCII 字符值。
图:训练 - 添加图像和对应的字符
提供训练数据:
- 单击“浏览”将图像加载到 picture box 中(您可以在 PatternDetector 的“bin”文件夹中找到一些图像——如果您愿意,也可以在 Paintbrush 中创建 20 x 20 的单色图像)。
- 输入与图像对应的 ASCII 字符——例如,如果您加载字符“A”的图像,则在文本框中输入“A”。
- 单击“添加到队列”按钮。
训练网络:
- 在将图像添加到训练队列后,单击“开始训练”按钮。将网络训练至少 1000 次,以获得低于平均水平的准确性。当您单击“开始训练”按钮时,训练将开始。
- 您将看到一个进度条,指示训练进度。
识别模式
- 训练完成后,转到“使用网络检测”窗格。
- 单击浏览按钮加载图像,然后单击“立即检测此图像”按钮来识别模式。
- 如果您对网络进行了足够次数的训练,并且提供了足够的样本,您将获得正确的输出。
图:识别图像
3.2 玩转源代码
PatternDetector 的代码非常简单。如果您查看 frmMain.vb 窗体的代码,您会发现三个主要函数:
- `InitNetwork` 方法,用于创建/初始化网络。
- `TrainPattern` 方法,用于训练网络。
- `DetectPattern` 方法,用于识别图像。
该程序背后的概念非常简单。
- 我们使用一个 400-400-8 的网络(输入层 400 个神经元,隐藏层 400 个神经元,输出层 8 个神经元)来执行所需的操作。
- 首先,我们将 20 x 20 的图像(即,如您所知,20 x 20 的图像由 400 个像素组成)转换为 1 和 0 的数组。白色像素视为 1,黑色像素视为 0。这被馈送到输入层。
- 如您所知,在训练阶段,我们应该在输入的同时提供输出。为此,字符 ASCII 值的二进制表示被馈送到输出层。
幸运的是,这些任务都不复杂。这可以使用 BrainNet 库的内置功能轻松实现。只需查看 PatternDetector 中的主要函数。
'A private variable to hold our network.
Private network As BrainNet.NeuralFramework.INeuralNetwork
'<summary> Initialize our network </summary>
Sub InitNetwork()
'We are analyzing a 20x20 pixel picture, so let us take the number
'of total inputs as 20 x 20 = 400 neurons
'So let us initialize a 400-400-8 network. I.e, 400 neurons in
'input layer, 400 neurons in hidden layer and 8 neurons in output layer
'We've chosen 8 neurons in output because we need 8 bits to
'represent an ASCII character
'Create the factory to create a Backward Propagation Neural Network
'(Backward Propagation neural network is a commonly used neural
'network model)
Dim factory As New BrainNet.NeuralFramework.BackPropNetworkFactory()
'This is an arralist which holds the number of neurons in each layer
Dim layers As ArrayList = New ArrayList()
'We need 400 neurons in first layer
layers.Add(400)
'We need 400 neurons in the second layer (the second layer is the first
'hidden layer)
layers.Add(400)
'We need 8 neurons in the output layer
layers.Add(8)
'Provide the arraylist as the parameter, to create a network
network = factory.CreateNetwork(layers)
End Sub
'<summary> Routine to train the network </summary>
Sub TrainPattern()
'This routine demonstrates how easily you can train
'a network using a NetworkHelper object
'Here, we are using a NetworkHelper object to train the
'network.
'Create a helper object
Dim helper As BrainNet.NeuralFramework.NetworkHelper
helper = New BrainNet.NeuralFramework.NetworkHelper(network)
'A helper object helps you to train the network more
'efficiently. First of all, you add each training data to the
'Training Queue using the helper. For this, you can use the
'AddTrainingData method of the helper
'Next, you can call the Train function of the helper to
'randomize entries to the training queue and train the network more
'efficiently
'Step 1 - Add the training data from our list view box to the helper
Dim item As ListViewItem
For Each item In Me.lvMain.Items
Dim img As Image = imlMain.Images(item.ImageIndex)
Dim asciiVal As Long = Asc(item.Text)
'The AddTrainingData method of Network helper helps you to
'add an image and its corresponding ASCII value directly
helper.AddTrainingData(img, asciiVal)
Next
'Step 2 - Train the network using the helper
'Get the number of times
Dim rounds As Long = Val(Me.txtTrainTimes.Text)
'Add the handler of ShowProgress delegate, to get
'the progress training progress
StopTraining = False
AddHandler helper.TrainingProgress, AddressOf ShowProgress
'Start training
helper.Train(rounds)
RemoveHandler helper.TrainingProgress, AddressOf ShowProgress
End Sub
'<summary> Routine to detect an image </summary>
Sub DetectPattern()
'Step 1 : Convert the image to detect to an arraylist
Dim imgHelper As New BrainNet.NeuralFramework.ImageProcessingHelper()
Dim input As ArrayList
input = imgHelper.ArrayListFromImage(Me.picImgDetect.Image)
'Step 2: Run the network and obtain the output
Dim output As ArrayList
output = network.RunNetwork(input)
'Step 3: Convert the output arraylist to long value
'so that we will get the ascii character code
Dim patternHelper As New BrainNet.NeuralFramework.PatternProcessingHelper()
Dim character As String = Chr(patternHelper.NumberFromArraylist(output))
Dim bitpattern As String = patternHelper.PatternFromArraylist(output)
'Display the result
Me.txtAsciiDetect.Text = character
Me.txtPatternDetect.Text = bitpattern
End Sub
代码中有大量的注释,但这里有一些额外的解释。
使用 Network Helper 进行训练
检查 `TrainPattern` 函数。我们没有直接训练网络(就像我们在二进制神经网络门的情况下所做的那样),而是使用 Network Helper 对象来训练网络。使用网络助手对象,您可以直接添加图像和相应的 ASCII 码。`NetworkHelper` 类的 `AddTrainingData` 方法已很好地重载,因此它可以接受各种参数(稍后将详细介绍)。
在这里,我们遍历列表视图中的每个元素(即训练队列),并将其添加到助手。然后,我们通过调用助手的“Train”方法来启动训练。输入到“Train”方法的是我们需要训练网络的轮数。更多详情,请参阅 BrainNet 库的帮助文件(包含在 zip 文件中)。
PatternProcessingHelper 和 ImageProcessingHelper
检查 `DetectPattern` 函数。在这里,我们应该向网络提供输入以获得输出。为了将图像转换为 1 和 0 的数组,我们使用 `ImageProcessingHelper` 类中的 `ArrayListFromImage` 函数。从网络获得输出后,我们应该将其转换为等效的 ASCII 码以在文本框中显示字符——为此,我们使用 `PatternProcessingHelper` 类中的 `NumberFromArrayList` 函数。类似地,`PatternFromArrayList` 函数将 ArrayList 转换为字符串(通常是 1 和 0 的字符串)。
除了上述函数外,PatternDetector 项目中还包含处理用户界面的代码。打开项目,查看源代码(有大量注释)以获得更好的理解。
4. 结论
今天就到这里。恭喜您兴致勃勃地完成了这篇文章!!
希望您喜欢这篇文章及相关项目。附件的 zip 文件包含 BrainNet Framework 程序集文件、CHM 格式的 BrainNet 库文档以及上述两个项目的源代码。下载并进行实验。
现在,您可以阅读本系列的第二部分,并下载完整的 BrainNet 库源代码。 在此阅读>> ,或 在此处阅读>>
- 访问我迄今为止发布的所有文章:amazedsaint。您会找到关于设计模式、神经网络、安全、黑客等文章。
- 您可以订阅我的技术文章博客的 XML atom feed,以跟踪新帖子。 点击此处 获取 XML Atom Feed。
访问我的网站 这里,获取大量教程和源代码。
如果您遇到任何错误,请在此处发布您的评论。