YOLO 모델을 사용한 스레드 안전 추론

멀티스레드 환경에서 YOLO 모델을 실행할 때는 스레드 안전성을 보장하기 위해 신중한 고려가 필요합니다. Python의 threading 모듈을 사용하면 여러 스레드를 동시에 실행할 수 있지만, 이러한 스레드 전반에서 YOLO 모델을 사용할 때는 주의해야 할 중요한 안전 문제가 있습니다. 이 페이지에서는 스레드 안전한 YOLO 모델 추론을 구현하는 방법을 안내합니다.



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

Python 스레딩 이해하기

Python 스레드는 프로그램이 여러 작업을 동시에 수행할 수 있게 하는 병렬 처리의 한 형태입니다. 하지만 Python의 전역 인터프리터 락(GIL)으로 인해 한 번에 하나의 스레드만 Python 바이트코드를 실행할 수 있습니다.

Single-thread vs multi-thread inference

이것이 제한 사항처럼 들릴 수 있지만, 스레드는 여전히 동시성을 제공할 수 있습니다. 특히 I/O 바운드 작업이나 YOLO의 기반이 되는 C 라이브러리에서 수행되는 것과 같이 GIL을 해제하는 작업을 사용할 때 유용합니다.

공유 모델 인스턴스의 위험성

스레드 외부에서 YOLO 모델을 인스턴스화하고 이 인스턴스를 여러 스레드에서 공유하면 경쟁 상태(race conditions)가 발생할 수 있으며, 동시 접근으로 인해 모델의 내부 상태가 일관되지 않게 수정될 수 있습니다. 이는 모델이나 구성 요소가 스레드 안전하게 설계되지 않은 상태를 유지할 때 특히 문제가 됩니다.

스레드 안전하지 않은 예시: 단일 모델 인스턴스

Python에서 스레드를 사용할 때는 동시성 문제를 일으킬 수 있는 패턴을 파악하는 것이 중요합니다. 다음은 피해야 할 사례입니다: 단일 YOLO 모델 인스턴스를 여러 스레드에서 공유하는 것.

# 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를 실행할 수 있어 예측 불가능한 결과가 발생할 수 있습니다.

스레드 안전하지 않은 예시: 다중 모델 인스턴스

마찬가지로, 여러 YOLO 모델 인스턴스를 사용하는 안전하지 않은 패턴은 다음과 같습니다:

# Unsafe: Sharing multiple model instances across threads can still lead to issues
from threading import Thread

from ultralytics import YOLO

# Instantiate multiple models outside the thread
shared_model_1 = YOLO("yolo26n_1.pt")
shared_model_2 = YOLO("yolo26n_2.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

# Starting threads with individual model instances
Thread(target=predict, args=(shared_model_1, "image1.jpg")).start()
Thread(target=predict, args=(shared_model_2, "image2.jpg")).start()

두 개의 별도 모델 인스턴스가 있더라도 동시성 문제의 위험은 여전히 존재합니다. YOLO의 내부 구현이 스레드 안전하지 않은 경우, 별도의 인스턴스를 사용하는 것만으로는 경쟁 상태를 방지하지 못할 수 있습니다. 특히 이러한 인스턴스가 스레드 로컬이 아닌 기초 리소스나 상태를 공유하는 경우 더욱 그렇습니다.

스레드 안전 추론 (Thread-Safe Inference)

스레드 안전한 추론을 수행하려면 각 스레드 내에서 별도의 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 인스턴스를 생성합니다. 이는 한 스레드가 다른 스레드의 모델 상태를 방해하는 것을 방지하여, 각 스레드가 다른 스레드와 예상치 못한 상호 작용 없이 안전하게 추론을 수행하도록 보장합니다.

Using ThreadingLocked Decorator

Ultralytics는 함수를 스레드 안전하게 실행할 수 있도록 하는 ThreadingLocked 데코레이터를 제공합니다. 이 데코레이터는 락을 사용하여 한 번에 하나의 스레드만 데코레이트된 함수를 실행할 수 있도록 보장합니다.

from ultralytics import YOLO
from ultralytics.utils import ThreadingLocked

# Create a model instance
model = YOLO("yolo26n.pt")

# Decorate the predict method 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 데코레이터는 스레드 간에 모델 인스턴스를 공유해야 하지만, 한 번에 하나의 스레드만 액세스할 수 있도록 보장해야 할 때 특히 유용합니다. 이 방식은 각 스레드마다 새로운 모델 인스턴스를 생성하는 것보다 메모리를 절약할 수 있지만, 스레드가 락이 해제되기를 기다려야 하므로 동시성이 감소할 수 있습니다.

결론

Python의 threading으로 YOLO 모델을 사용할 때는 항상 스레드 안전을 보장하기 위해 해당 모델을 사용할 스레드 내부에서 인스턴스화하십시오. 이러한 관행은 경쟁 상태를 방지하고 추론 작업이 안정적으로 실행되도록 합니다.

더 고급 시나리오와 멀티스레드 추론 성능을 최적화하려면 multiprocessing을 사용한 프로세스 기반 병렬 처리나 전용 워커 프로세스를 사용하는 작업 큐 활용을 고려하십시오.

FAQ

멀티스레드 Python 환경에서 YOLO 모델을 사용할 때 어떻게 경쟁 상태를 피할 수 있습니까?

멀티스레드 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()

스레드 안전성을 보장하는 방법에 대한 자세한 내용은 YOLO 모델을 사용한 스레드 안전 추론 페이지를 참조하십시오.

Python에서 멀티스레드 YOLO 모델 추론을 실행하기 위한 모범 사례는 무엇입니까?

Python에서 멀티스레드 YOLO 모델 추론을 안전하게 실행하려면 다음 모범 사례를 따르십시오:

  1. 단일 모델 인스턴스를 스레드 간에 공유하는 대신 각 스레드 내에서 YOLO 모델을 인스턴스화하십시오.
  2. Python의 multiprocessing 모듈을 사용하여 병렬 처리를 수행함으로써 전역 인터프리터 락(GIL)과 관련된 문제를 피하십시오.
  3. YOLO의 기반이 되는 C 라이브러리에서 수행되는 작업을 사용하여 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."""
    model = YOLO("yolo26n.pt")
    results = 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()

추가적인 맥락은 스레드 안전 추론 섹션을 참조하십시오.

왜 각 스레드는 자체 YOLO 모델 인스턴스를 가져야 합니까?

각 스레드는 경쟁 상태를 방지하기 위해 자체 YOLO 모델 인스턴스를 가져야 합니다. 단일 모델 인스턴스가 여러 스레드 간에 공유되면 동시 접근으로 인해 예측할 수 없는 동작과 모델 내부 상태의 변경이 발생할 수 있습니다. 별도의 인스턴스를 사용하면 스레드 격리가 보장되어 멀티스레드 작업이 안정적이고 안전해집니다.

자세한 가이드는 스레드 안전하지 않은 예시: 단일 모델 인스턴스스레드 안전한 예시 섹션을 확인하십시오.

Python의 전역 인터프리터 락(GIL)이 YOLO 모델 추론에 어떤 영향을 미칩니까?

Python의 전역 인터프리터 락(GIL)은 한 번에 하나의 스레드만 Python 바이트코드를 실행할 수 있게 하므로 CPU 바운드 멀티스레딩 작업의 성능을 제한할 수 있습니다. 하지만 I/O 바운드 작업이나 YOLO의 기반이 되는 C 라이브러리처럼 GIL을 해제하는 라이브러리를 사용하는 프로세스의 경우 여전히 동시성을 달성할 수 있습니다. 성능 향상을 위해 Python의 multiprocessing 모듈을 사용한 프로세스 기반 병렬 처리를 고려하십시오.

Python 스레딩에 대한 자세한 내용은 Python 스레딩 이해하기 섹션을 참조하십시오.

YOLO 모델 추론을 위해 스레딩 대신 프로세스 기반 병렬 처리를 사용하는 것이 더 안전합니까?

네, Python의 multiprocessing 모듈을 사용하는 것이 YOLO 모델 추론을 병렬로 실행할 때 더 안전하며 종종 더 효율적입니다. 프로세스 기반 병렬 처리는 별도의 메모리 공간을 생성하여 전역 인터프리터 락(GIL)을 피하고 동시성 문제의 위험을 줄입니다. 각 프로세스는 자체 YOLO 모델 인스턴스를 가지고 독립적으로 작동합니다.

YOLO 모델을 사용한 프로세스 기반 병렬 처리에 대한 자세한 내용은 스레드 안전 추론 페이지를 참조하십시오.

댓글