Skip to content

Commit 92f285f

Browse files
Dandelion Manétensorflower-gardener
authored andcommitted
Refactor the PluginAsset class so that PluginAssets are not directly responsible for serialization.
In the current PluginAsset api, the PluginAsset provides a serialize_to_directory method in which it directly writes contents to disk. This means that we as framework maintainers don't have the flexibility to change the serialization strategy in different contexts, e.g. providing good ways to serialize in contexts where we are writing to a db rather than to disk. Also, it presents a trivial landmine where users may use standard python file APIs rather than gfile and thus provide implementations that work externally but break within g3. After the change, the PluginAsset instead provides an 'assets' method, which provides asset names and asset contents. How this gets written out is now an implementation detail handled by the tf.summary.FileWriter. We haven't yet exposed the PluginAsset class as part of the TensorFlow API (it's hidden) so this isn't an API break. Change: 149985564
1 parent 32c11fd commit 92f285f

4 files changed

Lines changed: 32 additions & 31 deletions

File tree

tensorflow/python/summary/plugin_asset.py

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,16 @@
1414
# ==============================================================================
1515
"""TensorBoard Plugin asset abstract class.
1616
17-
TensorBoard plugins may need to write arbitrary assets to disk, such as
17+
TensorBoard plugins may need to provide arbitrary assets, such as
1818
configuration information for specific outputs, or vocabulary files, or sprite
1919
images, etc.
2020
2121
This module contains methods that allow plugin assets to be specified at graph
2222
construction time. Plugin authors define a PluginAsset which is treated as a
23-
singleton on a per-graph basis. The PluginAsset has a serialize_to_directory
24-
method which writes its assets to disk within a special plugin directory
25-
that the tf.summary.FileWriter creates.
23+
singleton on a per-graph basis. The PluginAsset has an assets method which
24+
returns a dictionary of asset contents. The tf.summary.FileWriter
25+
(or any other Summary writer) will serialize these assets in such a way that
26+
TensorBoard can retrieve them.
2627
"""
2728

2829
from __future__ import absolute_import
@@ -111,30 +112,30 @@ class PluginAsset(object):
111112
112113
Plugin authors are expected to extend the PluginAsset class, so that it:
113114
- has a unique plugin_name
114-
- provides a serialize_to_directory method that dumps its assets in that dir
115-
- takes no constructor arguments
115+
- provides an assets method that returns an {asset_name: asset_contents}
116+
dictionary. For now, asset_contents are strings, although we may add
117+
StringIO support later.
116118
117119
LifeCycle of a PluginAsset instance:
118120
- It is constructed when get_plugin_asset is called on the class for
119-
the first time.
121+
the first time.
120122
- It is configured by code that follows the calls to get_plugin_asset
121123
- When the containing graph is serialized by the tf.summary.FileWriter, the
122-
writer calls serialize_to_directory and the PluginAsset instance dumps its
123-
contents to disk.
124+
writer calls assets and the PluginAsset instance provides its contents to be
125+
written to disk.
124126
"""
125127
__metaclass__ = abc.ABCMeta
126128

127129
plugin_name = None
128130

129131
@abc.abstractmethod
130-
def serialize_to_directory(self, directory):
131-
"""Serialize the assets in this PluginAsset to given directory.
132+
def assets(self):
133+
"""Provide all of the assets contained by the PluginAsset instance.
132134
133-
The directory will be specific to this plugin (as determined by the
134-
plugin_key property on the class). This method will be called when the graph
135-
containing this PluginAsset is given to a tf.summary.FileWriter.
135+
The assets method should return a dictionary structured as
136+
{asset_name: asset_contents}. asset_contents is a string.
136137
137-
Args:
138-
directory: The directory path (as string) that serialize should write to.
138+
This method will be called by the tf.summary.FileWriter when it is time to
139+
write the assets out to disk.
139140
"""
140141
raise NotImplementedError()

tensorflow/python/summary/plugin_asset_test.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@
2626
class _UnnamedPluginAsset(plugin_asset.PluginAsset):
2727
"""An example asset with a dummy serialize method provided, but no name."""
2828

29-
def serialize_to_directory(self, unused_directory):
30-
pass
29+
def assets(self):
30+
return {}
3131

3232

3333
class _ExamplePluginAsset(_UnnamedPluginAsset):

tensorflow/python/summary/writer/writer.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ def add_graph(self, graph, global_step=None, graph_def=None):
164164

165165
# Serialize the graph with additional info.
166166
true_graph_def = graph.as_graph_def(add_shapes=True)
167-
self._write_tensorboard_metadata(graph)
167+
self._write_plugin_assets(graph)
168168
elif (isinstance(graph, graph_pb2.GraphDef) or
169169
isinstance(graph_def, graph_pb2.GraphDef)):
170170
# The user passed a `GraphDef`.
@@ -185,13 +185,18 @@ def add_graph(self, graph, global_step=None, graph_def=None):
185185
# Finally, add the graph_def to the summary writer.
186186
self._add_graph_def(true_graph_def, global_step)
187187

188-
def _write_tensorboard_metadata(self, graph):
189-
assets = plugin_asset.get_all_plugin_assets(graph)
188+
def _write_plugin_assets(self, graph):
189+
plugin_assets = plugin_asset.get_all_plugin_assets(graph)
190190
logdir = self.event_writer.get_logdir()
191-
for asset in assets:
192-
plugin_dir = os.path.join(logdir, _PLUGINS_DIR, asset.plugin_name)
191+
for asset_container in plugin_assets:
192+
plugin_name = asset_container.plugin_name
193+
plugin_dir = os.path.join(logdir, _PLUGINS_DIR, plugin_name)
193194
gfile.MakeDirs(plugin_dir)
194-
asset.serialize_to_directory(plugin_dir)
195+
assets = asset_container.assets()
196+
for (asset_name, content) in assets.items():
197+
asset_path = os.path.join(plugin_dir, asset_name)
198+
with gfile.Open(asset_path, "w") as f:
199+
f.write(content)
195200

196201
def add_meta_graph(self, meta_graph_def, global_step=None):
197202
"""Adds a `MetaGraphDef` to the event file.

tensorflow/python/summary/writer/writer_test.py

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -359,13 +359,8 @@ def test_clear(self):
359359
class ExamplePluginAsset(plugin_asset.PluginAsset):
360360
plugin_name = "example"
361361

362-
def serialize_to_directory(self, directory):
363-
foo = os.path.join(directory, "foo.txt")
364-
bar = os.path.join(directory, "bar.txt")
365-
with gfile.Open(foo, "w") as f:
366-
f.write("foo!")
367-
with gfile.Open(bar, "w") as f:
368-
f.write("bar!")
362+
def assets(self):
363+
return {"foo.txt": "foo!", "bar.txt": "bar!"}
369364

370365

371366
class PluginAssetsTest(test.TestCase):

0 commit comments

Comments
 (0)