From d7ae1742e98240442b88ea7930bd85def709fee8 Mon Sep 17 00:00:00 2001 From: Sayed Hadi Hashemi Date: Fri, 30 Nov 2018 14:04:22 -0600 Subject: [PATCH] Add Monkey Patching Version bump --- README.md | 14 ++++++ docs/conf.py | 5 +- docs/index.rst | 31 +++++++++++++ examples/README.md | 5 ++ examples/monkey_patching-example.py | 46 ++++++++++++++++++ setup.py | 4 +- tftracer/__init__.py | 4 +- tftracer/monkey_patching.py | 72 +++++++++++++++++++++++++++++ tftracer/tracing_server.py | 3 +- tftracer/version.py | 6 +++ 10 files changed, 183 insertions(+), 7 deletions(-) create mode 100644 examples/monkey_patching-example.py create mode 100644 tftracer/monkey_patching.py create mode 100644 tftracer/version.py diff --git a/README.md b/README.md index a323ba9..d0335e9 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,20 @@ pip install tensorflow-tracer http://0.0.0.0:9999 ``` +## How to Trace an Existing Code + +If you want to trace an existing script without any modification use `tftracer.hook_inject` +Please note that this is experimental and may cause unexpected errors: + +1. Add the following to the beggining of the main script: + .. code-block:: python + + import tftracer + tftracer.hook_inject() + ... +2. Run your code and browse to `http://0.0.0.0:9999` + + ## Command line Tracing sessions can be stored either through the web interface or by calling `tracing_server.save_session(filename)`. diff --git a/docs/conf.py b/docs/conf.py index e28fbaf..1dfeec9 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -17,6 +17,7 @@ sys.path.insert(0, os.path.abspath('..')) +from tftracer.version import __version__ # -- Project information ----------------------------------------------------- project = 'TensorFlow Runtime Tracer' @@ -24,9 +25,9 @@ author = 'Sayed Hadi Hashemi' # The short X.Y version -version = '1.0.2' +version = __version__ # The full version, including alpha/beta/rc tags -release = '1.0.2' +release = __version__ # -- General configuration --------------------------------------------------- diff --git a/docs/index.rst b/docs/index.rst index 514c488..0ee3b0e 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -70,6 +70,30 @@ How to Use http://0.0.0.0:9999 +How to Trace an Existing Code +============================= + +If you want to trace an existing script without any modification use :func:`tftracer.hook_inject`. Please note that +this is experimental and may cause unexpected errors: + +#. + Add the following to the beggining of the main script: + + .. code-block:: python + + import tftracer + tftracer.hook_inject() + ... + + +#. + Run your code and browse to: + + .. code-block:: html + + http://0.0.0.0:9999 + + Command line ============ @@ -111,6 +135,9 @@ Examples Low-Level API <`monitoredtrainingsession-example.py `__> Example of using :class:`tftracer.TracingServer` with TensorFlow ``MonitoredTrainingSession`` API. + Monkey Patching <`monkey_patching-example.py `__> + Example of using :func:`tftracer.hook_inject` to trace a script without any modifications. + Horovod: One Process <`horovod-example.py `__> Example of using :class:`tftracer.TracingServer` with ``horovod``. In this example only the one process is being traced. @@ -145,6 +172,10 @@ tftracer.Timeline :undoc-members: :exclude-members: communication_elapsed_time, communication_time, computation_time +tftracer.hook_inject +-------------------- +.. automodule:: tftracer + :members: hook_inject Known Bugs/Limitations diff --git a/examples/README.md b/examples/README.md index 1e0ef03..60f7dd2 100644 --- a/examples/README.md +++ b/examples/README.md @@ -9,6 +9,11 @@ Example of using `tftracer.TracingServer` with TensorFlow ``estimator`` API. [monitoredtrainingsession-example.py](https://github.com/xldrx/tensorflow-tracer/blob/master/examples/monitoredtrainingsession-example.py)
Example of using `tftracer.TracingServer` with TensorFlow `MonitoredTrainingSession` API. + +### Monkey Patching +[monkey_patching-example.py](https://github.com/xldrx/tensorflow-tracer/blob/master/examples/monkey_patching-example.py) +
+Example of using `tftracer.hook_inject` to trace a script without any modifications. ### Horovod: One Process [horovod-example.py](https://github.com/xldrx/tensorflow-tracer/blob/master/examples/horovod-example.py) diff --git a/examples/monkey_patching-example.py b/examples/monkey_patching-example.py new file mode 100644 index 0000000..c6bac4d --- /dev/null +++ b/examples/monkey_patching-example.py @@ -0,0 +1,46 @@ +#! /usr/bin/env python -u +# coding=utf-8 + +# Using tracing server with TesorFlow Estimator API + +__author__ = 'Sayed Hadi Hashemi' + +import tensorflow as tf + +import tftracer +tftracer.hook_inject() + +import numpy as np + +INPUT_SIZE = (299, 299, 3) +MINIBATCH_SIZE = 128 +NUM_CLASSES = 1000 +NUM_STEPS = 500 + + +def input_fn(): + dataset = tf.data.Dataset.from_tensor_slices([0]).repeat(MINIBATCH_SIZE) + dataset = dataset.map( + lambda _: + ( + {"x": np.random.uniform(size=INPUT_SIZE)}, + [np.random.random_integers(0, NUM_CLASSES)] + ) + ) + dataset = dataset.repeat(NUM_STEPS).batch(MINIBATCH_SIZE) + return dataset + + +def main(): + estimator = tf.estimator.DNNClassifier( + hidden_units=[10] * 150, + feature_columns=[tf.feature_column.numeric_column("x", shape=INPUT_SIZE)], + n_classes=NUM_CLASSES, + ) + estimator.train(input_fn) + estimator.evaluate(input_fn) + + +if __name__ == '__main__': + tf.logging.set_verbosity(tf.logging.INFO) + main() diff --git a/setup.py b/setup.py index 5610ca2..2b3a841 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,6 @@ from setuptools import setup import os - +from tftracer.version import __version__ with open(os.path.join(os.path.dirname(os.path.realpath(__file__)), "README.md"), "r") as fp: long_description = fp.read() @@ -10,7 +10,7 @@ setup( name='tensorflow-tracer', - version='1.0.2', + version=__version__, packages=['tftracer'], url='https://github.com/xldrx/tensorflow-tracer', license='Apache-2.0', diff --git a/tftracer/__init__.py b/tftracer/__init__.py index db9fda6..f984c4a 100755 --- a/tftracer/__init__.py +++ b/tftracer/__init__.py @@ -5,5 +5,5 @@ from .timeline import Timeline from .tracing_server import TracingServer - -__version__ = '1.0.2' +from .monkey_patching import hook_inject +from .version import __version__ \ No newline at end of file diff --git a/tftracer/monkey_patching.py b/tftracer/monkey_patching.py new file mode 100644 index 0000000..7f976b3 --- /dev/null +++ b/tftracer/monkey_patching.py @@ -0,0 +1,72 @@ +#! /usr/bin/env python -u +# coding=utf-8 + +__author__ = 'Sayed Hadi Hashemi' + + +def __add_tracing_server_hook(hooks): + if hooks is None: + return [hook_inject.__tracing_server.hook] + else: + hooks = list(hooks) + hooks.append(hook_inject.__tracing_server.hook) + return hooks + + +def __new_init(*args, **kwargs): + if hook_inject.__original_init is None: + return + + if "hooks" in hook_inject.__original_init.__code__.co_varnames: + hooks_index = hook_inject.__original_init.__code__.co_varnames.index("hooks") + if len(args) > hooks_index: + args = list(args) + args[hooks_index] = __add_tracing_server_hook(args[hooks_index]) + else: + kwargs["hooks"] = __add_tracing_server_hook(kwargs.get("hooks", None)) + else: + print("'hooks' not in '_MonitoredSession'") + + hook_inject.__original_init(*args, **kwargs) + + +def hook_inject(*args, **kwargs): + """ + (Experimental) Injects a tracing server hook to all instances of ``MonitoredSession`` by by monkey patching + the initializer. This function is an alternative to adding `hooks` to estimator or sessions. + Be aware, monkey patching could cause unexpected errors and is not recommended. + + This function should be called once in the main script preferably before importing anything else. + + Example: + + .. code-block:: python + + import tftracer + tftracer.hook_inject() + ... + + estimator.train(input_fn) + + + Args: + **kwargs: same as :class:`tftracer.TracingServer`. + + Note: + Monkey Patching (as :class:`tftracer.TracingServer`) works only with subclasses of ``MonitoredSession``. + For other ``Session`` types, use :class:`tftracer.Timeline`. + + + + """ + from . import TracingServer + from tensorflow.python.training.monitored_session import _MonitoredSession + + if hook_inject.__original_init is None: + hook_inject.__original_init = _MonitoredSession.__init__ + hook_inject.__tracing_server = TracingServer(*args, **kwargs) + _MonitoredSession.__init__ = __new_init + + +hook_inject.__tracing_server = None +hook_inject.__original_init = None diff --git a/tftracer/tracing_server.py b/tftracer/tracing_server.py index 03ddc9b..935cab3 100644 --- a/tftracer/tracing_server.py +++ b/tftracer/tracing_server.py @@ -17,7 +17,7 @@ import threading from .timeline import Timeline import tensorflow as tf - +from .version import __version__ class VisualizationServerBase: def __init__(self, server_port=9999, server_ip="0.0.0.0", **kwargs): @@ -170,6 +170,7 @@ def _get_flask_app(self): class TracingSource: + tftracer_version = __version__ def __init__(self, **kwargs): self._run_profile = OrderedDict() diff --git a/tftracer/version.py b/tftracer/version.py new file mode 100644 index 0000000..93782e2 --- /dev/null +++ b/tftracer/version.py @@ -0,0 +1,6 @@ +#! /usr/bin/env python -u +# coding=utf-8 + +__author__ = 'Sayed Hadi Hashemi' + +__version__ = '1.1.0'