web-dev-qa-db-fra.com

Matrice de confusion Tensorflow dans TensorBoard

Je veux avoir un visuel de la matrice de confusion dans tensorboard. Pour ce faire, je modifie l'exemple d'évaluation de Tensorflow Slim: https://github.com/tensorflow/models/blob/master/slim/eval_image_classifier.py

Dans cet exemple de code, Accuracy est déjà fourni, mais il n'est pas possible d'ajouter directement une métrique "matrice de confusion" car il ne s'agit pas d'une transmission en continu. 

Quelle est la différence entre les métriques en continu et celles qui ne le sont pas?

Par conséquent, j'ai essayé de l'ajouter comme ceci:

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)

Cela crée une image dans tensorboard mais il y a probablement un problème de formatage. La matrice doit être normalisée entre 0 et 1 afin de produire une image significative.

Comment puis-je produire une matrice de confusion significative? Comment puis-je traiter avec le processus d'évaluation multi-lots?

16
user2616232

Voici quelque chose que j'ai mis ensemble qui fonctionne raisonnablement bien. Encore faut-il ajuster quelques petites choses comme les placements de ticks, etc. 

 Confusion Matrix as Image in Tensorflow

Voici la fonction qui fera à peu près tout pour vous.

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

Et voici le reste du code dont vous aurez besoin pour appeler cette fonction. 

''' 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)

Confondre !!!

25
MLNINJA

Voici comment j'ai produit et affiché une matrice de confusion "en continu" pour le code de test (le test_op renvoyé est évalué pour chaque lot sur lequel effectuer le test).

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

Après avoir traité tous les lots de données en exécutant test_op, vous pouvez simplement consulter la matrice de confusion finale (au sein de votre session) par confusion.eval() ou sess.eval(confusion) si vous préférez.

16
Jerod

Voici quelque chose qui fonctionne avec tf.contrib.metrics.MetricSpec (lorsque vous utilisez Estimator). Il est inspiré de la réponse de Jerod et du fichier source metric_op.py. Vous obtenez une matrice de confusion en flux avec des pourcentages:

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

Vous pouvez ensuite l'utiliser comme métrique d'évaluation de la manière suivante:

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))}

Je vous suggère d'utiliser numpy.set_printoptions (precision = 2, suppress = True) pour l'imprimer.

5
ma3oun

Re: votre image n’a pas de sens - conformément à la documentation de tf.summary.image , pour uint8, les valeurs ne sont pas modifiées (ne seront pas normalisées) et sont interprétées dans la plage [0, 255]. Avez-vous essayé de re-normaliser votre image à [0,255] au lieu de [0,1]?

0
dandelion