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

282 lines
23 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
tags: [backbone, edgenext, feature_encoding, transfer_learning, timm, edge]
aliases: [EdgeNeXt, SDTA, visual_feature_encoding]
section: Кодирование визуальных признаков и модель EdgeNeXt
supervisor: мнс Павленко Б.В.
---
# Кодирование визуальных признаков и модель 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](https://arxiv.org/abs/2206.10589) · [timm feature extraction docs](https://huggingface.co/docs/timm/feature_extraction).
---
## 2. EdgeNeXt: архитектура
**EdgeNeXt** (Maaz, Shaker, Cholakkal, Khan, Zamir, Anwer, Khan — MBZUAI; [arXiv:2206.10589](https://arxiv.org/abs/2206.10589), [github.com/mmaaz60/EdgeNeXt](https://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](https://arxiv.org/abs/2206.10589) · [ar5iv full text](https://ar5iv.labs.arxiv.org/html/2206.10589) · [project page](https://amshaker.github.io/EdgeNeXt/) · XCA-механизм восходит к [XCiT, Ali et al., NeurIPS 2021, arXiv:2106.09681](https://arxiv.org/abs/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](https://arxiv.org/abs/2206.10589) · [timm/edgenext_xx_small.in1k](https://huggingface.co/timm/edgenext_xx_small.in1k) · [timm/edgenext_small.usi_in1k](https://huggingface.co/timm/edgenext_small.usi_in1k) · [timm/edgenext_base.in21k_ft_in1k](https://huggingface.co/timm/edgenext_base.in21k_ft_in1k).
---
## 4. Практика через `timm`
### 4.1. Актуальные имена моделей (verified, timm `edgenext.py`)
Реестр моделей в [timm/models/edgenext.py](https://github.com/huggingface/pytorch-image-models/blob/main/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. Создание модели и адаптация головы
```python
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-режим)
```python
# (а) Глобальный дескриптор 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
```python
# Корректные нормализация/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](https://huggingface.co/timm/edgenext_small.usi_in1k) · [timm feature extraction](https://huggingface.co/docs/timm/feature_extraction) · [timm models source](https://github.com/huggingface/pytorch-image-models/blob/main/timm/models/edgenext.py).
---
## 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](https://arxiv.org/abs/2210.08823) · FiLM — [Perez et al., AAAI 2018, arXiv:1709.07871](https://arxiv.org/abs/1709.07871) · LoRA — [Hu et al., ICLR 2022, arXiv:2106.09685](https://arxiv.org/abs/2106.09685).
---
### Сводка источников
- [EdgeNeXt, Maaz et al., ECCV CADL Workshop 2022 — arXiv:2206.10589](https://arxiv.org/abs/2206.10589)
- [Официальный репозиторий — github.com/mmaaz60/EdgeNeXt](https://github.com/mmaaz60/EdgeNeXt)
- [Project page — amshaker.github.io/EdgeNeXt](https://amshaker.github.io/EdgeNeXt/)
- [timm EdgeNeXt source](https://github.com/huggingface/pytorch-image-models/blob/main/timm/models/edgenext.py)
- [timm/edgenext_small.usi_in1k](https://huggingface.co/timm/edgenext_small.usi_in1k) · [timm/edgenext_xx_small.in1k](https://huggingface.co/timm/edgenext_xx_small.in1k) · [timm/edgenext_base.in21k_ft_in1k](https://huggingface.co/timm/edgenext_base.in21k_ft_in1k)
- [timm feature extraction docs](https://huggingface.co/docs/timm/feature_extraction)
- [XCiT (cross-covariance attention), Ali et al., NeurIPS 2021 — arXiv:2106.09681](https://arxiv.org/abs/2106.09681)