Meet YOLO26: next-gen vision AI.

Link to this sectionПотокобезопасный инференс с моделями YOLO#

To run Ultralytics YOLO inference safely across Python threads, instantiate a separate YOLO model inside each thread instead of sharing one instance across them. Sharing a single model causes race conditions that corrupt its internal state and produce unpredictable results, because Python's threading module runs the threads concurrently against the same object. This guide explains why sharing fails, shows the safe per-thread pattern, and covers the ThreadingLocked decorator for cases where you must share an instance.

Перейти к разделу: почему совместное использование модели приводит к ошибкам, потокобезопасный шаблон или декоратор ThreadingLocked.



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

Link to this sectionПонимание многопоточности в Python#

Потоки в Python — это форма параллелизма, позволяющая программе выполнять несколько операций одновременно. Однако из-за глобальной блокировки интерпретатора (GIL) в Python только один поток может выполнять байт-код Python в конкретный момент времени.

Single-thread vs multi-thread inference

Хотя это звучит как ограничение, потоки все равно могут обеспечить параллельное выполнение, особенно для операций, связанных с вводом-выводом (I/O), или при использовании операций, которые освобождают GIL, подобных тем, что выполняются базовыми C-библиотеками YOLO.

Link to this sectionОпасность совместного использования экземпляров моделей#

Создание экземпляра модели YOLO вне потоков и его совместное использование несколькими потоками может привести к состоянию гонки (race condition), при котором внутреннее состояние модели будет изменяться несогласованно из-за одновременного доступа. Это особенно проблематично, если модель или ее компоненты хранят состояние, не предназначенное для потокобезопасной работы.

Link to this sectionПример отсутствия потокобезопасности: один экземпляр модели#

При использовании потоков в 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 может быть вызван одновременно из нескольких потоков.

Link to this sectionБезопасный пример: отдельный экземпляр для каждого потока#

Использовать несколько отдельных экземпляров модели можно до тех пор, пока каждый поток владеет своим экземпляром и не передает его другому. Не имеет значения, что экземпляры ниже создаются до запуска потоков — единственный небезопасный шаблон — это использование одного экземпляра во всех потоках:

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

Поскольку каждый поток работает со своим выделенным экземпляром, нет общего состояния модели, которое потоки могли бы повредить. Создание экземпляра модели внутри каждого потока, как показано далее, — это самый простой способ гарантировать, что экземпляр никогда не будет случайно использован совместно.

Link to this sectionПотокобезопасный инференс#

Для выполнения потокобезопасного инференса следует создавать отдельный экземпляр модели YOLO внутри каждого потока. Это гарантирует, что каждый поток имеет свой изолированный экземпляр модели, устраняя риск возникновения состояний гонки.

Link to this sectionПример потокобезопасности#

Вот как создать экземпляр модели 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. Это предотвращает вмешательство одного потока в состояние модели другого, тем самым обеспечивая безопасное выполнение инференса каждым потоком без непредвиденного взаимодействия с другими потоками.

Link to this sectionИспользование декоратора ThreadingLocked#

Ultralytics предоставляет декоратор ThreadingLocked, который можно использовать для обеспечения потокобезопасного выполнения функций. Этот декоратор использует блокировку (lock), чтобы гарантировать, что в один момент времени декорированную функцию может выполнять только один поток.

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 особенно полезен, когда тебе нужно использовать экземпляр модели в разных потоках, но при этом необходимо обеспечить доступ к нему только для одного потока за раз.

Компромисс между памятью и параллелизмом

Использование одного заблокированного экземпляра модели экономит память по сравнению с загрузкой модели в каждом потоке, но снижает уровень параллелизма, так как потоки выстраиваются в очередь на блокировку и ждут своей очереди. Отдавай предпочтение шаблону «отдельный экземпляр на поток», если у тебя достаточно памяти и ты хочешь добиться максимальной параллелизации, и используй ThreadingLocked, когда объем памяти для моделей является критическим ограничением.

Link to this sectionЗаключение#

При работе с моделями YOLO через threading в Python выделяй каждому потоку свой собственный экземпляр модели и никогда не используй один экземпляр совместно в разных потоках. Создание экземпляра модели внутри потока, который его использует, — это самый простой способ гарантировать это, избежать состояний гонки и сделать выполнение задач вывода надежным.

Для более сложных сценариев и дальнейшей оптимизации производительности многопоточного инференса рассмотри возможность использования параллелизма на основе процессов с помощью multiprocessing или применения очереди задач со специализированными рабочими процессами.

Link to this sectionFAQ#

Link to this sectionКак мне избежать состояний гонки при использовании моделей YOLO в многопоточной среде Python?#

Чтобы предотвратить состояния гонки при использовании моделей Ultralytics YOLO в многопоточной среде Python, создавай отдельный экземпляр модели 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.

Link to this sectionКаковы лучшие практики для запуска многопоточного инференса моделей YOLO в Python?#

Чтобы безопасно выполнять многопоточный инференс моделей YOLO в Python, следуй этим лучшим практикам:

  1. Создавай экземпляры моделей YOLO внутри каждого потока, а не используй один экземпляр модели совместно в разных потоках.
  2. Используй модуль multiprocessing в Python для параллельной обработки, чтобы избежать проблем, связанных с Global Interpreter Lock (GIL).
  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()

Для дополнительного контекста обратись к разделу Потокобезопасный инференс.

Link to this sectionПочему каждый поток должен иметь свой собственный экземпляр модели YOLO?#

Каждый поток должен иметь свой собственный экземпляр модели YOLO для предотвращения состояний гонки. Когда один экземпляр модели совместно используется несколькими потоками, одновременный доступ может привести к непредсказуемому поведению и изменению внутреннего состояния модели. Используя отдельные экземпляры, ты обеспечиваешь изоляцию потоков, делая многопоточные задачи надежными и безопасными.

Для получения подробных инструкций ознакомься с разделами Пример отсутствия потокобезопасности: один экземпляр модели и Пример потокобезопасности.

Link to this sectionКак глобальная блокировка интерпретатора (GIL) Python влияет на инференс моделей YOLO?#

Глобальная блокировка интерпретатора (GIL) в Python позволяет только одному потоку выполнять байт-код Python одновременно, что может ограничить производительность многопоточных задач, связанных с нагрузкой на CPU. Однако для операций, связанных с вводом-выводом, или процессов, использующих библиотеки, освобождающие GIL, такие как базовые C-библиотеки YOLO, ты все равно можешь достичь параллелизма. Для повышения производительности рассмотри возможность использования параллелизма на основе процессов с помощью модуля multiprocessing в Python.

Подробнее о многопоточности в Python см. в разделе Понимание многопоточности в Python.

Link to this sectionБезопаснее ли использовать параллелизм на основе процессов вместо многопоточности для инференса моделей YOLO?#

Да, использование модуля multiprocessing в Python безопаснее и часто эффективнее для параллельного запуска инференса моделей YOLO. Параллелизм на основе процессов создает отдельные пространства памяти, избегая глобальной блокировки интерпретатора (GIL) и снижая риск проблем с параллелизмом. Каждый процесс будет работать независимо, имея свой собственный экземпляр модели YOLO.

Для получения дополнительных сведений о параллелизме на основе процессов при использовании моделей YOLO обратись к странице Потокобезопасный инференс.

Комментарии