[manager] Temporarily handle external tensors
authorParichay Kapoor <pk.kapoor@samsung.com>
Tue, 28 Sep 2021 05:45:50 +0000 (14:45 +0900)
committerJijoong Moon <jijoong.moon@samsung.com>
Fri, 1 Oct 2021 02:59:03 +0000 (11:59 +0900)
With rebase, the var_grads representing inputs cannot be null tensors.
This patch provides a temporary fix for this issue. Proper fix for the
issue is added in #1544.

Signed-off-by: Parichay Kapoor <pk.kapoor@samsung.com>
nntrainer/graph/network_graph.cpp
nntrainer/graph/network_graph.h
nntrainer/models/neuralnet.cpp
nntrainer/tensor/manager.cpp
nntrainer/tensor/manager.h

index 0d3ffc2..7fe73e8 100644 (file)
@@ -724,10 +724,6 @@ NetworkGraph::finalizeContext(const std::shared_ptr<LayerNode> &lnode,
   if (lnode->requireLabel())
     label_list.insert(label_list.end(), outputs.begin(), outputs.end());
 
-  /**
-   * @note must use existing properties like name/trainable of run_context to
-   * create the new run_context
-   */
   lnode->configureRunContext(
     // TODO: update weights spec for trainable based on layer trainable prop
     tensor_manager->requestWeights(gnode, init_context.getWeightsSpec()),
index dbb372b..720afca 100644 (file)
@@ -293,6 +293,15 @@ public:
    * @brief Allocate and initialize the weight variable
    */
   void initializeWeights() {
+    /**
+     * get the order of execution/usage order for the forwarding of the last
+     * layer and pass that as the max_exec_order ensuring that all weights with
+     * usage less than the max_exec_order are allocated.
+     *
+     * @note usage order of backwarding is not considered because weight has a
+     * separate memory pool for now. Later, if it shares pool with other
+     * tensors, then this must max of backward usage order.
+     */
     tensor_manager->initializeWeights(
       std::get<0>((*(cend() - 1))->getExecutionOrder()));
   }
@@ -303,10 +312,21 @@ public:
    */
   void initializeTensors(bool training) {
     if (!training)
+      /**
+       * get the order of execution/usage order for the forwarding of the last
+       * layer and pass that as the max_exec_order ensuring that all tensors
+       * with usage less than the max_exec_order are allocated.
+       */
       tensor_manager->initializeTensors(
         training, std::get<0>((*(cend() - 1))->getExecutionOrder()));
     else
       /** @todo update this to skip non-trainable layers */
+      /**
+       * get the order of execution/usage order for the backwarding of the first
+       * layer (as that will be the last layer to executed in the backwarding)
+       * and pass that as the max_exec_order ensuring that all tensors with
+       * usage less than the max_exec_order are allocated.
+       */
       tensor_manager->initializeTensors(
         training, std::get<1>((*(cbegin()))->getExecutionOrder()));
   }
index 9d14eab..a31a35b 100644 (file)
@@ -167,14 +167,14 @@ NeuralNetwork::~NeuralNetwork() { model_graph.reset(); }
 static void setLabels(const std::vector<Tensor> &data,
                       const std::vector<Var_Grad *> &label_list) {
 
-  NNTR_THROW_IF(!data.empty() && data.size() != label_list.size(),
+  NNTR_THROW_IF(data.size() > 1 && data.size() != label_list.size(),
                 std::invalid_argument)
     << "label size does not match with the network requirements"
     << " label size: " << data.size()
     << " requirements size: " << label_list.size();
 
   /// feed or clear label
-  for (unsigned int idx = 0; idx < data.size(); idx++) {
+  for (unsigned int idx = 0; idx < label_list.size(); idx++) {
     if (data.empty())
       label_list[idx]->initializeGradient();
     else if (data.size() == 1)
@@ -201,35 +201,21 @@ static void setInputs(const std::vector<Tensor> &data,
 static void setLabels(sharedConstTensors &data,
                       const std::vector<Var_Grad *> &label_list) {
 
-  NNTR_THROW_IF(data.size() > 1 && data.size() != label_list.size(),
-                std::invalid_argument)
-    << "label size does not match with the network requirements"
-    << " label size: " << data.size()
-    << " requirements size: " << label_list.size();
+  std::vector<Tensor> labels;
+  std::transform(data.begin(), data.end(), std::back_inserter(labels),
+                 [](auto const &val) { return *val.get(); });
 
-  /// feed or clear label
-  for (unsigned int idx = 0; idx < label_list.size(); idx++) {
-    if (data.empty())
-      label_list[idx]->initializeGradient();
-    else if (data.size() == 1)
-      label_list[idx]->initializeGradient(*data[0]);
-    else
-      label_list[idx]->initializeGradient(*data[idx]);
-  }
+  setLabels(labels, label_list);
 }
 
 static void setInputs(sharedConstTensors &data,
                       const std::vector<Var_Grad *> &input_list) {
 
-  NNTR_THROW_IF(data.size() != input_list.size(), std::invalid_argument)
-    << "input size does not match with the network requirements"
-    << " input size: " << data.size()
-    << " requirements size: " << input_list.size();
+  std::vector<Tensor> inputs;
+  std::transform(data.begin(), data.end(), std::back_inserter(inputs),
+                 [](auto const &val) { return *val.get(); });
 
-  /// feed or clear label
-  for (unsigned int idx = 0; idx < data.size(); idx++) {
-    input_list[idx]->initializeVariable(*data[idx]);
-  }
+  setInputs(inputs, input_list);
 }
 
 /**
index 44a942c..7195a3b 100644 (file)
@@ -850,9 +850,20 @@ Manager::requestInputs(const GraphNode &node,
       );
     }
 
-    inputs_v2.emplace_back(std::make_unique<Var_Grad>(var, grad));
+    /**
+     * TODO: This a temporary fix to handle external tensors due to rebase.
+     * This is properly fixed with #1544 using
+     * context.requestExternallyAllocatedTensor().
+     */
+    if (var && grad)
+      inputs_v2.emplace_back(std::make_unique<Var_Grad>(var, grad));
+    else
+      inputs_v2.emplace_back(std::make_unique<Var_Grad>(
+        dim, Tensor::Initializer::NONE, true, false,
+        node.getName() + std::string(":input") + std::to_string(idx)));
   }
 
+  ret.reserve(inputs_dim.size());
   std::transform(inputs_v2.begin() + current_size, inputs_v2.end(),
                  std::back_inserter(ret),
                  [](auto const &elem) { return elem.get(); });
index 511adb2..5904e81 100644 (file)
@@ -383,12 +383,16 @@ public:
   void untrackLayerInOuts(const std::string &layer_name);
 
   /**
-   * @brief Initialize the inputs/outputs/derivatives/gradients for the layers
-   * @param[in] training If true, initialize derivates/gradients, else, do not.
-   * @note The memory allocation strategy varies based on the training. The
-   * memory allocated for inference mode is not compatible with training, and
-   * will require full allocation than reusing memory allocated with inference
-   * mode.
+   * @brief Initialize the all the requested tensors
+   *
+   * @param[in] training If model will be training or not
+   * @param[in] max_exec_order The maximum order of execution to determine
+   * memory layout
+   *
+   * @note Any requested tensor which is not used inside the max_exec_order is
+   * not initialized and will not be allocated. The initialization uses a memory
+   * planner to plan the layout of all the tensors which are used at least once
+   * before the max_exec_order.
    */
   void initializeTensors(bool training, unsigned int max_exec_order);