Многоклассовая классификация: хорошая точность при проверке набора, но прогнозирование при тестировании набора

#keras #deep-learning #classification #conv-neural-network #multiclass-classification

#keras #глубокое обучение #классификация #conv-нейронная сеть #мультиклассовая классификация

Вопрос:

Я пытаюсь классифицировать изображения, принадлежащие к 16 классам. Изображения имеют разные геометрические формы (см. рис. 2). Обучающий набор состоит из 16 x 320 = 5120 изображений, набор для проверки содержит 16 x 160 = 2560 изображений, а тестовый набор содержит 16 x 2 = 32 изображения.

Я использую приведенный ниже код для построения CNN и выполнения прогнозов.

 import numpy as np
np.random.seed(0)

import keras
from keras.models import Sequential,Input,Model
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D
from keras.layers.normalization import BatchNormalization
from keras.layers.advanced_activations import LeakyReLU 
from keras import regularizers
from keras.layers import Activation

num_classes = 16
classifier = Sequential()
classifier.add(Conv2D(32, kernel_size=(3, 3),activation='relu',input_shape=(64, 64, 3),padding='same'))
classifier.add(MaxPooling2D((2, 2),padding='same'))

classifier.add(Dropout(0.2))

classifier.add(Conv2D(64, (3, 3), activation='relu',padding='same'))
#classifier.add(LeakyReLU(alpha=0.1))
classifier.add(MaxPooling2D(pool_size=(2, 2),padding='same'))

classifier.add(Dropout(0.2))

classifier.add(Conv2D(64, (3, 3), activation='relu',padding='same'))
classifier.add(MaxPooling2D(pool_size=(2, 2),padding='same'))

classifier.add(Dropout(0.25))

classifier.add(Conv2D(128, (3, 3), activation='relu',padding='same'))                 
classifier.add(MaxPooling2D(pool_size=(2, 2),padding='same'))

classifier.add(Dropout(0.25))

classifier.add(Flatten())
classifier.add(Dense(128, activation='relu'))    

classifier.add(Dropout(0.25))

classifier.add(Dense(num_classes, activation='softmax'))


# Compiling the CNN
classifier.compile(optimizer = 'adam', loss = 'categorical_crossentropy', metrics = ['accuracy'])

from keras.preprocessing.image import ImageDataGenerator
from IPython.display import display
from PIL import Image

train_datagen = ImageDataGenerator(rescale = 1./255,
                                   shear_range = 0.2,
                                   zoom_range = 0.2,
                                   width_shift_range=0.1, 
                                   height_shift_range=0.1)                              

test_datagen = ImageDataGenerator(rescale = 1./255)

training_set = train_datagen.flow_from_directory('dataset/training_set',
                                                 target_size = (64, 64),
                                                 batch_size = 32,
                                                 class_mode = 'categorical')

test_set = test_datagen.flow_from_directory('dataset/test_set',
                                            target_size = (64, 64),
                                            batch_size = 32,
                                            class_mode = 'categorical')

from keras.callbacks import ModelCheckpoint
from keras.callbacks import EarlyStopping

STEP_SIZE_TRAIN = training_set.n//training_set.batch_size
STEP_SIZE_TEST = test_set.n//test_set.batch_size

early_stopping_callback = EarlyStopping(monitor='val_loss', patience=3)
checkpoint_callback = ModelCheckpoint('model'   '.h5', monitor='val_loss', verbose=1, save_best_only=True, mode='min')

classifier.fit_generator(training_set,
                    steps_per_epoch = STEP_SIZE_TRAIN,
                    epochs = 10,
                    validation_data = test_set,
                    validation_steps = STEP_SIZE_TEST,
                    callbacks=[early_stopping_callback, checkpoint_callback],
                    workers = 32)

from keras.models import load_model
model = load_model('model.h5')


# Part 3 - making new predictions
import numpy as np
from keras.preprocessing import image
for i in range(1,33):
    test_image = image.load_img('dataset/single_prediction/Image '   str(i)  '.bmp', target_size = (64, 64))
    test_image = image.img_to_array(test_image)
    test_image = np.expand_dims(test_image, axis = 0)
    #print(model.predict(test_image)[0])
    print(model.predict(test_image)[0].argmax() 1)
  

Я получаю следующий результат для точности обучения и проверки и потери.

 Epoch 1/10
160/160 [==============================] - 29s 179ms/step - loss: 1.3693 - acc: 0.5299 - val_loss: 0.1681 - val_acc: 0.9297

Epoch 00001: val_loss improved from inf to 0.16809, saving model to model.h5
Epoch 2/10
160/160 [==============================] - 18s 112ms/step - loss: 0.2668 - acc: 0.8984 - val_loss: 0.0773 - val_acc: 0.9699

Epoch 00002: val_loss improved from 0.16809 to 0.07725, saving model to model.h5
Epoch 3/10
160/160 [==============================] - 18s 111ms/step - loss: 0.1469 - acc: 0.9482 - val_loss: 0.0133 - val_acc: 1.0000

Epoch 00003: val_loss improved from 0.07725 to 0.01327, saving model to model.h5
Epoch 4/10
160/160 [==============================] - 18s 111ms/step - loss: 0.0990 - acc: 0.9650 - val_loss: 0.0147 - val_acc: 1.0000

Epoch 00004: val_loss did not improve from 0.01327
Epoch 5/10
160/160 [==============================] - 18s 113ms/step - loss: 0.0700 - acc: 0.9740 - val_loss: 7.3014e-04 - val_acc: 1.0000

Epoch 00005: val_loss improved from 0.01327 to 0.00073, saving model to model.h5
Epoch 6/10
160/160 [==============================] - 18s 114ms/step - loss: 0.0545 - acc: 0.9809 - val_loss: 0.0012 - val_acc: 1.0000

Epoch 00006: val_loss did not improve from 0.00073
Epoch 7/10
160/160 [==============================] - 18s 111ms/step - loss: 0.0374 - acc: 0.9865 - val_loss: 0.0101 - val_acc: 1.0000

Epoch 00007: val_loss did not improve from 0.00073
Epoch 8/10
160/160 [==============================] - 18s 111ms/step - loss: 0.0489 - acc: 0.9832 - val_loss: 0.0200 - val_acc: 0.9992

  

При попытке протестировать модель на 32 изображениях тестового набора я получил только 3 правильных прогноза. Итак, мои вопросы:

1) Почему я получаю хорошую точность при проверке, но модели терпят неудачу в наборе тестов?

2) Как я могу отобразить случайную выборку набора проверки (скажем, 10 изображений) с их предсказанными классами, чтобы иметь представление о том, как CNN справляется с набором проверки?

3) Какие-либо общие советы о том, как повысить точность в наборе тестов?

Любая помощь приветствуется! Большое спасибо 🙂

Комментарии:

1. значение acc проверки равно 1 для некоторых эпох. Возможность утечки данных из поезда в действительный.

2. @Sreeram TP : у вас случайно нет идеи о том, как решить эту проблему?

3. 3 набора данных являются независимыми. Я имею в виду, изображения назначаются абсолютно случайным образом каждому из них? Если да, другой возможностью может быть переоснащение набора проверки. Попробуйте использовать очень мало изображений в наборе проверки и посмотрите, как это работает. Затем постепенно увеличивайте его размер и посмотрите, достигнете ли вы точки, в которой точность набора тестов уменьшается, а точность проверки увеличивается. Также вы можете попробовать досрочную остановку.

4. @DavideVisentin: Я использую раннюю остановку в своем коде. Дело в том, что я немного новичок, я не знаю, достаточно ли количества выборок для обучения и проверки. Что вы подразумеваете под «изображения назначаются абсолютно случайным образом каждому из них»? У меня есть три папки, и я помещаю изображения в каждую из них случайным образом. Имеет ли это смысл?

5. Любая помощь со вторым вопросом? Спасибо 🙂

Ответ №1:

Это могло произойти по многим причинам, но я рассмотрю одну из них, которая заключается в различии в распределении данных между вашим составом, наборами проверки и наборами тестов.

В идеальной ситуации у вас должны быть наборы train, validation и test из одного дистрибутива. Хотя это концепция, на практике это может означать не только одинаковое количество точек данных для каждого класса, но и среди многих других измерений. Таким измерением может быть качество изображений для каждого разделения, т. Е. вам следует избегать наличия качественных изображений в вашем наборе поездов и допустимом наборе, в то время как тестовый набор содержит изображения низкого качества. И есть еще много подобных измерений, по которым распределения в идеале должны быть одинаковыми.

Следовательно, это игра на удачу, и вы хотите избежать вероятности того, что из-за невезения и независимо от того, насколько мала вероятность такого события, в конечном итоге получится тестовый набор, который отличается от остальных разделений.

Чтобы преодолеть это:

1) Выберите другое начальное значение при перетасовке данных перед разделением

2) Выберите равный размер разделения для ваших наборов тестов и проверки

3) Используйте k-кратную перекрестную проверку

Вы можете выполнить один или любой из вышеперечисленных шагов отдельно или в комбинации. Подробнее об этом можно прочитать здесь:

https://cs230-stanford.github.io/train-dev-test-split.html

Надеюсь, это поможет