Перейти к содержанию

Модуль 9. Свёртки и представления

После этого модуля вы сможете

  • Назвать два предположения о данных, которые свёртка вносит в модель, и сказать, когда они ложны.
  • Посчитать число параметров свёрточного и полносвязного слоя и объяснить разницу в сотни раз.
  • Написать свёртку и пулинг с нуля и принять их gradient check.
  • Показать на данных, что свёрточная сеть переживает сдвиг изображения, а полносвязная нет.
  • Посмотреть, что выучил первый слой, и узнать в этом детекторы границ.

Время: около двух недель. Пререквизиты: модуль 8. Ноутбук: notebooks/09-convolutions.ipynb

Зачем это

Модуль 8 закончился поражением: на табличных данных сеть проиграла бустингу. Объяснение было структурным — столбцы таблицы можно переставить местами, и ничего не изменится, значит извлекать нечего.

У изображения не так. Поменяйте пиксели местами — картинка исчезнет. Соседние пиксели связаны, и одна и та же деталь может оказаться в любом углу кадра. Это структура, и архитектура, которая её знает, побеждает архитектуру, которая её игнорирует.

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

Что не так с полносвязным слоем

Возьмите изображение 28×28 в оттенках серого. Полносвязный слой на 128 нейронов:

\[784 \times 128 + 128 = 100\,480 \text{ параметров}\]

Сто тысяч параметров на один слой, и это ещё маленькая картинка. Но дороже другое.

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

И он не знает, что деталь может сдвинуться. Кот в левом верхнем углу и тот же кот в правом нижнем — для полносвязного слоя два совершенно разных входа. Ему придётся выучить детектор кота отдельно для каждой позиции.

Два предположения свёртки

Свёртка чинит обе беды, добавив в модель два утверждения о мире.

Локальность. Важные признаки собираются из соседних пикселей. Граница, угол, текстура — всё это видно в окне 3×3, и смотреть на весь кадр сразу не нужно. Значит нейрон может смотреть только в маленькое окно.

Разделение весов. Детектор границы полезен в любой точке кадра. Значит одно и то же окно весов протаскивается по всему изображению, а не заводится заново для каждой позиции.

Из второго следует трансляционная эквивариантность: сдвиньте вход — выход сдвинется так же. Признак остаётся найденным, просто в другом месте.

Это предположения, а не истины

Оба утверждения могут быть ложными, и тогда свёртка вредна.

В табличных данных соседство столбцов ничего не значит: признак «возраст» стоит рядом с «городом» случайно. Свёртка по такой строке накладывает связь, которой нет.

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

Правило то же, что с моментом в модуле 4 и лесом в модуле 6: приём вносит предположение, и работает он ровно там, где предположение верно.

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

Ядро размера \(k \times k\) скользит по изображению. В каждой позиции считается скалярное произведение ядра с накрытым куском — то самое скалярное произведение из модуля 3, и означает оно то же самое: насколько кусок похож на то, что ищет ядро.

Размер выхода при шаге \(s\) и паддинге \(p\):

\[n_{\text{вых}} = \left\lfloor \frac{n_{\text{вх}} + 2p - k}{s} \right\rfloor + 1\]

Слой обычно содержит несколько ядер — каналов выхода. Каждое ищет своё: одно горизонтальные границы, другое вертикальные, третье пятна.

Число параметров:

\[k \times k \times C_{\text{вх}} \times C_{\text{вых}} + C_{\text{вых}}\]

Оно не зависит от размера изображения. Слой из 8 ядер 3×3 на одноканальном входе — это 80 параметров, и столько же будет на картинке 28×28 и на 1024×1024. Против ста тысяч у полносвязного.

Пулинг

Второй кирпич, и он несёт больше, чем кажется.

Max-pooling 2×2 берёт максимум в каждом окне, уменьшая карту вдвое по каждой стороне. Заодно уменьшает объём вычислений вчетверо, что и позволяет строить глубокие сети.

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

Одной свёртки для инвариантности не хватает

Соберите сеть как свёртка → пулинг 2×2 → flatten → полносвязный слой, и она не будет устойчива к сдвигу. Пулинг 2×2 гасит сдвиг на один пиксель, а дальше flatten снова привязывает всё к позициям: полносвязный слой видит не «признак найден», а «признак найден в клетке номер 37».

Это не теория. В ноутбуке такая архитектура при сдвиге на два пикселя даёт 0.75 — ровно столько же, сколько обычная полносвязная сеть. Свёртка есть, инвариантности нет.

Лечится глобальным пулингом: максимум берётся по всей карте сразу, и от каждого ядра остаётся одно число — сработало или нет, безразлично где. С ним та же сеть держит 1.000 на сдвигах до трёх пикселей и 0.98 на пяти.

Разница между двумя вариантами — одна строка кода и весь смысл модуля.

Что выучивает первый слой

Обученные ядра первого слоя можно просто нарисовать, и это одна из немногих честных возможностей заглянуть внутрь сети.

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

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

Глубже становится хуже: второй слой — углы и дуги, дальше — куски объектов, а на верхних слоях интерпретация ядер перестаёт работать. Что там на самом деле — предмет отдельной области, и в модуле 24 будет разобрана статья на эту тему.

Аугментации

Приём, который выглядит как жульничество и им не является.

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

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

Отсюда правило выбора: применяйте только те преобразования, при которых метка правда не меняется. Отражение цифры 6 даёт не цифру 6. Поворот рентгеновского снимка на 180 градусов даёт снимок, которого не бывает. Аугментация, нарушающая смысл задачи, — это добавление шума под видом данных.

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

Первые слои выучивают границы и текстуры, а они одинаковы для любой задачи со зрением. Значит их можно не учить заново.

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

Это самый практичный приём всей части III, и в реальной работе он применяется чаще, чем обучение сети с нуля.

Практика

Часть 1. Ноутбук

Откройте notebooks/09-convolutions.ipynb.

Что внутри:

  1. Свёртка руками, проверенная на известном ядре: оператор Собеля должен найти границы.
  2. Подсчёт параметров: свёрточный слой против полносвязного на одной задаче.
  3. Свёрточная сеть с нуля — свёртка, ReLU, пулинг, полносвязная голова. Всё через gradient check.
  4. Обучение на синтетических изображениях: три класса фигур.
  5. Сдвиг изображения на два пикселя: что происходит с полносвязной сетью и что со свёрточной.
  6. Выученные ядра первого слоя. Ищите границы.
  7. Сравнение на одних данных: свёрточная сеть, полносвязная и бустинг из модуля 6.

Часть 2. Аугментации на своей задаче

Возьмите любой набор изображений — свои фотографии тоже подойдут.

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

Четвёртый пункт делают редко, а он показывает, что аугментация — это утверждение о задаче, а не бесплатное увеличение выборки.

Задание

  1. Посчитайте размер выхода свёртки для входа 32×32, ядра 5×5, шага 2, паддинга 1. Проверьте кодом.
  2. Реализуйте average-pooling и сравните со max-pooling на тех же данных. Объясните разницу в результате.
  3. Постройте задачу, где свёртка проигрывает полносвязной сети. Подсказка: сделайте так, чтобы положение признака было важным.
  4. Возьмите обученную сеть и подайте на вход изображение, сдвинутое на 1, 2, 4 и 8 пикселей. Постройте, как падает уверенность.
  5. Нарисуйте выученные ядра при разной инициализации. Всегда ли получаются детекторы границ?

Проверка себя

  1. Какие два предположения о данных вносит свёртка?
  2. Почему число параметров свёрточного слоя не зависит от размера изображения?
  3. Чем эквивариантность отличается от инвариантности и что из них даёт пулинг?
  4. Почему свёртка вредна на табличных данных?
  5. Что обычно выучивает первый свёрточный слой и почему именно это?
  6. Аугментация добавляет информацию? Если нет, то что она делает?
  7. Какое преобразование нельзя применять к изображениям цифр и почему?
  8. Почему перенос обучения работает лучше обучения с нуля на маленькой выборке?

Дальше

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

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