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

时间:2016-01-11 07:47:53

标签: python neural-network keras data-science

如果我想在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)

我问,因为如果我运行包含批量规范化的第二行的代码,如果我运行没有第二行的代码,我得到类似的输出。所以要么我没有在正确的位置调用该功能,要么我认为它没有那么大的差别。

8 个答案:

答案 0 :(得分:176)

只是更详细地回答这个问题,正如Pavel所说,批量标准化只是另一层,因此您可以使用它来创建所需的网络架构。

一般用例是在网络中的线性和非线性层之间使用BN,因为它将激活函数的输入标准化,以便您在激活函数的线性部分中居中(如Sigmoid)。对它进行了一些小讨论here

在上面的情况中,这可能如下所示:

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

希望这能澄清一些事情。

答案 1 :(得分:38)

此主题具有误导性。尝试评论Lucas Ramadan的回答,但我还没有正确的权限,所以我只想把它放在这里。

批量标准化在激活功能之后效果最佳,herehere就是原因:它是为了防止内部协变量偏移而开发的。当整个训练过程中层的激活的分布发生显着变化时,会发生内部协变量偏移。使用批量标准化,以便输入(以及这些输入实际上是激活函数的结果)到特定层的分布不会随着时间的推移而变化,因为每个批次的参数更新(或者至少允许它更改)以有利的方式)。它使用批量统计进行规范化,然后使用批量标准化参数(原始论文中的gamma和beta)“以确保插入网络中的转换可以表示身份转换”(引自原始论文)。但重点是我们正在尝试将输入规​​范化为一个层,因此它应该始终紧接在网络中的下一层之前。激活功能之后是否依赖于相关架构。

答案 2 :(得分:31)

这个主题在是否应该在当前层的非线性或前一层的激活之前应用BN方面存在一些争论。

虽然没有正确的答案,批量标准化的作者说 应该在当前图层的非线性之前立即应用。原因(引自原始论文) -

  

“我们在之前添加BN变换   非线性,通过归一化x = Wu + b。我们可以有   也标准化了层输入u,但因为你很可能   另一个非线性的输出,其分布的形状   在训练和约束期间可能会发生变化   它的第一和第二时刻不会消除协变量   转移。相比之下,吴+ b更有可能拥有   对称的非稀疏分布,即“更高斯”   (Hyv¨arinen& Oja,2000);正常化它很可能   产生具有稳定分布的激活。“

答案 3 :(得分:25)

现在几乎成为一种趋势,即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)))

答案 4 :(得分:25)

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

答案 5 :(得分:3)

它是另一种类型的图层,因此您应该将其作为图层添加到模型的适当位置

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

请在此处查看示例:https://github.com/fchollet/keras/blob/master/examples/kaggle_otto_nn.py

答案 6 :(得分:1)

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

在使用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])

答案 7 :(得分:0)

为关于是否应该在非线性激活之前或之后调用批标准化的辩论添加另一个条目:

除了原始论文在激活前使用批归一化之外,Bengio 的书 Deep Learning, section 8.7.1 给出了一些推理为什么在激活之后(或直接在输入到下一层之前)应用批归一化可能会导致一些问题:

<块引用>

很自然地想知道我们是否应该将批量归一化应用于 输入 X,或转换后的值 XW+b。 Ioffe 和 Szegedy (2015) 推荐后者。更具体地说,XW+b 应该替换为 a XW 的标准化版本。应该省略偏置项,因为它 随着批处理应用的 β 参数变得多余 归一化重新参数化。层的输入通常是 非线性激活函数的输出,例如整流线性 上一层的功能。因此,输入的统计信息是 更非高斯,更不适合线性标准化 操作。

换句话说,如果我们使用 relu 激活,所有负值都映射为零。这可能会导致平均值已经非常接近于零,但剩余数据的分布将严重偏向右侧。尝试将该数据标准化为漂亮的钟形曲线可能不会给出最佳结果。对于 relu 系列之外的激活,这可能不是什么大问题。

请记住,有报告称模型在激活后使用批归一化获得更好的结果,而其他模型在激活之前使用批归一化获得最佳结果。最好使用这两种配置来测试您的模型,如果激活后的批量标准化显着降低了验证损失,请改用该配置。