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

Основы CNN

Свёрточные нейросети: convolution, pooling, feature maps, receptive field, stride и padding.

CNN — как нейросети «видят» изображения

Fully connected сеть на изображении 224×224×3 = 150K входов. Один hidden layer с 1024 нейронами — 150M параметров. Это не масштабируется. Свёрточные нейросети (CNN) решают проблему тремя идеями: локальные связи (смотрим на маленький patch, а не на всё изображение), разделение весов (один фильтр применяется ко всем позициям) и иерархия фич (простые → сложные).

Архитектура CNN: свёрточные слои, пулинг и полносвязные слои
Типичная архитектура CNN: входное изображение → свёрточные блоки (Conv + ReLU + Pool) → flatten → FC → выход
Операция кросс-корреляции (свёртки): фильтр скользит по входному тензору
Кросс-корреляция: ядро (kernel) скользит по входу и вычисляет скалярное произведение с каждым patch-ем. Источник: d2l.ai (CC BY-SA 4.0)

Свёртка (Convolution)

Свёртка — ядро CNN. Фильтр (kernel) размера k×k скользит по изображению и вычисляет скалярное произведение с каждым patch-ем. Результат — feature map (карта признаков). Один фильтр = один признак: горизонтальные линии, вертикальные линии, углы, текстуры.

import torch.nn as nn

# Свёрточный слой: 3 входных канала (RGB), 64 фильтра, ядро 3×3
conv = nn.Conv2d(in_channels=3, out_channels=64, kernel_size=3, padding=1)
# Input:  (batch, 3, 224, 224)
# Output: (batch, 64, 224, 224) — 64 feature maps
# Параметры: 64 × (3 × 3 × 3 + 1) = 1,792  (vs 150M у FC!)

Ключевые параметры свёртки:

  • Kernel size — размер фильтра. 3×3 — стандарт (VGG показал, что стек 3×3 лучше одного 7×7). 1×1 — «pointwise» свёртка для смешивания каналов.
  • Stride — шаг скольжения. Stride=1 → размер сохраняется. Stride=2 → размер /2 (downsampling без pooling).
  • Padding — дополнение нулями по краям. Padding=1 при kernel=3 → размер сохраняется (same padding). Padding=0 → размер уменьшается (valid padding).
  • Dilation — «раздутая» свёртка. Dilation=2 при kernel 3×3 → эффективный receptive field 5×5, но всего 9 параметров. Используется в DeepLab для сегментации.

Формула выходного размера: H_out = (H_in + 2×padding - dilation×(kernel-1) - 1) / stride + 1

Pooling

Pooling уменьшает пространственное разрешение feature map, сохраняя важную информацию. Два основных типа:

  • Max Pooling — берёт максимум в окне. Сохраняет самые яркие активации. MaxPool2d(2, 2) → размер /2.
  • Average Pooling — берёт среднее. Мягче max pooling, меньше теряет контекст.
  • Global Average Pooling (GAP) — среднее по всему feature map → один вектор. Заменяет fully connected слои в конце сети (ResNet, EfficientNet). Нет параметров, меньше overfitting.

Современный тренд: вместо MaxPool используют stride=2 в свёртке — учится, какую информацию сохранять (а не hardcoded max). ResNet, ConvNeXt, EfficientNet — все перешли на strided convolutions.

Feature Maps и иерархия признаков

Ключевое свойство CNN — иерархическое извлечение признаков:

  • Ранние слои (conv1, conv2) — простые паттерны: грани, углы, текстуры, цветовые градиенты.
  • Средние слои (conv3, conv4) — части объектов: колёса, глаза, окна, буквы.
  • Глубокие слои (conv5+) — целые объекты и сцены: лица, машины, здания.

Каждый feature map — это «ответ» одного фильтра на все позиции изображения. Conv1 с 64 фильтрами даёт 64 feature maps. Conv5 с 512 фильтрами — 512 feature maps. Чем глубже — тем абстрактнее признаки и тем больше каналов.

Receptive Field

Receptive field — область исходного изображения, которая влияет на один пиксель feature map. Это критический параметр: если receptive field слишком мал, нейрон не «видит» весь объект.

Receptive field растёт с глубиной сети. Стек из N свёрток 3×3 имеет receptive field (2N+1)×(2N+1). Два слоя 3×3 → RF = 5×5 (как один 5×5, но меньше параметров и больше нелинейностей). Pooling и stride увеличивают RF мультипликативно.

Почему 3×3 — золотой стандарт

VGG (2014) показал: стек из двух 3×3 свёрток имеет тот же receptive field, что один 5×5, но меньше параметров (2 × 3² = 18 vs 5² = 25) и две нелинейности вместо одной. С тех пор 3×3 — стандарт почти во всех архитектурах.

Типичная архитектура CNN

import torch.nn as nn

class SimpleCNN(nn.Module):
    def __init__(self, num_classes=10):
        super().__init__()
        self.features = nn.Sequential(
            # Block 1: 3 → 32 channels, /2
            nn.Conv2d(3, 32, 3, padding=1),
            nn.BatchNorm2d(32),
            nn.ReLU(),
            nn.MaxPool2d(2, 2),              # 224 → 112

            # Block 2: 32 → 64 channels, /2
            nn.Conv2d(32, 64, 3, padding=1),
            nn.BatchNorm2d(64),
            nn.ReLU(),
            nn.MaxPool2d(2, 2),              # 112 → 56

            # Block 3: 64 → 128 channels, /2
            nn.Conv2d(64, 128, 3, padding=1),
            nn.BatchNorm2d(128),
            nn.ReLU(),
            nn.AdaptiveAvgPool2d(1),         # 56 → 1 (GAP)
        )
        self.classifier = nn.Linear(128, num_classes)

    def forward(self, x):
        x = self.features(x)       # (batch, 128, 1, 1)
        x = x.flatten(1)           # (batch, 128)
        return self.classifier(x)  # (batch, num_classes)

Паттерн: conv → batchnorm → relu → downsample, повторяем. Число каналов растёт (32 → 64 → 128 → ...), пространственное разрешение падает. В конце — GAP + linear classifier. Это скелет любой CNN.

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

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

Зачем свёртки, а не FC? Локальные связи + shared weights → в 1000x меньше параметров. Inductive bias: пространственная локальность и трансляционная эквивариантность. • Что такое receptive field? Область входа, влияющая на один пиксель выхода. Растёт с глубиной. Если RF < объект → модель не «видит» объект целиком. • 1×1 свёртка — зачем? Смешивание каналов без пространственного контекста. Снижение/увеличение числа каналов (bottleneck в ResNet, Inception). • BatchNorm — зачем? Нормализует активации → стабильнее градиенты, можно больший learning rate, работает как регуляризатор. Ставится после conv, перед activation (в классическом варианте).