initial push

This commit is contained in:
cupcakearmy 2020-01-17 19:56:30 +01:00
parent ae60abd9fb
commit 727f750aec
8 changed files with 504 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
yarn.lock
.cache
dist
node_modules

10
docker-compose.yml Normal file
View File

@ -0,0 +1,10 @@
version: '3.7'
services:
server:
image: cupcakearmy/static
restart: unless-stopped
ports:
- 80:80
volumes:
- ./dist:/srv:ro

16
package.json Normal file
View File

@ -0,0 +1,16 @@
{
"scripts": {
"start": "parcel src/index.html",
"build": "parcel build src/index.html"
},
"browserslist": [
"last 1 Chrome versions"
],
"dependencies": {
"@tensorflow/tfjs": "^1.5.1"
},
"devDependencies": {
"parcel-bundler": "^1.12.4",
"parcel-plugin-static-files-copy": "^2.2.1"
}
}

81
src/canvas.js Normal file
View File

@ -0,0 +1,81 @@
/* jslint esversion: 6, asi: true */
var canvas, ctx, flag = false,
prevX = 0,
currX = 0,
prevY = 0,
currY = 0,
dot_flag = false;
var x = "black",
y = 2;
function init() {
canvas = document.getElementById('can');
ctx = canvas.getContext("2d");
w = canvas.width;
h = canvas.height;
canvas.addEventListener("mousemove", function (e) {
findxy('move', e)
}, false);
canvas.addEventListener("mousedown", function (e) {
findxy('down', e)
}, false);
canvas.addEventListener("mouseup", function (e) {
findxy('up', e)
}, false);
canvas.addEventListener("mouseout", function (e) {
findxy('out', e)
}, false);
window.document.getElementById('clear').addEventListener('click', erase)
}
function draw() {
ctx.beginPath();
ctx.moveTo(prevX, prevY);
ctx.lineTo(currX, currY);
ctx.strokeStyle = x;
ctx.lineWidth = y;
ctx.stroke();
ctx.closePath();
}
function erase() {
ctx.clearRect(0, 0, w, h);
}
function findxy(res, e) {
if (res == 'down') {
prevX = currX;
prevY = currY;
currX = e.clientX - canvas.offsetLeft;
currY = e.clientY - canvas.offsetTop;
flag = true;
dot_flag = true;
if (dot_flag) {
ctx.beginPath();
ctx.fillStyle = x;
ctx.fillRect(currX, currY, 2, 2);
ctx.closePath();
dot_flag = false;
}
}
if (res == 'up' || res == "out") {
flag = false;
}
if (res == 'move') {
if (flag) {
prevX = currX;
prevY = currY;
currX = e.clientX - canvas.offsetLeft;
currY = e.clientY - canvas.offsetTop;
draw();
}
}
}
init()

61
src/index.html Normal file
View File

@ -0,0 +1,61 @@
<html>
<head>
<style>
* {
box-sizing: border-box;
font-family: monospace;
}
html,
body {
padding: 0;
margin: 0;
height: 100vh;
width: 100vw;
display: flex;
justify-content: center;
align-items: center;
}
body>div {
text-align: center;
}
div canvas {
display: inline-block;
border: 1px solid;
}
div input {
display: inline-block;
margin-top: .5em;
padding: .5em 2em;
background: white;
outline: none;
border: 1px solid;
font-weight: bold;
}
</style>
</head>
<body>
<div>
<h1>MNIST (Pretrained)</h1>
<canvas id="can" width="28" height="28"></canvas>
<br />
<input id="clear" type="button" value="clear">
<br />
<input id="test" type="button" value="test">
<br />
<h2 id="result"></h2>
<a href="https://github.com/cupcakearmy/mnist">
<h3>source code</h3>
</a>
</div>
<script src="./tf.js"></script>
<script src="./canvas.js"></script>
</body>
</html>

22
src/tf.js Normal file
View File

@ -0,0 +1,22 @@
/* jslint esversion: 8, asi: true */
import * as tf from '@tensorflow/tfjs';
let model
tf.loadLayersModel('/model.json').then(m => {
model = m
})
window.document.getElementById('test').addEventListener('click', async () => {
const canvas = window.document.querySelector('canvas')
const { data, width, height } = canvas.getContext('2d').getImageData(0, 0, 28, 28)
const tensor = tf.tensor(new Uint8Array(data.filter((_, i) => i % 4 === 3)), [1, 28, 28, 1])
const prediction = model.predict(tensor)
const result = await prediction.data()
const guessed = result.indexOf(1)
console.log(guessed)
window.document.querySelector('#result').innerText = guessed
})

BIN
static/group1-shard1of1.bin Normal file

Binary file not shown.

310
static/model.json Normal file
View File

@ -0,0 +1,310 @@
{
"format": "layers-model",
"generatedBy": "keras v2.2.4-tf",
"convertedBy": "TensorFlow.js Converter v1.4.0",
"modelTopology": {
"keras_version": "2.2.4-tf",
"backend": "tensorflow",
"model_config": {
"class_name": "Sequential",
"config": {
"name": "sequential",
"layers": [
{
"class_name": "Conv2D",
"config": {
"name": "conv2d",
"trainable": true,
"batch_input_shape": [
null,
28,
28,
1
],
"dtype": "float32",
"filters": 64,
"kernel_size": [
3,
3
],
"strides": [
1,
1
],
"padding": "valid",
"data_format": "channels_last",
"dilation_rate": [
1,
1
],
"activation": "relu",
"use_bias": true,
"kernel_initializer": {
"class_name": "GlorotUniform",
"config": {
"seed": 420,
"dtype": "float32"
}
},
"bias_initializer": {
"class_name": "Zeros",
"config": {
"dtype": "float32"
}
},
"kernel_regularizer": null,
"bias_regularizer": null,
"activity_regularizer": null,
"kernel_constraint": null,
"bias_constraint": null
}
},
{
"class_name": "Conv2D",
"config": {
"name": "conv2d_1",
"trainable": true,
"dtype": "float32",
"filters": 32,
"kernel_size": [
3,
3
],
"strides": [
1,
1
],
"padding": "valid",
"data_format": "channels_last",
"dilation_rate": [
1,
1
],
"activation": "relu",
"use_bias": true,
"kernel_initializer": {
"class_name": "GlorotUniform",
"config": {
"seed": 420,
"dtype": "float32"
}
},
"bias_initializer": {
"class_name": "Zeros",
"config": {
"dtype": "float32"
}
},
"kernel_regularizer": null,
"bias_regularizer": null,
"activity_regularizer": null,
"kernel_constraint": null,
"bias_constraint": null
}
},
{
"class_name": "MaxPooling2D",
"config": {
"name": "max_pooling2d",
"trainable": true,
"dtype": "float32",
"pool_size": [
2,
2
],
"padding": "valid",
"strides": [
2,
2
],
"data_format": "channels_last"
}
},
{
"class_name": "Dropout",
"config": {
"name": "dropout",
"trainable": true,
"dtype": "float32",
"rate": 0.25,
"noise_shape": null,
"seed": 420
}
},
{
"class_name": "Flatten",
"config": {
"name": "flatten",
"trainable": true,
"dtype": "float32",
"data_format": "channels_last"
}
},
{
"class_name": "Dense",
"config": {
"name": "dense",
"trainable": true,
"dtype": "float32",
"units": 128,
"activation": "relu",
"use_bias": true,
"kernel_initializer": {
"class_name": "GlorotUniform",
"config": {
"seed": 420,
"dtype": "float32"
}
},
"bias_initializer": {
"class_name": "Zeros",
"config": {
"dtype": "float32"
}
},
"kernel_regularizer": null,
"bias_regularizer": null,
"activity_regularizer": null,
"kernel_constraint": null,
"bias_constraint": null
}
},
{
"class_name": "Dropout",
"config": {
"name": "dropout_1",
"trainable": true,
"dtype": "float32",
"rate": 0.5,
"noise_shape": null,
"seed": 420
}
},
{
"class_name": "Dense",
"config": {
"name": "dense_1",
"trainable": true,
"dtype": "float32",
"units": 10,
"activation": "softmax",
"use_bias": true,
"kernel_initializer": {
"class_name": "GlorotUniform",
"config": {
"seed": 420,
"dtype": "float32"
}
},
"bias_initializer": {
"class_name": "Zeros",
"config": {
"dtype": "float32"
}
},
"kernel_regularizer": null,
"bias_regularizer": null,
"activity_regularizer": null,
"kernel_constraint": null,
"bias_constraint": null
}
}
]
}
},
"training_config": {
"loss": "categorical_crossentropy",
"metrics": [
"accuracy"
],
"weighted_metrics": null,
"sample_weight_mode": null,
"loss_weights": null,
"optimizer_config": {
"class_name": "Adam",
"config": {
"name": "Adam",
"learning_rate": 0.0010000000474974513,
"decay": 0.0,
"beta_1": 0.8999999761581421,
"beta_2": 0.9990000128746033,
"epsilon": 1e-07,
"amsgrad": false
}
}
}
},
"weightsManifest": [
{
"paths": [
"group1-shard1of1.bin"
],
"weights": [
{
"name": "conv2d/kernel",
"shape": [
3,
3,
1,
64
],
"dtype": "float32"
},
{
"name": "conv2d/bias",
"shape": [
64
],
"dtype": "float32"
},
{
"name": "conv2d_1/kernel",
"shape": [
3,
3,
64,
32
],
"dtype": "float32"
},
{
"name": "conv2d_1/bias",
"shape": [
32
],
"dtype": "float32"
},
{
"name": "dense/kernel",
"shape": [
4608,
128
],
"dtype": "float32"
},
{
"name": "dense/bias",
"shape": [
128
],
"dtype": "float32"
},
{
"name": "dense_1/kernel",
"shape": [
128,
10
],
"dtype": "float32"
},
{
"name": "dense_1/bias",
"shape": [
10
],
"dtype": "float32"
}
]
}
]
}