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]++;
}
// 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