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 if _distribute_summary_op_util.skip_summary(): 79 return _constant_op.constant('') 80 with _summary_op_util.summary_scope( 81 name, family, values=[tensor]) as (tag, scope): 82 val = _gen_logging_ops.scalar_summary(tags=tag, values=tensor, name=scope) 83 _summary_op_util.collect(val, collections, [_ops.GraphKeys.SUMMARIES]) 84 return val 85 86 87@tf_export(v1=['summary.image']) 88def image(name, tensor, max_outputs=3, collections=None, family=None): 89 """Outputs a `Summary` protocol buffer with images. 90 91 The summary has up to `max_outputs` summary values containing images. The 92 images are built from `tensor` which must be 4-D with shape `[batch_size, 93 height, width, channels]` and where `channels` can be: 94 95 * 1: `tensor` is interpreted as Grayscale. 96 * 3: `tensor` is interpreted as RGB. 97 * 4: `tensor` is interpreted as RGBA. 98 99 The images have the same number of channels as the input tensor. For float 100 input, the values are normalized one image at a time to fit in the range 101 `[0, 255]`. `uint8` values are unchanged. The op uses two different 102 normalization algorithms: 103 104 * If the input values are all positive, they are rescaled so the largest one 105 is 255. 106 107 * If any input value is negative, the values are shifted so input value 0.0 108 is at 127. They are then rescaled so that either the smallest value is 0, 109 or the largest one is 255. 110 111 The `tag` in the outputted Summary.Value protobufs is generated based on the 112 name, with a suffix depending on the max_outputs setting: 113 114 * If `max_outputs` is 1, the summary value tag is '*name*/image'. 115 * If `max_outputs` is greater than 1, the summary value tags are 116 generated sequentially as '*name*/image/0', '*name*/image/1', etc. 117 118 Args: 119 name: A name for the generated node. Will also serve as a series name in 120 TensorBoard. 121 tensor: A 4-D `uint8` or `float32` `Tensor` of shape `[batch_size, height, 122 width, channels]` where `channels` is 1, 3, or 4. 123 max_outputs: Max number of batch elements to generate images for. 124 collections: Optional list of ops.GraphKeys. The collections to add the 125 summary to. Defaults to [_ops.GraphKeys.SUMMARIES] 126 family: Optional; if provided, used as the prefix of the summary tag name, 127 which controls the tab name used for display on Tensorboard. 128 129 Returns: 130 A scalar `Tensor` of type `string`. The serialized `Summary` protocol 131 buffer. 132 """ 133 if _distribute_summary_op_util.skip_summary(): 134 return _constant_op.constant('') 135 with _summary_op_util.summary_scope( 136 name, family, values=[tensor]) as (tag, scope): 137 val = _gen_logging_ops.image_summary( 138 tag=tag, tensor=tensor, max_images=max_outputs, name=scope) 139 _summary_op_util.collect(val, collections, [_ops.GraphKeys.SUMMARIES]) 140 return val 141 142 143@tf_export(v1=['summary.histogram']) 144def histogram(name, values, collections=None, family=None): 145 # pylint: disable=line-too-long 146 """Outputs a `Summary` protocol buffer with a histogram. 147 148 Adding a histogram summary makes it possible to visualize your data's 149 distribution in TensorBoard. You can see a detailed explanation of the 150 TensorBoard histogram dashboard 151 [here](https://www.tensorflow.org/get_started/tensorboard_histograms). 152 153 The generated 154 [`Summary`](https://www.tensorflow.org/code/tensorflow/core/framework/summary.proto) 155 has one summary value containing a histogram for `values`. 156 157 This op reports an `InvalidArgument` error if any value is not finite. 158 159 Args: 160 name: A name for the generated node. Will also serve as a series name in 161 TensorBoard. 162 values: A real numeric `Tensor`. Any shape. Values to use to 163 build the histogram. 164 collections: Optional list of graph collections keys. The new summary op is 165 added to these collections. Defaults to `[GraphKeys.SUMMARIES]`. 166 family: Optional; if provided, used as the prefix of the summary tag name, 167 which controls the tab name used for display on Tensorboard. 168 169 Returns: 170 A scalar `Tensor` of type `string`. The serialized `Summary` protocol 171 buffer. 172 """ 173 if _distribute_summary_op_util.skip_summary(): 174 return _constant_op.constant('') 175 with _summary_op_util.summary_scope( 176 name, family, values=[values], 177 default_name='HistogramSummary') as (tag, scope): 178 val = _gen_logging_ops.histogram_summary( 179 tag=tag, values=values, name=scope) 180 _summary_op_util.collect(val, collections, [_ops.GraphKeys.SUMMARIES]) 181 return val 182 183 184@tf_export(v1=['summary.audio']) 185def audio(name, tensor, sample_rate, max_outputs=3, collections=None, 186 family=None): 187 # pylint: disable=line-too-long 188 """Outputs a `Summary` protocol buffer with audio. 189 190 The summary has up to `max_outputs` summary values containing audio. The 191 audio is built from `tensor` which must be 3-D with shape `[batch_size, 192 frames, channels]` or 2-D with shape `[batch_size, frames]`. The values are 193 assumed to be in the range of `[-1.0, 1.0]` with a sample rate of 194 `sample_rate`. 195 196 The `tag` in the outputted Summary.Value protobufs is generated based on the 197 name, with a suffix depending on the max_outputs setting: 198 199 * If `max_outputs` is 1, the summary value tag is '*name*/audio'. 200 * If `max_outputs` is greater than 1, the summary value tags are 201 generated sequentially as '*name*/audio/0', '*name*/audio/1', etc 202 203 Args: 204 name: A name for the generated node. Will also serve as a series name in 205 TensorBoard. 206 tensor: A 3-D `float32` `Tensor` of shape `[batch_size, frames, channels]` 207 or a 2-D `float32` `Tensor` of shape `[batch_size, frames]`. 208 sample_rate: A Scalar `float32` `Tensor` indicating the sample rate of the 209 signal in hertz. 210 max_outputs: Max number of batch elements to generate audio for. 211 collections: Optional list of ops.GraphKeys. The collections to add the 212 summary to. Defaults to [_ops.GraphKeys.SUMMARIES] 213 family: Optional; if provided, used as the prefix of the summary tag name, 214 which controls the tab name used for display on Tensorboard. 215 216 Returns: 217 A scalar `Tensor` of type `string`. The serialized `Summary` protocol 218 buffer. 219 """ 220 if _distribute_summary_op_util.skip_summary(): 221 return _constant_op.constant('') 222 with _summary_op_util.summary_scope( 223 name, family=family, values=[tensor]) as (tag, scope): 224 sample_rate = _ops.convert_to_tensor( 225 sample_rate, dtype=_dtypes.float32, name='sample_rate') 226 val = _gen_logging_ops.audio_summary_v2( 227 tag=tag, tensor=tensor, max_outputs=max_outputs, 228 sample_rate=sample_rate, name=scope) 229 _summary_op_util.collect(val, collections, [_ops.GraphKeys.SUMMARIES]) 230 return val 231 232 233@tf_export(v1=['summary.text']) 234def text(name, tensor, collections=None): 235 """Summarizes textual data. 236 237 Text data summarized via this plugin will be visible in the Text Dashboard 238 in TensorBoard. The standard TensorBoard Text Dashboard will render markdown 239 in the strings, and will automatically organize 1d and 2d tensors into tables. 240 If a tensor with more than 2 dimensions is provided, a 2d subarray will be 241 displayed along with a warning message. (Note that this behavior is not 242 intrinsic to the text summary api, but rather to the default TensorBoard text 243 plugin.) 244 245 Args: 246 name: A name for the generated node. Will also serve as a series name in 247 TensorBoard. 248 tensor: a string-type Tensor to summarize. 249 collections: Optional list of ops.GraphKeys. The collections to add the 250 summary to. Defaults to [_ops.GraphKeys.SUMMARIES] 251 252 Returns: 253 A TensorSummary op that is configured so that TensorBoard will recognize 254 that it contains textual data. The TensorSummary is a scalar `Tensor` of 255 type `string` which contains `Summary` protobufs. 256 257 Raises: 258 ValueError: If tensor has the wrong type. 259 """ 260 if tensor.dtype != _dtypes.string: 261 raise ValueError('Expected tensor %s to have dtype string, got %s' % 262 (tensor.name, tensor.dtype)) 263 264 summary_metadata = _SummaryMetadata( 265 plugin_data=_SummaryMetadata.PluginData(plugin_name='text')) 266 t_summary = tensor_summary( 267 name=name, 268 tensor=tensor, 269 summary_metadata=summary_metadata, 270 collections=collections) 271 return t_summary 272 273 274@tf_export(v1=['summary.tensor_summary']) 275def tensor_summary(name, 276 tensor, 277 summary_description=None, 278 collections=None, 279 summary_metadata=None, 280 family=None, 281 display_name=None): 282 """Outputs a `Summary` protocol buffer with a serialized tensor.proto. 283 284 Args: 285 name: A name for the generated node. If display_name is not set, it will 286 also serve as the tag name in TensorBoard. (In that case, the tag 287 name will inherit tf name scopes.) 288 tensor: A tensor of any type and shape to serialize. 289 summary_description: A long description of the summary sequence. Markdown 290 is supported. 291 collections: Optional list of graph collections keys. The new summary op is 292 added to these collections. Defaults to `[GraphKeys.SUMMARIES]`. 293 summary_metadata: Optional SummaryMetadata proto (which describes which 294 plugins may use the summary value). 295 family: Optional; if provided, used as the prefix of the summary tag, 296 which controls the name used for display on TensorBoard when 297 display_name is not set. 298 display_name: A string used to name this data in TensorBoard. If this is 299 not set, then the node name will be used instead. 300 301 Returns: 302 A scalar `Tensor` of type `string`. The serialized `Summary` protocol 303 buffer. 304 """ 305 306 if summary_metadata is None: 307 summary_metadata = _SummaryMetadata() 308 309 if summary_description is not None: 310 summary_metadata.summary_description = summary_description 311 312 if display_name is not None: 313 summary_metadata.display_name = display_name 314 315 serialized_summary_metadata = summary_metadata.SerializeToString() 316 317 if _distribute_summary_op_util.skip_summary(): 318 return _constant_op.constant('') 319 with _summary_op_util.summary_scope( 320 name, family, values=[tensor]) as (tag, scope): 321 val = _gen_logging_ops.tensor_summary_v2( 322 tensor=tensor, 323 tag=tag, 324 name=scope, 325 serialized_summary_metadata=serialized_summary_metadata) 326 _summary_op_util.collect(val, collections, [_ops.GraphKeys.SUMMARIES]) 327 return val 328 329 330@tf_export(v1=['summary.merge']) 331def merge(inputs, collections=None, name=None): 332 # pylint: disable=line-too-long 333 """Merges summaries. 334 335 This op creates a 336 [`Summary`](https://www.tensorflow.org/code/tensorflow/core/framework/summary.proto) 337 protocol buffer that contains the union of all the values in the input 338 summaries. 339 340 When the Op is run, it reports an `InvalidArgument` error if multiple values 341 in the summaries to merge use the same tag. 342 343 Args: 344 inputs: A list of `string` `Tensor` objects containing serialized `Summary` 345 protocol buffers. 346 collections: Optional list of graph collections keys. The new summary op is 347 added to these collections. Defaults to `[]`. 348 name: A name for the operation (optional). 349 350 Returns: 351 A scalar `Tensor` of type `string`. The serialized `Summary` protocol 352 buffer resulting from the merging. 353 354 Raises: 355 RuntimeError: If called with eager mode enabled. 356 357 @compatibility(eager) 358 Not compatible with eager execution. To write TensorBoard 359 summaries under eager execution, use `tf.contrib.summary` instead. 360 @end_compatibility 361 """ 362 # pylint: enable=line-too-long 363 if _context.executing_eagerly(): 364 raise RuntimeError( 365 'Merging tf.summary.* ops is not compatible with eager execution. ' 366 'Use tf.contrib.summary instead.') 367 if _distribute_summary_op_util.skip_summary(): 368 return _constant_op.constant('') 369 name = _summary_op_util.clean_tag(name) 370 with _ops.name_scope(name, 'Merge', inputs): 371 val = _gen_logging_ops.merge_summary(inputs=inputs, name=name) 372 _summary_op_util.collect(val, collections, []) 373 return val 374 375 376@tf_export(v1=['summary.merge_all']) 377def merge_all(key=_ops.GraphKeys.SUMMARIES, scope=None, name=None): 378 """Merges all summaries collected in the default graph. 379 380 Args: 381 key: `GraphKey` used to collect the summaries. Defaults to 382 `GraphKeys.SUMMARIES`. 383 scope: Optional scope used to filter the summary ops, using `re.match` 384 385 Returns: 386 If no summaries were collected, returns None. Otherwise returns a scalar 387 `Tensor` of type `string` containing the serialized `Summary` protocol 388 buffer resulting from the merging. 389 390 Raises: 391 RuntimeError: If called with eager execution enabled. 392 393 @compatibility(eager) 394 Not compatible with eager execution. To write TensorBoard 395 summaries under eager execution, use `tf.contrib.summary` instead. 396 @end_compatibility 397 """ 398 if _context.executing_eagerly(): 399 raise RuntimeError( 400 'Merging tf.summary.* ops is not compatible with eager execution. ' 401 'Use tf.contrib.summary instead.') 402 summary_ops = _ops.get_collection(key, scope=scope) 403 if not summary_ops: 404 return None 405 else: 406 return merge(summary_ops, name=name) 407 408 409@tf_export(v1=['summary.get_summary_description']) 410def get_summary_description(node_def): 411 """Given a TensorSummary node_def, retrieve its SummaryDescription. 412 413 When a Summary op is instantiated, a SummaryDescription of associated 414 metadata is stored in its NodeDef. This method retrieves the description. 415 416 Args: 417 node_def: the node_def_pb2.NodeDef of a TensorSummary op 418 419 Returns: 420 a summary_pb2.SummaryDescription 421 422 Raises: 423 ValueError: if the node is not a summary op. 424 425 @compatibility(eager) 426 Not compatible with eager execution. To write TensorBoard 427 summaries under eager execution, use `tf.contrib.summary` instead. 428 @end_compatibility 429 """ 430 431 if node_def.op != 'TensorSummary': 432 raise ValueError("Can't get_summary_description on %s" % node_def.op) 433 description_str = _compat.as_str_any(node_def.attr['description'].s) 434 summary_description = SummaryDescription() 435 _json_format.Parse(description_str, summary_description) 436 return summary_description 437