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