Ultralytics YOLO27:

Thread-sichere Inferenz mit YOLO-Modellen#

Um Ultralytics YOLO sicher auszuführen, erzeuge innerhalb jedes Python-Threads ein eigenes YOLO-Modell, anstatt eine Instanz threadübergreifend gemeinsam zu verwenden. Die gemeinsame Nutzung eines einzelnen Modells führt zu Race-Conditions, die seinen internen Zustand beschädigen und unvorhersehbare Ergebnisse erzeugen, weil Pythons Modul threading die Threads gleichzeitig auf demselben Objekt ausführt. Dieser Leitfaden erklärt, warum die gemeinsame Nutzung fehlschlägt, zeigt das sichere Muster mit einer Instanz pro Thread und behandelt den Decorator ThreadingLocked für Fälle, in denen du eine Instanz gemeinsam verwenden musst.

Springe zu warum die gemeinsame Nutzung eines Modells fehlschlägt, zum thread-sicheren Muster oder zum [Decorator ThreadingLocked].



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

Python-Threading verstehen#

Python-Threads sind eine Form der Parallelisierung, mit der dein Programm mehrere Vorgänge gleichzeitig ausführen kann. Pythons globale Interpretersperre (GIL) bedeutet jedoch, dass immer nur ein Thread Python-Bytecode ausführen kann.

Single-thread vs multi-thread inference

Auch wenn dies nach einer Einschränkung klingt, können Threads weiterhin Nebenläufigkeit ermöglichen, insbesondere bei E/A-gebundenen Vorgängen oder bei Vorgängen, die den GIL freigeben, etwa bei solchen, die von den zugrunde liegenden C-Bibliotheken von YOLO ausgeführt werden.

Die Gefahr gemeinsam genutzter Modellinstanzen#

Wenn du ein YOLO-Modell außerhalb deiner Threads erzeugst und diese Instanz von mehreren Threads gemeinsam verwendet wird, kann dies zu Race-Conditions führen. Dabei wird der interne Zustand des Modells durch gleichzeitige Zugriffe inkonsistent verändert. Das ist besonders problematisch, wenn das Modell oder seine Komponenten einen Zustand halten, der nicht für die Verwendung durch mehrere Threads ausgelegt ist.

Nicht thread-sicheres Beispiel: einzelne Modellinstanz#

Bei der Verwendung von Threads in Python ist es wichtig, Muster zu erkennen, die zu Problemen mit der Nebenläufigkeit führen können. Folgendes solltest du vermeiden: die gemeinsame Nutzung einer einzelnen YOLO26-Modellinstanz durch mehrere 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("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()

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

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 erzeugt werden – das einzige unsichere Muster ist die gemeinsame Nutzung einer Instanz durch mehrere Threads:

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

Da jeder Thread mit seiner eigenen Instanz arbeitet, gibt es keinen gemeinsamen Modellzustand, den die Threads beschädigen könnten. Das Modell innerhalb jedes Threads zu erzeugen, wie im Folgenden gezeigt, ist einfach die zuverlässigste Methode, um sicherzustellen, dass eine Instanz niemals versehentlich gemeinsam verwendet wird.

Thread-sichere Inferenz#

Um eine thread-sichere Inferenz durchzuführen, solltest du innerhalb jedes Threads ein eigenes YOLO-Modell erzeugen. Dadurch hat jeder Thread seine eigene isolierte Modellinstanz, wodurch das Risiko von Race-Conditions entfällt.

Thread-sicheres Beispiel#

So erzeugst du für eine sichere parallele Inferenz ein YOLO-Modell innerhalb jedes Threads:

# 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 diesem Beispiel erzeugt jeder Thread seine eigene YOLO-Instanz. Dadurch kann kein Thread den Modellzustand eines anderen Threads beeinflussen. Somit führt jeder Thread die Inferenz sicher und ohne unerwartete Wechselwirkungen mit den anderen Threads aus.

Verwendung des Decorators ThreadingLocked#

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

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

Der Decorator ThreadingLocked ist besonders nützlich, wenn du eine Modellinstanz von mehreren Threads gemeinsam verwenden musst, aber sicherstellen möchtest, dass immer nur ein Thread darauf zugreifen kann.

Abwägung zwischen Speicher und Nebenläufigkeit

Die gemeinsame Nutzung einer gesperrten Modellinstanz spart Speicher, verglichen mit dem Laden eines Modells in jedem Thread, verringert aber die Nebenläufigkeit, weil die Threads an der Sperre serialisiert werden und warten müssen, bis sie an der Reihe sind. Bevorzuge das Muster mit einer Instanz pro Thread, wenn du genügend Speicher zur Verfügung hast und maximale Parallelisierung möchtest, und verwende ThreadingLocked, wenn der Speicherbedarf des Modells der Engpass ist.

Fazit#

Bei der Verwendung von YOLO-Modellen mit Pythons threading solltest du jedem Thread eine eigene Modellinstanz zuweisen und niemals eine Instanz threadübergreifend gemeinsam verwenden. Das Modell innerhalb des Threads zu erzeugen, der es verwendet, ist die einfachste Methode, dies sicherzustellen, Race-Conditions zu vermeiden und deine Inferenzaufgaben zuverlässig auszuführen.

Für fortgeschrittenere Szenarien und zur weiteren Optimierung der Leistung deiner Inferenz mit mehreren Threads kannst du eine prozessbasierte Parallelisierung mit multiprocessing oder eine Aufgabenwarteschlange mit dedizierten Worker-Prozessen verwenden.

FAQ#

  • Um Race-Conditions bei der Verwendung von Ultralytics-YOLO-Modellen in einer Python-Umgebung mit mehreren Threads zu verhindern, erzeuge innerhalb jedes Threads ein eigenes YOLO-Modell. Dadurch hat jeder Thread seine eigene isolierte Modellinstanz, sodass gleichzeitige Änderungen am Modellzustand vermieden werden.

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

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

  • Befolge für die sichere Ausführung einer YOLO-Modellinferenz mit mehreren Threads in Python die folgenden bewährten Vorgehensweisen:

    1. Erzeuge YOLO-Modelle innerhalb jedes Threads, anstatt eine einzelne Modellinstanz threadübergreifend gemeinsam zu verwenden.
    2. Verwende für die parallele Verarbeitung Pythons Modul multiprocessing, um Probleme im Zusammenhang mit der globalen Interpretersperre (GIL) zu vermeiden.
    3. Beachte, dass die zugrunde liegenden C-Bibliotheken von YOLO (PyTorch, OpenCV) den GIL während rechenintensiver Vorgänge automatisch freigeben, sodass Threads weiterhin gleichzeitig Inferenz ausführen können.
    4. Ziehe bei gemeinsam verwendeten Modellinstanzen den Decorator ThreadingLocked in Betracht, wenn der Speicherbedarf eine Rolle spielt.

    Beispiel für die thread-sichere Erzeugung 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)
        # Process results
    
    # Initiate multiple threads
    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 Race-Conditions zu verhindern. Wenn eine einzelne Modellinstanz von mehreren Threads gemeinsam verwendet wird, können gleichzeitige Zugriffe zu unvorhersehbarem Verhalten und Änderungen am internen Zustand des Modells führen. Durch die Verwendung separater Instanzen stellst du die Isolation der Threads sicher, wodurch deine Aufgaben mit mehreren Threads zuverlässig und sicher ausgeführt werden.

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

  • Pythons globale Interpretersperre (GIL) erlaubt immer nur einem Thread, Python-Bytecode auszuführen, wodurch die Leistung von CPU-gebundenen Aufgaben mit mehreren Threads eingeschränkt werden kann. Bei E/A-gebundenen Vorgängen oder Prozessen, die Bibliotheken verwenden, die den GIL freigeben, etwa die zugrunde liegenden C-Bibliotheken von YOLO, kannst du jedoch weiterhin Nebenläufigkeit erreichen. Für eine höhere Leistung kannst du eine prozessbasierte Parallelisierung mit Pythons Modul multiprocessing in Betracht ziehen.

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

  • Ja, die Verwendung von Pythons Modul multiprocessing ist sicherer und für die parallele Ausführung einer YOLO-Modellinferenz oft effizienter. Die prozessbasierte Parallelisierung erzeugt separate Speicherbereiche, umgeht die globale Interpretersperre (GIL) und verringert das Risiko von Problemen mit der Nebenläufigkeit. Jeder Prozess arbeitet unabhängig mit seiner eigenen YOLO-Modellinstanz.

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

Kommentare