【问题标题】:XOR Neural Network(FF) converges to 0.5XOR 神经网络 (FF) 收敛到 0.5
【发布时间】:2016-10-08 02:48:02
【问题描述】:

我创建了一个程序,允许我创建任意大小/长度的灵活神经网络,但是我正在使用 XOR 设置的简单结构(前馈、Sigmoid 激活、反向传播、无批处理)对其进行测试.

编辑:以下是我原来的问题的全新方法,它没有提供足够的信息

编辑 2:我的体重开始在 -2.5 和 2.5 之间,并修复了我的代码中的一个问题,我忘记了一些负面因素。现在它要么在所有情况下收敛到 0,要么在所有情况下收敛到 1,而不是 0.5

一切都完全按照我认为应该的方式运行,但是它正在向 0.5 收敛,而不是在 0 和 1 的输出之间振荡。我已经完全完成并手动计算了整个设置前馈/计算增量错误/后退prop./等,它与我从程序中得到的相匹配。我还尝试通过改变学习率/动量来优化它,以及增加网络的复杂性(更多的神经元/层)。

因此,我假设我的方程式中的一个是错误的,或者我的神经网络中存在某种其他类型的误解。以下是我对每个步骤遵循的方程式逻辑:

我有一个包含两个输入和一个偏差的输入层,一个包含 2 个神经元和一个偏差的隐藏层,以及一个包含 1 个神经元的输出。

  1. 从两个输入神经元和偏置神经元中获取输入,然后将它们乘以各自的权重,然后将它们加在一起作为隐藏层中两个神经元中每个神经元的输入。
  2. 获取每个隐藏神经元的输入,通过 Sigmoid 激活函数(参考 1)并将其用作神经元的输出。
  3. 获取隐藏层中每个神经元的输出(偏置为 1),将它们乘以各自的权重,然后将这些值添加到输出神经元的输入中。
  4. 将输出神经元的输入通过 Sigmoid 激活函数,并将其用作整个网络的输出。
  5. 计算输出神经元的Delta误差(参考2
  6. 计算 2 个隐藏神经元中的每一个的 Delta 误差(参考 3
  7. 计算每个权重的梯度(参考4)(从末端开始计算)
  8. 计算每个权重的Delta权重(参考5),并将其添加到其值中。
  9. 通过更改输入和预期输出重新开始流程(参考6

以下是对方程式/过程的引用的详细信息(这可能是我的问题所在!):

  1. x 是神经元的输入:(1/(1 + Math.pow(Math.E, (-1 * x))))
  2. -1*(actualOutput - expectedOutput)*(Sigmoid(x) * (1 - Sigmoid(x))//Same sigmoid used in reference 1
  3. SigmoidDerivative(Neuron.input)*(The sum of(Neuron.Weights * the deltaError of the neuron they connect to))
  4. ParentNeuron.output * NeuronItConnectsTo.deltaError
  5. learningRate*(weight.gradient) + momentum*(Previous Delta Weight)
  6. 我有一个数组列表,其中包含值0,1,1,0 按此顺序排列。它需要第一对(0,1),然后需要1。第二次通过,它需要第二对(1,1) 并期望0。它只是不断迭代每个新集合的列表。也许以这种系统的方式训练它会导致问题?

就像我之前说的,他们认为我认为这不是代码问题的原因是它与我用纸和铅笔计算的结果完全匹配(如果出现编码错误就不会发生这种情况)。

另外,当我第一次初始化权重时,我会给它们一个介于 0 和 1 之间的随机双精度值。这篇文章认为这可能会导致问题:Neural Network with backpropogation not converging 会是这样吗? 我使用了 n^(-1/2) 规则,但这并没有解决问题。

如果我可以更具体或者您想要其他代码,请告诉我,谢谢!

【问题讨论】:

  • 您问题的简短摘要:我有一堆代码没有显示,因为我很确定它是正确的。但是有些东西不起作用。怎么了?
  • @Henry 是的,我很抱歉,但我不知道从哪里开始。它是 3 个类的组合,每个类都有几百行代码。然而,收敛到 0.5 的神经网络是一个非常具体的问题,我希望有人至少有一个方向让我开始寻找。我将添加我的 deltaerror 和梯度代码,因为它不会太长
  • @Henry 我刚刚完全重做了这个问题,为领域提供了更多信息和解释。希望你能重新评估?谢谢!

标签: java neural-network xor


【解决方案1】:

这是错误的

SigmoidDerivative(Neuron.input)*((Neuron.Weights * 他们连接的神经元的deltaError之和)) 首先是 sigmoid 激活 (g) 第二个是 sigmoid 激活的导数

private double g(double z) {
    return 1 / (1 + Math.pow(2.71828, -z));
}

private double gD(double gZ) {
    return gZ * (1 - gZ);
}

不相关的注释:你的 (-1*x) 符号真的很奇怪,只是使用 -x

从您如何表述 ANN 的步骤来看,您的实施似乎很糟糕。尝试专注于实现 Forward/BackPropogation,然后是 UpdateWeights 方法。 创建矩阵类

这是我的 Java 实现,它非常简单且有些粗糙。我使用 Matrix 类使其背后的数学在代码中显得非常简单。

如果您可以用 C++ 编写代码,则可以重载操作符,这将使编写更容易理解的代码成为可能。

https://github.com/josephjaspers/ArtificalNetwork/blob/master/src/artificalnetwork/ArtificalNetwork.java


这里是算法(C++)

所有这些代码都可以在我的 github 上找到(神经网络简单而实用) 每层都包含偏置节点,这就是为什么会有偏移量

void NeuralNet::forwardPropagation(std::vector<double> data) {
    setBiasPropogation(); //sets all the bias nodes activation to 1
    a(0).set(1, Matrix(data)); //1 to offset for bias unit (A = X)

    for (int i = 1; i < layers; ++i) {
        //  (set(1 -- offsets the bias unit

        z(i).set(1, w(i - 1) * a(i - 1)); 
        a(i) = g(z(i)); // g(z ) if the sigmoid function
    }
}
void NeuralNet::setBiasPropogation() {
    for (int i = 0; i < activation.size(); ++i) {
        a(i).set(0, 0, 1);
    }
}

outLayer D = A - Y (y 是输出数据) 隐藏层 d^l = (w^l(T) * d^l+1) *: gD(a^l)

d = 导数向量

W = 权重矩阵(长度 = 连接,宽度 = 特征)

a = 激活矩阵

gD = 导函数

^l = IS NOT POWER OF(这只是意味着在 l 层)

  • = 点积

*: = multiply(将每个元素“通过”相乘)

cpy(n) 返回偏移 n 的矩阵副本(忽略 n 行)

void NeuralNet::backwardPropagation(std::vector<double> output) {
    d(layers - 1) = a(layers - 1) - Matrix(output);
    for (int i = layers - 2; i > -1; --i) {
    d(i) = (w(i).T() * d(i + 1).cpy(1)).x(gD(a(i))); 
    }       
}

如果没有图片,解释此代码可能会令人困惑,因此我发送此链接,我认为这是一个很好的来源,它还包含对 BackPropagation 的解释,这可能比我自己的解释更好。 http://galaxy.agh.edu.pl/~vlsi/AI/backp_t_en/backprop.html

void NeuralNet::updateWeights() {
    // the operator () (int l, int w) returns a double reference at that position in the matrix
    // thet operator [] (int n) returns the nth double (reference) in the matrix (useful for vectors) 
    for (int l = 0; l < layers - 1; ++l) {
        for (int i = 1; i < d(l + 1).length(); ++i) {
            for (int j = 0; j < a(l).length(); ++j) {
                w(l)(i - 1, j) -= (d(l + 1)[i] * a(l)[j]) * learningRate + m(l)(i - 1, j);
                m(l)(i - 1, j) = (d(l + 1)[i] * a(l)[j]) * learningRate * momentumRate;
            }
        }
    }
}

【讨论】:

  • 感谢您的回答!但是,在实施 g 和 gD 之后,我仍然遇到类似的问题。现在它的收敛速度快了很多,但它仍然要么只变为 1,要么只变为 0,然后很快变为 NaN(对于 0 和 1)。
  • 您好,抱歉回复晚了。关于您在局部最小值处收敛的问题。这实际上发生在所有神经网络中。例如,如果您将所有权重设置为与随机初始化相反的相同常数,则在遍历数据集时,每个权重都会在同一方向上进行非常非常轻微的调整(“移动”)。当您陷入局部最小值时,就会发生这种情况。许多神经网络甚至需要多次重新运行,直到找到足够的最小值(无论是局部的还是最优的)。
  • 如果没有持续优化,您可以向隐藏层添加更多节点。您可以测试这如何通过 Xor 网络 2-2-1 与 2-10-1 相比增加优化机会(节点的增加降低了它们的权重开始变得彼此接近的机会)事实上你得到一个 nan错误意味着您的 delta 很可能没有被正确计算,或者您可能忘记或错误地添加了一个负号(因为一旦错误接近 0,权重应该几乎不会移动)。您可以尝试使用舍入方法来处理。
  • 我尝试在系统中增加很多复杂性,我将我的权重随机化在 -2.5 和 2.5 之间;仍然得到问题。我想那一定是增量错误。这是我使用的两个方程:-(ActualOutput - Expected)*Sigmoid'(Neuron.input) 用于输出神经元,Sigmoid'(Neuron.input)*(sum of (Weight * theNeuronItFeedsTo's delta error)) 用于所有其他神经元。我的 sigmoid 导数是-(e^-x)/(1+e^-x)^2。这些错了吗?非常感谢,这意味着很多!
  • 您的神经网络使用哪些资源?我推荐 Coursera 的 Andrew Ng 机器学习课程(第 4/5 周,他解释了神经网络的每个算法)。我在回复中添加了算法。你的 sigmoid 导数是错误的,它只是 (a / (1 - a)) a 已经被设置为 (1 / 1 + e ^-z)
猜你喜欢
  • 2018-11-04
  • 1970-01-01
  • 2020-03-28
  • 2018-01-31
  • 2016-05-13
  • 1970-01-01
  • 2017-07-13
  • 2012-03-03
相关资源
最近更新 更多