TL;DR Vous pouvez l'essayer sur cette page. http://handwritten-classifier.app.ginrou.com/ Le code source est ici. https://github.com/ginrou/handwritten_classifier
C'est comme ça.
Il s'agit d'une application qui applique l'image d'entrée à un réseau neuronal et indique le numéro qui a été entré. Le code source est basé sur cela. handwritten_classifier
Cela peut être utile pour ceux qui souhaitent voir le code source du réseau neuronal et qui souhaitent l'utiliser rapidement à partir d'une application Web.
Il s'agit d'un perceptron général à 3 couches constitué d'une couche d'entrée cachée couche-sortie couche. Nous ne gérons pas l'apprentissage en profondeur. La fonction sigmoïde est utilisée comme fonction d'activation.
Ce qui suit sera utile pour les détails de l'algorithme.
Le plan est comme suit.
De (0,0) à (W, H) de l'image est transformé en un vecteur unidimensionnel, et un terme constant est ajouté pour créer le signal d'entrée $ {\ bf x} $.
Multipliez $ {\ bf x} $ par le poids $ w ^ 1_ {i, j} $ pour obtenir l'entrée $ z_ {in, i} $ dans la couche cachée. La sortie de la couche cachée est obtenue en multipliant cela par la fonction sigmoïde.
z_{in,i} = \sum_{j=0}^{N} w^1_{i,j} x_j \\
z_{out,i} = sigmoid(z_{in,i})
De plus, la sortie $ z_ {out, i} $ de la couche cachée multipliée par le poids $ w ^ 2_ {i, j} $ devient l'entrée $ y_ {in, i} $ à la couche de sortie, et la fonction sigmoïde est appliquée. Le résultat final est $ y_ {out, i} $.
y_{in,i} = \sum_{j=0}^{N} w^2_{i,j} z_{out,j} \\
y_{out,i} = sigmoid(y_{in,i})
La sortie {\ bf y} est un vecteur à 10 dimensions. Celui avec la plus grande valeur de sortie est le résultat de l'estimation.
Les variables de réseau neuronal ont des poids $ {\ bf w ^ 1}, {\ bf w ^ 2} $. Apprenez sa valeur. Il se résume comme suit. L'écriture / lecture des paramètres appris est également ajoutée.
https://github.com/ginrou/handwritten_classifier/blob/master/NeuralNetwork.py
NeuralNetwork.py
#!/usr/bin/env python
from math import exp
import numpy
def sigmoid(x):
return 1.0 / (1.0 + exp(-x))
def sigmoid_a(array):
return numpy.vectorize(sigmoid)(array)
class NeuralNetwork:
def __init__(self, in_size, hidden_size, out_size):
self.hidden_weight = 0.1 * (numpy.random.random_sample((hidden_size, in_size+1)) - 0.5)
self.output_weight = 0.1 * (numpy.random.random_sample((out_size, hidden_size+1)) - 0.5)
def fit(self, x, t, update_ratio = 0.1):
z, y = self.fire(x)
dy = ( y - t ) *y * ( 1 - y )
dz = (self.output_weight.T.dot(dy))[1:] * z * ( 1- z )
output_input = numpy.r_[ numpy.array([1]), z ]
self.output_weight -= update_ratio * dy.reshape(-1,1) * output_input
hidden_input = numpy.r_[ numpy.array([1]), x ]
self.hidden_weight -= update_ratio * dz.reshape(-1,1) * hidden_input
def fire(self, x):
z = sigmoid_a(self.hidden_weight.dot(numpy.r_[ numpy.array([1]), x ]))
y = sigmoid_a(self.output_weight.dot(numpy.r_[ numpy.array([1]), z ]))
return (z, y)
def predicate(self, x):
z, y = self.fire(x)
return numpy.array(y).argmax()
def save(self, filepath):
numpy.savez(filepath, hidden = self.hidden_weight, output = self.output_weight)
def load(self, filepath):
npzfiles = numpy.load(filepath)
self.hidden_weight = npzfiles['hidden']
self.output_weight = npzfiles['output']
Nous formerons ce réseau neuronal.
Pour l'ensemble de données, j'ai utilisé MNIST Data Set. Une partie de http://deeplearning.net/tutorial/gettingstarted.html est au format Pickle car l'analyse de l'ensemble de données brutes est fastidieuse. Alors j'ai utilisé ça.
Étant donné que la taille de l'image d'entrée de cet ensemble de données est de 28 x 28, la taille de la couche d'entrée est de 784 dimensions, la couche de sortie reconnaît les nombres de 0 à 9, donc il s'agit de 10 dimensions et la couche intermédiaire est correctement définie sur 300 dimensions.
Exécutez avec handwritten_classifier.py inclus dans Repository Je peux le faire.
Il a fallu environ 2-3 minutes pour former 50 000 points de l'ensemble de données MNIST, et la précision était de 92,52%.
Utilisez le système de reconnaissance numérique en utilisant ce réseau neuronal à partir du navigateur. L'idée est
C'est un mécanisme. handwritten_classifier utilise Flask pour créer un frontal Web.
C'est comme ça pour obtenir la valeur de luminosité de l'image à partir du canevas avec JS et l'envoyer.
var estimate = function(context) {
var img_buf = getImageBuffer(context, 28, 28);
$.ajax({
type:"post",
url:"/estimate",
data: JSON.stringify({"input": img_buf}),
contentType: 'application/json',
success: function(result) {
$("#estimated").text("Estimated = " + result.estimated);
}
});
};
var getImageBuffer = function(context, width, height) {
var tmpCanvas = $('<canvas>').get(0);
tmpCanvas.width = width;
tmpCanvas.height = height;
var tmpContext = tmpCanvas.getContext('2d');
tmpContext.drawImage(context.canvas, 0, 0, width, height);
var image = tmpContext.getImageData(0,0,width,height);
var buffer = []
for( var i = 0; i < image.data.length; i += 4 ) {
var sum = image.data[i+0] + image.data[i+1] + image.data[i+2] + image.data[i+3];
buffer.push(Math.min(sum,255));
}
return buffer;
};
Si la taille de la toile est de 28 x 28, elle est trop petite, alors dessinez sur une grande toile sur le navigateur et Puis rétrécissez.
Le json envoyé est
{"input":[0,0,255,255,,,,255]}
Comme ça.
C'est ce que vous obtenez chez Flask
@app.route("/estimate", methods = ["POST"])
def estimate():
try:
x = numpy.array(request.json["input"]) / 255.0
y = int(nn.predicate(x))
return jsonify({"estimated":y})
except Exception as e:
print(e)
return jsonify({"error":e})
Dans le référentiel précédent
$ python app.py
Vous pouvez l'essayer sur http: // localhost: 5000
.
Docker Parce qu'il prend en charge Docker avec de la colle https://registry.hub.docker.com/u/ginrou/handwritten-classifier/ Peut être utilisé avec. Si vous voulez l'essayer rapidement, vous pouvez le déployer sur heroku.
L'écriture en Python le rend si court! Application Web, précision de reconnaissance étonnamment médiocre