[GNA] Fixed handling of unaligned crop layer (#11316)

This commit is contained in:
Elizaveta Lobanova
2022-03-31 20:03:51 +03:00
committed by GitHub
parent 1cb254307e
commit d3060d4bcc
8 changed files with 284 additions and 41 deletions
+14 -39
View File
@@ -1053,38 +1053,11 @@ void GNAGraphCompiler::CropPrimitive(InferenceEngine::CNNLayerPtr layer) {
IE_ASSERT(!layer->insData.empty());
auto inputs = layer->insData.begin()->lock();
IE_ASSERT(!cropLayer->axis.empty());
IE_ASSERT(cropLayer->axis.size() == cropLayer->dim.size());
IE_ASSERT(cropLayer->axis.size() == cropLayer->offset.size());
std::vector<int> axis, dim, offset;
for (int n = 0; n < cropLayer->axis.size(); n++) {
uint32_t input_dim = GetDataDimSize(inputs, inputs->getDims().size() - cropLayer->axis[n]);
// Exclude crop layer components that do nothing
if (cropLayer->offset[n] == 0 && cropLayer->dim[n] == input_dim) {
continue;
}
axis.push_back(cropLayer->axis[n]);
dim.push_back(cropLayer->dim[n]);
offset.push_back(cropLayer->offset[n]);
}
if (axis.size() != 1) {
THROW_GNA_EXCEPTION <<
"Crop layer does not support the number of (non-trivial) cropped dimensions more than 1, provided: "
<< axis.size() << ".";
}
size_t cropOffset = offset.front() * cropLayer->precision.size();
size_t cropOutputSize = dim.front() * cropLayer->precision.size();
const uint32_t noOfInputsDivisor = gnaFlags->input_low_precision ?
GNALimitations::noOfInputsLowPrecDivisor : GNALimitations::noOfInputsDivisor;
// fix for crop on tensor dim > 2D
for (int n = axis[0]+1; n < cropLayer->dim.size(); n++) {
cropOffset *= cropLayer->dim[n];
cropOutputSize *= cropLayer->dim[n];
}
size_t cropOffset, cropOutputSize;
std::vector<int32_t> axis;
std::tie(cropOffset, cropOutputSize, axis) = GetCropParams(cropLayer);
size_t cropOffsetBytes = cropOffset * cropLayer->precision.size();
size_t cropOutputSizeBytes = cropOutputSize * cropLayer->precision.size();
if (!LayerInfo(cropLayer).isCropAffined()) {
// leave crop as it is
@@ -1099,13 +1072,13 @@ void GNAGraphCompiler::CropPrimitive(InferenceEngine::CNNLayerPtr layer) {
}
// calculate index idx for connectInput last parameter
connectInput(layer, &cropLayerInfo->second.gna_ptr, cropOutputSize + cropOffset, cropOffset, 0);
connectInput(layer, &cropLayerInfo->second.gna_ptr, cropOutputSizeBytes + cropOffsetBytes, cropOffsetBytes, 0);
// cases for certain output layers
for (auto&& outLayer : getInputTo(layer->outData.front())) {
auto& nextLayer = outLayer.second;
if (LayerInfo(nextLayer).isConcat()) {
connectOutput(layer, &cropLayerInfo->second.gna_ptr, cropOutputSize);
connectOutput(layer, &cropLayerInfo->second.gna_ptr, cropOutputSizeBytes);
}
}
} else {
@@ -1119,10 +1092,12 @@ void GNAGraphCompiler::CropPrimitive(InferenceEngine::CNNLayerPtr layer) {
}
// TODO: add unit tests for 4d crops blobs
uint32_t num_rows_in = GetDataDimSize(inputs, inputs->getDims().size() - axis.front());
uint32_t num_rows_in = InferenceEngine::details::product(begin(inputs->getDims()), end(inputs->getDims()));
uint32_t num_columns_in = 1;
uint32_t num_rows_out = GetDataDimSize(outputs, inputs->getDims().size() - axis.front());
uint32_t num_rows_out = InferenceEngine::details::product(begin(outputs->getDims()), end(outputs->getDims()));
const uint32_t noOfInputsDivisor = gnaFlags->input_low_precision ?
GNALimitations::noOfInputsLowPrecDivisor : GNALimitations::noOfInputsDivisor;
uint32_t num_padding = ALIGN(num_rows_in, noOfInputsDivisor) - num_rows_in;
void* ptr_inputs = nullptr;
@@ -1158,7 +1133,7 @@ void GNAGraphCompiler::CropPrimitive(InferenceEngine::CNNLayerPtr layer) {
connectInput(layer, ptr_inputs, num_data_bytes_in, 0, 0);
connectOutput(layer, ptr_outputs, num_data_bytes_out);
FillWeightOfAligningFilter(layer, ptr_weights, offset.front(), (quantized == nullptr) ? false : true);
FillWeightOfAligningFilter(layer, ptr_weights, cropOffset, (quantized == nullptr) ? false : true);
(quantized == nullptr) ?
gnamem->readonly().push_value(layer, ptr_biases, 0.0f, num_rows_out, 64) :
@@ -1589,8 +1564,8 @@ void GNAGraphCompiler::FillWeightOfAligningFilter(InferenceEngine::CNNLayerPtr l
auto outputs = *layer->outData.begin();
auto inputs = layer->insData.begin()->lock();
uint32_t num_rows_in = InferenceEngine::details::product(++begin(inputs->getDims()), end(inputs->getDims()));
uint32_t num_rows_out = InferenceEngine::details::product(++begin(outputs->getDims()), end(outputs->getDims()));
uint32_t num_rows_in = InferenceEngine::details::product(begin(inputs->getDims()), end(inputs->getDims()));
uint32_t num_rows_out = InferenceEngine::details::product(begin(outputs->getDims()), end(outputs->getDims()));
if (!ptrWeights) {
THROW_GNA_EXCEPTION << "Weights memory is not allocated!!!";
@@ -5,6 +5,7 @@
#pragma once
#include <legacy/ie_layers.h>
#include "gna_graph_tools.hpp"
namespace GNAPluginNS {
class GNACropLayer {
@@ -16,9 +17,51 @@ public:
{}
InferenceEngine::CNNLayerPtr getCrop() { return cropLayer; }
/**
* pointer to gna croped memory beginning
*/
void *gna_ptr = nullptr;
};
/**
* @brief returns parameters extracted from Crop layer: elements offset, elements output size and axes
* @param cropLayer pointer to a Crop layer
*/
inline std::tuple<size_t, size_t, std::vector<int32_t>> GetCropParams(InferenceEngine::CropLayer* cropLayer) {
IE_ASSERT(!cropLayer->axis.empty());
IE_ASSERT(cropLayer->axis.size() == cropLayer->dim.size());
IE_ASSERT(cropLayer->axis.size() == cropLayer->offset.size());
std::vector<int> axis, dim, offset;
auto inputs = cropLayer->insData.begin()->lock();
for (int n = 0; n < cropLayer->axis.size(); n++) {
uint32_t input_dim = GetDataDimSize(inputs, inputs->getDims().size() - cropLayer->axis[n]);
// Exclude crop layer components that do nothing
if (cropLayer->offset[n] == 0 && cropLayer->dim[n] == input_dim) {
continue;
}
axis.push_back(cropLayer->axis[n]);
dim.push_back(cropLayer->dim[n]);
offset.push_back(cropLayer->offset[n]);
}
if (axis.size() != 1) {
THROW_GNA_EXCEPTION <<
"Crop layer does not support the number of (non-trivial) cropped dimensions more than 1, provided: "
<< axis.size() << ".";
}
size_t cropOffset = offset.front();
size_t cropOutputSize = dim.front();
// fix for crop on tensor dim > 2D
for (int n = axis[0]+1; n < cropLayer->dim.size(); n++) {
cropOffset *= cropLayer->dim[n];
cropOutputSize *= cropLayer->dim[n];
}
return std::make_tuple(cropOffset, cropOutputSize, axis);
}
} // namespace GNAPluginNS
@@ -17,6 +17,7 @@
#include <legacy/ngraph_ops/power.hpp>
#include <ngraph/opsets/opset8.hpp>
#include "ops/pwl.hpp"
#include "layers/gna_crop_layer.hpp"
namespace GNAPluginNS {
@@ -363,8 +364,10 @@ class LayerInfo {
// currently crop layer only supports 2 bytes in int16 and int8 mode.
// In fp32 mode this is not necessary but is useful for testing
auto bytesPerCropElement = 2;
size_t cropOffset = cropLayer->offset.back() * bytesPerCropElement;
return (ALIGN64(cropOffset) != cropOffset);
size_t offset;
std::tie(offset, std::ignore, std::ignore) = GetCropParams(cropLayer);
size_t bytesOffset = offset * bytesPerCropElement;
return (ALIGN64(bytesOffset) != bytesOffset);
}
return false;
}
@@ -0,0 +1,38 @@
// Copyright (C) 2022 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <vector>
#include "common_test_utils/test_constants.hpp"
#include "subgraph_tests/stridedslice_concat.hpp"
using namespace SubgraphTestsDefinitions;
namespace {
const std::vector<InferenceEngine::Precision> netPrecisions = {
InferenceEngine::Precision::FP32,
InferenceEngine::Precision::FP16
};
const std::vector<std::map<std::string, std::string>> configs = {
{
{"GNA_DEVICE_MODE", "GNA_SW_EXACT"},
}
};
const std::vector<StridedSliceParams> sliceParams = {
{{8, 16}, {1, 16}, {2, 16}, {1, 1}, {0, 1}, {0, 1}},
{{1, 16}, {1, 1}, {1, 2}, {1, 1}, {1, 0}, {1, 0}},
{{1, 8, 16}, {1, 1, 16}, {1, 2, 16}, {1, 1, 1}, {1, 0, 1}, {1, 0, 1}},
{{8, 25}, {3, 25}, {4, 25}, {1, 1}, {0, 1}, {0, 1}}
};
INSTANTIATE_TEST_SUITE_P(smoke_SliceConcatTest, SliceConcatTest,
::testing::Combine(
::testing::ValuesIn(netPrecisions),
::testing::Values(CommonTestUtils::DEVICE_GNA),
::testing::ValuesIn(configs),
::testing::ValuesIn(sliceParams)),
SliceConcatTest::getTestCaseName);
} // namespace
@@ -0,0 +1,15 @@
// Copyright (C) 2022 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include "shared_test_classes/subgraph/stridedslice_concat.hpp"
namespace SubgraphTestsDefinitions {
TEST_P(SliceConcatTest, CompareWithRefImpl) {
Run();
};
} // namespace SubgraphTestsDefinitions
@@ -0,0 +1,43 @@
// Copyright (C) 2022 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include <memory>
#include <string>
#include <tuple>
#include <vector>
#include "shared_test_classes/base/layer_test_utils.hpp"
#include "ngraph_functions/builders.hpp"
#include "ngraph_functions/utils/ngraph_helpers.hpp"
namespace SubgraphTestsDefinitions {
typedef std::tuple<
std::vector<int64_t>, // Input shape
std::vector<int64_t>, // Begin
std::vector<int64_t>, // End
std::vector<int64_t>, // Strides
std::vector<int64_t>, // Begin mask
std::vector<int64_t> // End mask
> StridedSliceParams;
typedef std::tuple<
InferenceEngine::Precision, // Network Precision
std::string, // Target Device
std::map<std::string, std::string>, // Configuration
StridedSliceParams // StridedSlice parameters
> SliceConcatParams;
class SliceConcatTest : public testing::WithParamInterface<SliceConcatParams>,
virtual public LayerTestsUtils::LayerTestsCommon {
public:
static std::string getTestCaseName(const testing::TestParamInfo<SliceConcatParams>& obj);
protected:
void SetUp() override;
};
} // namespace SubgraphTestsDefinitions
@@ -0,0 +1,66 @@
// Copyright (C) 2022 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "shared_test_classes/subgraph/stridedslice_concat.hpp"
#include "ngraph_functions/builders.hpp"
namespace SubgraphTestsDefinitions {
std::string SliceConcatTest::getTestCaseName(const testing::TestParamInfo<SliceConcatParams>& obj) {
InferenceEngine::Precision netPrecision;
std::string targetDevice;
std::map<std::string, std::string> configuration;
StridedSliceParams sliceParams;
std::tie(netPrecision, targetDevice, configuration, sliceParams) = obj.param;
std::vector<int64_t> inputShape, begin, end, strides, beginMask, endMask;
std::tie(inputShape, begin, end, strides, beginMask, endMask) = sliceParams;
std::ostringstream result;
result << "netPRC=" << netPrecision.name() << "_";
result << "targetDevice=" << targetDevice;
for (auto const& configItem : configuration) {
result << "_configItem=" << configItem.first << "_" << configItem.second;
}
result << "IS=" << CommonTestUtils::vec2str(inputShape) << "_";
result << "B=" << CommonTestUtils::vec2str(begin) << "_";
result << "E=" << CommonTestUtils::vec2str(end) << "_";
result << "S=" << CommonTestUtils::vec2str(strides) << "_";
result << "BM=" << CommonTestUtils::vec2str(beginMask) << "_";
result << "EM=" << CommonTestUtils::vec2str(endMask) << "_";
return result.str();
}
void SliceConcatTest::SetUp() {
InferenceEngine::Precision netPrecision;
std::map<std::string, std::string> tempConfig;
StridedSliceParams sliceParams;
std::tie(netPrecision, targetDevice, tempConfig, sliceParams) = this->GetParam();
configuration.insert(tempConfig.begin(), tempConfig.end());
std::vector<int64_t> inputShape, begin, end, strides, beginMask, endMask;
std::tie(inputShape, begin, end, strides, beginMask, endMask) = sliceParams;
auto ngPrc = FuncTestUtils::PrecisionUtils::convertIE2nGraphPrc(netPrecision);
size_t input_size = std::accumulate(std::begin(inputShape), std::end(inputShape), 1, std::multiplies<size_t>());
auto params = ngraph::builder::makeParams(ngPrc, {{1, input_size}});
ngraph::Output<ngraph::Node> input = params[0];
if (inputShape[0] != 1 || inputShape.size() != 2) {
input = std::make_shared<ngraph::opset8::Reshape>(params[0],
ngraph::builder::makeConstant(ngraph::element::i64, ngraph::Shape{inputShape.size()}, inputShape), false);
}
auto ss = ngraph::builder::makeStridedSlice(input, begin, end, strides, ngPrc, beginMask, endMask,
std::vector<int64_t>(inputShape.size(), 0),
std::vector<int64_t>(inputShape.size(), 0),
std::vector<int64_t>(inputShape.size(), 0));
ngraph::Shape const_shape(inputShape.size(), 1);
const_shape.back() = 32;
auto const_input = ngraph::builder::makeConstant(ngPrc, const_shape, std::vector<float>{}, true);
auto concat = ngraph::builder::makeConcat({const_input, ss}, inputShape.size() - 1);
function = std::make_shared<ngraph::Function>(concat, params, "StridedSliceConcatTest");
}
} // namespace SubgraphTestsDefinitions
@@ -0,0 +1,60 @@
// Copyright (C) 2022 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <vector>
#include <gtest/gtest.h>
// to suppress deprecated definition errors
#define IMPLEMENT_INFERENCE_ENGINE_PLUGIN
#include <legacy/ie_layers.h>
#include <layers/gna_crop_layer.hpp>
namespace {
typedef std::tuple<
std::vector<size_t>, // Input shape
std::vector<int>, // Output shape
std::vector<int>, // Axes
std::vector<int>, // Offset
size_t, // Offset in flatten data
size_t, // Output size in flatten data
std::vector<int> // Axes which arre not skipped
> CropParams;
const std::vector<CropParams> crop_params_vector = {
{{8, 16}, {1, 16}, {0, 1}, {1, 0}, 16, 16, {0}},
{{5, 24}, {1, 24}, {0, 1}, {2, 0}, 48, 24, {0}},
{{8, 16}, {2, 16}, {0, 1}, {1, 0}, 16, 32, {0}},
{{1, 16}, {1, 8}, {0, 1}, {0, 5}, 5, 8, {1}},
{{1, 8, 16}, {1, 1, 16}, {0, 1, 2}, {0, 1, 0}, 16, 16, {1}},
{{1, 1, 8, 16}, {1, 1, 1, 16}, {0, 1, 2, 3}, {0, 0, 1, 0}, 16, 16, {2}}
};
TEST(GetCropParamsTest, testGetCropParams) {
InferenceEngine::LayerParams attrs = {"Crop", "Crop", InferenceEngine::Precision::FP32};
for (const auto& crop_params : crop_params_vector) {
std::vector<size_t> in_shape;
std::vector<int> orig_out_shape, orig_axes, orig_offset;
size_t result_offset, result_out_size;
std::vector<int> result_axes;
std::tie(in_shape, orig_out_shape, orig_axes, orig_offset, result_offset, result_out_size, result_axes) = crop_params;
auto crop_layer = std::make_shared<InferenceEngine::CropLayer>(attrs);
auto layout = in_shape.size() == 2 ? InferenceEngine::NC : (in_shape.size() == 3 ? InferenceEngine::CHW : InferenceEngine::NCHW);
auto data = std::make_shared<InferenceEngine::Data>("Crop_input",
InferenceEngine::TensorDesc(InferenceEngine::Precision::FP32, in_shape, layout));
crop_layer->insData.push_back(data);
crop_layer->dim = orig_out_shape;
crop_layer->axis = orig_axes;
crop_layer->offset = orig_offset;
size_t offset, out_size;
std::vector<int32_t> axis;
std::tie(offset, out_size, axis) = GNAPluginNS::GetCropParams(crop_layer.get());
ASSERT_EQ(offset, result_offset);
ASSERT_EQ(out_size, result_out_size);
ASSERT_EQ(axis, result_axes);
}
}
} // namespace