vgg16微调狗猫分类在测试数据上失败

我一直在尝试对VGG16进行微调,以对一个我自己创建的包含4个类别的数据集进行分类。虽然训练集和验证集的准确率都有显著提高,但无论我做什么,测试集的准确率始终保持在25%。因此,我决定首先使用Kaggle上的猫狗数据集对VGG16进行微调,并按照一些教程的步骤操作,这些教程都取得了不错的准确率结果。然而,我遇到了与第一次相同的问题。现在准确率是50%(因为只有两个类别)。我开始认为这是Keras VGG16的问题。我尝试了网上所有不同的建议,包括StackOverflow上类似问题的建议,但似乎没有任何效果。所有预处理、数据增强和层冻结似乎都已正确完成,经过几周的反复试错后,我不得不求助于你们的建议和意见。

这是我使用的完整代码:

from keras.models import Sequential, Model, load_modelfrom keras import applicationsfrom keras import optimizersfrom keras.layers import Dropout, Flatten, Densefrom keras.preprocessing.image import ImageDataGeneratorfrom sklearn.metrics import  classification_report,confusion_matrixfrom keras.callbacks import ModelCheckpoint%matplotlib inlineimport matplotlib.pyplot as pltimport numpy as np

以下是我使用的混淆矩阵函数实现:

def plot_confusion_matrix_two(cm,                          target_names,                          title='Confusion matrix',                          cmap=None,                          normalize=True):import matplotlib.pyplot as pltimport numpy as npimport itertoolsaccuracy = np.trace(cm) / float(np.sum(cm))misclass = 1 - accuracyif cmap is None:    cmap = plt.get_cmap('Blues')plt.figure(figsize=(8, 6))plt.imshow(cm, interpolation='nearest', cmap=cmap)plt.title(title)plt.colorbar()if target_names is not None:    tick_marks = np.arange(len(target_names))    plt.xticks(tick_marks, target_names, rotation=45)    plt.yticks(tick_marks, target_names)if normalize:    cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]thresh = cm.max() / 1.5 if normalize else cm.max() / 2for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):    if normalize:        plt.text(j, i, "{:0.4f}".format(cm[i, j]),                 horizontalalignment="center",                 color="white" if cm[i, j] > thresh else "black")    else:        plt.text(j, i, "{:,}".format(cm[i, j]),                 horizontalalignment="center",                 color="white" if cm[i, j] > thresh else "black")plt.tight_layout()plt.ylabel('True label')plt.xlabel('Predicted label\naccuracy={:0.4f}; misclass={:0.4f}'.format(accuracy, misclass))plt.show()

调用VGG16使用imagenet权重,不带顶层并冻结低层:

img_rows, img_cols, img_channel = 224, 224, 3base_model = applications.VGG16(weights='imagenet', include_top=False, input_shape=(img_rows, img_cols, img_channel))for layer in base_model.layers[:-4]:    layer.trainable = False# check the trainable status of the individual layersfor layer in base_model.layers:    print(layer, layer.trainable)

添加用于分类我们数据的最后几层并编译模型:

add_model = Sequential()add_model.add(Flatten(input_shape=base_model.output_shape[1:]))add_model.add(Dense(256, activation='relu'))add_model.add(Dropout(0.5))add_model.add(Dense(2, activation='softmax'))for layer in add_model.layers[:-3]:    layer.trainable = Falsemodel = Model(inputs=base_model.input, outputs=add_model(base_model.output))model.compile(loss='categorical_crossentropy', optimizer=optimizers.SGD(lr=1e-4, momentum=0.9),              metrics=['accuracy'])model.summary()

训练参数、路径等…

image_size = 224epochs = 500train_batch = 50valid_batch = 30test_batch = 20train_dir = 'D:/PetImages/train'valid_dir = 'D:/PetImages/valid'test_dir = 'D:/PetImages/test'

用于从不同数据集读取数据的数据生成器。在我的情况下,数据集位于不同的文件夹中,因此不需要将训练集和验证集分开。

train_datagen = ImageDataGenerator(      rescale=1./255,      rotation_range=20,      width_shift_range=0.2,      height_shift_range=0.2,      horizontal_flip=True,      #vertical_flip=True,      fill_mode='nearest')validation_datagen = ImageDataGenerator(rescale=1./255)test_datagen = ImageDataGenerator(rescale=1./255)train_generator = train_datagen.flow_from_directory(        train_dir,        target_size=(image_size, image_size),        batch_size=train_batch,        class_mode='categorical',        shuffle=True)validation_generator = validation_datagen.flow_from_directory(        valid_dir,        target_size=(image_size, image_size),        batch_size=valid_batch,        class_mode='categorical',        shuffle=True)test_generator = test_datagen.flow_from_directory(        test_dir,        target_size=(image_size, image_size),        batch_size=test_batch,        class_mode='categorical',        shuffle=True)

训练模型:

history = model.fit_generator(    train_generator,    steps_per_epoch=train_generator.samples // train_generator.batch_size,    epochs=epochs,    validation_data=validation_generator,    validation_steps=validation_generator.samples // validation_generator.batch_size,    #callbacks=[ModelCheckpoint('VGG16-transferlearning.model', monitor='val_acc', save_best_only=True)]    verbose=1)

然后在测试集上进行预测,以与真实值进行比较并获取准确率等信息:

predictions = model.predict_generator(test_generator, steps=test_generator.samples//test_generator.batch_size,                                       verbose=0)#Confution Matrix and Classification Reportpredictions = np.argmax(predictions, axis=1)print('Confusion Matrix')cm = confusion_matrix(test_generator.classes, predictions)#print(cm)target_names =['cats', 'dogs']#target_names =['Bark', 'Jump','Stand', 'Walk']plot_confusion_matrix_two(cm, target_names, title='Confusion Matrix',cmap=None,normalize=False)print('Classification Report')print(classification_report(test_generator.classes, predictions, target_names=target_names))print('Confusion Matrix')print(cm)

我真的尝试了所有不同的技巧来检查。我甚至尝试检查模型在训练数据上的表现,而不是测试数据,结果仍然是50%(考虑到训练准确率几乎达到99%,这非常奇怪)。我尝试调整超参数,不同的算法,但仍然没有任何变化。

系统:Windows 10, Anaconda, Keras 2.1.1 Tensorflow-gpu 1.4.0 Python 3.6.4

使用的数据集:https://files.fm/u/t6zdskc7

我现在已经卡在这里几个星期了,真的很沮丧。如果有人能帮助我,我将非常感激!!

编辑:

在四处询问后,有人指出模型实际上是能够学习的,我可以使用以下代码检查预测的准确率:

x, y = zip(*(test_generator[i] for i in range(len(test_generator))))x_test, y_test = np.vstack(x), np.vstack(y)loss, acc = model.evaluate(x_test, y_test, batch_size=64)print("Accuracy: ", acc)print("Loss: ",loss)

结果显示我确实得到了一个合理的结果(根据超参数调整,大约70%)。所以我现在猜测,当我尝试使用混淆矩阵和报告函数进行分析时,出了什么问题。不过,我仍然无法找到问题所在。


回答:

Related Posts

在使用k近邻算法时,有没有办法获取被使用的“邻居”?

我想找到一种方法来确定在我的knn算法中实际使用了哪些…

Theano在Google Colab上无法启用GPU支持

我在尝试使用Theano库训练一个模型。由于我的电脑内…

准确性评分似乎有误

这里是代码: from sklearn.metrics…

Keras Functional API: “错误检查输入时:期望input_1具有4个维度,但得到形状为(X, Y)的数组”

我在尝试使用Keras的fit_generator来训…

如何使用sklearn.datasets.make_classification在指定范围内生成合成数据?

我想为分类问题创建合成数据。我使用了sklearn.d…

如何处理预测时不在训练集中的标签

已关闭。 此问题与编程或软件开发无关。目前不接受回答。…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注