Свёрточные нейронные сети: как работает CNN на примере кода

Свёрточная нейросеть ищет на картинке мелкие узоры фильтром 3 × 3 и собирает из них крупные.

Разбираем свёртку, ReLU и пулинг на коде NumPy с настоящим выводом, считаем, почему у свёрточного слоя в тысячи раз меньше весов, чем у полносвязного, и проходим по архитектурам от LeNet до ConvNeXt.

Статью написал:
Ваня Буявец, продюсер, основатель Checkroi
Ваня Буявец
Основатель Checkroi, продюсер, эксперт в выборе онлайн-курсов
Все 3119 статей автора Подписаться на Телеграм-канал
Одобрено экспертом:
Наташа Буявец, основатель Checkroi, эксперт по онлайн-курсам
Наташа Буявец
Основательница Checkroi, продюсер Youtube-каналов, эксперт по онлайн-курсам
Все 3773 экспертных мнения Подписаться на Телеграм-канал
Обложка: Свёрточные нейронные сети: как работает CNN на примере кода

Свёрточная нейронная сеть (CNN, convolutional neural network) ищет на картинке мелкие узоры маленьким окном-фильтром, а потом собирает из них узоры крупнее. Из границ получаются углы, из углов глаза и колёса, из них лицо или машина.

Окно скользит по изображению и в каждой точке считает одно число. Так получается карта признаков. Несколько слоёв такого поиска с упрощением между ними дают основу компьютерного зрения: распознавание лиц, медицинских снимков, дорожных знаков, брака на конвейере.

Ниже разберём свёртку на коде, который можно запустить у себя, и пройдём по слоям сети. Если с нейросетями вы пока не знакомы, сначала прочитайте как устроена нейросеть в целом.

CheckroiCheckroiПодборка курсов по машинному обучению150 курсов • 28 школСравните цены, школы, программу и найдите выгодные предложения по обучениюСравнить→

Чем свёрточная сеть отличается от обычной

Рой-инженер разглядывает карту признаков на мониторе

В обычной нейросети каждый нейрон первого слоя связан с каждым пикселем. Такие слои называют полносвязными. Для цветной фотографии 224 × 224 это 150 528 входов на один нейрон, и сеть быстро раздувается.

Посчитаем, сколько весов нужно слою из 32 нейронов в обоих случаях:

# свёрточный слой: 32 фильтра 3×3 по цветной картинке (3 канала)
conv = (3 * 3 * 3 + 1) * 32
# полносвязный слой: та же картинка 224×224×3 и всего 32 нейрона
dense = (224 * 224 * 3 + 1) * 32
print("Свёрточный слой:", conv)
print("Полносвязный слой:", dense)
print("Разница, раз:", dense // conv)
Свёрточный слой: 896
Полносвязный слой: 4816928
Разница, раз: 5376

Единица в скобках означает смещение (bias), по одному на фильтр или нейрон. Разница в пять тысяч раз появляется из двух идей.

  • Локальность. Фильтр смотрит только на соседние пиксели, окно 3 × 3 или 5 × 5. Чтобы найти границу, вся картинка не нужна.
  • Общие веса. Один и тот же фильтр проходит по всему изображению. Кошку в углу и кошку в центре находят одни и те же веса, сети не приходится учить их дважды.
Полносвязная сеть Свёрточная сеть
С чем связан нейрон Со всеми пикселями С окном из соседних пикселей
Веса Свои у каждой связи Общие для всей картинки
Объект сдвинулся Для сети это новые данные Фильтр найдёт его на новом месте
Где хороша Таблицы, финальное решение в конце CNN Изображения, звук, сигналы

Полносвязные слои из CNN никуда не делись. Они стоят в конце и принимают решение по признакам, которые нашли свёртки. Чем сети отличаются от других подходов к ИИ, мы разбирали в статье о видах искусственного интеллекта.

Как работает свёртка: разбор на Python

Возьмём картинку 6 × 8 пикселей: тёмный фон и светлая вертикальная полоса посередине. И фильтр 3 × 3, его ещё называют ядром свёртки. Фильтр накладываем на кусок картинки, перемножаем числа попарно и складываем.

Код ниже работает на чистом NumPy, его удобно запускать по кусочкам в Jupyter Notebook.

import numpy as np

# картинка 6×8: тёмный фон (0) и светлая вертикальная полоса (9)
image = np.array([[0, 0, 0, 9, 9, 0, 0, 0]] * 6)

# ядро 3×3, которое откликается на вертикальную границу «темно → светло»
kernel = np.array([
    [-1, 0, 1],
    [-1, 0, 1],
    [-1, 0, 1],
])

def conv2d(img, k):
    kh, kw = k.shape
    out_h = img.shape[0] - kh + 1
    out_w = img.shape[1] - kw + 1
    out = np.zeros((out_h, out_w), dtype=int)
    for i in range(out_h):
        for j in range(out_w):
            out[i, j] = np.sum(img[i:i+kh, j:j+kw] * k)
    return out

def relu(x):
    return np.maximum(x, 0)

def max_pool(x, size=2):
    h, w = x.shape[0] // size, x.shape[1] // size
    return x[:h*size, :w*size].reshape(h, size, w, size).max(axis=(1, 3))

fmap = conv2d(image, kernel)
print("Карта признаков после свёртки:")
print(fmap)
print("После ReLU:")
print(relu(fmap))
print("После max pooling 2×2:")
print(max_pool(relu(fmap)))

Вывод (Python 3.14, NumPy 2.4):

Карта признаков после свёртки:
[[  0  27  27 -27 -27   0]
 [  0  27  27 -27 -27   0]
 [  0  27  27 -27 -27   0]
 [  0  27  27 -27 -27   0]]
После ReLU:
[[ 0 27 27  0  0  0]
 [ 0 27 27  0  0  0]
 [ 0 27 27  0  0  0]
 [ 0 27 27  0  0  0]]
После max pooling 2×2:
[[27 27  0]
 [27 27  0]]

Посмотрите на первую матрицу. Там, где фон ровный, фильтр выдаёт 0. На левом краю полосы, где тёмное переходит в светлое, получается 27, на правом краю −27. Фильтр нашёл обе вертикальные границы и даже различил их направление.

Это ядро мы задали сами. В настоящей сети фильтры никто не задаёт: сеть сама подбирает их числа при обучении. Получаются детекторы границ, пятен цвета, текстур, о которых человек мог и не догадаться.

Строго говоря, в нейросетях считают не свёртку, а взаимную корреляцию (cross-correlation): от свёртки она отличается тем, что ядро не отражают перед умножением. Именно этот оператор указан в формуле слоя в документации Conv2d в PyTorch. На качество это не влияет, потому что веса ядра сеть подбирает сама.

Сколько пикселей останется после свёртки

Карта признаков в примере стала меньше картинки: 4 × 6 вместо 6 × 8. Фильтр 3 × 3 не может встать на крайние пиксели целиком. Размер выхода считают так:

выход = (W − K + 2P) / S + 1.

Здесь W означает ширину входа, K размер ядра, P рамку из нулей вокруг картинки (padding), S шаг (stride).

def out_size(w, k, p=0, s=1):
    return (w + 2 * p - k) // s + 1

print(out_size(224, 3))        # без рамки
print(out_size(224, 3, p=1))   # рамка 1 пиксель
print(out_size(224, 3, p=1, s=2))  # шаг 2
222
224
112

Знак // в функции означает деление с отбрасыванием остатка, как устроены сами функции, мы разбирали в статье о функциях в Python. Рамка в один пиксель сохраняет размер, шаг 2 уменьшает его вдвое. Полная формула с параметром dilation (разреженное ядро) есть в той же документации PyTorch, в разделе Shape.

Канал основателя Checkroi Вани Буявца3 700 человек читают мой Телеграм-канал про нейросетиСобрал промпты для Claude Code и ChatGPT, разборы ИИ-инструментов и лайфхаки по продвижению бизнеса в одном местеПрисоединиться

Из каких слоёв состоит CNN

Типичная свёрточная сеть повторяет один и тот же блок несколько раз, а в конце ставит классификатор:

  1. вход: картинка с тремя каналами цвета;
  2. свёрточный слой → ReLU → пулинг, и так несколько раз;
  3. развёртка карт признаков в один длинный вектор;
  4. один-два полносвязных слоя;
  5. выход с вероятностями по классам.

Свёрточный слой

В слое не один фильтр, а десятки или сотни. Как настраивать их число и размер, учат на курсах по машинному обучению. 32 фильтра дают 32 карты признаков, и следующий слой работает уже с ними как с 32 каналами.

Чем глубже слой, тем крупнее то, что он находит. Зейлер и Фергюс в 2013 году визуализировали слои обученной сети: второй слой у них откликается на углы и сочетания границ с цветом, третий на текстуры вроде сетки и текста, пятый на целые объекты, например клавиатуры и собак.

Функция активации ReLU

ReLU оставляет положительные числа как есть, а отрицательные превращает в ноль: max(0, x). В нашем примере она стёрла −27, и от фильтра осталась реакция только на границу «темно → светло».

Без такой нелинейности десять слоёв подряд сводятся к одному: композиция линейных операций остаётся линейной. Почему модели вообще учатся на примерах, мы объясняли в статье о машинном обучении. ReLU ещё и быстро считается. Авторы AlexNet пишут, что сеть с ReLU учится в несколько раз быстрее такой же сети с функцией tanh.

Пулинг

Пулинг (pooling, слой подвыборки) сжимает карту признаков. Max pooling 2 × 2 берёт из каждого квадрата 2 × 2 самое большое число, и карта уменьшается вдвое по каждой стороне. В примере 4 × 6 превратилось в 2 × 3.

  • Сеть считает меньше, следующие слои работают быстрее.
  • Сдвиг объекта на пиксель-другой почти не меняет результат.
  • Каждый нейрон следующего слоя видит больший кусок исходной картинки.

Полносвязный слой и выход

Последние карты признаков вытягивают в один вектор и подают в обычные полносвязные слои. Они решают, какой класс на картинке.

Выходной слой обычно заканчивается функцией softmax: она превращает числа в вероятности, сумма которых равна единице. В классической задаче ImageNet классов 1000, и выходов у сети столько же.

Как обучается свёрточная сеть

CNN учится так же, как любая нейросеть, методом обратного распространения ошибки. Разница только в том, что подбираются числа внутри фильтров.

  1. Сеть получает пачку размеченных картинок и делает прогноз.
  2. Функция потерь считает, насколько прогноз далёк от правильной метки.
  3. Обратный проход вычисляет, в какую сторону сдвинуть каждый вес, чтобы ошибка уменьшилась.
  4. Оптимизатор сдвигает веса на небольшой шаг.
  5. Всё повторяется по всем картинкам много эпох подряд.

На маленьких датасетах главная беда в переобучении: сеть запоминает обучающие картинки и плохо работает на новых. Против этого применяют два приёма, оба описаны ещё в статье 2012 года, о которой ниже.

  • Аугментация: из одной картинки делают несколько, отражая её и вырезая куски. Метка при этом не меняется.
  • Dropout: при обучении часть нейронов случайно выключается, и сеть не может опереться на один-единственный признак.

Свёртки хорошо ложатся на видеокарты. AlexNet училась пять-шесть дней на двух GTX 580. Сейчас для учебных задач хватит бесплатной видеокарты в Google Colab, а размеченные датасеты удобно брать на Kaggle.

Архитектуры CNN, которые стоит знать

Рой радуется, что сеть узнала кошку на фото

Почти каждая новая архитектура решала конкретную проблему предыдущей. Цифры в таблице взяты из статей авторов, ссылки ниже.

Год Сеть Что нового Цифра из статьи
1998 LeNet-5 Свёртки и подвыборка для распознавания документов Статья «Gradient-Based Learning Applied to Document Recognition»
2012 AlexNet ReLU, dropout, обучение на двух видеокартах Ошибка top-5 15,3 % против 26,2 % у второго места, 60 млн параметров
2014 VGG Только маленькие фильтры 3 × 3, 16–19 слоёв Конфигурация D (VGG-16): 138 млн параметров
2015 ResNet Остаточные связи: сигнал перепрыгивает через слои До 152 слоёв, ансамбль даёт 3,57 % ошибки top-5
2016 Xception Глубинно-разделимые свёртки Параметров столько же, сколько у Inception V3, на ImageNet немного точнее
2022 ConvNeXt ResNet, переделанный по образцу трансформеров 87,8 % top-1 на ImageNet

Ошибкой top-5 называют долю картинок, где правильного ответа нет среди пяти самых вероятных вариантов сети. На ImageNet с тысячей классов это стандартная мера.

Первоисточники: LeCun и соавторы, 1998, AlexNet, VGG, ResNet, Xception, ConvNeXt.

Если выбираете, с чего начать свой проект, берите ResNet. Предобученный ResNet есть и в torchvision, и в Keras Applications, так что его не придётся учить с нуля. Обзор других моделей, не только свёрточных, есть в статье о моделях машинного обучения.

Где применяют свёрточные нейросети

Где работают свёрточные сети: рентгеновский снимок, камера, фото с рамками

Везде, где данные похожи на сетку из чисел, а смысл прячется в соседних значениях.

  • Классификация изображений: что на фото, кошка или собака, опухоль или норма.
  • Поиск объектов (детекция): где на кадре пешеходы, машины, знаки. Это основа зрения беспилотников и роботов, вместе с лидарами и другими датчиками.
  • Сегментация: какие пиксели принадлежат дороге, а какие тротуару, где на снимке МРТ границы органа.
  • Распознавание лиц и документов: вход по лицу, чтение паспорта и номера машины.
  • Контроль качества: камера над конвейером находит царапины и сколы.
  • Звук: аудио превращают в спектрограмму, картинку частот, и дальше работают как с изображением.
  • Сигналы и ряды: одномерные свёртки ищут узоры в ЭКГ, показаниях датчиков, тексте.

Этим занимаются инженеры компьютерного зрения. Что входит в их работу и какой нужен стек, мы разбирали в статье «Кто такой CV-инженер».

Ваня БуявецКанал основателя Checkroi Вани БуявцаЗабирайте промпты и обучение по нейросетям в моём Телеграм-каналеБольше 3 700 человек уже применяют Claude Code, ChatGPT и другие нейросети в работе, учёбе, бизнесе и жизниПерейти в канал

Чего CNN не умеет и что пришло ей на смену

У свёрток есть врождённые слабости, и про них лучше знать до первого проекта.

  • Узкое окно. Фильтр видит несколько соседних пикселей. Связь между дальними частями картинки сеть замечает только в глубоких слоях.
  • Повороты и масштаб. Сдвиг сеть переносит хорошо, а перевёрнутый объект может не узнать, если таких примеров не было при обучении. Поэтому и нужна аугментация.
  • Много данных. Чтобы обучить CNN с нуля, обычно нужны тысячи размеченных картинок на класс. Когда примеров сотни, выручает дообучение готовой сети.

В 2020 году исследователи Google показали Vision Transformer: трансформер, который работает с картинкой как с последовательностью квадратных кусков и обходится без свёрточной сети. По их данным, при предобучении на больших объёмах данных он показывает отличные результаты в сравнении с лучшими свёрточными сетями.

Через два года вышла ConvNeXt, и её авторы пишут, что чисто свёрточная сеть не уступает трансформерам по точности и масштабируемости. Так что свёрточные сети остаются в строю.

Наш вывод для практики: для небольшого датасета и ограниченного железа начинайте с предобученной свёрточной сети. Трансформеры имеют смысл, когда данных и вычислений много.

Частые ошибки при первой свёрточной сети

Эти ошибки встречаются у всех, кто собирает первую CNN. Каждая выглядит как «сеть не учится», хотя причины у них разные.

Размеры не сходятся перед полносвязным слоем

Симптом: программа падает с ошибкой о несовпадении форм матриц на первом полносвязном слое. Причина в том, что после свёрток и пулинга карта стала другого размера, чем вы рассчитывали.

Решение: посчитайте размер по формуле из раздела выше или просто распечатайте форму тензора после каждого блока. Второй способ быстрее и не ошибается.

Перепутан порядок осей

PyTorch ждёт картинки в порядке (пачка, каналы, высота, ширина). Keras, если в его настройках ничего не менять, ждёт (пачка, высота, ширина, каналы): так сказано в описании слоя Conv2D. Перенесли код из одного фреймворка в другой без перестановки осей, и сеть получает мусор.

Пиксели поданы как есть, от 0 до 255

Сеть учится медленно, ошибка скачет. Обычно входы приводят к диапазону от 0 до 1 или вычитают среднее и делят на разброс.

Решение для предобученной сети: нормализуйте картинки теми же числами, что и при её обучении.

На обучении 99 %, на проверке намного хуже

Это переобучение. Помогают приёмы из раздела про обучение:

  • аугментация, чтобы картинок стало больше;
  • dropout перед полносвязными слоями;
  • остановка обучения, когда точность на проверочной выборке перестала расти;
  • предобученная сеть вместо обучения с нуля.

С чего начать изучение

Свёрточные сети осваивают в таком порядке, и каждый шаг занимает от пары вечеров до пары недель.

  1. Python и NumPy. Без них дальше никуда, начните с обзора языка Python.
  2. Свёртка руками. Перепишите пример из этой статьи, поменяйте ядро на горизонтальное и посмотрите, что изменится.
  3. Фреймворк. PyTorch или Keras: готовые слои Conv2d, пулинг, оптимизаторы.
  4. Первая сеть. Рукописные цифры MNIST или картинки CIFAR-10 в Jupyter Notebook или Colab.
  5. Дообучение. Возьмите предобученный ResNet и научите его своим классам: этот приём чаще всего нужен в работе.

Если хочется работать с этим профессионально, путь от Python до модели в проде расписан в статье «Как стать ML-инженером», а узкую специализацию на глубоких сетях мы разбирали в материале о Deep Learning Engineer.

Где освоить нейросети системно

Свёртку можно понять за вечер, а чтобы уверенно обучать и внедрять модели, нужны месяцы практики с наставником и проекты в портфолио. Ниже собраны курсы по машинному обучению с ценами и программами. Если интересует именно зрение, есть отдельная подборка курсов по компьютерному зрению.

КурсШколаСтоимость со скидкойВ рассрочкуДлитель­ностьОбзор курса от Checkroi
Machine Learning с нуля до Junior
Перейти на сайт курса
SkillboxSkillbox127 155 ₽4384 ₽/мес.9 месяцевОбзор курса
Бакалавриат «Data Science & Machine Learning»
Перейти на сайт курса
SkillboxSkillbox75 000 ₽ - 48 месяцевОбзор курса
Машинное обучение
Перейти на сайт курса
НетологияНетология43 600 ₽2598 ₽/мес.10 месяцевОбзор курса
Machine Learning. Basic
Перейти на сайт курса
OTUSOTUS60 000 ₽8613 ₽/мес.6 месяцевОбзор курса
Machine Learning Engineer с нуля
Перейти на сайт курса
SkillboxSkillbox69 000 ₽ - 9 месяцевОбзор курса

Больше программ — в полном каталоге курсов по машинному обучению

Часто задаваемые вопросы

Что такое свёрточная нейронная сеть простыми словами?

Это нейросеть, которая просматривает картинку маленьким окном-фильтром и ищет в каждом месте простые узоры: границы, пятна цвета, текстуры. Следующие слои собирают из них узоры сложнее, а в конце сеть решает, что изображено на картинке.

Чем свёрточный слой отличается от полносвязного?

Нейрон полносвязного слоя связан со всеми входами, а фильтр свёрточного слоя смотрит только на небольшое окно и проходит с одними и теми же весами по всей картинке. Поэтому весов у свёрточного слоя в тысячи раз меньше: 32 фильтра 3 × 3 по цветной картинке дают 896 параметров, а полносвязный слой из 32 нейронов на картинку 224 × 224 даёт больше 4,8 млн.

Что такое ядро свёртки?

Это небольшая матрица весов, чаще 3 × 3 или 5 × 5. Её накладывают на кусок картинки, перемножают числа попарно и складывают, результат становится одной точкой карты признаков. Значения ядра сеть подбирает сама при обучении.

Зачем в свёрточной сети ReLU и пулинг?

ReLU обнуляет отрицательные значения и делает сеть нелинейной, без неё несколько слоёв подряд работали бы как один. Пулинг уменьшает карту признаков, например вдвое по каждой стороне, чтобы сеть считала быстрее и меньше реагировала на мелкие сдвиги объекта.

На чём написать свёрточную нейросеть?

Чаще всего на Python с библиотекой PyTorch или Keras: в обеих есть готовые свёрточные слои, пулинг и предобученные модели вроде ResNet. Для первых опытов хватит бесплатной видеокарты в Google Colab.

Где применяют свёрточные нейронные сети?

В распознавании и поиске объектов на фото и видео, медицинских снимках, системах помощи водителю, контроле брака на производстве, распознавании лиц и документов. Одномерные свёртки работают со звуком, сигналами датчиков и текстом.

Читайте Checkroi первым в Google
Добавьте Checkroi в избранные источники — и наши разборы курсов и обзоры школ будут показываться выше в вашей выдаче Google.
Оставить комментарий
0 комментариев
Форма комментария

Оставьте комментарий

Напишите, что думаете. Нам важно ваше мнение!