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

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

我问是因为如果我运行包含批处理规格化的第二行代码,如果我不运行第二行代码,我会得到类似的输出。所以要么我没有在正确的地方调用函数,要么我猜这没有太大的区别。

231641 次浏览

它是另一种类型的层,所以你应该把它作为一个层添加到你的模型的适当位置

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

参见下面的例子:https://github.com/fchollet/keras/blob/master/examples/kaggle_otto_nn.py

为了更详细地回答这个问题,正如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)

希望这能让你更清楚一些。

现在有一个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)))

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

这个帖子有误导性。我试着评论卢卡斯·拉马丹的回答,但我还没有权限,所以我把这个放在这里。

批处理归一化在激活函数之后工作得最好,而在这里在这里是为什么:它是为了防止内部协变量移位而开发的。当一个层的激活分布在整个训练过程中发生显著变化时,就会发生内部协变量移位。批处理归一化的使用使得特定层的输入分布(这些输入实际上是激活函数的结果)不会因为每个批处理的参数更新而随着时间的推移而改变(或者至少允许它以一种有利的方式改变)。它使用批统计进行归一化,然后使用批归一化参数(原论文中的gamma和beta)“确保插入网络的变换能够表示恒等变换”(引用自原论文)。但关键是我们试图将输入归一化到一个层,所以它应该总是在网络中的下一层之前。这是否在激活函数之后取决于所讨论的架构。

关于BN应该应用在当前层的非线性之前还是应用在前一层的激活之前,这个线程有一些相当大的争论。

虽然没有正确答案,但批处理规范化的作者是这么说的 它应立即应用于当前层的非线性之前。原因(引自原论文)- .

"我们在 非线性,通过归一化x = Wu+b。我们可以 还规范化了层输入u,但由于u是可能的 另一个非线性的输出,它的分布的形状 很可能在训练过程中发生变化,并受到限制 它的一阶和二阶矩不会消去协变量 转变。相反,Wu + b更有可能 一个对称的非稀疏分布,即“更偏向高斯分布” (Hyv¨arinen,Oja, 2000);将其正常化很可能 产生稳定分布的激活。" < / p >

批处理归一化是通过调整激活的平均值和缩放来归一化输入层和隐藏层。由于这种在深度神经网络中附加层的归一化效应,网络可以使用更高的学习率而不会消失或爆炸梯度。此外,批归一化对网络进行了正则化,使其更容易泛化,因此不需要使用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)

如何应用批处理规范化?

假设我们向层l输入a[l-1],并且我们有层l的权值W[l]和偏置单位b[l]。添加非线性后)为层l, z[l]为添加非线性前的向量

  1. 使用a[l-1]和W[l],我们可以计算出层l的z[l]
  2. 通常在前馈传播中,我们会在此阶段向z[l]添加偏置单元,如z[l]+b[l],但在批处理归一化中,不需要添加b[l]这一步,也不使用b[l]参数。
  3. 计算z[l]的意思,并从每个元素中减去它
  4. 用标准差除以(z[l] - mean)。命名为Z_temp[l]
  5. 现在定义新的参数γ和β,将改变隐藏层的规模,如下所示:

    Z_norm [l] = γ。Z_temp[l] + β

在这段代码摘录中,Dense()取a[l-1],使用W[l]并计算z[l]。然后立即的BatchNormalization()将执行上述步骤以得到z_norm[l]。然后立即激活()将计算tanh(z_norm[l])给出一个[l],即。

a[l] = tanh(z_norm[l])

增加了关于批处理归一化应该在非线性激活之前还是之后调用的争论:

除了在激活前使用批量归一化的原始论文外,Bengio的书深度学习,8.7.1节给出了一些理由,说明为什么在激活后(或直接在下一层输入之前)应用批量归一化可能会导致一些问题:

我们很自然地想知道是否应该将批处理归一化应用于 输入X,或者变换后的值XW+b。Ioffe and Szegedy (2015) 推荐后者。更具体地说,XW+b应该被a取代 XW的规范化版本。偏差项应省略,因为它 批处理应用的β参数变得多余 标准化reparameterization。层的输入通常是 非线性激活函数的输出,如校正线性 函数在前一层。输入的统计信息是这样的 更非高斯,更不适合线性标准化 操作。< / p >

换句话说,如果我们使用relu激活,所有的负值都映射为零。这可能会导致一个已经非常接近于零的平均值,但剩余数据的分布将严重向右倾斜。试图将这些数据正常化为一条漂亮的钟形曲线可能不会得到最好的结果。对于relu家族以外的激活,这可能不是一个大问题。

请记住,有些模型在激活之后使用批处理归一化时会得到更好的结果,而其他模型在激活之前使用批处理归一化时会得到最好的结果。最好使用这两种配置来测试您的模型,如果激活后的批处理规范化显著降低了验证损失,则使用该配置。