Ultralytics YOLO27:

الاستدلال الآمن من حيث الخيوط باستخدام نماذج YOLO#

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

انتقل إلى سبب فشل مشاركة نموذج، أو النمط الآمن للخيوط، أو مزخرف ThreadingLocked.



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

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

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

Single-thread vs multi-thread inference

رغم أن هذا يبدو قيدًا، فلا يزال بإمكان الخيوط توفير التزامن، ولا سيما في العمليات المقيدة بالإدخال والإخراج أو عند استخدام عمليات تحرر GIL، مثل العمليات التي تنفذها مكتبات YOLO الأساسية المكتوبة بلغة C.

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

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

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

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

# 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 قد يُنفَّذ بالتزامن بواسطة خيوط متعددة.

مثال آمن: مثيل مخصص لكل خيط#

لا مشكلة في استخدام مثيلات نماذج متعددة ومنفصلة ما دام كل خيط يملك مثيله ولا يشاركه مع خيط آخر. ولا يهم أن المثيلات أدناه أُنشئت قبل بدء الخيوط — فالنمط غير الآمن الوحيد هو مشاركة مثيل واحد بين الخيوط:

# Safe: each thread uses its own dedicated model instance
from threading import Thread

from ultralytics import YOLO

# Instantiate one model per thread
model_1 = YOLO("yolo26n.pt")
model_2 = YOLO("yolo26n.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

# Each thread uses a separate, dedicated model instance
Thread(target=predict, args=(model_1, "image1.jpg")).start()
Thread(target=predict, args=(model_2, "image2.jpg")).start()

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

الاستدلال الآمن من حيث الخيوط#

لإجراء استدلال آمن من حيث الخيوط، ينبغي إنشاء نموذج 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 prediction function 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 مفيدًا بشكل خاص عندما تحتاج إلى مشاركة مثيل نموذج بين الخيوط، مع الرغبة في ضمان وصول خيط واحد فقط إليه في كل مرة.

المفاضلة بين الذاكرة والتزامن

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

الخلاصة#

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

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

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

  • لمنع حالات التسابق عند استخدام نماذج 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، اتبع أفضل الممارسات التالية:

    1. أنشئ نماذج YOLO داخل كل خيط بدلًا من مشاركة مثيل نموذج واحد بين الخيوط.
    2. استخدم وحدة multiprocessing في Python للمعالجة المتوازية لتجنب المشكلات المتعلقة بقفل المفسر العام (GIL).
    3. تذكّر أن مكتبات YOLO الأساسية المكتوبة بلغة C (PyTorch وOpenCV) تحرر GIL تلقائيًا أثناء العمليات الحسابية المكثفة، لذا يمكن للخيوط مواصلة تنفيذ الاستدلال بالتزامن.
    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."""
        local_model = YOLO("yolo26n.pt")
        results = local_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 خاص به لمنع حالات التسابق. فعندما تتم مشاركة مثيل نموذج واحد بين خيوط متعددة، قد يؤدي الوصول المتزامن إلى سلوك غير متوقع وإلى تعديلات في الحالة الداخلية للنموذج. وباستخدام مثيلات منفصلة، تضمن عزل الخيوط، مما يجعل مهامك متعددة الخيوط موثوقة وآمنة.

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

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

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

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

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

التعليقات