Всё началось с того, что на «Хабре» мне попалась статья о модели 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.000000 Bitrate: 1119 kb/s Codec: H.264 High Pixel format: yuv420p Color space: BT.709 Resolution: 1280 × 720 Video bitrate: 982 kb/s Frame 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 между повторными запусками. Чем он ниже, тем стабильнее результаты замеров.
Комментарии (6)

VIVIAR
30.07.2026 08:05Отличная работа! Особенно понравилось, что вы не просто обучили модель, а сделали акцент на прикладной задаче и показали результат на реальных игровых данных. Мне кажется, подобные модели могут стать хорошей основой не только для аналитики матчей, но и для автоматического сбора спортивной статистики, анализа тактики и даже помощи тренерскому штабу в разборе игр. Интересно, планируете ли вы развивать проект дальше - например, добавить трекинг игроков между кадрами (ByteTrack, BoT-SORT и т.п.) или перейти к распознаванию игровых событий и действий отдельных игроков?

asigatchov Автор
30.07.2026 08:05Это хобби-проект, поэтому скорость его развития сильно отстаёт от моих планов. В дальнейшем хотелось бы повторить функциональность зарубежных аналогов.
ProLimit
Очень круто, серьезный инженерный подход. Я решал подобную задачу для трекинга тенниса, но через пару месяцев потерял интерес из-за сложности проекта, для пет-проекта это черезчур. Задача была запустить детекцию мяча, игроков, их действий, ключевых точек корта, в 30 fps на мобильнике.
Вопросы:
1. каким образом тут используется TAPe — Theory of Active Perception, и их ключевой слоган " Recognition without convolution"? Упоминание только в начале статьи один раз, и все. Этот подход как-то отличает вашу модель от классических U-net, YOLO? У вас все же обычная CNN судя по дальнейшему тексту.
2. Для распознавания людей, по моему YOLO подходит идеально, точность там очень высокая, зачем что-то придумывать? И там не нужно 9 кадров на входе, досточно одного.
Насчет распознавания действий, напрямую через серию картинок решать это очень сложно, сети нужно будет выводить слишком много связей. Простое решение "из коробки" - YOLO pose и небольшая LSTM-модель по ключевым точкам. Ну и в теории YOLO pose может находить людей и ключевые точки, два-в-одном, но разрешение входа нужно побольше. Для точности конечно лучше запускать ее отдельно на кадом кропе.
asigatchov Автор
TAPe — Theory of Active Perception — скорее стало катализатором моего интереса к этой задаче и отправной точкой для поиска новых архитектурных решений. Однако в процессе экспериментов реализация действительно сместилась в сторону CNN, как вы верно заметили. Основной целью было сначала получить рабочую модель, а затем, решая возникающие проблемы, глубже разобраться в устройстве подобных систем.
В итоге я остановился на идее усиливать признаки игроков и мяча за счёт информации из соседних кадров. Поэтому модель получает на вход последовательность кадров, а не одно изображение.
Что касается YOLO: в сравнительной таблице есть результаты замеров, и YOLO действительно отлично справляется с детекцией игроков. Основная проблема возникает с мячом. Её выраженность сильно зависит от камеры, выдержки и качества видео: на некоторых кадрах мяч выглядит не как круглый объект, а как размытый овал, короткая полоса или вообще почти не виден.
В своей модели я пытаюсь объединить детекцию игроков и мяча, сохранив при этом приемлемую производительность на CPU.
И главный ответ на вопрос «зачем создавать свою модель, если уже есть YOLO?» — мне хотелось собрать систему по кирпичикам с нуля и глубже понять, как работают детекция, временные признаки, выбор областей внимания и оптимизация инференса на CPU.
ProLimit
Да, я также мотивировался, попробовать создать что-то свое с нуля, а не использовать YOLO. Для теннисного мяча задача еще сложнее, YOLO там с трудом применим, так как мяч может занимать пару смазанных пикселей. А TrackNet и его вариации слишком тяжелые для мобильного инференса, я на CPU с 16GB памяти его даже запустить не смог.
asigatchov Автор
Ранее я писал статью об облегчённых вариантах TrackNet/GridTackNet для запуска на CPU:
https://github.com/asigatchov/fast-volleyball-tracking-inference
Код для обучения моделей находится в отдельном репозитории:
https://github.com/asigatchov/vball-net-pytorch
Реализация основана на идеях из GridTrackNet и TrackNetV4.
На мобильных устройствах я эти модели пока не запускал. Один из возможных вариантов оптимизации — обучить модель обрабатывать каждый второй кадр при частоте видео 30 FPS, фактически выполняя детекцию на 15 FPS, а положение мяча на промежуточных кадрах интерполировать по соседним результатам.