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

380 lines
28 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.
# Задача классификации изображений: метрики, 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/)