CNN训练精度因BatchNorm而停滞,无需调整即可快速拟合

时间:2018-08-07 06:39:38

标签: python machine-learning keras deep-learning conv-neural-network

我有2种灰度图像,比如汽车和飞机。在我的训练集中,我有1000张图像(大约50/50的比例)。在此训练集中,我所有的飞机示例均在白色背景上,而所有汽车示例均在黑色背景上(这是有目的的,模型最终学会了区分汽车和飞机,而不是背景)

作为一个简单的证明,模型将快速适应背景,我创建了一个CNN。但是,我遇到了两种奇怪的情况:

  1. 如果我在转换层和另一层之间的任何位置添加BatchNorm,我的训练精度似乎徘徊在50%左右,并且无法提高。

  2. 如果我删除BatchNorm,我的训练准确性将迅速飙升至98%。尽管我使用我的训练数据集来创建一个验证数据集(因此,该验证数据集还具有黑白背景问题),但我的验证数据集却徘徊在50%左右。我希望我的训练数据集过拟合是由黑白背景引起的,而我的验证数据集也有并且可以针对此背景进行预测。

我已附上我的代码。我将数据作为1x4096向量获得,因此将其重塑为64x64图像。当我在下面的代码中取消注释任何BatchNorm步骤时,训练准确性似乎都在

#Normalize training data
        self.x = self.x.astype('float32')
        self.x /= 255

        numSamples = self.x.shape[0]
        #Reconstruct images
        width = 64
        height = 64
        xInput = self.x.reshape(numSamples,1,height,width)

        y_test = to_categorical(labels, 2)

        #Split data to get validation set
        X_train, X_test, y_train, y_test = train_test_split(xInput, y_test, test_size=0.3, random_state=0)

        #Construct model
        self.model = Sequential()
        self.model.add(Conv2D(64, kernel_size=(3, 3), strides=(1, 1),
                 activation='relu',
                 input_shape=(1,64,64), data_format='channels_first',activity_regularizer=regularizers.l1(0.01)))
        #self.model.add(BatchNormalization())
        self.model.add(MaxPooling2D((2, 2)))
        self.model.add(Dropout(0.5, noise_shape=None)) 
        self.model.add(Conv2D(128, kernel_size=(3, 3), strides=(1, 1), activation='relu'))
        #self.model.add(BatchNormalization())
        self.model.add(MaxPooling2D((2, 2)))
        self.model.add(Dropout(0.5, noise_shape=None)) 
        self.model.add(Conv2D(256, kernel_size=(3, 3), strides=(1, 1), activation='relu'))
        #self.model.add(BatchNormalization())
        self.model.add(MaxPooling2D((2, 2)))
        self.model.add(Dropout(0.5, noise_shape=None)) 
        self.model.add(Flatten())
        self.model.add(Dense(1000, activation='relu', activity_regularizer=regularizers.l2(0.01)))
        self.model.add(BatchNormalization())
        self.model.add(Dropout(0.5, noise_shape=None)) 
        self.model.add(Dense(units = 2, activation = 'softmax', kernel_initializer='lecun_normal'))

        self.model.compile(loss='categorical_crossentropy',
             optimizer='adam',
             metrics=['accuracy'])

        self.model.fit(X_train, y_train,
            batch_size=32,
            epochs=25,
            verbose=2,
            validation_data = (X_test,y_test),
            callbacks = [EarlyStopping(monitor = 'val_acc', patience =5)])

1 个答案:

答案 0 :(得分:0)

我认为您的ANN的架构有很多潜在的改进,并且存在一些基本问题。

基本挑战与训练集的构建方式有关:黑白背景。如果意图是背景不起作用,为什么不将它们全部设置为白色或黑色?请记住,就像任何机器学习算法一样,ANN都将尝试找到区别您的类的方法。在这种情况下,它将仅仅是背景。当背景提供如此清晰而有意义的区别时,为什么还要看汽车与飞机的微小细节呢?

解决方案:使两个集合的背景一致。然后,您的ANN便会忽略它。

为什么Batch Norm会破坏培训准确性?如您所知,测试准确性仍然很差。批次规范正在解决协方差偏移问题。后来,“问题”以看似不错的训练准确性和不良的测试表现出来。很棒的视频,来自安德鲁·伍(Andrew Ng)here。有关批量归一化的精彩视频,以及变迁

修复培训应解决此问题。其他一些事情:

  • 最后,您给出了2个密集单位,但是您的分类是二进制的。使它成为具有S型激活的单个单元。
  • 正如@Upasana Mittal指出的那样,将categorical_crossentropy替换为binary_crossentropy
  • 考虑使用较小的辍学率。请注意,您没有太多数据要始终丢弃一半。仅在有过拟合的证据后,才增加辍学率。
  • 将Conv2D与跨步配合使用可能比简单的最大池化更好。
  • 对于似乎没有那么复杂的内容,您有很多过滤器。考虑大幅减少过滤器数量,并仅在看到ANN没有足够的学习能力时才增加数量。您在这里只有2个班级,将汽车与喷气式飞机区分开的功能并不那么微妙。
  • 考虑使用较少的层数。同样的论点。
  • 使用至少2个堆叠的3x3 Conv2D图层可获得更好的结果。