Где я могу вызвать функцию BatchNormalization в Keras?

168

Если я хочу использовать функцию BatchNormalization в Keras, то нужно ли вызывать ее один раз только в начале?

Я прочитал эту документацию для этого: http://keras.io/layers/normalization/

Я не понимаю, где я должен это назвать. Ниже мой код пытается использовать его:

model = Sequential()
keras.layers.normalization.BatchNormalization(epsilon=1e-06, mode=0, momentum=0.9, weights=None)
model.add(Dense(64, input_dim=14, init='uniform'))
model.add(Activation('tanh'))
model.add(Dropout(0.5))
model.add(Dense(64, init='uniform'))
model.add(Activation('tanh'))
model.add(Dropout(0.5))
model.add(Dense(2, init='uniform'))
model.add(Activation('softmax'))

sgd = SGD(lr=0.1, decay=1e-6, momentum=0.9, nesterov=True)
model.compile(loss='binary_crossentropy', optimizer=sgd)
model.fit(X_train, y_train, nb_epoch=20, batch_size=16, show_accuracy=True, validation_split=0.2, verbose = 2)

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

pr338
источник

Ответы:

225

Просто чтобы ответить на этот вопрос немного подробнее, и, как сказал Павел, Batch Normalization - это просто еще один уровень, поэтому вы можете использовать его как таковой для создания желаемой сетевой архитектуры.

Общий вариант использования состоит в том, чтобы использовать BN между линейным и нелинейным слоями в вашей сети, поскольку он нормализует входные данные для вашей функции активации, так что вы центрированы в линейном участке функции активации (например, Sigmoid). Там небольшая дискуссия об этом здесь

В вашем случае выше это может выглядеть так:


# import BatchNormalization
from keras.layers.normalization import BatchNormalization

# instantiate model
model = Sequential()

# we can think of this chunk as the input layer
model.add(Dense(64, input_dim=14, init='uniform'))
model.add(BatchNormalization())
model.add(Activation('tanh'))
model.add(Dropout(0.5))

# we can think of this chunk as the hidden layer    
model.add(Dense(64, init='uniform'))
model.add(BatchNormalization())
model.add(Activation('tanh'))
model.add(Dropout(0.5))

# we can think of this chunk as the output layer
model.add(Dense(2, init='uniform'))
model.add(BatchNormalization())
model.add(Activation('softmax'))

# setting up the optimization of our weights 
sgd = SGD(lr=0.1, decay=1e-6, momentum=0.9, nesterov=True)
model.compile(loss='binary_crossentropy', optimizer=sgd)

# running the fitting
model.fit(X_train, y_train, nb_epoch=20, batch_size=16, show_accuracy=True, validation_split=0.2, verbose = 2)

Надеюсь, это прояснит ситуацию немного больше.

Лукас Рамадан
источник
25
К вашему сведению, нормализация партии работает лучше на практике после активации функции
Claudiu
10
Привет @Claudiu, не могли бы вы остановиться на этом FYI? Похоже, прямо противоречит ответу выше.
Бен Огорек
7
@benogorek: уверен , что, в основном я основывался исключительно на результатах здесь , где поместить пакетную норму после того , как Relu выполняется лучше. FWIW У меня не было успеха, применяя это так или иначе в одной сети, которую я пробовал
Claudiu
32
Интересный. Просто для продолжения, если вы продолжите читать в этом резюме, он говорит, что их лучшая модель [GoogLeNet128_BN_lim0606] на самом деле имеет уровень BN ДО RELU. Таким образом, хотя BN после активации может повысить точность в единичном случае, когда вся модель построена, прежде чем выполнить лучше. Возможно, что размещение BN после активации может повысить точность, но, вероятно, зависит от проблемы.
Лукас Рамадан
7
@ CarlThomé вроде. Смотрите этот реддит комментарий ReginaldIII, например. Они заявляют: «BN нормализует распределение признаков, полученных в результате свертки, некоторые из этих функций могут быть отрицательными [и] усечены нелинейностью, такой как ReLU. Если вы нормализуетесь до активации, вы включаете эти отрицательные значения в нормализация непосредственно перед отбраковкой их из пространства признаков. BN после активации нормализует положительные признаки без статистического смещения их с признаками, которые не доходят до следующего сверточного слоя. "
МАБ
60

Эта тема вводит в заблуждение. Пробовал комментировать ответ Лукаса Рамадана, но у меня пока нет нужных привилегий, поэтому я просто выложу это здесь.

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

jmancuso
источник
27
Я только что видел в классе deeplearning.ai, что Эндрю Нг говорит, что в сообществе Deep Learning идет спор об этом. Он предпочитает применять нормализацию партии перед нелинейностью.
Шахенша
3
@kRazzyR Я имел в виду, что профессор Эндрю Нг говорил об этой теме в своих уроках глубокого обучения по deeplearning.ai. Он сказал, что сообщество разделено на правильном способе ведения дел и что он предпочитает применять пакетную нормализацию перед применением нелинейности.
Шахенша
3
@jmancuso, BN применяется до активации. Из самой статьи уравнение есть g(BN(Wx + b))где gфункция активации.
yashgarg1232
43

В этой ветке ведутся серьезные дебаты о том, следует ли применять BN до нелинейности текущего слоя или для активаций предыдущего слоя.

Хотя нет правильного ответа, авторы Batch Normalization говорят, что он должен быть применен непосредственно перед нелинейностью текущего слоя. Причина (цитата из оригинальной статьи) -

«Мы добавляем преобразование BN непосредственно перед нелинейностью, нормализуя x = Wu + b. Мы могли бы также нормализовать входы слоя u, но, поскольку u, вероятно, является выходом другой нелинейности, форма его распределения, вероятно, изменится во время тренировка и ограничение его первого и второго моментов не устранят ковариатный сдвиг. Напротив, Wu + b, скорее всего, будет иметь симметричное, не разреженное распределение, то есть «более гауссово» (Hyv¨arinen & Oja, 2000) нормализация может привести к активациям со стабильным распределением ».

user12340
источник
3
По моему личному опыту, это не имеет большого значения, но при прочих равных условиях я всегда видел, как BN работает немного лучше, когда нормализация партии применяется до нелинейности (до функции активации).
Брэд Гессе
31

Keras теперь поддерживает эту use_bias=Falseопцию, поэтому мы можем сохранить некоторые вычисления, написав

model.add(Dense(64, use_bias=False))
model.add(BatchNormalization(axis=bn_axis))
model.add(Activation('tanh'))

или

model.add(Convolution2D(64, 3, 3, use_bias=False))
model.add(BatchNormalization(axis=bn_axis))
model.add(Activation('relu'))
dontloo
источник
чем model.add(BatchNormalization())отличается отmodel.add(BatchNormalization(axis=bn_axis))
kRazzy R
@kRazzR это не отличается, если вы используете в tensorflowкачестве бэкэнда. Это написано здесь, потому что он скопировал это из keras.applicationsмодуля, где bn_axisнужно указать, чтобы поддерживать оба channels_firstи channels_lastформаты.
ldavid
9
Может кто-нибудь уточнить, как это связано с вопросом ОП? (Я довольно новичок в NNs, так что, может быть, я что-то упустил.)
Pepacz
30

Это почти стала тенденцией теперь имеет Conv2Dсопровождаемую ReLuпоследующий BatchNormalizationслой. Поэтому я создал небольшую функцию, чтобы вызывать их все сразу. Делает определение модели намного понятнее и легче для чтения.

def Conv2DReluBatchNorm(n_filter, w_filter, h_filter, inputs):
    return BatchNormalization()(Activation(activation='relu')(Convolution2D(n_filter, w_filter, h_filter, border_mode='same')(inputs)))
stochastic_zeitgeist
источник
7
может толкнуть это в керас?
sachinruk
6

Это другой тип слоя, поэтому вы должны добавить его в качестве слоя в соответствующем месте вашей модели

model.add(keras.layers.normalization.BatchNormalization())

Смотрите пример здесь: https://github.com/fchollet/keras/blob/master/examples/kaggle_otto_nn.py

Павел Сурменок
источник
1
После того, как я добавил BatchNormalization, значение val_acc перестало увеличиваться с каждой эпохой. Val_acc оставался неизменным на том же номере после каждой эпохи после того, как я добавил BatchNormalization. Я думал, что нормализация партии должна была увеличить val_acc. Как мне узнать, работает ли он правильно? Вы знаете, что могло быть причиной этого?
pr338
к сожалению ссылка больше не действительна :(
user2324712
В вилках Keras есть копии этого примера (например, github.com/WenchenLi/kaggle/blob/master/otto/keras/… ), но я не знаю, почему он был удален из исходного репозитория Keras, и если Код совместим с последними версиями Keras.
Павел Сурменок
4

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

Сразу после вычисления линейной функции, скажем, Dense () или Conv2D () в Keras, мы используем BatchNormalization (), которая вычисляет линейную функцию в слое, а затем мы добавляем нелинейность в слой, используя Activation ().

from keras.layers.normalization import BatchNormalization
model = Sequential()
model.add(Dense(64, input_dim=14, init='uniform'))
model.add(BatchNormalization(epsilon=1e-06, mode=0, momentum=0.9, weights=None))
model.add(Activation('tanh'))
model.add(Dropout(0.5))
model.add(Dense(64, init='uniform'))
model.add(BatchNormalization(epsilon=1e-06, mode=0, momentum=0.9, weights=None))
model.add(Activation('tanh'))
model.add(Dropout(0.5))
model.add(Dense(2, init='uniform'))
model.add(BatchNormalization(epsilon=1e-06, mode=0, momentum=0.9, weights=None))
model.add(Activation('softmax'))

sgd = SGD(lr=0.1, decay=1e-6, momentum=0.9, nesterov=True)
model.compile(loss='binary_crossentropy', optimizer=sgd)
model.fit(X_train, y_train, nb_epoch=20, batch_size=16, show_accuracy=True, 
validation_split=0.2, verbose = 2)

Как применяется нормализация партии?

Предположим, мы ввели слой [l-1] в слой l. Также мы имеем веса W [l] и единицу смещения b [l] для слоя l. Пусть a [l] будет вектором активации, рассчитанным (т.е. после добавления нелинейности) для слоя l, а z [l] будет вектором до добавления нелинейности

  1. Используя [l-1] и W [l] мы можем вычислить z [l] для слоя l
  2. Обычно при прямом распространении мы добавляем единицу смещения к z [l] на этом этапе, как это z [l] + b [l], но в нормализации партии этот шаг добавления b [l] не требуется и нет b [l] параметр используется.
  3. Рассчитать z [l] означает и вычесть его из каждого элемента
  4. Разделите (z [l] - среднее), используя стандартное отклонение. Назовите это Z_temp [l]
  5. Теперь определите новые параметры γ и β, которые изменят масштаб скрытого слоя, следующим образом:

    z_norm [l] = γ.Z_temp [l] + β

В этом фрагменте кода Dense () принимает a [l-1], использует W [l] и вычисляет z [l]. Затем немедленная BatchNormalization () выполнит вышеуказанные шаги, чтобы получить z_norm [l]. И тогда немедленная Activation () вычислит tanh (z_norm [l]), чтобы получить [l], т.е.

a[l] = tanh(z_norm[l])
Айшвария Радхакришнан
источник