Шаг 226.
Глубокое обучение на Python. Продвинутые приемы глубокого обучения ... . Современные архитектурные шаблоны сверточных сетей. Пакетная нормализация

    На этом шаге мы рассмотрим особенности использования пакетной нормализации.

    Нормализация - это широкая категория методов, стремящихся сделать сходство разных образцов более заметным для модели машинного обучения, что помогает модели выделять и обобщать новые данные. Вы уже несколько раз видели наиболее распространенную форму нормализации: центрирование данных по нулю вычитанием среднего значения и придание единичного стандартного отклонения делением на их стандартное отклонение. Фактически такая нормализация предполагает, что данные соответствуют нормальному закону распределения (или закону Гаусса), центрируя и приводя это распределение к единичной дисперсии:

  normalized_data = (data - np.mean(data, axis=...)) / np.std(data, axis=...)

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

    Пакетная нормализация - это тип слоя (BatchNormalization в Keras), введенный в 2015 году Сергеем Йоффе и Кристианом Сегеди;


Ioffe Sergey and Szegedy Christian, Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift // Proceedings of the 32nd International Conference on Machine Learning, 2015, https://arxiv.org/abs/1502.03167.
он может адаптивно нормализовать данные, даже если среднее и дисперсия изменяются во время обучения. В процессе обучения образцы нормализуются с использованием среднего и дисперсии текущего пакета данных, а во время прогнозирования (когда достаточно большой пакет репрезентативных данных может быть недоступен) применяются экспоненциальное скользящее среднее и дисперсия по всем пакетам, наблюдавшиеся при обучении.

    В оригинальной статье авторы утверждают, что пакетная нормализация работает за счет "уменьшения внутреннего ковариантного сдвига", но в действительности никто точно не знает, почему она способствует улучшению эффективности обучения. Есть разные гипотезы, но нет уверенности. Далее вы не раз убедитесь, что подобное положение дел характерно для многих вопросов глубокого обучения. Глубокое обучение - это не точная наука, а набор постоянно меняющихся инженерных практик, полученных опытным путем и сплетенных в единое целое ненадежными стереотипами. Иногда может казаться, что излагаемый материал говорит вам, как делать то или это, но не дает конкретного объяснения, почему это работает. Причина проста: мы сами этого не знаем. При наличии надежного объяснения мы обязательно его упоминаем. Пакетная нормализация не относится к таким случаям.

    Эффект пакетной нормализации, по всей видимости, способствует распространению градиента - подобно остаточным связям - и, соответственно, делает возможным создание более глубоких сетей. Некоторые глубокие сети могут обучаться, только если включают в себя несколько слоев BatchNormalization. Например, слои пакетной нормализации широко используются во многих продвинутых архитектурах сверточных нейронных сетей, входящих в состав Keras (таких как ResNet50, EfficientNet и Xception).

    Слой BatchNormalization можно использовать после любого слоя - Dense, Conv2D и т. д.:

x = ...
# Поскольку выход слоя Conv2D нормализуется, слой не нуждается в собственном векторе смещения
x = layers.Conv2D(32, 3, use_bias=False)(x) 
x = layers.BatchNormalization()(x)


Слои обоих типов, Dense и Conv2D, включают вектор смещения (bias vector) - обучаемую переменную, цель которой - сделать слой аффинным, а не чисто линейным. Например, в общем случае слой Conv2D возвращает y = conv(x, kernel) + bias, а слой Dense - y = dot(x, kernel) + bias. Так как на этапе нормализации происходит центрирование результатов слоя по нулю, то при использовании BatchNormalization необходимость в векторе смещения отпадает и слой можно создать без него, передав параметр use_bias=False. Это делает слой немного тоньше.

    Обычно мы рекомендуем размещать активацию предыдущего слоя после слоя пакетной нормализации (хотя это и спорно). Поэтому вместо приема, показанного в примере 9.4, желательно использовать подход из примера 9.5.


Пример 9.4. Как не следует использовать пакетную нормализацию
x = layers.Conv2D(32, 3, activation="relu")(x) 
x = layers.BatchNormalization()(x)


Пример 9.5. Как следует использовать пакетную нормализацию: активация применяется после нормализации
# Обратите внимание на отсутствие функции активации здесь
x = layers.Conv2D(32, 3, use bias=False)(x)
x = layers.BatchNormalization()(x)	
# Активация применяется после слоя BatchNormalization
x = layers.Activation("relu")(x)

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


О пакетной нормализации и дообучении

    Применение пакетной нормализации имеет множество особенностей. Одна из них связана с дообучением: при дообучении модели, включающей слои BatchNormalization, рекомендуется замораживать эти слои (передавать им в атрибуте trainable значение False). Иначе они продолжат обновлять свое внутреннее среднее значение и дисперсию, что может помешать очень небольшим корректировкам, применяемым к окружающим слоям Conv2D.


    Перейдем к следующему архитектурному шаблону: раздельной свертке по глубине.

    На следующем шаге мы рассмотрим раздельную свертку по глубине.




Предыдущий шаг Содержание Следующий шаг