【发布时间】:2012-03-11 06:28:38
【问题描述】:
概述
所以我试图掌握神经网络的机制。我仍然没有完全掌握它背后的数学原理,但我想我明白如何实现它。我目前有一个可以学习 AND、OR 和 NOR 训练模式的神经网络。但是,我似乎无法让它实现 XOR 模式。我的前馈神经网络由2个输入、3个隐藏和1个输出组成。权重和偏差随机设置在-0.5和0.5之间 ,并使用 sigmoidal 激活函数
生成输出算法
到目前为止,我猜我在训练算法中犯了一个错误,如下所述:
- 对于输出层中的每个神经元,提供一个
error值,即desiredOutput - actualOutput--转到第 3 步 - 对于隐藏层或输入层(向后工作)中的每个神经元,提供一个
error值,它是所有forward connection weights * the errorGradient of the neuron at the other end of the connection的总和 --转到第 3 步 - 对于每个神经元,使用提供的
error值,生成一个等于output * (1-output) * error的error gradient。 --转到第 4 步 - 对于每个神经元,将偏差调整为等于
current bias + LEARNING_RATE * errorGradient。然后调整每个反向连接的权重等于current weight + LEARNING_RATE * output of neuron at other end of connection * this neuron's errorGradient
我正在在线训练我的神经网络,所以它会在每个训练样本之后运行。
代码
这是运行神经网络的主要代码:
private void simulate(double maximumError) {
int errorRepeatCount = 0;
double prevError = 0;
double error; // summed squares of errors
int trialCount = 0;
do {
error = 0;
// loop through each training set
for(int index = 0; index < Parameters.INPUT_TRAINING_SET.length; index++) {
double[] currentInput = Parameters.INPUT_TRAINING_SET[index];
double[] expectedOutput = Parameters.OUTPUT_TRAINING_SET[index];
double[] output = getOutput(currentInput);
train(expectedOutput);
// Subtracts the expected and actual outputs, gets the average of those outputs, and then squares it.
error += Math.pow(getAverage(subtractArray(output, expectedOutput)), 2);
}
} while(error > maximumError);
现在是train() 函数:
public void train(double[] expected) {
layers.outputLayer().calculateErrors(expected);
for(int i = Parameters.NUM_HIDDEN_LAYERS; i >= 0; i--) {
layers.allLayers[i].calculateErrors();
}
}
输出层calculateErrors()函数:
public void calculateErrors(double[] expectedOutput) {
for(int i = 0; i < numNeurons; i++) {
Neuron neuron = neurons[i];
double error = expectedOutput[i] - neuron.getOutput();
neuron.train(error);
}
}
普通(隐藏和输入)层calculateErrors()函数:
public void calculateErrors() {
for(int i = 0; i < neurons.length; i++) {
Neuron neuron = neurons[i];
double error = 0;
for(Connection connection : neuron.forwardConnections) {
error += connection.output.errorGradient * connection.weight;
}
neuron.train(error);
}
}
完整的神经元类:
package neuralNet.layers.neurons;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import neuralNet.Parameters;
import neuralNet.layers.NeuronLayer;
public class Neuron {
private double output, bias;
public List<Connection> forwardConnections = new ArrayList<Connection>(); // Forward = layer closer to input -> layer closer to output
public List<Connection> backwardConnections = new ArrayList<Connection>(); // Backward = layer closer to output -> layer closer to input
public double errorGradient;
public Neuron() {
Random random = new Random();
bias = random.nextDouble() - 0.5;
}
public void addConnections(NeuronLayer prevLayer) {
// This is true for input layers. They create their connections differently. (See InputLayer class)
if(prevLayer == null) return;
for(Neuron neuron : prevLayer.neurons) {
Connection.createConnection(neuron, this);
}
}
public void calcOutput() {
output = bias;
for(Connection connection : backwardConnections) {
connection.input.calcOutput();
output += connection.input.getOutput() * connection.weight;
}
output = sigmoid(output);
}
private double sigmoid(double output) {
return 1 / (1 + Math.exp(-1*output));
}
public double getOutput() {
return output;
}
public void train(double error) {
this.errorGradient = output * (1-output) * error;
bias += Parameters.LEARNING_RATE * errorGradient;
for(Connection connection : backwardConnections) {
// for clarification: connection.input refers to a neuron that outputs to this neuron
connection.weight += Parameters.LEARNING_RATE * connection.input.getOutput() * errorGradient;
}
}
}
结果
当我训练 AND、OR 或 NOR 时,网络通常可以在大约 1000 个 epoch 内收敛,但是当我使用 XOR 训练时,输出变得固定并且永远不会收敛。那么,我做错了什么?有什么想法吗?
编辑
听从其他人的建议,我重新开始并在没有类的情况下实现了我的神经网络......并且它有效。我仍然不确定我的问题出在上面的代码中,但它就在那里。
【问题讨论】:
-
哇,我已经很久 没有接触过神经网络了。当你说它卡住并且永远不会收敛时,我的第一个想法是你可能达到了局部最小值。我不记得什么样的 NN 架构和条件可以产生这种情况,或者你做了什么来解决它。
-
NN 实现中存在很多错误的可能性。您的架构应该能够学习 XOR,因此您的实现显然有问题。你应该仔细观察你的神经网络通过误差面的路径,看看它是否朝着正确的方向前进。这可能会给你一些关于出了什么问题的提示。除此之外,您的算法看起来不错,但我还没有将它与文献进行比较,所以最好仔细检查一下。
-
神经网络实现的一个很好的提示:不要使用面向对象来实现神经网络。尽管能够在对象级别上对神经元和连接进行建模似乎很好,但这通常只会使您的代码比它需要的更复杂和更慢。如果您仔细观察 NN 的作用,就会发现这一切都归结为简单的矩阵和向量运算。如果您以这些方式实现您的网络,您将拥有更简单的代码,并且调试会更容易。
-
面向对象更有意义。它也更容易阅读。我会尝试消除它,但我宁愿找出问题,因为它存在于我的代码的当前形式中......
标签: java algorithm artificial-intelligence machine-learning neural-network