TensorBoard 中的 Tensorflow 混淆矩阵

Posted

技术标签:

【中文标题】TensorBoard 中的 Tensorflow 混淆矩阵【英文标题】:Tensorflow Confusion Matrix in TensorBoard 【发布时间】:2017-05-27 19:31:09 【问题描述】:

我想在 tensorboard 中看到混淆矩阵。为此,我正在修改 Tensorflow Slim 的评估示例:https://github.com/tensorflow/models/blob/master/slim/eval_image_classifier.py

在此示例代码中,已经提供了准确度,但无法直接添加“混淆矩阵”指标,因为它不是流式传输的。

流媒体指标和非流媒体指标有什么区别?

因此,我尝试这样添加:

c_matrix = slim.metrics.confusion_matrix(predictions, labels)

#These operations needed for image summary
c_matrix = tf.cast(c_matrix, uint8)
c_matrix = tf.expand_dims(c_matrix, 2)
c_matrix = tf.expand_dims(c_matrix, 0)

op = tf.image_summary("confusion matrix", c_matrix, collections=[])
tf.add_to_collection(tf.GraphKeys.SUMMARIES, op)

这会在 tensorboard 中创建一个图像,但可能存在格式问题。矩阵应在 0-1 之间进行归一化,以便生成有意义的图像。

如何生成有意义的混淆矩阵?如何处理多批次评估流程?

【问题讨论】:

讨论有点晚了,但您可能对github.com/cheind/tf-matplotlib 感兴趣,它提供了一种生成图的通用方法,并且还支持混淆矩阵。混淆矩阵代码的灵感来自@mlninja 的回复。 我调整了上述解决方案以使用新的估算器 API:github.com/tensorflow/tensorboard/issues/… 【参考方案1】:

这是我整理的一些东西,效果相当好。仍然需要调整一些东西,比如刻度线位置等。

这个功能几乎可以为你做所有事情。

from textwrap import wrap
import re
import itertools
import tfplot
import matplotlib
import numpy as np
from sklearn.metrics import confusion_matrix



def plot_confusion_matrix(correct_labels, predict_labels, labels, title='Confusion matrix', tensor_name = 'MyFigure/image', normalize=False):
''' 
Parameters:
    correct_labels                  : These are your true classification categories.
    predict_labels                  : These are you predicted classification categories
    labels                          : This is a lit of labels which will be used to display the axix labels
    title='Confusion matrix'        : Title for your matrix
    tensor_name = 'MyFigure/image'  : Name for the output summay tensor

Returns:
    summary: TensorFlow summary 

Other itema to note:
    - Depending on the number of category and the data , you may have to modify the figzie, font sizes etc. 
    - Currently, some of the ticks dont line up due to rotations.
'''
cm = confusion_matrix(correct_labels, predict_labels, labels=labels)
if normalize:
    cm = cm.astype('float')*10 / cm.sum(axis=1)[:, np.newaxis]
    cm = np.nan_to_num(cm, copy=True)
    cm = cm.astype('int')

np.set_printoptions(precision=2)
###fig, ax = matplotlib.figure.Figure()

fig = matplotlib.figure.Figure(figsize=(7, 7), dpi=320, facecolor='w', edgecolor='k')
ax = fig.add_subplot(1, 1, 1)
im = ax.imshow(cm, cmap='Oranges')

classes = [re.sub(r'([a-z](?=[A-Z])|[A-Z](?=[A-Z][a-z]))', r'\1 ', x) for x in labels]
classes = ['\n'.join(wrap(l, 40)) for l in classes]

tick_marks = np.arange(len(classes))

ax.set_xlabel('Predicted', fontsize=7)
ax.set_xticks(tick_marks)
c = ax.set_xticklabels(classes, fontsize=4, rotation=-90,  ha='center')
ax.xaxis.set_label_position('bottom')
ax.xaxis.tick_bottom()

ax.set_ylabel('True Label', fontsize=7)
ax.set_yticks(tick_marks)
ax.set_yticklabels(classes, fontsize=4, va ='center')
ax.yaxis.set_label_position('left')
ax.yaxis.tick_left()

for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):
    ax.text(j, i, format(cm[i, j], 'd') if cm[i,j]!=0 else '.', horizontalalignment="center", fontsize=6, verticalalignment='center', color= "black")
fig.set_tight_layout(True)
summary = tfplot.figure.to_summary(fig, tag=tensor_name)
return summary
#

这里是调用此函数所需的其余代码。

''' confusion matrix summaries '''
img_d_summary_dir = os.path.join(checkpoint_dir, "summaries", "img")
img_d_summary_writer = tf.summary.FileWriter(img_d_summary_dir, sess.graph)
img_d_summary = plot_confusion_matrix(correct_labels, predict_labels, labels, tensor_name='dev/cm')
img_d_summary_writer.add_summary(img_d_summary, current_step)

迷路!!!

【讨论】:

工作得很好,谢谢。 sklearn 混淆矩阵函数不接受标签参数时出错,但幸运的是它不需要该参数,因此我将其删除,现在一切正常。 @Burton2000,请随意编辑并使代码更好 各位,看看这个链接。这是相同代码的更好实现。 github.com/tensorflow/tensorboard/issues/227 这个答案与问题无关,完全是另一个解决方案 不错的解决方案。我发现我必须添加 ax.set_ylim(len(cm)-0.5, -0.5) 才能阻止它裁剪 CM 的顶部和底部行。【参考方案2】:

以下内容适用于 tf.contrib.metrics.MetricSpec(当您使用 Estimator 时)。它的灵感来自 Jerod 的回答和 metric_op.py 源文件。你会得到一个带有百分比的流式混淆矩阵:

from tensorflow.python.framework import ops,dtypes
from tensorflow.python.ops import array_ops,variables

def _createLocalVariable(name, shape, collections=None, 
validate_shape=True,
              dtype=dtypes.float32):
  """Creates a new local variable.
  """
  # Make sure local variables are added to 
  # tf.GraphKeys.LOCAL_VARIABLES
  collections = list(collections or [])
  collections += [ops.GraphKeys.LOCAL_VARIABLES]
  return variables.Variable(
  initial_value=array_ops.zeros(shape, dtype=dtype),
  name=name,
  trainable=False,
  collections=collections,
  validate_shape=validate_shape)

def streamingConfusionMatrix(label, prediction, 
weights=None,num_classes=None):
  """
  Compute a streaming confusion matrix
  :param label: True labels
  :param prediction: Predicted labels
  :param weights: (Optional) weights (unused)
  :param num_classes: Number of labels for the confusion matrix
  :return: (percentConfusionMatrix,updateOp)
  """
  # Compute a per-batch confusion

  batch_confusion = tf.confusion_matrix(label, prediction,
                                    num_classes=num_classes,
                                    name='batch_confusion')

  count = _createLocalVariable(None,(),dtype=tf.int32)
  confusion = _createLocalVariable('streamConfusion',[num_classes, 
  num_classes],dtype=tf.int32)

  # Create the update op for doing a "+=" accumulation on the batch
  countUpdate = count.assign(count + tf.reduce_sum(batch_confusion))
  confusionUpdate = confusion.assign(confusion + batch_confusion)

  updateOp = tf.group(confusionUpdate,countUpdate)

  percentConfusion = 100 * tf.truediv(confusion,count)

  return percentConfusion,updateOp

然后您可以通过以下方式将其用作评估指标:

from tensorflow.contrib import learn,metrics
#[...]

evalMetrics = 'accuracy': 
learn.MetricSpec(metric_fn=metrics.streaming_accuracy),
               'confusionMatrix':learn.MetricSpec(metric_fn=
                                                  lambda 
label,prediction,weights=None:                         
streamingConfusionMatrix(                                                    
label,prediction,weights,num_classes=nLabels))

我建议你使用 numpy.set_printoptions(precision=2,suppress=True) 打印出来。

【讨论】:

【参考方案3】:

这是我为测试代码生成和显示“流式”混淆矩阵的方式(返回的 test_op 会针对要测试的每个批次进行评估)。

def _get_streaming_metrics(prediction,label,num_classes):

    with tf.name_scope("test"):
        # the streaming accuracy (lookup and update tensors)
        accuracy,accuracy_update = tf.metrics.accuracy(label, prediction, 
                                               name='accuracy')
        # Compute a per-batch confusion
        batch_confusion = tf.confusion_matrix(label, prediction,
                                             num_classes=num_classes,
                                             name='batch_confusion')
        # Create an accumulator variable to hold the counts
        confusion = tf.Variable( tf.zeros([num_classes,num_classes], 
                                          dtype=tf.int32 ),
                                 name='confusion' )
        # Create the update op for doing a "+=" accumulation on the batch
        confusion_update = confusion.assign( confusion + batch_confusion )
        # Cast counts to float so tf.summary.image renormalizes to [0,255]
        confusion_image = tf.reshape( tf.cast( confusion, tf.float32),
                                  [1, num_classes, num_classes, 1])
        # Combine streaming accuracy and confusion matrix updates in one op
        test_op = tf.group(accuracy_update, confusion_update)

        tf.summary.image('confusion',confusion_image)
        tf.summary.scalar('accuracy',accuracy)

    return test_op,accuracy,confusion

通过运行 test_op 处理所有数据批次后,您可以通过 confusion.eval()sess.eval(confusion)(如果您愿意)简单地查找最终的混淆矩阵(在您的会话中)。

【讨论】:

当我尝试这个时,我得到的摘要图像对应于变量的初始化(零)。如果我使用confusion_update,它似乎可以工作。知道为什么吗? 您将batch_confusion 分配给confusion_update,因此confusion_image 根本不会更新,并且您的摘要保持初始化状态。 这应该被选为最终解决方案@user2616232【参考方案4】:

Re:您的图像没有意义 - 根据tf.summary.image 的文档,uint8 值未更改(不会被标准化),并在 [0, 255] 范围内解释。您是否尝试过将图像重新归一化为 [0,255] 而不是 [0,1]?

【讨论】:

是的。这看起来更好。但是,我仍然无法从多个批次中收集结果并将其放入一个单一的混淆矩阵中......

以上是关于TensorBoard 中的 Tensorflow 混淆矩阵的主要内容,如果未能解决你的问题,请参考以下文章

Tensorflow:高级 api 估计器中的 Tensorboard

Tensorflow学习笔记3:TensorBoard可视化学习

Tensorflow Eager和Tensorboard图?

TensorFlow——TensorBoard可视化

TensorFlow篇--Tensorflow框架可视化之Tensorboard

谷歌 colab 中用于 tensorflow-1.x 的 Tensorboard