Основы CV
~25 мин

Классические архитектуры CNN

Эволюция CNN: LeNet → AlexNet → VGG → GoogLeNet/Inception → ResNet. Skip connections и batch normalization.

Эволюция CNN: от LeNet до ResNet

История CNN-архитектур — это история ImageNet Challenge (ILSVRC). Каждый год — новый прорыв в архитектуре, снижение top-5 error с 26% (2011) до 3.5% (2015). Понимание этой эволюции — обязательная база для CV-инженера: каждая архитектура ввела концепцию, которая используется до сих пор.

LeNet-5 (1998) — с чего всё началось

Yann LeCun создал LeNet для распознавания рукописных цифр (MNIST). Архитектура: 2 свёрточных слоя → 2 FC слоя → softmax. Размер: ~60K параметров. По современным меркам — крошечная, но это первая CNN, которая работала в продакшне (распознавание чеков в банках). Заложила все ключевые идеи: свёртки, pooling, иерархия признаков.

Архитектура LeNet-5: свёрточные слои, subsampling, полносвязные слои
LeNet-5: первая успешная CNN. Conv → Pool → Conv → Pool → FC → FC → Output. Источник: d2l.ai (CC BY-SA 4.0)

AlexNet (2012) — начало революции

ImageNet 2012: AlexNet побеждает с top-5 error 16.4% (у второго места — 26%). Это момент, когда deep learning стал mainstream. Что нового:

  • ReLU вместо sigmoid/tanh — быстрее обучение, нет vanishing gradients
  • GPU-тренировка — два GTX 580 (по 3GB VRAM каждая). Модель буквально разделена на две GPU
  • Dropout — регуляризация FC-слоёв (p=0.5). Предотвращает overfitting
  • Data augmentation — random crops, horizontal flips, color jitter. Впервые в таком масштабе
  • Архитектура: 5 conv → 3 FC, ~60M параметров. Фильтры: 11×11 (conv1), 5×5 (conv2), 3×3 (conv3-5)

VGG (2014) — глубина решает

VGGNet (Oxford) показал: глубина сети важнее сложности фильтров. Простая идея: используй только 3×3 свёртки, но ставь их много. VGG-16: 16 слоёв, 138M параметров. VGG-19: 19 слоёв.

Ключевой инсайт: два слоя 3×3 имеют receptive field 5×5, но меньше параметров и две нелинейности. VGG стала стандартным feature extractor для задач transfer learning (до ResNet).

Проблема VGG

138M параметров, ~530MB в памяти. Тяжёлая для инференса. FC-слои содержат 90% параметров. Современные сети заменили FC на Global Average Pooling.

GoogLeNet / Inception (2014) — параллельные пути

Google предложил Inception module: вместо одного фильтра — параллельные ветки с разными kernel sizes (1×1, 3×3, 5×5) + max pooling. Выходы конкатенируются по каналам. Модель сама выбирает масштаб фич.

Трюк: 1×1 bottleneck перед 3×3 и 5×5 свёртками снижает число каналов → меньше вычислений. GoogLeNet: 22 слоя, но всего 6.8M параметров (в 20 раз меньше VGG) при лучшем качестве.

Inception module: параллельные ветки 1×1, 3×3, 5×5 и max pooling
Inception module: параллельные свёртки разных масштабов + 1×1 bottleneck для снижения вычислений. Источник: d2l.ai (CC BY-SA 4.0)
  • Inception v2/v3 — factorized convolutions: 5×5 → два 3×3, 7×7 → 1×7 + 7×1
  • Inception v4 — комбинация Inception + residual connections

ResNet (2015) — skip connections меняют всё

Главная проблема глубоких сетей: degradation — добавление слоёв ухудшает качество (не из-за overfitting, а из-за сложности оптимизации). ResNet решил это skip connections (residual connections):

Вместо H(x) = F(x) учим H(x) = F(x) + x. Модель учит «остаток» (residual). Если слой не нужен, F(x) → 0, и H(x) = x (identity). Это делает оптимизацию trivial — сети можно углублять без degradation.

Residual block: вход → Conv → BN → ReLU → Conv → BN → + skip connection → ReLU
Residual block: F(x) + x. Skip connection позволяет градиенту течь напрямую к ранним слоям. Источник: d2l.ai (CC BY-SA 4.0)
import torch
import torch.nn as nn

class ResidualBlock(nn.Module):
    """Базовый residual block (ResNet-18/34)."""
    def __init__(self, channels):
        super().__init__()
        self.conv1 = nn.Conv2d(channels, channels, 3, padding=1, bias=False)
        self.bn1 = nn.BatchNorm2d(channels)
        self.conv2 = nn.Conv2d(channels, channels, 3, padding=1, bias=False)
        self.bn2 = nn.BatchNorm2d(channels)
        self.relu = nn.ReLU(inplace=True)

    def forward(self, x):
        identity = x                  # skip connection
        out = self.relu(self.bn1(self.conv1(x)))
        out = self.bn2(self.conv2(out))
        out += identity               # residual: F(x) + x
        return self.relu(out)

Варианты ResNet:

  • ResNet-18/34 — basic blocks (два 3×3 conv)
  • ResNet-50/101/152 — bottleneck blocks (1×1 → 3×3 → 1×1, снижают число каналов в 4 раза внутри блока)
  • ResNeXt — grouped convolutions внутри bottleneck (параллельные пути, как в Inception)
  • ResNet-D, ResNet-RS — modern improvements (антиалиасинг, улучшенный stem, cosine LR)

Bottleneck block

1×1 conv (256 → 64) → 3×3 conv (64 → 64) → 1×1 conv (64 → 256). Bottleneck сжимает каналы в 4 раза → вычисления 3×3 свёртки дешёвые. ResNet-50 с bottleneck быстрее ResNet-34 с basic blocks при лучшем качестве.

EfficientNet (2019) — баланс глубины, ширины и разрешения

Tan & Le (Google) показали: сбалансированное масштабирование глубины, ширины и разрешения лучше, чем увеличение одного параметра. EfficientNet-B0 → B7: compound scaling с коэффициентом φ. При тех же FLOPS — лучше accuracy, чем ResNet/Inception.

Базовый блок — MBConv (Mobile Inverted Bottleneck): depthwise separable convolution + SE attention + skip connection. EfficientNet-B0: 5.3M параметров, 77.1% top-1 на ImageNet. Для сравнения: ResNet-50 — 25.6M параметров, 76.0%.

Как выбрать backbone

На практике backbone (feature extractor) — это pretrained модель, чьи веса фиксируют или fine-tune. Выбор зависит от задачи:

  • Быстрый inference: MobileNetV3, EfficientNet-B0 (мобильные устройства, edge)
  • Баланс speed/quality: ResNet-50, EfficientNet-B3-B5 (production серверы)
  • Максимальное качество: ConvNeXt-L, Swin-L, ViT-L (если GPU не лимитирует)
  • Detection/Segmentation: ResNet-50 + FPN, Swin Transformer (backbone + neck для multi-scale)

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

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

Что такое skip connection и зачем? Shortcut из входа в выход блока: H(x) = F(x) + x. Решает проблему degradation в глубоких сетях. Градиенты текут напрямую через shortcut. • Чем bottleneck отличается от basic block? Bottleneck: 1×1→3×3→1×1, сжимает каналы внутри. Меньше FLOPs при тех же каналах. Используется в ResNet-50+. • Зачем 1×1 convolution? Изменение числа каналов без пространственного контекста. Bottleneck (снижение/повышение каналов), channel mixing. • Как VGG отличается от ResNet? VGG — просто стек conv+pool, нет skip connections, 138M параметров, деградация при углублении. ResNet — residual blocks, 25M параметров (ResNet-50), масштабируется до 150+ слоёв.