Разработка системы классификации изображений
Классификация изображений — присвоение одного или нескольких классов каждому изображению. Практические применения: сортировка медицинских снимков по патологиям, разметка e-commerce каталога по категориям, фильтрация пользовательского контента, классификация дефектов на производстве. Задача решена на уровне «выше человека» для стандартных бенчмарков ещё в 2015 году, но правильная адаптация под конкретный домен требует методичного подхода.
Выбор архитектуры
Для большинства задач оптимальный выбор — EfficientNet-B4 или ConvNeXt-Tiny: хороший баланс точности и скорости инференса.
| Архитектура | Top-1 ImageNet | Параметры | Latency (T4 GPU) |
|---|---|---|---|
| EfficientNet-B0 | 77.1% | 5.3M | 3.5 ms |
| EfficientNet-B4 | 82.9% | 19M | 9.2 ms |
| ConvNeXt-Tiny | 82.1% | 28M | 7.8 ms |
| ViT-B/16 | 81.8% | 86M | 12.1 ms |
| EfficientNet-B7 | 84.4% | 66M | 28 ms |
Для edge-устройств (Raspberry Pi, Jetson Nano): MobileNetV3, EfficientNet-Lite, YOLO11-cls.
Трансфер лернинг и fine-tuning
Обучение с нуля требует миллионы примеров. Fine-tuning предобученной модели даёт хорошие результаты с сотнями изображений на класс.
import timm
import torch.nn as nn
def build_classifier(num_classes: int,
pretrained_model: str = 'efficientnet_b4'):
model = timm.create_model(
pretrained_model,
pretrained=True,
num_classes=0 # убираем оригинальный classifier head
)
embedding_dim = model.num_features # 1792 для B4
# Замораживаем backbone на первых эпохах
for param in model.parameters():
param.requires_grad = False
# Кастомный классификационный head
classifier = nn.Sequential(
nn.Linear(embedding_dim, 512),
nn.GELU(),
nn.Dropout(0.3),
nn.Linear(512, num_classes)
)
model.classifier = classifier
return model
Стратегия обучения: 5 эпох с замороженным backbone → разморозить последние 2 блока → 10 эпох с LR 10x меньше → полная разморозка → ещё 10 эпох с cosine schedule.
Работа с дисбалансом классов
Реальные датасеты редко сбалансированы. Стратегии:
- Weighted random sampler: частота семплирования обратно пропорциональна размеру класса
-
Focal Loss:
FL(p) = -(1-p)^γ · log(p), фокусирует обучение на сложных примерах (γ=2 — стандартное значение) - Oversampling редких классов: albumentations-аугментация только для underrepresented классов
-
Class-weighted cross-entropy: веса классов пропорциональны
1 / class_frequency
Многоклассовая vs многолейбловая классификация
Многоклассовая (один класс на изображение): softmax + cross-entropy. Пример: тип животного.
Многолейбловая (несколько классов одновременно): sigmoid + binary cross-entropy. Пример: теги на фото (природа + горы + закат). Порог срабатывания подбирается отдельно по F1 для каждого класса.
Метрики оценки
- Top-1 / Top-5 Accuracy — для сбалансированных датасетов
- Macro-averaged F1 — для дисбаланса
- Cohen's Kappa — для медицинских задач
- AUC-ROC per class — для многолейбловой классификации
Производительность и деплой
Для API-сервиса: ONNX export + ONNX Runtime → latency 5–15ms на CPU (batch=1). Для GPU: TorchServe с dynamic batching. Для мобильных: Core ML (iOS), TFLite (Android).
| Сложность задачи | Срок |
|---|---|
| 2–10 классов, 1000+ фото/класс | 1–2 недели |
| 50+ классов или сложный домен | 3–5 недель |
| Иерархическая классификация, edge деплой | 5–8 недель |







