From a911075b09a9d183724f974b9f7e56a5f3a75185 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Dmitry=20Mozolev/AI=20Tools=20Lab=20/SRR/Engineer/=EC=82=BC?= =?utf8?q?=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Fri, 3 Aug 2018 17:26:42 +0300 Subject: [PATCH] Add interpreter test and Model IR graph creator that it uses (#872) Graph creator can create a small Model IR graph consisting of an input operator, and one other operator - the one being tested, like Conv2D for example. Signed-off-by: Dmitry Mozolev --- .../interpreter/test/include/graph_creator.h | 8 ++ .../backend/interpreter/test/src/graph_creator.cpp | 143 +++++++++++++++++++++ .../libs/backend/interpreter/test/src/op_test.cpp | 45 +++++++ 3 files changed, 196 insertions(+) create mode 100644 contrib/nnc/libs/backend/interpreter/test/include/graph_creator.h create mode 100644 contrib/nnc/libs/backend/interpreter/test/src/graph_creator.cpp create mode 100644 contrib/nnc/libs/backend/interpreter/test/src/op_test.cpp diff --git a/contrib/nnc/libs/backend/interpreter/test/include/graph_creator.h b/contrib/nnc/libs/backend/interpreter/test/include/graph_creator.h new file mode 100644 index 0000000..ad7ef24 --- /dev/null +++ b/contrib/nnc/libs/backend/interpreter/test/include/graph_creator.h @@ -0,0 +1,8 @@ +#ifndef NNC_INTERPRETER_OP_TEST_GRAPH_CREATOR_H +#define NNC_INTERPRETER_OP_TEST_GRAPH_CREATOR_H + +#include "nnc/core/IR/model/graph/graph.h" + +std::unique_ptr make_graph(const opinfo::OperatorInfo* opInfo); + +#endif // NNC_INTERPRETER_OP_TEST_GRAPH_CREATOR_H diff --git a/contrib/nnc/libs/backend/interpreter/test/src/graph_creator.cpp b/contrib/nnc/libs/backend/interpreter/test/src/graph_creator.cpp new file mode 100644 index 0000000..746b3f5 --- /dev/null +++ b/contrib/nnc/libs/backend/interpreter/test/src/graph_creator.cpp @@ -0,0 +1,143 @@ +#include +#include + +#include "nnc/core/IR/model/operations/variable_op.h" +#include "nnc/core/IR/model/operations/fully_connected_op.h" +#include "nnc/core/IR/model/operations/conv_2d_op.h" +#include "nnc/core/IR/model/operations/depthwise_conv2d_op.h" +#include "nnc/core/IR/model/operations/pool_op.h" +#include "nnc/core/IR/model/operations/relu_op.h" +#include "nnc/core/IR/model/operations/capped_relu_op.h" +#include "nnc/core/IR/model/operations/reshape_op.h" +#include "nnc/core/IR/model/operations/concat_op.h" +#include "nnc/core/IR/model/operations/bias_add_op.h" +#include "nnc/core/IR/model/operations/softmax_op.h" + +#include "nnc/core/IR/model/actions/ShapeInference.h" +#include "shape_helper.h" + +#include "op_info_generated.h" +#include "graph_creator.h" +#include "op_info_util.h" + +using namespace nncc::contrib::frontend::common; +using namespace nncc::contrib::core::IR::model; + +static INode::Ref createFullyConnected(std::unique_ptr& g, const opinfo::OperatorInfo* opInfo) +{ + return g->create( + "y", *getKernel(opInfo)); +} + +static INode::Ref createConv2D(std::unique_ptr& g, const opinfo::OperatorInfo* opInfo) +{ + return g->create( + "y", *getKernel(opInfo), getShapeParam(opInfo, 0), getPaddingType(opInfo)); +} + +static INode::Ref createDepthwiseConv2D(std::unique_ptr& g, const opinfo::OperatorInfo* opInfo) +{ + return g->create( + "y", *getKernel(opInfo), getShapeParam(opInfo, 0), getPaddingType(opInfo)); +} + +static INode::Ref createPool(std::unique_ptr& g, const opinfo::OperatorInfo* opInfo) +{ + return g->create("y", getShapeParam(opInfo, 0), getShapeParam(opInfo, 1), + getPoolingType(opInfo), getPaddingType(opInfo)); +} + +static INode::Ref createConcatenation(std::unique_ptr& g, const opinfo::OperatorInfo* opInfo) +{ + return g->create("y", opInfo->inputs()->size(), getAxis(opInfo)); +} + +static INode::Ref createReshape(std::unique_ptr& g, const opinfo::OperatorInfo* opInfo) +{ + auto op = g->create("y"); + op->getOperation()->setOutputShape(0, getShapeParam(opInfo, 0)); + return op; +} + +static INode::Ref createReLU(std::unique_ptr& g, const opinfo::OperatorInfo* opInfo) +{ + (void)opInfo; + return g->create("y"); +} + +static INode::Ref createCappedReLU(std::unique_ptr& g, const opinfo::OperatorInfo* opInfo) +{ + return g->create("y", getAxis(opInfo)); +} + +static INode::Ref createSoftmax(std::unique_ptr& g, const opinfo::OperatorInfo* opInfo) +{ + return g->create("y", getAxis(opInfo)); +} + +static INode::Ref createBiasAdd(std::unique_ptr& g, const opinfo::OperatorInfo* opInfo) +{ + return g->create("y", *getKernel(opInfo)); +} + +static INode::Ref createOp(std::unique_ptr& g, const opinfo::OperatorInfo* opInfo) +{ + switch (opInfo->op()) + { + case opinfo::OperatorType_FULLY_CONNECTED: + return createFullyConnected(g, opInfo); + case opinfo::OperatorType_CONV_2D: + return createConv2D(g, opInfo); + case opinfo::OperatorType_DEPTHWISE_CONV_2D: + return createDepthwiseConv2D(g, opInfo); + case opinfo::OperatorType_POOL_2D: + return createPool(g, opInfo); + case opinfo::OperatorType_CONCATENATION: + return createConcatenation(g, opInfo); + case opinfo::OperatorType_RESHAPE: + return createReshape(g, opInfo); + case opinfo::OperatorType_RELU: + return createReLU(g, opInfo); + case opinfo::OperatorType_SOFTMAX: + return createSoftmax(g, opInfo); + case opinfo::OperatorType_CAPPED_RELU: + return createCappedReLU(g, opInfo); + case opinfo::OperatorType_BIAS_ADD: + return createBiasAdd(g, opInfo); + default: + assert(false); + } +} + +std::unique_ptr make_graph(const opinfo::OperatorInfo* opInfo) +{ + // Create graph + std::unique_ptr g(new Graph()); + + // Create operation node + auto opNode = createOp(g, opInfo); + + for (unsigned int i = 0; i < opInfo->inputs()->size(); ++i) + { + // Create i-th input node + auto inputNode = g->create("x" + std::to_string(i)); + + // Connect i-th operation input to i-th input node + opNode->connectInputTo(i, inputNode->getOutput(0)); + + // Set input shape + auto inputShapeIter = opInfo->inputs()->Get(i)->shape()->dims(); + Shape inputShape = ShapeHelper::createShape(*inputShapeIter, inputShapeIter->size()); + inputNode->getOperation()->setOutputShape(0, inputShape); + } + + // Mark outputs + g->markOutput(opNode); + + // Run shape inference + auto shapeInferencer = new ShapeInference(); + g->accept(shapeInferencer); + delete shapeInferencer; + + return g; +} diff --git a/contrib/nnc/libs/backend/interpreter/test/src/op_test.cpp b/contrib/nnc/libs/backend/interpreter/test/src/op_test.cpp new file mode 100644 index 0000000..6ffe62a --- /dev/null +++ b/contrib/nnc/libs/backend/interpreter/test/src/op_test.cpp @@ -0,0 +1,45 @@ +#include +#include +#include + +#include "gtest/gtest.h" +#include "op_info_generated.h" + +#include "interpreter/core/Interpreter.h" +#include "nnc/core/IR/model/graph/graph.h" +#include "op_info_util.h" +#include "graph_creator.h" + +using namespace opinfo; +using namespace nncc::contrib::core::IR::model; +using namespace nncc::contrib::backend::interpreter; + +extern std::string opInfoBuf; +extern const OperatorInfoList* list; + +class InterpTestFixture : public ::testing::TestWithParam {}; + +TEST_P(InterpTestFixture, InterpTest) +{ + const OperatorInfo* opInfo = GetParam(); + std::unique_ptr g = make_graph(opInfo); + + auto interpreter = new core::NNInterpreter(); + + for (unsigned int i = 0; i < opInfo->inputs()->size(); ++i) + { + interpreter->setInput("x" + std::to_string(i), *getTensor(opInfo->inputs()->Get(i))); + } + + g->accept(interpreter); + + // TODO: Get and check equality for multiple outputs and results. + auto res = interpreter->getResult(g->getOutput("y"))[0]; + + assertTensorEq(res, *getTensor(opInfo->results()->Get(0))); + + delete interpreter; +} + +INSTANTIATE_TEST_CASE_P(InterpTestSuite, InterpTestFixture, + ::testing::ValuesIn(list->infos()->begin(), list->infos()->end())); -- 2.7.4