Ultralytics YOLO27:
Get Started

Thread-sichere Inferenz mit YOLO-Modellen#

Um Ultralytics YOLO-Inferenz sicher über Python-Threads hinweg auszuführen, erstelle in jedem Thread ein eigenes YOLO-Modell, statt eine Instanz gemeinsam zu verwenden. Die gemeinsame Verwendung eines einzelnen Modells führt zu Wettlaufsituationen, die seinen internen Zustand beschädigen und unvorhersehbare Ergebnisse verursachen, da das Python-Modul threading die Threads gleichzeitig auf dasselbe Objekt zugreifen lässt. Diese Anleitung erklärt, warum die gemeinsame Nutzung fehlschlägt, zeigt das sichere Muster mit einer Instanz pro Thread und behandelt den Dekorator ThreadingLocked für Fälle, in denen du eine Instanz gemeinsam verwenden musst.

Springe zu den Gründen, warum die gemeinsame Nutzung eines Modells fehlschlägt, zum thread-sicheren Muster oder zum ThreadingLocked-Dekorator.



Ansehen: So führst du threadsichere Inferenz mit Ultralytics YOLO-Modellen in Python aus | Multithreading 🚀

Python-Threading verstehen#

Python-Threads sind eine Form der Parallelverarbeitung, mit der dein Programm mehrere Vorgänge gleichzeitig ausführen kann. Allerdings sorgt Pythons Global Interpreter Lock (GIL) dafür, dass immer nur ein Thread gleichzeitig Python-Bytecode ausführen kann.

Single-thread vs multi-thread inference

Auch wenn das nach einer Einschränkung klingt, können Threads weiterhin gleichzeitige Verarbeitung ermöglichen, insbesondere bei E/A-gebundenen Vorgängen oder bei Vorgängen, die den GIL freigeben, wie etwa bei den zugrunde liegenden C-Bibliotheken von YOLO.

Die Gefahr gemeinsam genutzter Modellinstanzen#

Wenn du ein YOLO-Modell außerhalb deiner Threads instanziierst und diese Instanz in mehreren Threads gemeinsam verwendest, kann es zu Wettlaufsituationen kommen. Dabei wird der interne Zustand des Modells durch gleichzeitige Zugriffe uneinheitlich verändert. Besonders problematisch ist dies, wenn das Modell oder seine Komponenten Zustände enthalten, die nicht für die Thread-Sicherheit ausgelegt sind.

Nicht thread-sicheres Beispiel: einzelne Modellinstanz#

Bei der Verwendung von Threads in Python solltest du Muster erkennen, die zu Problemen bei der gleichzeitigen Verarbeitung führen können. Folgendes solltest du vermeiden: die gemeinsame Nutzung einer einzelnen YOLO26-Modellinstanz in mehreren Threads.

# Unsicher: Eine einzelne Modellinstanz wird von mehreren Threads gemeinsam verwendet
from threading import Thread

from ultralytics import YOLO

# Das Modell außerhalb des Threads instanziieren
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)
    # Ergebnisse verarbeiten

# Threads starten, die dieselbe Modellinstanz verwenden
Thread(target=predict, args=("image1.jpg",)).start()
Thread(target=predict, args=("image2.jpg",)).start()

Im obigen Beispiel wird shared_model von mehreren Threads verwendet. Das kann zu unvorhersehbaren Ergebnissen führen, weil predict gleichzeitig von mehreren Threads ausgeführt werden kann.

Sicheres Beispiel: eine eigene Instanz pro Thread#

Mehrere separate Modellinstanzen sind unproblematisch, solange jeder Thread seine eigene Instanz besitzt und sie niemals mit einem anderen Thread teilt. Es spielt keine Rolle, dass die folgenden Instanzen vor dem Start der Threads erstellt werden – unsicher ist nur, eine einzelne Instanz über mehrere Threads hinweg gemeinsam zu verwenden:

# Sicher: Jeder Thread verwendet eine eigene Modellinstanz
from threading import Thread

from ultralytics import YOLO

# Ein Modell pro Thread instanziieren
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)
    # Ergebnisse verarbeiten

# Jeder Thread verwendet eine separate, eigene Modellinstanz
Thread(target=predict, args=(model_1, "image1.jpg")).start()
Thread(target=predict, args=(model_2, "image2.jpg")).start()

Da jeder Thread mit seiner eigenen Instanz arbeitet, gibt es keinen gemeinsamen Modellzustand, den die Threads beschädigen könnten. Das Modell wie im nächsten Beispiel innerhalb jedes Threads zu instanziieren, ist einfach der leichteste Weg, um sicherzustellen, dass eine Instanz nicht versehentlich gemeinsam verwendet wird.

Threadsichere Inferenz#

Für eine thread-sichere Inferenz solltest du in jedem Thread ein eigenes YOLO-Modell instanziieren. So erhält jeder Thread eine isolierte Modellinstanz und das Risiko von Wettlaufsituationen entfällt.

Thread-sicheres Beispiel#

So instanziierst du für eine sichere parallele Inferenz in jedem Thread ein YOLO-Modell:

# Sicher: Eine einzelne Modellinstanz in jedem Thread instanziieren
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)
    # Ergebnisse verarbeiten

# Threads starten, die jeweils eine eigene Modellinstanz haben
Thread(target=thread_safe_predict, args=("image1.jpg",)).start()
Thread(target=thread_safe_predict, args=("image2.jpg",)).start()

In diesem Beispiel erstellt jeder Thread eine eigene YOLO-Instanz. Dadurch kann kein Thread den Modellzustand eines anderen Threads beeinflussen. So führt jeder Thread sicher Inferenz aus, ohne unerwartete Wechselwirkungen mit den anderen Threads.

Den ThreadingLocked-Dekorator verwenden#

Ultralytics stellt einen ThreadingLocked-Dekorator bereit, mit dem sich die thread-sichere Ausführung von Funktionen sicherstellen lässt. Der Dekorator verwendet eine Sperre, damit immer nur ein Thread gleichzeitig die dekorierte Funktion ausführen kann.

from ultralytics import YOLO
from ultralytics.utils import ThreadingLocked

# Eine Modellinstanz erstellen
model = YOLO("yolo26n.pt")

# Die Vorhersagefunktion dekorieren, damit sie thread-sicher ist
@ThreadingLocked()
def thread_safe_predict(image_path):
    """Thread-safe prediction using a shared model instance."""
    results = model.predict(image_path)
    return results

# Jetzt kannst du diese Funktion sicher aus mehreren Threads aufrufen

Der Dekorator ThreadingLocked ist besonders nützlich, wenn du eine Modellinstanz über mehrere Threads hinweg gemeinsam verwenden musst, aber sicherstellen möchtest, dass immer nur ein Thread gleichzeitig darauf zugreifen kann.

Abwägung zwischen Speicher und gleichzeitiger Verarbeitung

Wenn du eine einzelne, gesperrte Modellinstanz gemeinsam verwendest, sparst du Speicher, verglichen mit dem Laden eines Modells in jedem Thread. Gleichzeitig verringerst du die Parallelität, weil die Threads durch die Sperre nacheinander arbeiten und warten müssen, bis sie an der Reihe sind. Verwende das Muster mit einer Instanz pro Thread, wenn genügend Speicher vorhanden ist und du maximale Parallelität möchtest. Greife auf ThreadingLocked zurück, wenn der Modellspeicher zum Engpass wird.

Fazit#

Wenn du YOLO-Modelle mit Pythons threading verwendest, gib jedem Thread eine eigene Modellinstanz und verwende niemals dieselbe Instanz in mehreren Threads. Das Modell in dem Thread zu instanziieren, der es verwendet, ist der einfachste Weg, dies sicherzustellen. So vermeidest du Wettlaufsituationen und sorgst für zuverlässige Inferenzaufgaben.

Für anspruchsvollere Anwendungsfälle und zur weiteren Optimierung der Leistung deiner parallelen Inferenz kannst du die prozessbasierte Parallelverarbeitung mit multiprocessing oder eine Aufgabenwarteschlange mit eigenen Worker-Prozessen nutzen.

Häufig gestellte Fragen#

  • Um Wettlaufsituationen bei der Verwendung von Ultralytics-YOLO-Modellen in einer mehrthreadigen Python-Umgebung zu verhindern, instanziiere in jedem Thread ein eigenes YOLO-Modell. So erhält jeder Thread eine isolierte Modellinstanz und gleichzeitige Änderungen am Modellzustand werden vermieden.

    Beispiel:

    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)
        # Ergebnisse verarbeiten
    
    Thread(target=thread_safe_predict, args=("image1.jpg",)).start()
    Thread(target=thread_safe_predict, args=("image2.jpg",)).start()

    Weitere Informationen zur Gewährleistung der Thread-Sicherheit findest du unter Thread-sichere Inferenz mit YOLO-Modellen.

  • Beachte die folgenden Best Practices, um YOLO-Modellinferenz sicher mit mehreren Threads in Python auszuführen:

    1. Instanziiere YOLO-Modelle in jedem Thread, statt eine einzelne Modellinstanz über mehrere Threads hinweg gemeinsam zu verwenden.
    2. Verwende Pythons Modul multiprocessing für die parallele Verarbeitung, um Probleme im Zusammenhang mit dem Global Interpreter Lock (GIL) zu vermeiden.
    3. Beachte, dass die zugrunde liegenden C-Bibliotheken von YOLO (PyTorch, OpenCV) den GIL während rechenintensiver Vorgänge automatisch freigeben. Daher können Threads weiterhin gleichzeitig Inferenz ausführen.
    4. Wenn der Speicherverbrauch eine Rolle spielt, kannst du für gemeinsam genutzte Modellinstanzen den Dekorator ThreadingLocked verwenden.

    Beispiel für das threadsichere Instanziieren eines Modells:

    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)
        # Ergebnisse verarbeiten
    
    # Mehrere Threads starten
    Thread(target=thread_safe_predict, args=("image1.jpg",)).start()
    Thread(target=thread_safe_predict, args=("image2.jpg",)).start()

    Weitere Informationen findest du im Abschnitt Thread-sichere Inferenz.

  • Jeder Thread sollte eine eigene YOLO-Modellinstanz haben, um Wettlaufsituationen zu verhindern. Wird eine einzelne Modellinstanz von mehreren Threads gemeinsam verwendet, können gleichzeitige Zugriffe zu unvorhersehbarem Verhalten und Änderungen am internen Zustand des Modells führen. Separate Instanzen sorgen für eine Isolation der Threads und machen deine mehrthreadigen Aufgaben zuverlässig und sicher.

    Ausführliche Hinweise findest du in den Abschnitten Nicht thread-sicheres Beispiel: einzelne Modellinstanz und Thread-sicheres Beispiel.

  • Pythons Global Interpreter Lock (GIL) lässt immer nur einen Thread gleichzeitig Python-Bytecode ausführen. Das kann die Leistung mehrthreadiger, CPU-gebundener Aufgaben einschränken. Bei E/A-gebundenen Vorgängen oder Prozessen, die Bibliotheken verwenden, welche den GIL freigeben, wie etwa die zugrunde liegenden C-Bibliotheken von YOLO, ist jedoch weiterhin eine gleichzeitige Verarbeitung möglich. Für eine höhere Leistung kannst du die prozessbasierte Parallelverarbeitung mit Pythons Modul multiprocessing in Betracht ziehen.

    Weitere Informationen zu Threads in Python findest du im Abschnitt Python-Threading verstehen.

  • Ja, Pythons Modul multiprocessing ist sicherer und oft effizienter, wenn du Inferenz mit YOLO-Modellen parallel ausführen möchtest. Bei der prozessbasierten Parallelverarbeitung werden separate Speicherbereiche verwendet. Dadurch wird der Global Interpreter Lock (GIL) umgangen und das Risiko von Problemen bei der gleichzeitigen Verarbeitung verringert. Jeder Prozess arbeitet unabhängig mit einer eigenen YOLO-Modellinstanz.

    Weitere Informationen zur prozessbasierten Parallelverarbeitung mit YOLO-Modellen findest du auf der Seite Thread-sichere Inferenz.

Kommentare