Основы CNN
Свёрточные нейросети: convolution, pooling, feature maps, receptive field, stride и padding.
CNN — как нейросети «видят» изображения
Fully connected сеть на изображении 224×224×3 = 150K входов. Один hidden layer с 1024 нейронами — 150M параметров. Это не масштабируется. Свёрточные нейросети (CNN) решают проблему тремя идеями: локальные связи (смотрим на маленький patch, а не на всё изображение), разделение весов (один фильтр применяется ко всем позициям) и иерархия фич (простые → сложные).
Свёртка (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 — золотой стандарт
Типичная архитектура 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.
🎯 На собеседовании
Ключевые вопросы
Материалы
Лекции 5-9 подробно разбирают CNN: свёртки, архитектуры, обучение.
Визуальное объяснение свёрток с разными параметрами. Отличный для интуиции.
Karpathy объясняет CNN от первых принципов.