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];