2012-04-04 55 views
1

我有一个学校项目来编程多层感知器,将数据分为三类。我已经实现了从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; 
       } 
      } 
      } 
     } 
     } 
    } 

请问谁能告诉我我做错了什么或给我一个建议我必须去寻找一个错误?我希望我已经告诉了所有重要的事情。请原谅我英语不好。

+0

如果使用交叉熵作为误差函数,softmax激活函数的导数将与具有身份激活函数的导数和误差平方和的导数相同,即误差函数:output-target。顺便说一句:你的学习速度是很高的。尝试像0.005或更低。 – alfa 2012-04-05 16:54:40

+0

非常感谢,这对我有帮助。 – 2012-04-08 15:57:04

回答

2

高斯分类器(如BackpropNN)只会仿射连续样本集。

既然你的网在小套试题上学习,我假设小套没有不连续性。

这里用于例如。是训练样本集(输入向量--->输出向量)中的不连续点:

[0,1,0,1,1,0,1,0] ---> [0,1,0] 
[0,1,0,1,1,0,1,0] ---> [1,1,0] 

算法不能分类(样条线)这个。给定输入向量的输出向量必须是唯一的(连续的)。

如果您随机生成样本,这可以解释为什么小集合似乎总是工作 - 产生不连续性的可能性很小。较大的集合将保证这个问题。

所以,只要扫描并删除任何问题范例,如果这确实是问题。请记住,传递函数实际上是一个规范化器,所以看起来不同的实际输入向量可能会标准化为标准化。

如果您仍然陷在局部最大值或最小值上,请尝试更改epsilon(学习率)。您将其硬编码为.5尝试其他值。

作为最后的努力,我还建议用阶梯函数代替sigmoid传递函数。sigmoid只是这种数字功能的生物学模拟。通过直接使用数字传输来删除此转换(步进功能)。

Analog vs Digital transfer functions

S形在backprop使用的原因是韩丁的原创作品是从认知科学和神经元的传递函数为S型 - 最接近自然模拟到数字的功能。

+0

谢谢,我解决了我的问题改变学习率为0.005和更低。 – 2012-04-08 15:59:04

+0

只需回顾一下 - 请注意在OP的代码中,'epsilon'(学习率)被称为'alpha'。这是算法在每次通过期间校正网络的速率(导数)(向后误差传播)。直观地说,较低的费率对于更复杂的训练集合更好,但需要更高的传球次数。用布尔数字函数替换浮点模拟可以减少通过次数并显着缩短学习时间。 – 2016-09-19 23:07:27

+0

这是一个很好的观点。 – 2016-11-23 23:12:36