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 16"""Connects all half, float and double tensors to CheckNumericsOp.""" 17 18from tensorflow.python.eager import context 19from tensorflow.python.framework import dtypes 20from tensorflow.python.framework import ops 21from tensorflow.python.ops import array_ops 22from tensorflow.python.ops import control_flow_ops 23from tensorflow.python.util import deprecation 24from tensorflow.python.util import dispatch 25from tensorflow.python.util.tf_export import tf_export 26 27 28@tf_export(v1=["debugging.assert_all_finite", "verify_tensor_all_finite"]) 29@dispatch.add_dispatch_support 30@deprecation.deprecated_endpoints("verify_tensor_all_finite") 31def verify_tensor_all_finite(t=None, msg=None, name=None, x=None, message=None): 32 """Assert that the tensor does not contain any NaN's or Inf's. 33 34 Args: 35 t: Tensor to check. 36 msg: Message to log on failure. 37 name: A name for this operation (optional). 38 x: Alias for t. 39 message: Alias for msg. 40 41 Returns: 42 Same tensor as `t`. 43 """ 44 x = deprecation.deprecated_argument_lookup("x", x, "t", t) 45 message = deprecation.deprecated_argument_lookup( 46 "message", message, "msg", msg) 47 return verify_tensor_all_finite_v2(x, message, name) 48 49 50@tf_export("debugging.assert_all_finite", v1=[]) 51@dispatch.add_dispatch_support 52def verify_tensor_all_finite_v2(x, message, name=None): 53 """Assert that the tensor does not contain any NaN's or Inf's. 54 55 Args: 56 x: Tensor to check. 57 message: Message to log on failure. 58 name: A name for this operation (optional). 59 60 Returns: 61 Same tensor as `x`. 62 """ 63 with ops.name_scope(name, "VerifyFinite", [x]) as name: 64 x = ops.convert_to_tensor(x, name="x") 65 with ops.colocate_with(x): 66 verify_input = array_ops.check_numerics(x, message=message) 67 out = control_flow_ops.with_dependencies([verify_input], x) 68 return out 69 70 71@tf_export(v1=["add_check_numerics_ops"]) 72def add_check_numerics_ops(): 73 """Connect a `tf.debugging.check_numerics` to every floating point tensor. 74 75 `check_numerics` operations themselves are added for each `half`, `float`, 76 or `double` tensor in the current default graph. For all ops in the graph, the 77 `check_numerics` op for all of its (`half`, `float`, or `double`) inputs 78 is guaranteed to run before the `check_numerics` op on any of its outputs. 79 80 Note: This API is not compatible with the use of `tf.cond` or 81 `tf.while_loop`, and will raise a `ValueError` if you attempt to call it 82 in such a graph. 83 84 Returns: 85 A `group` op depending on all `check_numerics` ops added. 86 87 Raises: 88 ValueError: If the graph contains any numeric operations in a control flow 89 structure. 90 RuntimeError: If called with eager execution enabled. 91 92 @compatibility(eager) 93 Not compatible with eager execution. To check for `Inf`s and `NaN`s under 94 eager execution, call `tf.debugging.enable_check_numerics()` once before 95 executing the checked operations. 96 @end_compatibility 97 """ 98 if context.executing_eagerly(): 99 raise RuntimeError( 100 "add_check_numerics_ops() is not compatible with eager execution. " 101 "To check for Inf's and NaN's under eager execution, call " 102 "tf.debugging.enable_check_numerics() once before executing the " 103 "checked operations.") 104 105 check_op = [] 106 # This code relies on the ordering of ops in get_operations(). 107 # The producer of a tensor always comes before that tensor's consumer in 108 # this list. This is true because get_operations() returns ops in the order 109 # added, and an op can only be added after its inputs are added. 110 for op in ops.get_default_graph().get_operations(): 111 for output in op.outputs: 112 if output.dtype in [dtypes.float16, dtypes.float32, dtypes.float64]: 113 if op._get_control_flow_context() is not None: # pylint: disable=protected-access 114 raise ValueError("`tf.add_check_numerics_ops() is not compatible " 115 "with TensorFlow control flow operations such as " 116 "`tf.cond()` or `tf.while_loop()`.") 117 118 message = op.name + ":" + str(output.value_index) 119 with ops.control_dependencies(check_op): 120 check_op = [array_ops.check_numerics(output, message=message)] 121 return control_flow_ops.group(*check_op) 122