TensorFlow - 从 TensorBoard TFEvent 文件中导入数据?

Posted

技术标签:

【中文标题】TensorFlow - 从 TensorBoard TFEvent 文件中导入数据?【英文标题】:TensorFlow - Importing data from a TensorBoard TFEvent file? 【发布时间】:2016-09-15 05:25:59 【问题描述】:

我已经在 TensorFlow 中使用不同的图表进行了多次培训。我设置的摘要在训练和验证中显示了有趣的结果。现在,我想将我保存在摘要日志中的数据进行一些统计分析,并以不同的方式绘制和查看摘要数据。是否有任何现有方法可以轻松访问这些数据?

更具体地说,是否有任何内置方法可以将 TFEvent 记录读回 Python?

如果没有简单的方法可以做到这一点,TensorFlow states that all its file formats are protobuf files。根据我对 protobufs(这是有限的)的理解,如果我有 TFEvent 协议规范,我想我可以提取这些数据。有没有简单的方法来掌握这个?非常感谢。

【问题讨论】:

【参考方案1】:

你可以简单地使用:

tensorboard --inspect --event_file=myevents.out

或者如果您想过滤图表的特定事件子集:

tensorboard --inspect --event_file=myevents.out --tag=loss

如果你想创建更自定义的东西,你可以深入研究

/tensorflow/python/summary/event_file_inspector.py 

了解如何解析事件文件。

【讨论】:

这适用于哪个版本的 TensorFlow?我正在使用0.8。对我来说,--logdir 始终是必需的,尽管传递了这些其他参数,但 TensorBoard 似乎只是照常运行而忽略了这些参数。此外,--help 不显示这些参数中的任何一个。另外,为了确保我没有遗漏任何东西,这是否假设要在终端屏幕上打印一些东西?或者更改 TensorBoard 页面上显示的内容?或者是其他东西?谢谢! 沿着这条线索走得更远一点,我找到了EventAccumulator 类。在加载文件时可以提供汇总值的所有详细信息。我会更详细地更新您的答案。 这些参数确实在 tensorflow tip 中可用。【参考方案2】:

作为 Fabrizio says,TensorBoard 是可视化摘要日志内容的绝佳工具。但是,如果要执行自定义分析,可以使用tf.train.summary_iterator() 函数循环遍历日志中的所有tf.Eventtf.Summary 协议缓冲区:

for summary in tf.train.summary_iterator("/path/to/log/file"):
    # Perform custom processing in here.

tf2 更新:

from tensorflow.python.summary.summary_iterator import summary_iterator

您需要导入它,默认情况下当前未导入该模块级别。在 2.0.0-rc2 上

【讨论】:

这个地方有一些不错的辅助函数programtalk.com/python-examples/… TensorFlow 1.8+ 中没有tf.train.summary_iterator。现在似乎更改为tf.python.summary.summary_iterator 在 tf2 中找不到摘要迭代器 时间已经过去,现在可以在tf.compat.v1.train 下找到summary_iterator。此外,Tensorboard 包为那些不想依赖 Tensorflow 的人提供了 tensorboard.backend.event_processing 模块。详情见this answer【参考方案3】:

您可以使用脚本serialize_tensorboard,它将接受一个logdir并以json格式写出所有数据。

您还可以使用EventAccumulator 来获得方便的 Python API(这与 TensorBoard 使用的 API 相同)。

【讨论】:

从 Tensorboard 1.1 版开始,serialize_tensorboard 脚本不再可用。【参考方案4】:

要读取 TFEvent,您可以获得一个 Python 迭代器,它会产生事件协议缓冲区。

# This example supposes that the events file contains summaries with a
# summary value tag 'loss'.  These could have been added by calling
# `add_summary()`, passing the output of a scalar summary op created with
# with: `tf.scalar_summary(['loss'], loss_tensor)`.
for e in tf.train.summary_iterator(path_to_events_file):
    for v in e.summary.value:
        if v.tag == 'loss' or v.tag == 'accuracy':
            print(v.simple_value)

更多信息:summary_iterator

【讨论】:

提防simple_value。至少在我的情况下,它总是报告0.0。可以使用github.com/tensorflow/tensorboard/issues/… 提取实际值【参考方案5】:

这是一个从标量获取值的完整示例。可以查看Event protobuf消息here的消息规范

import tensorflow as tf


for event in tf.train.summary_iterator('runs/easy_name/events.out.tfevents.1521590363.DESKTOP-43A62TM'):
    for value in event.summary.value:
        print(value.tag)
        if value.HasField('simple_value'):
            print(value.simple_value)

【讨论】:

【参考方案6】:

我一直在用这个。它假定您只想查看多次记录的标签,这些标签的值是浮动的,并将结果作为pd.DataFrame 返回。只需致电metrics_df = parse_events_file(path)

from collections import defaultdict
import pandas as pd
import tensorflow as tf

def is_interesting_tag(tag):
    if 'val' in tag or 'train' in tag:
        return True
    else:
        return False


def parse_events_file(path: str) -> pd.DataFrame:
    metrics = defaultdict(list)
    for e in tf.train.summary_iterator(path):
        for v in e.summary.value:

            if isinstance(v.simple_value, float) and is_interesting_tag(v.tag):
                metrics[v.tag].append(v.simple_value)
            if v.tag == 'loss' or v.tag == 'accuracy':
                print(v.simple_value)
    metrics_df = pd.DataFrame(k: v for k,v in metrics.items() if len(v) > 1)
    return metrics_df

【讨论】:

【参考方案7】:

以下作品截至 tensorflow 版本2.0.0-beta1

import os

import tensorflow as tf
from tensorflow.python.framework import tensor_util

summary_dir = 'tmp/summaries'
summary_writer = tf.summary.create_file_writer('tmp/summaries')

with summary_writer.as_default():
  tf.summary.scalar('loss', 0.1, step=42)
  tf.summary.scalar('loss', 0.2, step=43)
  tf.summary.scalar('loss', 0.3, step=44)
  tf.summary.scalar('loss', 0.4, step=45)


from tensorflow.core.util import event_pb2
from tensorflow.python.lib.io import tf_record

def my_summary_iterator(path):
    for r in tf_record.tf_record_iterator(path):
        yield event_pb2.Event.FromString(r)

for filename in os.listdir(summary_dir):
    path = os.path.join(summary_dir, filename)
    for event in my_summary_iterator(path):
        for value in event.summary.value:
            t = tensor_util.MakeNdarray(value.tensor)
            print(value.tag, event.step, t, type(t))

my_summary_iterator 的代码是从 tensorflow.python.summary.summary_iterator.py 复制而来的 - 无法在运行时导入它。

【讨论】:

我正在分析由 tensorflow 对象检测 api 生成的 tfevent 文件,因此,仅使用 value.simple_value 总是产生 0,即使在 tensorboard gui 中,也有明显不同的数字。 t = tensor_util.MakeNdarray(value.tensor) 这行似乎对我有用 谢谢你!在 tensorflow 2.4 中,如果它是自定义指标而不是 keras 的默认值,则至少需要 tensor_util.MakeNdarray(value.tensor) 才能访问该值。如果您使用tf.summary.scalar() 编写它,由于某种原因它会被保存为张量而不是标量,并且value.simple_value 总是返回0【参考方案8】:

TensorFlow 和 TensorFlow Datasets 的 2020 年末版本建议采用不同的方法。使用tf.data.TFRecordDatasetevent_pb2

from os import path, listdir
from operator import contains
from functools import partial
from itertools import chain
from json import loads

import numpy as np
import tensorflow as tf
from tensorflow.core.util import event_pb2

# From https://github.com/Suor/funcy/blob/0ee7ae8/funcy/funcs.py#L34-L36
def rpartial(func, *args):
    """Partially applies last arguments."""
    return lambda *a: func(*(a + args))


tensorboard_logdir = "/tmp"


# Or you could just glob… for *tfevents*:
list_dir = lambda p: map(partial(path.join, p), listdir(p))

for event in filter(rpartial(contains, "tfevents"),
                    chain.from_iterable(
                        map(list_dir,
                            chain.from_iterable(
                                map(list_dir,
                                    filter(rpartial(contains, "_epochs_"),
                                           list_dir(tensorboard_logdir))))))):
    print(event)
    for raw_record in tf.data.TFRecordDataset(event):
        for value in event_pb2.Event.FromString(raw_record.numpy()).summary.value:
            print("value: !r ;".format(value))
            if value.tensor.ByteSize():
                t = tf.make_ndarray(value.tensor)
                if hasattr(event, "step"):
                    print(value.tag, event.step, t, type(t))
                elif type(t).__module__ == np.__name__:
                    print("t: !r ;".format(np.vectorize(loads)(t)))
    print()

【讨论】:

【参考方案9】:

读取this post中提到的事件文件有2种原生方式:

    事件累加器

    >>> from tensorboard.backend.event_processing.event_accumulator import EventAccumulator
    >>> event_acc = EventAccumulator(event_file)
    >>> event_acc.Reload() 
    <tensorboard.backend.event_processing.event_accumulator.EventAccumulator object at ...>
    >>> print(event_acc.Tags())
    'images': [], 'audio': [], 'histograms': [], 'scalars': ['y=2x'], 'distributions': [], 'tensors': [], 'graph': False, 'meta_graph': False, 'run_metadata': []
    >>> for e in event_acc.Scalars('y=2x'):
    ...   print(e.step, e.value)
    0 0.0
    1 2.0
    2 4.0
    3 6.0
    4 8.0
    

    总结迭代器

    >>> import tensorflow as tf
    >>> from tensorflow.python.summary.summary_iterator import summary_iterator
    >>> for e in summary_iterator(event_file):
    ...   for v in e.summary.value:
    ...     if v.tag == 'y=2x':
    ...       print(e.step, v.simple_value)
    0 0.0
    1 2.0
    2 4.0
    3 6.0
    4 8.0
    

对于多个事件文件或其他事件类型(例如,直方图),您可以使用tbparse 将事件日志解析为 pandas DataFrame 并在本地进行处理。如果您在解析过程中遇到任何问题,可以打开issue。 (我是tbparse的作者)

注意:只有将事件日志上传到 TensorBoard.dev (source),TensorBoard 才能将事件日志解析为 DataFrame,目前无法离线/本地使用。

【讨论】:

以上是关于TensorFlow - 从 TensorBoard TFEvent 文件中导入数据?的主要内容,如果未能解决你的问题,请参考以下文章

sh 从tensorflow冷冻模型到tensorflow lite

TensorFlow 从入门到精通:tensorflow.nn 详解

面临从 tensorflow core 转换为 tensorflow lite 的问题

如何从 TensorFlow 1.x 迁移到 TensorFlow 2.x

在Ubuntu中从源码编译TensorFlow

从源代码构建TensorFlow流程记录