ChatGPT解决这个技术问题 Extra ChatGPT

我在哪里调用 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)

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


L
Lucas Ramadan

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

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


仅供参考,在激活函数之后,批处理规范化在实践中效果更好
嗨@Claudiu,你介意扩大这个仅供参考吗?这似乎与上面的答案直接矛盾。
@benogorek:当然,基本上我完全基于结果here,在relu 之后放置批处理规范表现更好。 FWIW我没有成功地在我尝试过的一个网络上以一种或另一种方式应用它
有趣的。只是为了跟进,如果您继续阅读该摘要,它说他们的最佳模型 [GoogLeNet128_BN_lim0606] 实际上在 ReLU 之前具有 BN 层。因此,虽然激活后的 BN 可能会在孤立的情况下提高准确性,但在构建整个模型时,在执行最佳之前。在激活之后放置 BN 可能会提高准确性,但可能取决于问题。
@CarlThomé 有点像。例如,参见 ReginaldIII 的 this reddit 评论。他们指出:“BN 正在对卷积中的特征分布进行归一化,其中一些特征可能是负的 [并且] 会被 ReLU 等非线性截断。如果在激活之前进行归一化,则将这些负值包含在在从特征空间中剔除它们之前立即进行归一化。激活后的 BN 将对正特征进行归一化,而不会使它们在统计上偏向于无法通过下一个卷积层的特征。
j
jmancuso

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

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


我刚刚在 deeplearning.ai 课上看到 Andrew Ng 说在深度学习社区中对此存在争论。他更喜欢在非线性之前应用批量标准化。
@kRazzyR 我的意思是 Andrew Ng 教授在 deeplearning.ai 的深度学习课程中谈到了这个话题,他说社区在正确的做事方式上存在分歧,他更喜欢在应用非线性之前应用批量标准化。
@jmancuso,BN 在激活之前应用。从论文本身来看,方程是 g(BN(Wx + b)) ,其中 g 是激活函数。
之前是之后适合测试。没有人事先知道哪个实际上更好。但从理论上讲,是的,在非线性更有意义之前。
L
Lucas

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

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

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


以我个人的经验,它并没有太大的区别,但在其他条件相同的情况下,我总是看到 BN 在非线性之前(在激活函数之前)应用批量归一化时表现稍好一些。
l
ldavid

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)) 有何不同
@kRazzR 如果您使用 tensorflow 作为后端,它没有区别。之所以写在这里,是因为他从 keras.applications 模块复制了它,其中需要指定 bn_axis 以支持 channels_firstchannels_last 格式。
有人可以详细说明这与 OP 问题有何关系吗? (我是NN的初学者,所以也许我错过了一些东西。)
这个答案与 OP 问题无关。
s
stochastic_zeitgeist

现在几乎已成为一种趋势,即先有 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?
A
Aishwarya Radhakrishnan

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

使用 a[l-1] 和 W[l] 我们可以计算层 l 的 z[l] 通常在前馈传播中,我们将在这个阶段将偏置单元添加到 z[l],就像这样 z[l]+ b[l],但在批量标准化中,不需要添加 b[l] 的这一步,也没有使用 b[l] 参数。计算 z[l] 均值并将其从每个元素中减去 使用标准差除 (z[l] - mean)。称之为 Z_temp[l] 现在定义新的参数 γ 和 β,它们将改变隐藏层的规模,如下所示: 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])

P
Pavel Surmenok

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

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

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


在我添加 BatchNormalization 之后,val_acc 停止增加每个时期。在我添加 BatchNormalization 之后,每个 epoch 之后 val_acc 都保持不变。我认为批量标准化应该增加 val_acc。我怎么知道它是否工作正常?你知道这可能是什么原因造成的吗?
不幸的是,该链接不再有效:(
Keras 的分支中有该示例的副本(例如 github.com/WenchenLi/kaggle/blob/master/otto/keras/…),但我不知道为什么它会从原始 Keras 存储库中删除,以及代码是否与最新的 Keras 版本兼容。
L
Leland Hepworth

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

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

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

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

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