Глава 5b. Depthwise и Inverted Residual: когда даже узкий 3×3 дорог
Bottleneck сжал каналы перед
3×3.
Mobile-блоки задают следующий вопрос: а обязан ли3×3смешивать все каналы сразу?
Глава 5a экономила за счёт ширины.
Эта глава экономит за счёт факторизации самой свёртки — ценой другого prior’а на смешивание признаков.
5b.1. Обычная свёртка смешивает пространство и каналы разом
Conv 3×3 с C_in → C_out на каждом пространственном окне сразу:
- смотрит на соседей;
- смешивает входы по каналам;
- пишет выходы по каналам.
Это гибко и дорого.
Гипотеза мобильных архитектур:
Разделим работу на две дешёвые стадии:
1) пространственный фильтр по каждому каналу отдельно;
2)1×1, который смешивает каналы без большого окна.
5b.2. Depthwise separable: разделить, чтобы сэкономить
Depthwise 3×3: один пространственный фильтр на каждый входной канал (без смешивания каналов).
Pointwise 1×1: обычная свёртка 1×1 для смешивания каналов.
Грубая экономия относительно полного 3×3 (порядок величин):
полный: ~ K² · C_in · C_out
separable: ~ K² · C_in + C_in · C_out
При больших C и K=3 выигрыш ощутимый — именно поэтому MobileNet-линия вообще взлетела на телефонах.
Обмен:
| Получили | Чем заплатили |
|---|---|
| Меньше FLOPs/параметров | Меньше выразительности на один слой |
| Лучше FPS на edge | Часто нужно больше слоёв / шире подбирать ширину |
| Ясный prior «сначала пространство, потом каналы» | Не любой паттерн так же легко выучить |
5b.3. Inverted residual: широкий внутри, узкий снаружи
MobileNetV2 перевернул интуицию bottleneck из ResNet.
Классический ResNet bottleneck:
широкий → узкий → (3×3) → широкий
Inverted residual:
Почему так:
- depthwise дешёвый, ему можно дать больше каналов (expansion
t); - skip дешевле и стабильнее держать на узком тензоре (меньше памяти на активациях);
- снаружи блок остаётся тонким — удобно для мобильных декодеров/хребтов.
Это снова обмен, а не «мобильный ResNet»:
Мы платим лишним expand/project,
чтобы пространственная стадия жила в богатом канальном пространстве
без цены полной dense-свёртки.
5b.4. Карта родственников (чтобы не утонуть)
Bottleneck (5a) — сузить перед дорогим 3×3
Depthwise sep. — разделить пространство и каналы
Inverted residual — расширить для DW, skip на узком
CSP (гл. 9) — не все каналы пускать в тяжёлую ветку
Разные рычаги одной боли «дорого считать признаки»:
| Рычаг | Вопрос |
|---|---|
| Width | Сколько каналов? |
| Factorization | Должен ли 3×3 мешать каналы? |
| Partial branches | Всем ли каналам идти в F? |
| Resolution | На каком H×W мы это делаем? |
На практике YOLO-подобные и мобильные детекторы постоянно комбинируют эти рычаги.
Не ищите «единственный правильный блок» — ищите набор ручек под latency-бюджет.
flowchart TD
A[Дорогой 3x3 на широком тензоре] --> B[Bottleneck: сузить]
A --> C[Depthwise: не мешать каналы в 3x3]
A --> D[CSP: часть каналов транзитом]
B --> E[ResNet-стиль]
C --> F[MobileNet-стиль]
C --> G[Inverted residual]
D --> H[YOLO C3/C2f-стиль]
5b.5. Когда depthwise предаёт
Типичные провалы:
- слишком агрессивный expansion/ширина «на бумаге дешево», на деле memory-bound;
- задача требует раннего богатого смешивания каналов (иногда обычный
3×3на stem лучше); - железо без хороших depthwise-kernels — теоретические FLOPs не превращаются в ms;
- детекция мелких объектов: чрезмерная экономия на ранних слоях убивает края (рифма с частотной главой).
Правило профилирования то же, что во FlashAttention:
Считайте wall-clock на целевом чипе, не только MACs в калькуляторе.
Если бы вы были автором статьи…
-
Замените в одном stage обычные
3×3на DW+PW при фиксированных params.
Что случится с mAP мелких объектов и с ms на NPU/GPU? -
Абляции expansion t = 2/4/6 в inverted residual.
Где начинается плато качества и где кончается память активаций? -
Сравните два способа экономии при одном FPS: уже CSP-ветка vs глубже DW-стек.
Какой failure case у каждого?
В детекции эти блоки встречаются как «тихие герои» мобильных конфигов.
Дальше — другой полигон экономии: не каналы свёртки, а пространство, в котором шумит диффузия.