Revise planTensors in Linear (#5689)
author김용섭/On-Device Lab(SR)/Engineer/삼성전자 <yons.kim@samsung.com>
Fri, 19 Jul 2019 02:19:50 +0000 (11:19 +0900)
committer이한종/On-Device Lab(SR)/Engineer/삼성전자 <hanjoung.lee@samsung.com>
Fri, 19 Jul 2019 02:19:50 +0000 (11:19 +0900)
* Revise planTensors in Linear

- Introduce tensor_builder_map instead of iterTensorBuilders
- Replace the type of constants from std::vector<model::OperandIndex>
to model::OperandIndexSequence constants
- Add model::OperandIndexMap<uint32_t> def_map
- Append the step for disposing and validation

Signed-off-by: Yongseop Kim <yons.kim@samsung.com>
* Avoid cases where insertion of unordered_map could happen

runtimes/neurun/core/src/linear/Linear.cc

index 959d4b3..94d1089 100644 (file)
@@ -155,32 +155,35 @@ void Linear::accept(model::OperationVisitor &&visitor) const
 
 backend::TensorBuilderSet Linear::planTensors()
 {
-  using ITensorBuilderPtr = std::shared_ptr<backend::ITensorBuilder>;
-  using FnOnTensorBuilder = std::function<void(const model::OperandIndex &ind, ITensorBuilderPtr)>;
-
-  auto iterTensorBuilders = [this](const model::OperandIndex &ind, FnOnTensorBuilder fn) {
-    const auto lower_info = getLowerInfo(ind);
-    for (auto factor : lower_info->def_factors())
-    {
-      auto tensor_builder = factor.backend()->tensor_builder();
-      fn(ind, tensor_builder);
-    }
-  };
-
   backend::TensorBuilderSet tensor_builders;
+  model::OperandIndexMap<std::shared_ptr<backend::ITensorBuilder>> tensor_builder_map;
 
+  // TODO Add maps which support for subtensors
   model::OperandIndexMap<uint32_t> uses_map;
-  std::vector<model::OperandIndex> constants;
+  model::OperandIndexMap<uint32_t> def_map;
+  model::OperandIndexSequence constants;
 
+  // Prepare scanning
   _model->operands.iterate([&](const model::OperandIndex &ind, const model::Operand &obj) {
     const auto lower_info = getLowerInfo(ind);
+    // TODO Remove if neurun doesn't support anymore such as
+    // GeneratedTests.reshape_quant8_weights_as_inputs
+    if (lower_info->def_factors().size() == 0 && lower_info->use_factors().size() == 0 &&
+        _model->inputs.contains(ind) == false)
+    {
+      VERBOSE(LINEAR) << "Operand #" << ind.value() << " will be not used. no more process."
+                      << std::endl;
+      return;
+    }
+
     uses_map[ind] = obj.getUses().size();
+    def_map[ind] = obj.getDef().size(); // should be 1 or 0
 
     // If a tensor is a constant, increase the use of the tensor.
     // It makes the tensor not be dealloced.
     if (obj.isConstant())
     {
-      constants.push_back(ind);
+      constants.append(ind);
       uses_map[ind]++;
     }
 
@@ -213,73 +216,85 @@ backend::TensorBuilderSet Linear::planTensors()
 
       // Prepare tensor builders to be returned
       tensor_builders.insert(tensor_builder);
+
+      tensor_builder_map[ind] = tensor_builder;
     }
   });
 
   // If a tensor is model output, increase the use of the tensor.
   // This aim is same to above one.
-  // for (const auto &ind : _graph.getOutputs())
   for (const auto &ind : _model->outputs)
   {
+    assert(uses_map.find(ind) != uses_map.end());
     uses_map[ind]++;
   }
 
+  // Start scanning
   // Allocate constant operands first
   VERBOSE(LINEAR) << "TENSORS as CONSTANT" << std::endl;
   for (const auto &ind : constants)
   {
-    iterTensorBuilders(ind, [](const model::OperandIndex &ind, ITensorBuilderPtr tensor_builder) {
-      tensor_builder->notifyFirstUse(ind);
-    });
+    tensor_builder_map[ind]->notifyFirstUse(ind);
   }
 
   // Allocate Model's inputs
   VERBOSE(LINEAR) << "TENSORS as MODEL INPUT" << std::endl;
   for (const auto &ind : _model->inputs)
   {
-    iterTensorBuilders(ind, [](const model::OperandIndex &ind, ITensorBuilderPtr tensor_builder) {
-      tensor_builder->notifyFirstUse(ind);
-    });
+    auto tensor_builder = tensor_builder_map[ind];
+    if (!tensor_builder) // for GeneratedTests.xxx_weights_as_inputs
+      continue;
+    tensor_builder->notifyFirstUse(ind);
   }
 
   // At each operation,
   //   1. Scan USE of inputs. Decrease the USE and deallocate if the USE is 0
   //   2. Scan DEF of outputs. If the DEF, allocate it
   VERBOSE(LINEAR) << "TENSORS" << std::endl;
-  const auto &operands = _model->operands;
   for (const auto &e : *_elements)
   {
     for (const auto &op : e.subgraph->operations())
     {
       for (const auto &ind : op.node->getOutputs())
       {
-        const auto &obj = operands.at(ind);
-        if (obj.getDef().size())
+        assert(def_map.find(ind) != def_map.end());
+        if (def_map[ind])
         {
-          iterTensorBuilders(ind,
-                             [](const model::OperandIndex &ind, ITensorBuilderPtr tensor_builder) {
-                               tensor_builder->notifyFirstUse(ind);
-                             });
+          def_map[ind] = 0;
+          tensor_builder_map[ind]->notifyFirstUse(ind);
         }
       }
 
       for (const auto &ind : op.node->getInputs())
       {
+        assert(uses_map.find(ind) != uses_map.end());
+        assert(uses_map[ind] > 0);
         uses_map[ind]--;
         if (uses_map[ind] == 0)
         {
-          iterTensorBuilders(ind,
-                             [](const model::OperandIndex &ind, ITensorBuilderPtr tensor_builder) {
-                               tensor_builder->notifyLastUse(ind);
-                             });
+          tensor_builder_map[ind]->notifyLastUse(ind);
         }
       }
     }
   }
 
-  // Now, model outputs should be not deallocated
-  assert(std::all_of(_model->outputs.begin(), _model->outputs.end(),
-                     [&uses_map](const model::OperandIndex &ind) { return uses_map[ind] > 0; }));
+  // Dispose and validate
+  for (const auto &ind : _model->outputs)
+  {
+    --uses_map[ind];
+    tensor_builder_map[ind]->notifyLastUse(ind);
+  }
+
+  for (const auto &ind : constants)
+    --uses_map[ind];
+
+  assert(std::all_of(
+      uses_map.begin(), uses_map.end(),
+      [](std::pair<const model::OperandIndex, uint32_t> it) { return it.second == 0; }));
+
+  assert(std::all_of(
+      def_map.begin(), def_map.end(),
+      [](std::pair<const model::OperandIndex, uint32_t> it) { return it.second == 0; }));
 
   // Set subtensor information
   // Todo: move this phase outside as optimization phase