Детекция и сегментация
~22 мин

Семантическая сегментация

Попиксельная классификация: FCN, U-Net, DeepLab. Encoder-decoder архитектуры, atrous convolution.

Семантическая сегментация — класс для каждого пикселя

Detection даёт bounding boxes, но иногда нужно точнее. Автопилоту нужно знать не «где-то тут дорога», а точную границу проезжей части. Врачу — точный контур опухоли на МРТ. Семантическая сегментация присваивает каждому пикселю класс: дорога, тротуар, машина, человек, небо.

Семантическая сегментация: входное изображение → encoder → decoder → маска классов
Encoder-decoder архитектура сегментации: encoder сжимает пространственное разрешение, decoder восстанавливает до исходного размера с пиксельной классификацией

Формально: вход — изображение (H×W×3), выход — карта (H×W) с class ID для каждого пикселя. Это dense prediction: модель должна выдать столько же «ответов», сколько пикселей.

FCN — первая end-to-end сегментация

Fully Convolutional Networks (FCN, 2014) — первый подход к end-to-end сегментации. Идея: заменить FC-слои классификатора (VGG/ResNet) на свёрточные → выход — feature map с числом каналов = числу классов. Upsampling (deconvolution) возвращает пространственное разрешение.

Проблема FCN: потеря деталей при downsampling. Upsampled feature map — грубый, размытые границы. Skip connections от ранних слоёв частично решают проблему (FCN-8s), но качество всё ещё ограничено.

U-Net — encoder-decoder с skip connections

U-Net (2015) — архитектура для biomedical segmentation, ставшая стандартом. Симметричная форма буквы U:

  • Encoder (contracting path): стандартный CNN — conv + pooling, пространственное разрешение падает, число каналов растёт. Захватывает контекст.
  • Decoder (expanding path): transposed convolution (upsampling), разрешение растёт, каналы падают. Восстанавливает пространственную информацию.
  • Skip connections: конкатенация feature maps из encoder в соответствующий уровень decoder. Это ключ: encoder знает «что», decoder — «где», skip connections объединяют.
import torch
import torch.nn as nn

class UNetBlock(nn.Module):
    def __init__(self, in_ch, out_ch):
        super().__init__()
        self.conv = nn.Sequential(
            nn.Conv2d(in_ch, out_ch, 3, padding=1),
            nn.BatchNorm2d(out_ch),
            nn.ReLU(inplace=True),
            nn.Conv2d(out_ch, out_ch, 3, padding=1),
            nn.BatchNorm2d(out_ch),
            nn.ReLU(inplace=True),
        )
    def forward(self, x):
        return self.conv(x)

# Encoder: 3→64→128→256→512→1024
# Decoder: 1024→512→256→128→64→num_classes
# Skip: encoder[i] concat с decoder[i]
# Output: (batch, num_classes, H, W)

Вариации U-Net: U-Net++ (nested skip connections), Attention U-Net (attention gates в skip connections), nnU-Net (автоматическая конфигурация для медицинских задач — state-of-the-art в medical segmentation).

DeepLab — atrous convolution и ASPP

Проблема: pooling теряет пространственную информацию. DeepLab (Google) предложил atrous (dilated) convolution — свёртка с «дырками». Dilation rate=2: ядро 3×3, но receptive field 5×5. Расширяет receptive field без потери разрешения и без увеличения параметров.

ASPP (Atrous Spatial Pyramid Pooling) — параллельные atrous convolutions с разными dilation rates (6, 12, 18) + global average pooling. Захватывает контекст на разных масштабах. Как Inception module, но для сегментации.

DeepLab v3+ (2018) — текущий стандарт: 1. Encoder: backbone (ResNet/Xception) с atrous convolution + ASPP 2. Decoder: простой — upsample 4× + concat с low-level features + 3×3 conv + upsample 4× Проще U-Net-декодера, но работает не хуже благодаря мощному encoder.

Loss функции для сегментации

Стандартный Cross-Entropy работает, но есть проблема: class imbalance (фон >> объекты). Решения:

  • Weighted Cross-Entropy — вес каждого класса обратно пропорционален его частоте
  • Dice Loss — 1 - 2|A∩B|/(|A|+|B|). Напрямую оптимизирует метрику Dice. Хорош для бинарной сегментации.
  • Focal Loss — (1-p)^γ × CE. Фокусируется на трудных пикселях.
  • Combo: CE + Dice — стандартная комбинация в medical imaging.
import torch
import torch.nn.functional as F

def dice_loss(pred: torch.Tensor, target: torch.Tensor, smooth=1.0):
    """Dice loss для бинарной сегментации."""
    pred = torch.sigmoid(pred)
    pred_flat = pred.view(-1)
    target_flat = target.view(-1)
    intersection = (pred_flat * target_flat).sum()
    return 1 - (2. * intersection + smooth) / (
        pred_flat.sum() + target_flat.sum() + smooth
    )

Segment Anything Model (SAM)

SAM (Meta, 2023) — foundation model для сегментации. Обучен на 1 млрд масок (SA-1B dataset). Работает в zero-shot: любой объект, любой домен, без fine-tuning. Вход: изображение + промпт (точка, bbox, текст). Выход: маска. Революционная модель, как GPT для NLP — но для сегментации.

🎯 На собеседовании

Ключевые вопросы

U-Net vs DeepLab — в чём разница? U-Net: симметричный encoder-decoder, skip connections (concat). DeepLab: мощный encoder с atrous conv + простой decoder. U-Net популярнее в медицине, DeepLab — в autonomous driving. • Что такое atrous/dilated convolution? Свёртка с «дырками». Увеличивает receptive field без pooling/stride, сохраняет разрешение. • Зачем skip connections в U-Net? Encoder теряет пространственную информацию при downsampling. Skip connections передают high-resolution фичи в decoder для восстановления деталей. • Dice Loss vs Cross-Entropy? CE — per-pixel, страдает от class imbalance. Dice — region-based, оптимизирует overlap между prediction и GT. Комбинация CE + Dice — стандарт.