Implementamos o projeto ML usando o Flask como uma API REST e o tornamos acessível através do aplicativo Flutter


1. Introdução


O aprendizado de máquina já está em toda parte e é quase impossível encontrar software que não o use direta ou indiretamente. Vamos criar um pequeno aplicativo que pode carregar imagens em um servidor para reconhecimento posterior usando o ML. E então os disponibilizaremos por meio de um aplicativo móvel com pesquisa de texto por conteúdo.


Usaremos o Flask para nossa API REST, o Flutter para aplicativos móveis e o Keras para aprendizado de máquina. Usamos o MongoDB como um banco de dados para armazenar informações sobre o conteúdo das imagens e, para obter informações, usamos o modelo ResNet50 já treinado. Se necessário, podemos substituir o modelo usando os métodos save_model () e load_model () disponíveis no Keras. O último exigirá cerca de 100 MB após o carregamento inicial do modelo. Você pode ler sobre outros modelos disponíveis na documentação .


Vamos começar com o Flask


Se você não estiver familiarizado com o Flask, poderá criar uma rota adicionando simplesmente o decorador .route ('/') do aplicativo ao controlador, em que app é a variável do aplicativo. Um exemplo:


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

Quando você iniciar e acessar o endereço padrão 127.0.0.1 : 5000 / , veremos a resposta Olá, mundo! Você pode ler sobre como fazer algo mais complicado na documentação .


Vamos começar a criar um back-end 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 você pode ver, as importações contêm fluxo tensor , que usaremos como back-end para keras , bem como numpy para trabalhar com matrizes multidimensionais.


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

Na primeira linha, criamos um blueprint para uma organização mais conveniente do aplicativo. Por esse motivo , você precisará usar o mod .route ('/') para decorar o controlador. O Resnet50 pré-treinado em imagenet precisa chamar _make_predict_function () para inicializar. Sem esta etapa, é provável que ocorra um erro. E outro modelo pode ser usado substituindo a linha


 model = ResNet50(weights='imagenet') 

em


 model = load_model('saved_model.h5') 

Aqui está a aparência do 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() }) 

No código acima, a imagem baixada é passada para o método identityImage (file_path) , que é implementado da seguinte maneira:


 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 

Primeiro, convertemos a imagem em um tamanho de 224 * 224, porque é ele quem é necessário para o nosso modelo. Em seguida, passamos para os bytes de imagem pré-processados model.predict () . Agora, nosso modelo pode prever o que está na imagem ( top = 1 é necessário para obter o resultado mais provável).


Salve os dados recebidos sobre o conteúdo da imagem no MongoDB usando a função db.addData () . Aqui está o trecho de 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 o blueprint, o código da API pode ser colocado em um arquivo 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 você pode ver, usamos o json para retornar dados do banco de dados. Você pode ver o resultado no endereço 127.0.0.1 : 5000 / api


Acima, é claro, são apenas os trechos de código mais importantes. O projeto completo pode ser visualizado no repositório GitHub . E mais sobre Pymongo pode ser encontrado aqui .


Criamos o aplicativo Flutter


A versão móvel receberá imagens e dados em seu conteúdo por meio da API REST. Aqui está o resultado:



A classe ImageData encapsula os dados da imagem:


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

Aqui obtemos o json, convertemos para uma lista de objetos ImageData e devolvemos para o Future Builder usando a função LoadImages ()


Fazendo upload de imagens para o 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 disponibilizar o Flask na rede local, desative o modo de depuração e localize o endereço ipv4 usando ipconfig . Você pode iniciar o servidor local assim:


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

Às vezes, um firewall pode impedir que um aplicativo acesse um host local e precisará ser reconfigurado ou desativado.




Todo o código fonte do aplicativo está disponível no github . Aqui estão os links que ajudarão você a entender o que está acontecendo:


Keras: https://keras.io/


Flutter: https://flutter.dev/


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


Curso de Harvard Python e Flask: https://www.youtube.com/watch?v=j5wysXqaIV8&t=5515s (as palestras 2,3,4 são especialmente importantes)


GitHub: https://github.com/SHARONZACHARIA

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


All Articles