You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tvm.apache.org by ar...@apache.org on 2021/05/03 17:17:28 UTC
[tvm] branch main updated: [Graph Executor Debugger] Fix parameter
dump (#7903)
This is an automated email from the ASF dual-hosted git repository.
areusch pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tvm.git
The following commit(s) were added to refs/heads/main by this push:
new 8c56ce3 [Graph Executor Debugger] Fix parameter dump (#7903)
8c56ce3 is described below
commit 8c56ce3b9076e1b7e0f448929eacfe57852b16fb
Author: Mehrdad Hessar <mh...@octoml.ai>
AuthorDate: Mon May 3 10:17:05 2021 -0700
[Graph Executor Debugger] Fix parameter dump (#7903)
* remove debug mode
* reformat
* format
* address comments
* add single call for all layers
* fix test
* revert
* address comments
* address comments
* fix rerun node
* fix error
* format
* raise error on array()
* fix java
* Revert "fix java"
This reverts commit c4cf952dbc5c9c32d65ef0ca05d6ecbb5c06d5aa.
* bring back for java api
* fix error
* cleanup
* format
* rm redundancy
* add last execution track
* trigger build
* address comments
* format
* fix name overlap
* Trigger Build
* trigger build
* trigger
* trigger
---
python/tvm/contrib/debugger/debug_executor.py | 73 ++++++++++++++++------
python/tvm/contrib/debugger/debug_result.py | 20 ++++--
python/tvm/runtime/ndarray.py | 3 +
.../graph_executor/debug/graph_executor_debug.cc | 70 +++++++++++++++++----
4 files changed, 128 insertions(+), 38 deletions(-)
diff --git a/python/tvm/contrib/debugger/debug_executor.py b/python/tvm/contrib/debugger/debug_executor.py
index 1a1696b..dc04335 100644
--- a/python/tvm/contrib/debugger/debug_executor.py
+++ b/python/tvm/contrib/debugger/debug_executor.py
@@ -19,11 +19,11 @@
import os
import tempfile
import shutil
+import logging
import tvm._ffi
from tvm._ffi.base import string_types
from tvm.contrib import graph_executor
-from tvm.runtime.ndarray import array
from . import debug_result
_DUMP_ROOT_PREFIX = "tvmdbg_"
@@ -98,8 +98,10 @@ class GraphModuleDebug(graph_executor.GraphModule):
def __init__(self, module, device, graph_json_str, dump_root):
self._dump_root = dump_root
self._dump_path = None
- self._get_output_by_layer = module["get_output_by_layer"]
self._run_individual = module["run_individual"]
+ self._debug_get_output = module["debug_get_output"]
+ self._execute_node = module["execute_node"]
+ self._get_node_output = module["get_node_output"]
self._profile = module["profile"]
graph_executor.GraphModule.__init__(self, module)
self._create_debug_env(graph_json_str, device)
@@ -170,19 +172,51 @@ class GraphModuleDebug(graph_executor.GraphModule):
# init the debug dumping environment
self.debug_datum = debug_result.DebugResult(graph_json, self._dump_path)
+ def _execute_next_node(self, node_index, output_index):
+ """Execute node assuming all previous nodes has been executed.
+ Return the output of this node.
+
+ Parameters
+ ----------
+ node_index : int
+ The node index
+ output_index: int
+ The node output index
+ Return
+ ------
+ output_tensors : Array<NDarray>
+ Array of output tensors
+ """
+ output_tensors = self._execute_next_node_get_output(node_index, output_index)
+ return output_tensors
+
+ def _run_per_layer(self):
+ """Execute up to each node and each debug output will be
+ copied to the buffer.
+
+ """
+ output_tensors = []
+ for i, node in enumerate(self.debug_datum.get_graph_nodes()):
+ self._execute_node(i)
+ num_outputs = self.debug_datum.get_graph_node_output_num(node)
+ for j in range(num_outputs):
+ logging.info(
+ "running node=%d, output_ind=%d, with node_name: %s", i, j, node["name"]
+ )
+ output_tensors.append(self._get_node_output(i, j))
+ self.debug_datum.update_output_tensors(output_tensors)
+
def _run_debug(self):
"""Execute the node specified with index will be executed.
Each debug output will be copied to the buffer
Time consumed for each execution will be set as debug output.
"""
+ # Get timing.
self.debug_datum._time_list = [[float(t)] for t in self.run_individual(10, 1, 1)]
- for i, node in enumerate(self.debug_datum.get_graph_nodes()):
- num_outputs = self.debug_datum.get_graph_node_output_num(node)
- for j in range(num_outputs):
- out_tensor = self._get_output_by_layer(i, j)
- out_tensor = array(out_tensor)
- self.debug_datum._output_tensor_list.append(out_tensor)
+
+ # Get outputs.
+ self._run_per_layer()
def debug_get_output(self, node, out=None):
"""Run graph up to node and get the output to out
@@ -196,20 +230,19 @@ class GraphModuleDebug(graph_executor.GraphModule):
The output array container
"""
if isinstance(node, str):
- output_tensors = self.debug_datum.get_output_tensors()
- try:
- out = output_tensors[node]
- except KeyError:
- node_list = output_tensors.keys()
- raise RuntimeError(
- "Node " + node + " not found, available nodes are: " + str(node_list) + "."
- )
+ node_index = None
+ for i, graph_node in enumerate(self.debug_datum.get_graph_nodes()):
+ if graph_node["name"] == node:
+ node_index = i
+ break
+ else:
+ raise AttributeError(f"Could not find a node named {node} in this graph.")
elif isinstance(node, int):
- output_tensors = self.debug_datum._output_tensor_list
- out = output_tensors[node]
+ node_index = node
else:
- raise RuntimeError("Require node index or name only.")
- return out
+ raise RuntimeError(f"Require node index or name only.")
+
+ self._debug_get_output(node_index, out)
def run(self, **input_dict):
"""Run forward execution of the graph with debug
diff --git a/python/tvm/contrib/debugger/debug_result.py b/python/tvm/contrib/debugger/debug_result.py
index f58947f..57c6851 100644
--- a/python/tvm/contrib/debugger/debug_result.py
+++ b/python/tvm/contrib/debugger/debug_result.py
@@ -21,7 +21,6 @@ import os
import numpy as np
import tvm
-
GRAPH_DUMP_FILE_NAME = "_tvmdbg_graph_dump.json"
CHROME_TRACE_FILE_NAME = "_tvmdbg_execution_trace.json"
@@ -125,18 +124,29 @@ class DebugResult(object):
eid += 1
return output_tensors
+ def update_output_tensors(self, tensors):
+ """Update output tensors list
+
+ Parameters
+ ----------
+ tensors : list[NDArray]
+ """
+ if not isinstance(tensors, list):
+ AttributeError("tensors with incorrect type.")
+
+ for output_array in tensors:
+ self._output_tensor_list.append(output_array)
+
def dump_output_tensor(self):
"""Dump the outputs to a temporary folder, the tensors are in numpy format"""
# cleanup existing tensors before dumping
self._cleanup_tensors()
eid = 0
- order = 0
output_tensors = {}
- for node, time in zip(self._nodes_list, self._time_list):
+ for node in self._nodes_list:
num_outputs = self.get_graph_node_output_num(node)
for j in range(num_outputs):
- order += time[0]
- key = node["name"] + "_" + str(j) + "__" + str(order)
+ key = node["name"] + "____" + str(j)
output_tensors[key] = self._output_tensor_list[eid]
eid += 1
diff --git a/python/tvm/runtime/ndarray.py b/python/tvm/runtime/ndarray.py
index 1b0f130..68735e0 100644
--- a/python/tvm/runtime/ndarray.py
+++ b/python/tvm/runtime/ndarray.py
@@ -520,6 +520,9 @@ def array(arr, device=cpu(0)):
ret : NDArray
The created array
"""
+ if isinstance(arr, tvm.ir.container.Array):
+ raise AttributeError("arr is an instance of", type(arr))
+
if not isinstance(arr, (np.ndarray, NDArray)):
arr = np.array(arr)
return empty(arr.shape, arr.dtype, device).copyfrom(arr)
diff --git a/src/runtime/graph_executor/debug/graph_executor_debug.cc b/src/runtime/graph_executor/debug/graph_executor_debug.cc
index a146487..a1a689c 100644
--- a/src/runtime/graph_executor/debug/graph_executor_debug.cc
+++ b/src/runtime/graph_executor/debug/graph_executor_debug.cc
@@ -179,13 +179,6 @@ class GraphExecutorDebug : public GraphExecutor {
}
/*!
- * \brief Run each operation and get the output.
- * \param index The index of op which needs to be returned.
- * \param eid The Entry id of the op.
- */
- NDArray GetOutputByLayer(int index, int eid) { return data_entry_[entry_id(index, eid)]; }
-
- /*!
* \brief GetFunction Get the function based on input.
* \param name The function which needs to be invoked.
* \param sptr_to_self Packed function pointer.
@@ -208,9 +201,54 @@ class GraphExecutorDebug : public GraphExecutor {
}
/*!
+ * \brief Execute index-th node in the network.
+ *
+ * This method will do a partial run of the graph
+ * up to index-th node.
+ *
+ * \param node: The index of the node.
+ */
+ void ExecuteNode(int node) {
+ ICHECK_LT(static_cast<size_t>(node), op_execs_.size());
+
+ int start_ind;
+ int end_ind;
+ if (node < last_executed_node_) {
+ start_ind = 0;
+ end_ind = node;
+ } else if (node > last_executed_node_) {
+ start_ind = last_executed_node_ + 1;
+ end_ind = node;
+ } else {
+ return;
+ }
+
+ for (int i = start_ind; i <= end_ind; i++) {
+ if (op_execs_[i]) op_execs_[i]();
+ }
+ last_executed_node_ = end_ind;
+ }
+
+ /*!
+ * \brief Returns index-th output of node.
+ *
+ * This method will return index-th out_ind output
+ * of index-th node in the network.
+ *
+ * \param node: The index of the node.
+ * \param out_ind: The index of the output.
+ * \return Output array.
+ */
+ NDArray GetNodeOutput(int node, int out_ind) {
+ ICHECK_EQ(node, last_executed_node_);
+ ICHECK_LT(entry_id(node, out_ind), data_entry_.size());
+ return data_entry_[entry_id(node, out_ind)].CopyTo({kDLCPU, 0});
+ }
+
+ /*!
* \brief Copy index-th node to data_out.
*
- * This method will do a partial run of the the graph
+ * This method will do a partial run of the graph
* from begining upto the index-th node and return output of index-th node.
* This is costly operation and suggest to use only for debug porpose.
*
@@ -272,6 +310,9 @@ class GraphExecutorDebug : public GraphExecutor {
prof.Stop();
return prof.Report();
}
+
+ private:
+ int last_executed_node_ = -1;
};
/*!
@@ -282,11 +323,7 @@ class GraphExecutorDebug : public GraphExecutor {
PackedFunc GraphExecutorDebug::GetFunction(const std::string& name,
const ObjectPtr<Object>& sptr_to_self) {
// return member functions during query.
- if (name == "get_output_by_layer") {
- return PackedFunc([sptr_to_self, this](TVMArgs args, TVMRetValue* rv) {
- *rv = this->GetOutputByLayer(args[0], args[1]);
- });
- } else if (name == "debug_get_output") {
+ if (name == "debug_get_output") {
return PackedFunc([sptr_to_self, this](TVMArgs args, TVMRetValue* rv) {
if (String::CanConvertFrom(args[0])) {
this->DebugGetNodeOutput(this->GetNodeIndex(args[0]), args[1]);
@@ -294,6 +331,13 @@ PackedFunc GraphExecutorDebug::GetFunction(const std::string& name,
this->DebugGetNodeOutput(args[0], args[1]);
}
});
+ } else if (name == "execute_node") {
+ return PackedFunc(
+ [sptr_to_self, this](TVMArgs args, TVMRetValue* rv) { this->ExecuteNode(args[0]); });
+ } else if (name == "get_node_output") {
+ return PackedFunc([sptr_to_self, this](TVMArgs args, TVMRetValue* rv) {
+ *rv = this->GetNodeOutput(args[0], args[1]);
+ });
} else if (name == "run_individual") {
return PackedFunc([sptr_to_self, this](TVMArgs args, TVMRetValue* rv) {
int number = args[0];