我是机器学习的新手。目前,我正在使用与keras一起进行深度学习的水果/蔬菜分类项目。我能够训练模型。到目前为止,它可以正确地检测出已经训练好的对象,但是当我提供另一个未经训练的水果/蔬菜时,它是根据训练后的模型预测的,而应该将其识别为未知水果。
假设我用苹果,马铃薯和香蕉图像训练了一个模型。只要我提供Apple /土豆/香蕉的图像,它就可以正确预测。但是,当我提供橘子的图像时,它就可以预测为土豆或柠檬所预测的为苹果。这是我用来训练和预测结果的代码段:
import os.path
import numpy as np
np.random.seed(123)
from keras import applications
from keras.models import Sequential
from keras.layers import Dropout, Flatten, Dense
from keras.utils.np_utils import to_categorical
from keras.preprocessing.image import ImageDataGenerator, img_to_array, load_img
from keras.layers.normalization import BatchNormalization
import matplotlib.pyplot as plt
import math
import cv2
#dimensions of images
img_width, img_height = 224, 224
#file paths & directories
top_model_weights_path = 'bottleneck_fc_model.h5'
bottleneck_train_path = 'bottleneck_features_train.npy'
bottleneck_validation_path = 'bottleneck_features_validation.npy'
train_data_dir = 'data/train'
validation_data_dir = 'data/validation/'
#hyperparameters
epochs = 10
batch_size = 16
def save_bottleneck_features():
model = applications.VGG16(include_top=False, weights='imagenet')
datagen = ImageDataGenerator(rescale=1./255,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True)
generator = datagen.flow_from_directory(train_data_dir,
target_size=(img_width, img_height),
batch_size=batch_size,
shuffle=False)
no_train_samples = len(generator.filenames)
predict_size_train = int(math.ceil(no_train_samples / batch_size))
bottleneck_features_train = model.predict_generator(generator, predict_size_train)
np.save(bottleneck_train_path, bottleneck_features_train)
datagen = ImageDataGenerator(rescale=1./255)
generator = datagen.flow_from_directory(validation_data_dir,
target_size=(img_width, img_height),
batch_size=batch_size,
class_mode=None,
shuffle=False)
no_validation_samples = len(generator.filenames)
predict_size_validation = int(math.ceil(no_validation_samples / batch_size))
bottleneck_features_validation = model.predict_generator(generator, predict_size_validation)
np.save(bottleneck_validation_path, bottleneck_features_validation)
def train_top_model():
datagen_top = ImageDataGenerator(rescale=1./255)
generator_top = datagen_top.flow_from_directory(train_data_dir,
target_size=(img_width, img_height),
batch_size=batch_size,
class_mode='categorical',
shuffle=False)
num_classes = len(generator_top.class_indices)
# save the class indices to use later in predictions
np.save('class_indices.npy', generator_top.class_indices)
# get the class labels for the training data, in the original order
train_labels = generator_top.classes
# convert the training labels to categorical vectors
train_labels = to_categorical(train_labels, num_classes=num_classes)
generator_top = datagen_top.flow_from_directory(validation_data_dir,
target_size=(img_width, img_height),
batch_size=batch_size,
class_mode=None,
shuffle=False)
validation_labels = generator_top.classes
validation_labels = to_categorical(validation_labels, num_classes=num_classes)
# load the bottleneck features saved earlier
train_data = np.load('bottleneck_features_train.npy')
validation_data = np.load('bottleneck_features_validation.npy')
# build the model
model = Sequential()
model.add(Flatten(input_shape=train_data.shape[1:]))
model.add(BatchNormalization())
model.add(Dense(256, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(num_classes, activation='softmax'))
model.compile(optimizer='rmsprop', loss='categorical_crossentropy', metrics=['accuracy'])
history = model.fit(train_data, train_labels, epochs=epochs, batch_size=batch_size)
model.save_weights(top_model_weights_path)
def predict(image_path):
class_dictionary = np.load('class_indices.npy').item()
#print("Values: ",class_dictionary)
num_classes = len(class_dictionary)
orig = cv2.imread(image_path)
print('[INFO] loading and preprocessing image...')
image = load_img(image_path, target_size=(224, 224))
image = img_to_array(image)
image = image / 255
image = np.expand_dims(image, axis=0)
model = applications.VGG16(include_top=False, weights='imagenet')
bottleneck_prediction = model.predict(image)
# build top model
model = Sequential()
model.add(Flatten(input_shape=bottleneck_prediction.shape[1:]))
model.add(BatchNormalization())
model.add(Dense(256, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(num_classes, activation='sigmoid'))
model.load_weights(top_model_weights_path)
# use the bottleneck prediction on the top model to get the final classification
class_predicted = model.predict_classes(bottleneck_prediction)
probabilities = model.predict_proba(bottleneck_prediction)
inID = class_predicted[0]
inv_map = {v: k for k, v in class_dictionary.items()}
label = inv_map[inID]
print("Image ID: {}, Label: {}".format(inID, label))
cv2.putText(orig, "Predicted: {}".format(label), (10, 30),
cv2.FONT_HERSHEY_PLAIN, 1.5, (0, 0, 0), 2)
cv2.imshow('Classification', orig)
cv2.imwrite('predicted.jpg', orig)
cv2.waitKey(0)
if __name__ == '__main__':
if not os.path.exists(bottleneck_train_path):
save_bottleneck_features()
if not os.path.exists(top_model_weights_path):
train_top_model()
image_path = 'fruits/orange.jpg'
predict(image_path)
如何克服这种情况?任何帮助将不胜感激。
答案 0 :(得分:0)
在最后一层使用loss='categorical_crossentropy'
和activation='softmax'
进行训练时,每个类都由最后一层图中的1个节点表示。 softmax通过规范化所有值来确保所有节点的值总和为1。
分类交叉熵假定具有最高值的节点为预测类,并将其与标签进行比较。
例如,在预测样本后,您可以为节点提供以下值:0.33 banana, 0.33 apple, 0.34 potato
,因此,马铃薯将成为为预测选择的类。
如果您希望获得“未知类别”的预测,则应将其添加为另一个可能的类别,并在训练过程中将一些样本标记为未知类别。
编辑:
请注意,尽管我上面建议的内容很适合您,但对其进行培训可能会非常困难,因为它可能需要大量已知和未知的样本,因为“未知”功能难以推广,并且可能会破坏其他特征类的概括。
如我前面所述,一种更实用的方法是在预测您为每个可能的标签接收到一些值之后,定义一个阈值。挑选标签时,此值为标签的“置信度”分数。
检查上面的示例,我们将以0.34的置信度选择马铃薯。
您可以定义一些阈值,例如0.6,并在假定图像标签时,检查不同的置信度得分,如果最高(“选择”)标签低于阈值,则可以将其标记为“未知水果”。