Как ускорить YOLOv8n при многопоточном запуске: советы по повышению FPS

    Использование предобученной модели YOLOv8n для детекции объектов в реальном времени - популярная задача. Однако при стандартном запуске скорость может составлять около 30 кадров в секунду (FPS), а внедрение многопоточности не всегда даёт ожидаемый прирост. В этой статье разберём, почему потоковая обработка неэффективна и как действительно увеличить производительность детекции.

    Почему многопоточность не ускоряет YOLO?

    YOLO - это модель глубокого обучения, которая интенсивно использует GPU. Python-потоки (threading) работают в рамках GIL (Global Interpreter Lock), что ограничивает параллельное выполнение CPU-задач. Если детекция выполняется на GPU, потоки не дают выигрыша, так как GPU уже загружен одной задачей. В вашем коде поток detect постоянно вызывает модель, а основной поток читает кадры и рисует боксы - это приводит к гонке данных и блокировкам.

    Основные узкие места в коде

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

    • Глобальная переменная frame: поток детекции и основной поток одновременно обращаются к кадру без синхронизации, что вызывает задержки.
    • Бесконечный цикл детекции: поток detect работает без ожидания нового кадра, тратя ресурсы на повторную обработку одного и того же изображения.
    • Вызов time.sleep: задержки в 0.0017 и 0.025 секунды искусственно снижают FPS.
    • Отрисовка в основном потоке: операции cv2.rectangle и cv2.putText выполняются для каждого кадра, что добавляет нагрузку на CPU.

    Как увеличить FPS: практические шаги

    1. Используйте multiprocessing вместо threading

    Для обхода GIL применяйте модуль multiprocessing. Это позволит запустить детекцию в отдельном процессе, который сможет полноценно использовать GPU. Однако будьте осторожны с передачей данных между процессами - используйте очереди (Queue) или разделяемую память.

    2. Оптимизируйте размер входного кадра

    Уменьшите разрешение видео перед подачей в модель. YOLOv8n работает быстрее на меньших изображениях (например, 320x320 или 416x416). Используйте cv2.resize перед вызовом model(frame).

    3. Настройте параметры модели

    YOLOv8n поддерживает аргументы для ускорения: model(frame, half=True) - включение FP16 (половинной точности) на современных GPU, device='cuda' - явное указание GPU, conf=0.5 - повышение порога уверенности для уменьшения числа боксов.

    4. Используйте асинхронный захват кадров

    Захват видео через cv2.VideoCapture может быть медленным. Создайте отдельный процесс для чтения кадров с веб-камеры и складывайте их в очередь. Основной процесс будет брать последний кадр и детектировать, не ожидая захвата.

    5. Удалите лишние задержки и синхронизируйте потоки

    Уберите вызовы time.sleep и используйте блокировки (threading.Lock) для безопасного доступа к общим данным. Лучше реализовать паттерн «производитель-потребитель» с очередью.

    Пример оптимизированного подхода

    Вместо глобальной переменной frame создайте очередь cv2.Queue (или multiprocessing.Queue). Поток захвата кладёт кадры в очередь, поток детекции берёт оттуда последний кадр и обрабатывает. Результаты детекции передаются обратно в основной поток для отрисовки. Это минимизирует простои и повышает FPS до 50-60.

    Дополнительные советы

    Попробуйте использовать cv2.CAP_DSHOW для DirectShow на Windows, чтобы ускорить захват. Также отключите отрисовку, если она не нужна в реальном времени - записывайте результаты в буфер и рисуйте реже. Если модель загружается с Hugging Face, кэшируйте веса локально.

    Часто задаваемые вопросы