Dans ce matériel, il est proposé, avec un peu d'effort, de connecter python 3.7 + flask + tensorflow 2.0 + keras + petites inclusions de js et d'afficher une certaine interactivité sur la page web. L'utilisateur, dessinant sur le canevas, enverra des nombres pour la reconnaissance, et le modèle précédemment formé utilisant l'architecture CNN reconnaîtra le dessin résultant et produira le résultat. Le modèle est formé sur l'ensemble bien connu de chiffres manuscrits MNIST, par conséquent, il ne reconnaîtra que les chiffres de 0 à 9 inclus. Windows 7 est utilisé comme système sur lequel tout cela tournera.
Petite introduction
Ce qui est triste à propos des livres d'apprentissage automatique, c'est que le code devient obsolète presque aussitôt que le livre lui-même est publié. Et c'est bien si l'auteur de la publication soutient son enfant, en maintenant et en mettant à jour le code, mais souvent tout est limité à ce qu'ils écrivent - voici le requirements.txt, installez des packages obsolètes, et tout fonctionnera.
C'est arrivé cette fois aussi. En lisant l'apprentissage en profondeur Python pratique pour le Web par Anubhav Singh, Sayak Paul, tout s'est bien passé au début. Cependant, après le premier chapitre, les vacances étaient terminées. Le plus désagréable était que les exigences énoncées dans les exigences étaient généralement respectées.
Les développeurs des packages tensorflow et keras ont eux-mêmes ajouté du carburant au feu. Un paquet ne fonctionne qu'avec un certain autre et, soit une rétrogradation de l'un d'entre eux, soit le tambourin d'un chaman.
Mais ce n'est pas tout. Il s'avère que certains packages dépendent également de l'architecture!
Ainsi, en l'absence d'alternative au fer, tensorflow 2.0 a été installé sur une plate-forme avec Celeron j1900 et, comme il s'est avéré, il n'y a pas d'instructions AVX2 là-bas:
Et l'option via pip install tensorflow ne fonctionnait pas.
Mais tout n'est pas si triste avec le désir et Internet!
La variante avec tensorflow 2.0 a été implémentée via wheel - github.com/fo40225/tensorflow-windows-wheel/tree/master/2.0.0/py37/CPU/sse2 et installation x86: vc_redist.x86.exe, x64: vc_redist.x64 .exe (https://support.microsoft.com/en-us/help/2977003/the-latest-supported-visual-c-downloads).
Keras a été installé avec la version minimale avec laquelle il "est devenu compatible" avec tensorflow - Keras == 2.3.0.
donc
pip install tensorflow-2.0.0-cp37-cp37m-win_amd64.whl
et
pip install keras==2.3.0
Application principale
Considérons le code du programme principal.
flask_app.py
#code work with scipy==1.6.1, tensorflow @ file:///D:/python64/tensorflow-2.0.0-cp37-cp37m-win_amd64.whl,
#Keras==2.3.0
from flask import Flask, render_template, request
import imageio
#https://imageio.readthedocs.io/en/stable/examples.html
#from scipy.misc import imread, imresize
#from matplotlib.pyplot import imread
import numpy as np
import tensorflow as tf
from tensorflow.keras.models import model_from_json
from skimage import transform,io
json_file = open('model.json','r')
model_json = json_file.read()
json_file.close()
model = model_from_json(model_json)
model.load_weights("weights.h5")
model.compile(loss='categorical_crossentropy',optimizer='adam',metrics=['accuracy'])
#graph = tf.get_default_graph()
graph = tf.compat.v1.get_default_graph()
app = Flask(__name__)
@app.route('/')
def index():
return render_template("index.html")
import re
import base64
def convertImage(imgData1):
imgstr = re.search(r'base64,(.*)', str(imgData1)).group(1)
with open('output.png', 'wb') as output:
output.write(base64.b64decode(imgstr))
@app.route('/predict/', methods=['GET', 'POST'])
def predict():
global model, graph
imgData = request.get_data()
convertImage(imgData)
#print(imgData)
#x = imread('output.png', mode='L')
#x.shape
#(280, 280)
x = imageio.imread('output.png',pilmode='L')
#x = imresize(x, (28, 28))
#x = x.resize(x, (28, 28))
x = transform.resize(x, (28,28), mode='symmetric', preserve_range=True)
#(28, 28)
#type(x)
#<class 'numpy.ndarray'>
x = x.reshape(1, 28, 28, 1)
#(1, 28, 28, 1)
x = tf.cast(x, tf.float32)
# perform the prediction
out = model.predict(x)
#print(np.argmax(out, axis=1))
# convert the response to a string
response = np.argmax(out, axis=1)
return str(response[0])
if __name__ == "__main__":
# run the app locally on the given port
app.run(host='0.0.0.0', port=80)
# optional if we want to run in debugging mode
app.run(debug=True)
Paquets téléchargés:
from flask import Flask, render_template, request
import imageio
#https://imageio.readthedocs.io/en/stable/examples.html
#from scipy.misc import imread, imresize
#from matplotlib.pyplot import imread
import numpy as np
import tensorflow as tf
from tensorflow.keras.models import model_from_json
from skimage import transform,io
Comme imread l'a découvert, imresize est obsolète depuis scipy == 1.0. On ne sait pas comment tout a fonctionné pour l'auteur, étant donné que le livre est relativement nouveau (2019). Avec scipy moderne == 1.6.1, la version livresque du code ne fonctionnait pas.
Nous chargeons à partir du disque, compilons le modèle de réseau neuronal:
json_file = open('model.json','r')
model_json = json_file.read()
json_file.close()
model = model_from_json(model_json)
model.load_weights("weights.h5")
model.compile(loss='categorical_crossentropy',optimizer='adam',metrics=['accuracy'])
#graph = tf.get_default_graph()
graph = tf.compat.v1.get_default_graph()
Ici, nous l'avons remplacé par tf.compat.v1.get_default_graph () en raison d'une incompatibilité.
Vient ensuite la partie serveur flask. "Dessin" du modèle de page:
@app.route('/')
def index():
return render_template("index.html")
La partie qui convertit l'image en un tableau numérique:
import re
import base64
def convertImage(imgData1):
imgstr = re.search(r'base64,(.*)', str(imgData1)).group(1)
with open('output.png', 'wb') as output:
output.write(base64.b64decode(imgstr))
Fonction de prédiction principale:
def predict():
global model, graph
imgData = request.get_data()
convertImage(imgData)
#print(imgData)
#x = imread('output.png', mode='L')
#x.shape
#(280, 280)
x = imageio.imread('output.png',pilmode='L')
#x = imresize(x, (28, 28))
#x = x.resize(x, (28, 28))
x = transform.resize(x, (28,28), mode='symmetric', preserve_range=True)
#(28, 28)
#type(x)
#<class 'numpy.ndarray'>
x = x.reshape(1, 28, 28, 1)
#(1, 28, 28, 1)
x = tf.cast(x, tf.float32)
# perform the prediction
out = model.predict(x)
#print(np.argmax(out, axis=1))
# convert the response to a string
response = np.argmax(out, axis=1)
return str(response[0])
Les lignes ont été commentées, qui ont été remplacées par des lignes fonctionnelles, et les conclusions des lignes séparées ont également été laissées pour plus de clarté.
Comment ça fonctionne
Après avoir démarré avec la commande python flask_app.py , le serveur flask local est lancé, qui affiche index.html entrecoupé de js.
L'utilisateur dessine un nombre sur le canevas, clique sur "prédire". L'image «vole» vers le serveur, où elle est enregistrée et convertie en une matrice numérique. Ensuite, CNN entre dans la bataille, reconnaissant le chiffre et renvoyant la réponse sous la forme d'un chiffre.
Le réseau ne donne pas toujours la bonne réponse, car étudié pendant seulement 10 époques. Cela peut être observé si vous dessinez un chiffre «controversé», qui peut être interprété de différentes manières.
* Vous pouvez tourner le curseur pour augmenter ou diminuer l'épaisseur du contour du nombre à des fins de reconnaissance.
La deuxième version du programme est via API, curl
L'utilisateur télécharge son image avec un numéro de reconnaissance sur le serveur et clique sur "soumettre":
Remplaçons index.js par ce qui suit:
index.js:
$("form").submit(function(evt){
evt.preventDefault();
var formData = new FormData($(this)[0]);
$.ajax({
url: '/predict/',
type: 'POST',
data: formData,
async: false,
cache: false,
contentType: false,
enctype: 'multipart/form-data',
processData: false,
success: function (response) {
$('#result').empty().append(response);
}
});
return false;
});
Le modèle de page changera également:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>MNIST CNN</title>
</head>
<body>
<h1>MNIST Handwritten Digits Prediction</h1>
<form>
<input type="file" name="img"></input>
<input type="submit"></input>
</form>
<hr>
<h3>Prediction: <span id="result"></span></h3>
<script
src='https://code.jquery.com/jquery-3.6.0.min.js'></script>
<script src="{{ url_for('static',filename='index.js') }}"></script>
</body>
</html>
Le programme principal changera également légèrement:
flask_app2.py
#code work with scipy==1.6.1, tensorflow @ file:///D:/python64/tensorflow-2.0.0-cp37-cp37m-win_amd64.whl,
#Keras==2.3.0
from flask import Flask, render_template, request
import imageio
#https://imageio.readthedocs.io/en/stable/examples.html
#from scipy.misc import imread, imresize
#from matplotlib.pyplot import imread
import numpy as np
import tensorflow as tf
from tensorflow.keras.models import model_from_json
from skimage import transform,io
json_file = open('model.json','r')
model_json = json_file.read()
json_file.close()
model = model_from_json(model_json)
model.load_weights("weights.h5")
model.compile(loss='categorical_crossentropy',optimizer='adam',metrics=['accuracy'])
#graph = tf.get_default_graph()
graph = tf.compat.v1.get_default_graph()
app = Flask(__name__)
@app.route('/')
def index():
return render_template("index.html")
import re
import base64
def convertImage(imgData1):
imgstr = re.search(r'base64,(.*)', str(imgData1)).group(1)
with open('output.png', 'wb') as output:
output.write(base64.b64decode(imgstr))
@app.route('/predict/', methods=['POST'])
def predict():
global model, graph
imgData = request.get_data()
try:
stringToImage(imgData)
except:
f = request.files['img']
f.save('image.png')
#x = imread('output.png', mode='L')
#x.shape
#(280, 280)
x = imageio.imread('image.png',pilmode='L')
#x = imresize(x, (28, 28))
#x = x.resize(x, (28, 28))
x = transform.resize(x, (28,28), mode='symmetric', preserve_range=True)
#(28, 28)
#type(x)
#<class 'numpy.ndarray'>
x = x.reshape(1, 28, 28, 1)
#(1, 28, 28, 1)
x = tf.cast(x, tf.float32)
# perform the prediction
out = model.predict(x)
#print(np.argmax(out, axis=1))
# convert the response to a string
response = np.argmax(out, axis=1)
return str(response[0])
if __name__ == "__main__":
# run the app locally on the given port
app.run(host='0.0.0.0', port=80)
# optional if we want to run in debugging mode
app.run(debug=True)
Tout commence de la même manière - python flask_app2.py
Option Curl (pour Windows)
Télécharger curl
Dans la ligne de commande Windows, envoyez la commande:
curl -X POST -F img=@1.png http://localhost/predict/
où 1.png est une image avec un nombre (ou avec un chemin d'accès).
Un chiffre reconnu arrivera en réponse.
Fichiers à télécharger - télécharger .