380 lines
28 KiB
Markdown
380 lines
28 KiB
Markdown
# Задача классификации изображений: метрики, loss-функции, семплирование
|
||
|
||
> Учебно-исследовательский раздел методички (научный руководитель — мнс Павленко Б.В.).
|
||
> Контекст применения: HPO (Optuna) для EdgeNeXt на датасете NarutoSign (multi-class классификация знаков-печатей).
|
||
|
||
---
|
||
|
||
## 1. Постановка задачи multi-class классификации
|
||
|
||
Дана обучающая выборка $\{(x_i, y_i)\}_{i=1}^{N}$, где $x_i$ — изображение, $y_i \in \{1, \dots, C\}$ — метка одного из $C$ взаимоисключающих классов (multi-class, в отличие от multi-label, где классы не исключают друг друга). Модель $f_\theta$ выдаёт вектор **логитов** (необработанных скоров) $z = f_\theta(x) \in \mathbb{R}^{C}$.
|
||
|
||
### Softmax
|
||
|
||
Логиты переводятся в распределение вероятностей по классам функцией softmax:
|
||
|
||
$$
|
||
p_k = \mathrm{softmax}(z)_k = \frac{e^{z_k}}{\sum_{j=1}^{C} e^{z_j}}, \qquad \sum_{k=1}^{C} p_k = 1,\; p_k \in (0,1).
|
||
$$
|
||
|
||
Softmax инвариантен к сдвигу: $\mathrm{softmax}(z) = \mathrm{softmax}(z + c)$, поэтому на практике вычитают $\max_k z_k$ для численной устойчивости (log-sum-exp trick).
|
||
|
||
### One-hot и целевое распределение
|
||
|
||
Истинная метка $y$ кодируется **one-hot** вектором $q \in \{0,1\}^{C}$: $q_k = \mathbb{1}[k = y]$. Это «жёсткое» (hard) целевое распределение. «Мягкие» (soft) цели $q_k \in [0,1]$ возникают при label smoothing, mixup/cutmix и knowledge distillation (см. §3).
|
||
|
||
### Top-1 / top-k accuracy
|
||
|
||
Предсказание top-1: $\hat{y} = \arg\max_k p_k$. **Top-k** считает пример верным, если истинная метка попала в множество $k$ наибольших по вероятности классов:
|
||
|
||
$$
|
||
\text{top-}k\text{-acc} = \frac{1}{N}\sum_{i=1}^{N} \mathbb{1}\!\left[\, y_i \in \mathrm{TopK}_k\big(p^{(i)}\big)\,\right].
|
||
$$
|
||
|
||
Top-5 — историческая метрика ImageNet (1000 классов). Для задач с малым $C$ (например, 12 знаков-печатей) top-k при $k \geq 2$ малоинформативна; основная метрика — top-1.
|
||
|
||
---
|
||
|
||
## 2. Метрики
|
||
|
||
Базовые величины для класса $c$ из confusion matrix (one-vs-rest): $TP_c$ (true positive), $FP_c$, $FN_c$, $TN_c$. Обозначим $n_c$ — число истинных объектов класса $c$, $N = \sum_c n_c$.
|
||
|
||
| Метрика | Формула | Диапазон | Чувствительность к дисбалансу |
|
||
|---|---|---|---|
|
||
| Accuracy (top-1) | $\dfrac{\sum_c TP_c}{N}$ | $[0,1]$ | **Высокая** (доминирует majority-класс) |
|
||
| Balanced accuracy | $\dfrac{1}{C}\sum_c \dfrac{TP_c}{n_c} = \dfrac{1}{C}\sum_c \mathrm{Recall}_c$ | $[0,1]$ | Низкая (макро-усреднение recall) |
|
||
| Top-k accuracy | см. §1 | $[0,1]$ | Высокая |
|
||
| Precision (класс $c$) | $P_c = \dfrac{TP_c}{TP_c + FP_c}$ | $[0,1]$ | — |
|
||
| Recall (класс $c$) | $R_c = \dfrac{TP_c}{TP_c + FN_c}$ | $[0,1]$ | — |
|
||
| F1 (класс $c$) | $F1_c = \dfrac{2 P_c R_c}{P_c + R_c}$ | $[0,1]$ | — |
|
||
| Macro-F1 | $\dfrac{1}{C}\sum_c F1_c$ | $[0,1]$ | **Низкая** (классы равновесны) |
|
||
| Micro-F1 | $\dfrac{2\sum_c TP_c}{2\sum_c TP_c + \sum_c FP_c + \sum_c FN_c}$ | $[0,1]$ | Высокая ($=$ accuracy в multi-class) |
|
||
| Weighted-F1 | $\sum_c \dfrac{n_c}{N} F1_c$ | $[0,1]$ | Высокая (вес $\propto$ частоте) |
|
||
| MCC | см. ниже | $[-1,1]$ | Низкая (учитывает все 4 клетки) |
|
||
| Cohen's $\kappa$ | см. ниже | $[-1,1]$ | Низкая (поправка на случай) |
|
||
| ROC-AUC (OvR) | площадь под ROC, усреднённая | $[0,1]$ | Зависит от усреднения |
|
||
| PR-AUC (OvR) | площадь под precision-recall | $[0,1]$ | **Низкая** (лучше для редких классов) |
|
||
| ECE | см. §2.5 | $[0,1]$, ниже лучше | — (про калибровку) |
|
||
|
||
### 2.1 Macro / micro / weighted — когда какая
|
||
|
||
- **Micro**: агрегирует TP/FP/FN по всем классам, затем считает метрику. В multi-class с single-label **micro-F1 = micro-precision = micro-recall = accuracy**. Отражает производительность «на объект», доминирует majority-класс.
|
||
- **Macro**: метрика считается по каждому классу, затем простое среднее. Каждый класс весит одинаково → редкие классы влияют наравне с частыми. Главный выбор при дисбалансе.
|
||
- **Weighted**: macro со взвешиванием по $n_c$ → возвращает доминирование majority-класса, маскирует провал на редких классах.
|
||
|
||
| Сценарий | Рекомендуемое усреднение |
|
||
|---|---|
|
||
| Сбалансированные классы, важна общая доля верных | micro / accuracy |
|
||
| Дисбаланс, все классы одинаково важны | **macro** |
|
||
| Дисбаланс, но важность $\propto$ частоте в проде | weighted |
|
||
|
||
[scikit-learn — precision_recall_fscore_support / averaging](https://scikit-learn.org/stable/modules/model_evaluation.html#precision-recall-f-measure-metrics)
|
||
|
||
### 2.2 Confusion matrix
|
||
|
||
$M \in \mathbb{N}^{C \times C}$, $M_{ij}$ = число объектов истинного класса $i$, предсказанных как $j$. Диагональ — верные. Нормировка по строкам ($M_{ij}/n_i$) даёт **per-class accuracy** = recall класса $i$. Самый информативный диагностический инструмент: показывает *какие* классы путаются (для NarutoSign — визуально похожие печати). [sklearn.confusion_matrix](https://scikit-learn.org/stable/modules/generated/sklearn.metrics.confusion_matrix.html)
|
||
|
||
### 2.3 Matthews Correlation Coefficient (MCC)
|
||
|
||
Корреляция Пирсона между предсказанным и истинным классом. Multi-class форма ([sklearn.matthews_corrcoef](https://scikit-learn.org/stable/modules/generated/sklearn.metrics.matthews_corrcoef.html)):
|
||
|
||
$$
|
||
\mathrm{MCC} = \frac{\sum_k\sum_l\sum_m (M_{kk}M_{lm} - M_{kl}M_{mk})}
|
||
{\sqrt{\sum_k\big(\sum_l M_{kl}\big)\big(\sum_{k'\neq k}\sum_{l'} M_{k'l'}\big)}\;\sqrt{\sum_k\big(\sum_l M_{lk}\big)\big(\sum_{k'\neq k}\sum_{l'} M_{l'k'}\big)}}.
|
||
$$
|
||
|
||
$\mathrm{MCC}=1$ — идеал, $0$ — случай, $-1$ — полное расхождение. Высокий MCC требует хороших результатов по **всем** классам, поэтому это надёжная сводная метрика при дисбалансе.
|
||
|
||
### 2.4 Cohen's kappa
|
||
|
||
$$
|
||
\kappa = \frac{p_o - p_e}{1 - p_e},
|
||
$$
|
||
|
||
где $p_o$ — наблюдаемая accuracy, $p_e = \sum_c \frac{(\text{предсказано } c)\cdot(\text{истинно } c)}{N^2}$ — ожидаемое согласие «по случайности». Учитывает базовый уровень случайного угадывания. [sklearn.cohen_kappa_score](https://scikit-learn.org/stable/modules/generated/sklearn.metrics.cohen_kappa_score.html)
|
||
|
||
### 2.5 ROC-AUC / PR-AUC (one-vs-rest)
|
||
|
||
Для multi-class каждый класс берётся как «positive», остальные — «negative» (**OvR**), по вероятностям $p_c$ строится кривая, площади усредняются (macro / weighted). ROC-AUC = $P(p_c^{+} > p_c^{-})$ для случайной пары. При сильном дисбалансе ROC-AUC оптимистична (огромное число $TN$ распухает specificity), поэтому для редких классов предпочтительна **PR-AUC** (average precision), не использующая $TN$. [sklearn.roc_auc_score (multi_class='ovr')](https://scikit-learn.org/stable/modules/generated/sklearn.metrics.roc_auc_score.html) · [average_precision_score](https://scikit-learn.org/stable/modules/generated/sklearn.metrics.average_precision_score.html)
|
||
|
||
### 2.6 Калибровка (Expected Calibration Error, ECE)
|
||
|
||
Уверенность $\hat{p}_i = \max_k p_k^{(i)}$ должна совпадать с фактической accuracy. Разбиваем $[0,1]$ на $B$ бинов $\{b_m\}$:
|
||
|
||
$$
|
||
\mathrm{ECE} = \sum_{m=1}^{B} \frac{|b_m|}{N}\,\big|\,\mathrm{acc}(b_m) - \mathrm{conf}(b_m)\,\big|.
|
||
$$
|
||
|
||
Современные сети **переуверены** (over-confident); label smoothing и temperature scaling снижают ECE (Müller et al., 2019, [«When Does Label Smoothing Help?»](https://arxiv.org/abs/1906.02629); Guo et al., 2017, [«On Calibration of Modern Neural Networks»](https://arxiv.org/abs/1706.04599)).
|
||
|
||
### 2.7 Главная метрика при дисбалансе
|
||
|
||
При дисбалансе **accuracy вводит в заблуждение**: модель, предсказывающая только majority-класс, даёт высокую accuracy при нулевом recall на редких классах. Главными метриками выбирают **macro-F1** или **balanced accuracy** (= macro-recall, [sklearn.balanced_accuracy_score](https://scikit-learn.org/stable/modules/generated/sklearn.metrics.balanced_accuracy_score.html)), т.к. они усредняют по классам с равным весом. Различие: balanced accuracy смотрит только на recall; macro-F1 балансирует precision и recall — предпочтительна, когда важны и пропуски, и ложные срабатывания. **MCC** — надёжная вторичная сводка. Для целей Optuna в качестве `objective` рекомендуется **macro-F1** (или balanced accuracy) на валидации.
|
||
|
||
---
|
||
|
||
## 3. Loss-функции
|
||
|
||
Везде $p_k$ — softmax-вероятность, $y$ — истинный класс, $p_y$ — вероятность истинного класса.
|
||
|
||
### 3.1 Cross-Entropy (CE)
|
||
|
||
$$
|
||
\mathcal{L}_{\mathrm{CE}} = -\sum_{k=1}^{C} q_k \log p_k = -\log p_y \quad (\text{для one-hot } q).
|
||
$$
|
||
|
||
Базовый loss. В PyTorch `nn.CrossEntropyLoss` принимает **логиты** (применяет log-softmax внутри).
|
||
|
||
### 3.2 Label Smoothing CE
|
||
|
||
Smooth-цель: $q_k^{LS} = (1-\varepsilon)\,\mathbb{1}[k=y] + \dfrac{\varepsilon}{C}$ (равномерно размазывает $\varepsilon$ по всем классам).
|
||
|
||
$$
|
||
\mathcal{L}_{\mathrm{LS}} = -\sum_{k=1}^{C} q_k^{LS}\log p_k = (1-\varepsilon)\big(-\log p_y\big) + \frac{\varepsilon}{C}\sum_{k=1}^{C}\big(-\log p_k\big).
|
||
$$
|
||
|
||
Типично $\varepsilon \in [0.05, 0.1]$. Уменьшает переуверенность, улучшает калибровку и обобщение (Szegedy et al., 2016, [Inception-v3/ Rethinking the Inception Architecture](https://arxiv.org/abs/1512.00567); анализ — Müller et al., 2019, [arXiv:1906.02629](https://arxiv.org/abs/1906.02629)). Не борется напрямую с дисбалансом.
|
||
|
||
### 3.3 Focal Loss
|
||
|
||
Снижает вклад «лёгких» (хорошо классифицированных) примеров фактором $(1-p_y)^\gamma$ (Lin et al., 2017, [«Focal Loss for Dense Object Detection» / RetinaNet, arXiv:1708.02002](https://arxiv.org/abs/1708.02002)):
|
||
|
||
$$
|
||
\mathcal{L}_{\mathrm{FL}} = -\alpha_y\,(1 - p_y)^{\gamma}\,\log p_y.
|
||
$$
|
||
|
||
- $\gamma$ — focusing parameter (типично $\gamma = 2$); при $\gamma=0$ сводится к CE.
|
||
- $\alpha_y$ — балансирующий вес класса (опционально).
|
||
|
||
При $p_y \to 1$ множитель $(1-p_y)^\gamma \to 0$ → лёгкие примеры почти не дают градиента, обучение фокусируется на трудных. Хорош при дисбалансе и большом числе «лёгких» фоновых примеров.
|
||
|
||
### 3.4 Class-Balanced Loss (effective number)
|
||
|
||
Переход от «числа сэмплов» к «эффективному числу» — учёт перекрытия близких изображений (Cui et al., 2019, CVPR, [arXiv:1901.05555](https://arxiv.org/abs/1901.05555)):
|
||
|
||
$$
|
||
E_{n_c} = \frac{1 - \beta^{\,n_c}}{1 - \beta}, \qquad \beta = \frac{N-1}{N} \in [0,1).
|
||
$$
|
||
|
||
Вес класса $\propto 1/E_{n_c}$, нормированный так, что $\sum_c w_c = C$:
|
||
|
||
$$
|
||
w_c = \frac{1 - \beta}{1 - \beta^{\,n_c}}.
|
||
$$
|
||
|
||
Подставляется как мультипликатор в любой базовый loss (CB-CE, CB-Focal):
|
||
|
||
$$
|
||
\mathcal{L}_{\mathrm{CB}} = w_y \cdot \mathcal{L}_{\mathrm{base}}(p, y).
|
||
$$
|
||
|
||
При $\beta \to 0$ → нет ребалансировки; $\beta \to 1$ → вес $\propto 1/n_c$ (обратная частота). Типично $\beta \in \{0.99, 0.999, 0.9999\}$.
|
||
|
||
### 3.5 Weighted CE (class weights)
|
||
|
||
Частный случай: вес $\propto$ обратной частоте, $w_c = \dfrac{N}{C\, n_c}$ (нормировка опциональна):
|
||
|
||
$$
|
||
\mathcal{L}_{\mathrm{wCE}} = -w_y \log p_y.
|
||
$$
|
||
|
||
В PyTorch — аргумент `weight` в `nn.CrossEntropyLoss`. Простейшая мера против дисбаланса.
|
||
|
||
### 3.6 LDAM (кратко)
|
||
|
||
Label-Distribution-Aware Margin (Cao et al., 2019, NeurIPS, [arXiv:1906.07413](https://arxiv.org/abs/1906.07413)) добавляет **класс-зависимый отступ** в логит истинного класса перед softmax, увеличивая margin для редких классов:
|
||
|
||
$$
|
||
\mathcal{L}_{\mathrm{LDAM}} = -\log \frac{e^{\,z_y - \Delta_y}}{e^{\,z_y - \Delta_y} + \sum_{k \neq y} e^{z_k}}, \qquad \Delta_c = \frac{K}{n_c^{1/4}}.
|
||
$$
|
||
|
||
Маленький $n_c$ → больший margin $\Delta_c$ → строже decision boundary для minority. Обычно в связке с **DRW** (deferred re-weighting). Теоретически обоснован margin-based generalization bound.
|
||
|
||
### 3.7 Soft-target / KD-loss (кратко)
|
||
|
||
Knowledge Distillation (Hinton et al., 2015, [arXiv:1503.02531](https://arxiv.org/abs/1503.02531)): студент учится на «мягких» вероятностях teacher с температурой $T$:
|
||
|
||
$$
|
||
\mathcal{L}_{\mathrm{KD}} = (1-\lambda)\,\mathcal{L}_{\mathrm{CE}}(p^{S}, y) + \lambda\,T^2\,\mathrm{KL}\!\big(p^{T}_{/T}\,\|\,p^{S}_{/T}\big),
|
||
$$
|
||
|
||
где $p_{/T} = \mathrm{softmax}(z/T)$. Множитель $T^2$ компенсирует масштаб градиентов. Soft-target несёт «dark knowledge» о близости классов (релевантно для визуально похожих печатей).
|
||
|
||
### 3.8 Таблица «когда какой loss»
|
||
|
||
| Loss | Когда применять | Гиперпараметры | Борется с дисбалансом |
|
||
|---|---|---|---|
|
||
| CE | baseline, сбалансированные данные | — | нет |
|
||
| Label Smoothing CE | переуверенность, регуляризация, калибровка | $\varepsilon$ | нет |
|
||
| Focal | дисбаланс + много «лёгких» примеров | $\gamma$, $\alpha$ | частично (по трудности) |
|
||
| Weighted CE | умеренный дисбаланс, быстрый фикс | веса $w_c$ | да (по частоте) |
|
||
| Class-Balanced (eff. number) | сильный/long-tail дисбаланс | $\beta$, базовый loss | да (эфф. число) |
|
||
| LDAM (+DRW) | long-tail, нужен margin для minority | $K$, расписание DRW | да (margin) |
|
||
| KD / soft-target | есть teacher, похожие классы | $T$, $\lambda$ | косвенно |
|
||
|
||
---
|
||
|
||
## 4. Семплирование и борьба с дисбалансом
|
||
|
||
### 4.1 Random shuffle vs WeightedRandomSampler
|
||
|
||
- **Random shuffle** (`shuffle=True`): равномерная выборка без замены → батчи отражают исходное распределение классов → редкие классы редко попадают в батч.
|
||
- **WeightedRandomSampler**: семплирование с вероятностью $\propto$ весу объекта. Для класс-балансировки вес объекта $i$ класса $c$: $w_i = \dfrac{1}{n_c}$ (обратная частота). Тогда вероятность вытянуть любой класс одинакова → батчи приблизительно сбалансированы. Семплирование **с заменой** (`replacement=True`) → minority-объекты повторяются (фактический oversampling). [PyTorch WeightedRandomSampler](https://pytorch.org/docs/stable/data.html#torch.utils.data.WeightedRandomSampler)
|
||
|
||
### 4.2 Class-balanced batch sampling
|
||
|
||
Гарантирует фиксированное число объектов на класс в каждом батче (например, $P$ классов × $K$ объектов). Полезно для metric learning и когда нужна детерминированная балансировка батча, а не вероятностная как у WeightedRandomSampler.
|
||
|
||
### 4.3 Oversampling / undersampling
|
||
|
||
- **Oversampling** minority (дублирование / random oversampling): риск **переобучения** на повторённых картинках — смягчается аугментацией.
|
||
- **Undersampling** majority: теряется информация, но ускоряет эпоху.
|
||
- Библиотека [imbalanced-learn](https://imbalanced-learn.org/stable/) (`RandomOverSampler`, `RandomUnderSampler`) — для табличных/признаковых данных.
|
||
|
||
### 4.4 Почему SMOTE плохо подходит для сырых изображений
|
||
|
||
SMOTE (Chawla et al., 2002, [JAIR](https://www.jair.org/index.php/jair/article/view/10302)) генерирует синтетические объекты линейной интерполяцией между соседями в **признаковом пространстве**. На сырых пикселях это даёт нефизичные, «призрачные» изображения (наложение/двоение): пиксельное пространство невыпукло и не семантично — линейная смесь двух картинок печатей не является валидной картинкой. Если применять — то в пространстве эмбеддингов предобученной сети, не на пикселях. Для изображений предпочтительнее **аугментация** и sampler-балансировка.
|
||
|
||
### 4.5 Аугментация как «семплирование»
|
||
|
||
Аугментация расширяет эффективное распределение, заменяя грубое дублирование. Особенно полезна для редких классов как «умный oversampling».
|
||
|
||
| Метод | Суть | Цель | Источник |
|
||
|---|---|---|---|
|
||
| RandAugment | случайный выбор $N$ операций силой $M$ из набора | сильная регуляризация, 2 гиперпараметра | Cubuk et al., 2019, [arXiv:1909.13719](https://arxiv.org/abs/1909.13719) |
|
||
| mixup | $\tilde{x}=\lambda x_i+(1-\lambda)x_j$, $\tilde{y}=\lambda y_i+(1-\lambda)y_j$, $\lambda\sim\mathrm{Beta}(\alpha,\alpha)$ | линейная регуляризация, soft-target | Zhang et al., 2018, [arXiv:1710.09412](https://arxiv.org/abs/1710.09412) |
|
||
| CutMix | вырезает патч из $x_j$ и вставляет в $x_i$, метка $\propto$ площади | локальные признаки + регуляризация | Yun et al., 2019, [arXiv:1905.04899](https://arxiv.org/abs/1905.04899) |
|
||
|
||
mixup/cutmix дают **мягкие метки** → совместимы с CE по soft-target и сами по себе улучшают калибровку.
|
||
|
||
### 4.6 Стратифицированный split
|
||
|
||
Train/val/test делятся с сохранением пропорций классов (stratified) — иначе редкий класс может полностью отсутствовать в валидации, и метрика по нему неопределена. [sklearn StratifiedShuffleSplit / train_test_split(stratify=y)](https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.StratifiedShuffleSplit.html). Для маленьких датасетов — **StratifiedKFold**.
|
||
|
||
---
|
||
|
||
## 5. Связка loss × sampler (не дублировать компенсацию)
|
||
|
||
Дисбаланс компенсируют **либо** на уровне данных (sampler/oversampling), **либо** на уровне loss (class weights / CB / focal $\alpha$) — **но не обоими сразу с одинаковой силой**, иначе minority-классы переусиливаются: модель переобучается на них, recall редких растёт ценой обвала precision и общего качества.
|
||
|
||
| Комбинация | Эффект | Рекомендация |
|
||
|---|---|---|
|
||
| shuffle + CE | без компенсации | baseline |
|
||
| WeightedSampler + CE | компенсация в данных | OK |
|
||
| shuffle + weighted/CB/focal CE | компенсация в loss | OK |
|
||
| WeightedSampler + weighted CE | **двойная** компенсация | избегать |
|
||
| WeightedSampler + focal ($\alpha$=1) | sampler + фокус по трудности | приемлемо (разные механизмы) |
|
||
| mild sampler + mild class weights | частичная × частичная | допустимо при настройке |
|
||
|
||
Влияние на метрики: ребалансировка (любым способом) поднимает **macro-F1 / balanced accuracy / recall редких классов**, но обычно слегка снижает **overall accuracy / micro-F1**. Это ожидаемый и приемлемый trade-off при дисбалансе. Решение — какую метрику оптимизировать (см. §2.7).
|
||
|
||
---
|
||
|
||
## 6. Гиперпараметры для Optuna
|
||
|
||
| Гиперпараметр | Тип Optuna | Диапазон / значения | Комментарий |
|
||
|---|---|---|---|
|
||
| `loss_type` | categorical | `{ce, ls_ce, focal, weighted_ce, cb_focal}` | выбор семейства loss |
|
||
| `label_smoothing` | float | $[0.0, 0.2]$ | активен для ce/ls_ce |
|
||
| `focal_gamma` | float | $[0.5, 5.0]$ | активен для focal/cb_focal |
|
||
| `focal_alpha` | float | $[0.25, 1.0]$ | балансирующий вес |
|
||
| `cb_beta` | categorical / float | $\{0.99, 0.999, 0.9999\}$ | для class-balanced |
|
||
| `use_weighted_sampler` | bool (categorical) | `{True, False}` | sampler-балансировка |
|
||
| `mixup_alpha` | float | $[0.0, 0.4]$ (0 = off) | $\mathrm{Beta}(\alpha,\alpha)$ |
|
||
| `cutmix_alpha` | float | $[0.0, 1.0]$ (0 = off) | вероятность через отд. флаг |
|
||
| `randaug_N` / `randaug_M` | int | $N\in[1,3]$, $M\in[5,15]$ | сила аугментации |
|
||
|
||
Важно: задать **условную логику** (Optuna conditional / pruning), чтобы не подбирать одновременно `use_weighted_sampler=True` и `loss_type=weighted_ce` (см. §5). Целевая функция (`direction='maximize'`) — **macro-F1** или **balanced accuracy** на валидации. [Optuna docs](https://optuna.readthedocs.io/en/stable/).
|
||
|
||
---
|
||
|
||
## 7. Практические PyTorch-сниппеты
|
||
|
||
### 7.1 WeightedRandomSampler
|
||
|
||
```python
|
||
import numpy as np
|
||
import torch
|
||
from torch.utils.data import DataLoader, WeightedRandomSampler
|
||
|
||
labels = np.array(train_labels) # shape (N,), class indices
|
||
class_counts = np.bincount(labels) # n_c per class
|
||
class_weights = 1.0 / class_counts # w_c = 1 / n_c (inverse freq)
|
||
sample_weights = class_weights[labels] # per-sample weight
|
||
|
||
sampler = WeightedRandomSampler(
|
||
weights=torch.as_tensor(sample_weights, dtype=torch.double),
|
||
num_samples=len(sample_weights), # one epoch length
|
||
replacement=True, # required for oversampling
|
||
)
|
||
# NB: shuffle must be False when a sampler is passed
|
||
loader = DataLoader(train_ds, batch_size=64, sampler=sampler)
|
||
```
|
||
|
||
### 7.2 Focal Loss (multi-class)
|
||
|
||
```python
|
||
import torch
|
||
import torch.nn as nn
|
||
import torch.nn.functional as F
|
||
|
||
class FocalLoss(nn.Module):
|
||
"""Multi-class focal loss; expects raw logits."""
|
||
def __init__(self, gamma: float = 2.0, alpha: torch.Tensor | None = None):
|
||
super().__init__()
|
||
self.gamma = gamma
|
||
self.alpha = alpha # per-class weights, shape (C,)
|
||
|
||
def forward(self, logits: torch.Tensor, target: torch.Tensor) -> torch.Tensor:
|
||
logp = F.log_softmax(logits, dim=1) # (B, C)
|
||
logp_t = logp.gather(1, target[:, None]).squeeze(1) # log p_y
|
||
p_t = logp_t.exp() # p_y
|
||
loss = -((1 - p_t) ** self.gamma) * logp_t
|
||
if self.alpha is not None:
|
||
loss = self.alpha.to(logits.device)[target] * loss
|
||
return loss.mean()
|
||
```
|
||
|
||
### 7.3 Label smoothing в nn.CrossEntropyLoss
|
||
|
||
```python
|
||
import torch.nn as nn
|
||
|
||
# Built-in since PyTorch 1.10; optional per-class weight for imbalance.
|
||
criterion = nn.CrossEntropyLoss(label_smoothing=0.1, weight=class_weight_tensor)
|
||
loss = criterion(logits, target) # logits: raw (B, C)
|
||
```
|
||
|
||
### 7.4 Расчёт macro-F1 / balanced accuracy (sklearn)
|
||
|
||
```python
|
||
from sklearn.metrics import f1_score, balanced_accuracy_score, classification_report
|
||
|
||
y_pred = logits.argmax(dim=1).cpu().numpy()
|
||
y_true = target.cpu().numpy()
|
||
|
||
macro_f1 = f1_score(y_true, y_pred, average="macro")
|
||
bal_acc = balanced_accuracy_score(y_true, y_pred) # = macro-recall
|
||
|
||
# Per-class breakdown (precision / recall / F1 / support):
|
||
print(classification_report(y_true, y_pred, digits=4))
|
||
```
|
||
|
||
---
|
||
|
||
## Источники
|
||
|
||
- Lin et al., 2017 — Focal Loss / RetinaNet: [arXiv:1708.02002](https://arxiv.org/abs/1708.02002)
|
||
- Cui et al., 2019 — Class-Balanced Loss (effective number): [arXiv:1901.05555](https://arxiv.org/abs/1901.05555)
|
||
- Cao et al., 2019 — LDAM: [arXiv:1906.07413](https://arxiv.org/abs/1906.07413)
|
||
- Szegedy et al., 2016 — Label Smoothing (Inception-v3): [arXiv:1512.00567](https://arxiv.org/abs/1512.00567)
|
||
- Müller et al., 2019 — When Does Label Smoothing Help?: [arXiv:1906.02629](https://arxiv.org/abs/1906.02629)
|
||
- Guo et al., 2017 — Calibration of Modern Neural Networks (ECE): [arXiv:1706.04599](https://arxiv.org/abs/1706.04599)
|
||
- Hinton et al., 2015 — Knowledge Distillation: [arXiv:1503.02531](https://arxiv.org/abs/1503.02531)
|
||
- Zhang et al., 2018 — mixup: [arXiv:1710.09412](https://arxiv.org/abs/1710.09412)
|
||
- Yun et al., 2019 — CutMix: [arXiv:1905.04899](https://arxiv.org/abs/1905.04899)
|
||
- Cubuk et al., 2019 — RandAugment: [arXiv:1909.13719](https://arxiv.org/abs/1909.13719)
|
||
- Chawla et al., 2002 — SMOTE: [JAIR](https://www.jair.org/index.php/jair/article/view/10302)
|
||
- scikit-learn — [Model evaluation metrics](https://scikit-learn.org/stable/modules/model_evaluation.html), [balanced_accuracy_score](https://scikit-learn.org/stable/modules/generated/sklearn.metrics.balanced_accuracy_score.html), [matthews_corrcoef](https://scikit-learn.org/stable/modules/generated/sklearn.metrics.matthews_corrcoef.html)
|
||
- [imbalanced-learn](https://imbalanced-learn.org/stable/) · [PyTorch data sampling](https://pytorch.org/docs/stable/data.html) · [Optuna](https://optuna.readthedocs.io/en/stable/)
|