如何在 Tensorboard 中加载选定范围的样本

How to load selected range of samples in Tensorboard

我有一个包含 500 万个样本的 Tensorboard 日志文件。 Tensorboard 在加载时对其进行降采样,这样我就不会 运行 内存不足,但可以使用 --samples_per_plugin 覆盖此行为并加载所有这些行为。如果我这样做,我将 运行 内存不足。假设我想加载 first 1000 个样本 而无需下采样 (例如,如果我对开始时我的网络发生的事情的详细信息感兴趣的培训)。

有没有办法让 Tensorboard 仅加载指定的样本子集?我认为截至目前还没有命令行参数,但也许有办法编辑日志文件或 Tensorboard 代码或其他一些解决方法?

我认为没有任何方法可以让 TensorBoard 做到这一点,但可以 "slice" 事件文件。这些文件原来是记录文件(只有事件数据而不是示例),因此您可以将它们阅读为TFRecordDataset。显然,有第一条记录指示文件版本号,但除此之外它应该是直截了当的。假设你只有你想要切片的事件,你可以使用这样的函数(TF 1.x,尽管它在 2.x 中大致相同):

import tensorflow as tf

def slice_events(input_path, output_path, skip, take):
    with tf.Graph().as_default():
        ds = tf.data.TFRecordDataset([str(input_path)])
        rec_first = ds.take(1).make_one_shot_iterator().get_next()
        ds_data = ds.skip(skip + 1).take(take)
        rec_data = ds_data.batch(1000).make_one_shot_iterator().get_next()
        with tf.io.TFRecordWriter(str(output_path)) as writer, tf.Session() as sess:
            writer.write(sess.run(rec_first))
            while True:
                try:
                    for ev in sess.run(rec_data):
                        writer.write(ev)
                except tf.errors.OutOfRangeError: break

这会根据现有文件创建一个新的事件文件,其中第一个 skip 个事件被丢弃,然后 take 个事件被保存。您可以使用其他 Dataset 操作来选择要保留的数据。例如,下采样可以这样完成:

ds_data = ds.skip(1).window(1, 5).unbatch()  # Takes one in five events

你可以制作一个脚本,把一个目录下的所有事件文件切片,然后保存到另一个具有相同结构的文件中,例如:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# slice_events.py

import sys
import os
from pathlib import Path
os.environ['CUDA_VISIBLE_DEVICES'] = '-1'  # Not necessary to use GPU
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'  # Avoid log messages

def slice_events(input_path, output_path, skip, take):
    # Import here to avoid loading on error
    import tensorflow as tf
    # Code from before...

def slice_events_dir(input_dir, output_dir, skip, take):
    input_dir = Path(input_dir)
    output_dir = Path(output_dir)
    output_dir.mkdir(parents=True, exist_ok=True)
    for ev_file in input_dir.glob('**/*.tfevents*'):
        out_file = Path(output_dir, ev_file.relative_to(input_dir))
        out_file.parent.mkdir(parents=True, exist_ok=True)
        slice_events(ev_file, out_file, skip, take)

if __name__ == '__main__':
    if len(sys.argv) != 5:
        print(f'{sys.argv[0]} <input dir> <output dir> <skip> <take>', file=sys.stderr)
        sys.exit(1)
    input_dir, output_dir, skip, take = sys.argv[1:]
    skip = int(skip)
    take = int(take)
    slice_events_dir(input_dir, output_dir, skip, take)

然后你会用它作为

$ python slice_events.py log log_sliced 100 1000

请注意,这假设了一个简单的情况,即您只有一系列类似的事件需要切片。如果您有其他类型的事件(例如图形本身),或者同一文件中有多种类型的交错事件,或者其他东西,那么您需要根据需要调整逻辑。