كيفية استخدام FastAPI لتعلم الآلة

يوفر FastAPI طريقة سريعة لبناء خدمة خلفية باستخدام بايثون. باستخدام بعض المزخرفات، يمكنك تحويل دالة بايثون إلى تطبيق واجهة برمجة تطبيقات.

يُستخدم على نطاق واسع من قِبل العديد من الشركات، بما في ذلك مايكروسوفت وأوبر ونتفليكس. ووفقًا لاستطلاع مطوري بايثون، ارتفعت نسبة استخدام FastAPI من 21% في عام 2021 إلى 29% في عام 2023. وبالنسبة لعلماء البيانات، يُعدّ FastAPI ثاني أكثر إطارات العمل شيوعًا، حيث يستخدمه 31% منهم.

في هذا الدرس سنتناول أساسيات FastAPI لعلماء البيانات الذين قد يرغبون في إنشاء نموذج أولي سريع لمشروعهم.

ما هو FastAPI؟

FastAPI هو إطار عمل ويب شائع لبناء واجهات برمجة التطبيقات (API) باستخدام بايثون، ويعتمد على تلميحات نوع بايثون القياسية. يتميز بسهولة الاستخدام وبديهية الاستخدام، ويُمكّنه من إنشاء تطبيق جاهز للإنتاج في وقت قصير. وهو متوافق تمامًا مع OpenAPI ومخطط JSON.

لماذا نستخدم FastAPI لتعلم الآلة؟

تتكون معظم الفرق العاملة على مشاريع تعلم الآلة من علماء بيانات متخصصين في الإحصاء. قد لا يمتلكون خبرة في تطوير البرامج أو التطبيقات اللازمة لمشاريع تعلم الآلة الخاصة بهم. يُمكّن FastAPI علماء البيانات من إنشاء واجهات برمجة تطبيقات بسهولة للمشاريع التالية:

نشر نماذج التنبؤ

ربما قام فريق علوم البيانات بتدريب نموذج للتنبؤ بطلب المبيعات في أحد المستودعات. ولجعله مفيدًا، عليهم توفير واجهة برمجة تطبيقات (API) لتمكين الأجزاء الأخرى من نظام إدارة المخزون من استخدام وظيفة التنبؤ الجديدة هذه.

محركات الاقتراح

من الاستخدامات الشائعة لتعلم الآلة كنظام يقدم اقتراحات بناءً على اختيارات المستخدمين. على سبيل المثال، إذا أضاف أحدهم منتجات معينة إلى سلة التسوق، يمكن اقتراح المزيد من المنتجات عليه. يتطلب نظام التجارة الإلكترونية هذا استدعاء واجهة برمجة تطبيقات (API) لمحرك الاقتراحات الذي يأخذ معلمات الإدخال.

لوحات معلومات ديناميكية وأنظمة إعداد التقارير

أحيانًا، قد تحتاج تقارير مشاريع علوم البيانات إلى عرضها كلوحات معلومات ليتمكن المستخدمون من الاطلاع على النتائج بأنفسهم. أحد الحلول الممكنة هو توفير واجهة برمجة تطبيقات (API) لنموذج البيانات. يمكن لمطوري واجهات المستخدم الأمامية استخدام هذه الواجهة لإنشاء تطبيقات تتيح للمستخدمين التفاعل مع البيانات.

مزايا استخدام FastAPI

مقارنةً بأطر عمل بايثون الأخرى للويب، يتميز FastAPI بالبساطة وفعاليته الكاملة. يعتمد بشكل أساسي على المزخرفات وتلميحات الأنواع، مما يسمح لك ببناء تطبيق ويب دون تعقيد بناء نموذج ORM (تعيين الكائنات والعلاقات) بالكامل، مع مرونة استخدام أي قاعدة بيانات، بما في ذلك قواعد بيانات SQL وNoSQL. كما يوفر FastAPI إنشاءً تلقائيًا للوثائق، ودعمًا للمعلومات الإضافية والتحقق من صحة معلمات الاستعلام، ودعمًا جيدًا للمزامنة غير المتزامنة.

التطور السريع

إنشاء استدعاءات واجهة برمجة التطبيقات (API) في FastAPI سهلٌ كإضافة مزخرفات في شيفرة بايثون. لا يتطلب أي شخص يرغب في تحويل دالة بايثون إلى تطبيق يستجيب لاستدعاءات واجهة برمجة التطبيقات (API) سوى خبرة ضئيلة أو معدومة في البرمجة الخلفية.

توثيق سريع

يوفر FastAPI توثيقًا تفاعليًا تلقائيًا لواجهة برمجة التطبيقات (API) باستخدام واجهة مستخدم Swagger، وهو معيار صناعي. لا يتطلب الأمر جهدًا إضافيًا لبناء توثيق واضح مع أمثلة لاستدعاءات واجهة برمجة التطبيقات. هذا يُتيح ميزة لفرق علوم البيانات المشغولة التي قد لا تمتلك الطاقة والخبرة الكافيتين لكتابة المواصفات الفنية والوثائق.

اختبار سهل

كتابة الاختبارات من أهم خطوات تطوير البرمجيات، ولكنها قد تكون أيضًا من أكثرها إرهاقًا، خاصةً عندما يكون وقت فريق علوم البيانات ثمينًا. بفضل Starlette وHTTPX، أصبح اختبار FastAPI سهلًا. في معظم الأحيان، لا حاجة إلى تعديلات بسيطة، وتكون كتابة الاختبارات وفهمها سهلة.

نشر سريع

يأتي FastAPI مزودًا بأداة سطر أوامر تربط التطوير والنشر بسلاسة. تتيح لك هذه الأداة التبديل بسهولة بين وضع التطوير ووضع الإنتاج. بعد اكتمال التطوير، يُمكن نشر الكود بسهولة باستخدام حاوية Docker مع صور مُعدّة مسبقًا بلغة بايثون.

كيفية استخدام FastAPI لمشروع لتعلم الآلة

في هذا المثال، سنحوّل نموذج تنبؤ بالتصنيف، يستخدم خوارزمية “أقرب الجيران” للتنبؤ بأنواع طيور البطريق المختلفة بناءً على طول منقارها وزعانفها، إلى تطبيق خلفي. سنوفر واجهة برمجة تطبيقات تأخذ معلمات من معلمات استعلام عنوان URL وتُعيد التنبؤ. يوضح هذا كيف يُمكن لأي عالم بيانات، دون خبرة في تطوير التطبيقات الخلفية، إنشاء نموذج أولي بسرعة.

سنستخدم مُصنِّف “KNeighborsClassifier” البسيط على مجموعة بيانات البطريق كمثال. لن نتطرق إلى تفاصيل كيفية بناء النموذج، ولكن لا تتردد في الاطلاع على دفتر الملاحظات ذي الصلة هنا. في الدرس التالي، سنركز على استخدام FastAPI وشرح بعض المفاهيم الأساسية. سنبني نموذجًا أوليًا للقيام بذلك.

ابدأ مشروع FastAPI باستخدام PyCharm

في هذه التدوينة، سنستخدم PyCharm Professional 2024.1. أفضل طريقة لبدء استخدام FastAPI هي إنشاء مشروع FastAPI باستخدام PyCharm. عند النقر على “مشروع جديد” في PyCharm، ستظهر لك مجموعة واسعة من المشاريع للاختيار من بينها. اختر علامة التبويب FastAPI.

إنشاء مشروع FastAPI باستخدام PyCharm

من هنا، يمكنك إدخال اسم مشروعك والاستفادة من خيارات أخرى مثل تهيئة Git والبيئة الافتراضية التي تريد استخدامها.

بعد القيام بذلك، سوف ترى الهيكل الأساسي لمشروع FastAPI تم إعداده لك.

هناك أيضًا ملف test_main.http تم إعداده لك لاختبار جميع نقاط النهاية بسرعة.

إعداد تبعيات البيئة

بعد ذلك، قم بإعداد تبعية بيئتنا باستخدام requirements.txt عن طريق تحديد Sync Python Requirements ضمن قائمة أدوات PyCarm.

يمكنك بعد ذلك تحديد الملف requirements.txt الذي تريد استخدامه.

يمكنك نسخ ملف requirements.txt واستخدامه. سنستخدم pandas وscikit-learn لجزء تعلم الآلة من المشروع. أضف أيضًا ملف penguins.csv إلى مجلد مشروعك.

قم بإعداد نموذج تعلم الآلة الخاص بك

رتّب شيفرة تعلّم الآلة في ملف main.py. سنبدأ بنص برمجي لتدريب نموذجنا:

import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn import preprocessing
from sklearn.neighbors import KNeighborsClassifier
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler

data = pd.read_csv('penguins.csv')
data = data.dropna()

le = preprocessing.LabelEncoder()
X = data[["bill_length_mm", "flipper_length_mm"]]
le.fit(data["species"])
y = le.transform(data["species"])
X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y, random_state=0)
clf = Pipeline(
    steps=[("scaler", StandardScaler()), ("knn", KNeighborsClassifier(n_neighbors=11))]
)
clf.set_params().fit(X_train, y_train)

يمكننا وضع الكود أعلاه بعد app = FastAPI(). سيتم تنفيذه بالكامل عند بدء التطبيق.

مع ذلك، توجد طريقة أفضل لتشغيل شيفرة بدء التشغيل التي استخدمناها لإعداد نموذجنا. سنتناولها لاحقًا في هذه التدوينة.

اطلب الرد

سنتناول الآن كيفية إضافة نموذجنا إلى وظيفة FastAPI. كخطوة أولى، سنضيف استجابةً إلى جذر عنوان URL، وسنُعيد ببساطة رسالةً حول نموذجنا بصيغة JSON. غيّر الكود في async def root(): من “Hello world” إلى رسالتنا كما يلي:

@app.get("/")
async def root():
    return {
        "Name": "Penguins Prediction",
        "description": "This is a penguins prediction model based on the bill length and flipper length of the bird.",
    }

الآن، اختبر تطبيقنا. أولًا، سنبدأ تشغيله، وهو سهل الاستخدام في PyCharm. ما عليك سوى الضغط على زر السهم بجوار اسم مشروعك في الأعلى.

إذا كنت تستخدم الإعدادات الافتراضية، فسيعمل تطبيقك على http://127.0.0.1:8000. يمكنك التحقق من ذلك من خلال نافذة التشغيل.

بعد بدء العملية، انتقل إلى test_main.http واضغط على زر السهم الأول بجوار GET. من نافذة الخدمات، ستظهر لك رسالة الاستجابة التي أدخلناها.

يتم أيضًا حفظ ملف الاستجابة JSON للفحص في المستقبل.

طلب ​​مع معلمات الاستعلام

بعد ذلك، نود أن نسمح للمستخدمين بالتنبؤات من خلال توفير معلمات الاستعلام في عنوان URL. لنضف الكود التالي بعد دالة root.

@app.get("/predict/")
async def predict(bill_length_mm: float = 0.0, flipper_length_mm: float = 0.0):
    param = {
                "bill_length_mm": bill_length_mm,
                "flipper_length_mm": flipper_length_mm
            }
    if bill_length_mm <=0.0 or flipper_length_mm <=0.0:
        return {
            "parameters": param,
            "error message": "Invalid input values",
        }
    else:
        result = clf.predict([[bill_length_mm, flipper_length_mm]])
        return {
            "parameters": param,
            "result": le.inverse_transform(result)[0],
        }

هنا، نُعيّن القيمة الافتراضية لـ bill_length_mm وflipper_length_mm إلى 0 إذا لم يُدخل المستخدم قيمة. كما نضيف فحصًا للتحقق مما إذا كانت أيٌّ من القيمتين تساوي 0، ونُعيد رسالة خطأ بدلاً من محاولة التنبؤ بالبطريق الذي يُشير إليه المُدخل.

إذا لم تكن المدخلات تساوي 0، فسنستخدم النموذج للتنبؤ واستخدام المبرمج لإجراء تحويل عكسي للحصول على تسمية الهدف المتوقع، أي اسم نوع البطريق.

ليست هذه هي الطريقة الوحيدة للتحقق من المدخلات. يمكنك أيضًا استخدام Pydantic للتحقق من المدخلات.

إذا كنت تستخدم نفس إصدار FastAPI المذكور في ملف requirements.txt، فسيُحدّث FastAPI الخدمة تلقائيًا ويُطبّق التغييرات عند الحفظ. الآن، أدخل رابطًا جديدًا في test_main.http للاختبار (مفصولًا عن الرابط السابق بعلامة ###):

###

GET http://127.0.0.1:8000/predict/?bill_length_mm=40.3&flipper_length_mm=195
Accept: application/json

اضغط على زر السهم الموجود بجوار عنوان URL الجديد الخاص بنا وشاهد النتيجة.

بعد ذلك، يمكنك تجربة عنوان URL مع إزالة أحد المعلمتين أو كليهما لرؤية رسالة الخطأ:

###

GET http://127.0.0.1:8000/predict/?bill_length_mm=40.3
Accept: application/json

قم بإعداد نموذج تعلم الآلة مع أحداث العمر الافتراضي

أخيرًا، لنلقِ نظرة على كيفية إعداد نموذجنا باستخدام أحداث عمر FastAPI. ميزة ذلك هي ضمان عدم قبول أي طلب أثناء إعداد النموذج، ومسح الذاكرة المستخدمة لاحقًا. للقيام بذلك، سنستخدم asynccontextmanager. قبل app = FastAPI()، سنضيف:

from contextlib import asynccontextmanager

ml_models = {}

@asynccontextmanager
async def lifespan(app: FastAPI):
    # Set up the ML model here
    
    yield
    # Clean up the models and release resources


    ml_models.clear()

الآن سننقل استيراد pandas وscikit-learn إلى جانب عمليات الاستيراد الأخرى. سننقل أيضًا شيفرة الإعداد داخل دالة lifespan، مع ضبط نموذج تعلم الآلة وLabelEncoder داخل ml_models كما يلي:

from fastapi import FastAPI
from contextlib import asynccontextmanager

import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn import preprocessing
from sklearn.neighbors import KNeighborsClassifier
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler

ml_models = {}

@asynccontextmanager
async def lifespan(app: FastAPI):
    # Set up the ML model here

    data = pd.read_csv('penguins.csv')
    data = data.dropna()

    le = preprocessing.LabelEncoder()
    X = data[["bill_length_mm", "flipper_length_mm"]]
    le.fit(data["species"])
    y = le.transform(data["species"])
    X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y, random_state=0)
    clf = Pipeline(
        steps=[("scaler", StandardScaler()), ("knn", KNeighborsClassifier(n_neighbors=11))]
    )
    clf.set_params().fit(X_train, y_train)

    ml_models["clf"] = clf
    ml_models["le"] = le

    yield
    # Clean up the models and release resources

    ml_models.clear()

بعد ذلك سوف نضيف المعلمة lifespan=lifespan في app = FastAPI():

app = FastAPI(lifespan=lifespan)

الآن احفظ وجرّب مرة أخرى. كل شيء يعمل، وسنرى نفس النتيجة السابقة.

فكرة لاحقة: متى يتم تدريب النموذج؟

من مثالنا، قد تتساءل متى يتم تدريب النموذج. بما أن clf يُدرَّب في البداية، أي عند تشغيل الخدمة، فقد تتساءل لماذا لا ندرِّب النموذج في كل مرة يُقدِّم فيها شخص ما تنبؤًا.

لا نريد تدريب النموذج في كل مرة يُجري فيها شخص ما مكالمة، لأن إعادة تدريب كل شيء تتطلب موارد أكثر بكثير. بالإضافة إلى ذلك، قد يُسبب ذلك حالات تعارض نظرًا لأن تطبيق FastAPI يعمل بالتزامن. هذا ينطبق بشكل خاص إذا كنا نستخدم بيانات مباشرة تتغير باستمرار.

من الناحية الفنية، يمكننا إعداد واجهة برمجة تطبيقات لجمع البيانات وإعادة تدريب النموذج (سنوضح ذلك في المثال التالي). ومن الخيارات الأخرى جدولة إعادة التدريب في وقت محدد عند جمع كمية معينة من البيانات الجديدة، أو السماح لمستخدم رئيسي بتحميل بيانات جديدة وتفعيل إعادة التدريب.

حتى الآن، نهدف إلى بناء نموذج أولي يعمل محليًا. للمزيد من المعلومات، يُرجى الاطلاع على هذه المقالة حول نشر مشروع FastAPI على خدمة سحابية.

ما هو التزامن؟

ببساطة، يشبه التزامن الطهي في المطبخ، وبينما تنتظر غليان الماء، تقوم بتقطيع الخضراوات. في عالم خدمات الويب، يتواصل الخادم مع العديد من الأجهزة الطرفية، ويكون الاتصال بين الخادم والأجهزة الطرفية أبطأ من معظم التطبيقات الداخلية، لذا لن يتواصل الخادم مع الأجهزة الطرفية ويخدمها واحدة تلو الأخرى. بل سيتواصل مع العديد منها ويخدمها في الوقت نفسه أثناء تلبية طلباتها. قد ترغب في الاطلاع على هذا الشرح في وثائق FastAPI.

في بايثون، يتحقق ذلك باستخدام شيفرة غير متزامنة. في شيفرة FastAPI الخاصة بنا، يُعد استخدام async def بدلاً من def دليلاً واضحاً على أن FastAPI يعمل بشكل متزامن. هناك كلمات مفتاحية أخرى مستخدمة في شيفرة بايثون غير المتزامنة، مثل await وasyncio.get_event_loop، لكننا لن نتمكن من تغطيتها في هذه التدوينة.

كيفية استخدام FastAPI لمشروع تصنيف الصور

لاكتشاف المزيد من وظائف FastAPI، سنضيف نموذج تصنيف صور قائم على مثال MNIST في Keras إلى تطبيقنا أيضًا (نستخدم واجهة TensorFlow الخلفية). إذا ثبّت ملف requirements.txt المُرفق، فيجب أن يكون Keras وPillow مُثبّتين لديك لمعالجة الصور وبناء شبكة عصبية ملتوية (CNN).

إعادة الهيكلة

قبل أن نبدأ، لنُعِد هيكلة الكود. لجعل الكود أكثر تنظيمًا، سنضع إعداد النموذج لتوقعات البطاريق في دالة:

def penguins_pipeline():
    data = pd.read_csv('penguins.csv')
    data = data.dropna()

    le = preprocessing.LabelEncoder()
    X = data[["bill_length_mm", "flipper_length_mm"]]
    le.fit(data["species"])
    y = le.transform(data["species"])
    X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y, random_state=0)
    clf = Pipeline(
        steps=[("scaler", StandardScaler()), ("knn", KNeighborsClassifier(n_neighbors=11))]
    )
    clf.set_params().fit(X_train, y_train)

    return clf, le

ثم نعيد كتابة دالة العمر الافتراضي. مع إكمال سطر الكود بالكامل في PyCharm، يصبح الأمر سهلاً للغاية:

إعداد نموذج CNN للتنبؤ بـ MNIST

بنفس الطريقة التي استخدمناها في نموذج التنبؤ بالبطريق، قمنا بإنشاء دالة للتنبؤ بـ MNIST (وسنقوم بتخزين المعلمات الوصفية عالميًا):

# MNIST model meta parameters
num_classes = 10
input_shape = (28, 28, 1)
batch_size = 128
epochs = 15

def mnist_pipeline():
    # Load the data and split it between train and test sets
    (x_train, y_train), _ = keras.datasets.mnist.load_data()

    # Scale images to the [0, 1] range
    x_train = x_train.astype("float32") / 255

    # Make sure images have shape (28, 28, 1)
    x_train = np.expand_dims(x_train, -1)

    # convert class vectors to binary class matrices
    y_train = keras.utils.to_categorical(y_train, num_classes)

    model = keras.Sequential(
        [
            keras.Input(shape=input_shape),
            layers.Conv2D(32, kernel_size=(3, 3), activation="relu"),
            layers.MaxPooling2D(pool_size=(2, 2)),
            layers.Conv2D(64, kernel_size=(3, 3), activation="relu"),
            layers.MaxPooling2D(pool_size=(2, 2)),
            layers.Flatten(),
            layers.Dropout(0.5),
            layers.Dense(num_classes, activation="softmax"),
        ]
    )

    model.compile(loss="categorical_crossentropy", optimizer="adam", metrics=["accuracy"])

    model.fit(x_train, y_train, batch_size=batch_size, epochs=epochs, validation_split=0.1)

    return model

ثم أضف إعداد النموذج في وظيفة عمر الخدمة:

ml_models["cnn"] = mnist_pipeline()

لاحظ أنه منذ إضافة هذه الميزة، في كل مرة تُجري فيها تغييرات على ملف main.py وتحفظه، سيتم تدريب النموذج مرة أخرى. قد يستغرق الأمر بعض الوقت. لذلك، في مرحلة التطوير، قد ترغب في استخدام نموذج وهمي لا يتطلب أي تدريب على الإطلاق، أو نموذج مُدرّب مسبقًا. بعد التدريب، سيكون نموذج CNN جاهزًا للاستخدام.

قم بإعداد نقطة نهاية POST لتحميل ملف صورة للتنبؤ

لإعداد نقطة نهاية تستقبل ملف التحميل، يتعين علينا استخدام UploadFile في FastAPI:

@app.post("/predict-image/")
async def predicct_upload_file(file: UploadFile):
    img = await file.read()
    
    # process image for prediction
    img = Image.open(BytesIO(img)).convert('L')
    img = np.array(img).astype("float32") / 255
    img = np.expand_dims(img, (0, -1))
    
    # predict the result
    result = ml_models["cnn"].predict(img).argmax(axis=-1)[0]
    return {"filename": file.filename,
            "result": str(result)}

يرجى ملاحظة أن هذه نقطة نهاية POST (حتى الآن قمنا بإعداد نقاط نهاية GET فقط).

لا تنسى استيراد UploadFile من fastapi:

from fastapi import FastAPI, UploadFile

و”Image” من Pillow. نستخدم أيضًا “BytesIO” من وحدة “io”:

from PIL import Image
from io import BytesIO

لاختبار ذلك باستخدام عميل HTTP الخاص بـ PyCharm مع ملف صورة اختبار، سنستخدم ترميز multipart/form-data. يمكنك الاطلاع على صيغة طلب HTTP هنا. هذا ما ستضعه في ملف test_in.http:

###

POST http://127.0.0.1:8000/predict-image/ HTTP/1.1
Content-Type: multipart/form-data; boundary=boundary

--boundary
Content-Disposition: form-data; name="file"; filename="test_img0.png"

< ./test_img0.png

--boundary–

أضف واجهة برمجة التطبيقات (API) لجمع البيانات وتحفيز إعادة التدريب

الآن، تأتي مرحلة إعادة التدريب. نُعِدّ نقطة نهاية POST كما هو موضح أعلاه لقبول ملف مضغوط يحتوي على صور وملصقات تدريب. بعد ذلك، تتم معالجة ملف zip وتجهيز بيانات التدريب. بعد ذلك، سنُلائم نموذج CNN مرة أخرى:

@app.post("/upload-images/")
async def retrain_upload_file(file: UploadFile):

    img_files = []
    labels_file = None
    train_img = None

    with ZipFile(BytesIO(await file.read()), 'r') as zfile:
        for fname in zfile.namelist():
            if fname[-4:] == '.txt' and fname[:2] != '__':
                labels_file = fname
            elif fname[-4:] == '.png':
                img_files.append(fname)

        if len(img_files) == 0:
            return {"error": "No training images (png files) found."}
        else:
            for fname in sorted(img_files):
                with zfile.open(fname) as img_file:
                    img = img_file.read()

                    # process image
                    img = Image.open(BytesIO(img)).convert('L')
                    img = np.array(img).astype("float32") / 255
                    img = np.expand_dims(img, (0, -1))

                    if train_img is None:
                        train_img = img
                    else:
                        train_img = np.vstack((train_img, img))

        if labels_file is None:
            return {"error": "No training labels file (txt file) found."}
        else:
            with zfile.open(labels_file) as labels:
                labels_data = labels.read()
                labels_data = labels_data.decode("utf-8").split()
                labels_data = np.array(labels_data).astype("int")
                labels_data = keras.utils.to_categorical(labels_data, num_classes)

    # retrain model
    ml_models["cnn"].fit(train_img, labels_data, batch_size=batch_size, epochs=epochs, validation_split=0.1)

    return {"message": "Model trained successfully."}

تذكر استيراد ZipFile:

from zipfile import ZipFile

إذا حاولنا الآن نقطة النهاية باستخدام ملف zip الذي يحتوي على 1000 صورة وعلامات إعادة تدريب، فستجد أن الاستجابة تستغرق بعض الوقت، حيث يستغرق التدريب بعض الوقت:

POST http://127.0.0.1:8000/upload-images/ HTTP/1.1
Content-Type: multipart/form-data; boundary=boundary

--boundary
Content-Disposition: form-data; name="file"; filename="training_data.zip"

< ./retrain_img.zip

--boundary--

تخيل أن ملفات zip تحتوي على بيانات تدريب أكثر، أو أنك تُعيد تدريب نموذج أكثر تعقيدًا. سيضطر المستخدم حينها للانتظار طويلًا، ويبدو أن الأمور لا تسير على ما يرام بالنسبة له.

إعادة تدريب النموذج باستخدام BackgroundTasks

هناك طريقة أفضل لإدارة إعادة التدريب، وهي معالجتها بعد استلام بيانات التدريب والتحقق من صحتها، ثم إرسال رد يفيد بإعادة تشغيل عملية إعادة التدريب وتدريب النموذج في “BackgroundTasks”. إليك كيفية القيام بذلك: أولًا، سنضيف “BackgroundTasks” إلى نقطة نهاية “upload-images”:

@app.post("/upload-image/")
async def retrain_upload_file(file: UploadFile, background_tasks: BackgroundTasks):
    ...

تذكر أن تقوم باستيراده من fastapi:

from fastapi import FastAPI, UploadFile, BackgroundTasks

بعد ذلك، سنضع ملاءمة النموذج في background_tasks:

# retrain model
    background_tasks.add_task(
        ml_models["cnn"].fit,
        train_img,
        labels_data,
        batch_size=batch_size,
        epochs=epochs,
        validation_split=0.1
    )

وسوف نقوم أيضًا بتحديث الرسالة في الرد:

return {"message": "Data received successfully, model training has started."}

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

في هذه المرحلة، يمكن إضافة المزيد من الوظائف، على سبيل المثال، خيار لإعلام المستخدم لاحقًا (على سبيل المثال عبر البريد الإلكتروني) عند انتهاء التدريب أو تتبع تقدم التدريب في لوحة معلومات عند إنشاء تطبيق كامل.

في هذه التدوينة، عرضنا عملية توفير واجهة برمجة تطبيقات بسيطة لنموذج تنبؤ مُدرّب مسبقًا. لمعرفة المزيد عن FastAPI، أنصحك بالاطلاع على وثائق FastAPI الرسمية. إذا كنت تختار بين أطر عمل مختلفة، فاستكشف أوجه اختلاف FastAPI عن Django.


اكتشاف المزيد من بايثون العربي

اشترك للحصول على أحدث التدوينات المرسلة إلى بريدك الإلكتروني.

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *

Scroll to Top

اكتشاف المزيد من بايثون العربي

اشترك الآن للاستمرار في القراءة والحصول على حق الوصول إلى الأرشيف الكامل.

Continue reading