Выбор архитектуры сегментации изображений — всегда компромисс между точностью, скоростью и объёмом размеченных данных. Часто клиенты приходят с датасетом в 200 снимков КТ и хотят mIoU >0.9, а на деле U-Net справляется, а SegFormer не хватает данных. Или наоборот: промышленный поток с 5000 изображений, где SegFormer даёт +8% mIoU, но latency критична. Мы накопили опыт обучения моделей сегментации для медицинских (сегментация органов, сосудов, опухолей) и промышленных задач (дефекты на конвейере, трещины, контроль качества). За годы работы мы выполнили более 50 проектов по компьютерному зрению, и в каждом случае выбор архитектуры определялся тремя факторами: объёмом данных, требуемой точностью контуров и допустимой задержкой инференса. Средняя экономия на инференсе после оптимизации — до 60% операционных затрат.
U-Net и SegFormer — наиболее популярные архитектуры, каждая со своими сильными сторонами. Первый устойчив к малым данным, второй — лидер по mIoU на больших датасетах. SAM2 же добавляет интерактивность и fine-tuning с минимальной разметкой.
Какую архитектуру выбрать: U-Net, SegFormer или SAM?
U-Net и его вариации — медицина и промышленность
U-Net остаётся стандартом для медицинской сегментации не из-за качества (SegFormer лучше), а из-за устойчивости при малом датасете (100–500 изображений) и интерпретируемости. Мы рекомендуем U-Net++ для задач с тонкими структурами (сосуды, трещины).
import torch
import torch.nn as nn
import segmentation_models_pytorch as smp
def build_unet_model(
architecture: str = 'Unet', # 'Unet', 'UnetPlusPlus', 'MAnet'
encoder: str = 'efficientnet-b4', # backbone
encoder_weights: str = 'imagenet',
num_classes: int = 1, # 1 для бинарной сегментации
in_channels: int = 3
) -> nn.Module:
model = getattr(smp, architecture)(
encoder_name=encoder,
encoder_weights=encoder_weights,
in_channels=in_channels,
classes=num_classes,
activation=None # применяем sigmoid/softmax отдельно
)
return model
# Loss для медицинской сегментации с малым датасетом
class CombinedLoss(nn.Module):
def __init__(self, dice_weight: float = 0.5, bce_weight: float = 0.5):
super().__init__()
self.dice_weight = dice_weight
self.bce_weight = bce_weight
self.bce = nn.BCEWithLogitsLoss()
self.dice = smp.losses.DiceLoss(mode='binary', from_logits=True)
def forward(self, preds: torch.Tensor,
targets: torch.Tensor) -> torch.Tensor:
return (self.bce_weight * self.bce(preds, targets) +
self.dice_weight * self.dice(preds, targets))
SegFormer — semantic segmentation с акцентом на точность
SegFormer-B4 на большинстве задач semantic segmentation обходит U-Net при датасете >1000 изображений. На ADE20K он показывает mIoU 50.3%, что на 8 пунктов выше U-Net с EfficientNetB4. Для задач с высокими требованиями к детализации контуров мы используем SegFormer-B5 с полиномиальным затуханием learning rate.
from transformers import SegformerForSemanticSegmentation, SegformerConfig
import torch
import torch.nn.functional as F
def train_segformer(
num_labels: int,
id2label: dict,
label2id: dict,
pretrained_model: str = 'nvidia/mit-b4',
learning_rate: float = 6e-5,
num_epochs: int = 50
) -> SegformerForSemanticSegmentation:
model = SegformerForSemanticSegmentation.from_pretrained(
pretrained_model,
num_labels=num_labels,
id2label=id2label,
label2id=label2id,
ignore_mismatched_sizes=True
)
optimizer = torch.optim.AdamW(
model.parameters(),
lr=learning_rate,
weight_decay=0.01
)
# Poly LR decay — стандарт для semantic segmentation
scheduler = torch.optim.lr_scheduler.PolynomialLR(
optimizer,
total_iters=num_epochs,
power=0.9
)
return model, optimizer, scheduler
def segformer_inference(
model: SegformerForSemanticSegmentation,
pixel_values: torch.Tensor, # (B, 3, H, W)
target_size: tuple = None # (H, W) оригинального изображения
) -> torch.Tensor:
"""
SegFormer выдаёт логиты в 4x уменьшенном разрешении.
Нужен билинейный апскейл до оригинального размера.
"""
outputs = model(pixel_values=pixel_values)
logits = outputs.logits # (B, num_labels, H/4, W/4)
if target_size is not None:
logits = F.interpolate(
logits,
size=target_size,
mode='bilinear',
align_corners=False
)
return logits
SAM2 fine-tuning для кастомных доменов
SAM2 из коробки не знает специфические классы (микроскопия, промышленные дефекты). Fine-tuning только decoder mask head — эффективный подход. При замороженном encoder обучается всего ~4M параметров из 224M, что позволяет обучить модель на одном GPU за сутки.
from sam2.build_sam import build_sam2
import torch
def finetune_sam2_decoder(
checkpoint_path: str,
num_epochs: int = 30,
learning_rate: float = 1e-4,
freeze_image_encoder: bool = True, # encoder тяжёлый — замораживаем
freeze_prompt_encoder: bool = True
) -> torch.nn.Module:
sam2 = build_sam2(
'sam2_hiera_large.yaml',
checkpoint_path,
device='cuda'
)
# Замораживаем всё кроме mask decoder
for param in sam2.image_encoder.parameters():
param.requires_grad = not freeze_image_encoder
for param in sam2.prompt_encoder.parameters():
param.requires_grad = not freeze_prompt_encoder
# Только mask decoder обучаем
for param in sam2.mask_decoder.parameters():
param.requires_grad = True
trainable_params = sum(
p.numel() for p in sam2.parameters() if p.requires_grad
)
print(f'Trainable parameters: {trainable_params:,}')
# Для SAM2-Large с frozen encoder: ~4M из 224M
optimizer = torch.optim.AdamW(
filter(lambda p: p.requires_grad, sam2.parameters()),
lr=learning_rate,
weight_decay=1e-4
)
return sam2, optimizer
Почему fine-tuning SAM эффективнее обучения с нуля?
Предобученный image encoder SAM2 содержит обобщённые признаки форм и границ, которые переносятся на новый домен. Это снижает потребность в данных в 5–10 раз по сравнению с обучением U-Net с нуля. Кроме того, SAM поддерживает интерактивную сегментацию — можно дообучить модель под конкретные промпты (точки, боксы).
Пример оптимизации инференса
После квантизации INT8 latency снижается в 2-3 раза при падении mIoU не более 1%. В одном проекте мы сократили стоимость инференса в 3 раза.Процесс работы: пошагово
- Анализ данных и прототипирование. Мы оцениваем качество разметки, распределение классов, возможные артефакты. Выбираем архитектуру и формат аугментации. Результат — техническое задание с прогнозом метрик.
- Подготовка пайплайна обучения. Сборка препроцессинга, аугментация (Albumentations, torchvision), логирование в MLflow. Для медицинских задач используем комбинированный loss (Dice + Focal).
- Обучение и эксперименты. Проводим grid search по learning rate, weight decay, размеру батча. Фиксируем лучшие чекпоинты. Для SegFormer применяем polynomial LR scheduler, для U-Net — ReduceLROnPlateau.
- Оптимизация инференса. Экспорт в ONNX, квантизация INT8, профилирование на целевой видеокарте. Добиваемся latency p99 не выше порога заказчика.
- Интеграция и документация. Разворачиваем модель в Docker-контейнере, готовим REST/gRPC API. Пишем model card: описание архитектуры, метрики на тесте, ограничения.
Метрики сегментации
| Метрика | Формула | Когда использовать |
|---|---|---|
| mIoU | mean(TP/(TP+FP+FN)) по классам | Semantic segmentation |
| Dice | 2TP/(2TP+FP+FN) | Медицинская, дисбаланс |
| Boundary IoU | IoU только на границах | Точность контуров |
| PQ (Panoptic Quality) | SQ × RQ | Panoptic segmentation |
Сравнение архитектур
| Модель | mIoU ADE20K | Latency (640px) | VRAM обучение | Малый датасет |
|---|---|---|---|---|
| U-Net (EfficientB4) | 42.1 | 8ms | 6GB | Отлично |
| SegFormer-B2 | 46.5 | 15ms | 8GB | Хорошо |
| SegFormer-B4 | 50.3 | 28ms | 12GB | Хорошо |
| Mask2Former | 56.1 | 45ms | 16GB | Плохо |
| SAM2 (finetuned) | — | 60ms | 20GB | Отлично |
Что входит в работу
- Аналитика и прототип: аудит данных, выбор архитектуры, оценка достижимой точности.
- Разработка пайплайна: препроцессинг, аугментация, обучение с логированием в MLflow.
- Оптимизация инференса: экспорт в ONNX/TensorRT, квантизация INT8, снижение latency до p99.
- Интеграция API: REST/gRPC эндпоинт, контейнеризация Docker, деплой в Kubernetes.
- Документация: model card, инструкция по повторению эксперимента, описание метрик.
- Обучение команды: воркшоп по работе с моделью и поддержке.
Сроки
| Задача | Срок |
|---|---|
| Fine-tuning U-Net (готовые данные) | 2–3 недели |
| SAM2 fine-tuning под домен | 3–5 недель |
| Полная система semantic segmentation | 5–9 недель |
Получите консультацию по выбору архитектуры — это бесплатно. Если у вас есть датасет, закажите аудит данных: мы оценим достижимую точность и подберём архитектуру.







