19 KiB
Mona-layer (Multi-cognitive Visual Adapter) — adapter-based PEFT для зрения
Источники: статья Yin, Hu, Li, Zhang, Yang — «5%>100%: Breaking Performance Shackles of Full Fine-Tuning on Visual Recognition Tasks», arXiv:2408.08345 (CVPR 2025); официальная реализация GitHub Leiyi-Hu/mona. Все формулы блока и псевдокод ниже выверены по файлу
swin_transformer_mona.py(классыMonaиMonaOp).
1. Проблема: full fine-tuning против PEFT
Классическая схема переноса — pre-train & fine-tune: большой backbone обучается на крупном корпусе (ImageNet-21k, LVD-142M и т.п.), затем все его веса дообучаются на целевой задаче. На больших целевых датасетах это работает, но имеет два дефекта на малых данных:
- Стоимость. Для Swin-L это ~198M обучаемых параметров и отдельная полная копия весов на каждую задачу/чекпойнт (Yin et al., 2024).
- Переобучение. При малом числе примеров обновление всех параметров подгоняет backbone под шум обучающей выборки; обобщение падает.
PEFT (parameter-efficient fine-tuning, она же delta-tuning) решает обе проблемы: backbone заморожен (\nabla_\theta = 0), обучается лишь малая доля новых параметров \Delta (обычно 0.1–5 %). Семейства PEFT:
| Семейство | Что обучается | Представитель |
|---|---|---|
| Bias-tuning | только bias-векторы | BitFit |
| Low-rank | низкоранговые добавки BA к линейным слоям |
LoRA |
| Adapter (последовательный) | bottleneck-MLP внутри блока | Houlsby Adapter, AdaptFormer |
| Prompt-tuning | обучаемые prompt-токены на входе | VPT |
| Side-tuning | внешняя «боковая» сеть | LST |
Главная претензия статьи Mona: до неё ни один visual delta-tuning не превосходил full fine-tuning на сложных плотных задачах (detection, segmentation). Mona — первый метод, который это делает на всех протестированных задачах (arXiv:2408.08345, abstract).
2. Что такое Mona-блок
Mona — это последовательный adapter (вставляется в residual-ветку трансформерного блока), но с двумя ключевыми отличиями от языковых адаптеров:
- Multi-cognitive фильтры — внутри bottleneck стоят не линейные слои, а набор depth-wise свёрток разных масштабов (3×3, 5×5, 7×7), которые усредняются. Это даёт «vision-friendly» обработку (локальность, разные рецептивные поля).
- Scaled LayerNorm на входе — нормализация с двумя обучаемыми покомпонентными масштабами
\gammaи\gamma_x, регулирующая распределение признаков перед визуальными фильтрами.
2.1. Структура (по реализации)
Внутренний модуль MonaOp (multi-scale conv-агрегатор), работает на тензоре z \in \mathbb{R}^{B\times C_b\times H\times W} с C_b = 64 (bottleneck), все свёртки depth-wise (groups = C_b):
\mathrm{MonaOp}(z) = z' + \mathrm{Proj}_{1\times1}(z'),\qquad
z' = \frac{\mathrm{DW}_{3}(z) + \mathrm{DW}_{5}(z) + \mathrm{DW}_{7}(z)}{3} + z
где \mathrm{DW}_{k} — depth-wise conv с ядром k\times k и padding k//2, \mathrm{Proj}_{1\times1} — pointwise conv 1\times1. Обе агрегации обёрнуты в residual.
Внешний модуль Mona (вход — последовательность токенов x \in \mathbb{R}^{B\times N\times C}, N = H\cdot W):
\hat{x} = \mathrm{LayerNorm}(x)\odot \gamma + x \odot \gamma_x \qquad\text{(scaled norm, обучаемые } \gamma,\gamma_x\in\mathbb{R}^{C})
u = W_{\text{down}}\,\hat{x} \in \mathbb{R}^{B\times N\times 64}\quad\text{(down-projection, Linear } C\to 64)
u' = \mathrm{MonaOp}\big(\mathrm{reshape}(u)\big)\quad\text{(токены} \to \text{карта } H\times W \to \text{токены)}
y = W_{\text{up}}\,\mathrm{Dropout}\big(\mathrm{GELU}(u')\big)\in\mathbb{R}^{B\times N\times C}\quad\text{(up-projection, Linear } 64\to C)
\boxed{\;\mathrm{Mona}(x) = x + y\;}\quad\text{(внешний residual)}
Инициализация масштабов в коде: \gamma = 10^{-6}\cdot\mathbf{1} (LayerNorm-ветка стартует почти «выключенной»), \gamma_x = \mathbf{1} (тождественный проброс входа). Это делает Mona при инициализации близкой к identity — стабильный старт для дообучения.
Замечание по терминологии: «scaled LayerNorm» здесь =
LayerNorm(x)*γ + x*γx, то есть выпуклоподобная смесь нормированного и исходного признака с обучаемыми покомпонентными весами, а не нормировка с фиксированным множителем.
3. Куда вставляется и сколько добавляет
В Swin-блоке Mona вставляется дважды на каждый трансформерный блок — после attention-ветки и после FFN-ветки (см. SwinTransformerBlock.forward):
shortcut → (W-MSA/SW-MSA) → x = shortcut + drop_path(x)
x = Mona_1(x, (H,W)) # adapter после attention
identity = x; x = norm2(x); x = MLP(x)
x = identity + drop_path(x)
x = Mona_2(x, (H,W)) # adapter после FFN
- Замороженным остаётся весь backbone (attention, MLP, patch-merging, embeddings). Обучаются: параметры всех
Mona-модулей (down/up Linear, 3 depth-wise conv + 1×1 projector,\gamma,\gamma_x) и task-head/decoder. - Доля обучаемых параметров backbone: ~2.56 % на Swin-L и ~4.67 % на Swin-B (см. таблицы §4) (arXiv:2408.08345, Tables). Bottleneck фиксирован на 64 каналов, поэтому стоимость adapter не растёт квадратично с
C.
4. Результаты статьи
Сравнение проведено на Swin-B/Swin-L (ImageNet-21k pre-train) против full fine-tuning и набора PEFT. Ниже — выверенные числа из arXiv:2408.08345.
4.1. COCO instance segmentation (Cascade Mask R-CNN, Swin-B)
| Метод | Обуч. параметры | % | AP$_{box}$ | AP$_{mask}$ |
|---|---|---|---|---|
| Full fine-tuning | 89.14M | 100.0 | 52.40 | 45.10 |
| Fixed (frozen) | 0M | 0.0 | 48.00 | 41.60 |
| BitFit | 0.21M | 0.23 | 50.10 | 43.60 |
| LoRA | 3.06M | 3.43 | 50.40 | 43.90 |
| Adapter (Houlsby) | 3.19M | 3.58 | 52.10 | 45.00 |
| AdaptFormer | 1.60M | 1.79 | 51.70 | 44.60 |
| Mona | 4.16M | 4.67 | 53.40 | 46.00 |
4.2. ADE20K semantic segmentation (UperNet, Swin-L)
| Метод | Обуч. параметры | % | mIoU |
|---|---|---|---|
| Full fine-tuning | 198.58M | 100.0 | 51.18 |
| Fixed | 0M | 0.0 | 46.84 |
| BitFit | 0.30M | 0.15 | 48.37 |
| LoRA | 4.57M | 2.31 | 50.34 |
| Adapter | 4.61M | 2.33 | 50.78 |
| AdaptFormer | 2.34M | 1.18 | 50.83 |
| Mona | 5.08M | 2.56 | 51.36 |
4.3. Pascal VOC detection (RetinaNet, Swin-L) и DOTA oriented (Oriented R-CNN, Swin-B)
| Метод | VOC AP$_{box}$ | DOTA mAP |
|---|---|---|
| Full fine-tuning | 83.70 | 78.31 |
| BitFit | 85.40 | 76.05 |
| LoRA | 85.40 | 75.91 |
| Adapter | 86.70 | 78.27 |
| AdaptFormer | 86.60 | 77.43 |
| Mona | 87.30 | 78.44 |
4.4. Image classification (Swin-L, усреднение по датасетам)
| Метод | Top-1 Acc | Top-5 Acc |
|---|---|---|
| Full fine-tuning | 92.79 | 98.81 |
| BitFit | 93.51 | 99.69 |
| LoRA | 93.47 | 99.69 |
| Adapter | 93.99 | 99.61 |
| AdaptFormer | 93.70 | 99.65 |
| Mona | 94.04 | 99.76 |
4.5. Почему «5 % > 100 % full FT»
- На плотных задачах (detection, segmentation) full FT — сильный baseline, и линейные PEFT (LoRA, BitFit, AdaptFormer) его не достают. Mona обходит full FT на всех задачах: +1.0 AP${box}$ / +0.9 AP${mask}$ на COCO, +0.18 mIoU на ADE20K, +3.6 AP на VOC.
- Причина: conv-фильтры разных масштабов дают индуктивное смещение, подходящее под изображения (локальность, многомасштабность), которого нет у линейных адаптеров; а заморозка backbone регуляризует — на малых данных полная подгонка переобучается, а 5 % параметров «достаточно гибки, но не настолько, чтобы запомнить шум».
5. Mona vs LoRA vs обычный Adapter
| Критерий | LoRA | Adapter (Houlsby) | Mona |
|---|---|---|---|
| Куда вставляется | добавка \Delta W = \frac{\alpha}{r}BA к линейным слоям (q,v) |
bottleneck-MLP внутри блока | bottleneck с conv в residual-ветке (после attn и после FFN) |
| Внутренние операторы | две линейные матрицы A,B |
down-Linear → нелинейность → up-Linear | down-Linear → 3× depth-wise conv (3/5/7) + 1×1 → GELU → up-Linear |
| Учёт пространства | нет (работает потокенно) | нет | да (reshape в карту H\times W, multi-scale свёртки) |
| Нормализация входа | нет | обычно нет | scaled LayerNorm с обучаемыми \gamma,\gamma_x |
| Слияние в инференсе | можно слить в веса (zero-cost) | нет (доп. слой) | нет (доп. слой) |
| Сильная сторона | дёшево, мерджится | универсален | vision-friendly, превосходит full FT на dense-задачах |
| Доля параметров | ~2–3 % | ~2.3–3.6 % | ~2.5–4.7 % |
Ключевое отличие: LoRA и Houlsby-Adapter оперируют только линейными преобразованиями признаков и не используют 2D-структуру; Mona добавляет визуальное индуктивное смещение (multi-scale depth-wise conv) и adaptive scaled norm, поэтому выигрывает именно на изображениях.
6. Минимальный PyTorch-скелет Mona
Рабочий минимум, эквивалентный официальному коду (bottleneck=64 по умолчанию, как в репозитории; здесь параметризован).
import torch
import torch.nn as nn
import torch.nn.functional as F
class MonaOp(nn.Module):
"""Multi-cognitive conv aggregator: depthwise 3x3/5x5/7x7 + 1x1 projector."""
def __init__(self, dim: int):
super().__init__()
self.conv1 = nn.Conv2d(dim, dim, 3, padding=1, groups=dim) # depthwise 3x3
self.conv2 = nn.Conv2d(dim, dim, 5, padding=2, groups=dim) # depthwise 5x5
self.conv3 = nn.Conv2d(dim, dim, 7, padding=3, groups=dim) # depthwise 7x7
self.projector = nn.Conv2d(dim, dim, 1) # pointwise 1x1
def forward(self, x): # x: (B, dim, H, W)
identity = x
x = (self.conv1(x) + self.conv2(x) + self.conv3(x)) / 3.0 + identity
identity = x
return identity + self.projector(x) # second residual
class Mona(nn.Module):
"""Multi-cognitive visual adapter (Yin et al., CVPR 2025)."""
def __init__(self, in_dim: int, bottleneck: int = 64):
super().__init__()
self.norm = nn.LayerNorm(in_dim)
self.gamma = nn.Parameter(torch.ones(in_dim) * 1e-6) # scaled-norm branch
self.gammax = nn.Parameter(torch.ones(in_dim)) # identity branch
self.project1 = nn.Linear(in_dim, bottleneck) # down-projection
self.adapter_conv = MonaOp(bottleneck) # multi-scale conv
self.nonlinear = F.gelu
self.dropout = nn.Dropout(0.1)
self.project2 = nn.Linear(bottleneck, in_dim) # up-projection
def forward(self, x, hw_shape): # x: (B, N, C), hw_shape=(H, W)
identity = x
x = self.norm(x) * self.gamma + x * self.gammax # scaled LayerNorm
u = self.project1(x) # (B, N, bottleneck)
b, n, c = u.shape
h, w = hw_shape
u = u.reshape(b, h, w, c).permute(0, 3, 1, 2) # -> (B, c, H, W)
u = self.adapter_conv(u)
u = u.permute(0, 2, 3, 1).reshape(b, n, c) # -> (B, N, c)
u = self.dropout(self.nonlinear(u))
return identity + self.project2(u) # outer residual
Вставка в трансформерный блок (frozen backbone, обучается только Mona):
# внутри SwinBlock.forward после attention и после FFN:
x = shortcut + drop_path(attn_out)
x = mona_after_attn(x, (H, W))
x = x + drop_path(mlp_out)
x = mona_after_ffn(x, (H, W))
7. Применимость к маленькому датасету Naruto Sign на EdgeNeXt
Naruto Sign (распознавание ручных «печатей»/жестов) — малый датасет, EdgeNeXt — компактный backbone. Здесь Mona особенно уместен:
- Снижение переобучения. Backbone EdgeNeXt замораживается (предобученные веса сохраняют общие визуальные признаки), обучается лишь ~2.5–5 % параметров — меньше степеней свободы → меньше шансов запомнить шум малой выборки.
- Доменная адаптация через conv. Жесты рук — локальные многомасштабные паттерны (пальцы, контуры). Multi-scale depth-wise свёртки (3/5/7) подстраивают предобученные признаки под этот домен лучше линейных адаптеров.
- Дёшево по памяти. Хранится один frozen backbone + лёгкие Mona-веса; для edge-сценария это критично.
Замечание по совместимости: EdgeNeXt — гибрид conv+SDTA, а не чистый Swin. Mona-блок (
Mona/MonaOp) переносим почти без изменений: ему нужны лишь токенизированные признаки(B, N, C)+(H, W)для reshape, либо его можно применять прямо к feature-map(B, C, H, W), опустив permute. Точку вставки (после каждой стадии / после SDTA-блоков) выносим в гиперпараметры.
Гиперпараметры для Optuna
| Гиперпараметр | Диапазон / варианты поиска | Комментарий |
|---|---|---|
bottleneck (down-dim) |
{16, 32, 64, 96} | меньше → сильнее регуляризация, дешевле |
| набор ядер conv | {(3), (3,5), (3,5,7), (5,7)} | trade-off рецептивное поле vs параметры |
| агрегация ветвей | {mean, learnable-weighted sum} | взвешенная сумма даёт ещё ~k обучаемых скаляров |
init gamma |
{1e-6, 1e-4, 1e-2} | насколько «включена» scaled-norm-ветка на старте |
init gammax |
{1.0, 0.5} | сила identity-проброса |
| dropout в bottleneck | [0.0, 0.3] | регуляризация под малый датасет |
| стадии вставки | подмножество {stage1..stage4} | в ранние/поздние стадии или только в часть |
| позиции в блоке | {after-attn, after-ffn, both} | both = как в оригинале |
| LR для Mona-параметров | log-uniform [1e-4, 5e-3] | adapter-веса часто требуют LR выше backbone |
weight_decay Mona |
log-uniform [1e-5, 1e-2] | — |
Эмпирическое правило (из статьи): на малых/плотных задачах лучше вставлять Mona во все стадии и обе позиции (after-attn + after-ffn); сокращать набор ядер до (3,5) или bottleneck до 32 имеет смысл, если Optuna показывает переобучение или упор в бюджет параметров.
Источники
- Yin D., Hu L., Li B., Zhang Y., Yang X. «5%>100%: Breaking Performance Shackles of Full Fine-Tuning on Visual Recognition Tasks». arXiv:2408.08345, 2024 (CVPR 2025) — HTML-версия.
- Официальная реализация — GitHub Leiyi-Hu/mona; исходник блока —
swin_transformer_mona.py. - PEFT-baselines: LoRA (Hu et al., 2021, arXiv:2106.09685); Adapter/Houlsby (Houlsby et al., 2019, arXiv:1902.00751); AdaptFormer (Chen et al., 2022, arXiv:2205.13535); VPT (Jia et al., 2022, arXiv:2203.12119); BitFit (Zaken et al., 2021, arXiv:2106.10199).