我有一个学校项目来编程多层感知器,将数据分为三类。我已经实现了从http://home.agh.edu.pl/~vlsi/AI/backp_t_en/backprop.html反向传播算法。我检查了我的算法(通过手动计算反向传播的每一步),如果它确实符合这个解释的步骤并且符合。多层感知器 - 反向传播
对于分类,我使用一个热门的代码,我有两个值和三个输出神经元(每个单独的类)的向量组成的输入。在每个时代之后,我都会对输入数据进行混洗。对于分类,我使用sigmoid函数。我也尝试过实施softmax,但我还没有找到如何看起来像softmax。在权重调整中需要派生softmax吗?为了检查网络是否成功地对输入进行分类,我比较输出神经元的位置与输出神经元的最大输出的位置是否对应于当前输入的一个热码向量等于1的位置。
但是我的实现并不训练这个神经网络。我正在研究和调试几天,并在互联网上寻找我做错了什么,但我没有找到答案。我真的不知道我在哪里犯错。当我有10个输入时,我的神经网络将成功训练,但是当我有100,200,400和800个输入时,当它有一半好的分类输入时,它开始循环。正如我所说我的反向传播算法是好的。在Visual Studio 2010中整个C++项目,输入文件是在这里:http://www.st.fmph.uniba.sk/~vajda10/mlp.zip
结构:
struct input {
vector<double> x;
vector<double> cls;
};
struct neuron {
double output;
double error;
neuron(double o, double e): output(o), error(e) { };
};
全局变量:
double alpha = 0.5;
vector<vector<input>> data;
vector<vector<neuron>> hiddenNeurons;
vector<neuron> outputNeurons;
vector<vector<vector<double>>> weights;
这里是我的BP算法代码:
for (int b = 0; b < data[0].size(); b++) {
// calculate output of hidden neurons
for (int i = 0; i < hiddenNeurons.size(); i++) {
for (int j = 0; j < hiddenNeurons[i].size(); j++) {
double activation = neuronActivation(0, b, i, j);
hiddenNeurons[i][j].output = sigmoid(activation);
}
}
double partError = 0;
// calculate output and errors on output neurons
for (int k = 0; k < outputNeurons.size(); k++) {
double activation = neuronActivation(0, b, hiddenNeurons.size(), k);
outputNeurons[k].output = sigmoid(activation);
outputNeurons[k].error = data[0][b].cls[k] - outputNeurons[k].output;
partError += pow(outputNeurons[k].error, 2);
}
error += sqrt(partError)/outputNeurons.size();
// if classification is wrong
if (data[0][b].cls[maxOutputIndex(outputNeurons)] != 1) {
wrongClass++;
// error backpropagation
for (int i = hiddenNeurons.size()-1; i >= 0; i--) {
for (int j = 0; j < hiddenNeurons[i].size(); j++) {
hiddenNeurons[i][j].error = 0.0;
if (i < hiddenNeurons.size()-1) {
for (int k = 0; k < hiddenNeurons[i+1].size(); k++) {
hiddenNeurons[i][j].error += hiddenNeurons[i+1][k].error * weights[i+1][j][k];
}
}
else {
for (int k = 0; k < outputNeurons.size(); k++) {
hiddenNeurons[i][j].error += outputNeurons[k].error * weights[i+1][j][k];
}
}
}
}
// adjust weights
for (int i = 0; i < weights.size(); i++) {
int n;
if (i < weights.size()-1) {
n = hiddenNeurons[i].size();
}
else {
n = outputNeurons.size();
}
for (int k = 0; k < n; k++) {
for (int j = 0; j < weights[i].size(); j++) {
double y;
if (i == 0) {
y = data[0][b].x[j];
}
else {
y = hiddenNeurons[i-1][j].output;
}
if (i < weights.size()-1) {
weights[i][j][k] += alpha * hiddenNeurons[i][k].error * derivedSigmoid(hiddenNeurons[i][k].output) * y;
}
else {
weights[i][j][k] += alpha * outputNeurons[k].error * derivedSigmoid(outputNeurons[k].output) * y;
}
}
}
}
}
}
请问谁能告诉我我做错了什么或给我一个建议我必须去寻找一个错误?我希望我已经告诉了所有重要的事情。请原谅我英语不好。
如果使用交叉熵作为误差函数,softmax激活函数的导数将与具有身份激活函数的导数和误差平方和的导数相同,即误差函数:output-target。顺便说一句:你的学习速度是很高的。尝试像0.005或更低。 – alfa 2012-04-05 16:54:40
非常感谢,这对我有帮助。 – 2012-04-08 15:57:04