使用反向传播算法实现感知器

5
我正在尝试使用反向传播实现一个两层感知器来解决奇偶问题。该网络有4个二进制输入,第一层有4个隐藏单元,第二层有1个输出。我参考这个链接,但是收敛方面出现了问题。
首先,我想指出我在使用sigmoid函数进行激活,所以导数是(据我理解)sigmoid(v) * (1 - sigmoid(v))。因此,在计算delta值时会使用该值。
所以,基本上我设置了网络并运行了几个周期(遍历每种可能的模式——在这种情况下,是16种输入模式)。第一个周期后,权重会稍微改变。第二个周期后,权重不再改变,无论我再运行多少个周期。目前,我使用学习率为0.1和偏置为+1。
以下是训练网络的伪代码过程(根据我查阅的资料,我认为它是正确的):
前馈步骤:
v = SUM[weight connecting input to hidden * input value] + bias  
y = Sigmoid(v)  
set hidden.values to y  
v = SUM[weight connecting hidden to output * hidden value] + bias  
y = Sigmoid(v)  
set output value to y

输出层的反向传播:

error = desired - output.value  
outputDelta = error * output.value * (1 - output.value)

隐藏层的反向传播:

for each hidden neuron h:  
error = outputDelta * weight connecting h to output  
hiddenDelta[i] = error * h.value * (1 - h.value)

更新权重:

for each hidden neuron h connected to the output layer  
h.weight connecting h to output = learningRate * outputDelta * h.value

for each input neuron x connected to the hidden layer  
x.weight connecting x to h[i] = learningRate * hiddenDelta[i] * x.value

当然,这个过程在时期中循环,并且重量的变化是持久的。我的问题是,在第二个时期之后,是否有任何理由使权重保持不变?如果需要,我可以发布我的代码,但此时我希望能发现一些明显的问题。谢谢!编辑:以下是我的代码链接,如sarnold所建议的:
MLP.java:http://codetidy.com/1903
Neuron.java:http://codetidy.com/1904
Pattern.java:http://codetidy.com/1905
input.txt:http://codetidy.com/1906

1
几年前我在神经网络课程中遇到了一个非常相似的错误:值在许多十次迭代后不会改变,然后所有输出都转换为NaN,没有明显的原因。错误最终只是某个地方的一行错误代码,让我花了好几个小时才找到。你应该把你的一部分代码发布出来,也许其他人能够发现我所假设的你程序中的单行错误。 :) - sarnold
1个回答

4

我认为我找到了问题所在;有趣的是,你高层次描述中提到的内容就是问题所在,但我只是在代码中发现了一些奇怪的地方。首先,看看你的描述:

for each hidden neuron h connected to the output layer
h.weight connecting h to output = learningRate * outputDelta * h.value

for each input neuron x connected to the hidden layer
x.weight connecting x to h[i] = learningRate * hiddenDelta[i] * x.value

我认为应该相对于先前的权重更新h.weight。您的更新机制仅基于学习率、输出差和节点的进行设置。同样,x.weight也是基于学习率、隐藏差和节点的进行设置:

    /*** Weight updates ***/

    // update weights connecting hidden neurons to output layer
    for (i = 0; i < output.size(); i++) {
        for (Neuron h : output.get(i).left) {
            h.weights[i] = learningRate * outputDelta[i] * h.value;
        }
    }

    // update weights connecting input neurons to hidden layer
    for (i = 0; i < hidden.size(); i++) {
        for (Neuron x : hidden.get(i).left) {
            x.weights[i] = learningRate * hiddenDelta[i] * x.value;
        }
    }

我不知道什么是正确的解决方案;但我有两个建议:

  1. Replace these lines:

            h.weights[i] = learningRate * outputDelta[i] * h.value;
            x.weights[i] = learningRate * hiddenDelta[i] * x.value;
    

    with these lines:

            h.weights[i] += learningRate * outputDelta[i] * h.value;
            x.weights[i] += learningRate * hiddenDelta[i] * x.value;
    

    (+= instead of =.)

  2. Replace these lines:

            h.weights[i] = learningRate * outputDelta[i] * h.value;
            x.weights[i] = learningRate * hiddenDelta[i] * x.value;
    

    with these lines:

            h.weights[i] *= learningRate * outputDelta[i];
            x.weights[i] *= learningRate * hiddenDelta[i];
    

    (Ignore the value and simply scale the existing weight. The learning rate should be 1.05 instead of .05 for this change.)


1
是的,应该是+=。我简直不敢相信我会错过这样的事情。感谢您花时间帮助我,非常感谢! - Aaron

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接