Nous déployons le projet ML en utilisant Flask comme API REST et le rendons accessible via l'application Flutter


Présentation


L'apprentissage automatique est déjà partout et il est presque impossible de trouver un logiciel qui ne l'utilise pas directement ou indirectement. Créons une petite application qui peut télécharger des images sur un serveur pour une reconnaissance ultérieure à l'aide de ML. Et puis nous les rendrons disponibles via une application mobile avec recherche de texte par contenu.


Nous utiliserons Flask pour notre API REST, Flutter pour application mobile et Keras pour l'apprentissage automatique. Nous utilisons MongoDB comme base de données pour stocker des informations sur le contenu des images, et pour des informations nous prenons le modèle ResNet50 déjà formé. Si nécessaire, nous pouvons remplacer le modèle en utilisant les méthodes save_model () et load_model () disponibles dans Keras. Ce dernier nécessitera environ 100 Mo lors du chargement initial du modèle. Vous pouvez lire d'autres modèles disponibles dans la documentation .


Commençons par Flask


Si vous n'êtes pas familier avec Flask, vous pouvez créer un itinéraire sur celui-ci en ajoutant simplement le décorateur d' application .route ('/') au contrôleur, où app est la variable d'application. Un exemple:


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

Lorsque vous démarrez et accédez à l'adresse par défaut 127.0.0.1 : 5000 / nous verrons la réponse Bonjour tout le monde! Vous pouvez lire comment faire quelque chose de plus compliqué dans la documentation .


Commençons par créer un backend complet:


 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 

Comme vous pouvez le voir, les importations contiennent tensorflow , que nous utiliserons comme backend pour les keras , ainsi que numpy pour travailler avec des tableaux multi-tailles.


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

Sur la première ligne, nous créons un plan pour une organisation plus pratique de l'application. Pour cette raison, vous devrez utiliser le mod .route ('/') pour décorer le contrôleur. Le modèle Resnet50 , pré-formé sur imagenet, doit appeler _make_predict_function () pour s'initialiser. Sans cette étape, il y a une chance d'obtenir une erreur. Et un autre modèle peut être utilisé en remplaçant la ligne


 model = ResNet50(weights='imagenet') 

sur


 model = load_model('saved_model.h5') 

Voici à quoi ressemblera le contrôleur:


 @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() }) 

Dans le code ci-dessus, l'image téléchargée est transmise à la méthode identImage (file_path) , qui est implémentée comme suit:


 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 

Tout d'abord, nous convertissons l'image à une taille de 224 * 224, car c'est lui qui a besoin de notre modèle. Ensuite, nous passons aux octets d'image prétraités model.predict () . Maintenant, notre modèle peut prédire ce qui est sur l'image ( top = 1 est nécessaire pour obtenir le résultat le plus probable).


Enregistrez les données reçues sur le contenu de l'image dans MongoDB à l'aide de la fonction db.addData () . Voici le morceau de code pertinent:


 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 

Puisque nous avons utilisé le plan directeur, le code de l'API peut être placé dans un fichier séparé:


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

Comme vous pouvez le voir, nous utilisons json pour renvoyer les données de la base de données. Vous pouvez consulter le résultat à l'adresse 127.0.0.1 : 5000 / api


Au-dessus, bien sûr, ne sont que les éléments de code les plus importants. Le projet complet peut être consulté dans le référentiel GitHub . Et plus sur Pymongo peut être trouvé ici .


Nous créons l'application Flutter


La version mobile recevra des images et des données sur leur contenu via l'API REST. Voici le résultat:



La classe ImageData encapsule les données d'image:


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

Ici, nous obtenons json, le convertissons en une liste d'objets ImageData et le renvoyons à Future Builder en utilisant la fonction LoadImages ()


Téléchargement d'images sur le serveur


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

Pour rendre Flask disponible sur le réseau local, désactivez le mode de débogage et recherchez l'adresse ipv4 à l'aide d' ipconfig . Vous pouvez démarrer le serveur local comme ceci:


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

Parfois, un pare-feu peut empêcher une application d'accéder à un hôte local, alors il devra être reconfiguré ou désactivé.




Tout le code source de l'application est disponible sur github . Voici les liens qui vous aideront à comprendre ce qui se passe:


Keras: https://keras.io/


Flutter: https://flutter.dev/


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


Cours Harvard Python et Flask: https://www.youtube.com/watch?v=j5wysXqaIV8&t=5515s (les conférences 2,3,4 sont particulièrement importantes)


GitHub: https://github.com/SHARONZACHARIA

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


All Articles