反向传播在XOR问题上不起作用

在过去的两周里,我一直在学习反向传播,理解了背后的数学原理,并认为自己已经足够了解这个主题,可以进行自己的实现(不使用任何线性代数包等)。显然,我错了。下面是我能想到的最简单的网络示例:2个隐藏单元和1个输出单元。我试图学习XOR函数。然而,这完全不起作用。预测值总是大约0.5。我不确定我哪里出错了。或许有人能帮忙吗?

float sigmoid(float pX) {    return 1.0f/(1.0f+exp(-1.0f*pX));}int main(int argc, char const *argv[]) {// DEFINE XOR problemfloat examples[4][2] = { {0,0} , {0,1}, {1,0}, {1,1}};float labels[4] = {0, 1, 1, 0};/* I want to use a network with two hidden neurons and 1 output neuron */// Weights from input to hidden neuronsfloat WInput[2][2];float WInputBias[2];// Weights from hidden to output neuronfloat WOutput[2];float WOutputBias;// output of hidden layer to output neuronfloat hidden[2];// error for hidden layerfloat error[2];//output of network float yPred;// randomly init weightsstd::random_device rd;std::mt19937 gen(rd());std::normal_distribution<float> d(0, 0.1);WInput[0][0] = d(gen); WInput[0][1] = d(gen); WInput[1][0] = d(gen); WInput[1][1] = d(gen); WInputBias[0] = d(gen); WInputBias[1] = d(gen);WOutput[0] = d(gen); WOutput[1] = d(gen); WOutputBias = d(gen);// do the learningfor(unsigned int i = 0; i < 1000; ++i) {    for (unsigned int k = 0; k < 4; ++k) {        float * input = &examples[k][0];        float label = labels[k];        // Compute forward pass        hidden[0] = sigmoid(WInput[0][0]*input[0] + WInput[1][0]*input[1] + WInputBias[0]);        hidden[1] = sigmoid(WInput[0][1]*input[0] + WInput[1][1]*input[1] + WInputBias[1]);        yPred = sigmoid(WOutput[0]*hidden[0] + WOutput[1]*hidden[1] + WOutputBias);        std :: cout << "Target / Prediction: " << label << " / " << yPred << std :: endl;        // Backward pass with alpha = 0.1        float outputError = -(label - yPred)*yPred*(1-yPred);        WOutput[0] = WOutput[0] - 0.1f*outputError*hidden[0]; //hidden equals input from this layer        WOutput[1] = WOutput[1] - 0.1f*outputError*hidden[1];        WOutputBias = WOutputBias - 0.1f*outputError;        error[0] = (WOutput[0]*outputError)*hidden[0]*(1-hidden[0]);        error[1] = (WOutput[1]*outputError)*hidden[1]*(1-hidden[1]);        WInput[0][0] = WInput[0][0] - 0.1f*error[0]*input[0];        WInput[1][0] = WInput[1][0] - 0.1f*error[0]*input[1];        WInput[0][1] = WInput[0][1] - 0.1f*error[1]*input[0];        WInput[1][1] = WInput[1][1] - 0.1f*error[1]*input[1];        WInputBias[0] = WInputBias[0] - 0.1f*error[0];        WInputBias[1] = WInputBias[1] - 0.1f*error[1];    }    std :: cout << std :: endl;    // getch();} }

回答:

我又重新审视了代码,并调整了一些参数,结果发现所有的代码实际上都是正确的。

问题在于,仅有2个隐藏节点,这个问题学习起来相当困难,你使用的轮数(1000次)加上学习率(0.1)意味着它还没有收敛。

尝试让它训练大约4000-6000次(或者,最好是直到错误的绝对值下降到某个阈值以下),并尝试将权重更新乘以1.0而不是0.1。这样你应该能得到更好的结果。

随机初始化权重,使其在[-0.1, 0.1]范围内而不是[0.0, 0.1]范围内,这也可能有帮助。不过,这不会有太大的影响。

Related Posts

Keras Dense层输入未被展平

这是我的测试代码: from keras import…

无法将分类变量输入随机森林

我有10个分类变量和3个数值变量。我在分割后直接将它们…

如何在Keras中对每个输出应用Sigmoid函数?

这是我代码的一部分。 model = Sequenti…

如何选择类概率的最佳阈值?

我的神经网络输出是一个用于多标签分类的预测类概率表: …

在Keras中使用深度学习得到不同的结果

我按照一个教程使用Keras中的深度神经网络进行文本分…

‘MatMul’操作的输入’b’类型为float32,与参数’a’的类型float64不匹配

我写了一个简单的TensorFlow代码,但不断遇到T…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注