Нейронная сеть не работает должным образом - PullRequest
0 голосов
/ 06 июля 2019

В настоящее время я пытаюсь изучить машинное обучение и, в частности, нейронные сети.В c ++ я построил очень простую двухслойную (скрытую и выходную) нейронную сеть, в которой используется матричная библиотека, которую я также встроил в c ++.Тем не менее, когда я попытался натренировать его с очень тривиальной проблемой - проблемой xor - результат был не таким, каким я хотел его видеть.Вот код, который я пытаюсь реализовать:

int main(){

  int trainingData[4][3] =  {
                            {0,0,0},
                            {1,1,0},
                            {1,0,1},
                            {0,1,1}
                            };



  NeuralNetwork nn = NeuralNetwork(2,2,1);

  for (int i = 0; i < 10000; i++){
    std::vector<double> inputs(2);
    std::vector<double> targets(1);
    srand(time(NULL));
    int index = rand()%4;
    for(int j = 0; j < 3; j++){
      if (j < 2){
        inputs[j] = trainingData[index][j];
      }else{
        targets[0] = trainingData[index][j];
      }
    }
    // cout<<inputs[0]<<" "<<inputs[1]<<"  ->  "<<targets[0]<<endl;
    nn.train(inputs,targets);
  }

  std::vector<double> inputs = {0,0};


  nn.predict(inputs).print();
  //
  // for (int i = 0; i < prediction.size(); i++)
  //   cout<<prediction[i]<<" ";



  return 0;
}

Вот мой класс нейронной сети:

class NeuralNetwork{
private:
  int inputNodes,hiddenNodes,outputNodes;
  float learningRate;
  Matrix weightsIH, weightsHO, biasH, biasO;


public:
    //--------------------------------------------------------------------------
    //                              Constructor
    //--------------------------------------------------------------------------
    NeuralNetwork(int inNodes,int hidNodes,int outNodes,float lr = .1){
    inputNodes = inNodes;
    hiddenNodes = hidNodes;
    outputNodes = outNodes;
    learningRate = lr;

    //create matrices for the weights
    weightsIH.setSize(hiddenNodes,inputNodes);
    weightsHO.setSize(outputNodes,hiddenNodes);

    //randomize weights matrices
    weightsHO.randomize();
    weightsIH.randomize();

    //create matrices for the biases
    biasH.setSize(hiddenNodes,1);
    biasO.setSize(outputNodes,1);

    //randomize biases
    biasH.randomize();
    biasO.randomize();

  }
  //----------------------------------------------------------------------------
  //                                Prediction
  //----------------------------------------------------------------------------
  Matrix predict(std::vector<double> inputVector){
    //generate hidden outputs
    Matrix inputs = fromVector(inputVector);

    Matrix hiddenOutput = multiply(weightsIH, inputs);

    //apply bias
    hiddenOutput.add(biasH);

    //use activation function
    hiddenOutput.sigmoid();

    //output's output
    Matrix output = multiply(weightsHO, hiddenOutput);

    //apply bias
    output.add(biasO);

    //use activation function
    output.sigmoid();

    return output;
  }
  //----------------------------------------------------------------------------
  //                                 Training
  //----------------------------------------------------------------------------

  void train(std::vector<double> inputVector, std::vector<double> targetVector){

    //--------------------------------------------------------------------------
    //                        Feed Forward
    //--------------------------------------------------------------------------

    //generating hidden outputs
    Matrix inputs = fromVector(inputVector);
    //cout<<"1"<<endl;
    Matrix hiddenOutput = multiply(weightsIH, inputs);
    //add bias
    hiddenOutput.add(biasH);
    //activation function
    hiddenOutput.sigmoid();
    //generating second output
    Matrix outputs = multiply(weightsHO,hiddenOutput);
    //add bias
    outputs.add(biasO);
    //activation function
    outputs.sigmoid();

    //--------------------------------------------------------------------------
    //                        Back Propogation
    //--------------------------------------------------------------------------

    //convert targets vector to matrix
    Matrix targets = fromVector(targetVector);

    //calculate error
    Matrix outputErrors = subtract(targets,outputs);

    //calculate gradient
    Matrix gradients = dsigmoid(outputs);
    gradients = multiply(gradients,outputErrors);
    gradients.scale(learningRate);

    //calculate deltas
    Matrix hiddenOutputT = transpose(hiddenOutput);
    Matrix weightHoDeltas = multiply(gradients,hiddenOutputT);

    //adjust weights by deltas
    weightsHO.add(weightHoDeltas);
    biasO.add(gradients);

    //calculate hidden layer errors
    Matrix weightsHoTranspose = transpose(weightsHO);
    Matrix hiddenErrors = multiply(weightsHoTranspose,outputErrors);

    //calculate hidden gradient
    Matrix hiddenGradient = dsigmoid(hiddenOutput);
    hiddenGradient = multiply(hiddenGradient,hiddenErrors);
    hiddenGradient.scale(learningRate);

    //calculate inputs -> hidden deltas
    Matrix inputsT = transpose(inputs);
    Matrix weightsIhDeltas = multiply(hiddenGradient,inputsT);

    weightsIH.add(weightsIhDeltas);
    biasH.add(hiddenGradient);
  }

};

И вот мой класс матрицы в моей матричной библиотеке (есть больше функцийкоторые используются в классе нейронной сети, которые не входят в мой класс матрицы, однако полная библиотека имеет размер> 300 строк, поэтому я могу опубликовать это, но это

class Matrix{
private:
  int rows,cols;
  bool active;

  double sigmoidFunc(double x){
    return (double)(1/(1+exp(-x)));
  }
public:
  std::vector<std::vector<double>> data;

  Matrix(){
    rows = 0;
    cols = 0;
    active = false;
  }

  Matrix(int rowsNum,int colsNum){
    active = true;
    srand(time(NULL));
    rows = rowsNum; cols = colsNum;

    data.resize(rows);

    for (int i = 0; i < rows; i++){
      data[i].resize(cols);
    }

    for (int i = 0; i < rows; i++){
      for (int j = 0; j < cols; j++){
        data[i][j] = 0;
      }
    }
  }

  void roundFunc(int decimalLength){
    for (int i = 0; i < rows; i++){
      for (int j = 0; j < cols; j++){
        data[i][j] = round(data[i][j] * pow(10,decimalLength))/(pow(10,decimalLength));
      }
    }
  }

  void setSize(int rowsNum, int colsNum){
    if (rows == 0 || cols == 0){
      srand(time(NULL));
      rows = rowsNum; cols = colsNum;

      data.resize(rows);

      for (int i = 0; i < rows; i++){
        data[i].resize(cols);
      }

      for (int i = 0; i < rows; i++){
        for (int j = 0; j < cols; j++){
          data[i][j] = 0;
        }
      }


      active = true;
    }else{
      std::cout<<"Matrix is already initialized!\n";
      throw;
    }
  }

  void print(){
    if (active){
      for (int i = 0; i < rows; i++){
        for (int j = 0; j < cols; j++){
          std::cout<<data[i][j]<<" ";
        }
        std::cout<<std::endl;
      }
      std::cout<<std::endl;
    }else{
      std::cout<<"Matrix must be initialized!\n";
      throw;
    }
  }

  void scale(float scalar){
    if (active){
      for (int i = 0; i < rows; i++){
        for (int j = 0; j < cols; j++){
          data[i][j] *= scalar;
        }
      }
    }else{
      std::cout<<"Matrix must be initialized!\n";
      throw;
    }
  }

  void sigmoid(){
    if (active){
      for (int i = 0; i < rows; i++){
        for (int j = 0; j < cols; j++){
          data[i][j] = sigmoidFunc(data[i][j]);
        }
      }
    }else{
      std::cout<<"Matrix must be initialized!\n";
      throw;
    }
  }

  //matrix multiplication
  void multiply(Matrix b){
    if (active && b.isActive()){
      if(cols != b.getRows()){
        std::cout<<"Matrix columns and rows are not compatible!\n";
        throw;
      }
      for(int i = 0; i <rows; ++i){
          for(int j = 0; j < b.getCols(); ++j){
              for(int k = 0; k < cols; ++k){
                  data[i][j] += data[i][k] * b.data[k][j];
              }
          }
      }

    }else{
      std::cout<<"Matrix must be initialized!\n";
      throw;
    }
  }
  void randomize(){
    if (active){
      for (int i = 0; i < rows; i++){
        for (int j = 0; j < cols; j++){
          data[i][j] = rand()%10;
        }
      }
    }else{
      std::cout<<"Matrix must be initialized!\n";
      throw;
    }
  }
  void add(Matrix a){
    if (active){
      if (a.getRows() == rows && a.getCols() == cols){
        for (int i = 0; i < rows; i++){
          for (int j = 0; j < cols; j++){
            data[i][j] += a.data[i][j];
          }
        }
      }else{
        std::cout<<"Matrices' rows and colums are not equal!\n";
        throw;
      }
    }else{
      std::cout<<"Matrix must be initialized!\n";
      throw;
    }
  }


  void subtract(Matrix a){
    if (active){
      if (a.getRows() == rows && a.getCols() == cols){
        for (int i = 0; i < rows; i++){
          for (int j = 0; j < cols; j++){
            data[i][j] -= a.data[i][j];
          }
        }
      }else{
        std::cout<<"Matrices' rows and colums are not equal!\n";
        throw;
      }
    }else{
      std::cout<<"Matrix must be initialized!\n";
      throw;
    }
  }
  inline int getCols(){return cols;}
  inline int getRows(){return rows;}
  inline bool isActive(){return active;}
};

Я заранее извиняюсьпотому что я знаю, что это было много кода, но, честно говоря, я понятия не имею, где проблема. Любая помощь будет принята с благодарностью. Я очень плохо знаком с нейронными сетями и до сих пор не знаю, как все это работает.

...