[GNA] Detect unsupported concat layers (#7599)
* [GNA] Detect unsupported concat layers * [GNA] Add support for 3D transposes around convolutions and replace exception with user warning
This commit is contained in:
1 parent
afea9e0e87
commit
1c6c7bac2d
13 files changed
+769
-23
No files matched your search
@@ -0,0 +1,495 @@
|
||||
// Copyright (C) 2021 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
//
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
#include <string>
|
||||
|
||||
#include <ie_core.hpp>
|
||||
|
||||
#include "common_test_utils/common_utils.hpp"
|
||||
#include "functional_test_utils/plugin_cache.hpp"
|
||||
#include "shared_test_classes/base/layer_test_utils.hpp"
|
||||
#include "functional_test_utils/blob_utils.hpp"
|
||||
#include "ngraph_functions/utils/ngraph_helpers.hpp"
|
||||
#include "ngraph_functions/builders.hpp"
|
||||
#include "ngraph_functions/pass/convert_prc.hpp"
|
||||
|
||||
/* ============= Concat Layer Restrictions Tests ============= */
|
||||
|
||||
using ConcatRestrictionsParamsTuple = typename std::tuple<
|
||||
InferenceEngine::SizeVector, // Input shapes
|
||||
unsigned int, // Concatenation axis
|
||||
InferenceEngine::Precision, // Network Precision
|
||||
std::map<std::string, std::string>, // Configuration
|
||||
std::string>; // Device name
|
||||
|
||||
namespace ConcatTestsDefinitions {
|
||||
|
||||
struct ReLUConcatAxis {
|
||||
static const char* getName() { return "ReLUConcatAxis"; }
|
||||
static std::shared_ptr<ngraph::Function> createTopology(const InferenceEngine::SizeVector& inputShape, const unsigned int& axis,
|
||||
const InferenceEngine::Precision& netPrecision) {
|
||||
auto ngPrc = FuncTestUtils::PrecisionUtils::convertIE2nGraphPrc(netPrecision);
|
||||
ngraph::OutputVector concatInputs;
|
||||
|
||||
ngraph::ParameterVector params = ngraph::builder::makeParams(ngPrc, {inputShape});
|
||||
auto relu = ngraph::builder::makeActivation(params[0], ngPrc, ngraph::helpers::ActivationTypes::Relu);
|
||||
concatInputs.push_back(relu);
|
||||
size_t totalSize = ngraph::shape_size(inputShape);
|
||||
auto constValues = CommonTestUtils::generate_float_numbers(totalSize, -0.1f, 0.1f);
|
||||
auto constNode = ngraph::builder::makeConstant(ngPrc, {inputShape}, constValues);
|
||||
concatInputs.push_back(constNode);
|
||||
auto concat = ngraph::builder::makeConcat(concatInputs, axis);
|
||||
|
||||
ngraph::ResultVector results{std::make_shared<ngraph::opset8::Result>(concat)};
|
||||
return std::make_shared<ngraph::Function>(results, params, getName());
|
||||
}
|
||||
static const char* getMatch() { return "type: Concat, and concatenation axis("; }
|
||||
};
|
||||
|
||||
struct MatmulConcatAxis {
|
||||
static const char* getName() { return "MatmulConcatAxis"; }
|
||||
static std::shared_ptr<ngraph::Function> createTopology(const InferenceEngine::SizeVector& inputShape, const unsigned int& axis,
|
||||
const InferenceEngine::Precision& netPrecision) {
|
||||
auto ngPrc = FuncTestUtils::PrecisionUtils::convertIE2nGraphPrc(netPrecision);
|
||||
ngraph::OutputVector concatInputs;
|
||||
ngraph::ParameterVector params = ngraph::builder::makeParams(ngPrc, {inputShape});
|
||||
ngraph::Shape mulConstShape;
|
||||
|
||||
switch (inputShape.size()) {
|
||||
default:
|
||||
case 2:
|
||||
mulConstShape = {inputShape[1], inputShape[1]};
|
||||
break;
|
||||
case 3:
|
||||
mulConstShape = {inputShape[0], inputShape[2], inputShape[2]};
|
||||
break;
|
||||
case 4:
|
||||
mulConstShape = {inputShape[0], inputShape[1], inputShape[3], inputShape[3]};
|
||||
break;
|
||||
}
|
||||
|
||||
size_t mulConstSize = ngraph::shape_size(mulConstShape);
|
||||
std::vector<float> weights1(mulConstSize);
|
||||
std::vector<float> weights2(mulConstSize);
|
||||
std::iota(weights1.begin(), weights1.end(), 0.0f);
|
||||
std::iota(weights2.begin(), weights2.end(), 0.0f);
|
||||
auto constMul1 = ngraph::builder::makeConstant<float>(ngPrc, mulConstShape, weights1);
|
||||
auto constMul2 = ngraph::builder::makeConstant<float>(ngPrc, mulConstShape, weights2);
|
||||
auto matmul1 = std::make_shared<ngraph::opset8::MatMul>(params[0], constMul1, false, true);
|
||||
concatInputs.push_back(matmul1);
|
||||
auto matmul2 = std::make_shared<ngraph::opset8::MatMul>(params[0], constMul2, false, true);
|
||||
concatInputs.push_back(matmul2);
|
||||
auto concat = ngraph::builder::makeConcat(concatInputs, axis);
|
||||
|
||||
ngraph::ResultVector results{std::make_shared<ngraph::opset8::Result>(concat)};
|
||||
return std::make_shared<ngraph::Function>(results, params, getName());
|
||||
}
|
||||
static const char* getMatch() { return "type: Concat, and concatenation axis("; }
|
||||
};
|
||||
|
||||
struct ConvNCHWConcatAxis {
|
||||
static const char* getName() { return "ConvNCHWConcatAxis"; }
|
||||
static std::shared_ptr<ngraph::Function> createTopology(const InferenceEngine::SizeVector& inputShape, const unsigned int& axis,
|
||||
const InferenceEngine::Precision& netPrecision) {
|
||||
auto ngPrc = FuncTestUtils::PrecisionUtils::convertIE2nGraphPrc(netPrecision);
|
||||
ngraph::OutputVector concatInputs;
|
||||
ngraph::ParameterVector params = ngraph::builder::makeParams(ngPrc, {inputShape});
|
||||
|
||||
size_t numOutChannels = 8;
|
||||
size_t kernelSize = 1;
|
||||
std::vector<float> filterWeights = CommonTestUtils::generate_float_numbers(numOutChannels * inputShape[1] * kernelSize,
|
||||
-0.2f, 0.2f);
|
||||
auto conv = ngraph::builder::makeConvolution(params[0], ngPrc, {1, kernelSize}, {1, 1}, {0, 0}, {0, 0}, {1, 1},
|
||||
ngraph::op::PadType::VALID, numOutChannels, true, filterWeights);
|
||||
|
||||
concatInputs.push_back(conv);
|
||||
size_t totalSize = ngraph::shape_size(inputShape);
|
||||
auto constValues = CommonTestUtils::generate_float_numbers(totalSize, -0.0001f, 0.0001f);
|
||||
auto constNode = ngraph::builder::makeConstant(ngPrc, {inputShape}, constValues);
|
||||
concatInputs.push_back(constNode);
|
||||
auto concat = ngraph::builder::makeConcat(concatInputs, axis);
|
||||
|
||||
ngraph::ResultVector results{std::make_shared<ngraph::opset8::Result>(concat)};
|
||||
return std::make_shared<ngraph::Function>(results, params, getName());
|
||||
}
|
||||
static const char* getMatch() { return "for input dimensions"; }
|
||||
};
|
||||
|
||||
struct ConvNHWCConcatAxis {
|
||||
static const char* getName() { return "ConvNHWCConcatAxis"; }
|
||||
static std::shared_ptr<ngraph::Function> createTopology(const InferenceEngine::SizeVector& inputShape, const unsigned int& axis,
|
||||
const InferenceEngine::Precision& netPrecision) {
|
||||
auto ngPrc = FuncTestUtils::PrecisionUtils::convertIE2nGraphPrc(netPrecision);
|
||||
ngraph::OutputVector concatInputs;
|
||||
ngraph::ParameterVector params = ngraph::builder::makeParams(ngPrc, {inputShape});
|
||||
|
||||
auto transposeInOrder = ngraph::op::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {0, 3, 1, 2});
|
||||
auto transposeIn = std::make_shared<ngraph::opset8::Transpose>(params[0], transposeInOrder);
|
||||
size_t numOutChannels = 8;
|
||||
size_t kernelSize = 1;
|
||||
std::vector<float> filterWeights = CommonTestUtils::generate_float_numbers(numOutChannels * inputShape[3] * kernelSize,
|
||||
-0.2f, 0.2f);
|
||||
auto conv = ngraph::builder::makeConvolution(transposeIn, ngPrc, {1, kernelSize}, {1, 1}, {0, 0}, {0, 0}, {1, 1},
|
||||
ngraph::op::PadType::VALID, numOutChannels, true, filterWeights);
|
||||
auto transposeOutOrder = ngraph::op::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {0, 2, 3, 1});
|
||||
auto transposeOut = std::make_shared<ngraph::opset8::Transpose>(conv, transposeOutOrder);
|
||||
|
||||
concatInputs.push_back(transposeOut);
|
||||
size_t totalSize = ngraph::shape_size(inputShape);
|
||||
auto constValues = CommonTestUtils::generate_float_numbers(totalSize, -0.0001f, 0.0001f);
|
||||
auto constNode = ngraph::builder::makeConstant(ngPrc, {inputShape}, constValues);
|
||||
concatInputs.push_back(constNode);
|
||||
auto concat = ngraph::builder::makeConcat(concatInputs, axis);
|
||||
|
||||
ngraph::ResultVector results{std::make_shared<ngraph::opset8::Result>(concat)};
|
||||
return std::make_shared<ngraph::Function>(results, params, getName());
|
||||
}
|
||||
static const char* getMatch() { return "type: Concat, and concatenation axis("; }
|
||||
};
|
||||
|
||||
struct ConvConcatNHWCAxis {
|
||||
static const char* getName() { return "ConvConcatNHWCAxis"; }
|
||||
static std::shared_ptr<ngraph::Function> createTopology(const InferenceEngine::SizeVector& inputShape, const unsigned int& axis,
|
||||
const InferenceEngine::Precision& netPrecision) {
|
||||
auto ngPrc = FuncTestUtils::PrecisionUtils::convertIE2nGraphPrc(netPrecision);
|
||||
ngraph::OutputVector concatInputs;
|
||||
ngraph::ParameterVector params = ngraph::builder::makeParams(ngPrc, {inputShape});
|
||||
|
||||
auto transposeInOrder = ngraph::op::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {0, 3, 1, 2});
|
||||
auto transposeIn1 = std::make_shared<ngraph::opset8::Transpose>(params[0], transposeInOrder);
|
||||
auto transposeIn2 = std::make_shared<ngraph::opset8::Transpose>(params[0], transposeInOrder);
|
||||
size_t numOutChannels = 8;
|
||||
size_t kernelSize = 1;
|
||||
std::vector<float> filterWeights1 = CommonTestUtils::generate_float_numbers(numOutChannels * inputShape[3] * kernelSize,
|
||||
-0.1f, 2.2f);
|
||||
std::vector<float> filterWeights2 = CommonTestUtils::generate_float_numbers(numOutChannels * inputShape[3] * kernelSize,
|
||||
-1.2f, 0.5f);
|
||||
auto conv1 = ngraph::builder::makeConvolution(transposeIn1, ngPrc, {1, kernelSize}, {1, 1}, {0, 0}, {0, 0}, {1, 1},
|
||||
ngraph::op::PadType::VALID, numOutChannels, true, filterWeights1);
|
||||
auto conv2 = ngraph::builder::makeConvolution(transposeIn2, ngPrc, {1, kernelSize}, {1, 1}, {0, 0}, {0, 0}, {1, 1},
|
||||
ngraph::op::PadType::VALID, numOutChannels, true, filterWeights2);
|
||||
|
||||
concatInputs.push_back(conv1);
|
||||
concatInputs.push_back(conv2);
|
||||
auto concat = ngraph::builder::makeConcat(concatInputs, axis);
|
||||
|
||||
auto transposeOutOrder = ngraph::op::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {0, 2, 3, 1});
|
||||
auto transposeOut = std::make_shared<ngraph::opset8::Transpose>(concat, transposeOutOrder);
|
||||
|
||||
ngraph::ResultVector results{std::make_shared<ngraph::opset8::Result>(transposeOut)};
|
||||
return std::make_shared<ngraph::Function>(results, params, getName());
|
||||
}
|
||||
static const char* getMatch() { return "type: Concat, and concatenation axis("; }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class ConcatRestrictions : public testing::WithParamInterface<ConcatRestrictionsParamsTuple>,
|
||||
public LayerTestsUtils::LayerTestsCommon {
|
||||
public:
|
||||
static std::string getTestCaseName(testing::TestParamInfo<ConcatRestrictionsParamsTuple> obj) {
|
||||
InferenceEngine::SizeVector inputShape;
|
||||
unsigned int concatAxis;
|
||||
InferenceEngine::Precision netPrecision;
|
||||
std::map<std::string, std::string> configuration;
|
||||
std::string targetDevice;
|
||||
std::tie(inputShape, concatAxis, netPrecision, configuration, targetDevice) = obj.param;
|
||||
std::ostringstream result;
|
||||
result << T::getName() << "_";
|
||||
result << "inputShape=" << CommonTestUtils::vec2str(inputShape) << "_";
|
||||
result << "concatAxis=" << concatAxis << "_";
|
||||
result << "netPRC=" << netPrecision.name() << "_";
|
||||
result << "targetDevice=" << targetDevice << "_";
|
||||
for (auto const& configItem : configuration) {
|
||||
result << "configItem=" << configItem.first << "_" << configItem.second << "_";
|
||||
}
|
||||
return result.str();
|
||||
}
|
||||
static const char* getMatch() { return T::getMatch(); }
|
||||
protected:
|
||||
void SetUp() override {
|
||||
InferenceEngine::SizeVector inputShape;
|
||||
unsigned int concatAxis;
|
||||
InferenceEngine::Precision netPrecision;
|
||||
std::tie(inputShape, concatAxis, netPrecision, configuration, targetDevice) = this->GetParam();
|
||||
function = T::createTopology(inputShape, concatAxis, netPrecision);
|
||||
}
|
||||
};
|
||||
|
||||
using ReLUConcatRestrictionsNeg = ConcatRestrictions<ReLUConcatAxis>;
|
||||
using ReLUConcatRestrictionsPos = ConcatRestrictions<ReLUConcatAxis>;
|
||||
using MatMulConcatRestrictionsNeg = ConcatRestrictions<MatmulConcatAxis>;
|
||||
using MatMulConcatRestrictionsPos = ConcatRestrictions<MatmulConcatAxis>;
|
||||
using ConvNCHWConcatRestrictionsNeg = ConcatRestrictions<ConvNCHWConcatAxis>;
|
||||
using ConvNCHWConcatRestrictionsPos = ConcatRestrictions<ConvNCHWConcatAxis>;
|
||||
using ConvNHWCConcatRestrictionsNeg = ConcatRestrictions<ConvNHWCConcatAxis>;
|
||||
using ConvNHWCConcatRestrictionsPos = ConcatRestrictions<ConvNHWCConcatAxis>;
|
||||
using ConvConcatNHWCRestrictionsNeg = ConcatRestrictions<ConvConcatNHWCAxis>;
|
||||
using ConvConcatNHWCRestrictionsPos = ConcatRestrictions<ConvConcatNHWCAxis>;
|
||||
|
||||
TEST_P(ReLUConcatRestrictionsNeg, CompareWithRefImpl) {
|
||||
std::stringstream what;
|
||||
std::streambuf* sbuf = std::cout.rdbuf();
|
||||
std::cout.rdbuf(what.rdbuf());
|
||||
LoadNetwork();
|
||||
EXPECT_TRUE(what.str().find(getMatch()) != std::string::npos);
|
||||
std::cout.rdbuf(sbuf);
|
||||
};
|
||||
|
||||
// TODO: this test is left for future when GNA plugin handles const tranposition required for concats with interleaved layers
|
||||
//TEST_P(ReLUConcatRestrictionsPos, CompareWithRefImpl) {
|
||||
// Run();
|
||||
//};
|
||||
|
||||
TEST_P(MatMulConcatRestrictionsNeg, CompareWithRefImpl) {
|
||||
std::stringstream what;
|
||||
std::streambuf* sbuf = std::cout.rdbuf();
|
||||
std::cout.rdbuf(what.rdbuf());
|
||||
LoadNetwork();
|
||||
EXPECT_TRUE(what.str().find(getMatch()) != std::string::npos);
|
||||
std::cout.rdbuf(sbuf);
|
||||
};
|
||||
|
||||
TEST_P(MatMulConcatRestrictionsPos, CompareWithRefImpl) {
|
||||
Run();
|
||||
};
|
||||
|
||||
TEST_P(ConvNCHWConcatRestrictionsNeg, CompareWithRefImpl) {
|
||||
std::string what;
|
||||
try {
|
||||
LoadNetwork();
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
what.assign(e.what());
|
||||
}
|
||||
EXPECT_TRUE(what.find(getMatch()) != std::string::npos);
|
||||
};
|
||||
|
||||
TEST_P(ConvNCHWConcatRestrictionsPos, CompareWithRefImpl) {
|
||||
Run();
|
||||
};
|
||||
|
||||
TEST_P(ConvNHWCConcatRestrictionsNeg, CompareWithRefImpl) {
|
||||
std::stringstream what;
|
||||
std::streambuf* sbuf = std::cout.rdbuf();
|
||||
std::cout.rdbuf(what.rdbuf());
|
||||
LoadNetwork();
|
||||
EXPECT_TRUE(what.str().find(getMatch()) != std::string::npos);
|
||||
std::cout.rdbuf(sbuf);
|
||||
};
|
||||
|
||||
TEST_P(ConvNHWCConcatRestrictionsPos, CompareWithRefImpl) {
|
||||
Run();
|
||||
};
|
||||
|
||||
TEST_P(ConvConcatNHWCRestrictionsNeg, CompareWithRefImpl) {
|
||||
std::stringstream what;
|
||||
std::streambuf* sbuf = std::cout.rdbuf();
|
||||
std::cout.rdbuf(what.rdbuf());
|
||||
LoadNetwork();
|
||||
EXPECT_TRUE(what.str().find(getMatch()) != std::string::npos);
|
||||
std::cout.rdbuf(sbuf);
|
||||
};
|
||||
|
||||
TEST_P(ConvConcatNHWCRestrictionsPos, CompareWithRefImpl) {
|
||||
Run();
|
||||
};
|
||||
|
||||
const std::vector<InferenceEngine::Precision> netPrecisions = {InferenceEngine::Precision::FP32};
|
||||
const std::vector<std::map<std::string, std::string>> configs = {
|
||||
{
|
||||
{"GNA_DEVICE_MODE", "GNA_SW_FP32"},
|
||||
{"LOG_LEVEL", "LOG_WARNING"}
|
||||
}
|
||||
};
|
||||
|
||||
// Negative 4D MatMul cases
|
||||
const std::vector<std::vector<size_t>> inputShapesMatMul4D_neg = {{1, 2, 4, 8}};
|
||||
const std::vector<unsigned int> concatAxisMatMul4D_neg = {2, 3};
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(smoke_concat_restrictions_matmul_4d, MatMulConcatRestrictionsNeg,
|
||||
::testing::Combine(
|
||||
::testing::ValuesIn(inputShapesMatMul4D_neg),
|
||||
::testing::ValuesIn(concatAxisMatMul4D_neg),
|
||||
::testing::ValuesIn(netPrecisions),
|
||||
::testing::ValuesIn(configs),
|
||||
::testing::Values(CommonTestUtils::DEVICE_GNA)),
|
||||
MatMulConcatRestrictionsNeg::getTestCaseName);
|
||||
|
||||
// Positive 4D MatMul cases - TODO: this test fails with 4D Gemm computation errors
|
||||
//const std::vector<std::vector<size_t>> inputShapesMatMul4D_pos = {{1, 2, 4, 8}};
|
||||
//const std::vector<unsigned int> concatAxisMatMul4D_pos = {0, 1};
|
||||
//
|
||||
//INSTANTIATE_TEST_SUITE_P(smoke_concat_restrictions_matmul_4d, MatMulConcatRestrictionsPos,
|
||||
// ::testing::Combine(
|
||||
// ::testing::ValuesIn(inputShapesMatMul4D_pos),
|
||||
// ::testing::ValuesIn(concatAxisMatMul4D_pos),
|
||||
// ::testing::ValuesIn(netPrecisions),
|
||||
// ::testing::ValuesIn(configs),
|
||||
// ::testing::Values(CommonTestUtils::DEVICE_GNA)),
|
||||
// MatMulConcatRestrictionsPos::getTestCaseName);
|
||||
|
||||
// Negative 3D MatMul cases
|
||||
const std::vector<std::vector<size_t>> inputShapesMatMul3D_neg = {{2, 4, 8}};
|
||||
const std::vector<unsigned int> concatAxisMatMul3D_neg = {0, 2};
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(smoke_concat_restrictions_matmul_3d, MatMulConcatRestrictionsNeg,
|
||||
::testing::Combine(
|
||||
::testing::ValuesIn(inputShapesMatMul3D_neg),
|
||||
::testing::ValuesIn(concatAxisMatMul3D_neg),
|
||||
::testing::ValuesIn(netPrecisions),
|
||||
::testing::ValuesIn(configs),
|
||||
::testing::Values(CommonTestUtils::DEVICE_GNA)),
|
||||
MatMulConcatRestrictionsNeg::getTestCaseName);
|
||||
|
||||
// Positive 3D MatMul cases - TODO: this test fails with 3D Gemm computation errors
|
||||
//const std::vector<std::vector<size_t>> inputShapesMatMul3D_pos = {{2, 4, 8}};
|
||||
//const std::vector<unsigned int> concatAxisMatMul3D_pos = {1};
|
||||
//
|
||||
//INSTANTIATE_TEST_SUITE_P(smoke_concat_restrictions_matmul_3d, MatMulConcatRestrictionsPos,
|
||||
// ::testing::Combine(
|
||||
// ::testing::ValuesIn(inputShapesMatMul3D_pos),
|
||||
// ::testing::ValuesIn(concatAxisMatMul3D_pos),
|
||||
// ::testing::ValuesIn(netPrecisions),
|
||||
// ::testing::ValuesIn(configs),
|
||||
// ::testing::Values(CommonTestUtils::DEVICE_GNA)),
|
||||
// MatMulConcatRestrictionsPos::getTestCaseName);
|
||||
|
||||
// Negative 2D MatMul cases
|
||||
const std::vector<std::vector<size_t>> inputShapesMatMul2D_neg = {{8, 64}};
|
||||
const std::vector<unsigned int> concatAxisMatMul2D_neg = {0};
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(smoke_concat_restrictions_matmul_2d, MatMulConcatRestrictionsNeg,
|
||||
::testing::Combine(
|
||||
::testing::ValuesIn(inputShapesMatMul2D_neg),
|
||||
::testing::ValuesIn(concatAxisMatMul2D_neg),
|
||||
::testing::ValuesIn(netPrecisions),
|
||||
::testing::ValuesIn(configs),
|
||||
::testing::Values(CommonTestUtils::DEVICE_GNA)),
|
||||
MatMulConcatRestrictionsNeg::getTestCaseName);
|
||||
|
||||
// Positive 2D MatMul cases
|
||||
const std::vector<std::vector<size_t>> inputShapesMatMul2D_pos = {{8, 64}};
|
||||
const std::vector<unsigned int> concatAxisMatMul2D_pos = {1};
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(smoke_concat_restrictions_matmul_2d, MatMulConcatRestrictionsPos,
|
||||
::testing::Combine(
|
||||
::testing::ValuesIn(inputShapesMatMul2D_pos),
|
||||
::testing::ValuesIn(concatAxisMatMul2D_pos),
|
||||
::testing::ValuesIn(netPrecisions),
|
||||
::testing::ValuesIn(configs),
|
||||
::testing::Values(CommonTestUtils::DEVICE_GNA)),
|
||||
MatMulConcatRestrictionsPos::getTestCaseName);
|
||||
|
||||
// Negative ReLU cases
|
||||
const std::vector<std::vector<size_t>> inputShapesReLU_neg = {{64, 128}};
|
||||
const std::vector<unsigned int> concatAxisReLU_neg = {0};
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(smoke_concat_restrictions_relu, ReLUConcatRestrictionsNeg,
|
||||
::testing::Combine(
|
||||
::testing::ValuesIn(inputShapesReLU_neg),
|
||||
::testing::ValuesIn(concatAxisReLU_neg),
|
||||
::testing::ValuesIn(netPrecisions),
|
||||
::testing::ValuesIn(configs),
|
||||
::testing::Values(CommonTestUtils::DEVICE_GNA)),
|
||||
ReLUConcatRestrictionsNeg::getTestCaseName);
|
||||
|
||||
// Positive ReLU cases
|
||||
const std::vector<std::vector<size_t>> inputShapesReLU_pos = {{64, 128}};
|
||||
const std::vector<unsigned int> concatAxisReLU_pos = {1};
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(smoke_concat_restrictions_relu, ReLUConcatRestrictionsPos,
|
||||
::testing::Combine(
|
||||
::testing::ValuesIn(inputShapesReLU_pos),
|
||||
::testing::ValuesIn(concatAxisReLU_pos),
|
||||
::testing::ValuesIn(netPrecisions),
|
||||
::testing::ValuesIn(configs),
|
||||
::testing::Values(CommonTestUtils::DEVICE_GNA)),
|
||||
ReLUConcatRestrictionsPos::getTestCaseName);
|
||||
|
||||
// Negative cases NCHW
|
||||
const std::vector<std::vector<size_t>> inputShapesConvNCHW_neg = {{1, 8, 16, 32}};
|
||||
const std::vector<unsigned int> concatAxisConvNCHW_neg = {3}; // Axis 1 should be negative as well,
|
||||
// but is handled by the plugin in this case
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(smoke_concat_restrictions, ConvNCHWConcatRestrictionsNeg,
|
||||
::testing::Combine(
|
||||
::testing::ValuesIn(inputShapesConvNCHW_neg),
|
||||
::testing::ValuesIn(concatAxisConvNCHW_neg),
|
||||
::testing::ValuesIn(netPrecisions),
|
||||
::testing::ValuesIn(configs),
|
||||
::testing::Values(CommonTestUtils::DEVICE_GNA)),
|
||||
ConvNCHWConcatRestrictionsNeg::getTestCaseName);
|
||||
|
||||
// Positive cases NCHW
|
||||
const std::vector<std::vector<size_t>> inputShapesConvNCHW_pos = {{1, 8, 1, 64}};
|
||||
const std::vector<unsigned int> concatAxisConvNCHW_pos = {2, 3}; // TODO: incorrect output buffer calculation
|
||||
// when 0 axis is used
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(smoke_concat_restrictions, ConvNCHWConcatRestrictionsPos,
|
||||
::testing::Combine(
|
||||
::testing::ValuesIn(inputShapesConvNCHW_pos),
|
||||
::testing::ValuesIn(concatAxisConvNCHW_pos),
|
||||
::testing::ValuesIn(netPrecisions),
|
||||
::testing::ValuesIn(configs),
|
||||
::testing::Values(CommonTestUtils::DEVICE_GNA)),
|
||||
ConvNCHWConcatRestrictionsPos::getTestCaseName);
|
||||
|
||||
// Negative cases NHWC
|
||||
const std::vector<std::vector<size_t>> inputShapesNHWC_neg = {{1, 2, 16, 8}};
|
||||
const std::vector<unsigned int> concatAxisNHWC_neg = {2, 3};
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(smoke_concat_restrictions, ConvNHWCConcatRestrictionsNeg,
|
||||
::testing::Combine(
|
||||
::testing::ValuesIn(inputShapesNHWC_neg),
|
||||
::testing::ValuesIn(concatAxisNHWC_neg),
|
||||
::testing::ValuesIn(netPrecisions),
|
||||
::testing::ValuesIn(configs),
|
||||
::testing::Values(CommonTestUtils::DEVICE_GNA)),
|
||||
ConvNHWCConcatRestrictionsNeg::getTestCaseName);
|
||||
|
||||
// Positive cases NHWC
|
||||
const std::vector<std::vector<size_t>> inputShapesNHWC_pos = {{1, 1, 16, 8}};
|
||||
const std::vector<unsigned int> concatAxisNHWC_pos = {1, 2};
|
||||
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(smoke_concat_restrictions, ConvNHWCConcatRestrictionsPos,
|
||||
::testing::Combine(
|
||||
::testing::ValuesIn(inputShapesNHWC_pos),
|
||||
::testing::ValuesIn(concatAxisNHWC_pos),
|
||||
::testing::ValuesIn(netPrecisions),
|
||||
::testing::ValuesIn(configs),
|
||||
::testing::Values(CommonTestUtils::DEVICE_GNA)),
|
||||
ConvNHWCConcatRestrictionsPos::getTestCaseName);
|
||||
|
||||
// Negative cases NHWC with concat inside transposes - TODO: this test fails, because the transposes are not removed
|
||||
//const std::vector<std::vector<size_t>> inputShapesConcatNHWC_neg = {{1, 1, 16, 8}};
|
||||
//const std::vector<unsigned int> concatAxisConcatNHWC_neg = {1};
|
||||
//
|
||||
//INSTANTIATE_TEST_SUITE_P(smoke_concat_restrictions, ConvConcatNHWCRestrictionsNeg,
|
||||
// ::testing::Combine(
|
||||
// ::testing::ValuesIn(inputShapesConcatNHWC_neg),
|
||||
// ::testing::ValuesIn(concatAxisConcatNHWC_neg),
|
||||
// ::testing::ValuesIn(netPrecisions),
|
||||
// ::testing::ValuesIn(configs),
|
||||
// ::testing::Values(CommonTestUtils::DEVICE_GNA)),
|
||||
// ConvConcatNHWCRestrictionsNeg::getTestCaseName);
|
||||
|
||||
// Positive cases NHWC with concat inside transposes
|
||||
const std::vector<std::vector<size_t>> inputShapesConcatNHWC_pos = {{1, 1, 16, 8}};
|
||||
const std::vector<unsigned int> concatAxisConcatNHWC_pos = {2, 3}; // TODO: 0 fails with unsupported permute,
|
||||
// because the transposes are not removed
|
||||
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(smoke_concat_restrictions, ConvConcatNHWCRestrictionsPos,
|
||||
::testing::Combine(
|
||||
::testing::ValuesIn(inputShapesConcatNHWC_pos),
|
||||
::testing::ValuesIn(concatAxisConcatNHWC_pos),
|
||||
::testing::ValuesIn(netPrecisions),
|
||||
::testing::ValuesIn(configs),
|
||||
::testing::Values(CommonTestUtils::DEVICE_GNA)),
|
||||
ConvConcatNHWCRestrictionsPos::getTestCaseName);
|
||||
|
||||
} // namespace ConcatTestsDefinitions
|
||||
@@ -26,7 +26,8 @@ const std::map<std::string, std::string> supportedConfigKeysWithDefaults = {
|
||||
{GNA_CONFIG_KEY(PWL_MAX_ERROR_PERCENT), "1.000000"},
|
||||
{CONFIG_KEY(PERF_COUNT), CONFIG_VALUE(NO)},
|
||||
{GNA_CONFIG_KEY(LIB_N_THREADS), "1"},
|
||||
{CONFIG_KEY(SINGLE_THREAD), CONFIG_VALUE(YES)}
|
||||
{CONFIG_KEY(SINGLE_THREAD), CONFIG_VALUE(YES)},
|
||||
{CONFIG_KEY(LOG_LEVEL), PluginConfigParams::LOG_NONE}
|
||||
};
|
||||
|
||||
class GNAPluginConfigTest : public ::testing::Test {
|
||||
@@ -216,3 +217,14 @@ TEST_F(GNAPluginConfigTest, GnaConfigGnaCompileTargetTest) {
|
||||
ExpectThrow(GNA_CONFIG_KEY(COMPILE_TARGET), "GNA_TARGET_1_5");
|
||||
ExpectThrow(GNA_CONFIG_KEY(COMPILE_TARGET), "GNA_TARGET");
|
||||
}
|
||||
|
||||
TEST_F(GNAPluginConfigTest, GnaConfigLogLevel) {
|
||||
SetAndCompare(CONFIG_KEY(LOG_LEVEL), PluginConfigParams::LOG_WARNING);
|
||||
EXPECT_EQ(config.gnaFlags.log_level, PluginConfigParams::LOG_WARNING);
|
||||
SetAndCompare(CONFIG_KEY(LOG_LEVEL), PluginConfigParams::LOG_NONE);
|
||||
EXPECT_EQ(config.gnaFlags.log_level, PluginConfigParams::LOG_NONE);
|
||||
ExpectThrow(CONFIG_KEY(LOG_LEVEL), PluginConfigParams::LOG_ERROR);
|
||||
ExpectThrow(CONFIG_KEY(LOG_LEVEL), PluginConfigParams::LOG_INFO);
|
||||
ExpectThrow(CONFIG_KEY(LOG_LEVEL), PluginConfigParams::LOG_DEBUG);
|
||||
ExpectThrow(CONFIG_KEY(LOG_LEVEL), PluginConfigParams::LOG_TRACE);
|
||||
}
|
||||
@@ -685,6 +685,7 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
gnaPluginConfig[GNAConfigParams::KEY_GNA_EXEC_TARGET] = FLAGS_exec_target;
|
||||
gnaPluginConfig[GNAConfigParams::KEY_GNA_COMPILE_TARGET] = FLAGS_compile_target;
|
||||
gnaPluginConfig[PluginConfigParams::KEY_LOG_LEVEL] = FLAGS_log;
|
||||
gnaPluginConfig[GNAConfigParams::KEY_GNA_LIB_N_THREADS] =
|
||||
std::to_string((FLAGS_cw_r > 0 || FLAGS_cw_l > 0) ? 1 : FLAGS_nthreads);
|
||||
gnaPluginConfig[GNA_CONFIG_KEY(COMPACT_MODE)] = CONFIG_VALUE(NO);
|
||||
|
||||
@@ -43,6 +43,11 @@ static const char compile_target_message[] = "Optional. Specify GNA compile targ
|
||||
"or the latest fully supported generation by the software. "
|
||||
"See the GNA Plugin's GNA_COMPILE_TARGET config option description.";
|
||||
|
||||
/// @brief message for enabling GNA log
|
||||
static const char enable_log_message[] = "Optional. Enable GNA logging, which may give additional info "
|
||||
"about potential issues found in network. "
|
||||
"By default logging is disabled.";
|
||||
|
||||
/// @brief message for performance counters
|
||||
static const char performance_counter_message[] = "Optional. Enables per-layer performance report.";
|
||||
|
||||
@@ -140,6 +145,9 @@ DEFINE_string(exec_target, "", execution_target_message);
|
||||
/// \brief GNA compile target <br>
|
||||
DEFINE_string(compile_target, "", compile_target_message);
|
||||
|
||||
/// \brief GNA log level (default LOG_NONE) <br>
|
||||
DEFINE_string(log, "LOG_NONE", enable_log_message);
|
||||
|
||||
/// \brief Enable per-layer performance report
|
||||
DEFINE_bool(pc, false, performance_counter_message);
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <legacy/graph_tools.hpp>
|
||||
#include <layers/gna_layer_type.hpp>
|
||||
#include <layers/gna_layer_info.hpp>
|
||||
#include "gna_graph_tools.hpp"
|
||||
|
||||
namespace GNAPluginNS {
|
||||
namespace GNALimitations {
|
||||
@@ -167,8 +168,182 @@ void Validator::ThrowIfNotEmpty(const std::string prefix, const std::string erro
|
||||
|
||||
} // namespace Cnn2D
|
||||
|
||||
bool AreLayersSupported(InferenceEngine::CNNNetwork& network, std::string& errMessage) {
|
||||
IE_SUPPRESS_DEPRECATED_START
|
||||
IE_SUPPRESS_DEPRECATED_START
|
||||
static bool ValidateConcatAxis(const InferenceEngine::CNNLayerPtr layer, std::string& errMessage) {
|
||||
LayerInfo info(layer);
|
||||
auto concat_layer = info.as<InferenceEngine::ConcatLayer*>();
|
||||
IE_ASSERT(concat_layer);
|
||||
auto dims_size = concat_layer->insData[0].lock()->getDims().size();
|
||||
auto in_dims = concat_layer->insData[0].lock()->getDims();
|
||||
auto concat_axis = concat_layer->_axis;
|
||||
|
||||
if (dims_size >= 2) {
|
||||
InferenceEngine::CNNLayerPtr prev_layer, pre_prev_layer;
|
||||
// Skip all convolutions in this check, they will be handled during concat primitive creation
|
||||
auto isFusableWithConv = [](InferenceEngine::CNNLayerPtr ptr) {
|
||||
return (LayerInfo(ptr).isFusableWithConv() || LayerInfo(ptr).isNonFunctional() ||
|
||||
(LayerInfo(ptr).isPermute() && ((ptr->input()->getLayout() == InferenceEngine::Layout::NCHW &&
|
||||
ptr->GetParamAsInts("order") == GetPermuteOrder(InferenceEngine::Layout::NCHW, InferenceEngine::Layout::NHWC)) ||
|
||||
(ptr->input()->getLayout() == InferenceEngine::Layout::CHW &&
|
||||
ptr->GetParamAsInts("order") == std::vector<int32_t>{0, 2, 1} /* NCW to NWC */))));
|
||||
};
|
||||
|
||||
for (auto input_idx = 0; input_idx != concat_layer->insData.size(); input_idx++) {
|
||||
prev_layer = InferenceEngine::CNNNetPrevLayerSkipCertain(layer, input_idx, isFusableWithConv);
|
||||
if (prev_layer && LayerInfo(prev_layer).isConvolution())
|
||||
return true;
|
||||
}
|
||||
|
||||
// Look for trivial cases which will be flattened later
|
||||
// for explanation of what is meant by trivial case,
|
||||
// look to FlattenTrivialConcatPass comments
|
||||
// TODO: detection of trivial cases could be moved to one common place
|
||||
// when all transformations are migrated to ngraph
|
||||
bool is_not_trivial_concat = false;
|
||||
|
||||
// Concatentaion of consts and input parameters only is supported, even if first dimentsion of input parameter > 1
|
||||
bool concat_all_const_or_inputs = false;
|
||||
|
||||
// If concat axis > 0, detect any dimension > 1 before the concat axis
|
||||
if (concat_axis > 0) {
|
||||
for (auto axis = 0; axis < concat_axis; axis++) {
|
||||
if (in_dims[axis] > 1) {
|
||||
is_not_trivial_concat = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If concat axis == 0, detect any preceding functional layer's input
|
||||
// with 0'th dimension > 1, but take into account that some layers need to be skipped
|
||||
} else {
|
||||
concat_all_const_or_inputs = true;
|
||||
|
||||
for (auto input_idx = 0; input_idx != concat_layer->insData.size(); input_idx++) {
|
||||
if (concat_layer->insData[input_idx].lock()->getDims()[0] != 1) {
|
||||
// First we're checking concat input layers
|
||||
prev_layer = InferenceEngine::CNNNetPrevLayerSkipCertain(concat_layer, input_idx,
|
||||
[](InferenceEngine::CNNLayerPtr ptr) {
|
||||
return LayerInfo(ptr).isNonFunctional() || LayerInfo(ptr).isFakeQuantize();
|
||||
});
|
||||
|
||||
IE_ASSERT(prev_layer);
|
||||
|
||||
if (LayerInfo(prev_layer).isInput() && prev_layer->outData[0]->getDims()[0] == 1 ||
|
||||
LayerInfo(prev_layer).isConst()) {
|
||||
continue;
|
||||
} else if ((LayerInfo(prev_layer).isInput() && prev_layer->outData[0]->getDims()[0] != 1)) {
|
||||
is_not_trivial_concat = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// If it's not clear still if concat is supported,
|
||||
// we're moving one more layer back to see the dimensions
|
||||
pre_prev_layer = InferenceEngine::CNNNetPrevLayerSkipCertain(prev_layer, 0,
|
||||
[](InferenceEngine::CNNLayerPtr ptr) {
|
||||
return LayerInfo(ptr).isNonFunctional() || LayerInfo(ptr).isFakeQuantize() ||
|
||||
LayerInfo(ptr).isSplit();
|
||||
});
|
||||
|
||||
IE_ASSERT(pre_prev_layer);
|
||||
|
||||
if (LayerInfo(pre_prev_layer).isConst()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
concat_all_const_or_inputs = false;
|
||||
|
||||
if (LayerInfo(pre_prev_layer).isInput() && pre_prev_layer->outData[0]->getDims()[0] == 1)
|
||||
continue;
|
||||
|
||||
if (pre_prev_layer->outData[0]->getDims()[0] != 1) {
|
||||
is_not_trivial_concat = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This is a trivial concat or it isn't a 'not trivial one' :-)
|
||||
// it can be flattened and we're allowing it
|
||||
if (!is_not_trivial_concat || concat_all_const_or_inputs)
|
||||
return true;
|
||||
|
||||
// For interleaved inputs start checking from axis 1
|
||||
// and allow concatenation on axis 0 only when all other dimesions = 1
|
||||
std::rotate(in_dims.begin(), in_dims.begin() + 1, in_dims.end());
|
||||
concat_axis == 0 ? concat_axis = dims_size - 1 : concat_axis--;
|
||||
|
||||
// Looking for any axis with dimension > 1 before concatentaion axis;
|
||||
// in general such concatenation is unsupported
|
||||
auto end_dim = in_dims.begin() + concat_axis;
|
||||
auto unsupported_concat_axis = std::find_if(in_dims.begin(), end_dim, [](const size_t& in_dim) {
|
||||
return (in_dim > 1);
|
||||
});
|
||||
|
||||
if (unsupported_concat_axis != end_dim) {
|
||||
auto dims = concat_layer->insData[0].lock()->getDims();
|
||||
std::ostringstream in_dims_oss;
|
||||
std::copy(dims.begin(), dims.end(), std::ostream_iterator<size_t>(in_dims_oss, ","));
|
||||
errMessage = "[ WARNING ] Topology with layer: " + layer->name + ", type: " + layer->type +
|
||||
", and concatenation axis(" + std::to_string(concat_layer->_axis) +
|
||||
") for input dimensions(" + in_dims_oss.str() + ") not supported\n";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ValidateConvConcatAxis(const InferenceEngine::ConcatLayer* concat_layer) {
|
||||
IE_ASSERT(concat_layer);
|
||||
auto dims_size = concat_layer->insData[0].lock()->getDims().size();
|
||||
|
||||
if (dims_size >= 2) {
|
||||
InferenceEngine::CNNLayerPtr prev_layer;
|
||||
|
||||
// Skipping here all layers which would disappear or otherwise fuse with convolution in the final GNA graph
|
||||
auto isFusableWithConv = [](InferenceEngine::CNNLayerPtr ptr) {
|
||||
return (LayerInfo(ptr).isFusableWithConv() || LayerInfo(ptr).isNonFunctional());
|
||||
};
|
||||
|
||||
auto in_dims = concat_layer->insData[0].lock()->getDims();
|
||||
auto concat_axis = concat_layer->_axis;
|
||||
auto concat_layout = concat_layer->input()->getLayout();
|
||||
|
||||
for (auto input_idx = 0; input_idx != concat_layer->insData.size(); input_idx++) {
|
||||
// Supported cases for concatenation of a convolution
|
||||
prev_layer = InferenceEngine::CNNNetPrevLayerSkipCertain(concat_layer, input_idx, isFusableWithConv);
|
||||
if (prev_layer && LayerInfo(prev_layer).isConvolution()) {
|
||||
// Allow concatenation along N axis for non-interleaved primitives
|
||||
// (currently only convolution)
|
||||
if (concat_layer->_axis == 0)
|
||||
break;
|
||||
|
||||
// Convert dims to NHWC layout to allow later verification
|
||||
auto new_order = GetPermuteOrder(concat_layout, InferenceEngine::Layout::NHWC);
|
||||
InferenceEngine::SizeVector new_dims;
|
||||
for (size_t i = 0; i < dims_size; ++i) {
|
||||
new_dims.push_back(in_dims[new_order[i]]);
|
||||
}
|
||||
concat_axis = GetPermuteOrder(InferenceEngine::Layout::NHWC, concat_layout)[concat_axis];
|
||||
|
||||
// Looking for any axis with dimension > 1 before concatentaion axis;
|
||||
// in general such concatenation is unsupported
|
||||
auto end_dim = new_dims.begin() + concat_axis;
|
||||
auto unsupportedconcat_axis = std::find_if(new_dims.begin(), end_dim, [](const size_t& inDim) {
|
||||
return (inDim > 1);
|
||||
});
|
||||
|
||||
if (unsupportedconcat_axis != end_dim) {
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AreLayersSupported(InferenceEngine::CNNNetwork& network, std::string& errMessage, bool userWarning) {
|
||||
InferenceEngine::InputsDataMap inputs = network.getInputsInfo();
|
||||
std::unordered_set<InferenceEngine::CNNLayer *> allLayers;
|
||||
InferenceEngine::CNNLayerPtr startLayer;
|
||||
@@ -197,32 +372,36 @@ bool AreLayersSupported(InferenceEngine::CNNNetwork& network, std::string& errMe
|
||||
startLayer = secondLayers.begin()->second;
|
||||
}
|
||||
auto batch_size = network.getBatchSize();
|
||||
|
||||
bool check_result = true;
|
||||
InferenceEngine::details::UnorderedDFS(allLayers,
|
||||
startLayer,
|
||||
[&](const InferenceEngine::CNNLayerPtr layer) {
|
||||
LayerInfo info(layer);
|
||||
if (GNAPluginNS::LayerTypeFromStr(layer->type) == GNAPluginNS::LayerType::NO_TYPE) {
|
||||
errMessage = "The plugin does not support layer: " + layer->name + ":" + layer->type + "\n";
|
||||
check_result = false;
|
||||
}
|
||||
if (batch_size != 1 && GNAPluginNS::LayerInfo::isBatchSizeConstrained(layer->type)) {
|
||||
if (batch_size != 1 && info.isBatchSizeConstrained()) {
|
||||
errMessage = "topology with layer: " + layer->name + ", type: " + layer->type +
|
||||
", and batch size(" + std::to_string(batch_size) + ") != 1 not supported";
|
||||
check_result = false;
|
||||
}
|
||||
if (GNAPluginNS::LayerInfo(layer).isFullyConnected()) {
|
||||
size_t output_batch_size = GNAPluginNS::LayerInfo(layer).getOutputBatchSize();
|
||||
if (info.isFullyConnected()) {
|
||||
size_t output_batch_size = info.getOutputBatchSize();
|
||||
if (output_batch_size > 8) {
|
||||
errMessage = "topology with layer: " + layer->name + ", type: " + layer->type +
|
||||
", and batch size(" + std::to_string(output_batch_size) + ") not supported";
|
||||
check_result = false;
|
||||
errMessage = "topology with layer: " + layer->name + ", type: " + layer->type +
|
||||
", and batch size(" + std::to_string(output_batch_size) + ") not supported";
|
||||
check_result = false;
|
||||
}
|
||||
} else if (info.isConcat()) {
|
||||
if (!ValidateConcatAxis(layer, errMessage) && userWarning) {
|
||||
std::cout << errMessage;
|
||||
}
|
||||
}
|
||||
}, false);
|
||||
IE_SUPPRESS_DEPRECATED_END
|
||||
return check_result;
|
||||
}
|
||||
IE_SUPPRESS_DEPRECATED_END
|
||||
|
||||
} // namespace GNALimitations
|
||||
} // namespace GNAPluginNS
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <cstdint>
|
||||
#include <cpp/ie_cnn_network.h>
|
||||
#include <ie_algorithm.hpp>
|
||||
#include <legacy/ie_layers.h>
|
||||
|
||||
namespace GNAPluginNS {
|
||||
namespace GNALimitations {
|
||||
@@ -138,12 +139,21 @@ public:
|
||||
};
|
||||
} // namespace Cnn2D
|
||||
|
||||
bool AreLayersSupported(InferenceEngine::CNNNetwork& network, std::string& errMessage);
|
||||
bool AreLayersSupported(InferenceEngine::CNNNetwork& network, std::string& errMessage, bool userWarning);
|
||||
|
||||
inline size_t GetMinBatchToFitInBuffer(InferenceEngine::DataPtr input) {
|
||||
auto total_size = InferenceEngine::details::product(std::begin(input->getDims()), std::end(input->getDims()));
|
||||
return total_size / bufferMaxSize + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Validates if concat layer axis is supported by GNA
|
||||
* @param layer concat layer
|
||||
* @return true if concat layer axis is valid
|
||||
*/
|
||||
IE_SUPPRESS_DEPRECATED_START
|
||||
bool ValidateConvConcatAxis(const InferenceEngine::ConcatLayer* concatLayer);
|
||||
IE_SUPPRESS_DEPRECATED_END
|
||||
|
||||
} // namespace GNALimitations
|
||||
} // namespace GNAPluginNS
|
||||
@@ -5,6 +5,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include "gna/gna_config.hpp"
|
||||
|
||||
namespace GNAPluginNS {
|
||||
struct GNAFlags {
|
||||
@@ -18,5 +19,6 @@ struct GNAFlags {
|
||||
bool sw_fp32 = false;
|
||||
bool performance_counting = false;
|
||||
bool input_low_precision = false;
|
||||
std::string log_level = InferenceEngine::PluginConfigParams::LOG_NONE;
|
||||
};
|
||||
} // namespace GNAPluginNS
|
||||
@@ -952,6 +952,16 @@ void GNAGraphCompiler::ConcatPrimitive(InferenceEngine::CNNLayerPtr layer) {
|
||||
}
|
||||
}
|
||||
|
||||
// Concat axis validation
|
||||
if (!GNALimitations::ValidateConvConcatAxis(concatLayer) && gnaFlags->log_level == PluginConfigParams::LOG_WARNING) {
|
||||
std::ostringstream in_dims_oss;
|
||||
auto in_dims = concatLayer->insData[0].lock()->getDims();
|
||||
std::copy(in_dims.begin(), in_dims.end(), std::ostream_iterator<size_t>(in_dims_oss, ","));
|
||||
std::cout << "[ WARNING ] Topology with layer: " + layer->name + ", type: " + layer->type +
|
||||
", and concatenation axis(" + std::to_string(concatLayer->_axis) +
|
||||
") for input dimensions(" + in_dims_oss.str() + ") not supported\n";
|
||||
}
|
||||
|
||||
auto& concatLayerInfo = concat_connection.find(concatLayer->name)->second;
|
||||
for (auto &&outLayer : getInputTo(concatLayer->outData.front())) {
|
||||
auto concatCandidate = outLayer.second;
|
||||
|
||||
@@ -394,4 +394,4 @@ inline std::vector<TranspositionInfo> FindTranspositionInfoFromNextLayers(Infere
|
||||
return findTranspositionInfoRecursive(layer);
|
||||
}
|
||||
|
||||
} // namespace GNAPluginNS
|
||||
} // namespace GNAPluginNS
|
||||
@@ -761,7 +761,7 @@ void GNAPlugin::LoadNetwork(CNNNetwork & _network) {
|
||||
|
||||
// Check the input network
|
||||
std::string error;
|
||||
if (!GNAPluginNS::GNALimitations::AreLayersSupported(network, error)) {
|
||||
if (!GNAPluginNS::GNALimitations::AreLayersSupported(network, error, gnaFlags->log_level == PluginConfigParams::LOG_WARNING)) {
|
||||
THROW_GNA_EXCEPTION << error.c_str();
|
||||
}
|
||||
|
||||
|
||||
@@ -226,8 +226,15 @@ void Config::UpdateFromMap(const std::map<std::string, std::string>& config) {
|
||||
} else if (value == PluginConfigParams::NO) {
|
||||
gnaFlags.gna_openmp_multithreading = true;
|
||||
} else {
|
||||
log << "EXCLUSIVE_ASYNC_REQUESTS should be YES/NO, but not" << value;
|
||||
THROW_GNA_EXCEPTION << "EXCLUSIVE_ASYNC_REQUESTS should be YES/NO, but not" << value;
|
||||
log << "SINGLE_THREAD should be YES/NO, but not" << value;
|
||||
THROW_GNA_EXCEPTION << "SINGLE_THREAD should be YES/NO, but not" << value;
|
||||
}
|
||||
} else if (key == CONFIG_KEY(LOG_LEVEL)) {
|
||||
if (value == PluginConfigParams::LOG_WARNING || value == PluginConfigParams::LOG_NONE) {
|
||||
gnaFlags.log_level = value;
|
||||
} else {
|
||||
log << "Currently only LOG_LEVEL = LOG_WARNING or LOG_NONE is supported, not " << value;
|
||||
THROW_GNA_EXCEPTION << "Currently only LOG_LEVEL = LOG_WARNING and LOG_NONE are supported, not " << value;
|
||||
}
|
||||
} else {
|
||||
IE_THROW(NotFound)
|
||||
@@ -298,6 +305,7 @@ void Config::AdjustKeyMapValues() {
|
||||
keyConfigMap[GNA_CONFIG_KEY(LIB_N_THREADS)] = std::to_string(gnaFlags.gna_lib_async_threads_num);
|
||||
keyConfigMap[CONFIG_KEY(SINGLE_THREAD)] =
|
||||
gnaFlags.gna_openmp_multithreading ? PluginConfigParams::NO: PluginConfigParams::YES;
|
||||
keyConfigMap[CONFIG_KEY(LOG_LEVEL)] = gnaFlags.log_level;
|
||||
}
|
||||
|
||||
std::string Config::GetParameter(const std::string& name) const {
|
||||
|
||||
@@ -88,9 +88,9 @@ class LayerInfo {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
static bool isBatchSizeConstrained(const std::string name) {
|
||||
bool isBatchSizeConstrained() {
|
||||
static InferenceEngine::details::caseless_set<std::string> layersWithConstrains = {"memory", "convolution"};
|
||||
return layersWithConstrains.find(name) != layersWithConstrains.end();
|
||||
return layersWithConstrains.find(layer->name) != layersWithConstrains.end();
|
||||
}
|
||||
size_t getOutputBatchSize() const {
|
||||
if (!layer) {
|
||||
@@ -339,13 +339,15 @@ class LayerInfo {
|
||||
bool isCopy() const noexcept {
|
||||
return isOfType(CopyLayerName) || isOfType(DelayedCopyLayerName);
|
||||
}
|
||||
|
||||
bool isCopyDelayed() const noexcept {
|
||||
return isOfType(DelayedCopyLayerName);
|
||||
}
|
||||
bool isWeightableIdentity() const noexcept {
|
||||
return isConcatAlignFilter() || isSyntheticScaleShift() || isCropAffined();
|
||||
}
|
||||
bool isFusableWithConv() const noexcept {
|
||||
return isActivation() || isMaxPooling();
|
||||
}
|
||||
|
||||
bool isSynthetic() const noexcept {
|
||||
return isConcatAlignFilter() || isSyntheticScaleShift() || isConvolutionFilter() || isAffineFilter();
|
||||
|
||||
@@ -654,6 +654,8 @@ void RemovePermutationsNHWCToNCHWPass::run() {
|
||||
THROW_GNA_EXCEPTION << data->getName() <<
|
||||
" unexpected dimensions size in Permute - Conv - Permute pattern";
|
||||
}
|
||||
// HWC layout enum is used here as the only available in CNNNetwork for 3D vectors,
|
||||
// but the real layout is NCW and it's the one used in order vector later
|
||||
return dims_size == 4 ? Layout::NHWC : Layout::HWC;
|
||||
};
|
||||
|
||||
@@ -661,6 +663,15 @@ void RemovePermutationsNHWCToNCHWPass::run() {
|
||||
auto layout = getTransposedLayout(data);
|
||||
if (data->getLayout() == layout) return;
|
||||
|
||||
auto current_layer = getCreatorLayer(data).lock();
|
||||
if (LayerInfo(current_layer).isConcat()) {
|
||||
auto concat_layer = dynamic_cast<InferenceEngine::ConcatLayer*> (current_layer.get());
|
||||
auto dims_size = data->getDims().size();
|
||||
concat_layer->_axis = (dims_size == 4 ? GetPermuteOrder(Layout::NHWC, Layout::NCHW) :
|
||||
std::vector<int32_t>{0, 2, 1})[concat_layer->_axis];
|
||||
}
|
||||
|
||||
// NWC->NCW layouts are used here for order vector, see comments a few lines above
|
||||
auto dims = data->getDims();
|
||||
auto order = dims.size() == 4 ? GetPermuteOrder(Layout::NCHW, Layout::NHWC) :
|
||||
std::vector<int32_t>{0, 2, 1};
|
||||
@@ -971,11 +982,13 @@ void InsertCopyLayerPass::run() {
|
||||
void FlattenTrivialConcatPass::run() {
|
||||
OV_ITT_SCOPED_TASK(itt::domains::GNA_LT, "FlattenTrivialConcatPass");
|
||||
// change all trivial concatenations (concatenation where output buffer is a buffer made by appending input buffers)
|
||||
// by reshaping its inputs to 1 x total_input_size and its output to 1 x total_cocat_size and chaning the axis to 1
|
||||
// for example if 4D concat have unaligned inputs then ConcatAlignFilters need to be used if sizes before
|
||||
// axis are all ones then concat can be changed to 2D for example, lets say all unputs have same shape equal to:
|
||||
// by reshaping its inputs to 1 x total_input_size and its output to 1 x total_concat_size and changing the axis to 1
|
||||
// for example if 4D concat have unaligned inputs then ConcatAlignFilters need to be used; if sizes before concat
|
||||
// axis are all ones then concat can be changed to 2D for example, let's say all inputs have the same shape equal to:
|
||||
// 1, 1, 5, 3 then for axis 0, 1, 2 the change will be made and inputs will be reshaped to 1, 15,
|
||||
// but for shape 2, 1, 5, 3 only axis 0 is valid and inputs will reshape to 1, 30
|
||||
// but for shape 2, 1, 5, 3 only axis 0 is valid and in such case inputs will be reshaped to 1, 30
|
||||
// TODO: detection of trivial cases could be moved to one common place when all transformations are migrated to ngraph.
|
||||
// See as well code for detection of unsupported concat
|
||||
auto quantized = InferenceEngine::getInjectedData<QuantizedLayerParams>(pLayers->front());
|
||||
|
||||
auto getLayerByIndex = [](int idx, ConcatLayer* concatLayer) {
|
||||
@@ -993,21 +1006,26 @@ void FlattenTrivialConcatPass::run() {
|
||||
if (!concatLayer) continue;
|
||||
if (concatLayer->insData.size() < 1) continue;
|
||||
|
||||
// Skip obvious supported cases
|
||||
auto dims_size = concatLayer->insData[0].lock()->getDims().size();
|
||||
if (dims_size < 2 || concatLayer->_axis == dims_size - 1) continue;
|
||||
|
||||
// Skip cases which cannot be flattened (these might be unsupported at all)
|
||||
auto axis = concatLayer->_axis;
|
||||
bool skip_layer = false;
|
||||
for (unsigned int i = 0; i < axis; i++) {
|
||||
if (concatLayer->insData[0].lock()->getDims()[i] != 1) skip_layer = true;
|
||||
}
|
||||
if (skip_layer) continue;
|
||||
|
||||
// Calculate total input sizes
|
||||
std::vector<size_t> total_sizes;
|
||||
for (auto& input : concatLayer->insData) {
|
||||
auto input_dims = input.lock()->getDims();
|
||||
total_sizes.push_back(std::accumulate(input_dims.begin(), input_dims.end(), size_t(1), std::multiplies<size_t>()));
|
||||
}
|
||||
|
||||
// Reshape concat inputs
|
||||
for (size_t input_idx = 0; input_idx != concatLayer->insData.size(); input_idx++) {
|
||||
auto concatInput = getLayerByIndex(input_idx, concatLayer);
|
||||
|
||||
@@ -1020,6 +1038,7 @@ void FlattenTrivialConcatPass::run() {
|
||||
gnalog() << "\tInserted " << reshapeName << " between " << getCreatorLayer(concatInput).lock()->name << " and " << l->name << std::endl;
|
||||
}
|
||||
|
||||
// Reshape concat outputs back to the original size
|
||||
for (auto output_idx = 0; output_idx != concatLayer->outData.size(); output_idx++) {
|
||||
auto output = concatLayer->outData[output_idx];
|
||||
auto output_tensor_copy = TensorDesc(output->getTensorDesc());
|
||||
|
||||
Reference in new issue
Block a user