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

pr3*_*338 144 python neural-network keras data-science batch-normalization

如果我想在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)
Run Code Online (Sandbox Code Playgroud)

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

Luc*_*dan 198

只是为了更详细地回答这个问题,并且正如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)
Run Code Online (Sandbox Code Playgroud)

希望这能澄清一些事情.

  • 有趣.只是为了跟进,如果你继续阅读该摘要,它说他们的最佳模型[GoogLeNet128_BN_lim0606]实际上在ReLU之前有BN层.因此,虽然激活后的BN可能会提高孤立情况下的准确性,但在构建整个模型时,最佳表现之前.可能在激活后放置BN可能会提高准确性,但可能依赖于问题. (28认同)
  • 显然,批量标准化在激活功能之后在实践中更好地工作 (21认同)
  • 嗨@Claudiu,你介意扩大这个FYI吗?它似乎与上面的答案直接相矛盾. (7认同)
  • @benogorek:肯定的是,基本上我完全基于结果[这里](https://github.com/ducha-aiki/caffenet-benchmark/blob/master/batchnorm.md)在relu之后放置批量规范表现更好.FWIW我没有成功地在我试过的一个网上以这种方式应用它 (7认同)
  • @CarlThomé那种.例如,请参阅ReginaldIII的[this reddit](https://redd.it/67gonq)评论.他们指出:"BN正在规范卷积中出现的特征的分布,这些特征中的一些可能是负面的[并]被像ReLU这样的非线性截断.如果你在激活之前进行标准化,你将这些负值包含在在从特征空间中剔除它们之前立即进行归一化.激活后的BN将对正特征进行归一化,而不会使用不能通过下一个卷积层的特征对它们进行统计偏差. (7认同)
  • 哇,那个基准真的很有趣.对于那里到底发生了什么,有没有人有任何直觉?为什么在非线性之后偏移和缩放激活会更好?是因为贝塔和伽马必须处理较少的变化或类似的东西,因此当训练数据不丰富时,模型会更好地概括? (4认同)

小智 50

这个帖子很容易引起误解.尝试评论Lucas Ramadan的回答,但我还没有正确的权限,所以我只想把它放在这里.

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

  • 我刚刚在deeplearning.ai课上看到Andrew Ng说在深度学习社区中就此存在争议.他更喜欢在非线性之前应用批量标准化. (25认同)
  • @jmancuso,BN 在激活前应用。从论文本身来看,方程是 `g(BN(Wx + b))` ,其中 `g` 是激活函数。 (3认同)
  • @kRazzyR我的意思是Andrew Ng教授在他关于https://www.deeplearning.ai/的深度学习课程中谈到了这个话题.他说社区在正确的做事方式上存在分歧,他更倾向于应用批量规范化在应用非线性之前. (2认同)

小智 37

关于是否应该在当前层的非线性或前一层的激活之前应用BN,该线程存在一些争论.

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

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

  • 根据我个人的经验,它并没有产生很大的不同,但在其他条件相同的情况下,我总是看到BN在非线性(激活功能之前)之前应用批量标准化时表现稍好一些. (2认同)

don*_*loo 28

Keras现在支持该use_bias=False选项,因此我们可以通过编写来保存一些计算

model.add(Dense(64, use_bias=False))
model.add(BatchNormalization(axis=bn_axis))
model.add(Activation('tanh'))
Run Code Online (Sandbox Code Playgroud)

要么

model.add(Convolution2D(64, 3, 3, use_bias=False))
model.add(BatchNormalization(axis=bn_axis))
model.add(Activation('relu'))
Run Code Online (Sandbox Code Playgroud)

  • 有人可以详细说明这与OP问题有何关系吗?(我是NN的初学者,所以也许我错过了一些。) (6认同)

sto*_*ist 27

现在几乎成为一种趋势,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)))
Run Code Online (Sandbox Code Playgroud)

  • 也许把这推到keras? (6认同)

Ais*_*nan 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)
Run Code Online (Sandbox Code Playgroud)

如何应用批量标准化?

假设我们已经将 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] 添加偏置单元,就像这样 z[l]+b[l],但在 Batch Normalization 中,这一步添加 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])
Run Code Online (Sandbox Code Playgroud)


Pav*_*nok 6

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

model.add(keras.layers.normalization.BatchNormalization())
Run Code Online (Sandbox Code Playgroud)

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