反向传播在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

使用LSTM在Python中预测未来值

这段代码可以预测指定股票的当前日期之前的值,但不能预测…

如何在gensim的word2vec模型中查找双词组的相似性

我有一个word2vec模型,假设我使用的是googl…

dask_xgboost.predict 可以工作但无法显示 – 数据必须是一维的

我试图使用 XGBoost 创建模型。 看起来我成功地…

ML Tuning – Cross Validation in Spark

我在https://spark.apache.org/…

如何在React JS中使用fetch从REST API获取预测

我正在开发一个应用程序,其中Flask REST AP…

如何分析ML.NET中多类分类预测得分数组?

我在ML.NET中创建了一个多类分类项目。该项目可以对…

发表回复

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