8.5. Батч-нормализация

Обучение глубоких нейронных сетей — задача непростая. Добиться их сходимости за приёмлемое время бывает непросто. В этом разделе мы описываем батч-нормализацию, популярный и эффективный метод, который стабильно ускоряет сходимость глубоких сетей (Ioffe and Szegedy, 2015). В сочетании с остаточными блоками, которые будут рассмотрены позже в Section 8.6, батч-нормализация позволила специалистам регулярно обучать сети, насчитывающие более 100 слоёв. Дополнительным (случайным) преимуществом батч-нормализации является её встроенная регуляризация.

import torch
from torch import nn
from d2l import torch as d2l

8.5.1. Обучение глубоких сетей

При работе с данными мы часто выполняем их предобработку перед обучением. Выбор методов предобработки данных часто оказывает огромное влияние на итоговые результаты. Вспомним наше применение многослойных перцептронов для прогнозирования цен на дома (Section 5.7). Нашим первым шагом при работе с реальными данными было приведение признаков к виду с нулевым средним \(\boldsymbol{\mu} = 0\) и единичной дисперсией \(\boldsymbol{\Sigma} = \boldsymbol{1}\) по множеству наблюдений (Friedman, 1987), при этом часто масштабировалось последнее так, чтобы диагональ была равна единице, т. е. \(\Sigma_{ii} = 1\). Ещё одна стратегия заключается в приведении векторов к единичной длине, возможно, с нулевым средним для каждого наблюдения. Это может хорошо работать, например, для пространственных данных сенсоров. Эти методы предобработки и многие другие полезны для обеспечения хорошо контролируемой задачи оценки. Обзор методов отбора и извлечения признаков можно найти, например, в статье Guyon et al. (2008). Стандартизация векторов также имеет приятный побочный эффект: она ограничивает сложность функций, действующих на них. Например, знаменитое ограничение радиуса-маржи (Vapnik, 1995) в методах опорных векторов и теорема о сходимости перцептрона (Novikoff, 1962) опираются на входные данные с ограниченной нормой.

Интуитивно понятно, что такая стандартизация хорошо сочетается с нашими оптимизаторами, поскольку она приводит параметры априори к сопоставимому масштабу. Поэтому вполне естественно предположить, что соответствующий шаг нормализации внутри глубокой сети может оказаться полезным. Хотя именно так не рассуждали при изобретении батч-нормализации (Ioffe and Szegedy, 2015), это полезный способ понять её и её родственницу — нормализацию слоя (Ba et al., 2016) — в рамках единого фреймворка.

Во-вторых, для типичной многослойной перцептронной сети (MLP) или свёрточной нейронной сети (CNN) в процессе обучения значения переменных во внутренних слоях (например, результаты аффинных преобразований в MLP) могут сильно варьироваться по величине: как вдоль пути от входного слоя к выходному, так и между нейронами в одном слое, а также во времени из-за обновления параметров модели. Авторы батч-нормализации неформально предположили, что такое смещение распределения этих переменных может затруднять сходимость сети. Интуитивно можно предположить, что если активации одного слоя в 100 раз превышают активации другого, это может потребовать компенсаторной настройки скоростей обучения. Адаптивные алгоритмы оптимизации, такие как AdaGrad (Duchi et al., 2011), Adam (Kingma and Ba, 2014), Yogi (Zaheer et al., 2018) или Distributed Shampoo (Anil et al., 2020), пытаются решить эту проблему с точки зрения оптимизации, например, за счет включения элементов методов второго порядка. Альтернативный подход заключается в том, чтобы предотвратить возникновение проблемы, используя адаптивную нормализацию.

В-третьих, более глубокие сети сложнее и более склонны к переобучению. Это означает, что регуляризация становится более критичной. Одним из распространенных методов регуляризации является добавление шума. Этот подход известен уже давно, например, в контексте добавления шума к входным данным (Bishop, 1995). Он также лежит в основе дропаута, описанного в Section 5.6. Как оказалось, совершенно случайно, батч-нормализация обеспечивает все три преимущества: предобработку, численную устойчивость и регуляризацию.

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

Обратите внимание, что если бы мы попытались применить батч-нормализацию с мини-батчами размера 1, мы бы ничего не смогли выучить. Это связано с тем, что после вычитания средних значений каждое скрытое нейронное单元 приняло бы значение 0. Как можно догадаться, поскольку мы посвящаем целый раздел батч-нормализации, при достаточно больших размерах мини-батчей этот подход оказывается эффективным и стабильным. Один из важных выводов заключается в том, что при использовании батч-нормализации выбор размера батча имеет ещё большее значение, чем без неё, или, по крайней мере, требуется тщательная настройка, поскольку мы можем изменять размер батча.

Обозначим через \(\mathcal{B}\) мини-батч, а через \(\mathbf{x} \in \mathcal{B}\) — вход батч-нормализации (\(\textrm{BN}\)). В этом случае батч-нормализация определяется следующим образом:

(8.5.1)\[\textrm{BN}(\mathbf{x}) = \boldsymbol{\gamma} \odot \frac{\mathbf{x} - \hat{\boldsymbol{\mu}}_\mathcal{B}}{\hat{\boldsymbol{\sigma}}_\mathcal{B}} + \boldsymbol{\beta}.\]

В (8.5.1) \(\hat{\boldsymbol{\mu}}_\mathcal{B}\) — это выборочное среднее, а \(\hat{\boldsymbol{\sigma}}_\mathcal{B}\) — выборочное стандартное отклонение мини-батча \(\mathcal{B}\). После применения стандартизации полученный мини-батч имеет нулевое среднее и единичную дисперсию. Выбор именно единичной дисперсии (вместо какого-либо другого «магического» числа) является произвольным. Мы восстанавливаем эту степень свободы, вводя поэлементные параметры масштабирования \(\boldsymbol{\gamma}\) и сдвига \(\boldsymbol{\beta}\), которые имеют ту же форму, что и \(\mathbf{x}\). Оба они являются параметрами, которые необходимо обучать в процессе обучения модели.

Величины переменных промежуточных слоёв не могут расходиться в процессе обучения, поскольку батч-нормализация активно центрирует и перемасштабирует их обратно к заданному среднему значению и размеру (через \(\hat{\boldsymbol{\mu}}_\mathcal{B}\) и \({\hat{\boldsymbol{\sigma}}_\mathcal{B}}\)). Практический опыт подтверждает, что, как упоминалось при обсуждении перемасштабирования признаков, батч-нормализация позволяет использовать более агрессивные скорости обучения. Мы вычисляем \(\hat{\boldsymbol{\mu}}_\mathcal{B}\) и \({\hat{\boldsymbol{\sigma}}_\mathcal{B}}\) в (8.5.1) следующим образом:

(8.5.2)\[\hat{\boldsymbol{\mu}}_\mathcal{B} = \frac{1}{|\mathcal{B}|} \sum_{\mathbf{x} \in \mathcal{B}} \mathbf{x} \textrm{ and } \hat{\boldsymbol{\sigma}}_\mathcal{B}^2 = \frac{1}{|\mathcal{B}|} \sum_{\mathbf{x} \in \mathcal{B}} (\mathbf{x} - \hat{\boldsymbol{\mu}}_{\mathcal{B}})^2 + \epsilon.\]

Обратите внимание, что мы добавляем малую константу \(\epsilon > 0\) к оценке дисперсии, чтобы гарантировать, что мы никогда не попытаемся выполнить деление на ноль, даже в тех случаях, когда эмпирическая оценка дисперсии может быть очень малой или равной нулю. Оценки \(\hat{\boldsymbol{\mu}}_\mathcal{B}\) и \({\hat{\boldsymbol{\sigma}}_\mathcal{B}}\) противодействуют проблеме масштабирования, используя зашумлённые оценки среднего и дисперсии. Может показаться, что эта зашумлённость должна стать проблемой. Напротив, она оказывается полезной.

Как выяснилось, это повторяющаяся тема в глубоком обучении. По причинам, которые пока не имеют чёткого теоретического обоснования, различные источники шума в процессе оптимизации часто приводят к более быстрому обучению и меньшему переобучению: эта вариация, по-видимому, действует как форма регуляризации. Teye et al. (2018) и Luo et al. (2018) связывают свойства батч-нормализации с байесовскими априорными распределениями и штрафами соответственно. В частности, это проливает свет на загадку того, почему батч-нормализация лучше всего работает для умеренных размеров мини-батча в диапазоне 50–100. Такой конкретный размер мини-батча, кажется, добавляет в каждый слой «правильное количество» шума как по масштабу через \(\hat{\boldsymbol{\sigma}}\), так и по смещению через \(\hat{\boldsymbol{\mu}}\): больший мини-батч обеспечивает менее выраженную регуляризацию из-за более стабильных оценок, тогда как слишком маленькие мини-батчи разрушают полезный сигнал из-за высокой дисперсии. Дальнейшее исследование этого направления, включая рассмотрение альтернативных типов предобработки и фильтрации, может привести к другим эффективным видам регуляризации.

Закрепив обученную модель, можно подумать, что для оценки среднего и дисперсии мы предпочли бы использовать весь набор данных. Почему после завершения обучения одно и то же изображение должно классифицироваться по-разному в зависимости от того, в какой мини-батч оно попало? Во время обучения такой точный расчёт невозможен, поскольку промежуточные переменные для всех примеров данных изменяются каждый раз, когда мы обновляем модель. Однако после завершения обучения мы можем вычислить средние значения и дисперсии переменных каждого слоя на основе всего набора данных. Действительно, это стандартная практика для моделей, использующих батч-нормализацию; поэтому слои батч-нормализации функционируют по-разному в режиме обучения (нормализация по статистике мини-батча) и в режиме предсказания (нормализация по статистике набора данных). В таком виде они тесно напоминают поведение регуляризации дропаут Section 5.6, где шум добавляется только во время обучения.

8.5.2. Слои батч-нормализации

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

8.5.2.1. Полносвязные слои

При применении батч-нормализации к полносвязным слоям Ioffe and Szegedy (2015), в их оригинальной статье авторы помещали батч-нормализацию после аффинного преобразования и перед нелинейной функцией активации. В последующих работах экспериментировали с размещением батч-нормализации непосредственно после функций активации. Обозначая вход полносвязного слоя как \(\mathbf{x}\), аффинное преобразование как \(\mathbf{W}\mathbf{x} + \mathbf{b}\) (с параметром веса \(\mathbf{W}\) и параметром смещения \(\mathbf{b}\)), а функцию активации как \(\phi\), мы можем выразить вычисление выхода полносвязного слоя с поддержкой батч-нормализации \(\mathbf{h}\) следующим образом:

(8.5.3)\[\mathbf{h} = \phi(\textrm{BN}(\mathbf{W}\mathbf{x} + \mathbf{b}) ).\]

Напомним, что среднее значение и дисперсия вычисляются по тому же самому мини-батчу, к которому применяется преобразование.

8.5.2.2. Свёрточные слои

Аналогично свёрточным слоям, батч-нормализацию можно применять после свёртки, но перед нелинейной функцией активации. ⟦key⟧ное отличие батч-нормализации в свёрточных слоях от полносвязных заключается в том, что операция выполняется для каждого канала по всем позициям. Это согласуется с нашим предположением о трансляционной инвариантности, которое привело к использованию свёрток: мы предполагали, что конкретное расположение паттерна внутри изображения не является критичным для понимания.

Предположим, что наши мини-пакеты содержат \(m\) примеров и что для каждого канала выход свёртки имеет высоту \(p\) и ширину \(q\). Для свёрточных слоёв мы выполняем батч-нормализацию одновременно для \(m \cdot p \cdot q\) элементов на каждый выходной канал. Таким образом, при вычислении среднего и дисперсии мы собираем значения по всем пространственным позициям и, следовательно, применяем одно и то же среднее и дисперсию в пределах заданного канала для нормализации значения в каждой пространственной позиции. У каждого канала есть свои собственные параметры масштаба и сдвига, которые являются скалярами.

8.5.2.3. Нормализация слоя

Обратите внимание, что в контексте свёрток батч-нормализация корректно определена даже для мини-выборок размера 1: ведь у нас есть все позиции в пределах одного изображения, по которым можно вычислить среднее. Следовательно, среднее значение и дисперсия определены корректно, даже если они вычисляются только в рамках одного наблюдения. Именно это соображение привело Ba et al. (2016) к введению понятия нормализации слоя. Она работает так же, как и батч-нормализация, но применяется к одному наблюдению за раз. Следовательно, как параметр смещения, так и параметр масштабирования являются скалярами. Для \(n\)-мерного вектора \(\mathbf{x}\) нормы слоя вычисляются следующим образом:

(8.5.4)\[\mathbf{x} \rightarrow \textrm{LN}(\mathbf{x}) = \frac{\mathbf{x} - \hat{\mu}}{\hat\sigma},\]

где масштабирование и смещение применяются поэлементно и задаются как

(8.5.5)\[\hat{\mu} \stackrel{\textrm{def}}{=} \frac{1}{n} \sum_{i=1}^n x_i \textrm{ and } \hat{\sigma}^2 \stackrel{\textrm{def}}{=} \frac{1}{n} \sum_{i=1}^n (x_i - \hat{\mu})^2 + \epsilon.\]

Как и ранее, мы добавляем небольшое смещение \(\epsilon > 0\), чтобы избежать деления на ноль. Одним из главных преимуществ использования нормализации слоя является предотвращение расходимости. Ведь, если пренебречь \(\epsilon\), выход нормализации слоя не зависит от масштаба. То есть, мы имеем \(\textrm{LN}(\mathbf{x}) \approx \textrm{LN}(\alpha \mathbf{x})\) при любом выборе \(\alpha \neq 0\). Это становится равенством для \(|\alpha| \to \infty\) (приближенное равенство обусловлено смещением \(\epsilon\) для дисперсии).

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

8.5.2.4. Батч-нормализация при предсказании

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

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

8.5.3. Реализация с нуля

Чтобы понять, как батч-нормализация работает на практике, мы реализуем её с нуля ниже.

def batch_norm(X, gamma, beta, moving_mean, moving_var, eps, momentum):
    # Use is_grad_enabled to determine whether we are in training mode
    if not torch.is_grad_enabled():
        # In prediction mode, use mean and variance obtained by moving average
        X_hat = (X - moving_mean) / torch.sqrt(moving_var + eps)
    else:
        assert len(X.shape) in (2, 4)
        if len(X.shape) == 2:
            # When using a fully connected layer, calculate the mean and
            # variance on the feature dimension
            mean = X.mean(dim=0)
            var = ((X - mean) ** 2).mean(dim=0)
        else:
            # When using a two-dimensional convolutional layer, calculate the
            # mean and variance on the channel dimension (axis=1). Here we
            # need to maintain the shape of X, so that the broadcasting
            # operation can be carried out later
            mean = X.mean(dim=(0, 2, 3), keepdim=True)
            var = ((X - mean) ** 2).mean(dim=(0, 2, 3), keepdim=True)
        # In training mode, the current mean and variance are used
        X_hat = (X - mean) / torch.sqrt(var + eps)
        # Update the mean and variance using moving average
        moving_mean = (1.0 - momentum) * moving_mean + momentum * mean
        moving_var = (1.0 - momentum) * moving_var + momentum * var
    Y = gamma * X_hat + beta  # Scale and shift
    return Y, moving_mean.data, moving_var.data

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

Отложив в сторону алгоритмические детали, обратите внимание на шаблон проектирования, лежащий в основе нашей реализации слоя. Обычно мы определяем математическую часть в отдельной функции, например batch_norm. Затем мы интегрируем эту функциональность в пользовательский слой, код которого в основном занимается вспомогательными задачами, такими как перемещение данных в нужный контекст устройства, выделение и инициализация необходимых переменных, отслеживание скользящих средних (здесь для среднего и дисперсии) и так далее. Этот шаблон обеспечивает чёткое разделение математики и шаблонного кода. Также обратите внимание, что ради удобства мы не стали здесь заниматься автоматическим выводом формы входных данных; поэтому нам нужно указывать количество признаков на протяжении всего кода. В настоящее время все современные фреймворки глубокого обучения предлагают автоматическое определение размера и формы в высокоуровневых API батч-нормализации (на практике мы будем использовать именно их).

class BatchNorm(nn.Module):
    # num_features: the number of outputs for a fully connected layer or the
    # number of output channels for a convolutional layer. num_dims: 2 for a
    # fully connected layer and 4 for a convolutional layer
    def __init__(self, num_features, num_dims):
        super().__init__()
        if num_dims == 2:
            shape = (1, num_features)
        else:
            shape = (1, num_features, 1, 1)
        # The scale parameter and the shift parameter (model parameters) are
        # initialized to 1 and 0, respectively
        self.gamma = nn.Parameter(torch.ones(shape))
        self.beta = nn.Parameter(torch.zeros(shape))
        # The variables that are not model parameters are initialized to 0 and
        # 1
        self.moving_mean = torch.zeros(shape)
        self.moving_var = torch.ones(shape)

    def forward(self, X):
        # If X is not on the main memory, copy moving_mean and moving_var to
        # the device where X is located
        if self.moving_mean.device != X.device:
            self.moving_mean = self.moving_mean.to(X.device)
            self.moving_var = self.moving_var.to(X.device)
        # Save the updated moving_mean and moving_var
        Y, self.moving_mean, self.moving_var = batch_norm(
            X, self.gamma, self.beta, self.moving_mean,
            self.moving_var, eps=1e-5, momentum=0.1)
        return Y

Мы использовали momentum для управления агрегацией оценок прошлого среднего значения и дисперсии. Это название является somewhat условным, поскольку оно не имеет никакого отношения к члену momentum (импульса) в оптимизации. Тем не менее, это общепринятое название данного термина, и в соответствии с соглашением об именовании в API мы используем то же имя переменной в нашем коде.

8.5.4. LeNet с батч-нормализацией

Чтобы увидеть, как применять BatchNorm на практике, ниже мы применим его к традиционной модели LeNet (Section 7.6). Напомним, что батч-нормализация выполняется после свёрточных или полносвязных слоёв, но перед соответствующими функциями активации.

class BNLeNetScratch(d2l.Classifier):
    def __init__(self, lr=0.1, num_classes=10):
        super().__init__()
        self.save_hyperparameters()
        self.net = nn.Sequential(
            nn.LazyConv2d(6, kernel_size=5), BatchNorm(6, num_dims=4),
            nn.Sigmoid(), nn.AvgPool2d(kernel_size=2, stride=2),
            nn.LazyConv2d(16, kernel_size=5), BatchNorm(16, num_dims=4),
            nn.Sigmoid(), nn.AvgPool2d(kernel_size=2, stride=2),
            nn.Flatten(), nn.LazyLinear(120),
            BatchNorm(120, num_dims=2), nn.Sigmoid(), nn.LazyLinear(84),
            BatchNorm(84, num_dims=2), nn.Sigmoid(),
            nn.LazyLinear(num_classes))

Как и прежде, мы обучим нашу сеть на наборе данных Fashion-MNIST. Этот код практически идентичен тому, который мы использовали при первом обучении LeNet.

trainer = d2l.Trainer(max_epochs=10, num_gpus=1)
data = d2l.FashionMNIST(batch_size=128)
model = BNLeNetScratch(lr=0.1)
model.apply_init([next(iter(data.get_dataloader(True)))[0]], d2l.init_cnn)
trainer.fit(model, data)

Давайте рассмотрим параметр масштаба gamma и параметр сдвига beta, обученные на первом слое батч-нормализации.

model.net[1].gamma.reshape((-1,)), model.net[1].beta.reshape((-1,))

8.5.5. Краткая реализация

В отличие от класса BatchNorm, который мы определили самостоятельно, мы можем напрямую использовать класс BatchNorm, определённый в высокоуровневых API фреймворка глубокого обучения. Код практически идентичен нашей предыдущей реализации, за исключением того, что нам больше не нужно передавать дополнительные аргументы для корректного определения размеров.

class BNLeNet(d2l.Classifier):
    def __init__(self, lr=0.1, num_classes=10):
        super().__init__()
        self.save_hyperparameters()
        self.net = nn.Sequential(
            nn.LazyConv2d(6, kernel_size=5), nn.LazyBatchNorm2d(),
            nn.Sigmoid(), nn.AvgPool2d(kernel_size=2, stride=2),
            nn.LazyConv2d(16, kernel_size=5), nn.LazyBatchNorm2d(),
            nn.Sigmoid(), nn.AvgPool2d(kernel_size=2, stride=2),
            nn.Flatten(), nn.LazyLinear(120), nn.LazyBatchNorm1d(),
            nn.Sigmoid(), nn.LazyLinear(84), nn.LazyBatchNorm1d(),
            nn.Sigmoid(), nn.LazyLinear(num_classes))

Ниже мы используем те же гиперпараметры для обучения модели. Обратите внимание, что, как обычно, вариант с высокоуровневым API работает значительно быстрее, поскольку его код скомпилирован в C++ или CUDA, тогда как наша собственная реализация выполняется интерпретатором Python.

trainer = d2l.Trainer(max_epochs=10, num_gpus=1)
data = d2l.FashionMNIST(batch_size=128)
model = BNLeNet(lr=0.1)
model.apply_init([next(iter(data.get_dataloader(True)))[0]], d2l.init_cnn)
trainer.fit(model, data)

8.5.6. Обсуждение

Интуитивно считается, что батч-нормализация делает ландшафт оптимизации более гладким. Однако следует осторожно относиться к спекулятивным интуициям и отличать их от истинных объяснений явлений, наблюдаемых при обучении глубоких моделей. Напомним, что мы даже не знаем, почему более простые глубокие нейронные сети (многослойные перцептроны и обычные свёрточные нейронные сети) обладают хорошей обобщающей способностью. Даже при использовании дропаута и затухания весов они остаются настолько гибкими, что их способность обобщать данные, не встречавшиеся в обучающей выборке, вероятно, требует значительно более строгих теоретико-обучающих гарантий обобщения.

В оригинальной статье, предлагающей батч-нормализацию (Ioffe and Szegedy, 2015), наряду с описанием мощного и полезного инструмента, было предложено объяснение того, почему она работает: за счет уменьшения внутреннего сдвига ковариации. Вероятно, под внутренним сдвигом ковариации авторы имели в виду интуицию, выраженную выше, — идею о том, что распределение значений переменных меняется в процессе обучения. Однако у этого объяснения было две проблемы: i) этот дрейф сильно отличается от сдвига ковариации, поэтому название является некорректным. Скорее, оно ближе к сдвигу концепции. ii) Это объяснение дает недостаточно конкретную интуицию, оставляя вопрос о том, почему именно этот метод работает, открытым и требующим строгого обоснования. В течение всей этой книги мы стремимся передать интуиции, которыми руководствуются практики при разработке глубоких нейронных сетей. Однако мы считаем важным отделять эти направляющие интуиции от установленных научных фактов. В конечном итоге, когда вы освоите этот материал и начнете писать собственные исследовательские статьи, вам потребуется чётко разграничивать технические утверждения и предположения.

После успеха батч-нормализации её объяснение через концепцию внутреннего ковариатного сдвига неоднократно становилось предметом дискуссий в технической литературе и более широком обсуждении того, как представлять исследования в области машинного обучения. В запоминающейся речи, произнесённой при получении награды Test of Time Award на конференции NeurIPS 2017 года, Али Рахими использовал внутренний ковариатный сдвиг как ключевой аргумент в споре, сравнивая современную практику глубокого обучения с алхимией. Впоследствии этот пример был подробно рассмотрен в позиционной статье, в которой описывались тревожные тенденции в машинном обучении (Lipton and Steinhardt, 2018). Другие авторы предложили альтернативные объяснения успеха батч-нормализации; некоторые (Santurkar et al., 2018) утверждают, что её успех достигается вопреки поведению, которое в некотором роде противоположно тому, что утверждалось в оригинальной статье.

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

С практической точки зрения, следует помнить о нескольких аспектах, связанных с батч-нормализацией:

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

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

  • Как и слой дропаута, слои батч-нормализации ведут себя по-разному в режиме обучения и в режиме предсказания.

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

  • Для получения более устойчивых моделей, менее чувствительных к возмущениям входных данных, рассмотрите возможность отказа от батч-нормализации (Wang et al., 2022).

8.5.7. Упражнения

  1. Следует ли удалять параметр смещения из полносвязного слоя или из свёрточного слоя перед батч-нормализацией? Почему?

  2. Сравните скорости обучения для LeNet с батч-нормализацией и без нее.

    1. Постройте график роста точности на валидационной выборке.

    2. Насколько большим можно сделать скорость обучения, прежде чем оптимизация потерпит неудачу в обоих случаях?

  3. Нужна ли батч-нормализация в каждом слое? Поэкспериментируйте с этим.

  4. Реализуйте «облегченную» версию батч-нормализации, которая только вычитает среднее, или, альтернативно, такую, которая только вычитает дисперсию. Как она ведет себя?

  5. Исправьте параметры beta и gamma. Наблюдайте и анализируйте результаты.

  6. Можно ли заменить дропаут батч-нормализацией? Как изменится поведение?

  7. Исследовательские задачи: придумайте другие преобразования нормализации, которые можно применить:

    1. Можно ли применить интегральное преобразование вероятности?

    2. Можно ли использовать оценку ковариации полного ранга? Почему, вероятно, не стоит этого делать?

    3. Можно ли использовать другие компактные варианты матриц (блочно-диагональные, с низкой рангой смещения, Monarch и т. д.)?

    4. Служит ли сжатие за счёт разреженности регуляризатором?

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

Обсуждения