第4章 神经网络框架和感知机的实现

转载请注明出处,感谢大家的支持!
本文来自优优码:http://www.uucode.net/201406/nnframework-perceptron

在了解了感知机的运作原理之后,现在可以动手实现自己的感知机了。本书使用Neuroph神经网络框架来实现本书中提及的神经网络和相关示例。在此,让我们简单得了解一下Neuroph。Neuroph是一个轻量级的开源Java神经网络框架,它可以简化神经网络的开发和实现。Neuroph结构简单清晰,非常适合初学者入门。

首先,来看一下Neuroph中最重要的类Neuron。它表示单个神经元。Neuron结构如图4.1所示。这里没有罗列出Neuron所有的属性和方法,只展示了与本章节相关的部分。其它内容将在后续章节中一一给出介绍。

4.1 Neuron部分属性

其中inputConnections表示神经元的输入连接。比如一个输入刺激到神经元,就构成一条输入。由于神经元是可以有多个输入的,神经元和输入连接是一对多的关系。netInput表示净输入,输入函数的输出。output表示神经元的输入。error为神经元的误差。inputFunction 表示输入函数,通常选择加权求和。transferFunction表示传输函数。

另一个重要的类为Connection。它表示神经元的连接,可以是两个神经元之间的连接,也可以使输入信号与神经元之间的连接(实际上,输入信号可以看做一个输出永远等于输入的简单神经元),weight表示这个连接的权重。

方法Neuron.calculate()为神经元的核心方法。它根据神经元输入inputConnections计算神经元的净输入,并根据净输入得到神经元的输出。核心代码如下:

public void calculate() {

if ((this.inputConnections.length > 0)) {

    this.netInput = this.inputFunction.getOutput(this.inputConnections);

}

//净输入传入传输函数形成神经元的输出

this.output = this.transferFunction.getOutput(this.netInput);

}

可以看到,神经元首先使用输入函数计算净输入,然后根据净输入得到神经元的输出。此处,一般使用的输入函数为加权求和。其实现的核心如下:

public double getOutput(Connection[] inputConnections) {

double output = 0d;

//计算w1*p1+ w2*p2+ w3*p3+…..

for (Connection connection : inputConnections) {

output += connection.getWeightedInput();

}

return output;

}

Connection.getWeightedInput()的实现如下:

public double getWeightedInput() {

//计算w*q

return this.fromNeuron.getOutput() * weight.value;

}

参考代码中注释,可以看到,每个Connection都会根据输入和权重,计算加权输入。神经元的所有加权输入会被求和,形成净输入netInput。最终,净输入传入传输函数形成神经元的输出。第2章中提到的传输函数在Neuroph中都可以找到。下面看一下Step传输函数的实现:

public double getOutput(double net) {

if (net > 0d)

// yHigh 默认是1

return yHigh;

else

// yLow默认是0

return yLow;

}

至此,神经元模型的实现已经和第2章中提到的理论非常接近了,但仍然有一个重要的元素被遗漏,那就是神经元偏置。细心的读者一定发现,在Neuroph框架定义的Neuron中并没有偏置的出现。这是因为Neuroph使用一种特殊的神经元BiasNeuron来模拟神经元偏置。BiasNeuron神经元非常特殊,它总是输出1,接收一个BiasNeuron神经元做输入的任何神经元便等价于有了偏置1。BiasNeuron神经元到输入神经元间的权重w就是输入神经元的偏置b。读者可以回顾图2.1。

令一个常用的神经元是InputNeuron。它的输出就是它的输入,它用来表示一个独立的输入刺激。所以,使用Neuroph框架中的对象,来表示一个简单的感知机网络,便得到了如图4.2所示的结构。

4.2 Neuroph中的简单感知机

图4.3中,神经元偏置被视为输入恒为1的一个普通神经元输入,其权重为b。它的学习算法与其它神经元连接是一样的。

以下代码构建了一个有inputNeuronsCount个输入的感知机网络。

private void createNetwork(int inputNeuronsCount) {

// 设置网络类别为
感知机

this.setNetworkType(NeuralNetworkType.PERCEPTRON);

// 输入神经元建立
,表示输入的刺激

NeuronProperties inputNeuronProperties = new NeuronProperties();

inputNeuronProperties.setProperty(“neuronType”, InputNeuron.class);

// 由输入神经元构成的输入层

Layer inputLayer =

LayerFactory.createLayer(inputNeuronsCount, inputNeuronProperties);

this.addLayer(inputLayer);

// 在输入层增加BiasNeuron,表示神经元偏置

inputLayer.addNeuron(new BiasNeuron());

// 传输函数是Step

NeuronProperties outputNeuronProperties = new NeuronProperties();

outputNeuronProperties.setProperty(“transferFunction”,

TransferFunctionType.STEP);

// 输出层,也就是神经元

Layer outputLayer = LayerFactory.createLayer(1, outputNeuronProperties);

this.addLayer(outputLayer);

// 将输入层的输入导向神经元

ConnectionFactory.fullConnect(inputLayer, outputLayer);

NeuralNetworkFactory.setDefaultIO(this);

// 设置感知机学习算法 LMS学习算法可以理解为第3章介绍的感知机学习算法

this.setLearningRule(new LMS());

}

以上代码首先创建了一个含有inputNeuronsCount个输入的输入层,接着为这层加入了BiasNeuron,BiasNeuron用于模拟输出层神经元的偏置。接着创建了输出层的神经元,并指定传输函数为Step。最后,将输入层和传输层进行连接,同时指定了感知机网络的学习算法,有关这里LMS算法将在下一章给出解释,现在可以简单的理解为第3章介绍的感知机学习算法(实际上,两者对权值的更新公式也几乎一样)。

至此,一个简单的感知机网络已经建立,使用这个网络已经可以处理简单诸如水果分类之类的问题。在下一章中,我们将训练这个神经网络,并让他记忆和解决简单的问题。

发表评论

您的电子邮件地址将不会被公开. 必填昵称和邮箱 *

*

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

你必须启用javascript
滚动到顶部
备案号:浙ICP备08112675号-4 浙公网安备 33010502001953号