vgg16微调狗猫测试数据失败

时间:2018-09-17 14:46:37

标签: machine-learning keras neural-network computer-vision

因此,我一直在尝试微调VGG16以便对我制作的具有4个类别的数据集进行分类,但是尽管训练集和验证集的准确性都得到了很好的提高,但无论如何,测试总是会导致25%的准确性我做了什么。我决定首先对Kaggle的cats dogs数据集进行微调VGG16,然后按照不同的教程进行操作,以获得良好的准确性。但是,这是我第一次遇到的相同问题。现在准确度是50%(因为它是2类)。我开始认为这是Keras VGG16的问题。我在网上尝试了所有不同的建议,包括在stackoverflow中类似问题中的类似建议,但似乎无济于事。所有的预处理,扩充和冻结层似乎都已正确完成,在尝试了数周的错误之后,我发现我不得不就此事向您提出建议/建议。

这是我正在使用的完整代码:

from keras.models import Sequential, Model, load_model
from keras import applications
from keras import optimizers
from keras.layers import Dropout, Flatten, Dense
from keras.preprocessing.image import ImageDataGenerator
from sklearn.metrics import  classification_report,confusion_matrix
from keras.callbacks import ModelCheckpoint

%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np

这是我使用的混淆矩阵函数实现。

def plot_confusion_matrix_two(cm,
                          target_names,
                          title='Confusion matrix',
                          cmap=None,
                          normalize=True):

import matplotlib.pyplot as plt
import numpy as np
import itertools

accuracy = np.trace(cm) / float(np.sum(cm))
misclass = 1 - accuracy

if 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() / 2
for 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

img_rows, img_cols, img_channel = 224, 224, 3
base_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 layers

for 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 = False



model = 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 = 224

epochs = 500

train_batch = 50
valid_batch = 30
test_batch = 20

train_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 Report
predictions = 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%,具体取决于超参数调整)。所以我现在的猜测是,当我尝试使用confusion_matrix和报告函数进行分析时出了点问题。我仍然找不到问题。

2 个答案:

答案 0 :(得分:0)

  

对我制作的具有4个类别的数据集进行分类

对于初学者来说,对于4类分类问题,您的网络配置似乎很奇怪(至少可以说)。第一个建议:

  1. 在模型编译中更改为loss='categorical_crossentropy'

  2. 将最后一层更改为

add_model.add(Dense(4, activation='softmax'))

由于您的predictions = np.argmax(predictions, axis=1)行,我假设您已经在使用一键编码的标签...

答案 1 :(得分:0)

模型=模型(输入= base_model.input,输出= add_model(base_model.output)) 您无法正确添加新图层。只需使用功能性API。

out = base_model.output
out = Flatten()(out)
out = Dense(256, activation='relu')(out)
out = Dropout(0.5)(out)
out = Dense(2, activation='softmax')(out)
for layer in add_model.layers[:-3]:
    layer.trainable = False
model = Model(inputs=base_model.input, outputs=out)