Всё началось с того, что на «Хабре» мне попалась статья о модели TAPe — Theory of Active Perception, или «теории активного восприятия». В статье были громкие заявления и интересные описания, но попробовать модель на практике не удалось.
Я собрал ключевые тезисы о TAPe и обратился к ChatGPT с запросом:
«Я студент и хочу в рамках дипломной работы реализовать модель, использующую подходы Theory of Active Perception. Она должна определять, где находятся игроки и какие действия они выполняют: подачу, приём, передачу или атаку».
Я также уточнил, что у меня есть видеозаписи, а для передачи временного контекста я хочу использовать клипы из девяти кадров.
Почему именно девять кадров? Ранее я уже модифицировал модель TrackNet для трекинга волейбольного мяча по девяти последовательным кадрам и решил придерживаться похожего подхода, чтобы сократить вычислительные затраты.
Первые итерации
Первая версия модели использовала query-based-подход для одновременного поиска игроков и мяча в видеоклипе.
Принцип работы
-
На вход модели подаётся фиксированный клип из девяти кадров в формате
[B, T, C, H, W]. Каждый кадр приводится к разрешению 512 × 288 пикселей. -
TinyBackboneизвлекает признаки на трёх уровнях пирамиды FPN: 1/4, 1/8 и 1/16 от исходного разрешения. -
Для поиска игроков используются 20 обучаемых query-слотов с начальными пространственными якорями. Декодер последовательно применяет:
-
self-attention между query;
-
cross-attention к визуальным признакам;
-
temporal attention между кадрами.
-
-
Для каждого query модель предсказывает:
-
класс объекта —
playerилиbackground; -
ограничивающий прямоугольник — bounding box;
-
embedding для сопоставления одного и того же игрока между кадрами.
-
-
Мяч обнаруживается отдельной grid-head. Для каждого кадра модель предсказывает карту уверенности и смещение объекта внутри наиболее вероятной ячейки.
-
После инференса применяются порог уверенности и NMS для боксов игроков. Для мяча выбирается ячейка с максимальным значением уверенности.
На словах всё выглядело красиво. Оставалось найти данные, обучить модель и проверить, насколько хорошо теория работает на практике.
На первом этапе я решил уменьшить аппетиты и сосредоточиться только на детекции игроков. План был следующим: сначала научиться надёжно находить игроков, затем расширить временной контекст и добавить распознавание действий.
Главная проблема обучения подобных моделей — наличие качественных размеченных датасетов.
Первые эксперименты я проводил на датасете по паделу, состоящем из двух двадцатиминутных видео с покадровой разметкой.
После первых запусков модель действительно научилась находить игроков в паделе, но точность оставалась недостаточной. Она часто предсказывала боксы в пустых областях кадра, где в текущий момент игрока не было. При этом с точки зрения статистики такие предсказания выглядели объяснимо: в этих областях игроки часто находились на соседних кадрах или в других эпизодах.
Я довольно долго обсуждал с ChatGPT возможные причины ложных детекций. И только спустя некоторое время случайно заметил, что на визуализации валидации рамки вообще не совпадают с положением игроков.
Причина оказалась в разметке. В одном из матчей был эпизод с крупным планом, но соответствующие кадры при аннотации пропустили. Из-за этого вся последующая разметка сдвинулась относительно видео. В результате почти половина датасета оказалась некорректной.
Датасет для пляжного волейбола
Почему именно пляжный волейбол? Сейчас лето, и мы регулярно играем на песке. Я записываю матчи, чтобы потом посмотреть на свою игру со стороны.
На площадке всего четыре человека, поэтому такие видео проще размечать. Кроме того, в будущем мне было бы интересно автоматически получать статистику собственных матчей: нарезку игровых эпизодов без пауз, количество касаний, длительность розыгрышей и другие показатели.
Для первичной разметки датасета я использовал крупную модель YOLO11l. Однако быстро выяснилось, что авторазметка моих видео требует ручной корректировки.
Особенно заметны ошибки во время атак и блоков. Когда игрок прыгает, модель иногда обрезает bounding box по голове или не включает в него поднятые руки атакующего и блокирующего.
В процессе работы над датасетом я также понял, что мои записи слишком однообразны: одна и та же площадка, похожее освещение и практически неизменная позиция камеры. Чтобы увеличить разнообразие данных, я добавил видео с играми профессиональных спортсменов.
Обратная связь от LLM
Итак, у нас есть датасет для экспериментов и сгенерированная архитектура модели, которую можно обучать.
В идеальном мире после этого мы получили бы работающий детектор. В реальности модель действительно что-то находит, но часто не там, где нужно. А иногда, наоборот, не находит игроков там, где они явно присутствуют.
Тогда мы берём результаты и пишем:
«Дорогой ChatGPT, посмотри, что за ерунда получилась…»
LLM отвечает:
«Ты совершенно прав: это предсказуемая ошибка, которая заложена в архитектуре твоей сети…»
После этого обычно следует уверенное объяснение того, какой именно блок модели работает неправильно, почему ошибка была неизбежна и что необходимо изменить в архитектуре.
После каждого изменения архитектуры модель нужно заново обучать на моём датасете из 21 000 кадров. Одна эпоха занимает 6–7 минут, а полный цикл обучения на RTX 3060 с 12 ГБ видеопамяти — около 8–10 часов.
После более чем двадцати итераций мы получили модель, которая почти работает. Она уже достаточно уверенно находит игроков, но остаются проблемы с «прыгающими» боксами и периодической потерей детекций на отдельных кадрах.

После каждой доработки или изменения архитектуры важно не забывать сохранять код в Git. Не все улучшения действительно делают модель лучше, поэтому всегда должна оставаться возможность откатиться к последней удачной версии.
Смена архитектуры
После множества «правильных исправлений», предложенных LLM, в модели постепенно накопилось большое количество костылей, дополнительных параметров и механизмов, подогнанных под детекцию игроков. При этом качество предсказаний почти не улучшалось.
В какой-то момент я решил не продолжать бесконечно дорабатывать текущую реализацию, а попросил LLM полностью переработать архитектуру и устранить обнаруженные узкие места.
Главный вывод из этого этапа: важно вовремя распознать тупиковое направление и перейти к новому эксперименту, вместо того чтобы продолжать усложнять неудачное решение.
|
Компонент |
Нулевая версия |
|
|---|---|---|
|
Входные данные |
Grayscale, 1 канал |
RGB, 3 канала по умолчанию |
|
Backbone |
|
|
|
Поиск игроков |
20 фиксированных обучаемых queries и пространственные anchors |
Динамические proposals из карты |
|
Работа с признаками |
Cross-attention между queries и всей evidence memory |
|
|
Временная связь |
Temporal self-attention внутри decoder |
Явный |
|
Уточнение боксов |
Общий query decoder и единая box head |
Несколько |
|
Дополнительные выходы |
Класс, bounding box и embedding |
Класс, bounding box, embedding, точки головы и ног, visibility, court points и association |
|
Версия архитектуры |
18 |
19 |
Первая архитектура уже работала на удовлетворительном уровне, но дальнейшие улучшения давались всё тяжелее и почти не влияли на качество. Поэтому новая версия стала не просто очередной правкой, а отдельным архитектурным экспериментом.

Схема рабочей модели REVEL‑VB

Запустить модель самостоятельно можно из репозитория:
RAVEL-VB Beach Volleyball Tracking
Модель состоит из двух независимых ветвей:
-
первая отвечает за детекцию игроков;
-
вторая — за поиск мяча и построена на базе
vballnet_grid_v1a.
Замеры производительности
В качестве отправной точки я запустил YOLO11n через OpenVINO и получил производительность 19,16 FPS.
На этом фоне результаты собственной модели выглядели вполне обнадёживающе:
-
на CPU использовался OpenVINO;
-
на GPU — PyTorch с CUDA.
|
Backend |
Модель |
Устройство |
Pipeline FPS |
|---|---|---|---|
|
OpenVINO |
|
CPU |
23,557 |
|
OpenVINO |
|
CPU |
12,745 |
|
PyTorch |
|
CUDA |
84,71 |
|
PyTorch |
|
CUDA |
84,40 |
Во время подготовки статьи я решил сравнить производительность и точность модели с дообученной YOLO26n. Результат оказался неожиданным: YOLO26n-VB в OpenVINO показала 43,87 FPS.
Кадры в моём датасете имеют разрешение 512 × 288 пикселей. Это позволило ускорить YOLO-модели по сравнению с запуском на стандартном входном разрешении 640 × 640.
Почти двукратное отставание заставило меня глубже разобраться в вопросе производительности. Модель, которая должна была стать «убийцей YOLO», сама оказалась заметно медленнее.
Профилирование модели
|
Этап |
Доля времени |
|---|---|
|
Backbone |
51,4% |
|
Ball grid |
27,0% |
|
Proposal head |
15,3% |
|
New query sampler |
1,6% |
|
Persistent queries |
1,5% |
|
Temporal linker |
0,7% |
|
Остальные операции |
≈1,1% |
Профилирование показало, что больше половины времени выполнения занимает backbone. Ещё 27% приходится на ветку поиска мяча, а 15,3% — на proposal head.
Главный вывод: в первую очередь необходимо ускорять backbone. Именно он является основным узким местом всей архитектуры.
Архитектурные оптимизации RAVEL-VB-002/003 относительно RAVEL-VB-001
В качестве базовой рассматривается стандартная конфигурация модели: входное разрешение 512 × 288 пикселей, ширина признакового пространства 128 каналов, 32 запроса и плотная генерация предложений на карте P4.
1. Уменьшение ширины признакового пространства
В RAVEL-VB-001 размер скрытого представления составляет 128 каналов, тогда как RAVEL-VB-002 и RAVEL-VB-003 по умолчанию используют 64 канала.
Сокращение ширины признакового пространства уменьшает количество вычислений и объём промежуточных данных, передаваемых между слоями модели.
2. C3k2/CSP-backbone вместо полноканальных блоков
Backbone в оптимизированных версиях построен на блоках C3k2, использующих CSP-подобное разделение потока признаков:
-
входные признаки проецируются в два потока уменьшенной ширины;
-
вычислительно дорогие свёртки выполняются только над одним из потоков;
-
промежуточные признаки объединяются;
-
итоговая карта формируется с помощью компактной проекции.
При коэффициенте расширения 0,5 основные свёртки работают примерно с половиной исходного числа каналов. Остаточные связи внутри блоков C3k при этом помогают сохранить стабильность обучения.
Количество параметров backbone:
|
Модель |
Количество параметров |
|---|---|
|
RAVEL-VB-001 |
1 209 328 |
|
RAVEL-VB-002 |
404 848 |
|
RAVEL-VB-003 |
375 792 |
Таким образом, backbone RAVEL-VB-002 содержит примерно в три раза меньше параметров, чем backbone RAVEL-VB-001. В RAVEL-VB-003 количество параметров уменьшено ещё сильнее.
RAVEL-VB-002 сохраняет более информативное представление уровня P4, тогда как RAVEL-VB-003 реализует более агрессивный подход «вычисления по требованию». Плотная карта высокого разрешения используется только для первичного поиска объектов, после чего основная обработка переносится на разреженные запросы и признаки более низкого разрешения.
FPS бывают разными
Производительность модели можно измерять по-разному.
В одном случае оценивается максимальное количество входов, которое модель способна обработать за секунду. Такой тест обычно проводится на заранее подготовленных тензорах и показывает чистую скорость инференса без учёта чтения и декодирования видео.
В другом случае измеряется скорость обработки конкретного видео целиком.
Для практического применения нас интересует именно скорость получения предсказаний из видеопотока. Поэтому в итоговый замер входят:
-
чтение и декодирование кадров;
-
предварительная обработка;
-
инференс модели;
-
постобработка предсказаний.
Такой показатель правильнее называть производительностью всего конвейера, или pipeline FPS.
Тестовое видео
Для тестирования использовалось видео со следующими характеристиками:
Duration: 00:00:40.01 Start: 0.000000Bitrate: 1119 kb/sCodec: H.264 HighPixel format: yuv420pColor space: BT.709Resolution: 1280 × 720Video bitrate: 982 kb/sFrame rate: 29.97 FPS
Для обеспечения повторяемости тестов замеры проводились на VPS и выделенном GPU. Это позволяет сравнивать версии модели в одинаковых условиях и уменьшает влияние фоновой нагрузки, различий в процессорах, настройках системы и скорости накопителей.
Сравнение точности моделей
|
Model |
Weights |
Input |
mAP50 |
mAP50:95 |
Player mAP50:95 |
Ball mAP50:95 |
Precision |
Recall |
|---|---|---|---|---|---|---|---|---|
|
RAVEL-VB-001-9f |
beach-trained |
18×288×512 |
0.5888 |
0.3114 |
0.4870 |
0.1359 |
0.9069 |
0.7327 |
|
RAVEL-VB-002-9f |
beach-trained |
9×288×512 |
0.6428 |
0.3312 |
0.5094 |
0.1529 |
0.7830 |
0.8178 |
|
RAVEL-VB-003-9f |
beach-trained |
9×288×512 |
0.5889 |
0.2719 |
0.4114 |
0.1324 |
0.8158 |
0.7503 |
|
YOLO26n |
official COCO |
640 |
0.3820 |
0.2815 |
0.5396 |
0.0234 |
0.8458 |
0.6802 |
|
YOLO26n-VB |
beach-trained |
512 |
0.5808 |
0.3950 |
0.4269 |
0.3631 |
0.8594 |
0.5985 |
|
YOLO11n |
official COCO |
640 |
0.4262 |
0.3102 |
0.5829 |
0.0375 |
0.9676 |
0.7260 |
|
YOLO11n-VB |
beach-trained |
512 |
0.6005 |
0.3974 |
0.4741 |
0.3208 |
0.7031 |
0.6837 |
Замер производительности на облачном провейдере для повторяемости

|
Модель |
OpenVINO, FPS |
CV OpenVINO |
PyTorch (GPU), FPS |
CV PyTorch |
|---|---|---|---|---|
|
|
27,69 |
1,56% |
101,99 |
4,15% |
|
|
14,39 |
0,69% |
58,53 |
1,55% |
|
|
32,12 |
0,99% |
73,10 |
1,55% |
|
|
38,93 |
1,51% |
79,84 |
2,33% |
|
|
39,48 |
0,84% |
91,45 |
3,17% |
|
|
55,09 |
1,33% |
89,09 |
4,24% |
|
|
36,83 |
0,76% |
97,71 |
0,92% |
|
|
51,47 |
2,60% |
94,62 |
2,64% |
CV — коэффициент вариации FPS между повторными запусками. Чем он ниже, тем стабильнее результаты замеров.
ссылка на оригинал статьи https://habr.com/ru/articles/1064760/