#machine-learning #keras #tensorflow2.0
Вопрос:
Я знаю, что этот вопрос задавался раньше, но я перепробовал все их решения, и у меня ничего не работает.
Моя проблема:
Я запускаю CNN для классификации некоторых изображений, типичная задача, ничего слишком сумасшедшего. У меня есть следующая компиляция моей модели.
model.compile(optimizer = keras.optimizers.Adam(learning_rate = exp_learning_rate),
loss = tf.keras.losses.SparseCategoricalCrossentropy(),
metrics = ['accuracy'])
Я поместил это в свой обучающий набор данных и оценил в своем наборе данных проверки следующим образом:
history = model.fit(train_dataset, validation_data = validation_dataset, epochs = 5)
А затем я оценил отдельный набор тестов следующим образом:
model.evaluate(test_dataset)
Что привело к этому:
4/4 [==============================] — 30 секунд 7 секунд / шаг — потеря: 1.7180 — точность: 0.8627
Однако, когда я запускаю:
model.predict(test_dataset)
У меня есть следующий вывод матрицы путаницы:
Это явно не 86% точность, как говорит мне метод .evaluate. На самом деле точность составляет 35,39%. Чтобы убедиться, что это не проблема с моим набором данных для тестирования, я сделал прогноз моей модели для моих наборов данных для обучения и проверки, и я все равно получил тот же процент, что и здесь (~ 30%), несмотря на мое обучение, точность проверки во время подгонки выросла до 96%, 87% соответственно.
Вопрос:
Я не знаю, почему .predict и .evaluate выдают разные результаты? Что там происходит? Похоже, что когда я вызываю .predict, он не использует ни один из весов, которые я обучал во время подгонки? (на самом деле, учитывая, что существует 3 класса, этот результат ничем не лучше, чем просто слепое угадывание каждой метки). Не переносятся ли веса из моей подгонки на мой прогноз? Моя функция потерь верна (я помечаю свои данные в кодированном виде, поскольку tensorflow хочет использоваться с sparse_categorical_crossentropy), и когда я передаю «точность», она просто принимает точность, соответствующую моей функции потерь. Все это должно быть согласовано. Но почему существует такое несоответствие с результатами .evaluate и .predict? Какому из них я должен доверять?
Мои попытки исправить мою проблему:
Я подумал, что, возможно, разреженная категориальная перекрестная энтропия была неправильной, поэтому я сразу же закодировал свои целевые метки и вместо этого использовал потерю categorical_crossentropy. У меня все еще та же проблема, что и выше.
Проблемы:
Если значение .evaluate неверно, то не означает ли это, что точность моего обучения и точность проверки во время подгонки также неточны? Разве они также не используют метод .evaluate? Если это так, то чему я могу доверять? Потеря не является хорошим показателем того, хорошо ли работает моя модель, потому что хорошо известно, что минимальные потери не подразумевают хорошей точности (хотя обратное обычно верно в зависимости от того, какой стандарт «хорошего» мы используем). Как мне оценить эффективность моей модели в случае, если мои показатели точности неверны? Я действительно не знаю, на что больше смотреть, потому что у меня нет другого способа оценить, обучается ли моя модель, если кто-нибудь, пожалуйста, поможет мне понять, что происходит, я был бы очень признателен. Я так расстроен.
Редактировать: (28.10.2021: 12:26)
Хорошо, я предоставлю еще немного кода для устранения неполадок.
Я изначально предварительно обработал свои данные как таковые:
image_size = (256, 256)
batch_size = 16
train_ds = keras.preprocessing.image_dataset_from_directory(
directory = image_directory,
label_mode = 'categorical',
shuffle = True,
validation_split = 0.2,
subset = 'training',
seed = 24,
batch_size = batch_size
)
val_ds = keras.preprocessing.image_dataset_from_directory(
directory = image_directory,
label_mode = 'categorical',
shuffle = True,
validation_split = 0.2,
subset = 'validation',
seed = 24,
batch_size = batch_size
)
Where image_directory is a string with a path containing my images. Now you could probably read documentation, but the image_dataset_from_directory method actually returns a tf.data.Dataset object containing a bunch of batches of the respective (training, validation) data.
I imported the VGG16 architecture to do my classification so I called the respective preprocessing function for VGG16 as follows:
preprocess_input = tf.keras.applications.vgg16.preprocess_input
train_ds = train_ds.map(lambda x, y: (preprocess_input(x), y))
val_ds = val_ds.map(lambda x, y: (preprocess_input(x), y))
This transformed the images into something that was suitable as input for VGG16. Then, in my last processing steps, I did the following validation/test split:
val_batches = tf.data.experimental.cardinality(val_ds)
test_dataset = val_ds.take(val_batches // 3)
validation_dataset = val_ds.skip(val_batches // 3)
Then I proceeded to cache and prefetch my data:
AUTOTUNE = tf.data.AUTOTUNE
train_dataset = train_ds.prefetch(buffer_size = AUTOTUNE)
validation_dataset = validation_dataset.prefetch(buffer_size = AUTOTUNE)
test_dataset = test_dataset.prefetch(buffer_size = AUTOTUNE)
The Problem:
The problem occurs in the method above. I’m still not sure whether or not .evaluate is a true indicator of accuracy for my model. But I realized that the .evaluate and .predict always coincide when my neural network is a keras.Sequential() model. However, (correct me if I’m wrong) what I am suspecting is that VGG16, when imported from keras.applications API, is actually NOT a keras.Sequential() model. Therefore, I don’t think that the .predict and .evaluate results actually coincide when I feed my data straight into my model (I was going to post this as an answer, but I don’t have sufficient knowledge nor research to confirm that any of what I said is correct, someone please chime in because I like learning things I know little to nothing about, an edit this is for now).
In the end, I worked around my problem by calling Image_Data_Generator() instead of image_dataset_from_directory() as follows:
train_datagen = ImageDataGenerator(
preprocessing_function = preprocess_input,
width_shift_range = 0.2,
height_shift_range = 0.2,
shear_range = 0.2,
zoom_range = 0.2,
horizontal_flip = True
)
val_datagen = ImageDataGenerator(
preprocessing_function = preprocess_input
)
train_ds = train_datagen.flow_from_directory(
train_image_directory,
target_size = (224, 224),
batch_size = 16,
seed = 24,
shuffle = True,
classes = ['class1', 'class2', 'class3'],
class_mode = 'categorical'
)
test_ds = val_datagen.flow_from_directory(
test_image_directory,
target_size = (224, 224),
batch_size = 16,
seed = 24,
shuffle = False,
classes = ['class1', 'class2', 'class3'],
class_mode = 'categorical'
)
(ПРИМЕЧАНИЕ: я получил это на основе следующей ссылки из документации tensorflow: https://www.tensorflow.org/api_docs/python/tf/keras/preprocessing/image/ImageDataGenerator#flow_from_directory)
Это завершает всю предварительную обработку для меня. Затем, когда я вызываю model.evaluate(test_ds), он возвращает точно такой же результат, как и при выполнении model.predict_generator(test_ds). После некоторой незначительной обработки результатов прогнозирования я использую следующий код для своей матрицы путаницы:
Y_pred = model.predict(test_ds)
y_pred = np.argmax(Y_pred, axis=1)
cf = confusion_matrix(test_ds.classes, y_pred)
sns.heatmap(cf, annot= True, xticklabels = class_names,
yticklabels = class_names)
plt.title('Performance of Model on Testing Set')
Это устраняет несоответствие в матрице путаницы и результате model.evaluate(test_ds).
Вывод:
Если вы загружаете изображения в модель классификации, и ваши потери и точность совпадают, но вы получаете несоответствие между вашими прогнозами и потерями, точностью, попробуйте выполнить предварительную обработку всеми возможными способами. Обычно я предварительно обрабатываю свои изображения, используя метод image_dataset_from_directory() для всех моих моделей keras.sequential(), однако для модели VGG16, которая, как я подозреваю, не является моделью sequential(), использование ImageDataGenerator(…).flow_from_directory(…) привело к правильному формату для генерации моделипрогноз, который согласуется с показателями производительности.
TLDR Я не ответил ни на один из своих первоначальных вопросов, но я нашел обходной путь. Извините, если это спам в любом случае. Как и в большинстве сообщений о переполнении стека, я надеюсь, что моя суматоха за последние несколько часов поможет кому-то в будущем.
Комментарии:
1. Вам нужно включить код, который создает матрицу путаницы, что, если вы допустили ошибку там?
2. @Dr.Snoopy После некоторых размышлений я понял, что моя предварительная обработка данных была совершенно неправильной. Я подумывал об удалении этого сообщения, но это может помочь другим, которые выполняют аналогичную задачу. Я привожу полный ответ ниже. Я введу туда все свои мысли. Спасибо, что вы посмотрели на мой вопрос!
3. У меня была точно такая же проблема, и вы мне очень помогли! Спасибо!
Ответ №1:
У меня была та же проблема. И даже с ImageDataGenerator это оставалось таким странным поведением.
Но я думаю, что проблема заключается в флаге перемешивания набора проверки.
Вы изменили это отсюда:
val_ds = keras.preprocessing.image_dataset_from_directory(
directory = image_directory,
label_mode = 'categorical',
shuffle = True,
validation_split = 0.2,
subset = 'validation',
seed = 24,
batch_size = batch_size
)
Сюда:
test_ds = val_datagen.flow_from_directory(
test_image_directory,
target_size = (224, 224),
batch_size = 16,
seed = 24,
shuffle = False,
classes = ['class1', 'class2', 'class3'],
class_mode = 'categorical'
)
Комментарии:
1. Да! Я определенно рекомендую не перетасовывать ваш набор проверки, если вам нужно сохранить результаты (например, когда я вывожу свою матрицу путаницы). Фактически, непреднамеренное перетасование моего набора проверки было причиной несоответствия между .predict и .evaluate (у моих коллег была такая же проблема, как и у меня, и это было буквально причиной). Я понял это давно (но я не обновлял его по какой-то причине …). Это, безусловно, основная причина несоответствия. Принимая это как ответ. Спасибо!