Глава 9. CSP и C2f

Глава 9. Оптимизация на пределе: CSP и блоки C2f

Самый быстрый способ выполнить работу — не делать часть этой работы вообще.

У нас уже есть:

  • обучаемый глубокий backbone (residual + norm);
  • многомасштабная шея (FPN/PAN);
  • одностадийная голова.

На бумаге детектор жив.
На устройстве он может всё ещё не влезать в бюджет миллисекунд.

Следующий вопрос уже не «как вообще детектировать», а:

Где мы платим FLOPs и память за повтор вычислений,
которые не дают пропорционального качества?


9.1. Избыточность вычислений и градиентов

Посмотрите на обычный residual-стек.

В каждый блок заходит широкий тензор — скажем, 256 каналов.
Все каналы проходят тяжёлые свёртки. Потом результат складывается с входом.

Возникают две подозрительные вещи:

  1. Вычислительная: мы всегда платим полную цену за полную ширину.
  2. Обучающая: разные слои часто учат похожие признаки; градиенты дублируются.

Тяжёлый блок до CSP

Гипотеза:

А нужно ли всем каналам участвовать в тяжёлом F на каждом этапе?

Если нет — можно разрезать поток.


9.2. Разделяй и конкатенируй: CSP

Cross Stage Partial (CSP) предлагает грубо такой контракт:

  1. разделить входные каналы на две части;
  2. одну часть прогнать через блок преобразований;
  3. вторую провести транзитом почти без изменений;
  4. склеить (concat) на выходе.

CSP: разделение каналов

Что обычно получаем:

Эффект Почему
Меньше FLOPs Тяжёлая ветка уже
Меньше памяти Меньше промежуточных широких активаций
Часто не хуже / лучше точность Разнообразие: «свежие» и «переработанные» признаки рядом
Богаче градиентные маршруты Не всё проходит через одну кашу преобразований

Это прямой родственник идеи residual, но с другим акцентом:

  • residual: «добавь поправку к полному x»;
  • CSP: «не все каналы обязаны идти в дорогую переработку».

Обмен явный:

Жертвуем симметрией «все каналы равны в каждом блоке»
ради скорости и разнообразия представлений.


9.3. От CSP к C3 и C2f в YOLO-линии

В прикладных детекторах идея CSP обросла конкретными формами.

C3 (линия YOLOv5 и окружение)
Практическая упаковка CSP: входная свёртка, частичный проход через bottleneck-стек, склейка, выходная свёртка.
Инженерный смысл важнее названия: частичный тяжёлый путь стал стандартным кирпичом хребта.

C2f (линия YOLOv8 и дальше)
Буква f — про более «быстрый/богатый» сбор признаков.
Вместо одной финальной склейки двух половин блок собирает промежуточные состояния внутренних bottleneck’ов и конкатенирует их более гранулированно — «слоёный пирог» признаков.

C3 и C2f

Интуиция C2f:

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

Не нужно боготворить аббревиатуру. Нужно видеть рычаг:

ширина ветки
глубина bottleneck-стека
что именно конкатенируем на выходе

Именно этими рычагами семейство YOLO крутит баланс mAP ↔ latency под разные железки (n/s/m/l/x и т.д.).

flowchart TD
    A[Широкий тензор] --> B{Все каналы в тяжёлый F?}
    B -->|да| C[Дорого, много дублирования]
    B -->|нет, CSP| D[Часть транзитом]
    D --> E[C3: простой partial + bottlenecks]
    D --> F[C2f: partial + сбор промежуточных срезов]
    E --> G[Лучше FPS при той же глубине]
    F --> G

9.4. Исследовательский вопрос, который стоит прожить

В конце ранних черновиков этой книги уже звучал хороший вопрос:

Если деление пополам помогает, почему не на 10 частей?
Почему не менять пропорцию на каждом слое?

Возможные ответы (проверяемые, не догматические):

  1. Железо любит простые регулярные формы — половина/кратность каналов хорошо ложится на реализации.
  2. Слишком узкая тяжёлая ветка начинает душить выразительность.
  3. Слишком много веток/конкатов раздувает память на склейках и съедает выигрыш.
  4. Сладкая точка ищется абляциями на конкретных датасетах и размерах модели; «пополам» — сильный baseline, не закон природы.

Вот это и есть стиль Research Engineer: не заучить «C2f лучше», а уметь поставить эксперимент «что будет, если split ratio = 0.25 / 0.5 / 0.75».


9.5. Собираем детектор как конструктор компромиссов

К концу Части III картина должна сложиться без магии брендов:

Современный одностадийный детектор

Блок Роль
Backbone Глубокие признаки дёшево (Res + CSP/C2f)
SPPF Разный контекст на глубоком уровне
Neck FPN + PAN — дружба смысла и геометрии
Head Сетка / много масштабов; часто decoupled
Loss IoU-семейство + классификация (+ objectness…)

Главный навык, ради которого писалась эта часть:

Смотреть на блок и спрашивать не «как называется в YAML»,
а «какую боль закрыли и какой обмен приняли».

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


Если бы вы были автором статьи…

  1. Абляция split ratio: 1/4, 1/2, 3/4 при фиксированном бюджете FLOPs.
    Что важнее для mAP мелких объектов?

  2. C2f без конката промежуточных срезов — оставьте только выход последнего bottleneck.
    Сколько FPS вернёте и сколько mAP отдадите?

  3. Перенесите CSP-идею в Neck, а не в Backbone.
    Имеет ли смысл partial-обработка на FPN-слияниях, или там каналы и так узкое место другое?

Часть III закрыта. Дальше книга уходит в другой кризис — уже не про пространство картинки, а про последовательности и контекст: почему рекуррентность упёрлась в GPU и как внимание переписало правила.