--- 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) это критично: см. §5–6. > Ключевой тезис: **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 — малый датасет) модель на 1–6M параметров с сильным 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` (имя функции) | Доступные веса (тег) | 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.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 | Тезисно: 1. **Мало параметров → меньше переобучение.** Naruto Sign — малый датасет; модель на 1–6M параметров не «запоминает» обучающую выборку так агрессивно, как сеть на 80M+. Соотношение ёмкость/данные сбалансировано. 2. **Сильный ImageNet-prior.** Признаки краёв/текстур/частей объектов уже выучены — для распознавания конфигураций кистей рук (печатей) это переносится напрямую, дообучение быстро сходится. 3. **Быстро на одной RTX 4090.** Малая модель → большой batch (256–512), полный 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** | голова + последняя(-ие) стадия(-и); ранние стадии заморожены | малый датасет, нужна частичная адаптация признаков | стадии 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](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)