1# Copyright 2016 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 16"""Operations for writing summary data, for use in analysis and visualization. 17 18See the [Summaries and 19TensorBoard](https://www.tensorflow.org/guide/summaries_and_tensorboard) guide. 20""" 21 22from __future__ import absolute_import 23from __future__ import division 24from __future__ import print_function 25 26from google.protobuf import json_format as _json_format 27 28# exports Summary, SummaryDescription, Event, TaggedRunMetadata, SessionLog 29# pylint: disable=unused-import 30from tensorflow.core.framework.summary_pb2 import Summary 31from tensorflow.core.framework.summary_pb2 import SummaryDescription 32from tensorflow.core.framework.summary_pb2 import SummaryMetadata as _SummaryMetadata # pylint: enable=unused-import 33from tensorflow.core.util.event_pb2 import Event 34from tensorflow.core.util.event_pb2 import SessionLog 35from tensorflow.core.util.event_pb2 import TaggedRunMetadata 36# pylint: enable=unused-import 37 38from tensorflow.python.distribute import summary_op_util as _distribute_summary_op_util 39from tensorflow.python.eager import context as _context 40from tensorflow.python.framework import constant_op as _constant_op 41from tensorflow.python.framework import dtypes as _dtypes 42from tensorflow.python.framework import ops as _ops 43from tensorflow.python.ops import gen_logging_ops as _gen_logging_ops 44from tensorflow.python.ops import gen_summary_ops as _gen_summary_ops # pylint: disable=unused-import 45from tensorflow.python.ops import summary_op_util as _summary_op_util 46 47# exports FileWriter, FileWriterCache 48# pylint: disable=unused-import 49from tensorflow.python.summary.writer.writer import FileWriter 50from tensorflow.python.summary.writer.writer_cache import FileWriterCache 51# pylint: enable=unused-import 52 53from tensorflow.python.util import compat as _compat 54from tensorflow.python.util.tf_export import tf_export 55 56 57@tf_export(v1=['summary.scalar']) 58def scalar(name, tensor, collections=None, family=None): 59 """Outputs a `Summary` protocol buffer containing a single scalar value. 60 61 The generated Summary has a Tensor.proto containing the input Tensor. 62 63 Args: 64 name: A name for the generated node. Will also serve as the series name in 65 TensorBoard. 66 tensor: A real numeric Tensor containing a single value. 67 collections: Optional list of graph collections keys. The new summary op is 68 added to these collections. Defaults to `[GraphKeys.SUMMARIES]`. 69 family: Optional; if provided, used as the prefix of the summary tag name, 70 which controls the tab name used for display on Tensorboard. 71 72 Returns: 73 A scalar `Tensor` of type `string`. Which contains a `Summary` protobuf. 74 75 Raises: 76 ValueError: If tensor has the wrong shape or type. 77 78 @compatibility(TF2) 79 This API is not compatible with eager execution or `tf.function`. To migrate 80 to TF2, please use `tf.summary.scalar` instead. Please check 81 [Migrating tf.summary usage to 82 TF 2.0](https://www.tensorflow.org/tensorboard/migrate#in_tf_1x) for concrete 83 steps for migration. `tf.summary.scalar` can also log training metrics in 84 Keras, you can check [Logging training metrics in 85 Keras](https://www.tensorflow.org/tensorboard/scalars_and_keras) for detials. 86 87 #### How to Map Arguments 88 89 | TF1 Arg Name | TF2 Arg Name | Note | 90 | :------------ | :-------------- | :------------------------------------- | 91 | `name` | `name` | - | 92 | `tensor` | `data` | - | 93 | - | `step` | Explicit int64-castable monotonic step | 94 : : : value. If omitted, this defaults to : 95 : : : `tf.summary.experimental.get_step()`. : 96 | `collections` | Not Supported | - | 97 | `family` | Removed | Please use `tf.name_scope` instead to | 98 : : : manage summary name prefix. : 99 | - | `description` | Optional long-form `str` description | 100 : : : for the summary. Markdown is supported.: 101 : : : Defaults to empty. : 102 103 @end_compatibility 104 """ 105 if _distribute_summary_op_util.skip_summary(): 106 return _constant_op.constant('') 107 with _summary_op_util.summary_scope( 108 name, family, values=[tensor]) as (tag, scope): 109 val = _gen_logging_ops.scalar_summary(tags=tag, values=tensor, name=scope) 110 _summary_op_util.collect(val, collections, [_ops.GraphKeys.SUMMARIES]) 111 return val 112 113 114@tf_export(v1=['summary.image']) 115def image(name, tensor, max_outputs=3, collections=None, family=None): 116 """Outputs a `Summary` protocol buffer with images. 117 118 The summary has up to `max_outputs` summary values containing images. The 119 images are built from `tensor` which must be 4-D with shape `[batch_size, 120 height, width, channels]` and where `channels` can be: 121 122 * 1: `tensor` is interpreted as Grayscale. 123 * 3: `tensor` is interpreted as RGB. 124 * 4: `tensor` is interpreted as RGBA. 125 126 The images have the same number of channels as the input tensor. For float 127 input, the values are normalized one image at a time to fit in the range 128 `[0, 255]`. `uint8` values are unchanged. The op uses two different 129 normalization algorithms: 130 131 * If the input values are all positive, they are rescaled so the largest one 132 is 255. 133 134 * If any input value is negative, the values are shifted so input value 0.0 135 is at 127. They are then rescaled so that either the smallest value is 0, 136 or the largest one is 255. 137 138 The `tag` in the outputted Summary.Value protobufs is generated based on the 139 name, with a suffix depending on the max_outputs setting: 140 141 * If `max_outputs` is 1, the summary value tag is '*name*/image'. 142 * If `max_outputs` is greater than 1, the summary value tags are 143 generated sequentially as '*name*/image/0', '*name*/image/1', etc. 144 145 Args: 146 name: A name for the generated node. Will also serve as a series name in 147 TensorBoard. 148 tensor: A 4-D `uint8` or `float32` `Tensor` of shape `[batch_size, height, 149 width, channels]` where `channels` is 1, 3, or 4. 150 max_outputs: Max number of batch elements to generate images for. 151 collections: Optional list of ops.GraphKeys. The collections to add the 152 summary to. Defaults to [_ops.GraphKeys.SUMMARIES] 153 family: Optional; if provided, used as the prefix of the summary tag name, 154 which controls the tab name used for display on Tensorboard. 155 156 Returns: 157 A scalar `Tensor` of type `string`. The serialized `Summary` protocol 158 buffer. 159 160 @compatibility(TF2) 161 This API is not compatible with eager execution and `tf.function`. To migrate 162 to TF2, please use `tf.summary.image` instead. Please check 163 [Migrating tf.summary usage to 164 TF 2.0](https://www.tensorflow.org/tensorboard/migrate#in_tf_1x) for concrete 165 steps for migration. 166 167 #### How to Map Arguments 168 169 | TF1 Arg Name | TF2 Arg Name | Note | 170 | :------------ | :-------------- | :------------------------------------- | 171 | `name` | `name` | - | 172 | `tensor` | `data` | - | 173 | - | `step` | Explicit int64-castable monotonic step | 174 : : : value. If omitted, this defaults to : 175 : : : `tf.summary.experimental.get_step()`. : 176 | `max_outputs` | `max_outputs` | - | 177 | `collections` | Not Supported | - | 178 | `family` | Removed | Please use `tf.name_scope` instead | 179 : : : to manage summary name prefix. : 180 | - | `description` | Optional long-form `str` description | 181 : : : for the summary. Markdown is supported.: 182 : : : Defaults to empty. : 183 184 @end_compatibility 185 """ 186 if _distribute_summary_op_util.skip_summary(): 187 return _constant_op.constant('') 188 with _summary_op_util.summary_scope( 189 name, family, values=[tensor]) as (tag, scope): 190 val = _gen_logging_ops.image_summary( 191 tag=tag, tensor=tensor, max_images=max_outputs, name=scope) 192 _summary_op_util.collect(val, collections, [_ops.GraphKeys.SUMMARIES]) 193 return val 194 195 196@tf_export(v1=['summary.histogram']) 197def histogram(name, values, collections=None, family=None): 198 # pylint: disable=line-too-long 199 """Outputs a `Summary` protocol buffer with a histogram. 200 201 Adding a histogram summary makes it possible to visualize your data's 202 distribution in TensorBoard. You can see a detailed explanation of the 203 TensorBoard histogram dashboard 204 [here](https://www.tensorflow.org/get_started/tensorboard_histograms). 205 206 The generated 207 [`Summary`](https://www.tensorflow.org/code/tensorflow/core/framework/summary.proto) 208 has one summary value containing a histogram for `values`. 209 210 This op reports an `InvalidArgument` error if any value is not finite. 211 212 Args: 213 name: A name for the generated node. Will also serve as a series name in 214 TensorBoard. 215 values: A real numeric `Tensor`. Any shape. Values to use to 216 build the histogram. 217 collections: Optional list of graph collections keys. The new summary op is 218 added to these collections. Defaults to `[GraphKeys.SUMMARIES]`. 219 family: Optional; if provided, used as the prefix of the summary tag name, 220 which controls the tab name used for display on Tensorboard. 221 222 Returns: 223 A scalar `Tensor` of type `string`. The serialized `Summary` protocol 224 buffer. 225 226 @compatibility(TF2) 227 This API is not compatible with eager execution and `tf.function`. To migrate 228 to TF2, please use `tf.summary.histogram` instead. Please check 229 [Migrating tf.summary usage to 230 TF 2.0](https://www.tensorflow.org/tensorboard/migrate#in_tf_1x) for concrete 231 steps for migration. 232 233 #### How to Map Arguments 234 235 | TF1 Arg Name | TF2 Arg Name | Note | 236 | :------------ | :-------------- | :------------------------------------- | 237 | `name` | `name` | - | 238 | `values` | `data` | - | 239 | - | `step` | Explicit int64-castable monotonic step | 240 : : : value. If omitted, this defaults to : 241 : : : `tf.summary.experimental.get_step()` : 242 | - | `buckets` | Optional positive `int` specifying | 243 : : : the histogram bucket number. : 244 | `collections` | Not Supported | - | 245 | `family` | Removed | Please use `tf.name_scope` instead | 246 : : : to manage summary name prefix. : 247 | - | `description` | Optional long-form `str` description | 248 : : : for the summary. Markdown is supported.: 249 : : : Defaults to empty. : 250 251 @end_compatibility 252 """ 253 if _distribute_summary_op_util.skip_summary(): 254 return _constant_op.constant('') 255 with _summary_op_util.summary_scope( 256 name, family, values=[values], 257 default_name='HistogramSummary') as (tag, scope): 258 val = _gen_logging_ops.histogram_summary( 259 tag=tag, values=values, name=scope) 260 _summary_op_util.collect(val, collections, [_ops.GraphKeys.SUMMARIES]) 261 return val 262 263 264@tf_export(v1=['summary.audio']) 265def audio(name, tensor, sample_rate, max_outputs=3, collections=None, 266 family=None): 267 # pylint: disable=line-too-long 268 """Outputs a `Summary` protocol buffer with audio. 269 270 The summary has up to `max_outputs` summary values containing audio. The 271 audio is built from `tensor` which must be 3-D with shape `[batch_size, 272 frames, channels]` or 2-D with shape `[batch_size, frames]`. The values are 273 assumed to be in the range of `[-1.0, 1.0]` with a sample rate of 274 `sample_rate`. 275 276 The `tag` in the outputted Summary.Value protobufs is generated based on the 277 name, with a suffix depending on the max_outputs setting: 278 279 * If `max_outputs` is 1, the summary value tag is '*name*/audio'. 280 * If `max_outputs` is greater than 1, the summary value tags are 281 generated sequentially as '*name*/audio/0', '*name*/audio/1', etc 282 283 Args: 284 name: A name for the generated node. Will also serve as a series name in 285 TensorBoard. 286 tensor: A 3-D `float32` `Tensor` of shape `[batch_size, frames, channels]` 287 or a 2-D `float32` `Tensor` of shape `[batch_size, frames]`. 288 sample_rate: A Scalar `float32` `Tensor` indicating the sample rate of the 289 signal in hertz. 290 max_outputs: Max number of batch elements to generate audio for. 291 collections: Optional list of ops.GraphKeys. The collections to add the 292 summary to. Defaults to [_ops.GraphKeys.SUMMARIES] 293 family: Optional; if provided, used as the prefix of the summary tag name, 294 which controls the tab name used for display on Tensorboard. 295 296 Returns: 297 A scalar `Tensor` of type `string`. The serialized `Summary` protocol 298 buffer. 299 300 @compatibility(TF2) 301 This API is not compatible with eager execution or `tf.function`. To migrate 302 to TF2, please use `tf.summary.audio` instead. Please check 303 [Migrating tf.summary usage to 304 TF 2.0](https://www.tensorflow.org/tensorboard/migrate#in_tf_1x) for concrete 305 steps for migration. 306 307 #### How to Map Arguments 308 309 | TF1 Arg Name | TF2 Arg Name | Note | 310 | :------------ | :-------------- | :------------------------------------- | 311 | `name` | `name` | - | 312 | `tensor` | `data` | Input for this argument now must be | 313 : : : three-dimensional `[k, t, c]`, where : 314 : : : `k` is the number of audio clips, `t` : 315 : : : is the number of frames, and `c` is : 316 : : : the number of channels. Two-dimensional: 317 : : : input is no longer supported. : 318 | `sample_rate` | `sample_rate` | - | 319 | - | `step` | Explicit int64-castable monotonic step | 320 : : : value. If omitted, this defaults to : 321 : : : `tf.summary.experimental.get_step()`. : 322 | `max_outputs` | `max_outputs` | - | 323 | `collections` | Not Supported | - | 324 | `family` | Removed | Please use `tf.name_scope` instead to | 325 : : : manage summary name prefix. : 326 | - | `encoding` | Optional constant str for the desired | 327 : : : encoding. Check the docs for : 328 : : : `tf.summary.audio` for latest supported: 329 : : : audio formats. : 330 | - | `description` | Optional long-form `str` description | 331 : : : for the summary. Markdown is supported.: 332 : : : Defaults to empty. : 333 334 @end_compatibility 335 """ 336 if _distribute_summary_op_util.skip_summary(): 337 return _constant_op.constant('') 338 with _summary_op_util.summary_scope( 339 name, family=family, values=[tensor]) as (tag, scope): 340 sample_rate = _ops.convert_to_tensor( 341 sample_rate, dtype=_dtypes.float32, name='sample_rate') 342 val = _gen_logging_ops.audio_summary_v2( 343 tag=tag, tensor=tensor, max_outputs=max_outputs, 344 sample_rate=sample_rate, name=scope) 345 _summary_op_util.collect(val, collections, [_ops.GraphKeys.SUMMARIES]) 346 return val 347 348 349@tf_export(v1=['summary.text']) 350def text(name, tensor, collections=None): 351 """Summarizes textual data. 352 353 Text data summarized via this plugin will be visible in the Text Dashboard 354 in TensorBoard. The standard TensorBoard Text Dashboard will render markdown 355 in the strings, and will automatically organize 1d and 2d tensors into tables. 356 If a tensor with more than 2 dimensions is provided, a 2d subarray will be 357 displayed along with a warning message. (Note that this behavior is not 358 intrinsic to the text summary api, but rather to the default TensorBoard text 359 plugin.) 360 361 Args: 362 name: A name for the generated node. Will also serve as a series name in 363 TensorBoard. 364 tensor: a string-type Tensor to summarize. 365 collections: Optional list of ops.GraphKeys. The collections to add the 366 summary to. Defaults to [_ops.GraphKeys.SUMMARIES] 367 368 Returns: 369 A TensorSummary op that is configured so that TensorBoard will recognize 370 that it contains textual data. The TensorSummary is a scalar `Tensor` of 371 type `string` which contains `Summary` protobufs. 372 373 Raises: 374 ValueError: If tensor has the wrong type. 375 376 @compatibility(TF2) 377 This API is not compatible with eager execution or `tf.function`. To migrate 378 to TF2, please use `tf.summary.text` instead. Please check 379 [Migrating tf.summary usage to 380 TF 2.0](https://www.tensorflow.org/tensorboard/migrate#in_tf_1x) for concrete 381 steps for migration. 382 383 #### How to Map Arguments 384 385 | TF1 Arg Name | TF2 Arg Name | Note | 386 | :------------ | :-------------- | :------------------------------------- | 387 | `name` | `name` | - | 388 | `tensor` | `data` | - | 389 | - | `step` | Explicit int64-castable monotonic step | 390 : : : value. If omitted, this defaults to : 391 : : : `tf.summary.experimental.get_step()`. : 392 | `collections` | Not Supported | - | 393 | - | `description` | Optional long-form `str` description | 394 : : : for the summary. Markdown is supported.: 395 : : : Defaults to empty. : 396 397 @end_compatibility 398 """ 399 if tensor.dtype != _dtypes.string: 400 raise ValueError('Expected tensor %s to have dtype string, got %s' % 401 (tensor.name, tensor.dtype)) 402 403 summary_metadata = _SummaryMetadata( 404 plugin_data=_SummaryMetadata.PluginData(plugin_name='text')) 405 t_summary = tensor_summary( 406 name=name, 407 tensor=tensor, 408 summary_metadata=summary_metadata, 409 collections=collections) 410 return t_summary 411 412 413@tf_export(v1=['summary.tensor_summary']) 414def tensor_summary(name, 415 tensor, 416 summary_description=None, 417 collections=None, 418 summary_metadata=None, 419 family=None, 420 display_name=None): 421 """Outputs a `Summary` protocol buffer with a serialized tensor.proto. 422 423 Args: 424 name: A name for the generated node. If display_name is not set, it will 425 also serve as the tag name in TensorBoard. (In that case, the tag 426 name will inherit tf name scopes.) 427 tensor: A tensor of any type and shape to serialize. 428 summary_description: A long description of the summary sequence. Markdown 429 is supported. 430 collections: Optional list of graph collections keys. The new summary op is 431 added to these collections. Defaults to `[GraphKeys.SUMMARIES]`. 432 summary_metadata: Optional SummaryMetadata proto (which describes which 433 plugins may use the summary value). 434 family: Optional; if provided, used as the prefix of the summary tag, 435 which controls the name used for display on TensorBoard when 436 display_name is not set. 437 display_name: A string used to name this data in TensorBoard. If this is 438 not set, then the node name will be used instead. 439 440 Returns: 441 A scalar `Tensor` of type `string`. The serialized `Summary` protocol 442 buffer. 443 """ 444 445 if summary_metadata is None: 446 summary_metadata = _SummaryMetadata() 447 448 if summary_description is not None: 449 summary_metadata.summary_description = summary_description 450 451 if display_name is not None: 452 summary_metadata.display_name = display_name 453 454 serialized_summary_metadata = summary_metadata.SerializeToString() 455 456 if _distribute_summary_op_util.skip_summary(): 457 return _constant_op.constant('') 458 with _summary_op_util.summary_scope( 459 name, family, values=[tensor]) as (tag, scope): 460 val = _gen_logging_ops.tensor_summary_v2( 461 tensor=tensor, 462 tag=tag, 463 name=scope, 464 serialized_summary_metadata=serialized_summary_metadata) 465 _summary_op_util.collect(val, collections, [_ops.GraphKeys.SUMMARIES]) 466 return val 467 468 469@tf_export(v1=['summary.merge']) 470def merge(inputs, collections=None, name=None): 471 # pylint: disable=line-too-long 472 """Merges summaries. 473 474 This op creates a 475 [`Summary`](https://www.tensorflow.org/code/tensorflow/core/framework/summary.proto) 476 protocol buffer that contains the union of all the values in the input 477 summaries. 478 479 When the Op is run, it reports an `InvalidArgument` error if multiple values 480 in the summaries to merge use the same tag. 481 482 Args: 483 inputs: A list of `string` `Tensor` objects containing serialized `Summary` 484 protocol buffers. 485 collections: Optional list of graph collections keys. The new summary op is 486 added to these collections. Defaults to `[]`. 487 name: A name for the operation (optional). 488 489 Returns: 490 A scalar `Tensor` of type `string`. The serialized `Summary` protocol 491 buffer resulting from the merging. 492 493 Raises: 494 RuntimeError: If called with eager mode enabled. 495 496 @compatibility(TF2) 497 This API is not compatible with eager execution or `tf.function`. To migrate 498 to TF2, this API can be omitted entirely, because in TF2 individual summary 499 ops, like `tf.summary.scalar()`, write directly to the default summary writer 500 if one is active. Thus, it's not necessary to merge summaries or to manually 501 add the resulting merged summary output to the writer. See the usage example 502 shown below. 503 504 For a comprehensive `tf.summary` migration guide, please follow 505 [Migrating tf.summary usage to 506 TF 2.0](https://www.tensorflow.org/tensorboard/migrate#in_tf_1x). 507 508 #### TF1 & TF2 Usage Example 509 510 TF1: 511 512 ```python 513 dist = tf.compat.v1.placeholder(tf.float32, [100]) 514 tf.compat.v1.summary.histogram(name="distribution", values=dist) 515 writer = tf.compat.v1.summary.FileWriter("/tmp/tf1_summary_example") 516 summaries = tf.compat.v1.summary.merge_all() 517 518 sess = tf.compat.v1.Session() 519 for step in range(100): 520 mean_moving_normal = np.random.normal(loc=step, scale=1, size=[100]) 521 summ = sess.run(summaries, feed_dict={dist: mean_moving_normal}) 522 writer.add_summary(summ, global_step=step) 523 ``` 524 525 TF2: 526 527 ```python 528 writer = tf.summary.create_file_writer("/tmp/tf2_summary_example") 529 for step in range(100): 530 mean_moving_normal = np.random.normal(loc=step, scale=1, size=[100]) 531 with writer.as_default(step=step): 532 tf.summary.histogram(name='distribution', data=mean_moving_normal) 533 ``` 534 535 @end_compatibility 536 """ 537 # pylint: enable=line-too-long 538 if _context.executing_eagerly(): 539 raise RuntimeError( 540 'Merging tf.summary.* ops is not compatible with eager execution. ' 541 'Use tf.contrib.summary instead.') 542 if _distribute_summary_op_util.skip_summary(): 543 return _constant_op.constant('') 544 name = _summary_op_util.clean_tag(name) 545 with _ops.name_scope(name, 'Merge', inputs): 546 val = _gen_logging_ops.merge_summary(inputs=inputs, name=name) 547 _summary_op_util.collect(val, collections, []) 548 return val 549 550 551@tf_export(v1=['summary.merge_all']) 552def merge_all(key=_ops.GraphKeys.SUMMARIES, scope=None, name=None): 553 """Merges all summaries collected in the default graph. 554 555 Args: 556 key: `GraphKey` used to collect the summaries. Defaults to 557 `GraphKeys.SUMMARIES`. 558 scope: Optional scope used to filter the summary ops, using `re.match`. 559 name: A name for the operation (optional). 560 561 Returns: 562 If no summaries were collected, returns None. Otherwise returns a scalar 563 `Tensor` of type `string` containing the serialized `Summary` protocol 564 buffer resulting from the merging. 565 566 Raises: 567 RuntimeError: If called with eager execution enabled. 568 569 @compatibility(TF2) 570 This API is not compatible with eager execution or `tf.function`. To migrate 571 to TF2, this API can be omitted entirely, because in TF2 individual summary 572 ops, like `tf.summary.scalar()`, write directly to the default summary writer 573 if one is active. Thus, it's not necessary to merge summaries or to manually 574 add the resulting merged summary output to the writer. See the usage example 575 shown below. 576 577 For a comprehensive `tf.summary` migration guide, please follow 578 [Migrating tf.summary usage to 579 TF 2.0](https://www.tensorflow.org/tensorboard/migrate#in_tf_1x). 580 581 #### TF1 & TF2 Usage Example 582 583 TF1: 584 585 ```python 586 dist = tf.compat.v1.placeholder(tf.float32, [100]) 587 tf.compat.v1.summary.histogram(name="distribution", values=dist) 588 writer = tf.compat.v1.summary.FileWriter("/tmp/tf1_summary_example") 589 summaries = tf.compat.v1.summary.merge_all() 590 591 sess = tf.compat.v1.Session() 592 for step in range(100): 593 mean_moving_normal = np.random.normal(loc=step, scale=1, size=[100]) 594 summ = sess.run(summaries, feed_dict={dist: mean_moving_normal}) 595 writer.add_summary(summ, global_step=step) 596 ``` 597 598 TF2: 599 600 ```python 601 writer = tf.summary.create_file_writer("/tmp/tf2_summary_example") 602 for step in range(100): 603 mean_moving_normal = np.random.normal(loc=step, scale=1, size=[100]) 604 with writer.as_default(step=step): 605 tf.summary.histogram(name='distribution', data=mean_moving_normal) 606 ``` 607 608 @end_compatibility 609 """ 610 if _context.executing_eagerly(): 611 raise RuntimeError( 612 'Merging tf.summary.* ops is not compatible with eager execution. ' 613 'Use tf.contrib.summary instead.') 614 summary_ops = _ops.get_collection(key, scope=scope) 615 if not summary_ops: 616 return None 617 else: 618 return merge(summary_ops, name=name) 619 620 621@tf_export(v1=['summary.get_summary_description']) 622def get_summary_description(node_def): 623 """Given a TensorSummary node_def, retrieve its SummaryDescription. 624 625 When a Summary op is instantiated, a SummaryDescription of associated 626 metadata is stored in its NodeDef. This method retrieves the description. 627 628 Args: 629 node_def: the node_def_pb2.NodeDef of a TensorSummary op 630 631 Returns: 632 a summary_pb2.SummaryDescription 633 634 Raises: 635 ValueError: if the node is not a summary op. 636 637 @compatibility(eager) 638 Not compatible with eager execution. To write TensorBoard 639 summaries under eager execution, use `tf.contrib.summary` instead. 640 @end_compatibility 641 """ 642 643 if node_def.op != 'TensorSummary': 644 raise ValueError("Can't get_summary_description on %s" % node_def.op) 645 description_str = _compat.as_str_any(node_def.attr['description'].s) 646 summary_description = SummaryDescription() 647 _json_format.Parse(description_str, summary_description) 648 return summary_description 649