TensorFlow多标签分类器自动精度计算

3

我正在将一个多标签分类器拟合到(train_x, train_y)上,在监控验证集(val_x, val_y)上的损失和准确率:

classification_model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=0.0002),
              loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
              metrics=['accuracy'])
classification_model.fit(train_x, train_y, validation_data=(val_x, val_y), \
        epochs=10,
        batch_size=10
)

这将产生以下输出:
Epoch 1/10
50/50 [==============================] - ETA: 0s - loss: 0.1186 - accuracy: 0.7094
Epoch 1: val_loss improved from 0.15329 to 0.11998, saving model to best_classification_model.tf
50/50 [==============================] - 12s 186ms/step - loss: 0.1186 - accuracy: 0.7094 - val_loss: 0.1200 - val_accuracy: 0.6280
Epoch 2/10
50/50 [==============================] - ETA: 0s - loss: 0.0848 - accuracy: 0.7776
Epoch 2: val_loss improved from 0.11998 to 0.10281, saving model to best_classification_model.tf
50/50 [==============================] - 8s 167ms/step - loss: 0.0848 - accuracy: 0.7776 - val_loss: 0.1028 - val_accuracy: 0.7200
Epoch 3/10
50/50 [==============================] - ETA: 0s - loss: 0.0652 - accuracy: 0.8176
Epoch 3: val_loss improved from 0.10281 to 0.09259, saving model to best_classification_model.tf
50/50 [==============================] - 10s 202ms/step - loss: 0.0652 - accuracy: 0.8176 - val_loss: 0.0926 - val_accuracy: 0.7560
Epoch 4/10
50/50 [==============================] - ETA: 0s - loss: 0.0522 - accuracy: 0.8236
Epoch 4: val_loss improved from 0.09259 to 0.08710, saving model to best_classification_model.tf
50/50 [==============================] - 10s 206ms/step - loss: 0.0522 - accuracy: 0.8236 - val_loss: 0.0871 - val_accuracy: 0.7480
Epoch 5/10
50/50 [==============================] - ETA: 0s - loss: 0.0418 - accuracy: 0.8337
Epoch 5: val_loss improved from 0.08710 to 0.08441, saving model to best_classification_model.tf
50/50 [==============================] - 10s 209ms/step - loss: 0.0418 - accuracy: 0.8337 - val_loss: 0.0844 - val_accuracy: 0.7640

为了澄清每个选项的含义:
正确标签的总数量:对于每个图像,输出20个标签,其中一些是0,一些是1。报告正确标签的总数(=正确的0的数量+正确的1的数量),并将其除以标签的总数(=20*num_images)。我不认为这是发生的情况,因为这可能会导致更高的准确性。即使训练更长时间,仅仅预测0也会给出超过90%的准确率!而且事实并非如此。
所有标签都正确的行的总数:计算所有标签(0和1)都正确的图像数量,并将其除以图像的数量。

模型输出和验证标签如下所示。
>>> classification_model.predict(val_x)    # shape: (250, 20)
array([[ -9.385,  -5.443,  -8.274, ...,   1.936, -11.607,  -1.867],
       [-10.523,   3.074,  -7.765, ...,  -2.925, -10.35 ,  -2.602],
       [ -7.872,  -7.525,  -4.877, ...,  -6.434,  -9.063,  -8.485],
       ...,
       [ -6.04 ,  -4.826,   3.537, ...,  -5.68 ,  -7.276,  -6.05 ],
       [ -5.734,  -6.399,  -5.288, ...,  -5.495,  -6.673,   0.06 ],
       [ -9.458,  -7.892,   1.391, ...,  -6.422,  -9.75 ,  -7.702]],
      dtype=float32)
>>> val_y    # also shape: (250,20)
array([[0., 0., 0., ..., 0., 0., 1.],
       [0., 1., 0., ..., 0., 0., 0.],
       [0., 0., 0., ..., 0., 0., 0.],
       ...,
       [0., 0., 1., ..., 0., 0., 0.],
       [0., 0., 0., ..., 0., 0., 1.],
       [0., 0., 1., ..., 0., 0., 0.]])

“什么是'正确标签'?”因为您的标签是独热编码,我认为正确的标签应该是输出的argmax值。 - Tou You
你能更明确一些吗:“它是计算所有正确标签的总数,还是计算所有标签都正确的行数的总数?” - Tou You
1
请查看 https://dev59.com/kL7pa4cB1Zd3GeqP3qxe#65361719。这取决于您如何编译您的模型,而这在您的帖子中缺失了。您能否提供这些细节? - Proko
这篇文章非常相关:https://dev59.com/JlcP5IYBdhLWcg3wlq_3 - Jonas De Schouwer
1个回答

2
当你使用“accuracy”时,你相信Keras会在BinaryAccuracy、CategoricalAccuracy和SparseCategoricalAccruacy之间自动选择一个指标。但是,你可能会因为没有被捕捉到的边角情况而受到足够的伤害,所以最好明确地说明。因此,我建议使用:
metrics = [tf.keras.metrics.BinaryAccuracy(threshold=???)]

BinaryAccuracy被计算为每个标签都是一个大桶的一部分。所以如果您有两个图像,每个图像有10个可能的标签,在多类分类设置中,您将有20个可能的预测结果。二元精度仅为TP + TN / 20。如果这对您有意义,它是“reduce_sum(axes=all)”而不是“(reduce_sum(reduce_mean(axis-1) == 1))”。

但是Keras通常不会记录这些边角情况。您可以自己阅读代码(如果使用“accuracy”而不是实例化实际对象,则会更加困难)。或进行实验。

此外,由于您输出的是logits而不是预测值(例如在模型末尾没有逻辑/ sigmoid层),因此您的模型将输出-inf表示0%的置信度,零表示50%的置信度,+inf表示100%的置信度。您可以决定在哪里放置阈值。典型答案是50%的置信度,但如果您想调整召回率/精确度/特异性,则可以将其上移或下移。要获得50%的置信度,如果您的模型输出logits,则应将阈值设置为0.0,因为logit为0.0对应于50%。

>>> tf.sigmoid(0.0)
<tf.Tensor: shape=(), dtype=float32, numpy=0.5>

你可以这样做。

m = tf.keras.metrics.BinaryAccuracy(threshold=0.0)

以下是一个例子,如果不正确地控制logits的阈值会损害你。

In [12]: import tensorflow as tf

In [13]: y_true = tf.convert_to_tensor([[0,0,0],[0,1,1]])

In [14]: y_pred = tf.convert_to_tensor([[-.1, -.1, -.1], [.1, .1, .1]])

In [15]: m = tf.keras.metrics.BinaryAccuracy(threshold=0.0)

In [16]: m(y_true, y_pred)
Out[16]: <tf.Tensor: shape=(), dtype=float32, numpy=0.8333334>

In [17]: m = tf.keras.metrics.BinaryAccuracy() # default threshhold is 0.5

In [18]: m(y_true, y_pred)
Out[18]: <tf.Tensor: shape=(), dtype=float32, numpy=0.6666667>

很抱歉,这么简单的事情却让人感到痛苦。欢迎使用Tensorflow。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接