Do-it-yourself neural network from scratch. Part 3. Sad Or Happy?

In the previous part of the article, we wrote an implementation of the simplest neural network in the form of a JS class. Now let's try to give her a real assignment. The scenario will be as follows: the user will draw a smiley in a certain block of the web page, and our neural network will try to determine whether it is sad or funny. Let's get started.





Since we are implementing our small application as a web page, and layout and styling are beyond the scope of our topic, we will skip these points and dwell on programming in more detail. First, let's create a page template, place elements on it and connect a script with a neural network class.





<!doctype html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <meta name="viewport"
       content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
 <meta http-equiv="X-UA-Compatible" content="ie=edge">
 <script src="NeuralNetwork.js"></script>
 <title>Sad Or Happy?</title>
</head>
<body>
 <div id="wrapper">
   <canvas width="400" height="400" id="paintField"></canvas>
   <div id="controls">
     <button class="control" id="happy"></button>
     <button class="control" id="sad"></button>
     <button class="control" id="clear">
       Clear
     </button>
     <button class="control" id="train">
       Train
     </button>
     <button class="control" disabled id="predict">
       Predict
     </button>
   </div>
 </div>
</body>

<style>
   #wrapper {
       width: 400px;
       margin: 0 auto;
   }

   #paintField {
       height: 400px;
       width: 100%;
       border: 1px solid black;
   }

   #controls {
       display: grid;
       grid-gap: 10px;
       grid-template-columns: 1fr 1fr;
       margin-top: 30px;
   }

   #clear, #train, #predict {
       grid-column: 1 / -1;
   }

   .control {
       font-size: 20px;
       padding: 4px;
       cursor: pointer;
   }
</style>

<script>

</script>
</html>
      
      



Let's take a quick look at the controls.





The canvas with the id paintField is a 10-by-10 canvas of 40 pixels each. On it, the user will use the mouse to draw a smiley to train the network or make predictions from it.





Buttons with id happy and sad will fill the dataset for training the neural network. The user drew a smiley, pressed the corresponding button, the network remembered it and became a little smarter.





Clear . , .





Train .





, , Predict . .





<script> .





const canvas = document.querySelector('#paintField');
const clearBtn = document.querySelector('#clear');
const sadBtn = document.querySelector('#sad');
const happyBtn = document.querySelector('#happy');
const trainBtn = document.querySelector('#train');
const predictBtn = document.querySelector('#predict');
const ctx = canvas.getContext('2d');
const paintField = new Array(100);
const trainData = [];
const NN = new Network(100, 2);
let mouseDown = false;
let happyCount = 0;
let sadCount = 0;

NN.learningRate = 0.8;
      
      



:





paintField - . 100 , .





trainData - .





NN - . 100 - paintField 2 . , , - .





, , learningRate .





.





function drawGrid() {
 ctx.strokeStyle = '#CCC'

 for (let i = 1; i < 10; i++) {
   ctx.moveTo(0, i * 40);
   ctx.lineTo(400, i * 40);
   ctx.moveTo(i * 40, 0);
   ctx.lineTo(i * 40, 400);
 }

 ctx.stroke();
}

function clearCanvas() {
 ctx.fillStyle = '#FFF';
 ctx.fillRect(0, 0, 400, 400);
 drawGrid();
}

function drawSquare(row, column, color) {
 ctx.fillStyle = color;
 ctx.fillRect(column * 40 + 1, row * 40 + 1, 38, 38);
}

function draw(event) {
 const rowIndex = Math.floor(event.offsetY / 40);
 const columnIndex = Math.floor(event.offsetX / 40);
 const arrayIndex = rowIndex * 10 + columnIndex;
 paintField[arrayIndex] = 1;
 const color = paintField[arrayIndex] ? 'green' : 'white';
 drawSquare(rowIndex, columnIndex, color);
}

function clearField() {
 paintField.fill(false);
 clearCanvas(ctx)
}

function updateInterface() {
 happyBtn.innerText = `=) ${happyCount}`;
 sadBtn.innerText = `=( ${sadCount}`;
}

function storeResult(value) {
 trainData.push([[...paintField], value]);
 updateInterface()
}
      
      



drawGrid - .





clearCanvas - .





drawSquare - .





draw - , . , , .





clearField - .





updateInterface - , , .





storeResult - .





, , .





document.addEventListener('mousedown', (e) => {
 mouseDown = true;
});

document.addEventListener('mouseup', (e) => {
 mouseDown = false;
});

canvas.addEventListener('mousemove', (e) => {
 if (!mouseDown) {
   return;
 }
 draw(e);
});

clearBtn.addEventListener('click', () => {
 clearField();
});

happyBtn.addEventListener('click', () => {
 happyCount += 1;
 storeResult([1, 0]);
 clearField();
});

sadBtn.addEventListener('click', () => {
 sadCount += 1;
 storeResult([0, 1]);
 clearField();
});

predictBtn.addEventListener('click', () => {
 NN.input = [...paintField];
 const [happiness, sadness] = NN.prediction;
 alert(`I think it's a ${happiness > sadness ? 'happy' : 'sad'} face!\n
  Happiness: ${Math.round(happiness * 100)}% Sadness: ${Math.round(sadness * 100)}%`);
});

trainBtn.addEventListener('click', () => {
 NN.train(trainData, 1000).then(() => {
   predictBtn.disabled = false;
   alert('Trained!');
 })
});

clearField();
updateInterface();
      
      



. . , , .





, - , - . , Train . ? ! Predict.





That’s all, Folks!

. , , . . .













.








All Articles