9 LeNet / CNN
Контекст
Полносвязная сеть на изображении — катастрофа: миллионы весов и полное игнорирование структуры (соседние пиксели связаны, объект может сдвинуться). Ян Лекун (1989→1998) строит сеть, у которой эта структура зашита в архитектуру.
Идея и механизм
Три принципа. Локальные рецептивные поля: нейрон смотрит на маленький патч. Весовой шаринг: один набор весов (фильтр) скользит по всей картинке — это операция свёртки:
Один фильтр = детектор признака (грань, угол), инвариантный к положению. Pooling агрегирует соседние отклики → устойчивость к сдвигам и снижение размерности. Стек conv → pool → conv → pool → fc, обучаемый backprop end-to-end; ранние слои ловят грани, поздние — части объектов.
линейная алгебра Весовой шаринг: сколько параметров экономит свёртка
Возьмём вход 32×32 и скрытый слой из 32×32 нейронов. Полносвязный вариант: каждый из 1024 выходов связан с каждым из 1024 входов →
Свёрточный вариант с фильтром 5×5: один и тот же фильтр применяется ко всем позициям →
Экономия в десятки тысяч раз, и она же даёт трансляционную эквивариантность: сдвинули объект → отклик сдвинулся так же, потому что фильтр везде один. Свёртка кодирует априорное знание «локальность + инвариантность к положению» прямо в структуру — это сильнейшее индуктивное смещение для изображений.
NumPy Свёртка одного фильтра по изображению
import numpy as np
def conv2d(img, K): # img: (H,W), фильтр K: (k,k)
k = K.shape[0]
H, W = img.shape
out = np.zeros((H - k + 1, W - k + 1))
for i in range(out.shape[0]):
for j in range(out.shape[1]):
patch = img[i:i+k, j:j+k]
out[i, j] = (patch * K).sum() # один фильтр на всех позициях
return out # карта признаков
Почему это важно
LeNet-5 распознавал рукописные цифры в продакшене (чеки, индексы) и стал шаблоном всех CNN. Первая убедительная демонстрация, что обучаемая иерархия признаков из пикселей бьёт ручные фичи. Полную силу идея раскроет в 2012-м (AlexNet, #16), когда подоспеют GPU и ImageNet.
Связи
CNN — это та же сеть, обучаемая backprop, но с зашитыми ограничениями (локальность, шаринг). Свёртка — просто слой с общими весами; градиент через неё течёт по тем же правилам цепного правила.
AlexNet — это LeNet, выросший на GPU и ImageNet: те же свёртки + pooling, но глубже, с ReLU и dropout. Идея 1998-го дождалась данных и железа — и выстрелила.
ViT отказывается от зашитого индуктивного смещения свёрток и заменяет его масштабом данных + self-attention. CNN «знает» про локальность с рождения; ViT «выучивает» её, но только на больших данных. Спор «встроенные смещения vs выучить из данных» — сквозной в ML.
Вопросы пытливого ума
Свёртка даёт трансляционную эквивариантность, а не инвариантность — в чём разница и важно ли это?
Эквивариантность: сдвинул вход → выход сдвинулся так же (свойство самой свёртки). Инвариантность: сдвинул вход → выход не изменился (нужна для классификации «это кошка независимо где»). Инвариантность добирается пулингом и глобальным агрегированием в конце. Путать их — частая ошибка; CNN эквивариантна по построению и инвариантна только после pooling.
Если свёртка такая хорошая, почему её не придумали и не внедрили раньше 2012-го массово?
Она была (LeNet работал на чеках в 1990-х), но упиралась в данные и вычисления: маленькие датасеты + слабые CPU не давали глубоким CNN раскрыться, а SVM на тех задачах были конкурентны и проще. ImageNet (#15) и GPU сняли оба ограничения — и CNN сразу вырвались вперёд.
Pooling выбрасывает информацию о точном положении — это не вредит?
Это осознанный компромисс: жертвуем точной локализацией ради устойчивости к сдвигам и сжатия. Для классификации «что на картинке» это полезно. Но для задач, где положение важно (сегментация, детекция), агрессивный pooling мешает — там используют свёртки со страйдом, dilated-свёртки или вовсе обходятся без пулинга, чтобы сохранить пространственную точность.
Что читать в оригинале
Статья 1998-го длинная (46 стр.) — читать выборочно секции про свёртку, pooling и весовой шаринг; graph-transformer-часть в конце можно пропустить.