From e14fd4b1776d7dc14610080dd211e635ef73d063 Mon Sep 17 00:00:00 2001
From: =?utf8?q?=D0=9F=D0=B0=D0=B2=D0=B5=D0=BB=20=D0=98=D0=BB=D1=8C=D1=8E?=
=?utf8?q?=D1=82=D1=87=D0=B5=D0=BD=D0=BA=D0=BE/AI=20Tools=20Lab=20/SRR/Eng?=
=?utf8?q?ineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?=
Date: Mon, 17 Dec 2018 22:07:17 +0300
Subject: [PATCH] [nnc] Support Elementwise Add and Mul operations with weights
array (#2628)
* Add support Elementwise Add and Mul operations with weights array
* Support constant operation in soft cpu backend
* Remove ref type from InputParams and InputOps and add them to
Signed-off-by: Pavel Iliutchenko
Signed-off-by: Pavel Iliutchenko
Signed-off-by: Pavel Iliutchenko
* Add refs for all creates
Signed-off-by: Pavel Iliutchenko
---
contrib/nnc/core/modelIR/Graph.cpp | 8 ++++
contrib/nnc/include/core/modelIR/Graph.h | 6 +++
contrib/nnc/passes/soft_backend/ModelAnalyzer.cpp | 20 ++++++---
contrib/nnc/passes/soft_backend/ModelAnalyzer.h | 6 +--
.../soft_backend/code_snippets/cpp_operations.def | 18 ++++++++
.../passes/tflite_frontend/tflite_op_creator.cpp | 51 ++++++++++++++--------
.../nnc/passes/tflite_frontend/tflite_op_creator.h | 32 +++++++-------
7 files changed, 97 insertions(+), 44 deletions(-)
diff --git a/contrib/nnc/core/modelIR/Graph.cpp b/contrib/nnc/core/modelIR/Graph.cpp
index fd9eb87..462a712 100644
--- a/contrib/nnc/core/modelIR/Graph.cpp
+++ b/contrib/nnc/core/modelIR/Graph.cpp
@@ -128,6 +128,14 @@ std::vector Graph::collectInputs() const {
return res;
}
+std::vector Graph::collectConstants() const {
+ std::vector res;
+ for (auto& e : _constants) {
+ res.emplace_back(e);
+ }
+ return res;
+}
+
std::vector Graph::collectOutputs() const {
std::vector res;
for (auto& e : _outputs) {
diff --git a/contrib/nnc/include/core/modelIR/Graph.h b/contrib/nnc/include/core/modelIR/Graph.h
index edd227d..3456c19 100644
--- a/contrib/nnc/include/core/modelIR/Graph.h
+++ b/contrib/nnc/include/core/modelIR/Graph.h
@@ -62,6 +62,12 @@ class Graph {
std::vector collectInputs() const;
/**
+ * @brief Returns all constants from graph
+ * @returns vector containing all graph constant nodes
+ */
+ std::vector collectConstants() const;
+
+ /**
* @brief Returns all outputs from graph
* @returns vector containing all graph outputs nodes
*/
diff --git a/contrib/nnc/passes/soft_backend/ModelAnalyzer.cpp b/contrib/nnc/passes/soft_backend/ModelAnalyzer.cpp
index a2ef5a4..7f278a0 100644
--- a/contrib/nnc/passes/soft_backend/ModelAnalyzer.cpp
+++ b/contrib/nnc/passes/soft_backend/ModelAnalyzer.cpp
@@ -67,11 +67,16 @@ void ModelAnalyzer::addOpDescr(Operation* op, const string& opName) {
size_t nodeTid = INVALID_TENSOR_ID;
if (op->getPrevNodes().empty()) {
if (auto* p2const = dynamic_cast(op)) {
- type = OpDescr::Type::CONSTANT;
+ type = OpDescr::Type::ORDINARY;
+
auto* shape = const_cast (&p2const->getOutputShape(0));
- nodeTid = allocateTensor(name, TensorDescription::Type::CONSTANT, shape);
+ /*
+ * FIXME allocateTensor get const Shape
+ */
+ nodeTid = allocateTensor(name, TensorDescription::Type::ORDINARY, shape);
} else {
// process input op
+ assert(op->getType() == Operation::Type::variable);
Shape inputShape = op->getOutputShape(0);
nodeTid = allocateTensor(name, TensorDescription::Type::IN, &inputShape);
type = OpDescr::Type::IN;
@@ -90,10 +95,8 @@ void ModelAnalyzer::addOpDescr(Operation* op, const string& opName) {
nodeOutputs.push_back(nodeTid);
// process op outputs
// consider op as output if it has no consumers
- if (op->getNextNodes().empty() && (type != OpDescr::Type::CONSTANT)) {
- assert(type == OpDescr::Type::OUT);
+ if (op->getNextNodes().empty() && (type == OpDescr::Type::OUT))
_outputs.push_back(nodeTid);
- }
// process op inputs
vector nodeInputs;
for (const IODescriptor &d: op->getPrevNodes()) {
@@ -135,8 +138,13 @@ void ModelAnalyzer::analyze(const mir::Graph* g) {
// Set contains pointer to node if it is visited by DFS
set visited;
+ // Collect all inputs and constants
+ vector init_ops(g->collectInputs());
+ vector constant_ops(g->collectConstants());
+ init_ops.insert(init_ops.end(), constant_ops.begin(), constant_ops.end());
+
// Walk all network inputs
- for (Operation* in : g->collectInputs()) {
+ for (Operation* in : init_ops) {
assert(dynamic_cast(in) || dynamic_cast(in));
if (!visited.count(in)) {
visited.insert(in);
diff --git a/contrib/nnc/passes/soft_backend/ModelAnalyzer.h b/contrib/nnc/passes/soft_backend/ModelAnalyzer.h
index e01806e..04a56cb 100644
--- a/contrib/nnc/passes/soft_backend/ModelAnalyzer.h
+++ b/contrib/nnc/passes/soft_backend/ModelAnalyzer.h
@@ -45,8 +45,7 @@ struct TensorDescription {
enum class Type {
IN,
OUT,
- ORDINARY,
- CONSTANT
+ ORDINARY
};
size_t _id;
Type _type;
@@ -62,8 +61,7 @@ struct OpDescr {
enum class Type {
IN,
OUT,
- ORDINARY,
- CONSTANT
+ ORDINARY
};
Type _type;
diff --git a/contrib/nnc/passes/soft_backend/code_snippets/cpp_operations.def b/contrib/nnc/passes/soft_backend/code_snippets/cpp_operations.def
index 1547fe1..d837a9b 100644
--- a/contrib/nnc/passes/soft_backend/code_snippets/cpp_operations.def
+++ b/contrib/nnc/passes/soft_backend/code_snippets/cpp_operations.def
@@ -169,6 +169,20 @@ static bool isAddrAligned(const void *data, int alignment)
return (reinterpret_cast(data) % alignment) == 0;
}
+static inline Tensor deserializeTensor(const char*& buf)
+{
+ int32_t d_type = deserializeT(buf);
+ assert(d_type == 1 && "Unknown data type");
+ int32_t element_size = deserializeT(buf);
+ assert(element_size == 4 && "Unsupported element size");
+ Shape shape = deserializeShape(buf);
+ const float* data = reinterpret_cast(buf);
+
+ Tensor tensor(shape, const_cast(data));
+ buf += element_size * shape.getNumElems();
+ return tensor;
+}
+
static inline Kernel deserializeKernel(const char *&buf)
{
int32_t dType = deserializeT(buf);
@@ -655,3 +669,7 @@ void gather(Tensor &out, const char *params, const Tensor &data, const Tensor &i
shapeToRuntimeShape(indices.getShape()), indices.getData(),
shapeToRuntimeShape(out.getShape()), out.getData());
}
+
+void constant(Tensor& out, const char* params) {
+ out = deserializeTensor(params);
+}
diff --git a/contrib/nnc/passes/tflite_frontend/tflite_op_creator.cpp b/contrib/nnc/passes/tflite_frontend/tflite_op_creator.cpp
index e7bf27b..488a47b 100644
--- a/contrib/nnc/passes/tflite_frontend/tflite_op_creator.cpp
+++ b/contrib/nnc/passes/tflite_frontend/tflite_op_creator.cpp
@@ -31,6 +31,7 @@
#include "core/modelIR/operations/ReluOp.h"
#include "core/modelIR/operations/ReshapeOp.h"
#include "core/modelIR/operations/ResizeOp.h"
+#include "core/modelIR/operations/ScaleOp.h"
#include "core/modelIR/operations/SigmoidOp.h"
#include "core/modelIR/operations/SliceOp.h"
#include "core/modelIR/operations/SoftmaxOp.h"
@@ -38,13 +39,11 @@
#include "core/modelIR/operations/SqueezeOp.h"
#include "core/modelIR/operations/TanhOp.h"
-#include "core/modelIR/Tensor.h"
-#include "core/modelIR/ShapeRange.h"
#include "pass/PassException.h"
-#include "core/modelIR/Tensor.h"
#include "core/modelIR/Shape.h"
#include "core/modelIR/ShapeRange.h"
+#include "core/modelIR/Tensor.h"
using namespace nnc::mir;
using namespace ::tflite;
@@ -85,7 +84,7 @@ void TFLiteOpCreator::checkConv2D(const Conv2DOptions* opts,
checkActivationType(opts->fused_activation_function(), problems_op_set);
}
-std::vector TFLiteOpCreator::convertConv2D(InputOps inputs, InputParams params,
+std::vector TFLiteOpCreator::convertConv2D(InputOps& inputs, InputParams& params,
const Conv2DOptions* opts) {
const auto& input_shape = inputs[0]->getOutputShape(0);
const auto& kernel_shape = params[0].getShape();
@@ -108,7 +107,7 @@ void TFLiteOpCreator::checkDepthwiseConv2D(const DepthwiseConv2DOptions* opts,
}
std::vector
-TFLiteOpCreator::convertDepthwiseConv2D(InputOps inputs, InputParams params,
+TFLiteOpCreator::convertDepthwiseConv2D(InputOps& inputs, InputParams& params,
const DepthwiseConv2DOptions* opts) {
const auto& input_shape = inputs[0]->getOutputShape(0);
const auto& kernel_shape = params[0].getShape();
@@ -131,8 +130,8 @@ void TFLiteOpCreator::checkConcatenation(const ConcatenationOptions* opts,
checkActivationType(opts->fused_activation_function(), problems_op_set);
}
-std::vector TFLiteOpCreator::convertConcatenation(InputOps inputs,
- InputParams params,
+std::vector TFLiteOpCreator::convertConcatenation(InputOps& inputs,
+ InputParams& params,
const ConcatenationOptions* opts) {
std::vector descriptors;
for (auto i : inputs)
@@ -146,7 +145,7 @@ void TFLiteOpCreator::checkPool2D(const Pool2DOptions* opts,
checkActivationType(opts->fused_activation_function(), problems_op_set);
}
-std::vector TFLiteOpCreator::convertMaxPool2D(InputOps inputs, InputParams params,
+std::vector TFLiteOpCreator::convertMaxPool2D(InputOps& inputs, InputParams& params,
const Pool2DOptions* opts) {
auto& input_shape = inputs[0]->getOutputShape(0);
Shape window_shape{opts->filter_height(), opts->filter_width()};
@@ -163,8 +162,8 @@ std::vector TFLiteOpCreator::convertMaxPool2D(InputOps inputs,
ops::PoolOp::RoundMode::floor);
}
-std::vector TFLiteOpCreator::convertAveragePool2D(InputOps inputs,
- InputParams params,
+std::vector TFLiteOpCreator::convertAveragePool2D(InputOps& inputs,
+ InputParams& params,
const Pool2DOptions* opts) {
auto& input_shape = inputs[0]->getOutputShape(0);
Shape window_shape{opts->filter_height(), opts->filter_width()};
@@ -181,7 +180,7 @@ std::vector TFLiteOpCreator::convertAveragePool2D(InputOps inpu
ops::PoolOp::RoundMode::floor);
}
-std::vector TFLiteOpCreator::createSoftmax(InputOps inputs, InputParams params,
+std::vector TFLiteOpCreator::createSoftmax(InputOps& inputs, InputParams& params,
const SoftmaxOptions* opts) {
// Softmax in TFLite is always 2-D.
assert(inputs[0]->getOutputShape(0).rank() == 2);
@@ -198,7 +197,7 @@ Shape shapeFromTensor(mir::Tensor&& t) {
return temporary_shape;
}
-std::vector TFLiteOpCreator::createSlice(InputOps inputs, InputParams params,
+std::vector TFLiteOpCreator::createSlice(InputOps& inputs, InputParams& params,
const ::tflite::SliceOptions*) {
auto starts = shapeFromTensor(mir::Tensor(params[0]));
auto sizes = shapeFromTensor(mir::Tensor(params[1]));
@@ -208,7 +207,7 @@ std::vector TFLiteOpCreator::createSlice(InputOps inputs, Input
starts, sizes);
}
-std::vector TFLiteOpCreator::convertReshape(InputOps inputs, InputParams params,
+std::vector TFLiteOpCreator::convertReshape(InputOps& inputs, InputParams& params,
const ReshapeOptions* opts) {
// TODO: we should also support "-1" values in new_shape, which means that correct
// shape values must be calculated. Better do it in the shape inference module.
@@ -245,19 +244,35 @@ TFLiteOpCreator::convertResizeNN(InputOps& inputs, InputParams& params,
}
std::vector
-TFLiteOpCreator::createAdd(InputOps& inputs, InputParams&, const ::tflite::AddOptions* opts) {
+TFLiteOpCreator::createAdd(InputOps& inputs, const InputParams& params,
+ const ::tflite::AddOptions* opts) {
std::vector descriptors;
+
for (auto i : inputs)
descriptors.push_back(i->getOutput(0));
+
+ for (const auto& param : params) {
+ auto weights_tensor = createOp(ActivationFunctionType_NONE, param);
+ descriptors.push_back(weights_tensor[0]->getOutput(0));
+ }
+
return createOp(opts->fused_activation_function(), descriptors,
ops::ElementwiseOp::OpType::add);
}
std::vector
-TFLiteOpCreator::createMul(InputOps& inputs, InputParams&, const ::tflite::MulOptions* opts) {
+TFLiteOpCreator::createMul(InputOps& inputs, const InputParams& params,
+ const ::tflite::MulOptions* opts) {
std::vector descriptors;
+
for (auto i : inputs)
descriptors.push_back(i->getOutput(0));
+
+ for (const auto& param : params) {
+ auto weights_tensor = createOp(ActivationFunctionType_NONE, param);
+ descriptors.push_back(weights_tensor[0]->getOutput(0));
+ }
+
return createOp(opts->fused_activation_function(), descriptors,
ops::ElementwiseOp::OpType::mul);
}
@@ -281,7 +296,7 @@ TFLiteOpCreator::createMax(InputOps& inputs, InputParams&,
ops::ElementwiseOp::OpType::max);
}
-std::vector TFLiteOpCreator::convertReducer(InputOps inputs, InputParams params,
+std::vector TFLiteOpCreator::convertReducer(InputOps& inputs, InputParams& params,
ops::ReduceFOp::FuncType ft,
const ::tflite::ReducerOptions* opts) {
assert(params.at(0).getShape().rank() <= 1 && "Must be 1-dim or 0-dim tensor");
@@ -356,7 +371,7 @@ mir::Operation* TFLiteOpCreator::addFusedActivation(mir::Operation* input,
}
std::vector TFLiteOpCreator::createSqueeze(
- InputOps inputs, InputParams params, const ::tflite::SqueezeOptions* opts) {
+ InputOps& inputs, InputParams& params, const ::tflite::SqueezeOptions* opts) {
std::vector squeeze_dims{opts->squeeze_dims()->begin(), opts->squeeze_dims()->end()};
@@ -364,7 +379,7 @@ std::vector TFLiteOpCreator::createSqueeze(
squeeze_dims);
}
-std::vector TFLiteOpCreator::createPad(InputOps inputs, InputParams params,
+std::vector TFLiteOpCreator::createPad(InputOps& inputs, InputParams& params,
const ::tflite::PadOptions *opts) {
assert(params.size() == 1); // support pad with one param
std::vector> paddings;
diff --git a/contrib/nnc/passes/tflite_frontend/tflite_op_creator.h b/contrib/nnc/passes/tflite_frontend/tflite_op_creator.h
index 0d802c2..3ae321a 100644
--- a/contrib/nnc/passes/tflite_frontend/tflite_op_creator.h
+++ b/contrib/nnc/passes/tflite_frontend/tflite_op_creator.h
@@ -42,39 +42,39 @@ using mir::Shape;
class TFLiteOpCreator {
public:
- using InputOps = std::vector&;
- using InputParams = std::vector&;
+ using InputOps = std::vector;
+ using InputParams = std::vector;
explicit TFLiteOpCreator(Graph* g) : _graph(g) {}
- std::vector convertConv2D(InputOps, InputParams, const ::tflite::Conv2DOptions*);
+ std::vector convertConv2D(InputOps&, InputParams&, const ::tflite::Conv2DOptions*);
- std::vector convertDepthwiseConv2D(InputOps, InputParams,
+ std::vector convertDepthwiseConv2D(InputOps&, InputParams&,
const ::tflite::DepthwiseConv2DOptions*);
- std::vector convertConcatenation(InputOps, InputParams,
+ std::vector convertConcatenation(InputOps&, InputParams&,
const ::tflite::ConcatenationOptions*);
- std::vector convertMaxPool2D(InputOps, InputParams,
+ std::vector convertMaxPool2D(InputOps&, InputParams&,
const ::tflite::Pool2DOptions*);
- std::vector convertAveragePool2D(InputOps, InputParams,
+ std::vector convertAveragePool2D(InputOps&, InputParams&,
const ::tflite::Pool2DOptions*);
- std::vector convertReducer(InputOps, InputParams, ops::ReduceFOp::FuncType,
+ std::vector convertReducer(InputOps&, InputParams&, ops::ReduceFOp::FuncType,
const ::tflite::ReducerOptions*);
- std::vector createSoftmax(InputOps, InputParams, const ::tflite::SoftmaxOptions*);
+ std::vector createSoftmax(InputOps&, InputParams&, const ::tflite::SoftmaxOptions*);
- std::vector createSlice(InputOps, InputParams, const ::tflite::SliceOptions*);
-
- std::vector convertReshape(InputOps, InputParams,
+ std::vector createSlice(InputOps&, InputParams&, const ::tflite::SliceOptions*);
+
+ std::vector convertReshape(InputOps&, InputParams&,
const ::tflite::ReshapeOptions*);
- std::vector convertFullyConnected(InputOps, InputParams,
+ std::vector convertFullyConnected(InputOps&, InputParams&,
const ::tflite::FullyConnectedOptions*);
- std::vector convertResizeNN(InputOps, InputParams,
+ std::vector convertResizeNN(InputOps&, InputParams&,
const ::tflite::ResizeNearestNeighborOptions*);
std::vector createLogistic(InputOps& inputs, InputParams& params);
@@ -85,9 +85,9 @@ public:
const ::tflite::SqueezeOptions* opts);
/** @brief Elementwise Add */
- std::vector createAdd(InputOps&, InputParams&, const ::tflite::AddOptions*);
+ std::vector createAdd(InputOps&, const InputParams&, const ::tflite::AddOptions*);
/** @brief Elementwise product */
- std::vector createMul(InputOps&, InputParams&, const ::tflite::MulOptions*);
+ std::vector createMul(InputOps&, const InputParams&, const ::tflite::MulOptions*);
/** @brief Elementwise maximum */
std::vector createMax(InputOps&, InputParams&, const ::tflite::MaximumMinimumOptions*);
/** @brief Elementwise division */
--
2.7.4