Last active
June 28, 2019 10:12
-
-
Save henryzord/010436b43b5889aced40db88666a832a to your computer and use it in GitHub Desktop.
A snippet for demonstrating how to log metadata with tensorboard, even if you don't use deep learning models.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Code for demonstrating how to log metadata with tensorflow and tensorboard. | |
To install required libraries, run the following command in conda, or the equivalent in pip: | |
conda install matplotlib==2.2.3 numpy==1.16.1 tensorflow==1.13.1 tensorboard==1.13.1 psutil==5.6.2 | |
""" | |
import argparse | |
import os | |
import signal | |
import subprocess | |
import webbrowser | |
import numpy as np | |
import psutil | |
import tensorflow as tf | |
from datetime import datetime as dt | |
import time | |
# since viridis is created dynamically, this line will always throw an error when read in an IDE | |
from matplotlib.cm import viridis | |
class TfLogger(object): | |
def __init__(self, logdir_path, open_browser=False): | |
""" | |
:param logdir_path: Path in which run paths will be created. | |
Each run path has metadata regarding one run. | |
:param open_browser: Whether to open a new browser tab to monitor Tensorboard. | |
""" | |
now = dt.now() | |
if not os.path.isabs(logdir_path): | |
this_path = os.path.join(os.getcwd(), logdir_path, now.strftime('%d-%m-%Y-%H:%M:%S')) | |
else: | |
this_path = os.path.join(logdir_path, now.strftime('%d-%m-%Y-%H:%M:%S')) | |
os.mkdir(this_path) | |
self.this_path = this_path | |
# initializes summary writer | |
self.summary_writer = tf.summary.FileWriter(self.this_path) | |
# this doesn't need to be GPU intensive | |
gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction=0.1) | |
# initializes new tensorflow session | |
self.tf_session = tf.Session(config=tf.ConfigProto(gpu_options=gpu_options)) | |
self.some_placeholder = tf.placeholder(tf.float32, shape=[None]) # type: tf.Tensor | |
self.some_histogram = tf.summary.histogram('fitness', self.some_placeholder) # type: tf.Tensor | |
self.summaries = tf.summary.merge_all() | |
if open_browser: | |
self.__tensorboard_start__() | |
def __tensorboard_start__(self): | |
""" | |
1. Checks if tensorboard is already running; | |
1.1 Kill the process, if so; | |
2. Re-starts tensorboard, now watching the path for the current run; | |
3. Opens a new browser tab for monitoring this run. | |
""" | |
pid = self.__find_process_pid_by_name__('tensorboard') | |
if pid is not None: | |
os.kill(pid, signal.SIGKILL) | |
p = subprocess.Popen( | |
["tensorboard", "--logdir", self.this_path, "--port", "default"], | |
stdout=subprocess.PIPE, stderr=subprocess.STDOUT | |
) | |
time.sleep(1) | |
webbrowser.open_new_tab("http://localhost:6006") | |
@staticmethod | |
def __find_process_pid_by_name__(process_name): | |
""" | |
Returns PID of process if it is alive and running, otherwise returns None. | |
Adapted from https://thispointer.com/python-check-if-a-process-is-running-by-name-and-find-its-process-id-pid/ | |
""" | |
# Iterate over the all the running process | |
for proc in psutil.process_iter(): | |
try: | |
pinfo = proc.as_dict(attrs=['pid', 'name']) | |
# Check if process name contains the given name string. | |
if process_name.lower() == pinfo['name'].lower(): | |
return pinfo['pid'] | |
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess): | |
pass | |
return None | |
def log_scalar(self, tag, value, step): | |
""" | |
Logs a scalar variable. | |
:param tag: The name of the scalar. Must be consistent throughout the live of the algorithm. | |
:type tag: str | |
:param value: Current value of the scalar. | |
:type value: np.float32 | |
:param step: Current step being recorded. | |
:type step: int | |
""" | |
summary = tf.Summary(value=[tf.Summary.Value(tag=tag, simple_value=value)]) | |
self.summary_writer.add_summary(summary, step) | |
def log_histogram(self, values, step, placeholder, histogram): | |
""" | |
:param values: An array of values that will be transformed into a histogram. | |
:type values: numpy.ndarray | |
:param step: Current step being recorded. | |
:type step: int | |
:param placeholder: Whete to store the values. | |
:type placeholder: tensorflow.Tensor | |
:param histogram: Histogram object. | |
:type histogram: tensorflow.Tensor | |
""" | |
summary = self.tf_session.run( | |
histogram, feed_dict={placeholder: values.astype(placeholder.dtype.as_numpy_dtype)} | |
) | |
self.summary_writer.add_summary(summary, step) | |
self.summary_writer.flush() | |
def log_image(self, tag, matrix, step): | |
""" | |
Given a matrix of values, store it in an image. | |
:param tag: Name of the image. | |
:type tag: str | |
:param matrix: The image, as a numpy array. | |
:type matrix: numpy.ndarray | |
:param step: Current step being recorded. | |
:type step: int | |
""" | |
vals = (viridis(matrix) * 255).round().astype(np.uint8) | |
vals.shape = (1, *vals.shape) | |
# logging probabilities as image | |
img = tf.summary.image(name=tag, tensor=vals) | |
summary = self.tf_session.run(img) | |
self.summary_writer.add_summary(summary, step) | |
self.summary_writer.flush() | |
def main(metadata_path, open_browser): | |
logger = TfLogger(metadata_path, open_browser) | |
n_steps = 100 | |
loc = 0.5 | |
scale = 0.1 | |
factor = loc/n_steps | |
n_samples = 100 | |
all_values = [] | |
for i in range(n_steps): | |
vals = np.random.normal(loc=loc, scale=scale, size=n_samples) | |
loc = loc - factor | |
all_values += [vals] | |
logger.log_scalar(tag='mean', value=loc, step=i) | |
logger.log_histogram( | |
values=np.array(vals), step=i, placeholder=logger.some_placeholder, | |
histogram=logger.some_histogram | |
) | |
time.sleep(1) # naps for 1sec | |
print('step %d' % i) | |
logger.log_image(tag='image', matrix=np.array(all_values), step=i) | |
if __name__ == "__main__": | |
parser = argparse.ArgumentParser( | |
description='Toy script for showing how to log data with Tensorboard.' | |
) | |
parser.add_argument( | |
'--metadata', action='store', required=True, | |
help='Path to folder where Tensorflow metadata will be stored. Must be pre-existent. A new folder will be' | |
' created for each run.' | |
) | |
parser.add_argument( | |
'--open-browser', action='store_true', required=False, default=False, | |
help='Whether to open a new Browser tab to monitor the algorithm, or not. If you don\'t pass this parameter to' | |
' the algorithm, you will have to manually open tensorboard from the command line. The command for doing' | |
' that is:\n' | |
'\ttensorboard --logdir <path>' | |
) | |
args = parser.parse_args() | |
main(metadata_path=args.metadata, open_browser=args.open_browser) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment