Keras BatchNorm:训练准确度提高而测试准确度降低

Keras BatchNorm: Training accuracy increases while Testing accuracy decreases

我正在尝试在 Keras 中使用 BatchNorm。训练准确度会随着时间的推移而增加。从 12% 到 20%,缓慢但稳步。 然而,测试准确度从 12% 下降到 0%。随机基线为 12%。

我非常认为这是由于 batchnorm 层(删除 batchnorm 层导致约 12% 的测试精度)造成的,它可能没有足够好地初始化参数 gamma 和 beta。应用 batchnorm 时我需要考虑什么特别的事情吗?我真的不明白还有什么地方出了问题。我有以下型号:

模型=顺序()

model.add(BatchNormalization(input_shape=(16, 8)))
model.add(Reshape((16, 8, 1)))

#1. Conv (64 filters; 3x3 kernel)
model.add(default_Conv2D())
model.add(BatchNormalization(axis=3))
model.add(Activation('relu'))

#2. Conv (64 filters; 3x3 kernel)
model.add(default_Conv2D())
model.add(BatchNormalization(axis=3))
model.add(Activation('relu'))

... 

#8. Affine (NUM_GESTURES units) Output layer
model.add(default_Dense(NUM_GESTURES))
model.add(Activation('softmax'))


sgd = optimizers.SGD(lr=0.1)
model.compile(loss='categorical_crossentropy', optimizer=sgd, metrics=['accuracy'])

default_Conv2D和default_Dense定义如下:

def default_Conv2D():
    return Conv2D(
        filters=64,
        kernel_size=3,
        strides=1,
        padding='same',
        # activation=None,
        # use_bias=True,
        # kernel_initializer=RandomNormal(mean=0.0, stddev=0.01, seed=None), #RandomUniform(),
        kernel_regularizer=regularizers.l2(0.0001),
        # bias_initializer=RandomNormal(mean=0.0, stddev=0.01, seed=None), # RandomUniform(),
        # bias_regularizer=None
    )

def default_Dense(units):

    return Dense(
        units=units,
        # activation=None,
        # use_bias=True,
        # kernel_initializer=RandomNormal(mean=0.0, stddev=0.01, seed=None),#RandomUniform(),
        # bias_initializer=RandomNormal(mean=0.0, stddev=0.01, seed=None),#RandomUniform(),
        kernel_regularizer=regularizers.l2(0.0001),
        # bias_regularizer=None
    )

问题是过度拟合

您的前 2 个观察结果支持了这一点:

  1. 训练准确率会随着时间的推移而提高。从 12% 到 20%,.. 测试准确率从 12% 到 0%
  2. 删除 batchnorm 层导致约 12% 的测试精度

第一个语句告诉我你的网络正在记忆训练集。第二个陈述告诉我,当你阻止网络记住训练集(甚至学习)时,它就会停止犯与记忆有关的错误。

过拟合有一些解决方案,但问题比这个大post。请将以下列表视为 "top" 列表而不是详尽无遗:

  • 在最终的全连接层之前添加一个正则化器,例如 Dropout
  • 在矩阵权重上添加 L1 或 L2 正则化器
  • 在 CONV
  • 之间添加正则化器,例如 Dropout
  • 您的网络可能有太多的自由参数。尝试将层减少到仅 1 个 CONV,并一次添加一层,每次重新训练和测试。

精度提高缓慢

作为旁注,您通过说 缓慢但肯定 来暗示您的准确性没有像您希望的那样快速增长。当我完成以下所有步骤时,我已经取得了巨大的成功

  • 将损失函数更改为小批量中所有项目的所有预测的平均损失。这使得你的损失函数独立于你的批量大小,你会发现如果你改变你的批量大小并且你的损失函数随之改变那么你将不得不改变你的 SGD 学习率。
  • 你的损失是一个单一的数字,它是所有预测 类 和所有样本的平均损失,所以使用 1.0 的学习率。不再需要缩放它了。
  • 使用 tf.train.MomentumOptimizer,learning_rate = 1.0,动量 = 0.5。 MomentumOptimizer 已被证明 比 GradientDescent 更强大。

Keras 本身似乎有问题。

天真

pip install git+git://github.com/fchollet/keras.git --upgrade --no-deps

成功了。

@wontonimo,非常感谢您的精彩回答!