الاستدلال الآمن خيطياً باستخدام نماذج YOLO#
لتشغيل Ultralytics YOLO inference بأمان عبر مسارات تنفيذ Python، قم بإنشاء نسخة مستقلة من نموذج YOLO داخل كل مسار تنفيذ بدلاً من مشاركة نسخة واحدة بينها. تؤدي مشاركة نموذج واحد إلى حدوث حالات تسابق (race conditions) تؤدي إلى تلف حالته الداخلية وإنتاج نتائج غير متوقعة، لأن وحدة threading في Python تشغل مسارات التنفيذ بالتزامن مع نفس الكائن. يوضح هذا الدليل سبب فشل مشاركة النماذج، ويوضح النمط الآمن لكل مسار تنفيذ، ويغطي مُزيّن ThreadingLocked للحالات التي يجب فيها مشاركة نسخة واحدة.
انتقل إلى سبب فشل مشاركة النموذج، أو النمط الآمن لخيوط المعالجة، أو مُزين ThreadingLocked.
Watch: How to Perform Thread Safe Inference with Ultralytics YOLO Models in Python | Multi-Threading 🚀
فهم خيوط المعالجة في Python#
خيوط المعالجة في Python هي شكل من أشكال التوازي الذي يسمح لبرنامجك بتنفيذ عمليات متعددة في وقت واحد. ومع ذلك، فإن قفل المفسر العام (GIL) في Python يعني أن خيطاً واحداً فقط يمكنه تنفيذ بايت كود Python في كل مرة.
على الرغم من أن هذا يبدو كقيد، إلا أن الخيوط لا تزال قادرة على توفير التزامن، خاصة للعمليات المرتبطة بـ I/O أو عند استخدام عمليات تقوم بتحرير GIL، مثل تلك التي تؤديها مكتبات C الأساسية في YOLO.
خطر مثيلات النماذج المشتركة#
إن إنشاء مثيل لنموذج YOLO خارج خيوط المعالجة ومشاركة هذا المثيل عبر خيوط متعددة يمكن أن يؤدي إلى ظروف سباق (race conditions)، حيث يتم تعديل الحالة الداخلية للنموذج بشكل غير متسق بسبب الوصول المتزامن. يمثل هذا مشكلة خاصة عندما يحتفظ النموذج أو مكوناته بحالة لم يتم تصميمها لتكون آمنة خيطياً.
مثال غير آمن خيطياً: مثيل نموذج واحد#
عند استخدام خيوط المعالجة في 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، اتبع أفضل الممارسات التالية:
- قم بإنشاء نماذج YOLO داخل كل خيط بدلاً من مشاركة مثيل نموذج واحد عبر الخيوط.
- استخدم وحدة
multiprocessingفي Python للمعالجة المتوازية لتجنب المشكلات المتعلقة بقفل المفسر العام (GIL). - تذكر أن مكتبات C الأساسية لـ YOLO (مثل PyTorch وOpenCV) تحرر قفل GIL تلقائياً أثناء الحسابات المكثفة، لذا يمكن للخيوط أن تظل قادرة على إجراء الاستنتاج بشكل متزامن.
- فكر في استخدام مُزين
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)، مثل مكتبات C الأساسية في YOLO، لا يزال بإمكانك تحقيق التزامن. للحصول على أداء محسّن، فكر في استخدام التوازي القائم على العمليات مع وحدة
multiprocessingفي Python.لمزيد من المعلومات حول خيوط المعالجة في Python، راجع قسم فهم خيوط المعالجة في Python.
نعم، استخدام وحدة
multiprocessingفي Python أُكثر أمانًا وغالبًا ما يكون أكثر كفاءة لتشغيل استدلال نموذج YOLO بالتوازي. ينشئ التوازي القائم على العمليات مساحات ذاكرة منفصلة، مما يتجنب قفل المفسر العام (GIL) ويقلل من مخاطر مشكلات التزامن. سيعمل كل عملية بشكل مستقل مع مثيل نموذج YOLO الخاص بها.لمزيد من التفاصيل حول التوازي القائم على العمليات مع نماذج YOLO، ارجع إلى الصفحة الخاصة بـ الاستدلال الآمن لخيوط المعالجة.