Cómo conectar rápidamente una red neuronal a un sitio web





En este material, se propone, con un poco de esfuerzo, conectar python 3.7 + frasco + tensorflow 2.0 + keras + pequeñas inclusiones de js y mostrar una cierta interactividad en la página web. El usuario, dibujando en el lienzo, enviará números para reconocimiento, y el modelo previamente entrenado usando la arquitectura CNN reconocerá el dibujo resultante y generará el resultado. El modelo se entrena en el conocido conjunto de dígitos manuscritos MNIST, por lo tanto, solo reconocerá dígitos del 0 al 9 inclusive. Windows 7 se utiliza como el sistema en el que todo esto girará.



Pequeña introducción



Lo triste de los libros de aprendizaje automático es que el código se vuelve obsoleto casi tan pronto como se publica el libro. Y es bueno si el autor de la publicación apoya a su hijo, manteniendo y actualizando el código, pero a menudo todo se limita a lo que escribe: aquí están los requisitos.txt, instale paquetes obsoletos y todo funcionará.



También sucedió esta vez. Leyendo el aprendizaje profundo práctico de Python para la Web por Anubhav Singh, Sayak Paul, todo salió bien al principio. Sin embargo, después del primer capítulo, las vacaciones terminaron. Lo más desagradable fue que en general se cumplieron los requisitos establecidos en los requisitos.



Los propios desarrolladores de los paquetes tensorflow y keras agregaron más leña al fuego. Un paquete funciona solo con otro determinado y, ya sea una degradación de uno de ellos o la pandereta de un chamán.

Pero eso no es todo. ¡Resulta que algunos paquetes también dependen de la arquitectura!



Entonces, en ausencia de una alternativa a iron, tensorflow 2.0 se instaló en una plataforma con Celeron j1900 y, como resultó, no hay instrucción AVX2 allí:





y la opción a través de pip install tensorflow no funcionó.



¡Pero no todo es tan triste con las ganas e Internet!



La variante con tensorflow 2.0 se implementó a través de wheel - github.com/fo40225/tensorflow-windows-wheel/tree/master/2.0.0/py37/CPU/sse2 e instalación 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 se instaló con la versión mínima con la que "se hizo compatible" con tensorflow - Keras == 2.3.0.



por lo tanto



pip install tensorflow-2.0.0-cp37-cp37m-win_amd64.whl
      
      





y



pip install keras==2.3.0
      
      





Aplicación principal



Consideremos el código del programa 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)

      
      









Paquetes cargados:


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

      
      





Como descubrió imread, imresize ha quedado obsoleto desde scipy == 1.0. No está claro cómo funcionó todo para el autor, dado que el libro es relativamente nuevo (2019). Con scipy moderno == 1.6.1, la versión libreria del código no funcionó.



Cargamos desde disco, compilamos el modelo de red 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()

      
      





Aquí lo hemos reemplazado con tf.compat.v1.get_default_graph () debido a incompatibilidad.



Lo siguiente es la parte del servidor de matraces. "Dibujo" de la plantilla de página:




@app.route('/')
def index():
    return render_template("index.html")

      
      





La parte que convierte la imagen en una matriz numérica:




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))

      
      





Función de predicción principal:




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])

      
      





Se comentaron las líneas, que fueron reemplazadas por líneas de trabajo, y también se dejaron las conclusiones de líneas separadas para mayor claridad.



Cómo funciona



Después de comenzar con el comando python flask_app.py , se inicia el servidor local de flask, que muestra index.html intercalado con js.



El usuario dibuja un número en el lienzo, hace clic en "predecir". La imagen "vuela" al servidor, donde se guarda y se convierte en una matriz digital. Luego, CNN entra en la batalla, reconociendo el dígito y devolviendo la respuesta en forma de dígito.



La red no siempre da la respuesta correcta, porque estudiado por solo 10 eras. Esto se puede observar si se dibuja una figura "controvertida", que se puede interpretar de diferentes maneras.



* Puede girar el control deslizante para aumentar o disminuir el grosor del contorno del número con fines de reconocimiento.



La segunda versión del programa es a través de API, curl



El usuario carga su imagen con un número para su reconocimiento en el servidor y hace clic en "enviar":







Reemplace index.js con lo siguiente:



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;
});

      
      







La plantilla de la página también cambiará:



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>

      
      







El programa principal también cambiará ligeramente:



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)


      
      







Todo comienza de manera similar: python flask_app2.py



Opción curl (para windows)



Descargar curl



En la línea de comandos de Windows, envíe el comando:




curl -X POST -F img=@1.png http://localhost/predict/

      
      





donde 1.png es una imagen con un número (o tiene una ruta).

En respuesta, llegará un dígito reconocido.



Archivos para descargar - descargar .



All Articles