【问题标题】:CNN architecture: classifying "good" and "bad" imagesCNN 架构:对“好”和“坏”图像进行分类
【发布时间】:2019-09-16 14:18:33
【问题描述】:

我正在研究实现 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)

【问题讨论】:

  • 您当前的模型究竟有什么问题?
  • 我认为这是过度拟合,因为无论我使用什么输入进行预测,结果都是有偏差且非常相似的。无论时代数或步骤数如何,它都表现出这种行为,这让我认为这是架构的问题。例如,对于三个不同的图像,我的结果是 0.987 差和 0.999 好(到 3 个有效数字)。
  • 我不关注;什么是“0.987 坏和 0.999 好”?您的准确度是多少?
  • 啊,对不起。在训练我的 50 个 epoch 模型结束时,我的准确率约为 80%。我之前给你的是模型的预测......
  • 请在您的帖子中包含此信息!假设我们正在讨论 validation 准确性(请澄清这一点)。这是诊断可能问题的起点,而不是口头陈述(“有偏见且不可靠)或假设(我认为它过度拟合)......

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


【解决方案1】:

独立于任何其他建议(包括已经提供的答案),并假设classes=2(您没有澄清 - 我们在这里要求MCVE 是有原因的),您似乎犯了一个根本性错误在你的最后一层,即:

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

仅当您的最后一层由 单个 节点组成时,才适用 sigmoid 激活;如果classes=2,正如我所怀疑的那样,也是基于您在 cmets 中令人费解的陈述

三个不同的图像,我的结果是 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 - 请参阅 this thread;不使用它开始,仅在必要时添加(即,如果您看到 overfitting 的迹象)。

【讨论】:

  • 谢谢,我相信我已经尝试过使用 softmax 和 sigmoid 激活函数,只是想看看是否有任何区别,但 sigmoid 肯定是错误的。 Softmax 激活仍然会导致过度拟合和偏差,但更适合二进制分类。为了澄清一些参数,输入大小为 (320, 240, 3),并且有两个可能的类(好和坏)。
  • @JoshNewham 您发布的任何内容都不会导致过度拟合诊断,这(过度拟合)意味着验证准确度开始下降,而训练准确度仍在增加。同样,请尽量避免口头陈述(偏见?)并改用价值观。另外,请发布您的model.compile()(不在此处,编辑和更新您的帖子)。
  • 我已经编辑了原始帖子以包含该信息。
【解决方案2】:

我建议您进行迁移学习,而不是训练整个网络。 使用在像 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

【讨论】:

  • 好主意。我什至没有想到要获得预训练的权重,然后从那里训练我的模型。我已经用你的演示代码实现了一些东西,经过很短的训练期后,它似乎比我的原始模型好得多(它的预测根据输入而有所不同)。我已经将它停止训练更长时间,看看我是否能提高准确性......
  • 很高兴听到这个消息,如果完全解决了您的问题,请将我的回答标记为已接受的解决方案。
  • 这是一个非常有趣的线程...作为机器学习的新手,有没有什么开源软件可以用来对艺术家生成的图像数据集进行评分?
猜你喜欢
  • 2021-09-16
  • 2021-07-15
  • 2016-04-19
  • 2017-07-18
  • 2020-04-01
  • 2021-12-28
  • 1970-01-01
  • 2017-06-01
  • 1970-01-01
相关资源
最近更新 更多