YOLO Vision 2026:

Inferenza thread-safe con i modelli YOLO#

Per eseguire Ultralytics YOLO inference in modo sicuro tra diversi thread Python, istanzia un modello YOLO separato all'interno di ciascun thread anziché condividerne una sola istanza. La condivisione di un singolo modello causa condizioni di competizione (race conditions) che ne corrompono lo stato interno e producono risultati imprevedibili, poiché il modulo threading di Python esegue i thread contemporaneamente sullo stesso oggetto. Questa guida spiega perché la condivisione fallisce, mostra il pattern sicuro per thread e illustra il decoratore ThreadingLocked per i casi in cui devi necessariamente condividere un'istanza.

Passa a perché la condivisione di un modello fallisce, al pattern sicuro per thread o al decoratore ThreadingLocked.



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

Comprendere il threading in Python#

I thread di Python sono una forma di parallelismo che consente al tuo programma di eseguire più operazioni contemporaneamente. Tuttavia, il Global Interpreter Lock (GIL) di Python significa che solo un thread può eseguire il bytecode Python alla volta.

Single-thread vs multi-thread inference

Sebbene sembri una limitazione, i thread possono comunque fornire concorrenza, specialmente per operazioni I/O-bound o quando si utilizzano operazioni che rilasciano il GIL, come quelle eseguite dalle librerie C sottostanti di YOLO.

Il pericolo delle istanze di modello condivise#

Istanziare un modello YOLO al di fuori dei tuoi thread e condividere questa istanza tra più thread può portare a race condition, in cui lo stato interno del modello viene modificato in modo incoerente a causa di accessi simultanei. Questo è particolarmente problematico quando il modello o i suoi componenti mantengono uno stato non progettato per essere thread-safe.

Esempio non thread-safe: istanza di modello singola#

Quando usi i thread in Python, è importante riconoscere i pattern che possono portare a problemi di concorrenza. Ecco cosa dovresti evitare: condividere una singola istanza del modello YOLO26 tra più thread.

# 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()

Nell'esempio sopra, shared_model viene utilizzato da più thread, il che può portare a risultati imprevedibili perché predict potrebbe essere eseguito contemporaneamente da più thread.

Esempio sicuro: un'istanza dedicata per thread#

Più istanze del modello separate vanno bene finché ogni thread possiede la propria istanza e non la condivide mai con un altro thread. Non importa che le istanze qui sotto siano create prima dell'avvio dei thread: l'unico pattern non sicuro è condividere un'istanza tra i thread:

# 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()

Poiché ogni thread lavora con la propria istanza dedicata, non c'è alcuno stato del modello condiviso che i thread possano corrompere. Istanziare il modello all'interno di ogni thread, come mostrato di seguito, è semplicemente il modo più semplice per garantire che un'istanza non venga mai condivisa accidentalmente.

Inferenza thread-safe#

Per eseguire un'inferenza thread-safe, dovresti istanziare un modello YOLO separato all'interno di ogni thread. Questo garantisce che ogni thread abbia la propria istanza del modello isolata, eliminando il rischio di race condition.

Esempio thread-safe#

Ecco come istanziare un modello YOLO all'interno di ogni thread per un'inferenza parallela sicura:

# 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()

In questo esempio, ogni thread crea la propria istanza di YOLO. Questo impedisce a qualsiasi thread di interferire con lo stato del modello di un altro, garantendo così che ogni thread esegua l'inferenza in modo sicuro e senza interazioni impreviste con gli altri thread.

Utilizzo del decoratore ThreadingLocked#

Ultralytics fornisce un decoratore ThreadingLocked che può essere utilizzato per garantire l'esecuzione sicura per thread delle funzioni. Questo decoratore utilizza un blocco per assicurarsi che un solo thread alla volta possa eseguire la funzione decorata.

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

Il decoratore ThreadingLocked è particolarmente utile quando devi condividere un'istanza di modello tra i thread ma vuoi assicurarti che un solo thread possa accedervi alla volta.

Compromesso tra memoria e concorrenza

La condivisione di un'istanza di modello bloccata fa risparmiare memoria rispetto al caricamento di un modello in ogni thread, ma riduce la concorrenza poiché i thread si serializzano sul blocco e attendono il loro turno. Preferisci il pattern per thread quando hai memoria da risparmiare e desideri il massimo parallelismo, e ricorri a ThreadingLocked quando la memoria del modello è il collo di bottiglia.

Conclusione#

Quando usi i modelli YOLO con threading di Python, assegna a ogni thread la propria istanza di modello dedicata e non condividere mai un'istanza tra i thread. Istanziare il modello all'interno del thread che lo utilizza è il modo più semplice per garantirlo, evitando race condition e mantenendo affidabili le tue attività di inferenza.

Per scenari più avanzati e per ottimizzare ulteriormente le prestazioni di inferenza multithread, considera l'utilizzo del parallelismo basato su processi con multiprocessing o lo sfruttamento di una coda di attività con processi di lavoro dedicati.

FAQ#

Come posso evitare le race condition quando uso i modelli YOLO in un ambiente Python multi-thread?#

Per prevenire le race condition quando utilizzi i modelli YOLO di Ultralytics in un ambiente Python multi-thread, istanzia un modello YOLO separato all'interno di ogni thread. Questo garantisce che ogni thread abbia la propria istanza del modello isolata, evitando la modifica simultanea dello stato del modello.

Esempio:

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()

Per ulteriori informazioni su come garantire la sicurezza dei thread, visita la pagina Thread-Safe Inference with YOLO Models.

Quali sono le migliori pratiche per eseguire un'inferenza del modello YOLO multi-thread in Python?#

Per eseguire l'inferenza del modello YOLO multi-thread in modo sicuro in Python, segui queste migliori pratiche:

  1. Istanzia i modelli YOLO all'interno di ogni thread invece di condividere una singola istanza di modello tra i thread.
  2. Usa il modulo multiprocessing di Python per l'elaborazione parallela per evitare problemi correlati al Global Interpreter Lock (GIL).
  3. Ricorda che le librerie C sottostanti di YOLO (PyTorch, OpenCV) rilasciano automaticamente il GIL durante i calcoli intensivi, quindi i thread possono comunque eseguire l'inferenza contemporaneamente.
  4. Prendi in considerazione l'utilizzo del decoratore ThreadingLocked per istanze di modelli condivisi quando la memoria è un problema.

Esempio per l'istanziazione di modelli 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."""
    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()

Per ulteriore contesto, fai riferimento alla sezione su Thread-Safe Inference.

Perché ogni thread dovrebbe avere la propria istanza di modello YOLO?#

Ogni thread dovrebbe avere la propria istanza di modello YOLO per prevenire le race condition. Quando una singola istanza di modello viene condivisa tra più thread, gli accessi simultanei possono portare a comportamenti imprevedibili e modifiche dello stato interno del modello. Utilizzando istanze separate, garantisci l'isolamento dei thread, rendendo le tue attività multi-thread affidabili e sicure.

Per una guida dettagliata, controlla le sezioni Non-Thread-Safe Example: Single Model Instance e Thread-Safe Example.

In che modo il Global Interpreter Lock (GIL) di Python influisce sull'inferenza del modello YOLO?#

Il Global Interpreter Lock (GIL) di Python consente a un solo thread di eseguire bytecode Python alla volta, il che può limitare le prestazioni delle attività di multithreading vincolate alla CPU. Tuttavia, per operazioni di I/O o processi che utilizzano librerie che rilasciano il GIL, come le librerie C sottostanti di YOLO, puoi comunque ottenere concorrenza. Per prestazioni migliorate, considera l'utilizzo del parallelismo basato su processi con il modulo multiprocessing di Python.

Per saperne di più sul threading in Python, consulta la sezione Understanding Python Threading.

È più sicuro utilizzare il parallelismo basato su processi invece del threading per l'inferenza del modello YOLO?#

Sì, l'utilizzo del modulo multiprocessing di Python è più sicuro e spesso più efficiente per eseguire l'inferenza del modello YOLO in parallelo. Il parallelismo basato su processi crea spazi di memoria separati, evitando il Global Interpreter Lock (GIL) e riducendo il rischio di problemi di concorrenza. Ogni processo opererà in modo indipendente con la propria istanza di modello YOLO.

Per ulteriori dettagli sul parallelismo basato su processi con i modelli YOLO, fai riferimento alla pagina su Thread-Safe Inference.

Commenti