我正在自定义Tensorflow的示例代码retrain.py,通过添加额外的密集层、dropout、动量梯度下降等方法来训练我自己的图像数据。
我想在Tensorboard中添加一个混淆矩阵,所以我按照这个帖子中的第一个答案(Jerod的回答)进行操作(我也尝试了第二个答案,但遇到了一些调试问题),并在add_evaluation_step
函数中添加了几行代码。现在它看起来像这样:
def add_evaluation_step(result_tensor, ground_truth_tensor): with tf.name_scope('accuracy'): with tf.name_scope('correct_prediction'): prediction = tf.argmax(result_tensor, 1) correct_prediction = tf.equal( prediction, tf.argmax(ground_truth_tensor, 1)) with tf.name_scope('accuracy'): evaluation_step = tf.reduce_mean(tf.cast(correct_prediction, tf.float32)) tf.summary.scalar('accuracy', evaluation_step) print('prediction shape :: {}'.format(ground_truth_tensor)) #Add confusion matrix batch_confusion = tf.confusion_matrix(tf.argmax(ground_truth_tensor, 1), prediction, num_classes=7, name='batch_confusion') # Create an accumulator variable to hold the counts confusion = tf.Variable( tf.zeros([7,7], 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_update, tf.float32), [1, 7, 7, 1]) tf.summary.image('confusion',confusion_image) return evaluation_step, prediction
我的问题是如何在行(实际类别)和列(预测类别)上添加标签,以获得类似于下面的结果:
回答:
Jerod的回答几乎包含了你需要的所有内容,另外例如yauheni_selivonchyk的另一个回答展示了如何向Tensorboard添加自定义图像。
然后只需将所有内容整合在一起,即:
- 实现将绘制的图像传递给摘要的方法(作为RGB数组)
- 实现将矩阵数据转换为美化的混淆图像的方法
- 定义你的运行评估操作以获取混淆矩阵数据(以及其他指标),并准备一个占位符和摘要来接收绘制的图像
- 将所有内容结合使用
1. 实现将绘制的图像传递给摘要的方法
import matplotlibimport matplotlib.pyplot as pltimport pandas as pdimport seaborn as snsimport numpy as npimport tensorflow as tf# Inspired by yauheni_selivonchyk on SO (https://stackoverflow.com/a/42815564/624547)def get_figure(figsize=(10, 10), dpi=300): """ 返回一个pyplot图形 :param figsize: :param dpi: :return: """ fig = plt.figure(num=0, figsize=figsize, dpi=dpi) fig.clf() return figdef fig_to_rgb_array(fig, expand=True): """ 将图形转换为RGB数组 :param fig: PyPlot图形 :param expand: 是否扩展标志 :return: RGB数组 """ fig.canvas.draw() buf = fig.canvas.tostring_rgb() ncols, nrows = fig.canvas.get_width_height() shape = (nrows, ncols, 3) if not expand else (1, nrows, ncols, 3) return np.fromstring(buf, dtype=np.uint8).reshape(shape)def figure_to_summary(fig, summary, place_holder): """ 将图形转换为TF摘要 :param fig: 图形 :param summary: 要评估的摘要 :param place_holder: 摘要图像占位符 :return: 摘要 """ image = fig_to_rgb_array(fig) return summary.eval(feed_dict={place_holder: image})
2. 将矩阵数据转换为美化的混淆图像
(这里是一个示例,但具体取决于你的需求)
def confusion_matrix_to_image_summary(confusion_matrix, summary, place_holder, list_classes, figsize=(9, 9)): """ 绘制混淆矩阵并返回为TF摘要 :param matrix: 混淆矩阵(N x N) :param filename: 文件名 :param list_classes: 类别列表(N) :param figsize: Pyplot图形大小 :return: / """ fig = get_figure(figsize=(9, 9)) df = pd.DataFrame(confusion_matrix, index=list_classes, columns=list_classes) ax = sns.heatmap(df, annot=True, fmt='.0%') # 你想要的任何装饰: plt.title('混淆矩阵') plt.xticks(rotation=90) plt.yticks(rotation=0) image_sum = figure_to_summary(fig, summary, place_holder) return image_sum
3. 定义你的评估操作和准备占位符
# Inspired by Jerod's answer on SO (https://stackoverflow.com/a/42857070/624547) def add_evaluation_step(result_tensor, ground_truth_tensor, num_classes, confusion_matrix_figsize=(9, 9)): """ 设置评估操作,计算运行准确率和混淆图像 :param result_tensor: 输出张量 :param ground_truth_tensor: 目标类别张量 :param num_classes: 类别数量 :param confusion_matrix_figsize: 混淆图像的Pyplot图形大小 :return: TF操作、摘要和占位符(见下面的使用) """ scope = "evaluation" with tf.name_scope(scope): predictions = tf.argmax(result_tensor, 1, name="prediction") # 流式准确率(查找和更新张量): accuracy, accuracy_update = tf.metrics.accuracy(ground_truth_tensor, predictions, name='accuracy') # 每批次的混淆矩阵: batch_confusion = tf.confusion_matrix(ground_truth_tensor, predictions, num_classes=num_classes, name='batch_confusion') # 聚合混淆矩阵: confusion_matrix = tf.Variable(tf.zeros([num_classes, num_classes], dtype=tf.int32), name='confusion') confusion_update = confusion_matrix.assign(confusion_matrix + batch_confusion) # 我们假设每个批次包含一个完整的类别,直接按其大小进行归一化: evaluate_streaming_metrics_op = tf.group(accuracy_update, confusion_update) # 从矩阵生成混淆图像(需要扩展维度并转换为float,以便tf.summary.image重新归一化为[0,255]): confusion_image = tf.reshape(tf.cast(confusion_update, tf.float32), [1, num_classes, num_classes, 1]) # 摘要: tf.summary.scalar('accuracy', accuracy, collections=[scope]) summary_op = tf.summary.merge_all(scope) # 为混淆图像准备占位符(以便我们可以将绘制的图像传递给它): # (我们基本上预分配一个绘图图形,并将其RGB数组传递给占位符) confusion_image_placeholder = tf.placeholder(tf.uint8, fig_to_rgb_array(get_figure(figsize=confusion_matrix_figsize)).shape) confusion_image_summary = tf.summary.image('confusion_image', confusion_image_placeholder) # 隔离度量操作存储的所有变量: running_vars = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope=scope) running_vars += tf.get_collection(tf.GraphKeys.LOCAL_VARIABLES, scope=scope) # 初始化操作以启动/重置运行变量 reset_streaming_metrics_op = tf.variables_initializer(var_list=running_vars) return evaluate_streaming_metrics_op, reset_streaming_metrics_op, summary_op, confusion_image_summary, \ confusion_image_placeholder, confusion_image
4. 将所有内容整合在一起
一个快速示例,展示如何使用这些内容,尽管需要根据你的训练过程等进行调整。
classes = ["obj1", "obj2", "obj3"]num_classes = len(classes)model = your_network(...)evaluate_streaming_metrics_op, reset_streaming_metrics_op, summary_op,confusion_image_summary, confusion_image_placeholder, confusion_image = \add_evaluation_step(model.output, model.target, num_classes)def evaluate(session, model, eval_data_gen): """ 评估模型 :param session: TF会话 :param eval_data_gen: 用于评估的数据 :return: Tensorboard的评估摘要 """ # 重置流式变量: session.run(reset_streaming_metrics_op) # 在完整的评估数据集上评估运行操作,例如: for batch in eval_data_gen: feed_dict = {model.inputs: batch} session.run(evaluate_streaming_metrics_op, feed_dict=feed_dict) # 获取最终结果: summary_str, confusion_results = session.run([summary_op, confusion_image]) # 将混淆数据转换为绘图并生成摘要: confusion_img_str = confusion_matrix_to_image_summary( confusion_results[0,:,:,0], confusion_image_summary, confusion_image_placeholder, classes) summary_str += confusion_img_str return summary_str # 传递给SummaryWriter