Высокая обучаемость и достоверность проверки, плохая точность теста - PullRequest
0 голосов
/ 27 марта 2020

Я пытаюсь классифицировать 2 класса изображений. Несмотря на то, что я получаю высокую обучаемость и точность проверки (0,97) после 10 эпох, результаты моих тестов ужасны (точность 0,48), а матрица путаницы показывает, что сеть предсказывает изображения для неправильного класса (прикрепленные результаты).

В наборе данных есть только 2 класса, каждый класс имеет 10 000 примеров изображений (после дополнения). Я использую сеть VGG16. Полный набор данных делится на 20% на набор тестов (это разделение было выполнено путем отбора случайных изображений из каждого класса, поэтому оно перемешивается). Остальные изображения разделены на 80% обучающих и 20% допустимых наборов (как указано в строке кода ImageDataGenerator). Итак, в итоге получим:

12,904 Изображения поездов, принадлежащие 2 классам

3,224 Допустимые изображения, принадлежащие 2 классам

4032 Тестовые изображения, принадлежащие 2 классам

Это мой код:

def CNN(CNN='VGG16', choice='predict', prediction='./dataset/Test/image.jpg'):
    ''' Train images using one of several CNNs '''
    Train   = './dataset/Train'
    Tests   = './dataset/Test'
    shape   = (224, 224)
    epochs  = 10
    batches = 16
    classes = []
    for c in os.listdir(Train): classes.append(c)
    IDG = keras.preprocessing.image.ImageDataGenerator(validation_split=0.2)
    train = IDG.flow_from_directory(Train, target_size=shape, color_mode='rgb',
        classes=classes, batch_size=batches, shuffle=True, subset='training')
    valid = IDG.flow_from_directory(Train, target_size=shape, color_mode='rgb',
        classes=classes, batch_size=batches, shuffle=True, subset='validation')
    tests = IDG.flow_from_directory(Tests, target_size=shape, color_mode='rgb',
        classes=classes, batch_size=batches, shuffle=True)
    input_shape = train.image_shape
    if CNN == 'VGG16' or 'vgg16':
        model = VGG16(weights=None, input_shape=input_shape,
            classes=len(classes))
    elif CNN == 'VGG19' or 'vgg19':
        model = VGG19(weights=None, input_shape=input_shape,
            classes=len(classes))
    elif CNN == 'ResNet50' or 'resnet50':
        model = ResNet50(weights=None, input_shape=input_shape,
            classes=len(classes))
    elif CNN == 'DenseNet201' or 'densenet201':
        model = DenseNet201(weights=None, input_shape=input_shape,
            classes=len(classes))
    model.compile(optimizer=keras.optimizers.SGD(
            lr=1e-3,
            decay=1e-6,
            momentum=0.9,
            nesterov=True),
            loss='categorical_crossentropy',
            metrics=['accuracy'])
    Esteps = int(train.samples/train.next()[0].shape[0])
    Vsteps = int(valid.samples/valid.next()[0].shape[0])
    if choice == 'train':
        history= model.fit_generator(train,
            steps_per_epoch=Esteps,
            epochs=epochs,
            validation_data=valid,
            validation_steps=Vsteps,
            verbose=1)
        plt.plot(history.history['loss'])
        plt.plot(history.history['val_loss'])
        plt.title('Model Loss')
        plt.ylabel('Loss')
        plt.xlabel('Epoch')
        plt.legend(['Train', 'Validation'], loc='upper left')
        plt.show()
        plt.plot(history.history['acc'])
        plt.plot(history.history['val_acc'])
        plt.title('Model Accuracy')
        plt.ylabel('Accuracy')
        plt.xlabel('Epoch')
        plt.legend(['Train', 'Validation'], loc='upper left')
        plt.show()
        Y_pred = model.predict_generator(tests, verbose=1)
        y_pred = np.argmax(Y_pred, axis=1)
        matrix = confusion_matrix(tests.classes, y_pred)
        df_cm  = pd.DataFrame(matrix, index=classes, columns=classes)
        plt.figure(figsize=(10,7))
        sn.heatmap(df_cm, annot=True)
        print(classification_report(tests.classes,y_pred,target_names=classes))
        model.save_weights('weights.h5')
    elif choice == 'predict':
        model.load_weights('./weights.h5')
        img = image.load_img(prediction, target_size=shape)
        im = image.img_to_array(img)
        im = np.expand_dims(im, axis=0)
        if CNN == 'VGG16' or 'vgg16':
            im = keras.applications.vgg16.preprocess_input(im)
            prediction = model.predict(im)
            print(prediction)
        elif CNN == 'VGG19' or 'vgg19':
            im = keras.applications.vgg19.preprocess_input(im)
            prediction = model.predict(im)
            print(prediction)
        elif CNN == 'ResNet50' or 'resnet50':
            im = keras.applications.resnet50.preprocess_input(im)
            prediction = model.predict(im)
            print(prediction)
            print(keras.applications.resnet50.decode_predictions(prediction))
        elif CNN == 'DenseNet201' or 'densenet201':
            im = keras.applications.densenet201.preprocess_input(im)
            prediction = model.predict(im)
            print(prediction)
            print(keras.applications.densenet201.decode_predictions(prediction))

CNN(CNN='VGG16', choice='train')

Результаты:

enter image description here enter image description here enter image description here

          precision    recall  f1-score   support
Predator       0.49      0.49      0.49      2016
Omnivore       0.49      0.49      0.49      2016
accuracy       --        --        0.49      4032

Я подозреваю, что ImageDataGenerator () не тасует изображения «до» поезда / действительного разделения. Если это так, как я могу заставить ImageDataGenerator здесь, в Керасе, перетасовать набор данных перед разделением?

Если случайного перемешивания нет, как я могу решить мою проблему? что я делаю не так?

...