199

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

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

4

8 回答 8

260

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

希望这能进一步澄清一些事情。

于 2016-06-22T22:40:51.113 回答
70

该线程具有误导性。尝试评论 Lucas Ramadan 的回答,但我还没有合适的权限,所以我就把它放在这里。

批量归一化在激活函数之后效果最好,这里这里就是原因:它是为了防止内部协变量偏移而开发的。当激活的分布发生内部协变量偏移在整个训练过程中,一层的变化显着。使用批量归一化,使得输入(这些输入实际上是激活函数的结果)到特定层的分布不会由于每个批次的参数更新而随时间变化(或者至少允许它改变以有利的方式)。它使用批量统计进行归一化,然后使用批量归一化参数(原始论文中的 gamma 和 beta)“确保插入到网络中的变换可以表示恒等变换”(引自原始论文)。但关键是我们正在尝试对一层的输入进行归一化,所以它应该总是在网络中的下一层之前立即进行。不管是不是'

于 2017-08-10T22:17:24.913 回答
52

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

虽然没有正确答案,但 Batch Normalization 的作者表示, 它应该在当前层的非线性之前立即应用。原因(引自原始论文) -

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

于 2017-08-20T12:54:02.197 回答
33

现在几乎成为一种趋势,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)))
于 2016-12-14T16:02:37.207 回答
33

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'))
于 2016-12-29T07:42:36.713 回答
8

批量归一化用于通过调整激活的均值和缩放来归一化输入层和隐藏层。由于深度神经网络中附加层的这种归一化效果,网络可以使用更高的学习率而不会消失或爆炸梯度。此外,批量归一化对网络进行正则化,使其更容易泛化,因此无需使用 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] - mean)。称之为 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])
于 2019-04-09T08:08:34.427 回答
6

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

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

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

于 2016-01-12T18:31:08.973 回答
1

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

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

很自然地想知道我们是否应该对输入 X 或转换后的值 XW+b 应用批量归一化。Ioffe 和 Szegedy (2015) 推荐后者。更具体地说,XW+b 应该被 XW 的标准化版本替换。应该省略偏差项,因为它与批量归一化重新参数化应用的 β 参数变得多余。一层的输入通常是非线性激活函数的输出,例如前一层的修正线性函数。因此,输入的统计数据更加非高斯并且不太适合通过线性运算进行标准化。

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

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

于 2021-01-15T18:08:24.403 回答