如何在小型数据集上解释大型CNN的预测失败

时间:2019-09-10 16:07:38

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

我有一个约100张“阳性”样本图像和约2500张“阴性”样本图像的数据集(“一个对所有”分类,在Keras中损失binary_crossentropy)。图片的平均大小约为500x700,但由于它们并不完全相同,因此我在密集层之前使用SpatialPyramidPooling层。

由于每个类别的示例都不多,因此我使用Keras ImageDataGenerator生成更多样本(每个样本5000个)。

我已经训练了一个小型的CNN,并且效果很好(〜95%的准确性),但是我认为使用更大的网络可以取得更好的效果。

我尝试了一个更大的CNN(受VGG16结构启发),但是在训练过程的“测试”部分进行预测时,许多输出完全相同(即,来自测试数据集的所有分类示例的概率为0或0.34167683使用predict_on_batch,批量为1):

[[0.34167683]]
[[0.]]
[[0.]]
[[0.34167683]]
[[0.34167683]]
[[0.34167683]]
[[0.]]
[[0.]]
[[0.]]
[[0.34167683]]
[[0.34167683]]
[[0.34167683]]
[[0.]]
[[0.34167683]]
[[0.34167683]]
...

我训练的纪元的数量并没有改变这种行为:我在第一个纪元之后就知道了,对所有其他纪元都如此。

由于图像大小很大,因此我使用了一批大小为4的图像,因为我的GPU(NVIDIA RTX 2080 8 GB RAM)无法接受更多的图像(对于深层网络,我得到了OOM)。

我在每次BatchNormalization之后尝试使用和不使用Conv2D,但是问题仍然存在。

这里是小的CNN:

def build_one_vs_all():
    model = Sequential()

    model.add(Conv2D(64, (3, 3), padding='same', input_shape=(None, None, 1)))
    model.add(Activation('relu'))        
    model.add(MaxPooling2D(pool_size=(2, 2)))

    model.add(Conv2D(128, (3, 3), padding='same'))
    model.add(Activation('relu'))
    model.add(MaxPooling2D(pool_size=(2, 2)))

    model.add(Conv2D(256, (3, 3), padding='same'))
    model.add(Activation('relu'))

    model.add(SpatialPyramidPooling([1, 2, 4, 8]))       

    model.add(Dense(1024))           
    model.add(Activation('relu'))
    model.add(Dense(1024))           
    model.add(Activation('relu'))

    model.add(Dense(1, activation = 'sigmoid'))
    model.summary()

    img = Input(shape=(None, None, 1))
    validity = model(img)

    return Model(img, validity)

这是最大的一个:

def build_one_vs_all():
    model = Sequential()

    model.add(Conv2D(64, (3, 3), padding='same', input_shape=(None, None, 1)))
    model.add(Activation('relu'))        
    model.add(Conv2D(64, (3, 3), padding='same'))
    model.add(Activation('relu'))
    model.add(MaxPooling2D(pool_size=(2, 2)))

    model.add(Conv2D(128, (3, 3), padding='same'))
    model.add(Activation('relu'))
    model.add(Conv2D(128, (3, 3), padding='same'))
    model.add(Activation('relu'))
    model.add(MaxPooling2D(pool_size=(2, 2)))

    model.add(Conv2D(256, (3, 3), padding='same'))
    model.add(Activation('relu'))
    model.add(Conv2D(256, (3, 3), padding='same'))
    model.add(Activation('relu'))
    model.add(Conv2D(256, (3, 3), padding='same'))
    model.add(Activation('relu'))
    model.add(MaxPooling2D(pool_size=(2, 2)))

    model.add(Conv2D(512, (3, 3), padding='same'))
    model.add(Activation('relu'))
    model.add(Conv2D(512, (3, 3), padding='same'))
    model.add(Activation('relu'))
    model.add(Conv2D(512, (3, 3), padding='same'))
    model.add(Activation('relu'))
    model.add(MaxPooling2D(pool_size=(2, 2)))

    model.add(Conv2D(512, (3, 3), padding='same'))
    model.add(Activation('relu'))
    model.add(Conv2D(512, (3, 3), padding='same'))
    model.add(Activation('relu'))
    model.add(Conv2D(512, (3, 3), padding='same'))
    model.add(Activation('relu'))

    model.add(SpatialPyramidPooling([1, 2, 4, 8]))       
    model.add(Dense(1024))           
    model.add(Activation('relu'))
    model.add(Dense(1024))           
    model.add(Activation('relu'))

    model.add(Dense(1, activation = 'sigmoid'))
    model.summary()

    img = Input(shape=(None, None, 1))
    validity = model(img)

    return Model(img, validity)

为什么会这样?如何通过少量输入图像来使模型复杂化以实现稳定的分类?

0 个答案:

没有答案