keras tensorflow 角化模型中多类分类的查全率和查准率

5uzkadbs  于 2022-11-13  发布在  其他
关注(0)|答案(2)|浏览(180)

我们遇到了一个问题,要对三个类别进行分类。我们希望计算出每个类别的查全率和查准率指标。我们发现tf.keras.metrics中有内置的查准率和查全率指标。但这些指标似乎只适用于二进制分类。在我们的模型中,最后一层是具有活动函数“softmax”的Dense层。损失函数是sparse_categorical_crossentropy,因为我们对y使用了类别标签。

output = Dense(3, activation='softmax')(attention_mul)
model.compile(loss=tf.keras.losses.sparse_categorical_crossentropy, optimizer='Adam', metrics=['accuracy'])

预测结果的输出是每个类别的概率向量,例如[0.3,0.5,0.2]。为了得到类别标签,我们需要对预测结果应用np.argmax()。而内置的召回率和精确度度量接受输入的类别标签。

m = tf.keras.metrics.Recall()
m.update_state([0, 1, 1, 1], [1, 0, 1, 1])
m.result().numpy()

是否有任何解决方案来获得精确度和召回率指标,并在培训的每个阶段进行监测?

qmb5sa22

qmb5sa221#

Keras中的“精确度”和“召回率”不能用于多类分类问题是有原因的。由于度量是分批计算的,这两个度量的结果可能不准确。实际上Keras有一个“精确度”和“召回率”的实现,正是出于这个原因决定删除。
但是,如果您确实想这样做,您可以为精确度和召回率创建自定义度量,并将这些度量传递给编译器。
Keras GitHub中,删除的度量:

def precision(y_true, y_pred):
    """Precision metric.
    Only computes a batch-wise average of precision.
    Computes the precision, a metric for multi-label classification of
    how many selected items are relevant.
    """
    true_positives = K.sum(K.round(K.clip(y_true * y_pred, 0, 1)))
    predicted_positives = K.sum(K.round(K.clip(y_pred, 0, 1)))
    precision = true_positives / (predicted_positives + K.epsilon())
    return precision

def recall(y_true, y_pred):
    """Recall metric.
    Only computes a batch-wise average of recall.
    Computes the recall, a metric for multi-label classification of
    how many relevant items are selected.
    """
    true_positives = K.sum(K.round(K.clip(y_true * y_pred, 0, 1)))
    possible_positives = K.sum(K.round(K.clip(y_true, 0, 1)))
    recall = true_positives / (possible_positives + K.epsilon())
    return recall

将指标添加到compile

model.compile(loss=tf.keras.losses.sparse_categorical_crossentropy, optimizer='Adam', metrics=['accuracy', precision, recall])

这样,您就可以像您要求的那样,在每个时期监控这两个指标。

hl0ma9xz

hl0ma9xz2#

有一个keras metrics项目https://github.com/netrack/keras-metrics。但是,它没有得到维护,并且对于当前版本的Tensorflow(例如2.7)来说已经过时了。受该项目的启发,我最终找到了解决方案:我们可以自定义度量函数。代码如下:

def recall(y_true, y_pred, c):
        y_true = K.flatten(y_true)
        pred_c = K.cast(K.equal(K.argmax(y_pred, axis=-1), c), K.floatx())
        true_c = K.cast(K.equal(y_true, c), K.floatx())
        true_positives = K.sum(pred_c * true_c)
        possible_postives = K.sum(true_c)
        return true_positives / (possible_postives + K.epsilon())

    def precision(y_true, y_pred, c):
        y_true = K.flatten(y_true)
        pred_c = K.cast(K.equal(K.argmax(y_pred, axis=-1), c), K.floatx())
        true_c = K.cast(K.equal(y_true, c), K.floatx())
        true_positives = K.sum(pred_c * true_c)
        pred_positives = K.sum(pred_c)
        return true_positives / (pred_positives + K.epsilon())

    def recall_c1(y_true, y_pred):
        return recall(y_true, y_pred, 1)

    def precision_c1(y_true, y_pred):
        return precision(y_true, y_pred, 1)
    
    def recall_c2(y_true, y_pred):
        return recall(y_true, y_pred, 2)

    def precision_c2(self, y_true, y_pred):
        return precision(y_true, y_pred, 2)

我们可以使用precision_c1、recall_c1来表示类别1的精度和召回率指标,使用precision_c2、recall_c2来表示类别2的精度和召回率指标。通过将class_id值c传递给函数recall()和precision(),还可以支持更多类别。以下是模型训练期间的示例输出:

Epoch 2/2000
24/24 - 35s - loss: 1.1322 - accuracy: 0.0675 - recall_c1: 0.9962 - precision_c1: 0.0676 - recall_c2: 0.0054 - precision_c2: 0.0402 - val_loss: 1.1263 - val_accuracy: 0.0357 - val_recall_c1: 1.0000 - val_precision_c1: 0.0344 - val_recall_c2: 0.0000e+00 - val_precision_c2: 0.0000e+00 - 35s/epoch - 1s/step
Epoch 3/2000
24/24 - 35s - loss: 1.1321 - accuracy: 0.0678 - recall_c1: 0.9873 - precision_c1: 0.0679 - recall_c2: 0.0178 - precision_c2: 0.0876 - val_loss: 1.1254 - val_accuracy: 0.0382 - val_recall_c1: 0.8761 - val_precision_c1: 0.0346 - val_recall_c2: 0.2432 - val_precision_c2: 0.0948 - 35s/epoch - 1s/step

相关问题