You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tvm.apache.org by GitBox <gi...@apache.org> on 2021/04/23 00:11:48 UTC

[GitHub] [tvm] tkonolige commented on a change in pull request #7903: [Graph Executor Debugger] Fix parameter dump

tkonolige commented on a change in pull request #7903:
URL: https://github.com/apache/tvm/pull/7903#discussion_r618826620



##########
File path: python/tvm/contrib/debugger/debug_executor.py
##########
@@ -170,22 +173,74 @@ def _create_debug_env(self, graph_json, device):
         # init the debug dumping environment
         self.debug_datum = debug_result.DebugResult(graph_json, self._dump_path)
 
+    def _execute_next_node(self, node_index, entry_id):
+        """Execute node assuming all previous nodes has been executed.
+        Return the output of this node.
+
+        Parameters
+        ----------
+        node_index : int
+            The node index
+
+        entry_id : int
+            The entry id.
+        """
+        out_tensor = self._execute_next_node_get_output(node_index, entry_id)
+        return array(out_tensor)
+
+    def _run_per_layer(self):
+        """Execute up to each node and each debug output will be
+        copied to the buffer.
+
+        """
+        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):
+                logging.info("running: output=%d of node_name: %s", j, node["name"])
+                out_tensor = self._execute_next_node(i, j)
+                self.debug_datum._output_tensor_list.append(out_tensor)
+
+    def execute_node(self, node_name):
+        """Execute network up to this node.
+        Return the outputs of this node.
+
+        Parameters
+        ----------
+        node_index : str

Review comment:
       ```suggestion
           node_name : str
   ```

##########
File path: python/tvm/contrib/debugger/debug_executor.py
##########
@@ -170,22 +173,74 @@ def _create_debug_env(self, graph_json, device):
         # init the debug dumping environment
         self.debug_datum = debug_result.DebugResult(graph_json, self._dump_path)
 
+    def _execute_next_node(self, node_index, entry_id):
+        """Execute node assuming all previous nodes has been executed.
+        Return the output of this node.
+
+        Parameters
+        ----------
+        node_index : int
+            The node index
+
+        entry_id : int
+            The entry id.
+        """
+        out_tensor = self._execute_next_node_get_output(node_index, entry_id)
+        return array(out_tensor)
+
+    def _run_per_layer(self):
+        """Execute up to each node and each debug output will be
+        copied to the buffer.
+
+        """
+        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):
+                logging.info("running: output=%d of node_name: %s", j, node["name"])
+                out_tensor = self._execute_next_node(i, j)
+                self.debug_datum._output_tensor_list.append(out_tensor)
+
+    def execute_node(self, node_name):
+        """Execute network up to this node.
+        Return the outputs of this node.
+
+        Parameters
+        ----------
+        node_index : str
+            The node name
+        """
+        node_index = None
+        selected_node = None
+        for i, node in enumerate(self.debug_datum.get_graph_nodes()):
+            if node["name"] == node_name:
+                selected_node = node
+                node_index = i
+                break
+        if not node_index:
+            raise AttributeError("Node name is not valid.")

Review comment:
       ```suggestion
               raise AttributeError(f"Could not find a node named {node_name} in this graph.")
   ```

##########
File path: python/tvm/contrib/debugger/debug_executor.py
##########
@@ -170,22 +173,74 @@ def _create_debug_env(self, graph_json, device):
         # init the debug dumping environment
         self.debug_datum = debug_result.DebugResult(graph_json, self._dump_path)
 
+    def _execute_next_node(self, node_index, entry_id):
+        """Execute node assuming all previous nodes has been executed.
+        Return the output of this node.
+
+        Parameters
+        ----------
+        node_index : int
+            The node index
+
+        entry_id : int
+            The entry id.
+        """
+        out_tensor = self._execute_next_node_get_output(node_index, entry_id)
+        return array(out_tensor)
+
+    def _run_per_layer(self):
+        """Execute up to each node and each debug output will be
+        copied to the buffer.
+
+        """
+        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):
+                logging.info("running: output=%d of node_name: %s", j, node["name"])
+                out_tensor = self._execute_next_node(i, j)
+                self.debug_datum._output_tensor_list.append(out_tensor)
+
+    def execute_node(self, node_name):
+        """Execute network up to this node.
+        Return the outputs of this node.
+
+        Parameters
+        ----------
+        node_index : str
+            The node name
+        """
+        node_index = None
+        selected_node = None
+        for i, node in enumerate(self.debug_datum.get_graph_nodes()):
+            if node["name"] == node_name:
+                selected_node = node
+                node_index = i
+                break
+        if not node_index:
+            raise AttributeError("Node name is not valid.")
+
+        num_outputs = self.debug_datum.get_graph_node_output_num(selected_node)
+        output_tensors = []
+        for j in range(num_outputs):
+            out = self._execute_node_get_output(node_index, j)

Review comment:
       `_execute_node_get_output` should return all of the outputs instead of making you index into them. This way we can avoid re-executing for each output.

##########
File path: src/runtime/graph_executor/debug/graph_executor_debug.cc
##########
@@ -208,25 +201,70 @@ class GraphExecutorDebug : public GraphExecutor {
   }
 
   /*!
-   * \brief Copy index-th node to data_out.
+   * \brief Get number of outputs of the node.
+   * \param index The index of the node.
+   * \return The number of outputs.
+   */
+  size_t GetNodeNumOfOutputs(size_t index) {
+    if (nodes_[index].op_type != "tvm_op") return 1;
+    return static_cast<size_t>(nodes_[index].param.num_outputs);
+  }
+
+  /*!
+   * \brief Execute network to a specific node and return result.
    *
    * This method will do a partial run of the 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.
    *
-   * \param index: The  index of the node.
-   * \param data_out the node data.
+   * \param index: The index of the node.
+   * \param eid The Entry id of the op.
+   * \return Node output array.
    */
-  void DebugGetNodeOutput(int index, DLTensor* data_out) {
+  NDArray ExecuteNodeGetOutput(int index, int eid) {
     ICHECK_LT(static_cast<size_t>(index), op_execs_.size());
-    uint32_t eid = index;
 
-    for (size_t i = 0; i < op_execs_.size(); ++i) {
+    for (size_t i = 0; i <= static_cast<size_t>(index); i++) {
       if (op_execs_[i]) op_execs_[i]();
-      if (static_cast<int>(i) == index) break;
     }
 
-    data_entry_[eid].CopyTo(data_out);
+    return data_entry_[entry_id(index, eid)];
+  }
+
+  /*!
+   * \brief Execute next node in the network.
+   *
+   * This method will execute next node assuming
+   * previous nodes has been executed and return output of index-th node.
+   *
+   * \param index: The index of the node.
+   * \param eid The Entry id of the op.
+   * \return Node output array.
+   */
+  NDArray ExecuteNextNodeGetOutput(int index, int eid) {
+    ICHECK_LT(static_cast<size_t>(index), op_execs_.size());
+    if (op_execs_[index]) op_execs_[index]();
+    return data_entry_[entry_id(index, eid)];
+  }
+
+  /*!
+   * \brief Execute full network and store each layer outputs.
+   *
+   * This method will execute a full network and store layer
+   * outputs along execution.
+   *
+   * \return All node outputs.
+   */
+  Array<NDArray> RunAndGetLayersOutputs() {

Review comment:
       This function should return an `Array<Array<NDArray>>` where the outer node corresponds to the layer and the inner array is that layers outputs.

##########
File path: python/tvm/contrib/debugger/debug_executor.py
##########
@@ -170,22 +173,74 @@ def _create_debug_env(self, graph_json, device):
         # init the debug dumping environment
         self.debug_datum = debug_result.DebugResult(graph_json, self._dump_path)
 
+    def _execute_next_node(self, node_index, entry_id):
+        """Execute node assuming all previous nodes has been executed.
+        Return the output of this node.
+
+        Parameters
+        ----------
+        node_index : int
+            The node index
+
+        entry_id : int
+            The entry id.
+        """
+        out_tensor = self._execute_next_node_get_output(node_index, entry_id)
+        return array(out_tensor)
+
+    def _run_per_layer(self):
+        """Execute up to each node and each debug output will be
+        copied to the buffer.
+
+        """
+        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):
+                logging.info("running: output=%d of node_name: %s", j, node["name"])
+                out_tensor = self._execute_next_node(i, j)
+                self.debug_datum._output_tensor_list.append(out_tensor)
+
+    def execute_node(self, node_name):
+        """Execute network up to this node.
+        Return the outputs of this node.
+
+        Parameters
+        ----------
+        node_index : str
+            The node name
+        """
+        node_index = None
+        selected_node = None
+        for i, node in enumerate(self.debug_datum.get_graph_nodes()):
+            if node["name"] == node_name:
+                selected_node = node
+                node_index = i
+                break
+        if not node_index:
+            raise AttributeError("Node name is not valid.")
+
+        num_outputs = self.debug_datum.get_graph_node_output_num(selected_node)
+        output_tensors = []
+        for j in range(num_outputs):
+            out = self._execute_node_get_output(node_index, j)
+            out = array(out)
+            output_tensors.append(out)
+        return 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):

Review comment:
       Let's replace `debug_get_output` with `execute_node`. (Rename `execute_node` to `debug_get_output`).

##########
File path: python/tvm/contrib/debugger/debug_executor.py
##########
@@ -170,22 +173,74 @@ def _create_debug_env(self, graph_json, device):
         # init the debug dumping environment
         self.debug_datum = debug_result.DebugResult(graph_json, self._dump_path)
 
+    def _execute_next_node(self, node_index, entry_id):
+        """Execute node assuming all previous nodes has been executed.
+        Return the output of this node.
+
+        Parameters
+        ----------
+        node_index : int
+            The node index
+
+        entry_id : int
+            The entry id.
+        """
+        out_tensor = self._execute_next_node_get_output(node_index, entry_id)
+        return array(out_tensor)
+
+    def _run_per_layer(self):
+        """Execute up to each node and each debug output will be
+        copied to the buffer.
+
+        """
+        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):
+                logging.info("running: output=%d of node_name: %s", j, node["name"])
+                out_tensor = self._execute_next_node(i, j)
+                self.debug_datum._output_tensor_list.append(out_tensor)
+
+    def execute_node(self, node_name):
+        """Execute network up to this node.
+        Return the outputs of this node.
+
+        Parameters
+        ----------
+        node_index : str
+            The node name
+        """
+        node_index = None
+        selected_node = None
+        for i, node in enumerate(self.debug_datum.get_graph_nodes()):
+            if node["name"] == node_name:
+                selected_node = node
+                node_index = i
+                break
+        if not node_index:
+            raise AttributeError("Node name is not valid.")
+
+        num_outputs = self.debug_datum.get_graph_node_output_num(selected_node)
+        output_tensors = []
+        for j in range(num_outputs):
+            out = self._execute_node_get_output(node_index, j)
+            out = array(out)

Review comment:
       Is this necessary?

##########
File path: src/runtime/graph_executor/debug/graph_executor_debug.cc
##########
@@ -208,25 +201,70 @@ class GraphExecutorDebug : public GraphExecutor {
   }
 
   /*!
-   * \brief Copy index-th node to data_out.
+   * \brief Get number of outputs of the node.
+   * \param index The index of the node.
+   * \return The number of outputs.
+   */
+  size_t GetNodeNumOfOutputs(size_t index) {

Review comment:
       ```suggestion
     size_t NodeGetNumOutputs(size_t index) {
   ```

##########
File path: python/tvm/contrib/debugger/debug_executor.py
##########
@@ -170,22 +173,74 @@ def _create_debug_env(self, graph_json, device):
         # init the debug dumping environment
         self.debug_datum = debug_result.DebugResult(graph_json, self._dump_path)
 
+    def _execute_next_node(self, node_index, entry_id):
+        """Execute node assuming all previous nodes has been executed.
+        Return the output of this node.
+
+        Parameters
+        ----------
+        node_index : int
+            The node index
+
+        entry_id : int
+            The entry id.
+        """
+        out_tensor = self._execute_next_node_get_output(node_index, entry_id)
+        return array(out_tensor)
+
+    def _run_per_layer(self):
+        """Execute up to each node and each debug output will be
+        copied to the buffer.
+
+        """
+        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):
+                logging.info("running: output=%d of node_name: %s", j, node["name"])
+                out_tensor = self._execute_next_node(i, j)
+                self.debug_datum._output_tensor_list.append(out_tensor)
+
+    def execute_node(self, node_name):

Review comment:
       Document return value.

##########
File path: src/runtime/graph_executor/debug/graph_executor_debug.cc
##########
@@ -208,25 +201,70 @@ class GraphExecutorDebug : public GraphExecutor {
   }
 
   /*!
-   * \brief Copy index-th node to data_out.
+   * \brief Get number of outputs of the node.
+   * \param index The index of the node.
+   * \return The number of outputs.
+   */
+  size_t GetNodeNumOfOutputs(size_t index) {
+    if (nodes_[index].op_type != "tvm_op") return 1;
+    return static_cast<size_t>(nodes_[index].param.num_outputs);
+  }
+
+  /*!
+   * \brief Execute network to a specific node and return result.
    *
    * This method will do a partial run of the 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.
    *
-   * \param index: The  index of the node.
-   * \param data_out the node data.
+   * \param index: The index of the node.
+   * \param eid The Entry id of the op.
+   * \return Node output array.
    */
-  void DebugGetNodeOutput(int index, DLTensor* data_out) {
+  NDArray ExecuteNodeGetOutput(int index, int eid) {

Review comment:
       ```suggestion
     NDArray DebugGetNodeOutput(int index, int eid) {
   ```




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org