Как стать автором
Обновить

Часть 1: ResNet-18 — Архитектура, покорившая глубину

Уровень сложностиПростой
Время на прочтение4 мин
Количество просмотров485

Пролог: Парадокс глубины

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

ResNet решил это гениально просто: добавил "лифты" между этажами — остаточные связи (skip-connections). Теперь, если новый слой бесполезен, сеть просто "пропускает" его через эти лифты.

Разберём на простом примере

Как ResNet из картинки делает предсказание?
Допустим у нас есть задача предсказать, что в данном изображении будет "человек" класс (0) или "машина" класс (1).

1. Входные данные: RGB-изображение

Ваша фотография — это 3 матрицы чисел (Red, Green, Blue). Например, крошечное изображение 4×4:

Канал R:      Канал G:      Канал B:
[[2, 4, 1, 3]  [[2, 4, 1, 3]  [[2, 4, 1, 3]
 [0, 5, 8, 2]   [0, 5, 8, 2]   [0, 5, 8, 2]
 [4, 2, 7, 1]   [4, 2, 7, 1]   [4, 2, 7, 1]
 [3, 6, 0, 4]]  [3, 6, 0, 4]]  [3, 6, 0, 4]]

2. Свёртка: "Фильтр-детектор"

Сеть применяет к изображению фильтры (например, 3×3). Вот как это работает:

наглядная визуализация
наглядная визуализация
  • Фильтр "скользит" по картинке, умножая и суммируя числа.

  • Пример рассчета

    ==================================================

    Рассчитаем выход для позиции (0, 0):

    Канал 0:
    (2*1) + (4*-1) + (1*1) + (0*0) + (5*1) + (8*-1) + (4*-1) + (2*0) + (7*1) = 2 + -4 + 1 + 0 + 5 + -8 + -4 + 0 + 7
    = -1
    Канал 0 Сумма: -1

    Канал 1: Такой же как и на предыдущем шаге.

    Канал 2:Такой же как и на предыдущем шаге.

    Результат для позиции (0, 0) (Сумма по всем каналам): -1 - 1 -1 = -3
    ==================================================

    Рассчитаем выход для позиции (0, 1):

    Канал 0:
    (4*1) + (1*-1) + (3*1) + (5*0) + (8*1) + (2*-1) + (2*-1) + (7*0) + (1*1) = 4 + -1 + 3 + 0 + 8 + -2 + -2 + 0 + 1
    = 11
    Канал 0 Сумма: 11

    Канал 1: Такой же как и на предыдущем шаге.

    Канал 2: Такой же как и на предыдущем шаге.

    Результат для позиции (0, 1) (Сумма по всем каналам): 11 + 11 + 11 = 33
    ==================================================

    Рассчитаем выход для позиции (1, 0):

    Канал 0:
    (0*1) + (5*-1) + (8*1) + (4*0) + (2*1) + (7*-1) + (3*-1) + (6*0) + (0*1) = 0 + -5 + 8 + 0 + 2 + -7 + -3 + 0 + 0
    = -5
    Канал 0 Сумма: -5

    Канал 1: Такой же как и на предыдущем шаге.

    Канал 2: Такой же как и на предыдущем шаге.

    Результат для позиции (1, 0) (Сумма по всем каналам): -5 -5 -5 = -15
    ==================================================

    Рассчитаем выход для позиции (1, 1):

    Канал 0:
    (5*1) + (8*-1) + (2*1) + (2*0) + (7*1) + (1*-1) + (6*-1) + (0*0) + (4*1) = 5 + -8 + 2 + 0 + 7 + -1 + -6 + 0 + 4
    = 3
    Канал 0 Сумма: 3

    Канал 1: Такой же как и на предыдущем шаге.

    Канал 2: Такой же как и на предыдущем шаге.

    Результат для позиции (1, 1) (Сумма по всем каналам): 3 + 3 + 3 = 9
    ==================================================
  • Результат — новая матрица признаков:

    [[ -3,  33]
     [-15,   9]]
    

🔍 Фишка ResNet: Если фильтр "испортил" картинку, оригинал можно вернуть через skip-connection!

3. Pooling: "Сжатие без потерь"

MaxPooling оставляет только самое яркое значение в области 2×2:

Исходная матрица:   После MaxPooling:
[[ -3,  33]         [[33]]
 [-15,   9]]

(Как если бы вы сжали фото, оставив только ключевые детали)

Классический пуллинг
Классический пуллинг

4. Линейный слой: "Финальный вердикт"

  • Признаки преобразуются в вектор (например, [0.6, -1.2, 3.8]).

  • Умножается на веса классификатора:

    # Для классов "человек" (0) и "машина" (1):
    Класс 0: 0.6*0.7 + (-1.2)*0.5 + 3.8*1.0 + 0.1 = 3.7
    Класс 1: 0.6*(-1.2) + (-1.2)*0.3 + 3.8*(-0.4) - 0.2 = -2.8
    
  • Итог: Softmax(3.8, -1.59) → 99% вероятность "человек".

Ключевые компоненты ResNet в коде

1. Residual Block — "Лифт для градиентов"

class ResBlock(nn.Module):
    def forward(self, x):
        skip = x  # Сохраняем оригинальный вход!
        h = self.conv1(x)  # Первая свёртка
        h = self.bn1(h)    # Нормализация
        h = self.relu(h)   # Активация
        h = self.conv2(h)  # Вторая свёртка
        h = self.bn2(h)    # Нормализация
        return self.relu(skip + h)  # Складываем с исходным значением

Почему работает: Сеть учит не "абсолютное преобразование", а разницу от исходного x.

2. BatchNorm — "Стабилизатор обучения"

# Нормализует данные: (x - mean)/stddev
x = (x - torch.mean(x)) / torch.sqrt(torch.var(x) + 1e-5)
x = gamma * x + beta  # gamma/beta — обучаемые параметры

Эффект: Градиенты не "взрываются" и не "затухают" даже в 100+ слоях.

Как сеть учится? Обучаемые параметры

Что настраивается:

  1. Ядра свёрток: Числовые значения в фильтрах (например, 3×3 матрицы)

  2. Параметры BatchNorm: γ (масштаб) и β (сдвиг) для каждого канала

  3. Веса линейных слоёв: Матрицы в финальных слоях

  4. Смещения (bias): Добавочные константы в слоях

Процесс обучения:

  1. Прямой проход: Изображение преобразуется в предсказание (как в примере выше).

  2. Расчёт ошибки: Сравнение предсказания с истинной меткой через функцию потерь (например, кросс-энтропия).

  3. Обратное распространение:

    • Вычисляются градиенты (производные ошибки по каждому параметру)

    • Градиенты "протекают" обратно по сети через остаточные связи

  4. Оптимизация: Параметры корректируются в сторону, уменьшающую ошибку:

    параметр = параметр - learning_rate * градиент
    

Почему ResNet всё ещё актуален?

  1. Скорость: Работает в несколько раз быстрее ViT на небольших данных.

  2. Количество данных для обучения: Нужно в разы меньше данных, чем для обучения трансформеров.

  3. Масштабируемость: От 18 до 152 слоёв без коллапса.

Философский итог: Простая идея (остаточные связи) оказалась мощнее сложной математики. Иногда гениальное решение лежит на поверхности!

В следующей части: Как ViT (Vision Transformer) научился "понимать" изображения без свёрток — и почему это не всегда лучше ResNet.

P.S. Если хотите глубже разобрать BatchNorm или увидеть обучение ResNet с нуля — пишите в комментариях!

Теги:
Хабы:
0
Комментарии0

Публикации

Работа

Data Scientist
70 вакансий

Ближайшие события