【发布时间】:2018-09-17 14:46:36
【问题描述】:
所以我一直在尝试微调 VGG16,以便对我创建的具有 4 个类别的数据集进行分类,但是虽然训练集和验证集的准确度提高得很好,但无论如何测试总是会产生 25% 的准确度我做了什么。我决定首先在 Kaggle 的猫狗数据集上微调 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()
使用 imagenet 权重调用 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% 取决于超参数调整)。所以我现在的猜测是,当我尝试使用混淆矩阵和报告函数进行分析时,出现了问题。不过我还是找不到问题。
【问题讨论】:
-
请 1) 在
np.argmax()操作 之前 发布您的predictions变量的样本 2) 确认您的标签确实是一次性编码的(如我的假设下面回答) -
看来问题与我正在使用的 scikit-learn 的混淆矩阵和分类报告有关。不过,我仍在努力弄清楚!也许我需要在函数调用中使用它们之前修改预测/标签
标签: machine-learning keras deep-learning neural-network computer-vision