YOLO Vision 2026:

YOLO モデルによるスレッドセーフな推論#

Python スレッド間で Ultralytics YOLO 推論を安全に実行するには、複数のスレッド間で1つのインスタンスを共有するのではなく、各スレッド内に独立した YOLO モデルをインスタンス化してください。Python の threading モジュールは同じオブジェクトに対してスレッドを並行して実行するため、単一のモデルを共有すると内部状態が破損して予測不可能な結果を招く競合状態が発生します。このガイドでは、共有が失敗する理由、安全なスレッドごとのパターン、およびインスタンスを共有する必要があるケースに対応する ThreadingLocked デコレータについて説明します。

モデル共有が失敗する理由スレッドセーフなパターン、または ThreadingLocked デコレータへジャンプします。



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

Python スレッドの理解#

Python スレッドは、プログラムが複数の操作を同時に実行できるようにする並列処理の一形態です。しかし、Python のグローバルインタプリタロック(GIL)により、一度に実行できる Python バイトコードは 1 つのスレッドのみです。

Single-thread vs multi-thread inference

これは制限のように聞こえますが、スレッドは依然として並行性を提供します。特に I/O バウンドな操作や、YOLO の基盤となる C ライブラリによって実行される操作のように、GIL を解放する操作を使用する場合に有効です。

共有モデルインスタンスの危険性#

YOLO モデルをスレッドの外でインスタンス化し、そのインスタンスを複数のスレッド間で共有すると、レースコンディションが発生する可能性があります。これは、同時アクセスによってモデルの内部状態が矛盾した形で変更されるためです。モデルやそのコンポーネントがスレッドセーフではない状態を保持している場合、特に問題となります。

スレッドセーフではない例:単一モデルインスタンス#

Python でスレッドを使用する場合、並行処理の問題を引き起こす可能性のあるパターンを認識することが重要です。避けるべき事項は、単一の YOLO26 モデルインスタンスを複数のスレッド間で共有することです。

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

上記の例では、shared_model が複数のスレッドによって使用されており、predict が複数のスレッドによって同時に実行される可能性があるため、予測不可能な結果につながる恐れがあります。

安全な例:スレッドごとの専用インスタンス#

複数の個別のモデルインスタンスは、各スレッドが自身のインスタンスを所有し、他のスレッドと共有しない限り問題ありません。以下のインスタンスがスレッド開始前に作成されているかどうかは重要ではなく、唯一の安全でないパターンは1つのインスタンスをスレッド間で共有することです。

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

各スレッドは独自の専用インスタンスで動作するため、スレッドが壊すような共有モデル状態は存在しません。次に示すように、モデルを各スレッド内でインスタンス化することが、インスタンスが誤って共有されることを防ぐ最も簡単な方法です。

スレッドセーフな推論#

スレッドセーフな推論を行うには、各スレッド内で個別の YOLO モデルをインスタンス化する必要があります。これにより、各スレッドが独自の独立したモデルインスタンスを持つようになり、レースコンディションのリスクが排除されます。

スレッドセーフな例#

安全な並列推論のために、各スレッド内で YOLO モデルをインスタンス化する方法は以下の通りです。

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

この例では、各スレッドが独自の YOLO インスタンスを作成します。これにより、あるスレッドが他のスレッドのモデル状態に干渉するのを防ぎ、各スレッドが他のスレッドと予期せぬ干渉を起こすことなく安全に推論を実行できるようになります。

ThreadingLocked デコレータの使用#

Ultralytics は、関数のスレッドセーフな実行を保証するために使用できる ThreadingLocked デコレータを提供します。このデコレータはロックを使用して、一度に1つのスレッドのみがデコレートされた関数を実行できるようにします。

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

ThreadingLocked デコレータは、モデルインスタンスをスレッド間で共有する必要がありながら、一度に1つのスレッドだけがそれにアクセスできるようにしたい場合に特に便利です。

メモリと同時実行性のトレードオフ

ロックされた単一のモデルインスタンスを共有すると、すべてのスレッドでモデルをロードするのに比べてメモリを節約できますが、スレッドがロックで直列化され順番を待つため並行性が低下します。メモリに余裕があり最大の並列性を望む場合はスレッドごとのパターンを優先し、モデルメモリがボトルネックになる場合は ThreadingLocked を利用してください。

結論#

Python の threading で YOLO モデルを使用する場合、各スレッドに専用のモデルインスタンスを与え、1つのインスタンスをスレッド間で決して共有しないでください。使用するスレッド内でモデルをインスタンス化することがこれを保証する最も簡単な方法であり、競合状態を回避し、推論タスクを信頼性の高いものに保ちます。

より高度なシナリオや、マルチスレッド推論のパフォーマンスをさらに最適化するには、multiprocessing を使用したプロセスベースの並列処理の利用や、専用のワーカープロセスを持つタスクキューの活用を検討してください。

よくある質問 (FAQ)#

  • マルチスレッド Python 環境で Ultralytics YOLO モデルを使用する際にレースコンディションを防ぐには、各スレッド内で個別の YOLO モデルをインスタンス化してください。これにより、各スレッドが独自の独立したモデルインスタンスを持つことになり、モデル状態の同時変更を回避できます。

    例:

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

    スレッドセーフティの確保に関する詳細については、Thread-Safe Inference with YOLO Models をご覧ください。

  • Python でマルチスレッド YOLO モデル推論を安全に実行するには、以下のベストプラクティスに従ってください。

    1. 単一のモデルインスタンスをスレッド間で共有するのではなく、各スレッド内で YOLO モデルをインスタンス化してください。
    2. グローバルインタプリタロック (GIL) に関連する問題を回避するため、並列処理には Python の multiprocessing モジュールを使用してください。
    3. YOLOの基盤となるCライブラリ(PyTorch、OpenCV)は、負荷の高い計算中に自動的にGILを解放するため、スレッドは依然として並行して推論を実行できることに注意してください。
    4. メモリが懸念される場合は、共有モデルインスタンスに対して ThreadingLocked デコレータの使用を検討してください。

    スレッドセーフなモデルインスタンス化の例:

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

    追加のコンテキストについては、Thread-Safe Inference のセクションを参照してください。

  • 各スレッドが独自の YOLO モデルインスタンスを持つべきなのは、レースコンディションを防ぐためです。単一のモデルインスタンスが複数のスレッド間で共有されると、同時アクセスによって予測不能な動作やモデルの内部状態の変更が発生する可能性があります。別々のインスタンスを使用することでスレッドの分離が確保され、マルチスレッドタスクが信頼性の高い安全なものになります。

    詳細なガイダンスについては、Non-Thread-Safe Example: Single Model Instance および Thread-Safe Example のセクションを確認してください。

  • Python のグローバルインタプリタロック (GIL) は、一度に1つのスレッドしか Python バイトコードを実行できないようにするため、CPU 集中型のマルチスレッドタスクのパフォーマンスが制限される場合があります。ただし、I/O 集中型の操作や、YOLO の基盤となる C ライブラリのように GIL を解放するライブラリを使用するプロセスでは、引き続き並行性を達成できます。パフォーマンスを向上させるには、Python の multiprocessing モジュールを使用したプロセスベースの並列処理の利用を検討してください。

    Python のスレッド処理の詳細については、Understanding Python Threading セクションを参照してください。

  • はい、YOLO モデルの推論を並列実行するには、Python の multiprocessing モジュールを使用する方がより安全であり、多くの場合より効率的です。プロセスベースの並列処理は個別のメモリ空間を作成するため、グローバルインタプリタロック (GIL) を回避し、並行性の問題のリスクを軽減します。各プロセスは、独自の YOLO モデルインスタンスで独立して動作します。

    YOLO モデルを使用したプロセスベースの並列処理の詳細については、Thread-Safe Inference のページを参照してください。

コメント