Skip to content

Commit

Permalink
Added MNIST dev environment example
Browse files Browse the repository at this point in the history
  • Loading branch information
DanRuta committed Mar 18, 2018
1 parent c5a24a4 commit e365b4e
Show file tree
Hide file tree
Showing 12 changed files with 489 additions and 18 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Expand Up @@ -5,4 +5,5 @@ coverage
Plan.todo
*.stackdump
/test/googletest/
/build
/build
/examples/mnist/mnist.js
3 changes: 3 additions & 0 deletions CHANGELOG.md
Expand Up @@ -7,6 +7,9 @@
#### InputLayer
- Added InputLayer class

#### Examples
- Added MNIST dev enviromnment example

# 3.2.0 - IMG data, validation, early stopping
---
#### Network
Expand Down
11 changes: 8 additions & 3 deletions README.md
Expand Up @@ -46,9 +46,14 @@ https://ai.danruta.co.uk/mnist - Interactive MNIST Digit classifier, using FCLay

https://ai.danruta.co.uk/webassembly - Performance comparison between JS and WebAssembly (v2.0) versions.

`examples/mnist` - Development environment set up for the MNIST data set

<img width="100%" src="./examples/mnist/readmeimg.png">


## Loading
---
There are two different versions of jsNet: WebAssembly, and JavaScript-only. There are demos included for loading both versions, in nodejs, as well as in the browser. The WebAssembly version is a little more complex to load, due to the NetWASM files which are generated by emscripten, containing the compiled code and the glue code to manage the WASM code. The ```NetWASM.js``` lazy loads the ```NetWASM.wasm``` file with the given path.
There are two different versions of jsNet: WebAssembly, and JavaScript-only. There are demos included in the `examples` folder for loading both versions, in nodejs, as well as in the browser. The WebAssembly version is a little more complex to load, due to the NetWASM files which are generated by emscripten, containing the compiled code and the glue code to manage the WASM code. The ```NetWASM.js``` lazy loads the ```NetWASM.wasm``` file with the given path.

The API has been kept the same as the JavaScript only version. Every single value has get/set bindings to the WebAssembly variables, meaning that apart from not being able to freely browse the values in dev tools (need to call them, to see them), you should notice no API difference between the two versions. One thing to note is that when changing primitive WebAssembly array values, eg, setting `net.layers[1].neurons[0].weights[0]` to 1, you need to set the entire, modified weights array, not at an index. For example, you would do this instead:
```javascript
Expand Down Expand Up @@ -342,7 +347,7 @@ Confusion matrices can be generated for each training, validation, and testing,

When calling the function in nodejs, the chart is printed out in the terminal. When called in the browser, it is printed in the console as a table.

<img width="100%" src="confusion.png">
<img width="100%" src="./examples/confusion.png">

To access the computed data yourself, including the percentages, without the printing, you can call `NetUtil.makeConfusionMatrix(net.trainingConfusionMatrix)`, `NetUtil.makeConfusionMatrix(net.testConfusionMatrix)`, or `NetUtil.makeConfusionMatrix(net.validationConfusionMatrix)`, which will return a JSON version of the printed data.

Expand Down Expand Up @@ -386,7 +391,7 @@ const net = new Network({
net.fromIMG(document.querySelector("img"), IMGArrays)
```

<img width="100%" src="fc-784f-100f-10f.png">
<img width="100%" src="./examples/mnist/fc-784f-100f-10f.png">

### Trained usage
---
Expand Down
1 change: 1 addition & 0 deletions browserDemo.html
Expand Up @@ -40,6 +40,7 @@
</script>
</head>
<body>
<a href="/examples/mnist/mnist.html">MNIST example</a><br>
Open the console to see logs.
</body>
</html>
File renamed without changes
9 changes: 9 additions & 0 deletions examples/index.html
@@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head>
<title>jsNet examples index</title>
</head>
<body>
<a href="/examples/mnist/mnist.html">MNIST example</a><br>
</body>
</html>
101 changes: 101 additions & 0 deletions examples/mnist/NetChart.js
@@ -0,0 +1,101 @@
"use strict"

class NetChart {
constructor ({container, size = {x: 500, y: 500}, cutOff=0, avgSpan=10, validationSplit=avgSpan}) {
const canvas = document.createElement("canvas")
canvas.width = size.x
canvas.height = size.y
canvas.style.maxHeight = size.y

this.chart = new Chart(canvas.getContext("2d"), {
type: "line",
data: {
datasets: [{
label: "Training Error",
borderColor: "rgba(0, 0, 0, 0.1)",
data: [],
pointRadius: 0
}, {
label: "Validation Error",
fill: false,
data: [],
borderColor: "rgba(150, 26, 31, 0.25)",
backgroundColor: "rgba(150, 26, 31, 0.25)",
pointRadius: 0
}]
},
options: {
scales: {
xAxes: [{
type: "linear",
position: "bottom"
}],
yAxes: [{
ticks: {
beginAtZero: true
}
}]
},
tooltips: {
enabled: false
},
// maintainAspectRatio: false
responsive: false
}
})
this.chartX = 0
this.chartYCount = 0
this.chartY = 0
this.chartY2 = 0
this.chartY2Count = 0
this.avgSpan = avgSpan
this.validationSplit = validationSplit
this.cutOff = cutOff
container.appendChild(canvas)
}

addTrainingError (err) {

if (this.chartYCount==this.avgSpan-1) {

this.chart.data.datasets[0].data.push({
x: this.chartX,
y: this.chartY/this.avgSpan
})

if (this.cutOff && this.chart.data.datasets[0].data.length>this.cutOff/this.avgSpan) {
this.chart.data.datasets[0].data.shift()
}

this.chartYCount = 0
this.chartY = 0
this.chartX += this.avgSpan
this.chart.update()
} else {
this.chartY += err
this.chartYCount++
}
}

addValidationError (err) {
this.chart.data.datasets[1].data.push({
x: this.chartX,
y: err
})

this.chartY2Count = 0
this.chartY2 = 0
}

clear () {
this.chart.data.datasets[0].data = []
this.chart.data.datasets[1].data = []
this.chartX = 0
this.chartYCount = 0
this.chartY = 0
this.chartY2Count = 0
this.chartY2 = 0
this.chart.update()
}

}
File renamed without changes

0 comments on commit e365b4e

Please sign in to comment.