keras的BatchNormalization
层默认使用axis=-1
,并说明通常会对特征轴进行归一化。为什么会这样呢?
我觉得这有些令人惊讶,因为我更熟悉使用类似StandardScaler
的工具,这相当于使用axis=0
。这样可以单独对每个特征进行归一化。
为什么keras默认对样本进行单独归一化(即axis=-1
),而不是对特征呢?
编辑:具体的例子
通常我们会转换数据,使每个特征的均值为零,方差为单位。让我们仅考虑“零均值”部分,并使用这个模拟数据集,其中每一行为一个样本:
>>> data = np.array([[ 1, 10, 100, 1000], [ 2, 20, 200, 2000], [ 3, 30, 300, 3000]])>>> data.mean(axis=0)array([ 2., 20., 200., 2000.])>>> data.mean(axis=1)array([ 277.75, 555.5 , 833.25])
难道不是应该减去axis=0
的均值,而不是axis=1
的均值吗?使用axis=1
,单位和尺度可能会完全不同。
编辑2:
这篇论文第3节的第一个方程似乎暗示应该使用axis=0
来计算每个特征的期望和方差,假设你有一个形状为(m, n)的数据集,其中m是样本数,n是特征数。
编辑3:另一个例子
我想看看BatchNormalization
在玩具数据集上计算的均值和方差的维度:
import pandas as pdimport numpy as npfrom sklearn.datasets import load_irisfrom keras.optimizers import Adamfrom keras.models import Modelfrom keras.layers import BatchNormalization, Dense, Inputiris = load_iris()X = iris.datay = pd.get_dummies(iris.target).valuesinput_ = Input(shape=(4, ))norm = BatchNormalization()(input_)l1 = Dense(4, activation='relu')(norm)output = Dense(3, activation='sigmoid')(l1)model = Model(input_, output)model.compile(Adam(0.01), 'categorical_crossentropy')model.fit(X, y, epochs=100, batch_size=32)bn = model.layers[1]bn.moving_mean # <tf.Variable 'batch_normalization_1/moving_mean:0' shape=(4,) dtype=float32_ref>
输入X的形状为(150, 4),而BatchNormalization
层计算了4个均值,这意味着它在axis=0
上操作。
如果BatchNormalization
的默认值是axis=-1
,那么不应该有150个均值吗?
回答:
这种混淆是因为np.mean
中axis
的含义与BatchNormalization
中的不同。
当我们沿某个轴计算均值时,我们会压缩该维度并保留其他所有维度。在你的例子中,data.mean(axis=0)
压缩了0轴
,即data
的垂直维度。
当我们沿某个轴计算BatchNormalization
时,我们保留数组的维度,并根据所有其他轴上的均值和标准差进行归一化。所以在你的2D
例子中,BatchNormalization
使用axis=1
确实是在减去axis=0
的均值,正如你所期望的。这就是为什么bn.moving_mean
的形状是(4,)
。