用 C++ 实现的感知器未按预期进行训练。 (与逻辑门示例)
Perceptron implemented in C++ does not train as expected. (AND Logic Gate example)
下面是我的感知器实现。
FOR循环的最后一次迭代给出结果:
Input: 0 Input: 0
Output: 0.761594
Error: -0.761594
经过如此多的训练样本,这显然是错误的。
最后几行代码给出了
Input: 1 Input: 1
Output: 0.379652
Error: 0.620348
哪里又错了,而且还差得远...
(所有关于构造函数中的随机权重值。)
但是,如果我只对示例值 (1,1,1) 进行迭代,则每次迭代的结果都会更接近 1,这就是它应该工作的方式。
所以我想知道这可能是什么原因造成的?因为感知器应该能够学习与门,因为输出是线性可分的。
#include <iostream>
#include <time.h>
#include <stdlib.h>
#include <Windows.h>
#include <math.h>
#define println(x) std::cout<<x<<std::endl;
#define print(x) std::cout<<x;
#define END system("PAUSE"); return 0
#define delay(x) Sleep(x*1000);
typedef unsigned int uint;
class perceptron
{
public:
perceptron() :learningRate(0.15),biasValue(1),outputVal(0)
{
srand((uint)time(0));
weights = new double[2];
weights[0] = rand() / double(RAND_MAX);
weights[1] = rand() / double(RAND_MAX);
}
~perceptron()
{
delete[] weights;
}
void train(double x0, double x1, double target)
{
backProp(x0, x1, target);
}
private:
double biasValue;
double outputVal;
double* weights;
double learningRate;
private:
double activationFunction(double sum)
{
return tanh(sum);
}
void backProp(double x0, double x1, double target)
{
println("");
guess(x0, x1); //Setting outputVal to activationFunction value
//Calculating Error;
auto error = target - outputVal;
//Recalculating weights;
weights[0] = weights[0] + error * x0 * learningRate;
weights[1] = weights[1] + error * x1 * learningRate;
//Printing values;
std::cout << "Input: " << x0 << " Input: " << x1 << std::endl;
std::cout << " Output: " << outputVal << std::endl;
std::cout << "Error: " << error << std::endl;
}
double guess(double x0, double x1)
{
//Calculating outputValue
outputVal = activationFunction(x0 * weights[0] + x1 * weights[1]+biasValue);
return outputVal;
}
};
int main()
{
perceptron* p = new perceptron();
for (auto i = 0; i < 1800; i++)
{
p->train(1, 1, 1);
p->train(0, 1, 0);
p->train(1, 0, 0);
p->train(0, 0, 0);
}
println("-------------------------------------------------------");
delay(2);
p->train(1, 1, 1);
END;
}
我看到了一些问题:
- 感知激活不应该是
tanh()
。如果你使用它,你将必须确保适当地计算梯度。但是你可以用 替换激活
double activationFunction(double sum)
{
return sum > 0;
}
如果总和 > 0,这将 return 1,否则 returns 0。
- 更新权重时,
biasValue
也应该更新,因为感知器需要从您的训练数据中学习它的值。您可以使用 更新它
biasValue += error * learningRate;
这些更改将允许感知器学习与门。
下面是我的感知器实现。
FOR循环的最后一次迭代给出结果:
Input: 0 Input: 0
Output: 0.761594
Error: -0.761594
经过如此多的训练样本,这显然是错误的。
最后几行代码给出了
Input: 1 Input: 1
Output: 0.379652
Error: 0.620348
哪里又错了,而且还差得远...
(所有关于构造函数中的随机权重值。)
但是,如果我只对示例值 (1,1,1) 进行迭代,则每次迭代的结果都会更接近 1,这就是它应该工作的方式。
所以我想知道这可能是什么原因造成的?因为感知器应该能够学习与门,因为输出是线性可分的。
#include <iostream>
#include <time.h>
#include <stdlib.h>
#include <Windows.h>
#include <math.h>
#define println(x) std::cout<<x<<std::endl;
#define print(x) std::cout<<x;
#define END system("PAUSE"); return 0
#define delay(x) Sleep(x*1000);
typedef unsigned int uint;
class perceptron
{
public:
perceptron() :learningRate(0.15),biasValue(1),outputVal(0)
{
srand((uint)time(0));
weights = new double[2];
weights[0] = rand() / double(RAND_MAX);
weights[1] = rand() / double(RAND_MAX);
}
~perceptron()
{
delete[] weights;
}
void train(double x0, double x1, double target)
{
backProp(x0, x1, target);
}
private:
double biasValue;
double outputVal;
double* weights;
double learningRate;
private:
double activationFunction(double sum)
{
return tanh(sum);
}
void backProp(double x0, double x1, double target)
{
println("");
guess(x0, x1); //Setting outputVal to activationFunction value
//Calculating Error;
auto error = target - outputVal;
//Recalculating weights;
weights[0] = weights[0] + error * x0 * learningRate;
weights[1] = weights[1] + error * x1 * learningRate;
//Printing values;
std::cout << "Input: " << x0 << " Input: " << x1 << std::endl;
std::cout << " Output: " << outputVal << std::endl;
std::cout << "Error: " << error << std::endl;
}
double guess(double x0, double x1)
{
//Calculating outputValue
outputVal = activationFunction(x0 * weights[0] + x1 * weights[1]+biasValue);
return outputVal;
}
};
int main()
{
perceptron* p = new perceptron();
for (auto i = 0; i < 1800; i++)
{
p->train(1, 1, 1);
p->train(0, 1, 0);
p->train(1, 0, 0);
p->train(0, 0, 0);
}
println("-------------------------------------------------------");
delay(2);
p->train(1, 1, 1);
END;
}
我看到了一些问题:
- 感知激活不应该是
tanh()
。如果你使用它,你将必须确保适当地计算梯度。但是你可以用 替换激活
double activationFunction(double sum)
{
return sum > 0;
}
如果总和 > 0,这将 return 1,否则 returns 0。
- 更新权重时,
biasValue
也应该更新,因为感知器需要从您的训练数据中学习它的值。您可以使用 更新它
biasValue += error * learningRate;
这些更改将允许感知器学习与门。