title: Why does my multilayer perceptron's output converge to 0.5?
body: <p>I'm currently developing a neural network to solve XOR issue with Javascript. I have 2 inputs, 2 hidden neurons and 1 output. I added 1 bias in each layer. My output keeps converging to 0.5 despite the fact that I decreased my learning rate and checked the values of my weights to ensure that they got initialized randomly. </p>
  
  <p>I don't know what I should do... please help me. </p>
  
  <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
  <div class="snippet-code">
  <pre class="snippet-code-js lang-js prettyprint-override"><code>class Matrix {
  
      /*  Paramètres : 
          Table : tableau bidimensionnel */ 
      constructor (table) {
          this.table = table;
          this.h = table.length; 
          this.w = table[0].length; 
      }
  
      getTable () {
          return this.table; 
      }
  
      dot (arr, bias = []) {
  
          let m = []; 
  
          for (let i = 0; i &lt; this.h; i++) {
              let s = 0; 
              for (let j = 0; j &lt; this.w; j++) {
                  s += this.table[i][j] * arr[i]; 
              }
              if (bias.length &gt; 0) {
                  s += bias[i]; 
              }
              m.push([s]); 
          }
      
          return new Matrix(m).getTable(); 
  
      }
  
      
  }
  
  class Brain { // Les poids peuvent être initialisés à 0 !!!
  
      constructor (inputs, hiddens, outputs) {
          //this.inputs = Array.from(Array(inputs), n =&gt; Math.round(Math.random())); // Entrées binaires (0 ou 1)
          this.inputs = Array(); 
  
          this.weights_l1 = Array.from(Array(hiddens), x =&gt; (Array.from(Array(inputs), n =&gt; Math.random() * 5))) // Initialisation des poids de la première couche
          this.weights_l2 = Array.from(Array(outputs), x =&gt; (Array.from(Array(hiddens), n =&gt; Math.random() * 5))) // Initialisation des poids de la deuxième couche
  
          this.weights_l1_gradient = Array.from(Array(hiddens), x =&gt; (Array.from(Array(inputs), n =&gt; 0)))
          this.weights_l2_gradient = Array.from(Array(outputs), x =&gt; (Array.from(Array(hiddens), n =&gt; 0)))
  
          this.bias_l1 = [Math.random() * 5, Math.random() * 5]; 
          this.bias_l2 = Math.random() * 5; 
  
          this.bias_l1_gradient = [0, 0];  
          this.bias_l2_gradient = [0]; 
  
          this.nb_inputs = inputs; 
          this.nb_hiddens = hiddens; 
          this.nb_outputs = outputs; 
  
          this.learning_rate = 0.2; 
      }
  
      set (dataset) {
          this.dataset = dataset; 
      }
  
      sigmoid (x) {
          return (1 / (1 + Math.exp(-x))); 
      }
  
      sigmoid_der (x) {
          return x * (1 - x); 
      }
  
      getOutputs (values) {
          let outputs = Array();
  
          for (let i = 0; i &lt; values.length; i++) {
              outputs.push(this.sigmoid(values[i])); 
          }
  
          return outputs; 
      }
  
      initGradients () {
          this.weights_l1_gradient = Array.from(Array(this.nb_hiddens), x =&gt; (Array.from(Array(this.nb_inputs), n =&gt; 0)))
          this.weights_l2_gradient = Array.from(Array(this.nb_outputs), x =&gt; (Array.from(Array(this.nb_hiddens), n =&gt; 0)))
          this.bias_l1_gradient = [0, 0]; 
          this.bias_l2_gradient = 0; 
      }
  
      think () {
          
          let values_l1 = new Matrix(this.weights_l1);
  
          let arr = values_l1.dot(this.inputs, this.bias_l1); 
  
          this.outputs_l1 = this.getOutputs(arr); 
          
          let values_l2 = new Matrix(this.weights_l2); 
  
          let arr2 = values_l2.dot(this.outputs_l1, this.bias_l2); 
  
          this.output = this.getOutputs(arr2)[0]; 
  
          console.log(this.output); 
      }
  
      learn () {
  
          this.initGradients(); 
  
          // On parcourt le dataset
          for (let i = 0; i &lt; this.dataset.length; i++) {
  
              this.inputs[0] = this.dataset[i][0]; 
              this.inputs[1] = this.dataset[i][1]; 
              this.target = this.dataset[i][2]; 
  
              this.think(); // On parcourt le réseau 
              
              this.error = this.output - this.target; 
              console.log("error: " + this.error); 
              console.log("output: " + this.output); 
  
              for (let i = 0; i &lt; this.weights_l1_gradient.length; i++) {
                  for (let j = 0; j &lt; this.weights_l1_gradient[i].length; j++) {
                      this.weights_l1_gradient[i][j] += this.error * this.sigmoid_der(this.outputs_l1[i]) * this.inputs[i]; 
                  }
              }
  
              for (let i = 0; i &lt; this.bias_l1_gradient.length; i++) {
                  this.bias_l1_gradient[i] += this.error * this.sigmoid_der(this.outputs_l1[i]); 
              }
  
              for (let i = 0; i &lt; this.weights_l2_gradient.length; i++) {
                  for (let j = 0; j &lt; this.weights_l2_gradient[i].length; j++) {
                      this.weights_l2_gradient[i][j] += this.error * this.sigmoid_der(this.output) * this.outputs_l1[i]; 
                  }
              }
  
              this.bias_l2_gradient += this.error * this.sigmoid_der(this.output); 
          }
  
          for (let i = 0; i &lt; this.weights_l1.length; i++) {
              for (let j = 0; j &lt; this.weights_l1[i].length; j++) {
                  this.weights_l1[i][j] -= this.weights_l1_gradient[i][j] * this.learning_rate; 
              }
          }
  
          for (let i = 0; i &lt; this.bias_l1.length; i++) {
              this.bias_l1[i] -= this.bias_l1_gradient[i] * this.learning_rate; 
          }
  
          for (let i = 0; i &lt; this.weights_l2.length; i++) {
              for (let j = 0; j &lt; this.weights_l2[i].length; j++) {
                  this.weights_l2[i][j] -= this.weights_l2_gradient[i][j] * this.learning_rate; 
              }
          }
  
          this.bias_l2 -= this.bias_l2_gradient * this.learning_rate;  
  
      }
  }
  
  let brain = new Brain(2, 2, 1); 
  
  let dataset = [
      [1, 1, 0], 
      [1, 0, 1], 
      [0, 1, 1], 
      [0, 0, 0]
  ]; 
  
  brain.set(dataset); 
  
  for (let i = 0; i &lt; 200; i++) {
      brain.learn(); 
  }</code></pre>
  </div>
  </div>
  </p>
  
  <p>Thank you. </p>