model.predict и model.evaluate дают разный результат
Пишу функции для тестирования нейронных сетей и заметил вот такую странность. Сам код:
import shutil
import os
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from sklearn.metrics import confusion_matrix, precision_score, \
recall_score, roc_auc_score, ConfusionMatrixDisplay
def model_score_evaluate(path_name, model_name):
metrics = ['accuracy',
tf.keras.metrics.Recall(),
tf.keras.metrics.Precision(),
tf.keras.metrics.AUC()]
model = tf.keras.models.load_model(model_name, compile=False)
model.compile(loss="categorical_crossentropy",
optimizer="rmsprop",
metrics=metrics)
datagen = ImageDataGenerator(rescale = 1./255)
generator = datagen.flow_from_directory(path_name,
target_size=(Pic_Y, Pic_X),
batch_size=64,
class_mode='categorical')
(
_,
_,
test_recall,
test_precision,
test_auc
) = model.evaluate(generator, steps=len(generator))
print('Test recall:', test_recall)
print('Test precision:', test_precision)
print('Test AUC:', test_auc)
return
def model_score_predict(path_name, model_name):
model = tf.keras.models.load_model(model_name, compile=False)
model.compile(loss="categorical_crossentropy",
optimizer="rmsprop",
metrics=['accuracy'])
datagen = ImageDataGenerator(rescale = 1./255)
generator = datagen.flow_from_directory(path_name,
target_size=(Pic_Y, Pic_X),
batch_size=64,
class_mode='categorical')
true_labels = generator.classes
predictions = model.predict(generator)
predicted_labels = np.argmax(predictions, axis=1)
recall = recall_score(true_labels, predicted_labels, average='micro')
precision = precision_score(true_labels, predicted_labels, average='micro')
auc = roc_auc_score(true_labels, predictions, average='macro',
multi_class='ovr')
print('Test recall:', recall)
print('Test precision:', precision)
print('Test AUC:', auc)
cm = confusion_matrix(true_labels, predicted_labels)
class_names = list(generator.class_indices.keys())
disp = ConfusionMatrixDisplay(confusion_matrix=cm,
display_labels=class_names)
_, ax = plt.subplots(figsize=(10, 10))
disp.plot(ax=ax, cmap=plt.cm.Blues)
ax.set_title("Confusion matrix")
ax.set_xlabel("Predicted label")
ax.set_ylabel("True label")
plt.show()
return
Первая модель определяет перечень метрик при её компиляции. Затем она создает генератор из предложенных данных. Вызывается метод evaluate() и выводятся на печать метрики.
Вторая модель компилируется без дополнительного перечня метрик. У модели вызывается метод predict(), а у генератора - classes. Метрики рассчитываются с помощью библиотеки sklearn. Ну и бонусом вторая функция строит матрицу неточностей.
Приведу результаты работы функций на одних и тех де данных:
path_name = 'to_test'
model_name = 'convnet_from_scratch.h5'
model_score_evaluate(path_name, model_name)
Результат:
Test recall: 0.9272338151931763
Test precision: 0.932723343372345
Test AUC: 0.9822500944137573
model_score_predict(path_name, model_name)
Результат:
Test recall: 0.13846976993044408
Test precision: 0.13846976993044408
Test AUC: 0.4982606769303777
Матрицу неточностей не привожу. Смотреть вообще не на что при таком AUC... Почему такой разный результат?
UPD: Пощелкал метод model.predict. Формат выходных данных ожидаем:
img = Image.open('to_test/03/55907903_b524_c1222_user_652_T.jpg')
img = np.array(img.resize((Pic_X, Pic_Y))) / 255
img = np.expand_dims(img, axis=0)
model.predict(img)
Результат:
array([[9.648740e-36, 0.000000e+00, 1.000000e+00, 0.000000e+00,
7.593448e-24, 0.000000e+00, 1.165523e-33, 0.000000e+00,
0.000000e+00]], dtype=float32)
Изображение взято из третьей по счёту стопки (с индексом 2). Степень уверенности модели очень высока, как видно. Так и с прочими, которые я проверил руками.
Содержимое generator.classes без сюрпризов. Данные не перемешиваются, по порядку цифры от 0 до 8 (всего 9 классов).