Ultralytics YOLO27:
Get Started

Inferenza thread-safe con i modelli YOLO#

Per eseguire inferenze di Ultralytics YOLO in sicurezza su più thread Python, crea un modello YOLO separato all’interno di ogni thread, invece di condividere un’unica istanza tra più thread. La condivisione di un singolo modello causa race condition che ne corrompono lo stato interno e producono risultati imprevedibili, perché il modulo threading di Python esegue i thread contemporaneamente sullo stesso oggetto. Questa guida spiega perché la condivisione non funziona, illustra il modello sicuro con un’istanza per thread e descrive il decoratore ThreadingLocked per i casi in cui devi condividere un’istanza.

Vai direttamente a perché la condivisione di un modello non funziona, al modello thread-safe o al decoratore ThreadingLocked.



Guarda: Come eseguire inferenze thread-safe con i modelli Ultralytics YOLO in Python | Multi-threading 🚀

Capire il threading in Python#

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

Single-thread vs multi-thread inference

Anche se può sembrare un limite, i thread possono comunque offrire concorrenza, soprattutto per le operazioni vincolate dall’I/O o quando si usano operazioni che rilasciano il GIL, come quelle eseguite dalle librerie C sottostanti di YOLO.

I rischi delle istanze di modello condivise#

Creare un modello YOLO al di fuori dei thread e condividerne l’istanza tra più thread può causare race condition, in cui lo stato interno del modello viene modificato in modo incoerente a causa degli accessi concorrenti. Questo è particolarmente problematico quando il modello o i suoi componenti mantengono uno stato che non è progettato per essere thread-safe.

Esempio non thread-safe: istanza di un singolo modello#

Quando usi i thread in Python, è importante riconoscere gli schemi che possono causare problemi di concorrenza. Ecco cosa devi evitare: condividere un’unica istanza del modello YOLO26 tra più thread.

# Non sicuro: condivisione di un’unica istanza del modello tra thread
from threading import Thread

from ultralytics import YOLO

# Crea il modello al di fuori del 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)
    # Elabora i risultati

# Avvio di thread che condividono la stessa istanza del modello
Thread(target=predict, args=("image1.jpg",)).start()
Thread(target=predict, args=("image2.jpg",)).start()

Nell’esempio precedente, più thread usano shared_model, il che può portare a risultati imprevedibili perché predict potrebbe essere eseguito simultaneamente da più thread.

Esempio sicuro: un’istanza dedicata per thread#

Puoi usare più istanze di modello separate, purché ogni thread possieda la propria istanza e non la condivida mai con un altro thread. Non importa che le istanze qui sotto vengano create prima dell’avvio dei thread: l’unico schema non sicuro consiste nel condividere un’istanza tra thread.

# Sicuro: ogni thread usa la propria istanza dedicata del modello
from threading import Thread

from ultralytics import YOLO

# Crea un modello per ogni 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)
    # Elabora i risultati

# Ogni thread usa un’istanza del modello separata e dedicata
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 esiste uno stato del modello condiviso che i thread possano corrompere. Creare il modello all’interno di ogni thread, come mostrato di seguito, è semplicemente il modo più facile per garantire che un’istanza non venga mai condivisa per errore.

Inferenza thread-safe#

Per eseguire inferenze thread-safe, devi creare un modello YOLO separato all’interno di ogni thread. In questo modo ogni thread ha un’istanza del modello isolata, eliminando il rischio di race condition.

Esempio thread-safe#

Ecco come creare un modello YOLO all’interno di ogni thread per eseguire inferenze parallele in sicurezza:

# Sicuro: creazione di un singolo modello all’interno di ogni 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)
    # Elabora i risultati

# Avvia thread, ciascuno con la propria istanza del modello
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 YOLO. In questo modo un thread non può interferire con lo stato del modello di un altro, garantendo che ogni thread esegua inferenze in sicurezza e senza interazioni impreviste con gli altri thread.

Uso del decoratore ThreadingLocked#

Ultralytics offre un decoratore ThreadingLocked che puoi usare per garantire l’esecuzione thread-safe delle funzioni. Questo decoratore usa un lock per fare in modo che un solo thread alla volta possa eseguire la funzione decorata.

from ultralytics import YOLO
from ultralytics.utils import ThreadingLocked

# Crea un’istanza del modello
model = YOLO("yolo26n.pt")

# Applica il decoratore alla funzione di previsione per renderla thread-safe
@ThreadingLocked()
def thread_safe_predict(image_path):
    """Thread-safe prediction using a shared model instance."""
    results = model.predict(image_path)
    return results

# Ora puoi chiamare questa funzione in sicurezza da più thread

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

Compromesso tra memoria e concorrenza

Condividere un’istanza del modello protetta da un lock fa risparmiare memoria rispetto a caricare un modello in ogni thread, ma riduce la concorrenza, perché i thread si accodano sul lock e aspettano il proprio turno. Preferisci il modello con un’istanza per thread se hai memoria a sufficienza e vuoi ottenere il massimo parallelismo; scegli ThreadingLocked quando la memoria del modello è il fattore limitante.

Conclusione#

Quando usi i modelli YOLO con threading di Python, assegna a ogni thread un’istanza dedicata del modello e non condividere mai la stessa istanza tra thread. Creare il modello all’interno del thread che lo usa è il modo più semplice per garantirlo, evitare race condition e mantenere affidabili le attività di inferenza.

Per scenari più avanzati e per ottimizzare ulteriormente le prestazioni dell’inferenza multithread, valuta il parallelismo basato sui processi con multiprocessing oppure usa una coda di attività con processi worker dedicati.

Domande frequenti#

  • Per evitare race condition quando usi i modelli Ultralytics YOLO in un ambiente Python multithread, crea un modello YOLO separato all’interno di ogni thread. In questo modo ogni thread ha un’istanza del modello isolata, evitando modifiche concorrenti allo 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)
        # Elabora i risultati
    
    Thread(target=thread_safe_predict, args=("image1.jpg",)).start()
    Thread(target=thread_safe_predict, args=("image2.jpg",)).start()

    Per maggiori informazioni su come garantire la sicurezza dei thread, consulta Inferenza thread-safe con i modelli YOLO.

  • Per eseguire inferenze multithread con i modelli YOLO in sicurezza in Python, segui queste best practice:

    1. Crea i modelli YOLO all’interno di ogni thread invece di condividere un’unica istanza del modello tra più thread.
    2. Usa il modulo multiprocessing di Python per l’elaborazione parallela, così da evitare i problemi legati al Global Interpreter Lock (GIL).
    3. Ricorda che le librerie C sottostanti di YOLO (PyTorch, OpenCV) rilasciano automaticamente il GIL durante i calcoli più intensivi, quindi i thread possono comunque eseguire inferenze contemporaneamente.
    4. Se la memoria è un problema, valuta l’uso del decoratore ThreadingLocked per le istanze di modello condivise.

    Esempio di creazione thread-safe del modello:

    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)
        # Elabora i risultati
    
    # Avvia più thread
    Thread(target=thread_safe_predict, args=("image1.jpg",)).start()
    Thread(target=thread_safe_predict, args=("image2.jpg",)).start()

    Per ulteriori informazioni, consulta la sezione Inferenza thread-safe.

  • Ogni thread dovrebbe avere una propria istanza del modello YOLO per evitare race condition. Quando una singola istanza del modello è condivisa tra più thread, gli accessi concorrenti possono causare comportamenti imprevedibili e modifiche allo stato interno del modello. Usando istanze separate, garantisci l’isolamento dei thread e rendi le tue attività multithread affidabili e sicure.

    Per istruzioni dettagliate, consulta le sezioni Esempio non thread-safe: istanza di un singolo modello ed Esempio thread-safe.

  • Il Global Interpreter Lock (GIL) di Python consente a un solo thread alla volta di eseguire bytecode Python, il che può limitare le prestazioni delle attività multithread vincolate dalla CPU. Tuttavia, puoi comunque ottenere concorrenza con operazioni vincolate dall’I/O o processi che usano librerie che rilasciano il GIL, come le librerie C sottostanti di YOLO. Per migliorare le prestazioni, valuta il parallelismo basato sui processi con il modulo multiprocessing di Python.

    Per saperne di più sul threading in Python, consulta la sezione Capire il threading in Python.

  • Sì, usare il modulo multiprocessing di Python è più sicuro e spesso più efficiente per eseguire inferenze parallele con i modelli YOLO. Il parallelismo basato sui processi crea spazi di memoria separati, evitando il Global Interpreter Lock (GIL) e riducendo il rischio di problemi di concorrenza. Ogni processo opera in modo indipendente con una propria istanza del modello YOLO.

    Per ulteriori dettagli sul parallelismo basato sui processi con i modelli YOLO, consulta la pagina Inferenza thread-safe.

Commenti