[graphnode] Remove index from graph node
authorParichay Kapoor <pk.kapoor@samsung.com>
Wed, 4 Aug 2021 03:46:41 +0000 (12:46 +0900)
committerJijoong Moon <jijoong.moon@samsung.com>
Tue, 17 Aug 2021 02:29:39 +0000 (11:29 +0900)
Currently each graph node has two identifiers - name and idx - where
both were unique. This patch removes the idx as the indentifier.
The corresponding functions are also removed.
In order to support fast fetching of nodes, graphcore has a map nodes.

This change revealed a bug with the names in the code. As ini does not
allow case sensitive names, the names from the ini are changed to lower
case. However, input_layers property names were allowed to be
case-sensitive. Further names set by the API were also case sensitive.
This patch forces all such names to be case-insensitive to lowercase.

Signed-off-by: Parichay Kapoor <pk.kapoor@samsung.com>
nntrainer/graph/graph_core.cpp
nntrainer/graph/graph_core.h
nntrainer/graph/graph_node.h
nntrainer/graph/network_graph.cpp
nntrainer/graph/network_graph.h
nntrainer/layers/layer_node.cpp
nntrainer/layers/layer_node.h

index 0413c52ee8ca44d06d0ce6c6c10276033d79a94a..0760467c029124b200d66d09f240a4180b4fb25d 100644 (file)
 namespace nntrainer {
 
 void GraphCore::addGraphNode(std::shared_ptr<GraphNode> node) {
-  node->setIndex(node_list.size());
   node_list.push_back(node);
+  node_map[node->getName()] = node_list.size() - 1;
 }
 
 const std::shared_ptr<GraphNode> &GraphCore::getNode(unsigned int ith) const {
-  if (ith >= size())
-    throw std::invalid_argument("Exceed total number of nodes");
-
-  if (node_list[ith]->getIndex() != ith)
-    throw std::runtime_error("Graph internal index mismatch");
-
-  return node_list[ith];
+  return node_list.at(ith);
 }
 
 const std::shared_ptr<GraphNode> &
 GraphCore::getSortedNode(unsigned int ith) const {
-  if (ith >= Sorted.size())
-    throw std::invalid_argument("Exceed total number of nodes");
-
-  return Sorted[ith];
+  return Sorted.at(ith);
 }
 
 void GraphCore::makeAdjacencyList(
@@ -55,7 +46,7 @@ void GraphCore::makeAdjacencyList(
   /** make the connections */
   for (auto &node : node_list) {
     for (auto const &in_conn : node->getInputConnections()) {
-      unsigned int to_node_id = getNode(in_conn)->getIndex();
+      unsigned int to_node_id = getNodeIdx(in_conn);
       adj[to_node_id].push_back(node);
     }
   }
@@ -69,7 +60,7 @@ void GraphCore::topologicalSortUtil(
 
   std::list<std::shared_ptr<GraphNode>>::iterator i;
   for (i = adj[ith].begin(); i != adj[ith].end(); ++i) {
-    auto index = (*i)->getIndex();
+    auto index = getNodeIdx((*i)->getName());
     if (!visited[index])
       topologicalSortUtil(adj, index, visited, dfs_stack);
   }
@@ -107,14 +98,7 @@ void GraphCore::topologicalSort() {
 
 const std::shared_ptr<GraphNode> &
 GraphCore::getNode(const std::string &name) const {
-  for (auto &lnode : node_list) {
-    if (istrequal(lnode->getName(), name))
-      return lnode;
-  }
-
-  std::stringstream ss;
-  ss << "Cannot find graph node: " << name;
-  throw std::invalid_argument(ss.str());
+  return node_list.at(node_map.at(name));
 }
 
 void GraphCore::addNode(std::shared_ptr<GraphNode> node, bool ensure_name) {
@@ -126,14 +110,26 @@ void GraphCore::addNode(std::shared_ptr<GraphNode> node, bool ensure_name) {
   addGraphNode(node);
 }
 
-void GraphCore::ensureName(GraphNode &node, const std::string &prefix,
-                           const std::string &postfix, bool force_rename) {
-  std::string orig_name = node.getName();
+void GraphCore::ensureName(GraphNode &node, const std::string &prefix_,
+                           const std::string &postfix_, bool force_rename) {
+  auto to_lower = [](const std::string &str) -> std::string {
+    std::string ret = str;
+    ;
+    std::transform(ret.begin(), ret.end(), ret.begin(),
+                   [](unsigned char c) { return std::tolower(c); });
+    return ret;
+  };
+
+  std::string orig_name = to_lower(node.getName());
+  std::string prefix = to_lower(prefix_);
+  std::string postfix = to_lower(postfix_);
+
   bool orig_name_empty = orig_name.empty();
   /** If node already has name which is unique and valid, and force is
    * disabled, then nothing to do.
    */
   if (!orig_name_empty && !force_rename && !verifyNode(orig_name)) {
+    node.setName(orig_name);
     node_names.insert(orig_name);
     return;
   }
@@ -167,9 +163,15 @@ void GraphCore::ensureName(GraphNode &node, const std::string &prefix,
 
 void GraphCore::replaceNode(std::shared_ptr<GraphNode> from,
                             std::shared_ptr<GraphNode> to) {
-  unsigned int idx = from->getIndex();
-  to->setIndex(idx);
-  node_list[idx] = to;
+  if (node_map.find(from->getName()) == node_map.end())
+    throw std::invalid_argument("Graph node to be replaced is missing");
+  if (node_map.find(to->getName()) != node_map.end())
+    throw std::invalid_argument("Nodes in the graph must be unique");
+
+  unsigned int from_idx = getNodeIdx(from->getName());
+  node_list[from_idx] = to;
+  node_map.erase(from->getName());
+  node_map[to->getName()] = from_idx;
 }
 
 void GraphCore::realizeInputOutputNode() {
@@ -183,4 +185,8 @@ void GraphCore::realizeInputOutputNode() {
   }
 }
 
+unsigned int GraphCore::getNodeIdx(const std::string &name) {
+  return node_map.at(name);
+}
+
 } /* namespace nntrainer */
index 4884f461fbdecaa21ade04b24763cb1c5c5cb37a..e4d7d6e933309856c630b59be50164de71209696 100644 (file)
@@ -21,6 +21,7 @@
 #include <map>
 #include <memory>
 #include <stack>
+#include <unordered_map>
 #include <unordered_set>
 #include <vector>
 
@@ -65,6 +66,7 @@ public:
     using std::swap;
 
     swap(lhs.node_list, rhs.node_list);
+    swap(lhs.node_map, rhs.node_map);
     swap(lhs.Sorted, rhs.Sorted);
     swap(lhs.node_names, rhs.node_names);
     swap(lhs.def_name_count, rhs.def_name_count);
@@ -75,6 +77,7 @@ public:
    */
   void reset() {
     node_list.clear();
+    node_map.clear();
     Sorted.clear();
     node_names.clear();
     def_name_count = 0;
@@ -261,6 +264,7 @@ private:
   std::vector<std::shared_ptr<GraphNode>> output_list;
   std::vector<std::shared_ptr<GraphNode>>
     node_list;                                    /**< Unordered Node List  */
+  std::unordered_map<std::string, int> node_map;  /**< Unordered Node map  */
   std::vector<std::shared_ptr<GraphNode>> Sorted; /**< Ordered Node List  */
   bool sorted; /** if the node_list is sorted */
 
@@ -290,6 +294,14 @@ private:
    */
   void
   makeAdjacencyList(std::vector<std::list<std::shared_ptr<GraphNode>>> &adj);
+
+  /**
+   * @brief     Get index of the node with given name
+   *
+   * @param     name Name of the node
+   * @return    internal index of the node
+   */
+  unsigned int getNodeIdx(const std::string &name);
 };
 
 } // namespace nntrainer
index 687f695ada5157de4dafb1c829dfd015d9ac5699..755752b0624033cde686149b02ce398ef4c7e7a6 100644 (file)
@@ -31,18 +31,6 @@ public:
    */
   virtual ~GraphNode() = default;
 
-  /**
-   * @brief     Get index of the node
-   *
-   */
-  virtual size_t getIndex() const = 0;
-
-  /**
-   * @brief     Set index of the node
-   *
-   */
-  virtual void setIndex(size_t) = 0;
-
   /**
    * @brief     Get the Name of the underlying object
    *
index 555dbe8479790f292c04b89e5f0128effee92629..32dafb233ad4362924ecda46ea2aa0c6423f453a 100644 (file)
@@ -90,7 +90,7 @@ void NetworkGraph::addDefaultInputLayers() {
 }
 
 void NetworkGraph::addLayerNode(std::unique_ptr<Layer> layer) {
-  graph.addNode(std::make_unique<LayerNode>(std::move(layer), graph.size()));
+  graph.addNode(std::make_unique<LayerNode>(std::move(layer)));
 }
 
 void NetworkGraph::countNonTrainableLayersAtBegin() {
@@ -269,7 +269,6 @@ int NetworkGraph::addLossLayer(const std::string &loss_type_) {
     lnode->setInputLayers({second_to_last_layer_node->getName()});
 
     if (is_cross_entropy_loss) {
-      lnode->setIndex(output_layer_node->getIndex());
       graph.replaceNode(output_layer_node, lnode);
     } else {
       graph.addNode(lnode, false);
@@ -702,14 +701,11 @@ int NetworkGraph::initialize(std::shared_ptr<Manager> manager) {
       for (unsigned int i = 0; i < input_layers.size(); ++i) {
         auto in_layer_node = getLayerNode(input_layers[i]);
 
-        unsigned int location = 0;
-        for (unsigned int j = 0; j < in_layer_node->getNumOutputConnections();
-             ++j) {
-          if (in_layer_node->getOutputLayers()[j] == lnode->getName()) {
-            location = j;
-            break;
-          }
-        }
+        auto const &in_layer_out_connect = in_layer_node->getOutputLayers();
+        unsigned int location =
+          std::find(in_layer_out_connect.begin(), in_layer_out_connect.end(),
+                    lnode->getName()) -
+          in_layer_out_connect.begin();
 
         lnode->setInputDimension(in_layer_node->getOutputDimensions()[location],
                                  i);
index 608825e169cdc6ef25cbd3510e3dc36bc58da563..6610d749e530dccec250d93a45bc447c5ac3d823 100644 (file)
@@ -97,15 +97,6 @@ public:
     skip_non_trainable_layers = 0;
   }
 
-  /**
-   * @brief getter of LayerNode with index number
-   * @param[in] index
-   * @ret LayerNode
-   */
-  std::shared_ptr<LayerNode> getLayerNode(unsigned int ith) const {
-    return std::static_pointer_cast<LayerNode>(graph.getNode(ith));
-  }
-
   /**
    * @brief getter of Sorted LayerNode with index number
    * @param[in] index
index ca858063b195869efa19cce39333f77b9c73cda4..61eb3b3cdfb1f376cf0355398f3bd444cdbc3e00 100644 (file)
@@ -118,9 +118,8 @@ createLayerNode(std::unique_ptr<nntrainer::Layer> &&layer,
   return lnode;
 }
 
-LayerNode::LayerNode(std::unique_ptr<nntrainer::Layer> &&l, size_t idx) :
+LayerNode::LayerNode(std::unique_ptr<nntrainer::Layer> &&l) :
   layer(std::move(l)),
-  index(idx),
   finalized(false),
   activation_type(ActivationType::ACT_NONE),
   layer_node_props(new PropsType(props::Name(), props::Flatten(),
index 81e8376a01acdb7cd55df9e5537731bfab6a40e1..f8df519d3172194961ea2f224bcf707b59e51bcf 100644 (file)
@@ -59,14 +59,14 @@ public:
   /**
    * @brief Default constructor
    */
-  LayerNode() : LayerNode(nullptr, 0) {}
+  LayerNode() : LayerNode(nullptr) {}
 
   /**
    * @brief Constructor of LayerNode class for v2
    * @param l layer to wrap with, the ownership is transferred to layer node
    *
    */
-  LayerNode(std::unique_ptr<nntrainer::Layer> &&l, size_t idx = 0);
+  LayerNode(std::unique_ptr<nntrainer::Layer> &&l);
 
   /**
    * @brief     Destructor of LayerNode Class
@@ -110,19 +110,6 @@ public:
    * Support all the interface requirements by nntrainer::GraphNode
    */
 
-  /**
-   * @brief     Get index of the node
-   *
-   * @return    Index of the node
-   */
-  size_t getIndex() const { return index; }
-
-  /**
-   * @brief     Set the index for the node
-   * @param     idx Index for the node
-   */
-  void setIndex(size_t idx) { index = idx; }
-
   /**
    * @brief     set name of layer
    *
@@ -363,7 +350,17 @@ public:
    * @param layers Name of the layers
    */
   void setInputLayers(const std::vector<std::string> &layers) {
-    input_layers = layers;
+    auto to_lower = [](const std::string &str) -> std::string {
+      std::string ret = str;
+      ;
+      std::transform(ret.begin(), ret.end(), ret.begin(),
+                     [](unsigned char c) { return std::tolower(c); });
+      return ret;
+    };
+
+    input_layers.reserve(layers.size());
+    for (auto const &name : layers)
+      input_layers.push_back(to_lower(name));
     resizeInputDimensions(input_layers.size());
   }
 
@@ -587,9 +584,6 @@ private:
   std::unique_ptr<nntrainer::Layer>
     layer; /**< The actual object in the graph node */
 
-  // TODO: possibly remove, two identifiers for the same node (name and
-  // index) can lead to issues later
-  size_t index;   /**< index of each node */
   bool finalized; /**< if the layer node has been finalized */
 
   std::vector<std::string> input_layers;  /**< input layer names */