如何在张量流中获得 class 0 的精度?

How to get precision for class 0 in tensorflow?

有没有一种方法可以使用 tf.keras.metrics.Precision 在二进制 class化模型中获得 class 0 的精度?

我尝试将 class_id 设置为 0,但它仍然给出 class 1.

的精度

我想使用回调保存具有最佳 class 0 精度值的模型,这是我在编译时需要一个精度指标的原因。

我使用 tf.keras.preprocessing.image_dataset_from_directory 创建我的数据集,train/validation/test 集的代码看起来相同(当然训练集和验证集被打乱):

ds_test = tf.keras.preprocessing.image_dataset_from_directory(
        directory = test_path,
        batch_size = my_batch_size,
        image_size = (img_height, img_width),
        shuffle = False
    )

编译方法中添加精度指标:

model.compile(loss = tf.keras.losses.BinaryCrossentropy(),
              optimizer = tf.keras.optimizers.Adam(...),
              metrics = ["accuracy",
                         tf.keras.metrics.Precision(class_id = 0, name = "precision_0")
                        ]
              )

当使用 tensorflow model.evaluate 评估模型时,我得到的精度是 class 1 而不是 class 0:

   precision_0: 0.9556

使用 sklearn.metrics.classification_report 我得到了两个 classes 的精度:

           precision
       0     0.9723
       1     0.9556

我也想在 tensorflow 中获得 class 0 的精度,在本例中为 0.9723。有任何想法吗? 提前致谢!

您可以为此编写自定义指标。如果您使用 sigmoid 激活,那么作为预测结果,您会得到 概率 class 1.

一旦你subclass tf.keras.metrics.Metric你可以改变这个:

class my_precision_class_0(tf.keras.metrics.Metric):
    def __init__(self, threshold, name='my_precision_class_0', **kwargs):
        super(my_precision_class_0, self).__init__(name=name, **kwargs)
        self.true_positives = self.add_weight(name='tp', initializer='zeros')
        self.false_positives = self.add_weight(name='fp', initializer='zeros')
        self.threshold = threshold
        
    def update_state(self, y_true, y_pred, sample_weight=None):
        y_true_cls = tf.cast(tf.equal(y_true[:, 0], 0), tf.int64)
        y_pred_cls = tf.cast(tf.less_equal(y_pred[:, 0], self.threshold), tf.int64)
        true_positives = tf.math.count_nonzero(y_true_cls * y_pred_cls)
        false_positives = tf.math.count_nonzero(y_pred_cls * (1 - y_true_cls))

        self.true_positives.assign_add(tf.cast(true_positives, tf.float32))
        self.false_positives.assign_add(tf.cast(false_positives, tf.float32))

    def result(self):
        return self.true_positives / (self.true_positives + self.false_positives)

    def reset_states(self):
        self.true_positives.assign(0)
        self.false_positives.assign(0)

这是 y_pred_cls 使用 tf.less_equal 时发生的情况,同样的事情也适用于 y_true_cls:

x = tf.constant([0.4, 4.0, 6.0])
y = tf.constant([0.5])
r = tf.math.less_equal(x, y) # --> [True, False, False]
tf.cast(r, tf.int64) # --> [1, 0, 0]

我们可以在编译中使用这个指标:

model = tf.keras.Sequential([
    tf.keras.layers.Dense(10, activation='relu'),
    tf.keras.layers.Dense(1, activation='sigmoid')
])

model.compile(optimizer='adam', loss='binary_crossentropy', 
              metrics=['accuracy', my_precision_class_0(threshold = 0.5),                                                
                       tf.keras.metrics.Precision()])

model.fit(X, y, epochs=16)
model.evaluate(X, y, batch_size = 1)
# --> loss: 0.3370 - accuracy: 0.8790 - my_precision_class_0: 0.8983 - precision: 0.8617

from sklearn.metrics import classification_report

y_hat = (model.predict(X) > 0.5).astype(int)
print(classification_report(y, y_hat, digits=4))

              precision    recall  f1-score   support
           0     0.8983    0.8531    0.8751       497
           1     0.8617    0.9046    0.8826       503
    accuracy                         0.8790      1000
   macro avg     0.8800    0.8788    0.8789      1000
weighted avg     0.8799    0.8790    0.8789      1000

我找到了一个可以简单解决我的问题的解决方法:

我使用 tf.keras.utils.image_dataset_from_directoryclass_names 参数来定义 class 的顺序,添加我的“class 0”作为第二个 class:

"class_names:仅当"labels"为"inferred"时有效。这是class名称的显式列表(必须匹配子目录的名称)。用于控制顺序classes(否则使用字母数字顺序)。

创建数据集的修改代码:

ds_test = tf.keras.preprocessing.image_dataset_from_directory(
    directory = test_path,
    class_names = ["my_class_1", "my_class_0"]
    batch_size = my_batch_size,
    image_size = (img_height, img_width),
    shuffle = False
)

不如定义自定义指标那么优雅,但它确实有效。 重要说明:这仅适用于二进制 classification!