Last active
October 25, 2019 13:13
-
-
Save mpj/d93a4bdcce7b31f7a70ae66bdb34a9f9 to your computer and use it in GitHub Desktop.
Neural Vanilla Workshop
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<!-- http://bit.ly/vanillaneural --> | |
<head> | |
<link href="style.css" rel="stylesheet" /> | |
</head> | |
<body> | |
<div class="legend legendX">Scariness</div> | |
<div class="legend legendY">Actual power</div> | |
<canvas id="mycanvas" width="1000" height="1000"></canvas> | |
<script> | |
const someDragons = generateDragons(500) | |
function generateDragons(numberOfDragonsToGenerate) { | |
let dragons = [] | |
for (let i = 0; i < numberOfDragonsToGenerate; i++) { | |
const dragon = { | |
scariness: randomNumber(0, 1000), | |
power: randomNumber(0, 1000) | |
} | |
dragons.push(dragon) | |
} | |
return dragons | |
} | |
const initialWeights = { | |
scariness: randomNumber(-1, 1), | |
power: randomNumber(-1, 1), | |
} | |
let trainedWeights = initialWeights | |
const trainingSetSize = 20000 | |
const noiseProbability = 0.01 | |
for(const dragon of generateDragons(trainingSetSize)) { | |
const correctClassification = powerClassification(dragon) | |
let trainOnClassification = correctClassification | |
if(Math.random() < noiseProbability) { | |
trainOnClassification *= -1 | |
} | |
trainedWeights = train( | |
trainedWeights, dragon, trainOnClassification) | |
} | |
function train (weights, dragon, actualPowerClassification) { | |
const guessResult = guessPowerClassification(weights, dragon) | |
const error = actualPowerClassification - guessResult | |
return { | |
scariness: weights.scariness + error * dragon.scariness, | |
power: weights.power + error * dragon.power | |
} | |
} | |
const canvas = document.getElementById('mycanvas') | |
const context = canvas.getContext('2d') | |
context.beginPath() | |
context.moveTo(0, 0) | |
context.lineTo(1000, 1000) | |
context.stroke() | |
for (const dragon of someDragons) { | |
const x = dragon.scariness | |
const y = dragon.power | |
const rectangleHeight = 5 | |
const rectangleWidth = 5 | |
if (guessPowerClassification(trainedWeights, dragon) === 1) { | |
context.fillStyle = 'black' | |
} else { | |
context.fillStyle = 'hotpink' | |
} | |
context.fillRect(x, y, rectangleWidth, rectangleHeight) | |
} | |
// Legend | |
// 1 = more powerful than it looks | |
// -1 = less powerful than it looks | |
function powerClassification(dragon) { | |
return (dragon.power > dragon.scariness) ? 1 : -1 | |
} | |
function guessPowerClassification(weights, dragon) { | |
const someMathGarble = | |
dragon.power * weights.power + | |
dragon.scariness * weights.scariness | |
return someMathGarble >= 0 ? 1 : -1 | |
} | |
function randomNumber(lower, higher) { | |
return Math.random() * (higher - lower) + lower | |
} | |
</script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
body { | |
font-family: Helvetica; | |
padding: 1rem; | |
} | |
.legend { | |
background-color: black; | |
color: white; | |
font-weight: bold; | |
} | |
.legendX { | |
padding-left: 30px; | |
width: 1000px; | |
height: 20px; | |
} | |
.legendY { | |
writing-mode: vertical-rl; | |
text-orientation: mixed; | |
float: left; | |
height: 1000px; | |
padding-top: 10px; | |
} | |
canvas { | |
float: left; | |
margin-bottom: 2rem; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment