• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2015 The TensorFlow Authors. All Rights Reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14# ==============================================================================
15"""Logging and Summary Operations."""
16# pylint: disable=protected-access
17from __future__ import absolute_import
18from __future__ import division
19from __future__ import print_function
20
21import collections as py_collections
22import os
23import pprint
24import random
25import sys
26
27from absl import logging
28import six
29
30from tensorflow.python import pywrap_tfe
31from tensorflow.python.framework import dtypes
32from tensorflow.python.framework import ops
33from tensorflow.python.framework import sparse_tensor
34from tensorflow.python.framework import tensor_util
35from tensorflow.python.ops import gen_logging_ops
36from tensorflow.python.ops import string_ops
37# go/tf-wildcard-import
38# pylint: disable=wildcard-import
39from tensorflow.python.ops.gen_logging_ops import *
40# pylint: enable=wildcard-import
41from tensorflow.python.platform import tf_logging
42from tensorflow.python.util import dispatch
43from tensorflow.python.util import nest
44from tensorflow.python.util.deprecation import deprecated
45from tensorflow.python.util.tf_export import tf_export
46
47# Register printing to the cell output if we are in a Colab or Jupyter Notebook.
48try:
49  get_ipython()  # Exists in an ipython env like Jupyter or Colab
50  pywrap_tfe.TFE_Py_EnableInteractivePythonLogging()
51except NameError:
52  pass
53
54# The python wrapper for Assert is in control_flow_ops, as the Assert
55# call relies on certain conditionals for its dependencies.  Use
56# control_flow_ops.Assert.
57
58# Assert and Print are special symbols in Python 2, so we must
59# have an upper-case version of them. When support for it is dropped,
60# we can allow lowercase.
61# See https://github.com/tensorflow/tensorflow/issues/18053
62
63
64# pylint: disable=invalid-name
65@deprecated("2018-08-20", "Use tf.print instead of tf.Print. Note that "
66            "tf.print returns a no-output operator that directly "
67            "prints the output. Outside of defuns or eager mode, "
68            "this operator will not be executed unless it is "
69            "directly specified in session.run or used as a "
70            "control dependency for other operators. This is "
71            "only a concern in graph mode. Below is an example "
72            "of how to ensure tf.print executes in graph mode:\n")
73@tf_export(v1=["Print"])
74@dispatch.add_dispatch_support
75def Print(input_, data, message=None, first_n=None, summarize=None, name=None):
76  """Prints a list of tensors.
77
78  This is an identity op (behaves like `tf.identity`) with the side effect
79  of printing `data` when evaluating.
80
81  Note: This op prints to the standard error. It is not currently compatible
82    with jupyter notebook (printing to the notebook *server's* output, not into
83    the notebook).
84
85  @compatibility(TF2)
86  This API is deprecated. Use `tf.print` instead. `tf.print` does not need the
87  `input_` argument.
88
89  `tf.print` works in TF2 when executing eagerly and inside a `tf.function`.
90
91  In TF1-styled sessions, an explicit control dependency declaration is needed
92  to execute the `tf.print` operation. Refer to the documentation of
93  `tf.print` for more details.
94  @end_compatibility
95
96  Args:
97    input_: A tensor passed through this op.
98    data: A list of tensors to print out when op is evaluated.
99    message: A string, prefix of the error message.
100    first_n: Only log `first_n` number of times. Negative numbers log always;
101      this is the default.
102    summarize: Only print this many entries of each tensor. If None, then a
103      maximum of 3 elements are printed per input tensor.
104    name: A name for the operation (optional).
105
106  Returns:
107    A `Tensor`. Has the same type and contents as `input_`.
108
109    ```python
110    sess = tf.compat.v1.Session()
111    with sess.as_default():
112        tensor = tf.range(10)
113        print_op = tf.print(tensor)
114        with tf.control_dependencies([print_op]):
115          out = tf.add(tensor, tensor)
116        sess.run(out)
117    ```
118  """
119  return gen_logging_ops._print(input_, data, message, first_n, summarize, name)
120
121
122# pylint: enable=invalid-name
123
124
125def _generate_placeholder_string(x, default_placeholder="{}"):
126  """Generate and return a string that does not appear in `x`."""
127  placeholder = default_placeholder
128  rng = random.Random(5)
129  while placeholder in x:
130    placeholder = placeholder + str(rng.randint(0, 9))
131  return placeholder
132
133
134def _is_filepath(output_stream):
135  """Returns True if output_stream is a file path."""
136  return isinstance(output_stream, str) and output_stream.startswith("file://")
137
138
139# Temporarily disable pylint g-doc-args error to allow giving more context
140# about what the kwargs are.
141# Because we are using arbitrary-length positional arguments, python 2
142# does not support explicitly specifying the keyword arguments in the
143# function definition.
144# pylint: disable=g-doc-args
145@tf_export("print")
146@dispatch.add_dispatch_support
147def print_v2(*inputs, **kwargs):
148  """Print the specified inputs.
149
150  A TensorFlow operator that prints the specified inputs to a desired
151  output stream or logging level. The inputs may be dense or sparse Tensors,
152  primitive python objects, data structures that contain tensors, and printable
153  Python objects. Printed tensors will recursively show the first and last
154  elements of each dimension to summarize.
155
156  Example:
157    Single-input usage:
158
159    ```python
160    tensor = tf.range(10)
161    tf.print(tensor, output_stream=sys.stderr)
162    ```
163
164    (This prints "[0 1 2 ... 7 8 9]" to sys.stderr)
165
166    Multi-input usage:
167
168    ```python
169    tensor = tf.range(10)
170    tf.print("tensors:", tensor, {2: tensor * 2}, output_stream=sys.stdout)
171    ```
172
173    (This prints "tensors: [0 1 2 ... 7 8 9] {2: [0 2 4 ... 14 16 18]}" to
174    sys.stdout)
175
176    Changing the input separator:
177    ```python
178    tensor_a = tf.range(2)
179    tensor_b = tensor_a * 2
180    tf.print(tensor_a, tensor_b, output_stream=sys.stderr, sep=',')
181    ```
182
183    (This prints "[0 1],[0 2]" to sys.stderr)
184
185    Usage in a `tf.function`:
186
187    ```python
188    @tf.function
189    def f():
190        tensor = tf.range(10)
191        tf.print(tensor, output_stream=sys.stderr)
192        return tensor
193
194    range_tensor = f()
195    ```
196
197    (This prints "[0 1 2 ... 7 8 9]" to sys.stderr)
198
199  *Compatibility usage in TF 1.x graphs*:
200
201    In graphs manually created outside of `tf.function`, this method returns
202    the created TF operator that prints the data. To make sure the
203    operator runs, users need to pass the produced op to
204    `tf.compat.v1.Session`'s run method, or to use the op as a control
205    dependency for executed ops by specifying
206    `with tf.compat.v1.control_dependencies([print_op])`.
207
208    ```python
209    tf.compat.v1.disable_v2_behavior()  # for TF1 compatibility only
210
211    sess = tf.compat.v1.Session()
212    with sess.as_default():
213      tensor = tf.range(10)
214      print_op = tf.print("tensors:", tensor, {2: tensor * 2},
215                          output_stream=sys.stdout)
216      with tf.control_dependencies([print_op]):
217        tripled_tensor = tensor * 3
218
219      sess.run(tripled_tensor)
220    ```
221
222    (This prints "tensors: [0 1 2 ... 7 8 9] {2: [0 2 4 ... 14 16 18]}" to
223    sys.stdout)
224
225  Note: In Jupyter notebooks and colabs, `tf.print` prints to the notebook
226    cell outputs. It will not write to the notebook kernel's console logs.
227
228  Args:
229    *inputs: Positional arguments that are the inputs to print. Inputs in the
230      printed output will be separated by spaces. Inputs may be python
231      primitives, tensors, data structures such as dicts and lists that may
232      contain tensors (with the data structures possibly nested in arbitrary
233      ways), and printable python objects.
234    output_stream: The output stream, logging level, or file to print to.
235      Defaults to sys.stderr, but sys.stdout, tf.compat.v1.logging.info,
236      tf.compat.v1.logging.warning, tf.compat.v1.logging.error,
237      absl.logging.info, absl.logging.warning and absl.logging.error are also
238      supported. To print to a file, pass a string started with "file://"
239      followed by the file path, e.g., "file:///tmp/foo.out".
240    summarize: The first and last `summarize` elements within each dimension are
241      recursively printed per Tensor. If None, then the first 3 and last 3
242      elements of each dimension are printed for each tensor. If set to -1, it
243      will print all elements of every tensor.
244    sep: The string to use to separate the inputs. Defaults to " ".
245    end: End character that is appended at the end the printed string. Defaults
246      to the newline character.
247    name: A name for the operation (optional).
248
249  Returns:
250    None when executing eagerly. During graph tracing this returns
251    a TF operator that prints the specified inputs in the specified output
252    stream or logging level. This operator will be automatically executed
253    except inside of `tf.compat.v1` graphs and sessions.
254
255  Raises:
256    ValueError: If an unsupported output stream is specified.
257  """
258  # Because we are using arbitrary-length positional arguments, python 2
259  # does not support explicitly specifying the keyword arguments in the
260  # function definition. So, we manually get the keyword arguments w/ default
261  # values here.
262  output_stream = kwargs.pop("output_stream", sys.stderr)
263  name = kwargs.pop("name", None)
264  summarize = kwargs.pop("summarize", 3)
265  sep = kwargs.pop("sep", " ")
266  end = kwargs.pop("end", os.linesep)
267  if kwargs:
268    raise ValueError("Unrecognized keyword arguments for tf.print: %s" % kwargs)
269  format_name = None
270  if name:
271    format_name = name + "_format"
272
273  # Match the C++ string constants representing the different output streams.
274  # Keep this updated!
275  output_stream_to_constant = {
276      sys.stdout: "stdout",
277      sys.stderr: "stderr",
278      tf_logging.INFO: "log(info)",
279      tf_logging.info: "log(info)",
280      tf_logging.WARN: "log(warning)",
281      tf_logging.warning: "log(warning)",
282      tf_logging.warn: "log(warning)",
283      tf_logging.ERROR: "log(error)",
284      tf_logging.error: "log(error)",
285      logging.INFO: "log(info)",
286      logging.info: "log(info)",
287      logging.INFO: "log(info)",
288      logging.WARNING: "log(warning)",
289      logging.WARN: "log(warning)",
290      logging.warning: "log(warning)",
291      logging.warn: "log(warning)",
292      logging.ERROR: "log(error)",
293      logging.error: "log(error)",
294  }
295
296  if _is_filepath(output_stream):
297    output_stream_string = output_stream
298  else:
299    output_stream_string = output_stream_to_constant.get(output_stream)
300    if not output_stream_string:
301      raise ValueError("Unsupported output stream, logging level, or file." +
302                       str(output_stream) +
303                       ". Supported streams are sys.stdout, "
304                       "sys.stderr, tf.logging.info, "
305                       "tf.logging.warning, tf.logging.error. " +
306                       "File needs to be in the form of 'file://<filepath>'.")
307
308  # If we are only printing a single string scalar, there is no need to format
309  if (len(inputs) == 1 and tensor_util.is_tf_type(inputs[0]) and
310      (not isinstance(inputs[0], sparse_tensor.SparseTensor)) and
311      (inputs[0].shape.ndims == 0) and (inputs[0].dtype == dtypes.string)):
312    formatted_string = inputs[0]
313  # Otherwise, we construct an appropriate template for the tensors we are
314  # printing, and format the template using those tensors.
315  else:
316    # For each input to this print function, we extract any nested tensors,
317    # and construct an appropriate template to format representing the
318    # printed input.
319    templates = []
320    tensors = []
321    # If an input to the print function is of type `OrderedDict`, sort its
322    # elements by the keys for consistency with the ordering of `nest.flatten`.
323    # This is not needed for `dict` types because `pprint.pformat()` takes care
324    # of printing the template in a sorted fashion.
325    inputs_ordered_dicts_sorted = []
326    for input_ in inputs:
327      if isinstance(input_, py_collections.OrderedDict):
328        inputs_ordered_dicts_sorted.append(
329            py_collections.OrderedDict(sorted(input_.items())))
330      else:
331        inputs_ordered_dicts_sorted.append(input_)
332    tensor_free_structure = nest.map_structure(
333        lambda x: "" if tensor_util.is_tf_type(x) else x,
334        inputs_ordered_dicts_sorted)
335
336    tensor_free_template = " ".join(
337        pprint.pformat(x) for x in tensor_free_structure)
338    placeholder = _generate_placeholder_string(tensor_free_template)
339
340    for input_ in inputs:
341      placeholders = []
342      # Use the nest utilities to flatten & process any nested elements in this
343      # input. The placeholder for a tensor in the template should be the
344      # placeholder string, and the placeholder for a non-tensor can just be
345      # the printed value of the non-tensor itself.
346      for x in nest.flatten(input_):
347        # support sparse tensors
348        if isinstance(x, sparse_tensor.SparseTensor):
349          tensors.extend([x.indices, x.values, x.dense_shape])
350          placeholders.append(
351              "SparseTensor(indices={}, values={}, shape={})".format(
352                  placeholder, placeholder, placeholder))
353        elif tensor_util.is_tf_type(x):
354          tensors.append(x)
355          placeholders.append(placeholder)
356        else:
357          placeholders.append(x)
358
359      if isinstance(input_, six.string_types):
360        # If the current input to format/print is a normal string, that string
361        # can act as the template.
362        cur_template = input_
363      else:
364        # We pack the placeholders into a data structure that matches the
365        # input data structure format, then format that data structure
366        # into a string template.
367        #
368        # NOTE: We must use pprint.pformat here for building the template for
369        # unordered data structures such as `dict`, because `str` doesn't
370        # guarantee orderings, while pprint prints in sorted order. pprint
371        # will match the ordering of `nest.flatten`.
372        # This even works when nest.flatten reorders OrderedDicts, because
373        # pprint is printing *after* the OrderedDicts have been reordered.
374        cur_template = pprint.pformat(
375            nest.pack_sequence_as(input_, placeholders))
376      templates.append(cur_template)
377
378    # We join the templates for the various inputs into a single larger
379    # template. We also remove all quotes surrounding the placeholders, so that
380    # the formatted/printed output will not contain quotes around tensors.
381    # (example of where these quotes might appear: if we have added a
382    # placeholder string into a list, then pretty-formatted that list)
383    template = sep.join(templates)
384    template = template.replace("'" + placeholder + "'", placeholder)
385    formatted_string = string_ops.string_format(
386        inputs=tensors,
387        template=template,
388        placeholder=placeholder,
389        summarize=summarize,
390        name=format_name)
391
392  return gen_logging_ops.print_v2(
393      formatted_string, output_stream=output_stream_string, name=name, end=end)
394
395
396# pylint: enable=g-doc-args
397
398
399@ops.RegisterGradient("Print")
400def _PrintGrad(op, *grad):
401  return list(grad) + [None] * (len(op.inputs) - 1)
402
403
404def _Collect(val, collections, default_collections):
405  if collections is None:
406    collections = default_collections
407  for key in collections:
408    ops.add_to_collection(key, val)
409
410
411@deprecated(
412    "2016-11-30", "Please switch to tf.summary.histogram. Note that "
413    "tf.summary.histogram uses the node name instead of the tag. "
414    "This means that TensorFlow will automatically de-duplicate summary "
415    "names based on the scope they are created in.")
416def histogram_summary(tag, values, collections=None, name=None):
417  # pylint: disable=line-too-long
418  """Outputs a `Summary` protocol buffer with a histogram.
419
420  This ops is deprecated. Please switch to tf.summary.histogram.
421
422  For an explanation of why this op was deprecated, and information on how to
423  migrate, look
424  ['here'](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/contrib/deprecated/__init__.py)
425
426  The generated
427  [`Summary`](https://www.tensorflow.org/code/tensorflow/core/framework/summary.proto)
428  has one summary value containing a histogram for `values`.
429
430  This op reports an `InvalidArgument` error if any value is not finite.
431
432  Args:
433    tag: A `string` `Tensor`. 0-D.  Tag to use for the summary value.
434    values: A real numeric `Tensor`. Any shape. Values to use to build the
435      histogram.
436    collections: Optional list of graph collections keys. The new summary op is
437      added to these collections. Defaults to `[GraphKeys.SUMMARIES]`.
438    name: A name for the operation (optional).
439
440  Returns:
441    A scalar `Tensor` of type `string`. The serialized `Summary` protocol
442    buffer.
443  """
444  with ops.name_scope(name, "HistogramSummary", [tag, values]) as scope:
445    val = gen_logging_ops.histogram_summary(tag=tag, values=values, name=scope)
446    _Collect(val, collections, [ops.GraphKeys.SUMMARIES])
447  return val
448
449
450@deprecated(
451    "2016-11-30", "Please switch to tf.summary.image. Note that "
452    "tf.summary.image uses the node name instead of the tag. "
453    "This means that TensorFlow will automatically de-duplicate summary "
454    "names based on the scope they are created in. Also, the max_images "
455    "argument was renamed to max_outputs.")
456def image_summary(tag, tensor, max_images=3, collections=None, name=None):
457  # pylint: disable=line-too-long
458  """Outputs a `Summary` protocol buffer with images.
459
460  For an explanation of why this op was deprecated, and information on how to
461  migrate, look
462  ['here'](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/contrib/deprecated/__init__.py)
463
464  The summary has up to `max_images` summary values containing images. The
465  images are built from `tensor` which must be 4-D with shape `[batch_size,
466  height, width, channels]` and where `channels` can be:
467
468  *  1: `tensor` is interpreted as Grayscale.
469  *  3: `tensor` is interpreted as RGB.
470  *  4: `tensor` is interpreted as RGBA.
471
472  The images have the same number of channels as the input tensor. For float
473  input, the values are normalized one image at a time to fit in the range
474  `[0, 255]`.  `uint8` values are unchanged.  The op uses two different
475  normalization algorithms:
476
477  *  If the input values are all positive, they are rescaled so the largest one
478     is 255.
479
480  *  If any input value is negative, the values are shifted so input value 0.0
481     is at 127.  They are then rescaled so that either the smallest value is 0,
482     or the largest one is 255.
483
484  The `tag` argument is a scalar `Tensor` of type `string`.  It is used to
485  build the `tag` of the summary values:
486
487  *  If `max_images` is 1, the summary value tag is '*tag*/image'.
488  *  If `max_images` is greater than 1, the summary value tags are
489     generated sequentially as '*tag*/image/0', '*tag*/image/1', etc.
490
491  Args:
492    tag: A scalar `Tensor` of type `string`. Used to build the `tag` of the
493      summary values.
494    tensor: A 4-D `uint8` or `float32` `Tensor` of shape `[batch_size, height,
495      width, channels]` where `channels` is 1, 3, or 4.
496    max_images: Max number of batch elements to generate images for.
497    collections: Optional list of ops.GraphKeys.  The collections to add the
498      summary to.  Defaults to [ops.GraphKeys.SUMMARIES]
499    name: A name for the operation (optional).
500
501  Returns:
502    A scalar `Tensor` of type `string`. The serialized `Summary` protocol
503    buffer.
504  """
505  with ops.name_scope(name, "ImageSummary", [tag, tensor]) as scope:
506    val = gen_logging_ops.image_summary(
507        tag=tag, tensor=tensor, max_images=max_images, name=scope)
508    _Collect(val, collections, [ops.GraphKeys.SUMMARIES])
509  return val
510
511
512@deprecated(
513    "2016-11-30", "Please switch to tf.summary.audio. Note that "
514    "tf.summary.audio uses the node name instead of the tag. "
515    "This means that TensorFlow will automatically de-duplicate summary "
516    "names based on the scope they are created in.")
517def audio_summary(tag,
518                  tensor,
519                  sample_rate,
520                  max_outputs=3,
521                  collections=None,
522                  name=None):
523  # pylint: disable=line-too-long
524  """Outputs a `Summary` protocol buffer with audio.
525
526  This op is deprecated. Please switch to tf.summary.audio.
527  For an explanation of why this op was deprecated, and information on how to
528  migrate, look
529  ['here'](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/contrib/deprecated/__init__.py)
530
531  The summary has up to `max_outputs` summary values containing audio. The
532  audio is built from `tensor` which must be 3-D with shape `[batch_size,
533  frames, channels]` or 2-D with shape `[batch_size, frames]`. The values are
534  assumed to be in the range of `[-1.0, 1.0]` with a sample rate of
535  `sample_rate`.
536
537  The `tag` argument is a scalar `Tensor` of type `string`.  It is used to
538  build the `tag` of the summary values:
539
540  *  If `max_outputs` is 1, the summary value tag is '*tag*/audio'.
541  *  If `max_outputs` is greater than 1, the summary value tags are
542     generated sequentially as '*tag*/audio/0', '*tag*/audio/1', etc.
543
544  Args:
545    tag: A scalar `Tensor` of type `string`. Used to build the `tag` of the
546      summary values.
547    tensor: A 3-D `float32` `Tensor` of shape `[batch_size, frames, channels]`
548      or a 2-D `float32` `Tensor` of shape `[batch_size, frames]`.
549    sample_rate: A Scalar `float32` `Tensor` indicating the sample rate of the
550      signal in hertz.
551    max_outputs: Max number of batch elements to generate audio for.
552    collections: Optional list of ops.GraphKeys.  The collections to add the
553      summary to.  Defaults to [ops.GraphKeys.SUMMARIES]
554    name: A name for the operation (optional).
555
556  Returns:
557    A scalar `Tensor` of type `string`. The serialized `Summary` protocol
558    buffer.
559  """
560  with ops.name_scope(name, "AudioSummary", [tag, tensor]) as scope:
561    sample_rate = ops.convert_to_tensor(
562        sample_rate, dtype=dtypes.float32, name="sample_rate")
563    val = gen_logging_ops.audio_summary_v2(
564        tag=tag,
565        tensor=tensor,
566        max_outputs=max_outputs,
567        sample_rate=sample_rate,
568        name=scope)
569    _Collect(val, collections, [ops.GraphKeys.SUMMARIES])
570  return val
571
572
573@deprecated("2016-11-30", "Please switch to tf.summary.merge.")
574def merge_summary(inputs, collections=None, name=None):
575  # pylint: disable=line-too-long
576  """Merges summaries.
577
578  This op is deprecated. Please switch to tf.compat.v1.summary.merge, which has
579  identical
580  behavior.
581
582  This op creates a
583  [`Summary`](https://www.tensorflow.org/code/tensorflow/core/framework/summary.proto)
584  protocol buffer that contains the union of all the values in the input
585  summaries.
586
587  When the Op is run, it reports an `InvalidArgument` error if multiple values
588  in the summaries to merge use the same tag.
589
590  Args:
591    inputs: A list of `string` `Tensor` objects containing serialized `Summary`
592      protocol buffers.
593    collections: Optional list of graph collections keys. The new summary op is
594      added to these collections. Defaults to `[GraphKeys.SUMMARIES]`.
595    name: A name for the operation (optional).
596
597  Returns:
598    A scalar `Tensor` of type `string`. The serialized `Summary` protocol
599    buffer resulting from the merging.
600  """
601  with ops.name_scope(name, "MergeSummary", inputs):
602    val = gen_logging_ops.merge_summary(inputs=inputs, name=name)
603    _Collect(val, collections, [])
604  return val
605
606
607@deprecated("2016-11-30", "Please switch to tf.summary.merge_all.")
608def merge_all_summaries(key=ops.GraphKeys.SUMMARIES):
609  """Merges all summaries collected in the default graph.
610
611  This op is deprecated. Please switch to tf.compat.v1.summary.merge_all, which
612  has
613  identical behavior.
614
615  Args:
616    key: `GraphKey` used to collect the summaries.  Defaults to
617      `GraphKeys.SUMMARIES`.
618
619  Returns:
620    If no summaries were collected, returns None.  Otherwise returns a scalar
621    `Tensor` of type `string` containing the serialized `Summary` protocol
622    buffer resulting from the merging.
623  """
624  summary_ops = ops.get_collection(key)
625  if not summary_ops:
626    return None
627  else:
628    return merge_summary(summary_ops)
629
630
631def get_summary_op():
632  """Returns a single Summary op that would run all summaries.
633
634  Either existing one from `SUMMARY_OP` collection or merges all existing
635  summaries.
636
637  Returns:
638    If no summaries were collected, returns None. Otherwise returns a scalar
639    `Tensor` of type `string` containing the serialized `Summary` protocol
640    buffer resulting from the merging.
641  """
642  summary_op = ops.get_collection(ops.GraphKeys.SUMMARY_OP)
643  if summary_op is not None:
644    if summary_op:
645      summary_op = summary_op[0]
646    else:
647      summary_op = None
648  if summary_op is None:
649    summary_op = merge_all_summaries()
650    if summary_op is not None:
651      ops.add_to_collection(ops.GraphKeys.SUMMARY_OP, summary_op)
652  return summary_op
653
654
655@deprecated(
656    "2016-11-30", "Please switch to tf.summary.scalar. Note that "
657    "tf.summary.scalar uses the node name instead of the tag. "
658    "This means that TensorFlow will automatically de-duplicate summary "
659    "names based on the scope they are created in. Also, passing a "
660    "tensor or list of tags to a scalar summary op is no longer "
661    "supported.")
662def scalar_summary(tags, values, collections=None, name=None):
663  # pylint: disable=line-too-long
664  """Outputs a `Summary` protocol buffer with scalar values.
665
666  This ops is deprecated. Please switch to tf.summary.scalar.
667  For an explanation of why this op was deprecated, and information on how to
668  migrate, look
669  ['here'](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/contrib/deprecated/__init__.py)
670
671  The input `tags` and `values` must have the same shape.  The generated
672  summary has a summary value for each tag-value pair in `tags` and `values`.
673
674  Args:
675    tags: A `string` `Tensor`.  Tags for the summaries.
676    values: A real numeric Tensor.  Values for the summaries.
677    collections: Optional list of graph collections keys. The new summary op is
678      added to these collections. Defaults to `[GraphKeys.SUMMARIES]`.
679    name: A name for the operation (optional).
680
681  Returns:
682    A scalar `Tensor` of type `string`. The serialized `Summary` protocol
683    buffer.
684  """
685  with ops.name_scope(name, "ScalarSummary", [tags, values]) as scope:
686    val = gen_logging_ops.scalar_summary(tags=tags, values=values, name=scope)
687    _Collect(val, collections, [ops.GraphKeys.SUMMARIES])
688  return val
689
690
691ops.NotDifferentiable("HistogramSummary")
692ops.NotDifferentiable("ImageSummary")
693ops.NotDifferentiable("AudioSummary")
694ops.NotDifferentiable("AudioSummaryV2")
695ops.NotDifferentiable("MergeSummary")
696ops.NotDifferentiable("ScalarSummary")
697ops.NotDifferentiable("TensorSummary")
698ops.NotDifferentiable("TensorSummaryV2")
699ops.NotDifferentiable("Timestamp")
700