Frontender écrit des neurones. Niveau de difficulté "Je veux gérer"

Tôt ou tard, cela doit arriver

Tôt ou tard, le développeur front-end se lasse de jouer avec ses frameworks, se lasse de déranger ses collègues - backend, se lasse de jouer aux devops et commence à se tourner vers l'apprentissage automatique, les données sont de la science et c'est tout. Heureusement, un cours sur deux pour ceux qui souhaitent accéder au site Web contribue à cela, en criant sur toutes les plateformes à quel point c'est facile. Moi aussi, marre de transférer des données de la base de données vers l'API, puis de l'API vers les tables et les formulaires, j'ai décidé de prendre de courtes vacances et d'essayer d'appliquer mes compétences frontales à l'apprentissage automatique. Heureusement, il y a des gens comme  Daniel Shiffman  et  Charlie Gerard qui, par leur exemple, aident à ne pas abandonner ce qu'ils ont commencé après avoir vu les premières pages avec des formules mathématiques.





Si nous revenons un peu en arrière et regardons le titre, nous verrons que je ne vais pas  copier des livres et  lancer des mots high-tech pour essayer d'expliquer ce que j'ai fait.





Je suis presque sûr que tout le monde, en entendant l'expression «apprentissage automatique», imagine une image où de très nombreux neurones en plusieurs couches et tous sont entrelacés. Donc, ce n'est pas une coïncidence. C'est pourquoi l'apprentissage automatique a été conçu - pour implémenter le cerveau humain et ses réseaux neuronaux sous forme numérique.





Diagramme de réseau neuronal
Diagramme de réseau neuronal

? , . , , . - , , , . , , .





. , , - , . - () .





, ? , - , ( , , ).





- , - . .





- . . . .





“ ” - , , , , .





, . , , , . , -, , .





Poids du réseau neuronal

, , . ,  0.1*X1 (W1 == 0.1)   X1. (, , , , , , -1 1). , 10 . , ,  1*X2 (W2 == 1).





, . , .





, , -? , ( - ). f() = .   - input - output ,  f, - .





, .  input  X   output  . , - , , , , .





, , ,   , -  i  .





 label  . , , -  3,  label = “ ”, , . , , , .





. “ !” . -, , , ?





, . , ?





 thecodingtrain, . , .





, . .





, , ( ). .





? , . - , . . . , , .





, .  score, .





. , , () , , , , . , , , .





, , ,   raid shadow legends.  dino game   google chrome. , , ?





Dino game

 p5.js. , , . 5 : setup, , ;  draw - , , .





? , , , . , , .





- , , . . .





class Cactus {
  constructor() {}
}

class Dino {
  constructor() {}
}
      
      



, - - ( - , ), . ? , , , -  GameObject,  onTick, . , , . .





...

onTick(cb = () => { }) {
  cb(this);
}

...
      
      



, , . ,  , , .





(, , ). , . , : - , , , , , , . ,  , .





switch (this.state) {
  case DinoStateEnum.run: break;
  case DinoStateEnum.jump: {
    this.currH += this.jumpSpeed;

    if (this.currH == this.maxH) {
      this.state = DinoStateEnum.fall;
    }

    break;
  }
  case DinoStateEnum.fall: {
    this.currH -= this.jumpSpeed;

    if (this.currH == 0) {
      this.state = DinoStateEnum.run;
    }

    break;
  }
}
      
      



, . , . . .





function updateCactuses() {
  const copy = cactuses.slice();

  for (let i = 0; i < copy.length; i++) {
    let c = copy[i];

    c.onTick(cactus => {
      drawCactus(cactus)

      cactus.currDistance -= dinoVelocitySlider.value();

      if (cactus.currDistance + cactusW < initialDinoW && !cactus.passDinoPosition) {
        updateDinoScore()

        cactus.passDinoPosition = true;
      }

      if (cactus.currDistance < 0) {
        cactuses.splice(i, 1);
      }
    })
  }
}
      
      



, ,   .





 tensorflowjs  , - . , . .





<script
  src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@2.0.0/dist/tf.min.js">
</script>

<script>
  tf.setBackend('cpu') // tf  
</script>
      
      



, ? . : . , ?





, . , , . - . , . , , , . , .





, . . , . , ?





, - . , , . ( , , , ).





, , . ? .





? - 200-300 , . , (best score) , , . , . . ().





, , , .





  .





  • - .





  • C - .





  • - , .





  , :





  • T  .





  • .





  • .





  • , .





4 .





8 . 2, :  .





:





createModel() {
  const model = tf.sequential();

  const hiddenLayer = tf.layers.dense({
    units: this.hidden_nodes, // -     (8)
    inputShape: [this.input_nodes], // -     (4)
    activation: "sigmoid" //  
  });

  model.add(hiddenLayer);

  const outputLayer = tf.layers.dense({
    units: this.output_nodes, // -     (2)
    activation: "sigmoid"
  });

  model.add(outputLayer);

  return model;
}
      
      



 sequential()  . , . - , . . ,  sigmoid.





, , - ,  tensorflow  .





, . , .





predict(inputs) {
  return tf.tidy(() => {
    const xs = tf.tensor([inputs]); //     ( )

    const ys = this.model.predict(xs); //  

    const output = ys.dataSync(); //    

    return output;
  });
}
      
      



 tensorflow  ,  tensor ( ) , , , ,  tidy.





tensorflow  , , . , , . ( , ). 2, 2 . , , , , . ,  output[0] > output[1], .





 dino npc.





- , , .





, - .





function drawDino(dino) {
  if (dino.isDead) return;

  if (dino.state != DinoStateEnum.run) {
    //   ,      
    image(dino2, initialDinoW, initialDinoH - dino.currH, dinoW, dinoH); // 5      
  } else if (iteration % 7 == 0)
    //      
    image(dino1, initialDinoW, initialDinoH, dinoW, dinoH);
  else
    image(dino2, initialDinoW, initialDinoH, dinoW, dinoH);
}
      
      



. , , , , , . .





function updateGenerationIfNeeded() {
  if (dinos.every(d => d.isDead)) {
    cactuses = [];
    dinoVelocitySlider.value(initDinoVelocity);

    dinos = newGeneration(dinos)
  }
}
      
      



, , . , . .





, , . , .





: .





mutate(rate) {
  tf.tidy(() => {
    const weights = this.model.getWeights(); //   

    const mutatedWeights = [];

    for (let i = 0; i < weights.length; i++) {
      let tensor = weights[i]; //   -  
      let shape = weights[i].shape;
      let values = tensor.dataSync().slice();

      for (let j = 0; j < values.length; j++) {
        if (Math.random() < rate) { //    
          let w = values[j];
          values[j] = w + this.gaussianRandom(); //       -1  1
        }
      }

      let newTensor = tf.tensor(values, shape);
      mutatedWeights[i] = newTensor;
    }

    this.model.setWeights(mutatedWeights); //   
  });
}
      
      



, . . e .  fitness ( ).





const calculateFitness = (dinos) => {
  let sum = 0;

  dinos.map(d => sum += d.score)
  dinos.map(d => d.fitness = d.score / sum)
}
      
      



. . ( ), , .





:





const pickOne = (dinos) => { //       fitness
  let index = 0;
  let r = Math.random();

  while (r > 0) {
    r = r - dinos[index].fitness;
    index++;
  }

  index--;

  let dino = dinos[index] //   -   ,    rate

  const dinoBrain = dino.brain.copy();
  dinoBrain.mutate(0.2) //   

  let newDino = new Dino(dinoBrain) //    

  return newDino;
}
      
      



. , . , , .





for (let i = 0; i < TOTAL; i++) {
  newDinos.push(pickOne(oldDinos));
}

console.log(currentGeneration++);
return newDinos;
      
      



, , , , . 50+ . .





.





P.S. , welcome to PR's.  v_hadoocken








All Articles