Files
PracticeClassif/_research/SECTION_edgenext.md
2026-06-30 15:17:40 +03:00

23 KiB
Raw Blame History

tags, aliases, section, supervisor
tags aliases section supervisor
backbone
edgenext
feature_encoding
transfer_learning
timm
edge
EdgeNeXt
SDTA
visual_feature_encoding
Кодирование визуальных признаков и модель 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) это критично: см. §56.

Ключевой тезис: 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:

  1. Мало параметров → меньше переобучение. При N_{\text{train}} порядка сотен-тысяч примеров (Naruto Sign — малый датасет) модель на 16M параметров с сильным ImageNet-prior гораздо устойчивее к overfitting, чем ViT-B (86M) или ConvNeXt-B (88M).
  2. Линейная сложность SDTA делает inference дешёвым на одном GPU/edge-чипе.
  3. Сильный 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.35.6M 8688M
Риск переобучения на малых данных низкий высокий
ImageNet-prior сильный (IN-1k/USI/21k) сильный
Стоимость fine-tune на RTX 4090 минуты, большой batch дольше, меньший batch
Inference latency edge-уровень (1949 ms Jetson Nano) неприемлемо для edge

Тезисно:

  1. Мало параметров → меньше переобучение. Naruto Sign — малый датасет; модель на 16M параметров не «запоминает» обучающую выборку так агрессивно, как сеть на 80M+. Соотношение ёмкость/данные сбалансировано.
  2. Сильный ImageNet-prior. Признаки краёв/текстур/частей объектов уже выучены — для распознавания конфигураций кистей рук (печатей) это переносится напрямую, дообучение быстро сходится.
  3. Быстро на одной RTX 4090. Малая модель → большой batch (256512), полный fine-tune за минуты, что позволяет провести HPO (hyperparameter optimization, тема методички у Павленко Б.В.) — десятки прогонов lr/wd/augment в разумное время.
  4. 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 голова + последняя(-ие) стадия(-и); ранние стадии заморожены малый датасет, нужна частичная адаптация признаков стадии 34
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 12) или адаптеры.

Источники по 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.


Сводка источников