23 KiB
tags, aliases, section, supervisor
| tags | aliases | section | supervisor | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
Кодирование визуальных признаков и модель EdgeNeXt | мнс Павленко Б.В. |
Кодирование визуальных признаков и модель EdgeNeXt
1. Кодирование визуальных признаков (visual feature encoding)
Кодирование визуальных признаков — это преобразование сырого изображения (тензор пикселей x \in \mathbb{R}^{H \times W \times 3}) в компактное численное представление (эмбеддинг, feature vector), пригодное для решения downstream-задачи (классификация, retrieval, сегментация). Цель — отбросить избыточную низкоуровневую информацию (точные значения пикселей, освещение, шум) и сохранить семантически значимые абстракции (формы, текстуры, объекты, в нашем случае — конфигурацию кистей рук в дзюцу-печатях).
От пикселей к эмбеддингу
Backbone (свёрточная или гибридная сеть) реализует иерархическое отображение:
x \in \mathbb{R}^{H \times W \times 3} \;\xrightarrow{\ f_\theta\ }\; F \in \mathbb{R}^{H' \times W' \times C}
\;\xrightarrow{\ \text{pool}\ }\; z \in \mathbb{R}^{C}
где f_\theta — backbone с параметрами \theta, F — карта признаков (feature map) последней стадии (для EdgeNeXt-S: C = 304, пространственный размер H/32 \times W/32 = 8 \times 8 при входе 256), а z — глобальный дескриптор после пулинга.
Карты признаков vs глобальный дескриптор
| Представление | Что это | Размерность (EdgeNeXt-S, вход 256) | Когда нужно |
|---|---|---|---|
Feature maps (F) |
Пространственно-разрешённые признаки по стадиям | \{48\times64^2,\ 96\times32^2,\ 160\times16^2,\ 304\times8^2\} |
Сегментация, детекция, FPN, attention-fusion, CVGL-retrieval по патчам |
Global descriptor (z) |
Один вектор на изображение (GAP по H',W') |
\mathbb{R}^{304} |
Классификация, image-level retrieval, метрик-обучение |
Глобальный дескриптор получают global average pooling:
z_c = \frac{1}{H' W'} \sum_{i=1}^{H'} \sum_{j=1}^{W'} F_{i,j,c}, \qquad c = 1, \dots, C
Для классификации поверх z ставится линейный классификатор (head): \hat{y} = \mathrm{softmax}(W z + b), W \in \mathbb{R}^{K \times C}, K — число классов.
Роль предобучения (ImageNet) и переноса (transfer learning)
- Backbone = feature encoder. Сам по себе backbone не «классифицирует» — он кодирует изображение в
z. Голова (classifier head) уже решает конкретную задачу. Поэтому один и тот же предобученный encoder переиспользуется для разных задач сменой головы (reset_classifier). - ImageNet-prior. Веса
\theta, обученные на ImageNet-1k (1.28M изображений, 1000 классов) или ImageNet-21k (~14M, ~21k классов), кодируют универсальные визуальные примитивы (края, текстуры, части объектов). Эти признаки переносимы на задачи, где у нас мало собственных данных. - Transfer learning. Вместо обучения
f_\thetaс нуля (требует сотни тысяч изображений) мы инициализируем\thetaпредобученными весами и до-обучаем (fine-tuning) на целевом датасете. На малом датасете (Naruto Sign) это критично: см. §5–6.
Ключевой тезис: backbone — это feature encoder. Качество эмбеддинга
zопределяет потолок точности downstream-задачи, а предобучение задаёт качественную стартовую точку для\theta.
Источники: EdgeNeXt, Maaz et al., ECCV CADL Workshop 2022, arXiv:2206.10589 · timm feature extraction docs.
2. EdgeNeXt: архитектура
EdgeNeXt (Maaz, Shaker, Cholakkal, Khan, Zamir, Anwer, Khan — MBZUAI; arXiv:2206.10589, github.com/mmaaz60/EdgeNeXt) — light-weight гибридная CNN-Transformer сеть, ориентированная на edge-устройства. Идея: брать дешёвую свёрточную базу (ConvNeXt-блоки) и точечно добавлять линейное по сложности внимание (SDTA), чтобы получить глобальный рецептивный охват без квадратичной стоимости классического self-attention.
2.1. Общая иерархия (4 стадии)
EdgeNeXt следует пирамидальной схеме в стиле ConvNeXt:
Input 3×256×256
│ Stem (Conv 4×4, stride 4)
▼
Stage 1 (1/4 res, C1=48) : Conv-encoders ×N1, kernel 3
│ Downsample (Conv 2×2, stride 2)
▼
Stage 2 (1/8 res, C2=96) : Conv-encoders + [PE] + SDTA-encoder, kernel 5
│ Downsample
▼
Stage 3 (1/16 res, C3=160): Conv-encoders + SDTA-encoder, kernel 7
│ Downsample
▼
Stage 4 (1/32 res, C4=304): Conv-encoders + SDTA-encoder, kernel 9
│ LayerNorm → GAP → Linear head
▼
logits ∈ ℝ^K
- Stem: неперекрывающаяся свёртка
4\times4, stride 4 → понижение разрешения в 4 раза (patchify). - Downsample между стадиями: LayerNorm + свёртка
2\times2, stride 2. - Адаптивные ядра Conv-encoder растут по стадиям
\{3,5,7,9\}: на ранних стадиях (высокое разрешение) — малые ядра (дёшево), на поздних — крупные (для большего рецептивного поля при малом разрешении). - Positional Encoding (PE): добавляется только перед SDTA в stage 2 (раннее введение позиционной информации; дальше она распространяется по сети) — экономит вычисления.
2.2. Conv-encoder (ConvNeXt-блок с адаптивным ядром)
Каждый Conv-encoder — это инвертированный bottleneck в стиле ConvNeXt:
\begin{aligned}
u &= \mathrm{DWConv}_{k\times k}(x) \quad (\text{depth-wise, } k \in \{3,5,7,9\}) \\
u &= \mathrm{LayerNorm}(u) \\
u &= \mathrm{Linear}_{C \to 4C}(u),\quad u = \mathrm{GELU}(u),\quad u = \mathrm{Linear}_{4C \to C}(u) \\
y &= x + \gamma \odot u
\end{aligned}
где \gamma — обучаемый layer-scale, \odot — поканальное умножение. Depth-wise свёртка обеспечивает пространственное смешивание, а $1\times1$-свёртки (Linear) — канальное.
2.3. SDTA-encoder (Split Depth-wise Transpose Attention)
Ключевая новация. SDTA состоит из двух частей.
(а) Multi-scale ветвь (Res2Net-style split-DWConv). Вход делится по каналам на s подмножеств \{x_1, \dots, x_s\}. Каждое (кроме первого) пропускается через depth-wise свёртку, причём вход свёртки складывается с выходом предыдущей подгруппы — иерархический каскад, неявно увеличивающий рецептивное поле и кодирующий multi-scale признаки:
y_i =
\begin{cases}
x_i, & i = 1 \\
\mathrm{DWConv}_{3\times3}(x_i), & i = 2 \\
\mathrm{DWConv}_{3\times3}(x_i + y_{i-1}), & 3 \le i \le s
\end{cases}
\qquad
y = \mathrm{Concat}(y_1, \dots, y_s)
(б) Transposed / cross-covariance attention (XCA). Вместо классического self-attention по токенам (сложность O(N^2 d), N=HW), EdgeNeXt применяет внимание по каналам (как в XCiT / Restormer). Карта внимания строится на ковариации каналов d \times d, а не токенов N \times N, что даёт линейную сложность $O(N \cdot d^2)$ по числу токенов. Для стабильности Q и K L2-нормируются по токенной оси, а температура \tau — обучаемая:
\mathrm{XCA}(Q,K,V) = V \cdot \mathrm{softmax}\!\left( \frac{\hat{Q}^{\top} \hat{K}}{\tau} \right),
\qquad
\hat{Q} = \frac{Q}{\lVert Q \rVert_2},\ \ \hat{K} = \frac{K}{\lVert K \rVert_2}
где Q,K,V \in \mathbb{R}^{N \times d}, а произведение \hat{Q}^{\top}\hat{K} \in \mathbb{R}^{d \times d} — поэтому softmax и attention считаются в канальном (а не токенном) пространстве. Завершается блок LayerNorm + позиционным FFN с residual-связями.
Итог: SDTA даёт глобальный (по каналам) и multi-scale (по пространству) охват без квадратичного взрыва по числу токенов — идеально для высокого разрешения на edge.
Источники: EdgeNeXt arXiv:2206.10589 · ar5iv full text · project page · XCA-механизм восходит к XCiT, Ali et al., NeurIPS 2021, arXiv:2106.09681.
3. Варианты EdgeNeXt и числа
Числа на ImageNet-1k, вход 256\times256 (если не указано иное), по таблицам статьи и карточкам timm на Hugging Face.
| Вариант | Params | MAdds (GMACs) | Top-1 (%) | Предобучение | Latency (Jetson Nano) |
|---|---|---|---|---|---|
| EdgeNeXt-XXS | 1.33M | ~0.26 | 71.2 | IN-1k | ~19 ms |
| EdgeNeXt-XS | 2.34M | ~0.54 | 75.0 | IN-1k | ~31 ms |
| EdgeNeXt-S | 5.59M | ~1.3 | 79.4 | IN-1k (USI) | ~49 ms |
| EdgeNeXt-B | 18.51M | ~3.8 | 82.5 / 83.3 | IN-1k / IN-21k→1k | — |
- USI = «Useful Information Set» рецепт обучения (knowledge-distillation), даёт более сильные веса для
edgenext_small.usi_in1kиedgenext_base.usi_in1k. - Variant-B с предобучением на ImageNet-21k достигает 83.3% Top-1 — лучший вариант по точности, но 18.5M параметров избыточны для очень малого датасета.
Почему XXS/XS/S подходят для маленьких датасетов и edge:
- Мало параметров → меньше переобучение. При
N_{\text{train}}порядка сотен-тысяч примеров (Naruto Sign — малый датасет) модель на 1–6M параметров с сильным ImageNet-prior гораздо устойчивее к overfitting, чем ViT-B (86M) или ConvNeXt-B (88M). - Линейная сложность SDTA делает inference дешёвым на одном GPU/edge-чипе.
- Сильный prior при низкой ёмкости — оптимальный баланс «обобщающая способность / риск переобучения».
Источники: EdgeNeXt таблицы, arXiv:2206.10589 · timm/edgenext_xx_small.in1k · timm/edgenext_small.usi_in1k · timm/edgenext_base.in21k_ft_in1k.
4. Практика через timm
4.1. Актуальные имена моделей (verified, timm edgenext.py)
Реестр моделей в timm/models/edgenext.py. Имя = <arch>.<pretrained_tag>:
arch (имя функции) |
Доступные веса (тег) | Params | train / test size |
|---|---|---|---|
edgenext_xx_small |
.in1k |
1.33M | 256 / 288 |
edgenext_x_small |
.in1k |
2.34M | 256 / 288 |
edgenext_small |
.usi_in1k |
5.59M | 256 / 320 |
edgenext_base |
.usi_in1k, .in21k_ft_in1k |
18.51M | 256 / 320 |
edgenext_small_rw |
.sw_in1k (timm re-implementation) |
~7.8M | 256 / 320 |
Проверка доступных тегов в коде:
timm.list_models('edgenext*', pretrained=True).
4.2. Создание модели и адаптация головы
import timm
import torch
NUM_CLASSES = 12 # число классов Naruto Sign (пример)
# Создать с предобученными ImageNet-весами и сразу заменить голову на N классов.
# Голова инициализируется заново под NUM_CLASSES, encoder = pretrained.
model = timm.create_model(
'edgenext_small.usi_in1k',
pretrained=True,
num_classes=NUM_CLASSES,
)
# Эквивалентно: создать с дефолтной головой и заменить через API.
model = timm.create_model('edgenext_xx_small.in1k', pretrained=True)
model.reset_classifier(num_classes=NUM_CLASSES) # пересоздать только классификатор
4.3. Извлечение признаков (encoder-режим)
# (а) Глобальный дескриптор z (pre-logits embedding):
model = timm.create_model('edgenext_small.usi_in1k', pretrained=True, num_classes=0)
x = torch.randn(1, 3, 256, 256)
feat_maps = model.forward_features(x) # карта признаков последней стадии
z = model.forward_head(feat_maps, pre_logits=True) # эмбеддинг z ∈ ℝ^C (после GAP+norm)
print(z.shape, model.num_features) # torch.Size([1, 304]) 304
# (б) Многоуровневые карты признаков (для fusion / FPN / сегментации):
fmodel = timm.create_model('edgenext_small.usi_in1k', pretrained=True, features_only=True)
feats = fmodel(x) # список из 4 тензоров по стадиям
print([f.shape for f in feats])
# [1,48,64,64], [1,96,32,32], [1,160,16,16], [1,304,8,8]
print(fmodel.feature_info.channels()) # [48, 96, 160, 304]
model.num_features— размерность эмбеддингаC(дляedgenext_small= 304).forward_head(..., pre_logits=True)возвращаетzдо линейного классификатора (то, что нужно для retrieval / метрик-обучения / переноса).
4.4. Дефолтный input size и data config
# Корректные нормализация/resize/crop берутся из конфигурации весов — НЕ хардкодить.
data_config = timm.data.resolve_model_data_config(model)
print(data_config)
# {'input_size': (3, 256, 256), 'crop_pct': 0.9, 'crop_mode': 'center',
# 'mean': (0.485, 0.456, 0.406), 'std': (0.229, 0.224, 0.225), ...}
train_tf = timm.data.create_transform(**data_config, is_training=True)
eval_tf = timm.data.create_transform(**data_config, is_training=False)
resolve_model_data_config(model)— актуальный API (вместо устаревшегоresolve_data_config(model.pretrained_cfg)). Дефолтный train-вход EdgeNeXt —256\times256; test-разрешение выше (288/320), но для собственного датасета обычно дообучают на 256.
Источники: timm/edgenext_small.usi_in1k card · timm feature extraction · timm models source.
5. Почему EdgeNeXt — хороший выбор для классификации на МАЛЕНЬКОМ датасете (Naruto Sign)
| Фактор | EdgeNeXt-XXS/XS/S | Большие сети (ViT-B/ConvNeXt-B) |
|---|---|---|
| Параметры | 1.3–5.6M | 86–88M |
| Риск переобучения на малых данных | низкий | высокий |
| ImageNet-prior | сильный (IN-1k/USI/21k) | сильный |
| Стоимость fine-tune на RTX 4090 | минуты, большой batch | дольше, меньший batch |
| Inference latency | edge-уровень (19–49 ms Jetson Nano) | неприемлемо для edge |
Тезисно:
- Мало параметров → меньше переобучение. Naruto Sign — малый датасет; модель на 1–6M параметров не «запоминает» обучающую выборку так агрессивно, как сеть на 80M+. Соотношение ёмкость/данные сбалансировано.
- Сильный ImageNet-prior. Признаки краёв/текстур/частей объектов уже выучены — для распознавания конфигураций кистей рук (печатей) это переносится напрямую, дообучение быстро сходится.
- Быстро на одной RTX 4090. Малая модель → большой batch (256–512), полный fine-tune за минуты, что позволяет провести HPO (hyperparameter optimization, тема методички у Павленко Б.В.) — десятки прогонов lr/wd/augment в разумное время.
- Edge-готовность. Если конечная цель — деплой (камера/телефон/Jetson), EdgeNeXt уже спроектирован под latency-бюджет.
6. Мостик к freezing / частичной заморозке / адаптерам
На малых данных полный fine-tune всех \theta может переобучить encoder и «стереть» полезный ImageNet-prior. Стандартные стратегии переноса (от более «бережных» к более «агрессивным»):
| Стратегия | Что обучается | Когда применять | Параметров обучается |
|---|---|---|---|
| Linear probing (full freeze) | только голова reset_classifier |
очень мало данных, prior близок к домену | \sim C \cdot K |
| Partial freeze | голова + последняя(-ие) стадия(-и); ранние стадии заморожены | малый датасет, нужна частичная адаптация признаков | стадии 3–4 |
| Adapters / PEFT (MONA, LoRA, FiLM/SSF) | вставленные лёгкие модули; backbone заморожен | малые данные + хочется адаптации без переобучения | <5% весов |
| Full fine-tune | все \theta + голова |
данных достаточно, домен далёк от ImageNet | 100% |
- Заморозка (freezing):
for p in model.parameters(): p.requires_grad = False, затем разморозить голову (и при partial — поздние стадии). Снижает число обучаемых параметров → меньше overfitting и быстрее обучение. - Адаптеры (MONA — Multi-cognitive visual adapter, и др.): в замороженный backbone вставляются обучаемые мини-модули, адаптирующие признаки под целевой домен почти без роста параметров. Это лучший компромисс «адаптация vs переобучение» именно для малых датасетов.
Детали — в разделах методички про freezing и MONA (PEFT-адаптеры). Для EdgeNeXt на Naruto Sign разумный старт: full fine-tune с сильной аугментацией + early stopping; при признаках переобучения → partial freeze (заморозить stage 1–2) или адаптеры.
Источники по PEFT-контексту проекта: SSF — Lian et al., NeurIPS 2022 / TPAMI · FiLM — Perez et al., AAAI 2018, arXiv:1709.07871 · LoRA — Hu et al., ICLR 2022, arXiv:2106.09685.
Сводка источников
- EdgeNeXt, Maaz et al., ECCV CADL Workshop 2022 — arXiv:2206.10589
- Официальный репозиторий — github.com/mmaaz60/EdgeNeXt
- Project page — amshaker.github.io/EdgeNeXt
- timm EdgeNeXt source
- timm/edgenext_small.usi_in1k · timm/edgenext_xx_small.in1k · timm/edgenext_base.in21k_ft_in1k
- timm feature extraction docs
- XCiT (cross-covariance attention), Ali et al., NeurIPS 2021 — arXiv:2106.09681