Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Logging to tensorboard without tensorflow operations. Uses manually generated summaries instead of summary ops
"""Simple example on how to log scalars and images to tensorboard without tensor ops.
License: BSD License 2.0
"""
__author__ = "Michael Gygli"
import tensorflow as tf
from StringIO import StringIO
import matplotlib.pyplot as plt
import numpy as np
class Logger(object):
"""Logging in tensorboard without tensorflow ops."""
def __init__(self, log_dir):
"""Creates a summary writer logging to log_dir."""
self.writer = tf.summary.FileWriter(log_dir)
def log_scalar(self, tag, value, step):
"""Log a scalar variable.
Parameter
----------
tag : basestring
Name of the scalar
value
step : int
training iteration
"""
summary = tf.Summary(value=[tf.Summary.Value(tag=tag,
simple_value=value)])
self.writer.add_summary(summary, step)
def log_images(self, tag, images, step):
"""Logs a list of images."""
im_summaries = []
for nr, img in enumerate(images):
# Write the image to a string
s = StringIO()
plt.imsave(s, img, format='png')
# Create an Image object
img_sum = tf.Summary.Image(encoded_image_string=s.getvalue(),
height=img.shape[0],
width=img.shape[1])
# Create a Summary value
im_summaries.append(tf.Summary.Value(tag='%s/%d' % (tag, nr),
image=img_sum))
# Create and write Summary
summary = tf.Summary(value=im_summaries)
self.writer.add_summary(summary, step)
def log_histogram(self, tag, values, step, bins=1000):
"""Logs the histogram of a list/vector of values."""
# Convert to a numpy array
values = np.array(values)
# Create histogram using numpy
counts, bin_edges = np.histogram(values, bins=bins)
# Fill fields of histogram proto
hist = tf.HistogramProto()
hist.min = float(np.min(values))
hist.max = float(np.max(values))
hist.num = int(np.prod(values.shape))
hist.sum = float(np.sum(values))
hist.sum_squares = float(np.sum(values**2))
# Requires equal number as bins, where the first goes from -DBL_MAX to bin_edges[1]
# See https://github.com/tensorflow/tensorflow/blob/master/tensorflow/core/framework/summary.proto#L30
# Thus, we drop the start of the first bin
bin_edges = bin_edges[1:]
# Add bin edges and counts
for edge in bin_edges:
hist.bucket_limit.append(edge)
for c in counts:
hist.bucket.append(c)
# Create and write Summary
summary = tf.Summary(value=[tf.Summary.Value(tag=tag, histo=hist)])
self.writer.add_summary(summary, step)
self.writer.flush()
@gyglim

This comment has been minimized.

Copy link
Owner Author

gyglim commented Jan 4, 2017

Example usage:

    import numpy as np
    logger = Logger('/tmp/test')
    for i in range(1000):
        l.log_histogram('test_hist',np.random.rand(50)*(i+1),i)

Then simpy run tensorboard:

    tensorboard --logdir /tmp/test

Gives the following histogram on tensorboard (and the corresponding distribution)
image

@MadcowD

This comment has been minimized.

Copy link

MadcowD commented Jan 11, 2017

This is great!

@el3ment

This comment has been minimized.

Copy link

el3ment commented May 20, 2017

Any chance you can add a function for text?

@nasimrahaman

This comment has been minimized.

Copy link

nasimrahaman commented Jun 27, 2017

Could you include a license?

@MiguelMonteiro

This comment has been minimized.

Copy link

MiguelMonteiro commented Jul 18, 2017

Thanks or the code it works great, found a small bug though...
If values is a list in log_histogram then because list has no attribute shape the program crashes you should write values=np.array(values) in the beginning of the function to avoid these issue.

@gyglim

This comment has been minimized.

Copy link
Owner Author

gyglim commented Oct 3, 2017

@nasimrahaman: Added copyleft
@MiguelMonteiro fixed

@Yikhan

This comment has been minimized.

Copy link

Yikhan commented Oct 27, 2017

Thank you for such a helpful tool ! I've been confused about how to write what I want into tensorboard

@dc0d32

This comment has been minimized.

Copy link

dc0d32 commented Dec 21, 2017

Thanks!

@adizhol

This comment has been minimized.

Copy link

adizhol commented Apr 3, 2018

            s = StringIO()
            plt.imsave(s, img, format='png')

doesn't work because pyplot.imsave() expects a file path

@gyglim

This comment has been minimized.

Copy link
Owner Author

gyglim commented Apr 12, 2018

doesn't work because pyplot.imsave() expects a file path

That's not true, at least for more recent versions, where it can be a "file-like" object, see:
https://matplotlib.org/api/_as_gen/matplotlib.pyplot.imsave.html

@adizhol: Maybe your version is outdated?

@yongjun823

This comment has been minimized.

Copy link

yongjun823 commented Apr 13, 2018

Thanks!

@yongzhengqi

This comment has been minimized.

Copy link

yongzhengqi commented Jul 26, 2018

It works, thx!

@kukuruza

This comment has been minimized.

Copy link

kukuruza commented Aug 3, 2018

Great code, thanks

@raytroop

This comment has been minimized.

Copy link

raytroop commented Sep 12, 2018

excellent work, and I have to use BytesIO instead of StringIO for python 3.5.5, matplotlib 2.2.2

@gavr97

This comment has been minimized.

Copy link

gavr97 commented Oct 10, 2018

Cool! Thanks

@gavr97

This comment has been minimized.

Copy link

gavr97 commented Oct 11, 2018

@gyglim Maybe it is worth to add flush method? I think for newcomers to tensorboard it would be a good hint that they should consider flushing.

@jensdebruijn

This comment has been minimized.

Copy link

jensdebruijn commented Jan 29, 2019

Thanks a lot, perfect!

@kvanhoey

This comment has been minimized.

Copy link

kvanhoey commented Mar 12, 2019

Thanks a lot Michael, this helped me today :).
BTW: I had to use a Bytes-like object (BytesIO) instead of a StringIO for it to work (TF 1.13, Matplotlib 3.0.3).

Cheers !

@cottrell

This comment has been minimized.

Copy link

cottrell commented Mar 18, 2019

Are you sure this works for multiple scalars? Is flush needed? I see points showing up in tboard but they do not seem to update often enough?

@cottrell

This comment has been minimized.

Copy link

cottrell commented Mar 19, 2019

Also anyone know what to put in a step to get the scalars to look similar to the keras callback scalars?

@shawnthu

This comment has been minimized.

Copy link

shawnthu commented Apr 3, 2019

text summary can be a new feature

@shawnthu

This comment has been minimized.

Copy link

shawnthu commented Apr 3, 2019

Anyone knows how to construct text summary?

@beanmilk

This comment has been minimized.

Copy link

beanmilk commented May 27, 2019

What does 'License: Copyleft' mean?
Can you provide more detailed license information, such as GPL, LGPL or MPL?

Thanks!!

@gyglim

This comment has been minimized.

Copy link
Owner Author

gyglim commented Jul 22, 2019

Added BSD License 2.0

@beanmilk

This comment has been minimized.

Copy link

beanmilk commented Jul 23, 2019

@gyglim Thanks!! :)

@xrz000

This comment has been minimized.

Copy link

xrz000 commented Aug 28, 2019

To add text summary

from tensorboard.plugins.text import metadata

class Logger(object):
    """Logging in tensorboard without tensorflow ops."""

    def __init__(self, log_dir):
        """Creates a summary writer logging to log_dir."""
        self.writer = tf.summary.FileWriter(log_dir)

	def log_text(self, tag, value, step):
	        """Log string or 2D string tables. """
	        summary_metadata = metadata.create_summary_metadata(
	                display_name="text",
	                description="Text Summary")
	        summary_metadata = tf.SummaryMetadata.FromString(
	                summary_metadata.SerializeToString())
	        tensor = tf.make_tensor_proto(value, dtype=tf.string)
	        summary = tf.Summary(value=[tf.Summary.Value(
	            tag=tag,
	            metadata=summary_metadata,
	            tensor=tensor
	            )])
	        self.writer.add_summary(summary, step)
	        self.writer.flush()

Example usage:

logger = Logger('/tmp/test')
logger.log_text(tag="string", value="test", step=0)
logger.log_text(tag="table", value=[["r0c0", "r0c1"], ["r1c0", "r1c1"]], step=0)

Tensorboard:
text

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.