我在哪里可以在Keras中调用BatchNormalization函数?


166

如果我想在Keras中使用BatchNormalization函数,那么是否仅需要在开始时调用一次?

我为此阅读了该文档: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)

我问,因为如果我用第二行(包括批处理规范化)运行代码,而如果我不使用第二行运行代码,则会得到类似的输出。因此,要么我没有在正确的位置调用该函数,要么我猜它并没有太大的区别。

Answers:


225

只是为了更详细地回答这个问题,正如Pavel所说的,批处理规范化只是另一层,因此您可以使用它来创建所需的网络体系结构。

一般用例是在网络的线性层和非线性层之间使用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
FYI显然,激活功能后,批次归一化在实践中效果更好
Claudiu

10
嗨@Claudiu,您介意扩大本FYI吗?看来与上述答案直接矛盾。
Ben Ogorek

7
@benogorek:可以肯定的是,基本上我完全基于这里的结果,在relu之后放置批处理规范会更好。FWIW我没有在一个尝试过的网络上以一种或另一种方式成功应用它
Claudiu

32
有趣。只是为了跟进,如果您继续阅读该摘要,它表示他们的最佳模型[GoogLeNet128_BN_lim0606]实际上在ReLU之前具有BN层。因此,虽然激活后的BN在孤立的情况下可能会提高准确性,但在构建整个模型之前,最好先执行。激活后放置BN可能会提高准确性,但可能取决于问题。
卢卡斯·拉马丹

7
@CarlThomé之类的。例如,请参阅ReginaldIII的此reddit评论。他们指出:“ BN正在对卷积中的特征分布进行归一化,其中某些特征可能是负的,并且会被诸如ReLU之类的非线性截断。如果在激活之前进行归一化,则将这些负值包括在内在从特征空间中剔除它们之前,立即进行归一化。激活后的BN将对正特征进行归一化,而不会通过统计误差对正特征进行偏斜,这些特征不会使其进入下一个卷积层。”
人与生物圈计划

60

该线程具有误导性。试图评论卢卡斯·斋月的答案,但我没有适当的特权,所以我只想把它放在这里。

在激活功能之后,在此处此处,批标准化最有效就是的原因:它是为防止内部协变量移位而开发的。当激活分布时发生内部协变量移位在整个训练过程中,一层的变化很大。使用批处理规范化,以便由于每个批处理中的参数更新(或至少允许其更改),输入(具体来说,这些输入是激活函数的结果)到特定层的分布不会随时间变化以有利的方式)。它使用批处理统计信息进行归一化,然后使用批处理归一化参数(原始论文中的gamma和beta)“以确保插入到网络中的转换可以表示身份转换”(引自原始论文)。但是关键是我们试图将输入归一化,因此它应该总是紧接在网络的下一层之前。是否


27
我在deeplearning.ai课堂上刚刚看到Andrew Ng表示,深度学习社区对此进行了辩论。他更喜欢在非线性之前应用批量归一化。
shahensha

3
@kRazzyR我的意思是,吴安德(Andrew Ng)教授在其关于deeplearning.ai的深度学习课程中谈到了这个话题。 他说,社区在正确的做事方式上存在分歧,他更喜欢在应用非线性之前应用批处理规范化。
shahensha

3
@jmancuso,在激活之前应用BN。从本文本身来看,方程为g(BN(Wx + b)),其中g激活函数为。
yashgarg1232

43

该线程对于是否应在当前层的非线性之前应用BN或对前一层的激活进行广泛的辩论。

尽管没有正确的答案,但批处理规范化的作者说, 应在当前层的非线性之前立即应用它。原因(引自原文)-

“我们通过归一化x = Wu + b来在非线性之前添加BN变换。我们也可以归一化层输入u,但是由于u可能是另一个非线性的输出,因此其分布的形状可能会在训练,并限制其第一和第二时刻并不能消除协变量偏移,相反,Wu + b更有可能具有对称的,非稀疏的分布,即“更呈高斯分布”(Hyvèarinen&Oja,2000) ;规范化它可能会产生具有稳定分布的激活。”


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'))

怎么样了model.add(BatchNormalization())从不同model.add(BatchNormalization(axis=bn_axis))
kRazzyř

@kRazzR,如果您tensorflow用作后端,则没有什么不同。之所以写在这里,是因为他从keras.applications模块中复制了此代码,bn_axis需要在该模块中指定该代码以同时支持channels_firstchannels_last格式。
ldavid

9
有人可以详细说明一下这与OP问题的关系吗?(我是
NN的

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)))

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停止增加每个时期。在我添加BatchNormalization之后的每个纪元之后,val_acc停滞在相同的数字。我认为批处理规范化应该增加val_acc。我怎么知道它是否正常工作?你知道是什么原因造成的吗?
pr338

不幸的是,该链接不再有效:​​(
user2324712

Keras的分支中有该示例的副本(例如github.com/WenchenLi/kaggle/blob/master/otto/keras/…),但我不知道为什么将其从原始Keras仓库中删除,以及该代码与最新的Keras版本兼容。
Pavel Surmenok

4

批归一化用于通过调整激活的均值和缩放来归一化输入层和隐藏层。由于深度神经网络中具有附加层的这种归一化效果,该网络可以使用更高的学习速率而不会消失或爆炸梯度。此外,批量归一化对网络进行规范化,使其更易于泛化,因此无需使用压差来减轻过度拟合的情况。

在使用Keras中的Dense()或Conv2D()计算线性函数之后,我们立即使用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)

批量标准化如何应用?

假设我们已将a [l-1]输入到层l。同样,我们对层l具有权重W [l]和偏置单元b [l]。令a [l]是为层l计算的激活向量(即,在添加了非线性之后),而z [l]是在添加非线性之前的向量

  1. 使用a [l-1]和W [l]我们可以计算层l的z [l]
  2. 通常,在前馈传播中,我们会在此阶段像z [l] + b [l]一样向z [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])得出a [l],即

a[l] = tanh(z_norm[l])
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.