Skip to main content

tboardfs

CI Coverage Status      Version: 0.3.0 Status: Alpha      License: MIT Python: >=3.12

Mount and inspect TensorBoard event logs as ordinary files.

tboardfs has two access modes:

  • Filesystem mode mounts a log directory with FUSE.
  • Command mode inspects or copies the virtual content of one event file.

Both modes use the same virtual paths for TensorBoard tabs such as scalars, images, tensors, meshes, pr_curves, hparams, and custom_scalars.

Filesystem Mode

Mount a TensorBoard log directory:

tboardfs SOURCE MOUNTPOINT

For non-developers, the simplest way to run it without cloning this repository or managing a local virtual environment is:

uvx tboardfs SOURCE MOUNTPOINT

Example:

tboardfs runs/experiment-1 mnt/tboardfs
ls mnt/tboardfs
cat mnt/tboardfs/train/scalars/loss.json

Mount mode is the primary workflow for browsing full log directories. It exposes run directories and supported sidecars such as projector/profile files.

A run directory inside another run is a directory beside the tabs of that run. When its name is also an entry of that run, such as the run exp/scalars below the run exp, which has the tab scalars, it gets ~2 (then ~3, and so on) and tboardfs logs a warning once. The run exp/scalars is then under /exp/scalars~2/, and /exp/scalars/ has only the scalars of exp. The runs below a renamed directory follow it. A directory that has the name scalars~2 on disk keeps that name; the renamed directory then gets ~3.

Symlinked directories in the source are followed, so a run kept elsewhere and linked into the log directory is a run under the link name. A directory that several links reach is shown once, under the first path in sorted order, and link loops end. Sidecar files of a linked run may resolve inside its real run directory; other links out of the source stay hidden. Do not link to the mountpoint from inside the source: reading the link would call back into the mount and stop it.

Each open file keeps the version it had when it was opened, so reads stay whole while a training run writes new events. A new open shows the new data. Mounted files use direct I/O: shared memory maps (mmap with MAP_SHARED, np.load(..., mmap_mode="r")) fail with ENODEV; private maps (mmap_mode="c") and plain reads work.

--refresh-age-seconds (default 60) sets how old the data can get before the next file operation checks the source again. A check lists each directory once and opens only the event files whose device, inode, size, mtime or ctime changed. Every write changes the ctime, so a rewritten file is read again even when its mtime is set back. Only a rewrite to the same size within one timestamp tick of a filesystem with coarse timestamps is not seen until the next change. On a network filesystem, a larger value makes fewer round trips.

Rendered files are kept in memory, so ls -l followed by cat renders a file once. --cache-size-mb sets the memory for this cache (default 1024; 0 turns it off). When the cache goes over the limit, the least recently used files are dropped until half the limit is left. New events in a run make only the files of that run render again.

Files and directories belong to root (uid and gid 0) by default. --user-owner gives them to the user and group that mount the filesystem; --root-owner is the default. The permissions stay read-only for everyone (0444 files, 0555 directories).

--scalar-format selects the scalar and histogram table formats, as a comma-separated list of json, tsv, csv, and npz (default json,tsv,npz). --step-digits sets the zero-padding width of step file names, from 1 to 20 (default 6). --loglevel takes a loguru level name in any case. Both commands refuse other values with a usage error.

A resumed run hides the rows it replaces, as TensorBoard does. When a writer marks a restart at step S (a SessionLog.START event, for example from PyTorch SummaryWriter(purge_step=S)), rows written before it with step S or higher are not shown. Graphs stay. This applies to event files with file version 2 or later, which all current writers produce.

Command Mode

Use tboardfs-file when mounting is unavailable or when you need scripted access to TensorBoard event files.

List every virtual file:

tboardfs-file list events.out.tfevents.123

List files below a virtual path:

tboardfs-file list events.out.tfevents.123 /meshes

Extract one virtual file to stdout:

tboardfs-file get events.out.tfevents.123 /scalars/loss.json -o -

Extract one virtual file to disk:

tboardfs-file get events.out.tfevents.123 /images/sample/000001.png -o sample.png

The virtual path may be written with or without the leading /. If -o points to an existing directory, or to a missing path ending in /, get writes the virtual file basename inside that directory.

tboardfs-file get events.out.tfevents.123 scalars/loss.json -o exported/

Copy the full virtual tree:

tboardfs-file copy-all events.out.tfevents.123 exported-event

For one event file, command mode exposes tab directories directly at the root, for example /scalars, /images, and /meshes, without sibling sidecars. SOURCE can also be a run directory or a log directory. Then the commands show the same tree as a mount of that directory: a run directory has its tabs at the root, a log directory has one directory per run, and both include sidecars.

get refuses to overwrite existing files unless --force is provided. copy-all copies files in deterministic virtual-path order. If it reaches an existing target without --force, it stops, reports how many files were already copied, lists those virtual paths, prints the conflicting output path, and suggests --force. After a successful copy, copy-all reports the number of copied files.

Use --skip-existing to leave existing output files untouched and continue copying the rest of the tree:

tboardfs-file copy-all events.out.tfevents.123 exported-event --skip-existing

Each skipped virtual path is reported as a warning on stderr. --force and --skip-existing are mutually exclusive.

Supported Objects

A tag is a path below its tab, so train/loss is /scalars/train/loss.json. Empty parts of a tag are left out, and a tag without a name is untagged. When two tags of a run get the same path, such as a/b and a//b, the tag that the path spells keeps it. The other tag gets ~2 (then ~3, and so on) on its last part in every tab, and tboardfs logs a warning once. A tag directory can also have the name of a file, such as the tag a/000001.npy beside the step file 000001.npy of the tag a, or the tag loss.json/x beside /scalars/loss.json. Then the directory gets ~2 in every tab, such as /tensors/a/000001.npy~2/, and the file keeps its name. When two files without a tag meet at one path, such as two profile sidecars a and a/c, the first file stays, and tboardfs logs a warning.

The virtual tree covers these TensorBoard objects:

  • Scalars: full-series json, tsv, and npz exports under /scalars. The epoch column of scalar and histogram tables is the epoch scalar written at the same step, as PyTorch Lightning writes it. A step without an epoch scalar has the last epoch written before it.
  • Custom scalars: layout JSON under /custom_scalars.
  • Images: encoded image files under /images. A TensorFlow 2 image summary with more than one image gives one file per image, <step>_<i>, such as 000001_0.png.
  • Audio: encoded audio files under /audio, with the same <step>_<i> names for more than one clip.
  • Videos: encoded video/GIF outputs under /videos, including raw subpaths when present.
  • Histograms: per-step json, tsv, and npz exports under /histograms. TensorFlow 1 and TensorFlow 2 histogram summaries give the same tables. As in TensorBoard, a TensorFlow 1 histogram runs from its minimum to its maximum, without the empty buckets at its two ends, and a histogram of no values has no step file.
  • Distributions: per-step distribution tables under /distributions, with the values that the TensorBoard Distributions tab shows. The percentile column has 9 values: 0, 6.68, 15.87, 30.85, 50, 69.15, 84.13, 93.32 and 100, which are the mean and ±1, 2 and 3 standard deviations of a normal distribution. Each value interpolates linearly inside its histogram bucket.
  • Text summaries: UTF-8 text files under /text. A summary with one string is that text. A summary with many strings is a Markdown table, as TensorBoard shows it: a vector is one column, and a tensor with more than 2 dimensions shows its first 2-D slice after a warning. A .json file next to the table keeps the shape and the exact strings.
  • Meshes: per-step json, npz, and Wavefront obj exports under /meshes. The OBJ file has one object (o mesh_<i>) per batch element when the batch has more than one mesh. Vertex colors follow the coordinates as r g b values in [0, 1], which MeshLab and Blender read. A mesh without faces is an OBJ point cloud. The ply file is a binary PLY mesh, which keeps the coordinates exactly: float32 coordinates as float, other numbers as double, and colors as uchar red green blue. A point cloud has no face element. A batch is one PLY mesh, with the faces of a later element offset by the vertices before it, and a comment mesh_<i> vertices <start> <count> line per element. Faces that are not vertex indices, and colors that are not whole numbers from 0 to 255, are not in the PLY file; the npz file keeps them. The path of a mesh is its tag without the _VERTEX, _FACE or _COLOR suffix, so train/cloud_VERTEX is under /meshes/train/cloud. A tag without that suffix uses the mesh name, which the json file keeps. This is different from TensorBoard, which groups meshes by the mesh name only and thus mixes train/cloud and val/cloud.
  • PR curves: per-step json, tsv, and npy exports under /pr_curves. The tables have one row per threshold, with the columns threshold, true_positives, false_positives, true_negatives, false_negatives, precision, and recall. The thresholds are evenly spaced in [0, 1], as in TensorBoard. The .npy file keeps the raw [6, N] tensor. A tensor of another shape keeps generic value_<i> columns.
  • HParams: merged experiment/session/metric JSON under /hparams. The metrics are the declared metric tags, or all scalar tags when the run declares no experiment, as in TensorBoard. Each metric has its last value, or null without data. Metrics in a sub-run group (for example Keras validation) have no value here; read them from the scalars of that run. sessions lists every session of the run; session_start and session_end are the first ones, as in TensorBoard. The hparams.yaml file that PyTorch Lightning writes in the run directory is also in /hparams.
  • Tensors: tensor arrays as npy plus compact JSON or native blob files under /tensors. Every numeric TensorFlow dtype that NumPy has keeps its dtype, including float16, int8, int16, uint16 and complex. NumPy has no bfloat16, so bfloat16 tensors are widened to float32; this is exact. Float8 and 4-bit tensors are not decoded. String tensors are NumPy text arrays (dtype U), so np.load reads them without allow_pickle. A numeric tensor written without a plugin name is also a tensor here. A tensor with one value is a scalar instead. A tensor of 1 KiB or more also has its raw bytes as a native blob file, unless its plugin has its own tab: a large histogram, PR curve, mesh or text summary is only in that tab.
  • Graphs: graph protobuf files under /graphs. graph.pb is the graph that TensorBoard shows: the newest graph that the event files hold as a graph_def, which TensorFlow 1 and PyTorch add_graph write, or without one, the graph of the newest TensorFlow 1 meta graph. A run with several graph_def graphs also has graph_<i>.pb for each one, in write order. meta_graph.pb is the newest TensorFlow 1 MetaGraphDef, with meta_graph_<i>.pb in the same way. A TensorFlow 2 graph summary is in /graphs/<tag>. The Keras model config that the Keras TensorBoard callback writes is <step>.json, and the RunMetadata of tf.summary.trace_export is <step>.run_metadata.pb. Next to each one, <step>.conceptual.pb or <step>.pb is the GraphDef that the TensorBoard Graphs tab shows for it. A TensorFlow 1 tagged RunMetadata, which FileWriter.add_run_metadata and PyTorch add_graph write, is also /graphs/<tag>/<step>.run_metadata.pb. Next to each RunMetadata, <step>.run_metadata.pbtxt is the profile text that the Graphs tab shows for it. TensorBoard 2.21 cannot draw a functional model inside a Sequential model from a Keras 3 config, because it reads the one input of the nested model as three inputs; tboardfs draws it with that one input. A malformed summary, RunMetadata or meta graph has no converted file (GraphDef, profile text or graph.pb); tboardfs logs a warning for it once, when it reads the event. Its native file stays.
  • Projector and profile sidecars: available in filesystem mode, and in command mode for a directory, under /projector and /profile; command mode for one event file omits sibling sidecar files. The embedding files that projector_config.pbtxt names (tensor_path, metadata_path, sprite image_path, bookmarks_path), such as the <step>/<tag>/tensors.tsv files of PyTorch and tensorboardX add_embedding, are under /projector at the same relative paths. Only relative paths to files of the run are followed, and only the first MiB of the config is read.
  • Other plugin JSON payloads: exposed under /plugins when no typed tab handles them.

A record that tboardfs cannot convert has no file. Such records are an hparams or mesh record whose plugin content does not decode, a custom scalar summary whose tensor has no layout that decodes, and the malformed graph data above. tboardfs logs one warning for each, when it reads the event. The other values of the same event stay. A native file, which holds the stored bytes, always stays.

Output Rules

All .json files are strict JSON (RFC 8259). Infinities are written as the strings "Infinity" and "-Infinity". In scalar, histogram and other table files, NaN is a missing value and is written as null. In other JSON files, NaN is written as the string "NaN", as in protobuf JSON. A complex number is written as its [real, imag] pair. Bytes that are valid UTF-8 are written as text. Other bytes are written as {"base64": "..."}.

An event without a step field is at step 0, as in TensorBoard: writers leave out step 0.

tboardfs-file list prints virtual file paths to stdout, one per line. tboardfs-file get -o - writes raw bytes to stdout. Extraction status, warnings, errors, copied-file counts, skipped-path warnings, copied-path conflict reports, and overwrite hints are written to stderr through Loguru/Click so stdout remains safe for pipelines.

License

MIT

Star History

Star History Chart

Metadata

Release files for tboardfs 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for tboardfs 0.3.0
File Size Uploaded Provenance Actions
tboardfs-0.3.0.tar.gz 84.9 kB Without provenance Details for tboardfs-0.3.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for tboardfs 0.3.0
File Interpreter ABI Platform Actions
tboardfs-0.3.0-py3-none-any.whl Python 3 none any Details for tboardfs-0.3.0-py3-none-any.whl

Total release size: 190.8 kB

Release files / tboardfs-0.3.0.tar.gz

Download URL tboardfs-0.3.0.tar.gz
Size 84.9 kB
Tags Source
SHA-256 checksum
How to use checksums
35fb18bd95ac65adba76cabc3b8ca27865008111ca59c628f6b80e209e5539b1
BLAKE2b-256 checksum
How to use checksums
5ac7da773500a9991b26e31fd4e9e183b47de816cb085b37bad1b532b6d42e7f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.10

Release files / tboardfs-0.3.0-py3-none-any.whl

Download URL tboardfs-0.3.0-py3-none-any.whl
Size 105.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6178e013dd615c7c77780bde35a9faea2c5b42606868a4fa8da07ad8510fb0f2
BLAKE2b-256 checksum
How to use checksums
0f6790c8c7773b26e0609fae83701bbb6879eb1b5ba200feaf4fe5be71c99565
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.10

Security for tboardfs 0.3.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page