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