نقوم بنشر مشروع ML باستخدام Flask كواجهة برمجة تطبيقات REST وجعله قابلاً للوصول من خلال تطبيق Flutter


مقدمة


التعلم الآلي موجود بالفعل في كل مكان ومن المستحيل تقريبًا العثور على برنامج لا يستخدمه بشكل مباشر أو غير مباشر. لنقم بإنشاء تطبيق صغير يمكنه تحميل الصور إلى خادم للتعرف عليها لاحقًا باستخدام ML. وبعد ذلك سنوفرها من خلال تطبيق الهاتف المحمول مع البحث عن النص حسب المحتوى.


سوف نستخدم Flask لواجهة REST API الخاصة بنا ، ورفرفة لتطبيق الهاتف المحمول و Keras للتعلم الآلي. نستخدم MongoDB كقاعدة بيانات لتخزين المعلومات حول محتويات الصور ، وللعلم نأخذ نموذج ResNet50 المدربين بالفعل. إذا لزم الأمر ، يمكننا استبدال النموذج باستخدام أساليب save_model () و load_model () المتاحة في Keras. سيتطلب الأخير حوالي 100 ميغابايت عند التحميل الأولي للنموذج. يمكنك أن تقرأ عن الطرز الأخرى المتاحة في الوثائق .


لنبدأ مع قارورة


إذا لم تكن معتادًا على Flask ، فيمكنك إنشاء مسار على ذلك من خلال إضافة التطبيق .route ('/') إلى وحدة التحكم ، حيث يكون التطبيق هو متغير التطبيق. مثال:


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

عند البدء والانتقال إلى العنوان الافتراضي 127.0.0.1 : 5000 / سنرى إجابة Hello World! يمكنك أن تقرأ عن كيفية القيام بشيء أكثر تعقيدًا في الوثائق .


لنبدأ في إنشاء خلفية كاملة:


 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 

كما ترون ، تحتوي الواردات على tensorflow ، والتي سوف نستخدمها كواجهة خلفية للكاميرا ، وكذلك شاذة للعمل مع المصفوفات متعددة الأبعاد.


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

في السطر الأول ، نقوم بإنشاء مخطط لتنظيم أكثر ملاءمة للتطبيق. لهذا السبب ، سوف تحتاج إلى استخدام mod .rout ('/') لتزيين جهاز التحكم. يحتاج نموذج Resnet50 ، الذي تم تدريبه مسبقًا على imagenet ، إلى استدعاء _make_predict_function () للبدء. بدون هذه الخطوة ، هناك فرصة للحصول على خطأ. ويمكن استخدام نموذج آخر عن طريق استبدال الخط


 model = ResNet50(weights='imagenet') 

في


 model = load_model('saved_model.h5') 

إليك ما ستبدو عليه وحدة التحكم:


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

في الكود أعلاه ، يتم تمرير الصورة التي تم تنزيلها إلى طريقة identImage (file_path) ، والتي يتم تنفيذها على النحو التالي:


 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 

أولاً ، نقوم بتحويل الصورة إلى حجم 224 * 224 ، لأن هذا هو بالضبط ما يحتاج نموذجنا. بعد ذلك نمرر إلى بايتات الصورة التي تمت معالجتها مسبقًا من قبل model.predict () . الآن يمكن أن يتنبأ نموذجنا بما هو موجود في الصورة ( أعلى = 1 مطلوب للحصول على النتيجة الأكثر ترجيحًا).


احفظ البيانات المستلمة حول محتوى الصورة في MongoDB باستخدام وظيفة db.addData () . فيما يلي الجزء المتعلق بالكود:


 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 

منذ أن استخدمنا مخططًا ، يمكن وضع رمز واجهة برمجة التطبيقات في ملف منفصل:


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

كما ترون ، نستخدم json لإرجاع بيانات قاعدة البيانات. يمكنك إلقاء نظرة على النتيجة على العنوان 127.0.0.1 : 5000 / api


أعلاه ، بالطبع ، ليست سوى أهم أجزاء التعليمات البرمجية. يمكن الاطلاع على المشروع بالكامل في مستودع جيثب . ويمكن الاطلاع على المزيد حول Pymongo هنا .


نخلق تطبيق الرفرفة


ستتلقى نسخة الجوال الصور والبيانات على محتوياتها عبر واجهة برمجة تطبيقات REST. هذه هي النتيجة:



الطبقة ImageData بتغليف بيانات الصورة:


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

هنا نحصل على json ، ونحوله إلى قائمة كائنات ImageData ، ونعيده إلى Future Builder باستخدام دالة LoadImages ()


تحميل الصور إلى الخادم


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

لإتاحة Flask على الشبكة المحلية ، قم بتعطيل وضع التصحيح وابحث عن عنوان ipv4 باستخدام ipconfig . يمكنك بدء تشغيل الخادم المحلي مثل هذا:


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

في بعض الأحيان ، يمكن لجدار الحماية منع تطبيق من الوصول إلى مضيف محلي ، ثم يجب إعادة تكوينه أو تعطيله.




كل رمز مصدر التطبيق متاح على جيثب . فيما يلي الروابط التي ستساعدك على فهم ما يحدث:


Keras: https://keras.io/


الرفرفة: https://flutter.dev/


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


دورة هارفارد بيثون ودار القارورة: https://www.youtube.com/watch؟v=j5wysXqaIV8&t=5515s (تعتبر المحاضرات 2،3،4 ذات أهمية خاصة)


جيثب: https://github.com/SHARONZACHARIA

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


All Articles