From 4d725edab14435769a2b09b51761a0ede71cfeb2 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=EA=B9=80=EC=9A=A9=EC=84=AD/On-Device=20Lab=28SR=29/Enginee?= =?utf8?q?r/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Fri, 19 Jul 2019 11:19:50 +0900 Subject: [PATCH] Revise planTensors in Linear (#5689) * Revise planTensors in Linear - Introduce tensor_builder_map instead of iterTensorBuilders - Replace the type of constants from std::vector to model::OperandIndexSequence constants - Add model::OperandIndexMap def_map - Append the step for disposing and validation Signed-off-by: Yongseop Kim * Avoid cases where insertion of unordered_map could happen --- runtimes/neurun/core/src/linear/Linear.cc | 85 ++++++++++++++++++------------- 1 file changed, 50 insertions(+), 35 deletions(-) diff --git a/runtimes/neurun/core/src/linear/Linear.cc b/runtimes/neurun/core/src/linear/Linear.cc index 959d4b3..94d1089 100644 --- a/runtimes/neurun/core/src/linear/Linear.cc +++ b/runtimes/neurun/core/src/linear/Linear.cc @@ -155,32 +155,35 @@ void Linear::accept(model::OperationVisitor &&visitor) const backend::TensorBuilderSet Linear::planTensors() { - using ITensorBuilderPtr = std::shared_ptr; - using FnOnTensorBuilder = std::function; - - 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> tensor_builder_map; + // TODO Add maps which support for subtensors model::OperandIndexMap uses_map; - std::vector constants; + model::OperandIndexMap 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 it) { return it.second == 0; })); + + assert(std::all_of( + def_map.begin(), def_map.end(), + [](std::pair it) { return it.second == 0; })); // Set subtensor information // Todo: move this phase outside as optimization phase -- 2.7.4