diff options
author | A. Unique TensorFlower <gardener@tensorflow.org> | 2017-05-30 19:01:39 -0700 |
---|---|---|
committer | TensorFlower Gardener <gardener@tensorflow.org> | 2017-05-30 19:05:23 -0700 |
commit | 37d9d5f0e877064899f10ab7fed0934d08049662 (patch) | |
tree | c700ced38f81b430ef3c7d9d30c3259a62a2dfb4 | |
parent | d58cd296202b89440f59c2bcc8776a6eb08dc961 (diff) |
Add some routines for managing summaries to slim.
PiperOrigin-RevId: 157541902
-rw-r--r-- | tensorflow/contrib/slim/BUILD | 27 | ||||
-rw-r--r-- | tensorflow/contrib/slim/__init__.py | 1 | ||||
-rw-r--r-- | tensorflow/contrib/slim/python/slim/summaries.py | 220 | ||||
-rw-r--r-- | tensorflow/contrib/slim/python/slim/summaries_test.py | 108 |
4 files changed, 356 insertions, 0 deletions
diff --git a/tensorflow/contrib/slim/BUILD b/tensorflow/contrib/slim/BUILD index 012413d8e9..fbe8ced46e 100644 --- a/tensorflow/contrib/slim/BUILD +++ b/tensorflow/contrib/slim/BUILD @@ -144,6 +144,7 @@ py_library( ":learning", ":model_analyzer", ":queues", + ":summaries", "//tensorflow/contrib/framework:framework_py", "//tensorflow/contrib/layers:layers_py", "//tensorflow/contrib/losses:losses_py", @@ -160,6 +161,32 @@ py_library( ], ) +py_library( + name = "summaries", + srcs = ["python/slim/summaries.py"], + srcs_version = "PY2AND3", + deps = [ + "//tensorflow/python:framework", + "//tensorflow/python:logging_ops", + "//tensorflow/python:nn", + "//tensorflow/python:summary", + ], +) + +py_test( + name = "summaries_test", + srcs = ["python/slim/summaries_test.py"], + srcs_version = "PY2AND3", + deps = [ + ":summaries", + "//tensorflow/python:array_ops", + "//tensorflow/python:client_testlib", + "//tensorflow/python:framework", + "//tensorflow/python:platform", + "//tensorflow/python:summary", + ], +) + filegroup( name = "all_files", srcs = glob( diff --git a/tensorflow/contrib/slim/__init__.py b/tensorflow/contrib/slim/__init__.py index 67846a95fd..22998b1126 100644 --- a/tensorflow/contrib/slim/__init__.py +++ b/tensorflow/contrib/slim/__init__.py @@ -34,6 +34,7 @@ from tensorflow.contrib.slim.python.slim import evaluation from tensorflow.contrib.slim.python.slim import learning from tensorflow.contrib.slim.python.slim import model_analyzer from tensorflow.contrib.slim.python.slim import queues +from tensorflow.contrib.slim.python.slim import summaries from tensorflow.contrib.slim.python.slim.data import data_decoder from tensorflow.contrib.slim.python.slim.data import data_provider from tensorflow.contrib.slim.python.slim.data import dataset diff --git a/tensorflow/contrib/slim/python/slim/summaries.py b/tensorflow/contrib/slim/python/slim/summaries.py new file mode 100644 index 0000000000..358359d6eb --- /dev/null +++ b/tensorflow/contrib/slim/python/slim/summaries.py @@ -0,0 +1,220 @@ +# Copyright 2017 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +"""Contains helper functions for creating summaries. + +This module contains various helper functions for quickly and easily adding +tensorflow summaries. These allow users to print summary values +automatically as they are computed and add prefixes to collections of summaries. + +Example usage: + + import tensorflow as tf + slim = tf.contrib.slim + + slim.summaries.add_histogram_summaries(slim.variables.get_model_variables()) + slim.summaries.add_scalar_summary(total_loss, 'Total Loss') + slim.summaries.add_scalar_summary(learning_rate, 'Learning Rate') + slim.summaries.add_histogram_summaries(my_tensors) + slim.summaries.add_zero_fraction_summaries(my_tensors) +""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +from tensorflow.python.framework import ops +from tensorflow.python.ops import logging_ops +from tensorflow.python.ops import nn_impl as nn +from tensorflow.python.summary import summary + + +def _get_summary_name(tensor, name=None, prefix=None, postfix=None): + """Produces the summary name given. + + Args: + tensor: A variable or op `Tensor`. + name: The optional name for the summary. + prefix: An optional prefix for the summary name. + postfix: An optional postfix for the summary name. + + Returns: + a summary name. + """ + if not name: + name = tensor.op.name + if prefix: + name = prefix + '/' + name + if postfix: + name = name + '/' + postfix + return name + + +def add_histogram_summary(tensor, name=None, prefix=None): + """Adds a histogram summary for the given tensor. + + Args: + tensor: A variable or op tensor. + name: The optional name for the summary. + prefix: An optional prefix for the summary names. + + Returns: + A scalar `Tensor` of type `string` whose contents are the serialized + `Summary` protocol buffer. + """ + return summary.histogram( + _get_summary_name(tensor, name, prefix), tensor) + + +def add_image_summary(tensor, name=None, prefix=None, print_summary=False): + """Adds an image summary for the given tensor. + + Args: + tensor: a variable or op tensor with shape [batch,height,width,channels] + name: the optional name for the summary. + prefix: An optional prefix for the summary names. + print_summary: If `True`, the summary is printed to stdout when the summary + is computed. + + Returns: + An image `Tensor` of type `string` whose contents are the serialized + `Summary` protocol buffer. + """ + summary_name = _get_summary_name(tensor, name, prefix) + # If print_summary, then we need to make sure that this call doesn't add the + # non-printing op to the collection. We'll add it to the collection later. + collections = [] if print_summary else None + op = summary.image( + name=summary_name, tensor=tensor, collections=collections) + if print_summary: + op = logging_ops.Print(op, [tensor], summary_name) + ops.add_to_collection(ops.GraphKeys.SUMMARIES, op) + return op + + +def add_scalar_summary(tensor, name=None, prefix=None, print_summary=False): + """Adds a scalar summary for the given tensor. + + Args: + tensor: a variable or op tensor. + name: the optional name for the summary. + prefix: An optional prefix for the summary names. + print_summary: If `True`, the summary is printed to stdout when the summary + is computed. + + Returns: + A scalar `Tensor` of type `string` whose contents are the serialized + `Summary` protocol buffer. + """ + collections = [] if print_summary else None + summary_name = _get_summary_name(tensor, name, prefix) + + # If print_summary, then we need to make sure that this call doesn't add the + # non-printing op to the collection. We'll add it to the collection later. + op = summary.scalar( + name=summary_name, tensor=tensor, collections=collections) + if print_summary: + op = logging_ops.Print(op, [tensor], summary_name) + ops.add_to_collection(ops.GraphKeys.SUMMARIES, op) + return op + + +def add_zero_fraction_summary(tensor, name=None, prefix=None, + print_summary=False): + """Adds a summary for the percentage of zero values in the given tensor. + + Args: + tensor: a variable or op tensor. + name: the optional name for the summary. + prefix: An optional prefix for the summary names. + print_summary: If `True`, the summary is printed to stdout when the summary + is computed. + + Returns: + A scalar `Tensor` of type `string` whose contents are the serialized + `Summary` protocol buffer. + """ + name = _get_summary_name(tensor, name, prefix, 'Fraction of Zero Values') + tensor = nn.zero_fraction(tensor) + return add_scalar_summary(tensor, name, print_summary=print_summary) + + +def add_histogram_summaries(tensors, prefix=None): + """Adds a histogram summary for each of the given tensors. + + Args: + tensors: A list of variable or op tensors. + prefix: An optional prefix for the summary names. + + Returns: + A list of scalar `Tensors` of type `string` whose contents are the + serialized `Summary` protocol buffer. + """ + summary_ops = [] + for tensor in tensors: + summary_ops.append(add_histogram_summary(tensor, prefix=prefix)) + return summary_ops + + +def add_image_summaries(tensors, prefix=None): + """Adds an image summary for each of the given tensors. + + Args: + tensors: A list of variable or op tensors. + prefix: An optional prefix for the summary names. + + Returns: + A list of scalar `Tensors` of type `string` whose contents are the + serialized `Summary` protocol buffer. + """ + summary_ops = [] + for tensor in tensors: + summary_ops.append(add_image_summary(tensor, prefix=prefix)) + return summary_ops + + +def add_scalar_summaries(tensors, prefix=None, print_summary=False): + """Adds a scalar summary for each of the given tensors. + + Args: + tensors: a list of variable or op tensors. + prefix: An optional prefix for the summary names. + print_summary: If `True`, the summary is printed to stdout when the summary + is computed. + + Returns: + A list of scalar `Tensors` of type `string` whose contents are the + serialized `Summary` protocol buffer. + """ + summary_ops = [] + for tensor in tensors: + summary_ops.append(add_scalar_summary(tensor, prefix=prefix, + print_summary=print_summary)) + return summary_ops + + +def add_zero_fraction_summaries(tensors, prefix=None): + """Adds a scalar zero-fraction summary for each of the given tensors. + + Args: + tensors: a list of variable or op tensors. + prefix: An optional prefix for the summary names. + + Returns: + A list of scalar `Tensors` of type `string` whose contents are the + serialized `Summary` protocol buffer. + """ + summary_ops = [] + for tensor in tensors: + summary_ops.append(add_zero_fraction_summary(tensor, prefix=prefix)) + return summary_ops diff --git a/tensorflow/contrib/slim/python/slim/summaries_test.py b/tensorflow/contrib/slim/python/slim/summaries_test.py new file mode 100644 index 0000000000..873ee78de2 --- /dev/null +++ b/tensorflow/contrib/slim/python/slim/summaries_test.py @@ -0,0 +1,108 @@ +# Copyright 2017 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +"""Tests for tensorflow.contrib.slim.summaries.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import glob +import os + + +from tensorflow.contrib.slim.python.slim import summaries +from tensorflow.python.framework import ops +from tensorflow.python.ops import array_ops +from tensorflow.python.platform import gfile +from tensorflow.python.platform import test +from tensorflow.python.summary import summary +from tensorflow.python.summary import summary_iterator + + +class SummariesTest(test.TestCase): + + def safe_create(self, output_dir): + if gfile.Exists(output_dir): + gfile.DeleteRecursively(output_dir) + gfile.MakeDirs(output_dir) + + def assert_scalar_summary(self, output_dir, names_to_values): + """Asserts that the given output directory contains written summaries. + + Args: + output_dir: The output directory in which to look for even tfiles. + names_to_values: A dictionary of summary names to values. + """ + # The events file may have additional entries, e.g. the event version + # stamp, so have to parse things a bit. + output_filepath = glob.glob(os.path.join(output_dir, '*')) + self.assertEqual(len(output_filepath), 1) + + events = summary_iterator.summary_iterator(output_filepath[0]) + summaries_list = [e.summary for e in events if e.summary.value] + values = [] + for item in summaries_list: + for value in item.value: + values.append(value) + saved_results = {v.tag: v.simple_value for v in values} + for name in names_to_values: + self.assertAlmostEqual(names_to_values[name], saved_results[name]) + + def testScalarSummaryIsPartOfCollectionWithNoPrint(self): + tensor = array_ops.ones([]) * 3 + name = 'my_score' + prefix = 'eval' + op = summaries.add_scalar_summary(tensor, name, prefix, print_summary=False) + self.assertTrue(op in ops.get_collection(ops.GraphKeys.SUMMARIES)) + + def testScalarSummaryIsPartOfCollectionWithPrint(self): + tensor = array_ops.ones([]) * 3 + name = 'my_score' + prefix = 'eval' + op = summaries.add_scalar_summary(tensor, name, prefix, print_summary=True) + self.assertTrue(op in ops.get_collection(ops.GraphKeys.SUMMARIES)) + + def verify_scalar_summary_is_written(self, print_summary): + value = 3 + tensor = array_ops.ones([]) * value + name = 'my_score' + prefix = 'eval' + summaries.add_scalar_summary(tensor, name, prefix, print_summary) + + output_dir = os.path.join(self.get_temp_dir(), + 'scalar_summary_no_print_test') + self.safe_create(output_dir) + + summary_op = summary.merge_all() + + summary_writer = summary.FileWriter(output_dir) + with self.test_session() as sess: + new_summary = sess.run(summary_op) + summary_writer.add_summary(new_summary, 1) + summary_writer.flush() + + self.assert_scalar_summary(output_dir, { + '%s/%s' % (prefix, name): value + }) + + def testScalarSummaryIsWrittenWithNoPrint(self): + self.verify_scalar_summary_is_written(print_summary=False) + + def testScalarSummaryIsWrittenWithPrint(self): + self.verify_scalar_summary_is_written(print_summary=True) + + +if __name__ == '__main__': + test.main() |