Перейти к содержимому
ПереводыStanford

CS231n: свёрточные сети, часть 2 — пулинг, полносвязные слои и архитектуры (перевод конспекта)

Перевод второй половины конспекта Stanford CS231n «Convolutional Neural Networks»: слой пулинга, нормализация, полносвязный слой и его превращение в свёрточный, шаблоны слоёв и размеров, разбор LeNet, AlexNet, ZFNet, GoogLeNet, VGGNet и ResNet, подсчёт памяти и параметров VGG-16.

В архитектурах свёрточных сетей принято периодически вставлять слой пулинга (pooling) между последовательными слоями Conv. Его задача — постепенно уменьшать пространственный размер представления, чтобы сократить число параметров и вычислений в сети и тем самым также бороться с переобучением. Слой пулинга работает независимо с каждым срезом глубины входа и уменьшает его пространственно с помощью операции MAX. Самая распространённая форма — слой пулинга с фильтрами 2 × 2 и шагом 2: он уменьшает каждый срез глубины вдвое и по ширине, и по высоте, отбрасывая 75% активаций. Каждая операция MAX в этом случае берёт максимум из 4 чисел (маленькой области 2 × 2 в каком-то срезе глубины). Измерение глубины не меняется. В общем виде слой пулинга:

  • принимает объём размера W1×H1×D1W_1 \times H_1 \times D_1;
  • требует двух гиперпараметров:
    • пространственный размер FF,
    • шаг SS;
  • выдаёт объём размера W2×H2×D2W_2 \times H_2 \times D_2, где:
    • W2=(W1−F)/S+1W_2 = (W_1 - F)/S + 1,
    • H2=(H1−F)/S+1H_2 = (H_1 - F)/S + 1,
    • D2=D1D_2 = D_1;
  • не вводит параметров, поскольку вычисляет фиксированную функцию входа;
  • дополнение нулями для слоёв пулинга обычно не используют.

Стоит заметить, что на практике встречаются лишь два варианта слоя max-пулинга: с F=3,S=2F = 3, S = 2 (его называют перекрывающимся пулингом) и, чаще, с F=2,S=2F = 2, S = 2. Пулинг с бо́льшими рецептивными полями слишком разрушителен.

Общий пулинг. Помимо max-пулинга, блоки пулинга могут вычислять и другие функции, например усреднение (average pooling) или даже L2-норму. Усредняющий пулинг исторически использовали часто, но в последнее время он уступил max-пулингу, который на практике работает лучше.

Рисунок (в оригинале). Слой пулинга уменьшает объём пространственно, независимо в каждом срезе глубины входного объёма. Слева: входной объём размера [224 × 224 × 64] пулится фильтром размера 2 с шагом 2 в выходной объём [112 × 112 × 64]. Глубина объёма сохраняется. Справа: самая распространённая операция понижения разрешения — максимум, отсюда max-пулинг; показан с шагом 2. То есть каждый максимум берётся из 4 чисел (маленького квадрата 2 × 2).

Обратное распространение. Из главы об обратном распространении помним, что обратный проход операции max⁡(x,y)\max(x, y) просто направляет градиент к входу, у которого при прямом проходе было наибольшее значение. Поэтому при прямом проходе слоя пулинга обычно запоминают индекс максимальной активации (его иногда называют переключателями, switches), чтобы при обратном распространении эффективно направлять градиент.

Отказ от пулинга. Многим пулинг не нравится, и они считают, что можно обойтись без него. Например, статья Striving for Simplicity: The All Convolutional Net предлагает отказаться от слоя пулинга в пользу архитектуры только из повторяющихся слоёв CONV. Чтобы уменьшать размер представления, авторы предлагают время от времени использовать в слое CONV шаг побольше. Отказ от слоёв пулинга оказался важен и для обучения хороших генеративных моделей — вариационных автокодировщиков (VAE) и генеративно-состязательных сетей (GAN). Похоже, в будущих архитектурах слоёв пулинга будет очень мало или не будет вовсе.

Для свёрточных архитектур предлагалось много типов слоёв нормализации, иногда с намерением реализовать схемы торможения, наблюдаемые в биологическом мозге. Однако эти слои с тех пор вышли из моды: на практике их вклад оказался минимальным, если вообще был. О разных видах нормализации см. обсуждение в API библиотеки cuda-convnet Алекса Крижевского.

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

Превращение полносвязных слоёв в свёрточные

Заголовок раздела «Превращение полносвязных слоёв в свёрточные»

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

  • Для любого слоя CONV существует слой FC, реализующий ту же прямую функцию. Его матрица весов будет большой и в основном нулевой, кроме определённых блоков (из-за локальной связности), причём веса во многих блоках будут одинаковыми (из-за разделения параметров).
  • И наоборот, любой слой FC можно превратить в слой CONV. Например, слой FC с K=4096K = 4096, смотрящий на входной объём размера 7×7×5127 \times 7 \times 512, можно эквивалентно выразить слоем CONV с F=7,P=0,S=1,K=4096F = 7, P = 0, S = 1, K = 4096. Иначе говоря, мы делаем размер фильтра в точности равным размеру входного объёма, и выход будет просто 1×1×40961 \times 1 \times 4096, поскольку по входному объёму «умещается» лишь один столбец глубины, — результат тот же, что у исходного слоя FC.

Превращение FC → CONV. Из двух превращений на практике особенно полезно превращение слоя FC в слой CONV. Рассмотрим свёрточную архитектуру, которая принимает изображение 224 × 224 × 3, а затем серией слоёв CONV и POOL сводит его к объёму активаций 7 × 7 × 512 (в архитектуре AlexNet, которую мы увидим позже, это делается пятью слоями пулинга, каждый из которых вдвое уменьшает вход по пространству, так что итоговый пространственный размер равен 224/2/2/2/2/2 = 7). Дальше AlexNet использует два слоя FC размера 4096 и, наконец, последний слой FC из 1000 нейронов, вычисляющий оценки классов. Каждый из этих трёх слоёв FC можно превратить в слой CONV, как описано выше:

  • заменить первый слой FC, смотрящий на объём [7 × 7 × 512], слоем CONV с размером фильтра F=7F = 7, получив выходной объём [1 × 1 × 4096];
  • заменить второй слой FC слоем CONV с размером фильтра F=1F = 1, получив выходной объём [1 × 1 × 4096];
  • аналогично заменить последний слой FC с F=1F = 1, получив итоговый выход [1 × 1 × 1000].

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

Например, если изображение 224 × 224 даёт объём размера [7 × 7 × 512], то есть уменьшение в 32 раза, то прямой проход изображения 384 × 384 через превращённую архитектуру даст эквивалентный объём размера [12 × 12 × 512], поскольку 384/32 = 12. Следующие 3 слоя CONV, только что полученные из слоёв FC, дадут итоговый объём размера [6 × 6 × 1000], поскольку (12−7)/1+1=6(12 - 7)/1 + 1 = 6. Заметьте: вместо одного вектора оценок классов размера [1 × 1 × 1000] мы получаем целый массив 6 × 6 оценок классов по изображению 384 × 384.

Применить исходную свёрточную сеть (со слоями FC) независимо к вырезкам 224 × 224 изображения 384 × 384 с шагом 32 пикселя — то же самое, что один раз прогнать превращённую сеть.

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

Наконец, что если мы хотим эффективно применить исходную сеть к изображению с шагом меньше 32 пикселей? Этого можно добиться несколькими прямыми проходами. Например, чтобы получить шаг 16 пикселей, можно объединить объёмы, полученные двумя прогонами превращённой сети: сначала по исходному изображению, затем по изображению, сдвинутому на 16 пикселей и по ширине, и по высоте.

  • Ноутбук IPython Net Surgery показывает, как выполнить превращение на практике в коде (на Caffe).

Мы видели, что свёрточные сети обычно состоят всего из трёх типов слоёв: CONV, POOL (по умолчанию max-пулинг) и FC (полносвязный). Функцию активации RELU, поэлементно применяющую нелинейность, мы тоже будем явно записывать как слой. В этом разделе обсудим, как эти слои обычно складывают в целые свёрточные сети.

Самая распространённая форма архитектуры свёрточной сети складывает несколько слоёв CONV-RELU, затем слой POOL и повторяет этот шаблон, пока изображение не будет пространственно сведено к малому размеру. В какой-то момент обычно переходят к полносвязным слоям. Последний полносвязный слой хранит выход, например оценки классов. Иначе говоря, самая распространённая архитектура следует шаблону:

INPUT -> [[CONV -> RELU]*N -> POOL?]*M -> [FC -> RELU]*K -> FC

где * означает повторение, а POOL? — необязательный слой пулинга. Причём N >= 0 (и обычно N <= 3), M >= 0, K >= 0 (и обычно K < 3). Вот распространённые архитектуры, следующие этому шаблону:

  • INPUT -> FC — линейный классификатор. Здесь N = M = K = 0.
  • INPUT -> CONV -> RELU -> FC
  • INPUT -> [CONV -> RELU -> POOL]*2 -> FC -> RELU -> FC. Между слоями POOL по одному слою CONV.
  • INPUT -> [CONV -> RELU -> CONV -> RELU -> POOL]*3 -> [FC -> RELU]*2 -> FC. Перед каждым слоем POOL по два слоя CONV. Это обычно хорошая идея для больших и глубоких сетей: несколько сложенных слоёв CONV могут выработать более сложные признаки входного объёма до разрушительной операции пулинга.

Предпочитайте стопку слоёв CONV с маленькими фильтрами одному слою CONV с большим рецептивным полем. Пусть вы сложили три слоя CONV 3 × 3 один на другой (с нелинейностями между ними, конечно). При таком устройстве каждый нейрон первого слоя CONV видит область входного объёма 3 × 3. Нейрон второго слоя CONV видит область 3 × 3 первого слоя, а значит, область 5 × 5 входного объёма. Аналогично нейрон третьего слоя CONV видит область 3 × 3 второго слоя и, значит, 7 × 7 входного объёма. Пусть вместо этих трёх слоёв CONV 3 × 3 мы взяли бы один слой CONV с рецептивным полем 7 × 7. Рецептивное поле его нейронов по входу было бы того же пространственного размера (7 × 7), но с рядом недостатков. Во-первых, нейроны вычисляли бы линейную функцию входа, тогда как стопка из трёх слоёв CONV содержит нелинейности, делающие признаки выразительнее. Во-вторых, если у всех объёмов CC каналов, один слой CONV 7 × 7 содержал бы C×(7×7×C)=49C2C \times (7 \times 7 \times C) = 49 C^2 параметров, а три слоя CONV 3 × 3 — лишь 3×(C×(3×3×C))=27C23 \times (C \times (3 \times 3 \times C)) = 27 C^2. Интуитивно стопка слоёв CONV с крошечными фильтрами вместо одного слоя с большими фильтрами позволяет выражать более мощные признаки входа при меньшем числе параметров. Практический минус: для обратного распространения может понадобиться больше памяти, чтобы хранить все промежуточные результаты слоёв CONV.

Недавние отступления. Стоит отметить, что традиционная парадигма линейного списка слоёв недавно была поставлена под сомнение — в архитектурах Inception от Google и в современных (передовых) остаточных сетях (Residual Networks) от Microsoft Research Asia. У обеих (подробности — ниже, в разборе архитектур) более замысловатая и необычная структура связей.

На практике: используйте то, что лучше всего работает на ImageNet. Если вы немного устали от размышлений об архитектурных решениях, вас обрадует, что в 90% и более приложений о них можно не беспокоиться. Я формулирую это так: «не будьте героем». Вместо того чтобы придумывать свою архитектуру для задачи, посмотрите, какая архитектура сейчас лучше всего работает на ImageNet, скачайте предобученную модель и дообучите её на своих данных. Обучать свёрточную сеть с нуля или проектировать её с нуля приходится редко. Я говорил об этом и на Deep Learning school.

До сих пор мы не упоминали типичные гиперпараметры слоёв свёрточной сети. Сначала сформулируем распространённые эмпирические правила выбора размеров, а затем обсудим их:

Входной слой (с изображением) должен многократно делиться на 2. Типичные размеры: 32 (например, CIFAR-10), 64, 96 (например, STL-10), 224 (типичные сети для ImageNet), 384 и 512.

Свёрточные слои должны использовать маленькие фильтры (например, 3 × 3 или максимум 5 × 5), шаг S=1S = 1 и, что важно, дополнять входной объём нулями так, чтобы слой conv не менял пространственные размеры входа. То есть при F=3F = 3 дополнение P=1P = 1 сохранит исходный размер входа. При F=5F = 5 — P=2P = 2. В общем случае видно, что P=(F−1)/2P = (F - 1)/2 сохраняет размер входа. Если без больших фильтров (вроде 7 × 7) не обойтись, их обычно используют только в самом первом слое conv, который смотрит на входное изображение.

Слои пулинга отвечают за понижение пространственного разрешения входа. Самая распространённая настройка — max-пулинг с рецептивными полями 2 × 2 (то есть F=2F = 2) и шагом 2 (то есть S=2S = 2). Это отбрасывает ровно 75% активаций входного объёма (из-за уменьшения вдвое и по ширине, и по высоте). Чуть менее распространённая настройка — рецептивные поля 3 × 3 с шагом 2, но тогда «подгонка» сложнее (например, слою 32 × 32 × 3 понадобится дополнение нулями для max-пулинга с полем 3 × 3 и шагом 2). Рецептивные поля max-пулинга больше 3 встречаются очень редко: такой пулинг слишком агрессивен и теряет слишком много информации. Обычно это ухудшает качество.

Меньше головной боли с размерами. Схема выше удобна тем, что все слои CONV сохраняют пространственный размер входа, а за пространственное понижение разрешения отвечают только слои POOL. В альтернативной схеме, где в слоях CONV используются шаги больше 1 или вход не дополняется нулями, пришлось бы очень тщательно отслеживать входные объёмы по всей архитектуре и следить, чтобы все шаги и фильтры «сходились», а сеть была соединена аккуратно и симметрично.

Почему шаг 1 в CONV? Меньшие шаги на практике работают лучше. Кроме того, как уже говорилось, шаг 1 позволяет оставить всё пространственное понижение разрешения слоям POOL, а слоям CONV — только преобразовывать входной объём по глубине.

Зачем дополнение нулями? Помимо уже упомянутой пользы — сохранения пространственных размеров после CONV, — оно на деле улучшает качество. Если бы слои CONV не дополняли входы нулями и выполняли только «допустимые» свёртки, размер объёмов после каждого CONV немного уменьшался бы, и информация на краях «вымывалась» бы слишком быстро.

Компромиссы из-за ограничений памяти. В некоторых случаях (особенно в начале свёрточных архитектур) при следовании правилам выше объём памяти может расти очень быстро. Например, фильтрация изображения 224 × 224 × 3 тремя слоями CONV 3 × 3 по 64 фильтра с дополнением 1 создаст три объёма активаций размера [224 × 224 × 64]. Это всего около 10 млн активаций, или 72 МБ памяти (на изображение, для активаций и градиентов). Поскольку GPU часто упираются в память, может понадобиться компромисс. На практике его обычно делают только в первом слое CONV сети. Например, можно взять в первом слое CONV фильтры 7 × 7 с шагом 2 (как в ZF Net). Другой пример — AlexNet использует фильтры 11 × 11 с шагом 4.

В области свёрточных сетей есть несколько архитектур, получивших имена. Самые распространённые:

  • LeNet. Первые успешные применения свёрточных сетей разработал Ян Лекун в 1990-х годах. Самая известная из них — архитектура LeNet, которой читали почтовые индексы, цифры и т. п.
  • AlexNet. Первой работой, популяризовавшей свёрточные сети в компьютерном зрении, стала AlexNet Алекса Крижевского, Ильи Суцкевера и Джеффа Хинтона. AlexNet участвовала в соревновании ImageNet ILSVRC в 2012 году и значительно обошла второе место (ошибка top-5 — 16% против 26% у второго места). Архитектура была очень похожа на LeNet, но глубже, больше и содержала свёрточные слои, сложенные друг на друга (раньше обычно был один слой CONV, за которым сразу шёл слой POOL).
  • ZF Net. Победителем ILSVRC 2013 стала свёрточная сеть Мэттью Зайлера и Роба Фергюса. Она стала известна как ZFNet (от Zeiler & Fergus Net). Это улучшение AlexNet за счёт настройки гиперпараметров архитектуры, в частности расширения средних свёрточных слоёв и уменьшения шага и размера фильтра в первом слое.
  • GoogLeNet. Победителем ILSVRC 2014 стала свёрточная сеть Сегеди и др. из Google. Её главный вклад — модуль Inception, резко сокративший число параметров сети (4 млн против 60 млн у AlexNet). Кроме того, в этой статье наверху сети вместо полносвязных слоёв используется усредняющий пулинг, что убирает массу параметров, которые, похоже, не очень важны. У GoogLeNet есть несколько последующих версий, последняя — Inception-v4.
  • VGGNet. Второе место в ILSVRC 2014 заняла сеть Карена Симоняна и Эндрю Зиссермана, ставшая известной как VGGNet. Её главный вклад — показать, что глубина сети — ключевой фактор хорошего качества. Их лучшая итоговая сеть содержит 16 слоёв CONV/FC и, что привлекательно, имеет крайне однородную архитектуру: от начала до конца только свёртки 3 × 3 и пулинг 2 × 2. Предобученная модель доступна для использования в Caffe «из коробки». Минус VGGNet — она дороже в вычислении и требует гораздо больше памяти и параметров (140 млн). Большинство параметров — в первом полносвязном слое, и позже выяснилось, что слои FC можно убрать без потери качества, что значительно сокращает число необходимых параметров.
  • ResNet. Остаточная сеть (Residual Network) Каймина Хэ и др. победила в ILSVRC 2015. В ней есть особые обходные соединения (skip connections) и активно используется пакетная нормализация (batch normalization). В конце сети также нет полносвязных слоёв. Читателю рекомендуем выступление Каймина (видео, слайды) и недавние эксперименты, воспроизводящие эти сети в Torch. Сейчас ResNet — безусловно, передовые модели свёрточных сетей и выбор по умолчанию на практике (на 10 мая 2016 года). См. также более новые работы с доработками исходной архитектуры: Kaiming He et al. Identity Mappings in Deep Residual Networks (март 2016).

VGGNet подробно. Разберём VGGNet подробнее как пример. Вся VGGNet состоит из слоёв CONV, выполняющих свёртки 3 × 3 с шагом 1 и дополнением 1, и слоёв POOL, выполняющих max-пулинг 2 × 2 с шагом 2 (без дополнения). Можно выписать размер представления на каждом шаге обработки и следить и за размером представления, и за общим числом весов:

INPUT: [224x224x3] memory: 224*224*3=150K weights: 0
CONV3-64: [224x224x64] memory: 224*224*64=3.2M weights: (3*3*3)*64 = 1,728
CONV3-64: [224x224x64] memory: 224*224*64=3.2M weights: (3*3*64)*64 = 36,864
POOL2: [112x112x64] memory: 112*112*64=800K weights: 0
CONV3-128: [112x112x128] memory: 112*112*128=1.6M weights: (3*3*64)*128 = 73,728
CONV3-128: [112x112x128] memory: 112*112*128=1.6M weights: (3*3*128)*128 = 147,456
POOL2: [56x56x128] memory: 56*56*128=400K weights: 0
CONV3-256: [56x56x256] memory: 56*56*256=800K weights: (3*3*128)*256 = 294,912
CONV3-256: [56x56x256] memory: 56*56*256=800K weights: (3*3*256)*256 = 589,824
CONV3-256: [56x56x256] memory: 56*56*256=800K weights: (3*3*256)*256 = 589,824
POOL2: [28x28x256] memory: 28*28*256=200K weights: 0
CONV3-512: [28x28x512] memory: 28*28*512=400K weights: (3*3*256)*512 = 1,179,648
CONV3-512: [28x28x512] memory: 28*28*512=400K weights: (3*3*512)*512 = 2,359,296
CONV3-512: [28x28x512] memory: 28*28*512=400K weights: (3*3*512)*512 = 2,359,296
POOL2: [14x14x512] memory: 14*14*512=100K weights: 0
CONV3-512: [14x14x512] memory: 14*14*512=100K weights: (3*3*512)*512 = 2,359,296
CONV3-512: [14x14x512] memory: 14*14*512=100K weights: (3*3*512)*512 = 2,359,296
CONV3-512: [14x14x512] memory: 14*14*512=100K weights: (3*3*512)*512 = 2,359,296
POOL2: [7x7x512] memory: 7*7*512=25K weights: 0
FC: [1x1x4096] memory: 4096 weights: 7*7*512*4096 = 102,760,448
FC: [1x1x4096] memory: 4096 weights: 4096*4096 = 16,777,216
FC: [1x1x1000] memory: 1000 weights: 4096*1000 = 4,096,000
TOTAL memory: 24M * 4 bytes ~= 93MB / image (only forward! ~*2 for bwd)
TOTAL params: 138M parameters

(Таблица оставлена как в оригинале: memory — число активаций слоя, weights — число весов; в итоге — около 93 МБ на изображение только для прямого прохода, примерно вдвое больше с обратным, и 138 млн параметров.)

Как обычно для свёрточных сетей, бо́льшая часть памяти (и времени вычислений) уходит на первые слои CONV, а бо́льшая часть параметров — в последних слоях FC. В данном случае первый слой FC содержит 100 млн весов из 140 млн.

Главное узкое место при построении свёрточных архитектур — память. У многих современных GPU предел 3, 4 или 6 ГБ памяти, у лучших — около 12 ГБ. Нужно следить за тремя основными источниками расхода памяти:

  • Промежуточные объёмы: сырое число активаций на каждом слое сети и их градиенты (того же размера). Обычно бо́льшая часть активаций — в ранних слоях (первых слоях Conv). Их хранят, потому что они нужны для обратного распространения; но умная реализация, запускающая сеть только на этапе тестирования, могла бы в принципе сильно сократить расход, храня лишь текущие активации каждого слоя и выбрасывая активации нижележащих слоёв.
  • Параметры: числа, хранящие параметры сети, их градиенты при обратном распространении и обычно ещё кэш шага, если оптимизация использует момент, Adagrad или RMSProp. Поэтому память под один лишь вектор параметров обычно надо умножать как минимум примерно на 3.
  • Прочее: любая реализация свёрточной сети хранит разное — батчи изображений, возможно, их аугментированные версии и т. д.

Получив грубую оценку общего числа значений (активаций, градиентов и прочего), переведите её в гигабайты. Умножьте число значений на 4, чтобы получить число байтов (каждое число с плавающей точкой занимает 4 байта, или 8 при двойной точности), а затем несколько раз разделите на 1024, получая килобайты, мегабайты и, наконец, гигабайты. Если сеть не помещается, распространённая эвристика «чтобы влезло» — уменьшить размер батча, поскольку бо́льшую часть памяти обычно занимают активации.

Ресурсы, связанные с реализацией:

ENRU
pooling, max pooling, average poolingпулинг, max-пулинг, усредняющий пулинг
overlapping poolingперекрывающийся пулинг
switchesпереключатели (индексы максимумов)
fully-connected layerполносвязный слой
layer patterns, layer sizingшаблоны слоёв, выбор размеров слоёв
skip connection, residual networkобходное соединение, остаточная сеть
batch normalizationпакетная нормализация
“don’t be a hero”«не будьте героем» (берите проверенную архитектуру)