Implementamos el proyecto ML usando Flask como REST API y lo hacemos accesible a través de la aplicación Flutter


Introduccion


El aprendizaje automático ya está en todas partes y es casi imposible encontrar software que no lo use directa o indirectamente. Creemos una pequeña aplicación que pueda cargar imágenes a un servidor para su posterior reconocimiento usando ML. Y luego los haremos disponibles a través de una aplicación móvil con búsqueda de texto por contenido.


Usaremos Flask para nuestra API REST, Flutter para aplicaciones móviles y Keras para aprendizaje automático. Usamos MongoDB como una base de datos para almacenar información sobre el contenido de las imágenes, y para información tomamos el modelo ResNet50 ya entrenado. Si es necesario, podemos reemplazar el modelo utilizando los métodos save_model () y load_model () disponibles en Keras. Esto último requerirá aproximadamente 100 MB tras la carga inicial del modelo. Puede leer sobre otros modelos disponibles en la documentación .


Comencemos con el matraz


Si no está familiarizado con Flask, puede crear una ruta en él simplemente agregando el decorador .route ('/') de la aplicación al controlador, donde app es la variable de la aplicación. Un ejemplo:


from flask import Flask app = Flask(__name__) @app.route('/') def hello_world(): return 'Hello, World!' 

Cuando comience y vaya a la dirección predeterminada 127.0.0.1 : 5000 / ¡veremos la respuesta Hello World! Puede leer sobre cómo hacer algo más complicado en la documentación .


Comencemos a crear un backend completo:


 import os import tensorflow as tf from tensorflow.keras.models import load_model from tensorflow.keras.preprocessing import image as img from keras.preprocessing.image import img_to_array import numpy as np from PIL import Image from keras.applications.resnet50 import ResNet50,decode_predictions,preprocess_input from datetime import datetime import io from flask import Flask,Blueprint,request,render_template,jsonify from modules.dataBase import collection as db 

Como puede ver, las importaciones contienen tensorflow , que usaremos como backend para keras , así como numpy para trabajar con matrices multidimensionales.


 mod = Blueprint('backend', __name__, template_folder='templates', static_folder='./static') UPLOAD_URL = 'http://192.168.1.103:5000/static/' model = ResNet50(weights='imagenet') model._make_predict_function() 

En la primera línea creamos un plan para una organización más conveniente de la aplicación. Debido a esto, necesitará usar mod .route ('/') para decorar el controlador. Resnet50 pre-entrenado en imagenet necesita llamar a _make_predict_function () para inicializar. Sin este paso, existe la posibilidad de obtener un error. Y se puede usar otro modelo reemplazando la línea


 model = ResNet50(weights='imagenet') 

en


 model = load_model('saved_model.h5') 

Así se verá el controlador:


 @mod.route('/predict', methods=['POST']) def predict(): if request.method == 'POST': # ,    if 'file' not in request.files: return "someting went wrong 1" user_file = request.files['file'] temp = request.files['file'] if user_file.filename == '': return "file name not found ..." else: path = os.path.join(os.getcwd()+'\\modules\\static\\'+user_file.filename) user_file.save(path) classes = identifyImage(path) db.addNewImage( user_file.filename, classes[0][0][1], str(classes[0][0][2]), datetime.now(), UPLOAD_URL+user_file.filename) return jsonify({ "status":"success", "prediction":classes[0][0][1], "confidence":str(classes[0][0][2]), "upload_time":datetime.now() }) 

En el código anterior, la imagen descargada se pasa al método IdentityImage (file_path) , que se implementa de la siguiente manera:


 def identifyImage(img_path): image = img.load_img(img_path, target_size=(224,224)) x = img_to_array(image) x = np.expand_dims(x, axis=0) # images = np.vstack([x]) x = preprocess_input(x) preds = model.predict(x) preds = decode_predictions(preds, top=1) print(preds) return preds 

Primero, convertimos la imagen a un tamaño de 224 * 224, porque es él quien necesita nuestro modelo. Luego pasamos a los bytes de imagen preprocesados model.predict () . Ahora nuestro modelo puede predecir qué hay en la imagen ( se necesita top = 1 para obtener el resultado más probable).


Guarde los datos recibidos sobre el contenido de la imagen en MongoDB utilizando la función db.addData () . Aquí está el código relevante:


 from pymongo import MongoClient from bson import ObjectId client = MongoClient("mongodb://localhost:27017") # host uri db = client.image_predition #Select the database image_details = db.imageData def addNewImage(i_name, prediction, conf, time, url): image_details.insert({ "file_name":i_name, "prediction":prediction, "confidence":conf, "upload_time":time, "url":url }) def getAllImages(): data = image_details.find() return data 

Como usamos blueprint, el código para la API se puede colocar en un archivo separado:


 from flask import Flask,render_template,jsonify,Blueprint mod = Blueprint('api',__name__,template_folder='templates') from modules.dataBase import collection as db from bson.json_util import dumps @mod.route('/') def api(): return dumps(db.getAllImages()) 

Como puede ver, usamos json para devolver datos de la base de datos. Puede ver el resultado en la dirección 127.0.0.1 : 5000 / api


Por encima, por supuesto, son solo las piezas de código más importantes. El proyecto completo se puede ver en el repositorio de GitHub . Y más sobre Pymongo se puede encontrar aquí .


Creamos la aplicación Flutter


La versión móvil recibirá imágenes y datos sobre sus contenidos a través de la API REST. Aquí está el resultado:



La clase ImageData encapsula datos de imagen:


 import 'dart:convert'; import 'package:http/http.dart' as http; import 'dart:async'; class ImageData { // static String BASE_URL ='http://192.168.1.103:5000/'; String uri; String prediction; ImageData(this.uri,this.prediction); } Future<List<ImageData>> LoadImages() async { List<ImageData> list; //complete fetch .... var data = await http.get('http://192.168.1.103:5000/api/'); var jsondata = json.decode(data.body); List<ImageData> newslist = []; for (var data in jsondata) { ImageData n = ImageData(data['url'],data['prediction']); newslist.add(n); } return newslist; } 

Aquí obtenemos json, lo convertimos en una lista de objetos ImageData y lo devolvemos a Future Builder usando la función LoadImages ()


Subir imágenes al servidor


 uploadImageToServer(File imageFile) async { print("attempting to connecto server......"); var stream = new http.ByteStream(DelegatingStream.typed(imageFile.openRead())); var length = await imageFile.length(); print(length); var uri = Uri.parse('http://192.168.1.103:5000/predict'); print("connection established."); var request = new http.MultipartRequest("POST", uri); var multipartFile = new http.MultipartFile('file', stream, length, filename: basename(imageFile.path)); //contentType: new MediaType('image', 'png')); request.files.add(multipartFile); var response = await request.send(); print(response.statusCode); } 

Para hacer que Flask esté disponible en la red local, desactive el modo de depuración y busque la dirección ipv4 usando ipconfig . Puede iniciar el servidor local de esta manera:


 app.run(debug=False, host='192.168.1.103', port=5000) 

A veces, un firewall puede evitar que una aplicación acceda a un host local, luego deberá reconfigurarse o deshabilitarse.




Todo el código fuente de la aplicación está disponible en github . Aquí están los enlaces que lo ayudarán a comprender lo que está sucediendo:


Keras: https://keras.io/


Aleteo: https://flutter.dev/


MongoDB: https://www.tutorialspoint.com/mongodb/


Harvard Python and Flask Course: https://www.youtube.com/watch?v=j5wysXqaIV8&t=5515s (las conferencias 2,3,4 son especialmente importantes)


GitHub: https://github.com/SHARONZACHARIA

Source: https://habr.com/ru/post/460995/


All Articles