【问题标题】:Multilayer perceptron - backpropagation多层感知器 - 反向传播
【发布时间】:2012-04-18 14:46:35
【问题描述】:

我有一个学校项目来编写多层感知器,将数据分为三类。我已经从http://home.agh.edu.pl/~vlsi/AI/backp_t_en/backprop.html 实现了反向传播算法。我已经检查了我的算法(通过手动计算反向传播的每个步骤),如果它真的符合这个解释的步骤并且它符合。

对于分类,我使用的是 one-hot 代码,我的输入由具有 2 个值的向量和三个输出神经元(每个用于单个类)组成。在每个时代之后,我都会对输入数据进行洗牌。对于分类,我使用的是 sigmoid 函数。我也尝试实现 softmax,但我还没有发现派生 softmax 的外观如何。权重调整是否需要导数 softmax?为了检查网络是否成功分类输入,我正在比较具有输出神经元最大输出的输出神经元的位置是否对应于当前输入 one-hot 代码向量中等于 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;

这是我的反向传播算法代码:

    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 激活函数的导数将与使用恒等激活函数和误差平方和作为误差函数的导数相同:输出目标。顺便说一句:你的学习率太高了。试试 0.005 或更低的值。
  • 非常感谢,这对我有帮助。

标签: classification backpropagation neural-network


【解决方案1】:

高斯分类器(如 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 只是这个数字函数的生物模拟。通过直接使用数字传输(阶跃函数)删除此转换。

在反向传播中使用 sigmoid 的原因是 Hinton 的原始工作来自认知科学,神经元的传递函数是 sigmoid - 最接近数字函数的自然模拟。

【讨论】:

  • 谢谢,我解决了将学习率更改为 0.005 及更低的问题。
  • 只是回顾一下 - 请注意在 OP 的代码中,“epsilon”(学习率)被称为“alpha”。这是算法在每次通过(反向错误传播)期间纠正网络的速率(导数)。直观地说,较低的速率对于更复杂的训练集更好,但需要更多的通过次数。然而,用布尔数字函数代替浮点模拟可以减少通过次数并显着减少学习时间。
猜你喜欢
  • 2017-07-12
  • 2013-03-04
  • 2015-07-11
  • 1970-01-01
  • 2019-09-28
  • 1970-01-01
  • 2015-08-14
  • 2017-10-18
  • 1970-01-01
相关资源
最近更新 更多