Batch-normalization

Материал из Викиконспекты
Перейти к: навигация, поиск

Пакетная нормализация (англ. batch-normalization) — метод, который позволяет повысить производительность и стабилизировать работу искусственных нейронных сетей. Суть данного метода заключается в том, что некоторым слоям нейронной сети на вход подаются данные, предварительно обработанные и имеющие нулевое математическое ожидание и единичную дисперсию. Впервые данный метод был представлен в [1].

Идея[править]

Нормализация входного слоя нейронной сети обычно выполняется путем масштабирования данных, подаваемых в функции активации. Например, когда есть признаки со значениями от [math]0[/math] до [math]1[/math] и некоторые признаки со значениями от [math]1[/math] до [math]1000[/math], то их необходимо нормализовать, чтобы ускорить обучение. Нормализацию данных можно выполнить и в скрытых слоях нейронных сетей, что и делает метод пакетной нормализации.

Пакет[править]

Предварительно, напомним, что такое пакет (англ. batch). Возможны два подхода к реализации алгоритма градиентного спуска для обучения нейросетевых моделей: стохастический и пакетный[2].

  • Стохастический градиентный спуск (англ. stochastic gradient descent) — реализация, в которой на каждой итерации алгоритма из обучающей выборки каким-то (случайным) образом выбирается только один объект;
  • Пакетный (батч) (англ. batch gradient descent) — реализация градиентного спуска, когда на каждой итерации обучающая выборка просматривается целиком, и только после этого изменяются веса модели.

Также существует "золотая середина" между стохастическим градиентным спуском и пакетным градиентным спуском — когда просматривается только некоторое подмножество обучающей выборки фиксированного размера (англ. batch-size). В таком случае такие подмножества принято называть мини-пакетом (англ. mini-batch). Здесь и далее, мини-пакеты будем также называть пакетом.

Ковариантный сдвиг[править]

Рисунок 1. Верхние две строки роз показывают первое подмножество данных, а нижние две строки показывают другое подмножество. Два подмножества имеют разные пропорции изображения роз. На графиках показано распределение двух классов в пространстве объектов с использованием красных и зеленых точек. Синяя линия показывает границу между двумя классами. Иллюстрация из статьи.

Пакетная нормализация уменьшает величину, на которую смещаются значения узлов в скрытых слоях (т.н. ковариантный сдвиг (англ. covariance shift)).

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

Проиллюстрируем ковариантный сдвиг примером. Пусть есть глубокая нейронная сеть, которая обучена определять находится ли на изображении роза. И нейронная сеть была обучена на изображениях только красных роз. Теперь, если попытаться использовать обученную модель для обнаружения роз различных цветов, то, очевидно, точность работы модели будет неудовлетворительной. Это происходит из-за того, что обучающая и тестовая выборки содержат изображения красных роз и роз различных цветов в разных пропорциях. Другими словами, если модель обучена отображению из множества [math]X[/math] в множество [math]Y[/math] и если пропорция элементов в [math]X[/math] изменяется, то появляется необходимость обучить модель заново, чтобы "выровнять" пропорции элементов в [math]X[/math] и [math]Y[/math]. Когда пакеты содержат изображения разных классов, распределенные в одинаковой пропорции на всем множестве, то ковариантный сдвиг незначителен. Однако, когда пакеты выбираются только из одного или двух подмножеств (в данном случае, красные розы и розы различных цветов), то ковариантный сдвиг возрастает. Это довольно сильно замедляет процесс обучения модели. На Рисунке 1 изображена разница в пропорциях.

Простой способ решить проблему ковариантного сдвига для входного слоя — это случайным образом перемешать данные перед созданием пакетов. Но для скрытых слоев нейронной сети такой метод не подходит, так как распределение входных данных для каждого узла скрытых слоев изменяется каждый раз, когда происходит обновление параметров в предыдущем слое. Эта проблема называется внутренним ковариантным сдвигом (англ. internal covariate shift). Для решения данной проблемы часто приходится использовать низкий темп обучения (англ. learning rate) и методы регуляризации при обучении модели. Другим способом устранения внутреннего ковариантного сдвига является метод пакетной нормализации.

Свойства пакетной нормализации[править]

Кроме того, использование пакетной нормализации обладает еще несколькими дополнительными полезными свойствами:

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

Описание метода[править]

Опишем устройство метода пакетной нормализации. Пусть на вход некоторому слою нейронной сети поступает вектор размерности [math]d[/math]: [math]x = (x^{(1)}, \ldots, x^{(d)})[/math]. Нормализуем данный вектор по каждой размерности [math]k[/math]:

[math]\hat{x}^{(k)} = \displaystyle \frac{x^{(k)} - E(x^{(k)})}{\sqrt{D(x^{(k)})}}[/math],

где математическое ожидание и дисперсия считаются по всей обучающей выборке. Такая нормализация входа слоя нейронной сети может изменить представление данных в слое. Чтобы избежать данной проблемы, вводятся два параметра сжатия и сдвига нормализованной величины для каждого [math]x^{(k)}[/math]: [math]\gamma^{(k)}[/math], [math]\beta^{(k)}[/math] — которые действуют следующим образом:

[math]y^{(k)} = \gamma^{(k)} \hat{x}^{(k)} + \beta^{(k)}[/math].

Данные параметры настраиваются в процессе обучения вместе с остальными параметрами модели.

Пусть обучение модели производится с помощью пакетов [math]B[/math] размера [math]m[/math]: [math]B = \{x_{1},\ldots, x_{m}\}[/math]. Здесь нормализация применяется к каждому элементу входа с номером [math]k[/math] отдельно, поэтому в [math]x^{(k)}[/math] индекс опускается для ясности изложения. Пусть были получены нормализованные значения пакета [math]\hat{x}_{1},\ldots, \hat{x}_{m}[/math]. После применения операций сжатия и сдвига были получены [math]y_{1},\ldots, y_{m}[/math]. Обозначим данную функцию пакетной нормализации следующим образом:

[math]BN_{\gamma, \beta}: \{x_{1},\ldots, x_{m}\} \rightarrow \{y_{1},\ldots, y_{m}\}[/math]

Тогда алгоритм пакетной нормализации можно представить так:

Вход: значения [math]x[/math] из пакета [math]B = \{x_{1},\ldots, x_{m}\}[/math]; настраиваемые параметры [math]\gamma, \beta[/math]; константа [math]\epsilon[/math] для вычислительной устойчивости.
Выход: [math]\{y_{i} = BN_{\gamma, \beta}(x_{i})\}[/math]
[math]\mu_{B} = \displaystyle \frac{1}{m} \sum_{i=1}^{m} x_{i}[/math] // математическое ожидание пакета
[math]\sigma_{B}^{2} = \displaystyle \frac{1}{m} \sum_{i=1}^{m} (x_{i} - \mu_{B})^{2}[/math] // дисперсия пакета
[math]\hat{x}_{i} = \displaystyle \frac{x_{i} - \mu_{B}}{\sqrt{\sigma_{B}^{2} + \epsilon}}[/math] // нормализация
[math]y_{i} = \gamma \hat{x}_{i} + \beta \equiv BN_{\gamma, \beta}(x_{i}) [/math] // сжатие и сдвиг

Заметим, что если [math]\beta=\mu_{B}[/math] и [math]\gamma=\sqrt{\sigma_{B}^{2} + \epsilon}[/math], то [math]y_{i}[/math] равен [math]x_{i}[/math], то есть [math]BN_{\gamma, \beta}(\cdot)[/math] является тождественным отображением. Таким образом, использование пакетной нормализации не может привести к снижению точности, поскольку оптимизатор просто может использовать нормализацию как тождественное отображение.

Обучение нейронных сетей с пакетной нормализацией[править]

Рисунок 2. Граф вычислений слоя пакетной нормализации алгоритмом обратного распространения ошибки. Слева-направо черными стрелками показана работа алгоритма в прямом направлении. А справа-налево красными стрелками — в обратном направлении, где вычисляется градиент функции потерь. Здесь [math]N=m[/math] и [math]D=d[/math]. Иллюстрация из статьи.

Для обучения нейронных сетей необходимо вычислять градиент функции потерь [math]l[/math]. В случае использования метода пакетной нормализации градиент вычисляется следующим образом:

[math]\displaystyle \frac{\partial l}{\partial \hat{x}_{i}} = \frac{\partial l}{\partial y_{i}} \cdot \gamma[/math] [math] (1)[/math]

[math]\displaystyle \frac{\partial l}{\partial \sigma_{B}^{2}} = \sum_{i=1}^{m}\frac{\partial l}{\partial \hat{x}_{i}} \cdot (x_{i} - \mu_{B}) \cdot \frac{-1}{2}(\sigma_{B}^{2} + \epsilon)^{-3/2}[/math] [math] (2)[/math]

[math]\displaystyle \frac{\partial l}{\partial \mu_{B}} = \left(\sum_{i=1}^{m}\frac{\partial l}{\partial \hat{x}_{i}} \cdot \frac{-1}{\sqrt{\sigma_{B}^{2} + \epsilon}}\right) + \frac{\partial l}{\partial \sigma_{B}^{2}} \cdot \frac{\sum_{i=1}^{m}-2(x_{i}-\mu_{B})}{m}[/math] [math] (3)[/math]

[math]\displaystyle \frac{\partial l}{\partial x_{i}} = \frac{\partial l}{\partial \hat{x}_{i}} \cdot \frac{1}{\sqrt{\sigma_{B}^{2} + \epsilon}} + \frac{\partial l}{\partial \sigma_{B}^{2}} \cdot \frac{2(x_{i}-\mu_{B})}{m} + \frac{\partial l}{\partial \mu_{B}} \cdot \frac{1}{m}[/math] [math] (4)[/math]

[math]\displaystyle \frac{\partial l}{\partial \gamma} = \sum_{i=1}^{m}\frac{\partial l}{\partial y_{i}} \cdot \hat{x}_{i}[/math] [math] (5)[/math]

[math]\displaystyle \frac{\partial l}{\partial \beta} = \sum_{i=1}^{m}\frac{\partial l}{\partial y_{i}}[/math] [math] (6)[/math]

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

В прямом направлении, как и описано в алгоритме метода, из входа [math]x[/math] вычисляется среднее значение по каждой размерности признакового пространства. Затем полученный вектор средних значение вычитается из каждого элемента обучающей выборки. Далее вычисляется дисперсия, и с помощью нее вычисляется знаменатель для нормализации. Затем полученное значение инвертируется и умножается на разницу входа [math]x[/math] и средних значений. В конце применяются параметры [math]\gamma[/math] и [math]\beta[/math].

В обратном направлении вычисляются производные необходимых функций. В следующей таблице подробнее изображены шаги вычисления градиента функции потерь (иллюстрации из статьи, здесь [math]N=m[/math] и [math]D=d[/math]):

Шаг Изображение Описание
1 Step9.png Сначала вычисляется производная по параметру [math]\beta[/math], как в уравнении [math](6)[/math], так как к нему применяется только операции суммирования. И значение градиента выхода передается без изменений.
2 Step8.png Далее, пользуясь правилом вычисления производной при умножении, как в уравнении [math](5)[/math], вычисляется градиент по параметру [math]\gamma[/math]. Градиент выхода умножается на данную константу, получая уравнение [math](1)[/math], и передается в следующий узел.
3 Step7.png Данный шаг вычисляется аналогично предыдущему, применяя правило вычисления производной при умножении.
4 Step6.png Пользуясь производной обратной величины, вычисляем следующий узел графа.
5 Step5.png Вычисляем производную квадратного корня с добавлением [math]\epsilon[/math].
6 Step4.png Вычисляем производную суммы по всем компонентам входного вектора, получая матрицу.
7 Step3.png Получаем производную квадрата входящей функции.
8 Step2.png На данном шаге в одном узле сходятся ветки, поэтому полученные производные просто складываются, получая уравнение [math](2)[/math] для производной по дисперсии.
9 Step1.png Аналогично шагу 6 вычисляем матрицу по сумме для производной по математическому ожиданию, получая формулу [math](3)[/math].
10 Step0.png В начальной вершине получаем уравнение [math](4)[/math], складывая входящие производные.

Пакетная нормализация в свёрточных сетях[править]

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

[math]z = g(Wu + b)[/math],

где [math]W[/math] и [math]b[/math] — настраиваемые параметры модели, а [math]g(\cdot)[/math] — некоторая нелинейная функция, например cигмоида или ReLU. Данной функцией можно описать как обычные, так и сверточные слои нейронных сетей. Пакетная нормализация применяется сразу перед функцией [math]g(\cdot)[/math] к [math]x = Wu + b[/math]. Параметр [math]b[/math] может быть опущен, так как в дальнейших вычислениях его роль будет играть параметр [math]\beta[/math]. Поэтому [math]z = g(Wu + b)[/math] может быть записано так:

[math]z = g(BN(Wu))[/math],

где [math]BN[/math] применяется отдельно к каждой размерности [math]x=Wu[/math] с отдельной парой параметров [math]\gamma^{(k)}[/math] и [math]\beta^{(k)}[/math] для каждой размерности.

В случае свёрточных сетей, дополнительно необходима нормализация, чтобы удовлетворить свойство свёрточных сетей, что различные элементы в разных местах одной карты признаков (образ операции свёртки, англ. feature map) должны быть нормализованы одинаково. Чтобы этого добиться, нормализация выполняется совместно над всеми значениями в пакете. Пусть [math]B[/math] — множество всех значений в карте признаков по всему пакету и всем точкам в карте признаков. Тогда для пакета размера [math]m[/math] и карты признаков размера [math]p \times q[/math] размер [math]B[/math] равен [math]m'=|B|=m \cdot pq[/math]. Тогда параметры [math]\gamma^{(k)}[/math] и [math]\beta^{(k)}[/math] настраиваются для каждой карты признаков отдельно.

Пример[править]

Рисунок 3. Точность распознавания в зависимости от итерации обучения. Оранжевая кривая изображает результаты для модели с использованием пакетной нормализации, синяя кривая — без. Иллюстрация из статьи.
Рисунок 4. Точность распознавания в зависимости от итерации обучения c использованием сигмоиды в качетсве функции активации. Иллюстрация из статьи.

Приведем пример демонстрирующий работу пакетной нормализации. Рассмотрим задачу распознавания рукописных цифр на известном датасете MNIST [3]. Для решения задачи будет использоваться обычная нейронная сеть с [math]3[/math] скрытыми полносвязными слоями по [math]100[/math] узлов в каждом. Функция активации — ReLU. Выходной слой содержит [math]10[/math] узлов. Размер пакета равен [math]60[/math]. Сравниваются две одинаковые модели, но в первой перед каждым скрытым слоем используется пакетная нормализация, а во второй — нет. Темп обучения равен [math]0.01[/math]. Веса инициализированы значениями с малой дисперсией.

На Рисунке 3 изображены два графика, показывающие разницу между моделями. Как видно, обе модели достигли высокой точности, но модель с использованием пакетной нормализации достигла точности более [math]90\%[/math] быстрее, почти сразу, и достигла максимума, примерно, уже на [math]10000[/math] итераций. Однако, модель без пакетной нормализации достигла скорости обучения примерно [math]510[/math] пакетов в секунду, а модель с использованием пакетной нормализации — [math]270[/math]. Однако, как можно видеть, пакетная нормализация позволяет выполнить меньшее количество итераций и, в итоге, сойтись за меньшее время.

На Рисунке 4 изображен график, сравнивающий точно такие же модели, но с использованием сигмоиды в качестве функции активации. Такая конфигурация моделей требует большего времени, чтобы начать обучение. В итоге, модель обучается, но на это потребовалось более [math]45000[/math] итераций, чтобы получить точность более [math]80\%[/math]. При использовании пакетной нормализации получилось достичь точность более [math]90\%[/math] примерно за [math]1000[/math] итераций.

Реализации[править]

Механизм пакетной нормализации реализован практически во всех современных инструментариях для машинного обучения, таких как: TensorFlow [4], Keras [5], CNTK [6], Theano [7], PyTorch [8] и т.д.

Приведем пример[9] применения пакетной нормализации с использованием библиотеки TensorFlow на языке программирования Python [10]:

 import tensorflow as tf
 # ...
 is_train = tf.placeholder(tf.bool, name="is_train");
 # ...
 x_norm = tf.layers.batch_normalization(x, training=is_train)
 # ...
 update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS)
 with tf.control_dependencies(update_ops):
     train_op = optimizer.minimize(loss)

Модификации[править]

Существует несколько модификаций и вариаций метода пакетной нормализации:

  1. Тим Койманс[11] в 2016 г. предложил способ применения пакетной нормализации к рекуррентным нейронным сетям;
  2. Расширение метода пакетной нормализации было предложено Ликси Хуангом[12] в 2018 г. Метод получил название декоррелированная пакетная нормализация (англ. Decorrelated Batch Normalization). В данном методе кроме операций масштабирования и сдвига была предложено использование специальной функции затирания данных;
  3. Джимми Лей Ба[13] в 2016 г. предложил метод нормализации слоев (англ. Layer Normalization), который решает проблему выбора размера пакета;
  4. В работе Сергея Иоффе[14] в 2017 г. было представлено расширение метода пакетной нормализации: пакетная ренормализация (англ. Batch Renormalization). Данный метод улучшает пакетную нормализацию, когда размер пакетов мал и не состоит из независимых данных;
  5. Метод потоковой нормализации (англ. Streaming Normalization) был предложен Кифэном Ляо[15] в 2016 г. Данный метод убирает два ограничения пакетной нормализации: использование при online-обучении и использование в рекуррентных нейронных сетях.

См. также[править]

Примечания[править]

Источники информации[править]