Wir stellen das ML-Projekt mit Flask als REST-API bereit und machen es über die Flutter-Anwendung zugänglich


Einführung


Maschinelles Lernen ist bereits überall und es ist fast unmöglich, Software zu finden, die es nicht direkt oder indirekt verwendet. Erstellen wir eine kleine Anwendung, die Bilder zur späteren Erkennung mit ML auf einen Server hochladen kann. Und dann werden wir sie über eine mobile Anwendung mit Textsuche nach Inhalten verfügbar machen.


Wir werden Flask für unsere REST-API, Flutter für mobile Anwendungen und Keras für maschinelles Lernen verwenden. Wir verwenden MongoDB als Datenbank zum Speichern von Informationen über den Inhalt von Bildern, und für Informationen verwenden wir das bereits trainierte ResNet50- Modell. Bei Bedarf können wir das Modell mithilfe der in Keras verfügbaren Methoden save_model () und load_model () ersetzen. Letzteres benötigt beim ersten Laden des Modells ca. 100 MB. Weitere verfügbare Modelle finden Sie in der Dokumentation .


Beginnen wir mit Flask


Wenn Sie mit Flask nicht vertraut sind, können Sie eine Route darauf erstellen, indem Sie einfach den App- Dekorator .route ('/') zum Controller hinzufügen, wobei app die Anwendungsvariable ist. Ein Beispiel:


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

Wenn Sie beginnen und zur Standardadresse 127.0.0.1 : 5000 / gehen , wird die Antwort Hallo Welt! In der Dokumentation erfahren Sie, wie Sie etwas Komplizierteres tun können.


Beginnen wir mit der Erstellung eines vollständigen Backends:


 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 

Wie Sie sehen können, enthalten Importe Tensorflow , den wir als Backend für Keras verwenden , sowie Numpy für die Arbeit mit Arrays mit mehreren Größen.


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

In der ersten Zeile erstellen wir einen Entwurf für eine bequemere Organisation der Anwendung. Aus diesem Grund müssen Sie mod .route ('/') verwenden , um den Controller zu dekorieren. Das auf imagenet vorab trainierte Resnet50- Modell muss zum Initialisieren _make_predict_function () aufrufen. Ohne diesen Schritt besteht die Möglichkeit, dass ein Fehler auftritt. Ein anderes Modell kann durch Ersetzen der Leitung verwendet werden


 model = ResNet50(weights='imagenet') 

auf


 model = load_model('saved_model.h5') 

So sieht der Controller aus:


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

Im obigen Code wird das heruntergeladene Bild an die Methode identityImage (file_path) übergeben , die wie folgt implementiert wird:


 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 

Zuerst konvertieren wir das Bild in eine Größe von 224 * 224, weil Genau das braucht unser Modell. Dann übergeben wir die vorverarbeiteten Bildbytes model.predict () . Jetzt kann unser Modell vorhersagen, was sich auf dem Bild befindet ( top = 1 wird benötigt, um das wahrscheinlichste Einzelergebnis zu erhalten).


Speichern Sie die empfangenen Daten zum Bildinhalt in MongoDB mit der Funktion db.addData () . Hier ist der relevante Code:


 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 

Da wir Blueprint verwendet haben, kann der Code für die API in einer separaten Datei abgelegt werden:


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

Wie Sie sehen können, verwenden wir json, um Datenbankdaten zurückzugeben. Sie können das Ergebnis unter der Adresse 127.0.0.1 : 5000 / api ansehen


Oben sind natürlich nur die wichtigsten Codeteile aufgeführt. Das vollständige Projekt kann im GitHub-Repository angezeigt werden. Und mehr über Pymongo finden Sie hier .


Wir erstellen die Flutter-Anwendung


Die mobile Version empfängt Bilder und Daten zu deren Inhalten über die REST-API. Hier ist das Ergebnis:



Die ImageData- Klasse kapselt Bilddaten:


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

Hier erhalten wir json, konvertieren es in eine Liste von ImageData- Objekten und geben es mit der Funktion LoadImages () an Future Builder zurück


Hochladen von Bildern auf den Server


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

Deaktivieren Sie den Debug-Modus und suchen Sie die IPv4-Adresse mithilfe von ipconfig, um Flask im lokalen Netzwerk verfügbar zu machen. Sie können den lokalen Server folgendermaßen starten:


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

Manchmal kann eine Firewall verhindern, dass eine Anwendung auf einen lokalen Host zugreift. Dann muss sie neu konfiguriert oder deaktiviert werden.




Der gesamte Quellcode der Anwendung ist auf github verfügbar. Hier sind die Links, die Ihnen helfen zu verstehen, was passiert:


Keras: https://keras.io/


Flattern: https://flutter.dev/


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


Harvard Python- und Flask-Kurs: https://www.youtube.com/watch?v=j5wysXqaIV8&t=5515s (Vorlesungen 2,3,4 sind besonders wichtig)


GitHub: https://github.com/SHARONZACHARIA

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


All Articles