我有一个约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)
为什么会这样?如何通过少量输入图像来使模型复杂化以实现稳定的分类?