CNN 架构:对“好”和“坏”图像进行分类

问题描述 投票:0回答:2

我正在研究实现 CNN 的可能性,以便将图像分类为“好”或“坏”,但我目前的架构不太好。

表示“坏”图像的特征:

  • 曝光过度
  • 过饱和
  • 白平衡不正确
  • 模糊

实现神经网络来根据这些特征对图像进行分类是否可行,还是最好留给传统算法,仅查看整个图像的亮度/对比度差异并以这种方式对其进行分类?

我尝试使用 VGGNet 架构训练 CNN,但无论轮数或步骤数如何,我似乎总是得到一个有偏差且不可靠的模型。

示例:

我当前模型的架构非常简单(因为我对整个机器学习世界来说是新手),但似乎可以很好地处理其他分类问题,并且我对其进行了稍微修改以更好地处理这个二元分类问题:

    # CONV => RELU => POOL layer set
    # define convolutional layers, use "ReLU" activation function
    # and reduce the spatial size (width and height) with pool layers
    model.add(Conv2D(32, (3, 3), padding="same", input_shape=input_shape)) # 32 3x3 filters (height, width, depth)
    model.add(Activation("relu"))
    model.add(BatchNormalization(axis=channel_dimension))
    model.add(MaxPooling2D(pool_size=(2,2)))
    model.add(Dropout(0.25)) # helps prevent overfitting (25% of neurons disconnected randomly)

    # (CONV => RELU) * 2 => POOL layer set (increasing number of layers as you go deeper into CNN)
    model.add(Conv2D(64, (3, 3), padding="same", input_shape=input_shape)) # 64 3x3 filters
    model.add(Activation("relu"))
    model.add(BatchNormalization(axis=channel_dimension))
    model.add(Conv2D(64, (3, 3), padding="same", input_shape=input_shape)) # 64 3x3 filters
    model.add(Activation("relu"))
    model.add(BatchNormalization(axis=channel_dimension))
    model.add(MaxPooling2D(pool_size=(2,2)))
    model.add(Dropout(0.25)) # helps prevent overfitting (25% of neurons disconnected randomly)

    # (CONV => RELU) * 3 => POOL layer set (input volume size becoming smaller and smaller)
    model.add(Conv2D(128, (3, 3), padding="same", input_shape=input_shape)) # 128 3x3 filters
    model.add(Activation("relu"))
    model.add(BatchNormalization(axis=channel_dimension))
    model.add(Conv2D(128, (3, 3), padding="same", input_shape=input_shape)) # 128 3x3 filters
    model.add(Activation("relu"))
    model.add(BatchNormalization(axis=channel_dimension))
    model.add(Conv2D(128, (3, 3), padding="same", input_shape=input_shape)) # 128 3x3 filters
    model.add(Activation("relu"))
    model.add(BatchNormalization(axis=channel_dimension))
    model.add(MaxPooling2D(pool_size=(2,2)))
    model.add(Dropout(0.25)) # helps prevent overfitting (25% of neurons disconnected randomly)

    # only set of FC => RELU layers
    model.add(Flatten())
    model.add(Dense(512))
    model.add(Activation("relu"))
    model.add(BatchNormalization())
    model.add(Dropout(0.5))

    # sigmoid classifier (output layer)
    model.add(Dense(classes))
    model.add(Activation("sigmoid"))

这个模型是否有任何明显的遗漏或错误,或者我是否可以使用深度学习(使用我当前的 GPU,GTX 970)来解决这个问题?

这是我编译/训练模型的代码:

# initialise the model and optimiser
print("[INFO] Training network...")
opt = SGD(lr=initial_lr, decay=initial_lr / epochs)
model.compile(loss="sparse_categorical_crossentropy", optimizer=opt, metrics=["accuracy"])

# set up checkpoints
model_name = "output/50_epochs_{epoch:02d}_{val_acc:.2f}.model"
checkpoint = ModelCheckpoint(model_name, monitor='val_acc', verbose=1, 
save_best_only=True, mode='max')
reduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.2,
                          patience=5, min_lr=0.001)
tensorboard = TensorBoard(log_dir="logs/{}".format(time()))
callbacks_list = [checkpoint, reduce_lr, tensorboard]

# train the network
H = model.fit_generator(training_set, steps_per_epoch=500, epochs=50, validation_data=test_set, validation_steps=150, callbacks=callbacks_list)
python machine-learning keras deep-learning conv-neural-network
2个回答
5
投票

独立于任何其他建议(包括已经提供的答案),并假设

classes=2
(您没有澄清 - 我们在这里要求MCVE是有原因的),您似乎在您的最后一层,即:

# sigmoid classifier (output layer)
model.add(Dense(classes))
model.add(Activation("sigmoid"))

仅当您的最后一层由单个节点组成时,S形激活才适用;如果

classes=2
,正如我怀疑的那样,也基于您在评论中令人费解的陈述

使用三张不同的图像,我的结果是 0.987 不好,0.999 好

我之前已经给你了模型的预测

您应该使用 softmax 激活,即

model.add(Dense(classes))
model.add(Activation("softmax"))

或者,您可以使用 sigmoid,但最后一层应由单个节点组成,即

model.add(Dense(1))
model.add(Activation("sigmoid"))

在二元分类设置中通常首选后者,但结果原则上应该是相同的。

更新(更新问题后):

sparse_categorical_crossentropy
也不是正确的损失。

总而言之,请尝试以下更改:

model.compile(loss="binary_crossentropy", optimizer=Adam(), metrics=["accuracy"])

# final layer:
model.add(Dense(1))
model.add(Activation("sigmoid"))

使用 Adam 优化器(需要导入)。另外,不应该使用 dropout 默认情况下 - 请参阅此线程;从不添加它开始,仅在必要时添加(即,如果您看到过度拟合的迹象)。


3
投票

我建议你进行迁移学习而不是训练整个网络。 使用在大型数据集(如 ImageNet

)上训练的权重

您可以使用 Keras 轻松完成此操作,您只需导入具有 xception 等权重的模型,并将表示 1000 个类的 imagenet 数据集的最后一层删除到 2 节点密集层,因为您只有 2 个类,并将

trainable=False
设置为基础层和
trainable=True
用于自定义添加的层,例如具有节点 = 2 的密集层。

您可以像平常一样训练模型。

演示代码 -

from keras.applications import *
from keras.models import Model

base_model = Xception(input_shape=(img_width, img_height, 3), weights='imagenet', include_top=False
x = base_model.output
x = GlobalAveragePooling2D()(x)
predictions = Dense(2, activation='softmax')(x)
model = Model(base_model.input, predictions)
# freezing the base layer weights
for layer in base_model.layers:
    layer.trainable = False
© www.soinside.com 2019 - 2024. All rights reserved.