反向传播不工作为异或
Backpropagation not working for XOR
过去两周我一直在学习反向传播,做了它背后的数学计算,并认为我对这个主题的理解足够好,可以用于我自己的实现(没有任何线性代数包等)。显然,我错了。下面你可以找到我能想到的最简单的网络示例:2个隐藏单元和1个输出单元。我试着学习异或函数。然而,这根本不起作用。预测总是在0.5
附近。我不知道我在哪里搞砸了。也许有人能帮忙?
float sigmoid(float pX) {
return 1.0f/(1.0f+exp(-1.0f*pX));
}
int main(int argc, char const *argv[]) {
// DEFINE XOR problem
float 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 neurons
float WInput[2][2];
float WInputBias[2];
// Weights from hidden to output neuron
float WOutput[2];
float WOutputBias;
// output of hidden layer to output neuron
float hidden[2];
// error for hidden layer
float error[2];
//output of network
float yPred;
// randomly init weights
std::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 learning
for(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个隐藏节点,这个问题很难学习,你使用的epoch数(1000)结合你使用的学习率(0.1)仅仅意味着它还没有收敛。
试着让它训练大约4000-6000次(或者,最好是,直到你的误差绝对值降到某个阈值以下),并尝试将权重更新乘以1.0而不是0.1。那么你应该得到更好的结果。
随机初始化权重为[-0.1,0.1]而不是[0.0,0.1]也可能有所帮助。但这不会有太大的区别。
相关文章:
- QSqlquery prepare()和bindvalue()不工作
- 导入库可以跨dll版本工作吗
- 以螺旋方式打印矩阵的程序.(工作不好)
- 对象指针在c++中是如何工作的
- 为什么在Windows上的VS 2019和Clang 9中"size_t"在没有标题的情况下工作
- VSOMEIP-2个设备之间的通信(TCP/UDP)不工作
- 为字符串中每 N 个字符插入空格的函数没有按照我认为的方式工作?
- C++为线程工作动态地分割例程
- 为什么我的 std::ref 无法按预期工作?
- 布尔比较运算符是如何在C++中工作的
- SampleConsensusPrerejective(ext.RANSAC)是如何真正工作的
- 不确定要在我的main中放入什么才能使我的代码正常工作
- 为什么std::condition_variable notify_all的工作速度比notify_one快(对于随机请
- <<操作员在下面的行中工作
- 有人能解释一下为什么下界是这样工作的吗C++的
- ExtractIconEx:可以工作,但偶尔会崩溃
- C++中的memset函数工作不正常
- 当我在第一个循环中使用"auto"时,它工作正常,但是使用"int"它会给出错误,为什么?
- 链表c++插入,所有情况都已检查,但没有任何工作
- 反向传播不工作为异或