Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/tensorflow/python/debug/cli/evaluator.py: 24%
49 statements
« prev ^ index » next coverage.py v7.4.0, created at 2024-01-03 07:57 +0000
« prev ^ index » next coverage.py v7.4.0, created at 2024-01-03 07:57 +0000
1# Copyright 2017 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"""Library for arbitrary expression evaluation based on a debugger data dump."""
16import re
18import numpy as np # pylint: disable=unused-import
20from tensorflow.python.debug.lib import debug_data
22_DUMP_TENSOR_PATTERN = re.compile(r"`.*?`")
23_DEVICE_NAME_PREFIX_PATTERN = re.compile(
24 r"/job:(\w)+/replica:(\d)+/task:(\d)+/(\w)+:(\d)+:")
25_EXEC_INDEX_SUFFIX_PATTERN = re.compile(r"\[(\d)*\]$")
27_DEFAULT_DEBUG_OP = "DebugIdentity"
30def _parse_debug_tensor_name(debug_tensor_name):
31 # pylint: disable=line-too-long
32 """Parse a debug tensor name in a to-be-evaluated expression.
34 Args:
35 debug_tensor_name: name of the debug tensor, with or without
36 device name as a prefix, with or without debug op, with or
37 without '[<exec_index>]' as a suffix.
38 E.g., without device name prefix, without debug op suffix:
39 "hidden_0/MatMul:0"
40 E.g., with device name prefix:
41 "/job:worker/replica:0/task:1/gpu:0:hidden_0/MatMul:0"
42 E.g., with debug op suffix:
43 "hidden_0/MatMul:0:DebugNumericSummary"
44 E.g., with device name prefix and debug op suffix:
45 "/job:worker/replica:0/task:1/gpu:0:hidden_0/MatMul:0:DebugNumericSummary"
46 E.g., with device name prefix, debug op and an exec index:
47 "/job:worker/replica:0/task:1/gpu:0:hidden_0/MatMul:0:DebugNumericSummary[1]"
49 Returns:
50 device_name: If device name prefix exists, the device name; otherwise,
51 `None`.
52 node_name: Name of the node.
53 output_slot: Output slot index as an `int`.
54 debug_op: If the debug op suffix exists, the debug op name; otherwise,
55 `None`.
56 exec_index: Execution index (applicable to cases in which a debug tensor
57 is computed multiple times in a `tf.Session.run` call, e.g., due to
58 `tf.while_loop`). If the exec_index suffix does not exist, this value
59 defaults to `0`.
61 Raises:
62 ValueError: If the input `debug_tensor_name` is malformed.
63 """
64 # pylint: enable=line-too-long
65 device_prefix_match = re.match(_DEVICE_NAME_PREFIX_PATTERN, debug_tensor_name)
66 if device_prefix_match:
67 device_name = debug_tensor_name[
68 device_prefix_match.start() : device_prefix_match.end() - 1]
69 debug_tensor_name = debug_tensor_name[device_prefix_match.end():]
70 else:
71 device_name = None
73 split_items = debug_tensor_name.split(":")
74 if len(split_items) not in (2, 3):
75 raise ValueError(
76 "The debug tensor name in the to-be-evaluated expression is malformed: "
77 "'%s'" % debug_tensor_name)
78 # TODO(cais): Provide examples of good debug tensor names in the error
79 # message.
81 exec_index_match = re.search(_EXEC_INDEX_SUFFIX_PATTERN, split_items[-1])
82 if exec_index_match:
83 exec_index = int(split_items[-1][
84 exec_index_match.start() + 1 : exec_index_match.end() - 1])
85 split_items[-1] = split_items[-1][:exec_index_match.start()]
86 else:
87 exec_index = 0
89 if len(split_items) == 2:
90 node_name = split_items[0]
91 output_slot = int(split_items[1])
92 debug_op = _DEFAULT_DEBUG_OP
93 else:
94 split_items = debug_tensor_name.split(":")
95 node_name = split_items[0]
96 output_slot = int(split_items[1])
97 debug_op = split_items[2]
99 return device_name, node_name, output_slot, debug_op, exec_index
102class ExpressionEvaluator(object):
103 """Evaluates Python expressions using debug tensor values from a dump."""
105 def __init__(self, dump):
106 """Constructor of ExpressionEvaluator.
108 Args:
109 dump: an instance of `DebugDumpDir`.
110 """
111 self._dump = dump
112 self._cached_tensor_values = {}
114 def evaluate(self, expression):
115 """Parse an expression.
117 Args:
118 expression: the expression to be parsed.
120 Returns:
121 The result of the evaluation.
123 Raises:
124 ValueError: If the value of one or more of the debug tensors in the
125 expression are not available.
126 """
127 dump_tensors_iter = re.finditer(_DUMP_TENSOR_PATTERN, expression)
128 rewritten_expression = expression
129 for match in reversed(list(dump_tensors_iter)):
130 tensor_name = match.group(0)[1:-1].strip()
131 device_name, node_name, output_slot, debug_op, exec_index = (
132 _parse_debug_tensor_name(tensor_name))
133 if tensor_name not in self._cached_tensor_values:
134 try:
135 value = self._dump.get_tensors(
136 node_name, output_slot, debug_op,
137 device_name=device_name)[exec_index]
138 except debug_data.WatchKeyDoesNotExistInDebugDumpDirError:
139 raise ValueError(
140 "Eval failed due to the value of %s:%d:DebugIdentity being "
141 "unavailable" % (node_name, output_slot))
142 self._cached_tensor_values[tensor_name] = value
143 rewritten_expression = (
144 rewritten_expression[:match.start(0)] +
145 "self._cached_tensor_values['" + tensor_name + "']" +
146 rewritten_expression[match.end(0):])
148 return eval(rewritten_expression) # pylint: disable=eval-used