[tfdbg2] Fix num_outputs properties when execution or graph op has no output
The previous assumption that `self._output_tensor_ids` is always a tuple is incorrect. It can be `None` for ops without output tensors. Also in this CL: Clarify when properties are `None` and when they are `tuple`s in doc strings of the data objects. PiperOrigin-RevId: 315261796 Change-Id: I398192ba4451e9d8087a2b9e934dff3f561b651a
This commit is contained in:
parent
251a474096
commit
94ce307aa0
@ -308,14 +308,17 @@ class Execution(ExecutionDigest):
|
|||||||
graph_id: ID of the executed FuncGraph (applicable only the execution of a
|
graph_id: ID of the executed FuncGraph (applicable only the execution of a
|
||||||
tf.function). `None` for the eager execution of an individual op.
|
tf.function). `None` for the eager execution of an individual op.
|
||||||
input_tensor_ids: IDs of the input (eager) tensor(s) for this execution, if
|
input_tensor_ids: IDs of the input (eager) tensor(s) for this execution, if
|
||||||
any.
|
any. If the eager execution has no input tensor, this is `None`. Else,
|
||||||
|
this is a `tuple` of `int`s.
|
||||||
output_tensor_ids: IDs of the output (eager) tensor(s) from this execution,
|
output_tensor_ids: IDs of the output (eager) tensor(s) from this execution,
|
||||||
if any.
|
if any. If the eager execution produces no output tensor, this is `None`.
|
||||||
|
Else, this is a `tuple` of `int`s.
|
||||||
debug_tensor_values: Values of the debug tensor(s), applicable only to
|
debug_tensor_values: Values of the debug tensor(s), applicable only to
|
||||||
non-FULL_TENSOR tensor debug mode. A tuple of list of numbers. Each
|
non-FULL_TENSOR tensor debug mode. A tuple of list of numbers. Each
|
||||||
element of the tuple corresponds to an output tensor of the execution.
|
element of the tuple corresponds to an output tensor of the execution.
|
||||||
See documentation of the various TensorDebugModes for the semantics of the
|
See documentation of the various TensorDebugModes for the semantics of the
|
||||||
numbers.
|
numbers. If the eager execution produces no output tensor, this is
|
||||||
|
`None`. Else, this is a `tuple` of `list`s.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
@ -362,7 +365,7 @@ class Execution(ExecutionDigest):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def num_outputs(self):
|
def num_outputs(self):
|
||||||
return len(self._output_tensor_ids)
|
return len(self._output_tensor_ids) if self._output_tensor_ids else 0
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def output_tensor_ids(self):
|
def output_tensor_ids(self):
|
||||||
@ -542,6 +545,8 @@ class GraphOpCreationDigest(BaseDigest):
|
|||||||
op_type: Type name of the op (e.g., "MatMul").
|
op_type: Type name of the op (e.g., "MatMul").
|
||||||
op_name: Name of the op (e.g., "dense_1/MatMul").
|
op_name: Name of the op (e.g., "dense_1/MatMul").
|
||||||
output_tensor_ids: Debugger-generated IDs for the output(s) of the op.
|
output_tensor_ids: Debugger-generated IDs for the output(s) of the op.
|
||||||
|
If the op produces no output tensor, this is `None`. Else, this is a
|
||||||
|
`tuple` of `int`s.
|
||||||
input_names: Names of the input tensors to the op.
|
input_names: Names of the input tensors to the op.
|
||||||
device_name: The name of the device that the op is placed on (if available).
|
device_name: The name of the device that the op is placed on (if available).
|
||||||
host_name: Name of the host on which the op is created.
|
host_name: Name of the host on which the op is created.
|
||||||
@ -588,7 +593,7 @@ class GraphOpCreationDigest(BaseDigest):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def num_outputs(self):
|
def num_outputs(self):
|
||||||
return len(self._output_tensor_ids)
|
return len(self._output_tensor_ids) if self.output_tensor_ids else 0
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def input_names(self):
|
def input_names(self):
|
||||||
|
@ -583,7 +583,7 @@ class DebugEventsWriterTest(dumping_callback_test_lib.DumpingCallbackTestBase,
|
|||||||
self.assertEqual(traces[-1].op_name, "Op_%d" % (expected_end - 1))
|
self.assertEqual(traces[-1].op_name, "Op_%d" % (expected_end - 1))
|
||||||
|
|
||||||
|
|
||||||
class DataObjectsTest(test_util.TensorFlowTestCase):
|
class DataObjectsTest(test_util.TensorFlowTestCase, parameterized.TestCase):
|
||||||
|
|
||||||
def jsonRoundTripCheck(self, obj):
|
def jsonRoundTripCheck(self, obj):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
@ -660,6 +660,22 @@ class DataObjectsTest(test_util.TensorFlowTestCase):
|
|||||||
self.assertIsNone(json["output_tensor_ids"])
|
self.assertIsNone(json["output_tensor_ids"])
|
||||||
self.assertIsNone(json["debug_tensor_values"])
|
self.assertIsNone(json["debug_tensor_values"])
|
||||||
|
|
||||||
|
@parameterized.named_parameters(
|
||||||
|
("EmptyList", []),
|
||||||
|
("None", None),
|
||||||
|
)
|
||||||
|
def testExecutionWithNoOutputTensorsReturnsZeroForNumOutputs(
|
||||||
|
self, output_tensor_ids):
|
||||||
|
execution = debug_events_reader.Execution(
|
||||||
|
debug_events_reader.ExecutionDigest(1234, 5678, "FooOp"),
|
||||||
|
"localhost", ("a1", "b2"),
|
||||||
|
debug_event_pb2.TensorDebugMode.FULL_HEALTH,
|
||||||
|
graph_id="abcd",
|
||||||
|
input_tensor_ids=[13, 37],
|
||||||
|
output_tensor_ids=output_tensor_ids,
|
||||||
|
debug_tensor_values=None)
|
||||||
|
self.assertEqual(execution.num_outputs, 0)
|
||||||
|
|
||||||
def testDebuggedDeviceToJons(self):
|
def testDebuggedDeviceToJons(self):
|
||||||
debugged_device = debug_events_reader.DebuggedDevice("/TPU:3", 4)
|
debugged_device = debug_events_reader.DebuggedDevice("/TPU:3", 4)
|
||||||
self.assertEqual(debugged_device.to_json(), {
|
self.assertEqual(debugged_device.to_json(), {
|
||||||
@ -697,6 +713,24 @@ class DataObjectsTest(test_util.TensorFlowTestCase):
|
|||||||
"inner_graph_ids": ["c2d3", "c2d3e4"],
|
"inner_graph_ids": ["c2d3", "c2d3e4"],
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@parameterized.named_parameters(
|
||||||
|
("EmptyList", []),
|
||||||
|
("None", None),
|
||||||
|
)
|
||||||
|
def testGraphOpDigestWithNoOutpusReturnsNumOutputsZero(
|
||||||
|
self, output_tensor_ids):
|
||||||
|
op_creation_digest = debug_events_reader.GraphOpCreationDigest(
|
||||||
|
1234,
|
||||||
|
5678,
|
||||||
|
"deadbeef",
|
||||||
|
"FooOp",
|
||||||
|
"Model_1/Foo_2",
|
||||||
|
output_tensor_ids,
|
||||||
|
"machine.cluster", ("a1", "a2"),
|
||||||
|
input_names=None,
|
||||||
|
device_name=None)
|
||||||
|
self.assertEqual(op_creation_digest.num_outputs, 0)
|
||||||
|
|
||||||
def testGraphOpCreationDigestNoInputNoDeviceNameToJson(self):
|
def testGraphOpCreationDigestNoInputNoDeviceNameToJson(self):
|
||||||
op_creation_digest = debug_events_reader.GraphOpCreationDigest(
|
op_creation_digest = debug_events_reader.GraphOpCreationDigest(
|
||||||
1234,
|
1234,
|
||||||
|
Loading…
Reference in New Issue
Block a user