Keras:不同模型的分类报告准确度不同,多分类的预测准确度不同

kxxlusnw  于 2023-04-06  发布在  其他
关注(0)|答案(3)|浏览(229)

Colab链接为here
导入数据的方式如下

train_ds = tf.keras.preprocessing.image_dataset_from_directory(
    main_folder,
    validation_split=0.1,
    subset="training",
    label_mode='categorical',
    seed=123,
    image_size=(dim, dim))

val_ds = tf.keras.preprocessing.image_dataset_from_directory(
    main_folder,
    validation_split=0.1,
    subset="validation",
    label_mode='categorical',
    seed=123,
    image_size=(dim, dim))

该模型通过以下方式训练

model = tf.keras.models.Sequential([
    tf.keras.layers.experimental.preprocessing.Rescaling(1. / 255),
    ...
    tf.keras.layers.Dense(2, activation='softmax')
])

model.compile(optimizer="adam", loss=tf.keras.losses.CategoricalCrossentropy(), metrics=['accuracy'])

我正在努力获得正确的predicted categories和正确的true_categories来使分类报告工作:

y_pred = model.predict(val_ds, batch_size=1)
predicted_categories = np.argmax(y_pred, axis=1)

true_categories = tf.concat([y for x, y in val_ds], axis=0).numpy()
true_categories_argmax = np.argmax(true_categories, axis=1)

print(classification_report(true_categories_argmax, predicted_categories))

此时,epoch的输出与分类报告相矛盾

Epoch 22/75
144/144 [==============================] - 7s 48ms/step - loss: 0.0611 - accuracy: 0.9776 - val_loss: 0.0768 - val_accuracy: 0.9765

模型的验证集返回

model.evaluate(val_ds)

[==============================] - 0s 16ms/step - loss: 0.0696 - accuracy: 0.9784
[0.06963862478733063, 0.9784313440322876]

而分类报告则大不相同:

precision    recall  f1-score   support
     0.0       0.42      0.44      0.43       221
     1.0       0.56      0.54      0.55       289
    accuracy                           0.49       510
   macro avg       0.49      0.49      0.49       510
weighted avg       0.50      0.49      0.50       510

类似的问题hereherehereherehere没有答案。

ecfdbz9o

ecfdbz9o1#

你设置label_mode='categorical',那么这是一个多类分类,你需要在最后一个密集层使用softmax激活。因为softmax强制输出总和等于1。你可以把它们解释为概率。使用sigmoid,不可能找到主要类。它可以无限制地分配任何值。

我的模型最后一层Dense(5, activation = 'softmax')
我的模特损失loss=tf.keras.losses.CategoricalCrossentropy(),和你的一样。在这种情况下,标签是独热编码的。
**说明:**我使用了5类分类用于演示目的,但它遵循相同的逻辑。

y_pred = model.predict(val_ds)

y_pred[:2]
>>> array([[0.28257513, 0.4343998 , 0.18222839, 0.04164065, 0.05915598],
       [0.36404607, 0.08850227, 0.15335019, 0.21602921, 0.17807229]],
      dtype=float32)

这包含了每个类的概率,例如第一个例子有43%的概率属于类2。您需要使用argmax来查找类索引。

predicted_categories = np.argmax(y_pred, axis = 1)
predicted_categories[:2]

array([1, 0])

我们现在有了预测的类。现在需要获得真正的类。

true_categories = tf.concat([y for x, y in val_ds], axis = 0).numpy() # convert to np array

    true_categories[:2]
>>> array([[1., 0., 0., 0., 0.],
       [0., 0., 0., 0., 1.]], dtype=float32)

如果您将此输入分类报告,您将获得以下信息:

ValueError: Classification metrics can't handle a mix of multilabel-indicator and multiclass targets

我们还需要:

true_categories_argmax = np.argmax(true_categories, axis = 1)
    true_categories_argmax[:2]
>>> array([0, 4])

现在可以进行比较了。

print(classification_report(true_categories_argmax, predicted_categories))

这应该会产生预期的结果:

precision    recall  f1-score   support

   0       0.55      0.43      0.48       129
   1       0.53      0.83      0.64       176
   2       0.48      0.56      0.52       120
   3       0.75      0.72      0.73       152
   4       0.66      0.31      0.42       157

编辑:tf.keras.preprocessing.image_dataset_from_directory设置shuffle = True可能会打乱类。对于val_ds,请尝试设置shuffle = False。如下所示:

val_ds = tf.keras.preprocessing.image_dataset_from_directory(
    main_folder,
    validation_split=0.1,
    subset="validation",
    shuffle = False,
    label_mode='categorical',
    seed=123,
    image_size=(dim, dim))

**编辑2:**以下是我提出的:

prediction_classes = np.array([])
true_classes =  np.array([])

for x, y in val_ds:
  prediction_classes = np.concatenate([prediction_classes,
                       np.argmax(model.predict(x), axis = -1)])
  true_classes = np.concatenate([true_classes, np.argmax(y.numpy(), axis=-1)])

分类报告:

print(classification_report(true_classes, prediction_classes))

              precision    recall  f1-score   support

         0.0       0.74      0.81      0.77      1162
         1.0       0.80      0.72      0.75      1179

    accuracy                           0.77      2341
   macro avg       0.77      0.77      0.76      2341
weighted avg       0.77      0.77      0.76      2341
bq8i3lrv

bq8i3lrv2#

我在那里,我有同样的问题,对我来说,这是不够的,有一个softmax层和shuffle = False.事实上,设置shuffle = False在image_dataset_from_directory我有以下问题:train_ds仅包含5个类中的3个,瓦尔_ds包含5个类中的2个(在不创建异质样本的情况下进行拆分)
如果有帮助的话,我被建议做以下事情:

  • 要仅创建2个文件夹(无论您的类数如何):列车文件夹和验证文件夹。它们必须包含整个列车的混洗部分。
  • 使用标签的sklearn.model_selection.train_test_split(带分层参数)来创建包含异质样本的文件夹。
  • 调用image_dataset_from_directory时,不要将其拆分为确认中的train,而是调用不同的文件夹(train文件夹和确认文件夹),现在两者都使用shuffle = False。
ee7vknir

ee7vknir3#

我在这里遇到的一个问题是我的数据集是批处理的。一种方法是将batch_size设置为1:

val_ds = tf.keras.preprocessing.image_dataset_from_directory(
    base_dir,
    labels='inferred',
    validation_split=0.2,
    subset="validation",
    label_mode='int',
    seed=1337,
    color_mode="rgb",
    image_size=(150,150),
    batch_size=1,
   # shuffle=True
)

然后照常拟合模型得到分类报告如下:

from sklearn.metrics import classification_report
import numpy as np
y_true = []
y_pred=[]
for images, labels in val_ds.as_numpy_iterator():
    y_pred_probs = conv_model.predict(images, batch_size=1, verbose=0)
    y_pred_classes = np.argmax(y_pred_probs, axis=1)
    y_true.extend(labels)
    y_pred.extend(y_pred_classes)

# Convert the true labels to class labels
#y_true_classes = np.argmax(y_true, axis=0)

# Generate a classification report
report = classification_report(y_true, y_pred)

print(report)

希望这个有用。

相关问题