Inférence thread-safe avec les modèles YOLO
L'exécution de modèles YOLO dans un environnement multithread nécessite un examen attentif pour garantir la sécurité des threads. Python threading
module vous permet d'exécuter plusieurs threads simultanément, mais lorsqu'il s'agit d'utiliser les modèles YOLO dans ces threads, il y a d'importantes questions de sécurité à connaître. Cette page vous guidera dans la création d'une inférence de modèle YOLO thread-safe.
Regarder : Comment effectuer une inférence thread-safe avec les modèles Ultralytics YOLO en python | Multi-Threading 🚀
Comprendre le threading en python
Les threads Python sont une forme de parallélisme qui permet à votre programme d'exécuter plusieurs opérations simultanément. Cependant, le verrou global de l'interpréteur (GIL) de Python signifie qu'un seul thread peut exécuter du bytecode Python à la fois.
Bien que cela puisse ressembler à une limitation, les threads peuvent toujours fournir une concurrence, en particulier pour les opérations liées aux E/S ou lors de l'utilisation d'opérations qui libèrent le GIL, comme celles effectuées par les bibliothèques C sous-jacentes de YOLO.
Le danger des instances de modèle partagées
L'instanciation d'un modèle YOLO en dehors de vos threads et le partage de cette instance entre plusieurs threads peuvent entraîner des conditions de concurrence, où l'état interne du modèle est modifié de manière incohérente en raison d'accès simultanés. Ceci est particulièrement problématique lorsque le modèle ou ses composants contiennent un état qui n'est pas conçu pour être thread-safe.
Exemple non thread-safe : Instance de modèle unique
Lors de l'utilisation de threads en Python, il est important de reconnaître les schémas qui peuvent entraîner des problèmes de concurrence. Voici ce que vous devriez éviter : partager une seule instance de modèle YOLO entre plusieurs threads.
# 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("yolo11n.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()
Dans l'exemple ci-dessus, le shared_model
est utilisé par plusieurs threads, ce qui peut entraîner des résultats imprévisibles car predict
pourrait être exécuté simultanément par plusieurs threads.
Exemple non thread-safe : Instances de modèles multiples
De même, voici un schéma non sécurisé avec plusieurs instances de modèle 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("yolo11n_1.pt")
shared_model_2 = YOLO("yolo11n_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()
Même s'il existe deux instances de modèle distinctes, le risque de problèmes de concurrence existe toujours. Si l'implémentation interne de YOLO
n'est pas thread-safe, l'utilisation d'instances séparées peut ne pas empêcher les conditions de concurrence, surtout si ces instances partagent des ressources ou des états sous-jacents qui ne sont pas thread-local.
Inférence Thread-Safe
Pour effectuer une inférence thread-safe, vous devez instancier un modèle YOLO distinct dans chaque thread. Cela garantit que chaque thread possède sa propre instance de modèle isolée, éliminant ainsi le risque de conditions de concurrence.
Exemple de sécurité des threads
Voici comment instancier un modèle YOLO dans chaque thread pour une inférence parallèle sécurisée :
# 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("yolo11n.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()
Dans cet exemple, chaque thread crée son propre YOLO
instance. Cela empêche tout thread d'interférer avec l'état du modèle d'un autre, garantissant ainsi que chaque thread effectue l'inférence en toute sécurité et sans interactions inattendues avec les autres threads.
Utilisation du décorateur ThreadingLocked
Ultralytics fournit un ThreadingLocked
decorator qui peut être utilisé pour garantir l'exécution thread-safe des fonctions. Ce decorator utilise un verrou pour s'assurer qu'un seul thread à la fois peut exécuter la fonction décorée.
from ultralytics import YOLO
from ultralytics.utils import ThreadingLocked
# Create a model instance
model = YOLO("yolo11n.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
L'argument ThreadingLocked
decorator est particulièrement utile lorsque vous devez partager une instance de modèle entre plusieurs threads, mais que vous voulez vous assurer qu'un seul thread puisse y accéder à la fois. Cette approche peut économiser de la mémoire par rapport à la création d'une nouvelle instance de modèle pour chaque thread, mais elle peut réduire la concurrence car les threads devront attendre que le verrou soit libéré.
Conclusion
Lors de l'utilisation de modèles YOLO avec Python threading
, instanciez toujours vos modèles dans le thread qui les utilisera pour garantir la sécurité des threads. Cette pratique évite les conditions de concurrence et garantit que vos tâches d'inférence s'exécutent de manière fiable.
Pour des scénarios plus avancés et pour optimiser davantage les performances de votre inférence multithread, envisagez d'utiliser le parallélisme basé sur les processus avec multiprocessing ou en exploitant une file d'attente de tâches avec des processus de travail dédiés.
FAQ
Comment puis-je éviter les conditions de concurrence lors de l'utilisation de modèles YOLO dans un environnement Python multithread ?
Pour éviter les conditions de concurrence lors de l'utilisation des modèles Ultralytics YOLO dans un environnement Python multithread, instanciez un modèle YOLO distinct dans chaque thread. Cela garantit que chaque thread possède sa propre instance de modèle isolée, évitant ainsi la modification simultanée de l'état du modèle.
Exemple :
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("yolo11n.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()
Pour plus d'informations sur la garantie de la sécurité des threads, consultez la page Inférence Thread-Safe avec les modèles YOLO.
Quelles sont les meilleures pratiques pour exécuter l'inférence de modèles YOLO multithread en Python ?
Pour exécuter l’inférence du modèle YOLO multi-thread en toute sécurité dans python, suivez ces bonnes pratiques :
- Instanciez les modèles YOLO dans chaque thread plutôt que de partager une seule instance de modèle entre les threads.
- Utiliser les
multiprocessing
module pour le traitement parallèle afin d'éviter les problèmes liés au verrouillage global de l'interpréteur (GIL). - Libérez le GIL en utilisant les opérations effectuées par les bibliothèques C sous-jacentes de YOLO.
- Envisagez d'utiliser le
ThreadingLocked
decorator pour les instances de modèle partagées lorsque la mémoire est une préoccupation.
Exemple d'instanciation de modèle thread-safe :
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("yolo11n.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()
Pour plus de contexte, consultez la section sur l'Inférence Thread-Safe.
Pourquoi chaque thread devrait-il avoir sa propre instance de modèle YOLO ?
Chaque thread doit avoir sa propre instance de modèle YOLO pour éviter les conditions de concurrence. Lorsqu'une seule instance de modèle est partagée entre plusieurs threads, les accès simultanés peuvent entraîner un comportement imprévisible et des modifications de l'état interne du modèle. En utilisant des instances distinctes, vous assurez l'isolation des threads, ce qui rend vos tâches multi-thread fiables et sûres.
Pour des instructions détaillées, consultez les sections Exemple non thread-safe : Instance de modèle unique et Exemple thread-safe.
Comment le verrouillage global de l'interpréteur (GIL) de python affecte-t-il l'inférence du modèle YOLO ?
Le verrouillage global de l'interpréteur (GIL) de Python ne permet qu'à un seul thread d'exécuter le bytecode Python à la fois, ce qui peut limiter les performances des tâches multithread liées au CPU. Cependant, pour les opérations liées aux E/S ou les processus qui utilisent des bibliothèques libérant le GIL, comme les bibliothèques C sous-jacentes de YOLO, vous pouvez toujours obtenir de la concurrence. Pour des performances améliorées, envisagez d'utiliser le parallélisme basé sur les processus avec le module multiprocessing
module.
Pour en savoir plus sur le threading en Python, consultez la section Comprendre le threading en Python.
Est-il plus sûr d'utiliser le parallélisme basé sur les processus plutôt que le threading pour l'inférence du modèle YOLO ?
Oui, en utilisant multiprocessing
module est plus sûr et souvent plus efficace pour exécuter l'inférence du modèle YOLO en parallèle. Le parallélisme basé sur les processus crée des espaces mémoire distincts, évitant ainsi le verrouillage global de l'interpréteur (GIL) et réduisant le risque de problèmes de concurrence. Chaque processus fonctionnera indépendamment avec sa propre instance de modèle YOLO.
Pour plus de détails sur le parallélisme basé sur les processus avec les modèles YOLO, consultez la page sur l'Inférence Thread-Safe.