为多标签分类生成 sklearn 指标的问题

Posted

技术标签:

【中文标题】为多标签分类生成 sklearn 指标的问题【英文标题】:Issues producing sklearn metrics for multi-label classification 【发布时间】:2021-12-06 02:09:24 【问题描述】:

我已经在视网膜(眼睛)图像上实现了一个 EfficientNet 预训练模型,但我无法弄清楚为什么我的指标不起作用!如果这是问题,我愿意使用其他指标包(keras?)。

# Loading a pretrained conv base model
input_shape = (256, 256, 3)
conv_base = EfficientNetB7(weights=None, include_top=False, input_shape=input_shape)

dropout_rate = 0.2
number_of_classes = 3

initial_learning_rate=2e-5
lr_schedule = tf.keras.optimizers.schedules.ExponentialDecay(
    initial_learning_rate,
    decay_steps=100000,
    decay_rate=0.96,
    staircase=True
)

en_model = models.Sequential()
en_model.add(conv_base)
en_model.add(layers.GlobalMaxPooling2D(name='gap'))

# Avoid overfitting 
en_model.add(layers.Dropout(rate=dropout_rate, name='dropout_out'))

# Set number_of_classes to the number of your final predictions
en_model.add(layers.Dense(number_of_classes, activation='sigmoid', name='fc_out')) #replaced softmax with sigmoid
conv_base.trainable = False

en_model.compile(
    #loss='sparse_categorical_crossentropy',
    #loss='categorical_crossentropy',
    #optimizer=optimizers.RMSprop(learning_rate=2e-5),
    loss='binary_crossentropy',
    optimizer=optimizers.Adam(learning_rate=lr_schedule),
    metrics=['accuracy']
)

history = en_model.fit(
    train_generator,
    steps_per_epoch=10,
    epochs=100,
    validation_data=val_generator,
    #validation_steps=None,
    validation_freq=1,
    verbose=1,
    callbacks=[tensorboard_callbacks],
    use_multiprocessing=True,
    workers=4
)
print('Average test loss: ', np.average(history.history['loss']))

指标 - 这是视网膜(眼睛)图像数据,共有三个类别/标签 - 糖尿病视网膜病变、青光眼和其他。我将展示第一类的代码,您可以在其中看到每个度量的数字相同,并且混淆矩阵为零。我不知道发生了什么!

from sklearn.metrics import confusion_matrix, accuracy_score, f1_score, precision_score, recall_score
# y_true are the labels from the validation generator; we have three labels (DR, glaucoma, other)
print(f'Accuracy = accuracy_score(val_generator.labels[:,0],[round(x) for x in val_pred[:,0]])')
print(f"F1 = f1_score(val_generator.labels[:,0],[round(x) for x in val_pred[:,0]], average='micro')")
print(f"Precision = precision_score(val_generator.labels[:,0],[round(x) for x in val_pred[:,0]], average='micro')")
print(f"Recall = recall_score(val_generator.labels[:,0],[round(x) for x in val_pred[:,0]], average='micro')")
print('Confusion matrix =')
confusion_matrix(val_generator.labels[:,0],[round(x) for x in val_pred[:,0]])

输出

Accuracy = 0.7807953443258971
F1 = 0.7807953443258971
Precision = 0.7807953443258971
Recall = 0.7807953443258971
Confusion matrix =
array([[805,   0],
       [226,   0]])

上面的相同代码(用 1 和 2 替换 0)产生以下结果:

Accuracy = 0.8244422890397672
F1 = 0.8244422890397672
Precision = 0.8244422890397672
Recall = 0.8244422890397672
Confusion matrix =
array([[850,   0],
       [181,   0]])
Accuracy = 0.6876818622696411
F1 = 0.6876818622696411
Precision = 0.6876818622696411
Recall = 0.6876818622696411
Confusion matrix =
array([[  0, 322],
       [  0, 709]])

【问题讨论】:

【参考方案1】:

Keras 和 Tensorflow 已经有很多 metrics(如果不是全部),如果您正在寻找替代品,您会提到:


!pip install -U tensorflow-addons
import tensorflow as tf

from tensorflow.python.keras.metrics import Accuracy
from tensorflow.python.keras.metrics import Recall
from tensorflow.python.keras.metrics import Precision
from tensorflow.python.keras.metrics import AUC
import tensorflow_addons as tfa

tf.math.confusion_matrix
tfa.metrics.F1Score

关于你的Sigmoid 激活函数,你提到你有3个类;为什么不考虑使用实际用于多类逻辑回归的Softmax 激活函数?您还必须将 binary_crossentropy 损失函数替换为 categorical_crossentropysparse_categorical_crossentropy,具体取决于标签的编码方式。如果您有一个旨在预测零个或多个类别标签 (0, 1) 的多标签分类问题,那么binary_crossentropy 是您的正确选择。

【讨论】:

标签是 0 和 1。 那么一个热编码?糖尿病视网膜病变 --> 1, 0, 0, 青光眼 --> 0, 1, 0, and other --> 0, 0, 1? 如何导入这些指标。 import tf.keras.metrics.accuracy 给了我一个错误ModuleNotFoundError: No module named 'tf'即使我已经将 tensorflow 导入为 tf.我也做了from tensorflow import keras 不是真正的 one-hot 编码,因为每个图像在所有三个类中都可以有一个 1。 检查您的 tensorflow 版本,以及它是否与网站上可用的指标匹配的版本

以上是关于为多标签分类生成 sklearn 指标的问题的主要内容,如果未能解决你的问题,请参考以下文章

为多标签文本分类转换数据集

将单标签分类器转换为多标签分类器

转换为多标签分类

将二进制分类转换为多标签?

为多类多标签分类构建混淆矩阵

XGBoost 用于多标签分类?