الاستدلال الآمن خيطياً باستخدام نماذج YOLO

يتطلب تشغيل نماذج YOLO في بيئة متعددة الخيوط (multi-threaded) دراسة متأنية لضمان سلامة الخيوط. تسمح وحدة threading في Python بتشغيل عدة خيوط في وقت واحد، ولكن عند استخدام نماذج YOLO عبر هذه الخيوط، هناك مشكلات سلامة مهمة يجب الانتباه إليها. سترشدك هذه الصفحة خلال عملية إنشاء استدلال آمن خيطياً لنماذج YOLO.



Watch: How to Perform Thread Safe Inference with Ultralytics YOLO Models in Python | Multi-Threading 🚀

فهم تعدد الخيوط في Python

خيوط Python هي شكل من أشكال التوازي الذي يسمح لبرنامجك بتنفيذ عمليات متعددة في وقت واحد. ومع ذلك، يعني قفل المفسر العام (GIL) في Python أنه لا يمكن لخيط واحد فقط تنفيذ كود البايت (bytecode) الخاص بـ Python في كل مرة.

Single-thread vs multi-thread inference

على الرغم من أن هذا يبدو كقيد، إلا أن الخيوط لا تزال قادرة على توفير التزامن، خاصة للعمليات المعتمدة على الإدخال/الإخراج (I/O-bound) أو عند استخدام عمليات تحرر قفل المفسر العام (GIL)، مثل تلك التي تنفذها مكتبات C الأساسية في YOLO.

خطر مشاركة مثيلات النموذج

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

مثال غير آمن خيطياً: مثيل نموذج فردي

عند استخدام الخيوط في Python، من المهم التعرف على الأنماط التي يمكن أن تؤدي إلى مشكلات التزامن. إليك ما يجب تجنبه: مشاركة مثيل نموذج YOLO واحد عبر خيوط متعددة.

# Unsafe: Sharing a single model instance across threads
from threading import Thread

from ultralytics import YOLO

# Instantiate the model outside the thread
shared_model = YOLO("yolo26n.pt")

def predict(image_path):
    """Predicts objects in an image using a preloaded YOLO model, take path string to image as argument."""
    results = shared_model.predict(image_path)
    # Process results

# Starting threads that share the same model instance
Thread(target=predict, args=("image1.jpg",)).start()
Thread(target=predict, args=("image2.jpg",)).start()

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

مثال غير آمن خيطياً: مثيلات نماذج متعددة

وبالمثل، إليك نمط غير آمن باستخدام مثيلات نماذج YOLO متعددة:

# Unsafe: Sharing multiple model instances across threads can still lead to issues
from threading import Thread

from ultralytics import YOLO

# Instantiate multiple models outside the thread
shared_model_1 = YOLO("yolo26n_1.pt")
shared_model_2 = YOLO("yolo26n_2.pt")

def predict(model, image_path):
    """Runs prediction on an image using a specified YOLO model, returning the results."""
    results = model.predict(image_path)
    # Process results

# Starting threads with individual model instances
Thread(target=predict, args=(shared_model_1, "image1.jpg")).start()
Thread(target=predict, args=(shared_model_2, "image2.jpg")).start()

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

الاستدلال الآمن للخيوط (Thread-Safe Inference)

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

مثال آمن خيطياً

إليك كيفية إنشاء مثيل نموذج YOLO داخل كل خيط لإجراء استدلال متوازٍ آمن:

# Safe: Instantiating a single model inside each thread
from threading import Thread

from ultralytics import YOLO

def thread_safe_predict(image_path):
    """Predict on an image using a new YOLO model instance in a thread-safe manner; takes image path as input."""
    local_model = YOLO("yolo26n.pt")
    results = local_model.predict(image_path)
    # Process results

# Starting threads that each have their own model instance
Thread(target=thread_safe_predict, args=("image1.jpg",)).start()
Thread(target=thread_safe_predict, args=("image2.jpg",)).start()

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

استخدام مصمم ThreadingLocked

توفر Ultralytics مصمم ThreadingLocked الذي يمكن استخدامه لضمان تنفيذ الوظائف بشكل آمن خيطياً. يستخدم هذا المصمم قفلاً لضمان أن خيطاً واحداً فقط في كل مرة يمكنه تنفيذ الوظيفة المزخرفة.

from ultralytics import YOLO
from ultralytics.utils import ThreadingLocked

# Create a model instance
model = YOLO("yolo26n.pt")

# Decorate the predict method to make it thread-safe
@ThreadingLocked()
def thread_safe_predict(image_path):
    """Thread-safe prediction using a shared model instance."""
    results = model.predict(image_path)
    return results

# Now you can safely call this function from multiple threads

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

خاتمة

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

للحصول على سيناريوهات أكثر تقدماً ولزيادة تحسين أداء الاستدلال متعدد الخيوط، فكر في استخدام التوازي القائم على العمليات مع multiprocessing أو الاستفادة من طابور مهام مع عمليات عاملة مخصصة.

الأسئلة الشائعة

كيف يمكنني تجنب حالات التسابق عند استخدام نماذج YOLO في بيئة Python متعددة الخيوط؟

لمنع حالات التسابق عند استخدام نماذج Ultralytics YOLO في بيئة Python متعددة الخيوط، قم بإنشاء مثيل نموذج YOLO منفصل داخل كل خيط. وهذا يضمن أن لكل خيط مثيل نموذجه الخاص والمعزول، مما يتجنب التعديل المتزامن لحالة النموذج.

مثال:

from threading import Thread

from ultralytics import YOLO

def thread_safe_predict(image_path):
    """Predict on an image in a thread-safe manner."""
    local_model = YOLO("yolo26n.pt")
    results = local_model.predict(image_path)
    # Process results

Thread(target=thread_safe_predict, args=("image1.jpg",)).start()
Thread(target=thread_safe_predict, args=("image2.jpg",)).start()

لمزيد من المعلومات حول ضمان سلامة الخيوط، قم بزيارة الاستدلال الآمن خيطياً باستخدام نماذج YOLO.

ما هي أفضل الممارسات لتشغيل استدلال نموذج YOLO متعدد الخيوط في Python؟

لتشغيل استدلال نموذج YOLO متعدد الخيوط بأمان في Python، اتبع أفضل الممارسات التالية:

  1. قم بإنشاء مثيلات نماذج YOLO داخل كل خيط بدلاً من مشاركة مثيل نموذج واحد عبر الخيوط.
  2. استخدم وحدة multiprocessing في Python للمعالجة المتوازية لتجنب المشكلات المتعلقة بقفل المفسر العام (GIL).
  3. قم بتحرير قفل المفسر العام (GIL) باستخدام العمليات التي تنفذها مكتبات C الأساسية في YOLO.
  4. فكر في استخدام مصمم ThreadingLocked لمثيلات النماذج المشتركة عندما تكون الذاكرة مصدر قلق.

مثال لإنشاء مثيل نموذج آمن خيطياً:

from threading import Thread

from ultralytics import YOLO

def thread_safe_predict(image_path):
    """Runs inference in a thread-safe manner with a new YOLO model instance."""
    model = YOLO("yolo26n.pt")
    results = model.predict(image_path)
    # Process results

# Initiate multiple threads
Thread(target=thread_safe_predict, args=("image1.jpg",)).start()
Thread(target=thread_safe_predict, args=("image2.jpg",)).start()

لمزيد من السياق، راجع القسم الخاص بـ الاستدلال الآمن خيطياً.

لماذا يجب أن يكون لكل خيط مثيل نموذج YOLO الخاص به؟

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

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

كيف يؤثر قفل المفسر العام (GIL) في Python على استدلال نموذج YOLO؟

يسمح قفل المفسر العام (GIL) في Python لخيط واحد فقط بتنفيذ كود البايت (bytecode) الخاص بـ Python في كل مرة، مما قد يحد من أداء مهام تعدد الخيوط المعتمدة على المعالج (CPU-bound). ومع ذلك، بالنسبة للعمليات المعتمدة على الإدخال/الإخراج (I/O-bound) أو العمليات التي تستخدم مكتبات تحرر قفل المفسر العام (GIL)، مثل مكتبات C الأساسية في YOLO، لا يزال بإمكانك تحقيق التزامن. للحصول على أداء معزز، فكر في استخدام التوازي القائم على العمليات مع وحدة multiprocessing في Python.

لمزيد من المعلومات حول تعدد الخيوط في Python، راجع قسم فهم تعدد الخيوط في Python.

هل من الآمن استخدام التوازي القائم على العمليات بدلاً من تعدد الخيوط لاستدلال نموذج YOLO؟

نعم، استخدام وحدة multiprocessing في Python أكثر أماناً وغالباً ما يكون أكثر كفاءة لتشغيل استدلال نموذج YOLO بالتوازي. ينشئ التوازي القائم على العمليات مساحات ذاكرة منفصلة، مما يتجنب قفل المفسر العام (GIL) ويقلل من خطر حدوث مشكلات التزامن. ستعمل كل عملية بشكل مستقل مع مثيل نموذج YOLO الخاص بها.

لمزيد من التفاصيل حول التوازي القائم على العمليات مع نماذج YOLO، راجع الصفحة الخاصة بـ الاستدلال الآمن خيطياً.

التعليقات