我正在研究实现一个CNN来将图像分类为“优质”或“劣质”,但目前的架构似乎并不奏效。
表示“劣质”图像的特征包括:
- overexposure(曝光过度)
- oversaturation(饱和度过高)
- incorrect white balance(白平衡错误)
- blurriness(模糊)
基于这些特征,使用神经网络来分类图像是否可行,还是最好使用传统算法,仅通过检查图像中亮度/对比度的变化来进行分类?
我尝试使用VGGNet架构训练CNN,但无论是增加训练轮数还是步数,得到的模型总是有偏差且不可靠。
示例:
我的当前模型架构非常简单(因为我刚开始接触机器学习领域),在处理其他分类问题时表现良好,我已经对其进行了少许修改以更好地适应这个二元分类问题:
# CONV => RELU => POOL 层设置 # 定义卷积层,使用“ReLU”激活函数 # 并通过池化层减小空间尺寸(宽度和高度) model.add(Conv2D(32, (3, 3), padding="same", input_shape=input_shape)) # 32个3x3滤波器(高度,宽度,深度) model.add(Activation("relu")) model.add(BatchNormalization(axis=channel_dimension)) model.add(MaxPooling2D(pool_size=(2,2))) model.add(Dropout(0.25)) # 帮助防止过拟合(随机断开25%的神经元) # (CONV => RELU) * 2 => POOL 层设置(随着CNN深入,增加层数) model.add(Conv2D(64, (3, 3), padding="same", input_shape=input_shape)) # 64个3x3滤波器 model.add(Activation("relu")) model.add(BatchNormalization(axis=channel_dimension)) model.add(Conv2D(64, (3, 3), padding="same", input_shape=input_shape)) # 64个3x3滤波器 model.add(Activation("relu")) model.add(BatchNormalization(axis=channel_dimension)) model.add(MaxPooling2D(pool_size=(2,2))) model.add(Dropout(0.25)) # 帮助防止过拟合(随机断开25%的神经元) # (CONV => RELU) * 3 => POOL 层设置(输入体积尺寸越来越小) model.add(Conv2D(128, (3, 3), padding="same", input_shape=input_shape)) # 128个3x3滤波器 model.add(Activation("relu")) model.add(BatchNormalization(axis=channel_dimension)) model.add(Conv2D(128, (3, 3), padding="same", input_shape=input_shape)) # 128个3x3滤波器 model.add(Activation("relu")) model.add(BatchNormalization(axis=channel_dimension)) model.add(Conv2D(128, (3, 3), padding="same", input_shape=input_shape)) # 128个3x3滤波器 model.add(Activation("relu")) model.add(BatchNormalization(axis=channel_dimension)) model.add(MaxPooling2D(pool_size=(2,2))) model.add(Dropout(0.25)) # 帮助防止过拟合(随机断开25%的神经元) # 仅一组FC => RELU 层 model.add(Flatten()) model.add(Dense(512)) model.add(Activation("relu")) model.add(BatchNormalization()) model.add(Dropout(0.5)) # sigmoid 分类器(输出层) model.add(Dense(classes)) model.add(Activation("sigmoid"))
这个模型是否存在明显的遗漏或错误,或者我是否无法使用深度学习(使用我的当前GPU,GTX 970)解决这个问题?
以下是我编译/训练模型的代码:
# 初始化模型和优化器print("[INFO] 正在训练网络...")opt = SGD(lr=initial_lr, decay=initial_lr / epochs)model.compile(loss="sparse_categorical_crossentropy", optimizer=opt, metrics=["accuracy"])# 设置检查点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]# 训练网络H = model.fit_generator(training_set, steps_per_epoch=500, epochs=50, validation_data=test_set, validation_steps=150, callbacks=callbacks_list)
回答:
我建议你采用迁移学习而不是从头开始训练整个网络。使用在像ImageNet这样的大型数据集上训练的权重。
你可以使用Keras轻松实现这一点,只需导入带权重的模型,如xception,并删除表示ImageNet数据集1000个类别的最后一层,改为2个节点的密集层,因为你只有两个类别,并将基础层的trainable
设置为False
,而将自定义添加的层(如节点数为2的密集层)的trainable
设置为True
。
然后你可以像往常一样训练模型。
演示代码 –
from keras.applications import *from keras.models import Modelbase_model = Xception(input_shape=(img_width, img_height, 3), weights='imagenet', include_top=Falsex = base_model.outputx = GlobalAveragePooling2D()(x)predictions = Dense(2, activation='softmax')(x)model = Model(base_model.input, predictions)# 冻结基础层权重for layer in base_model.layers: layer.trainable = False