[layer-internal] refactoring weight, input, output to layer_node
authorhyeonseok lee <hs89.lee@samsung.com>
Thu, 17 Jun 2021 02:14:07 +0000 (11:14 +0900)
committerJijoong Moon <jijoong.moon@samsung.com>
Wed, 23 Jun 2021 07:42:19 +0000 (16:42 +0900)
- Implement getter for variable and grad of weight, input, output
- Implement getNumWeights

Self evaluation:

Build test: [X]Passed [ ]Failed [ ]Skipped
Run test: [X]Passed [ ]Failed [ ]Skipped

Signed-off-by: hyeonseok lee <hs89.lee@samsung.com>
nntrainer/graph/network_graph.cpp
nntrainer/layers/layer_node.h
nntrainer/models/neuralnet.cpp
test/unittest/unittest_nntrainer_models.cpp

index d7fd2e1..d02b74d 100644 (file)
@@ -478,9 +478,10 @@ sharedConstTensors NetworkGraph::forwarding(bool training) const {
   }
 
   std::vector<sharedConstTensor> out;
-  for (auto const &nh :
-       getSortedLayerNode(graph.size() - 1)->getObject()->net_hidden)
-    out.push_back(MAKE_SHARED_TENSOR(nh->getVariable()));
+  auto const &last_layer_node = getSortedLayerNode(graph.size() - 1);
+  for (unsigned int i = 0; i < last_layer_node->getNumOutputs(); ++i) {
+    out.push_back(MAKE_SHARED_TENSOR(last_layer_node->getOutput(i)));
+  }
 
   return out;
 }
index 64cadc0..41e80b1 100644 (file)
@@ -167,6 +167,19 @@ public:
   unsigned int getNumOutputs() const { return output_layers.size(); }
 
   /**
+   * @brief Get the number of weights
+   *
+   * @return unsigned int number of weights
+   */
+  unsigned int getNumWeights() const {
+    if (LAYER_V2) {
+      return run_context.getNumWeights();
+    } else {
+      return getLayer()->getNumWeights();
+    }
+  }
+
+  /**
    * @brief     Get the Input Layers object
    *
    * @return const std::vector<std::string>&
@@ -274,6 +287,90 @@ public:
   }
 
   /**
+   * @brief Get the Weight tensor object
+   *
+   * @param idx Identifier of the weight
+   * @return Tensor& Reference to the weight tensor
+   */
+  Tensor &getWeight(unsigned int idx) {
+    if (LAYER_V2) {
+      return run_context.getWeight(idx);
+    } else {
+      return getLayer()->getWeightsRef()[idx].getVariableRef();
+    }
+  }
+
+  /**
+   * @brief Get the Weight Gradient tensor object
+   *
+   * @param idx Identifier of the weight
+   * @return Tensor& Reference to the weight grad tensor
+   */
+  Tensor &getWeightGrad(unsigned int idx) {
+    if (LAYER_V2) {
+      return run_context.getWeightGrad(idx);
+    } else {
+      return getLayer()->getWeightsRef()[idx].getGradientRef();
+    }
+  }
+
+  /**
+   * @brief Get the Input tensor object
+   *
+   * @param idx Identifier of the input
+   * @return Tensor& Reference to the input grad tensor
+   */
+  Tensor &getInput(unsigned int idx) {
+    if (LAYER_V2) {
+      return run_context.getInput(idx);
+    } else {
+      return getLayer()->getInputRef()[idx]->getVariableRef();
+    }
+  }
+
+  /**
+   * @brief Get the Input Grad tensor object
+   *
+   * @param idx Identifier of the input
+   * @return Tensor& Reference to the input grad tensor
+   */
+  Tensor &getInputGrad(unsigned int idx) {
+    if (LAYER_V2) {
+      return run_context.getInputGrad(idx);
+    } else {
+      return getLayer()->getInputRef()[idx]->getGradientRef();
+    }
+  }
+
+  /**
+   * @brief Get the Output tensor object
+   *
+   * @param idx Identifier of the output
+   * @return Tensor& Reference to the output tensor
+   */
+  Tensor &getOutput(unsigned int idx) {
+    if (LAYER_V2) {
+      return run_context.getOutput(idx);
+    } else {
+      return getLayer()->getOutputRef()[idx]->getVariableRef();
+    }
+  }
+
+  /**
+   * @brief Get the Output Grad tensor object
+   *
+   * @param idx Identifier of the output
+   * @return Tensor& Reference to the output grad tensor
+   */
+  Tensor &getOutputGrad(unsigned int idx) {
+    if (LAYER_V2) {
+      return run_context.getOutputGrad(idx);
+    } else {
+      return getLayer()->getOutputRef()[idx]->getGradientRef();
+    }
+  }
+
+  /**
    * @brief this function helps exporting the layer in a predefined format,
    * while workarounding issue caused by templated function type eraser
    *
index dfbff83..8b10d47 100644 (file)
@@ -226,24 +226,21 @@ sharedConstTensors NeuralNetwork::forwarding(sharedConstTensors input,
     << " input_batch: " << input[0]->batch()
     << " label_batch: " << label[0]->batch() << " target_batch: " << batch_size;
 
-  auto fill_label = [&label](auto &layer) {
-    NNTR_THROW_IF(label.size() != layer.net_hidden.size(),
+  auto fill_label = [&label](auto const &layer_node) {
+    NNTR_THROW_IF(label.size() != layer_node->getNumOutputs(),
                   std::invalid_argument)
       << "label size does not match with the layer requirements"
-      // TODO: update this to use layer node after #986
-      // << " layer: " << layer.getName() << " label size: " << label.size()
-      << " layer: "
-      << " label size: " << label.size()
-      << " requirements size: " << layer.net_hidden.size();
-
-    for (unsigned int i = 0; i < layer.net_hidden.size(); i++) {
-      layer.net_hidden[i]->getGradientRef() = *label[i];
+      << " layer: " << layer_node->getName() << " label size: " << label.size()
+      << " requirements size: " << layer_node->getNumOutputs();
+
+    for (unsigned int i = 0; i < layer_node->getNumOutputs(); i++) {
+      layer_node->getOutputGrad(i) = *label[i];
     }
   };
 
-  auto clear_label = [](auto &layer) {
-    for (unsigned int i = 0; i < layer.net_hidden.size(); i++) {
-      layer.net_hidden[i]->getGradientRef() = Tensor();
+  auto clear_label = [](auto const &layer_node) {
+    for (unsigned int i = 0; i < layer_node->getNumOutputs(); i++) {
+      layer_node->getOutputGrad(i) = Tensor();
     }
   };
 
@@ -251,12 +248,11 @@ sharedConstTensors NeuralNetwork::forwarding(sharedConstTensors input,
   for (auto iter = model_graph.cbegin(); iter != model_graph.cend(); iter++) {
     auto &l = *iter->getObject();
     if (l.requireLabel()) {
-      label.empty() ? clear_label(l) : fill_label(l);
+      label.empty() ? clear_label(*iter) : fill_label(*iter);
     }
   }
 
-  auto &first_layer = model_graph.getSortedLayerNode(0)->getObject();
-  first_layer->net_input[0]->getVariableRef() = *input[0];
+  model_graph.getSortedLayerNode(0)->getInput(0) = *input[0].get();
 
   return forwarding(training);
 }
@@ -345,9 +341,9 @@ void NeuralNetwork::backwarding(int iteration) {
  *            No need to call at first Input Layer (No data to be updated)
  */
 void NeuralNetwork::backwarding(sharedConstTensors label, int iteration) {
-  auto &loss_layer =
-    model_graph.getSortedLayerNode(model_graph.size() - 1)->getObject();
-  loss_layer->net_hidden[0]->getGradientRef() = *label[0].get();
+  auto const &loss_layer_node =
+    model_graph.getSortedLayerNode(model_graph.size() - 1);
+  loss_layer_node->getOutputGrad(0) = *label[0].get();
 
   backwarding(iteration);
 }
@@ -501,10 +497,10 @@ sharedConstTensors NeuralNetwork::inference(sharedConstTensors X,
   forwarding(X, {}, false);
   END_PROFILE(profile::NN_FORWARD);
 
-  auto &last_layer =
-    model_graph.getSortedLayerNode(model_graph.size() - 1)->getObject();
-  for (unsigned int i = 0; i < last_layer->getNumOutputs(); ++i) {
-    out.push_back(MAKE_SHARED_TENSOR(last_layer->net_hidden[i]->getVariable()));
+  auto const &last_layer_node =
+    model_graph.getSortedLayerNode(model_graph.size() - 1);
+  for (unsigned int i = 0; i < last_layer_node->getNumOutputs(); ++i) {
+    out.push_back(MAKE_SHARED_TENSOR(last_layer_node->getOutput(i)));
   }
 
   if (free_mem)
@@ -586,13 +582,13 @@ int NeuralNetwork::train_run() {
     iter = 0;
   }
 
-  auto &first_layer = model_graph.getSortedLayerNode(0)->getObject();
-  auto &last_layer =
-    model_graph.getSortedLayerNode(model_graph.size() - 1)->getObject();
+  auto const &first_layer_node = model_graph.getSortedLayerNode(0);
+  auto const &last_layer_node =
+    model_graph.getSortedLayerNode(model_graph.size() - 1);
 
-  auto &output = last_layer->net_hidden[0]->getVariableRef();
-  auto &label = last_layer->net_hidden[0]->getGradientRef();
-  auto &in = first_layer->net_input[0]->getVariableRef();
+  auto &output = last_layer_node->getOutput(0);
+  auto &label = last_layer_node->getOutputGrad(0);
+  auto &in = first_layer_node->getInput(0);
 
   for (epoch_idx = epoch_idx + 1; epoch_idx <= epochs; ++epoch_idx) {
     training.loss = 0.0f;
index 5bd2326..3b5e2b3 100644 (file)
@@ -41,7 +41,7 @@ static const std::string getModelsPath(const std::string &file_name) {
  * Watcher Classes                                      *
  ********************************************************/
 
-using NodeType = std::shared_ptr<const nntrainer::LayerNode>;
+using NodeType = std::shared_ptr<nntrainer::LayerNode>;
 using FlatGraphType = nntrainer::NeuralNetwork::FlatGraphType;
 using NetworkGraphType = nntrainer::NetworkGraph;
 
@@ -114,7 +114,7 @@ public:
    * @param node node to watch.
    */
   NodeWatcher(const NodeType &node) : node(node) {
-    unsigned int num_weights = node->getObject()->getNumWeights();
+    unsigned int num_weights = node->getNumWeights();
     try {
       node->getObject()->setTrainable(true);
     } catch (...) {
@@ -140,9 +140,9 @@ public:
    *
    */
   void readLayerWeight(std::ifstream &f) {
-    for (unsigned int i = 0; i < node->getObject()->getNumWeights(); ++i) {
+    for (unsigned int i = 0; i < node->getNumWeights(); ++i) {
       /// @note below is harrasing the fact the tensor shares same base memory
-      node->getObject()->weightAt(i).getVariable().read(f);
+      node->getWeight(i).read(f);
     }
   }
 
@@ -301,8 +301,7 @@ void NodeWatcher::read(std::ifstream &in) {
 
 void NodeWatcher::verifyWeight(const std::string &error_msg) {
   for (unsigned int i = 0; i < expected_weights.size(); ++i) {
-    verify(node->getObject()->weightAt(i).getVariable(),
-           expected_weights[i].getVariable(),
+    verify(node->getWeight(i), expected_weights[i].getVariable(),
            error_msg + " " + node->getObject()->weightAt(i).getName() +
              " weight");
   }