我正在研究实现 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)
独立于任何其他建议(包括已经提供的答案),并假设
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 默认情况下 - 请参阅此线程;从不添加它开始,仅在必要时添加(即,如果您看到过度拟合的迹象)。
我建议你进行迁移学习而不是训练整个网络。 使用在大型数据集(如 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