Add CNN1D limitation for stride > filter, add negative tests, simplify (#9506)
Pad filter when effective stride > filter
Add tests with stride bigger than filter
Add stride not aligned to 8 from review
This commit is contained in:
committed by
GitHub
parent
ae648614d9
commit
68ef22a53d
@@ -283,6 +283,9 @@ void GNAGraphCompiler::ConvolutionPrimitive(InferenceEngine::CNNLayerPtr layer)
|
||||
(convolution._stride_y * convolution._kernel_x);
|
||||
convolution._kernel_x *= convolution._kernel_y;
|
||||
convolution._kernel_y = 1;
|
||||
// since _kernel_y = 1 && in_height = 1
|
||||
// it will be finalized with finalizeConvolution1DPrimitive()
|
||||
// unless some other exception thrown
|
||||
}
|
||||
|
||||
if (in_batch != 1 || out_batch != 1) {
|
||||
@@ -316,7 +319,6 @@ void GNAGraphCompiler::ConvolutionPrimitive(InferenceEngine::CNNLayerPtr layer)
|
||||
// When layer layout is in NHWC it means that is was created by PassManager
|
||||
return finalizeConvolution2DPrimitive(layer, in_batch, in_channels, in_height, in_width,
|
||||
out_batch, out_channels, out_height, out_width);
|
||||
THROW_GNA_LAYER_EXCEPTION(layer) << "Convolution 2D is not supported on GNA 1.0 library";
|
||||
}
|
||||
finalizeConvolution1DPrimitive(layer, in_batch, in_channels, in_width,
|
||||
out_batch, out_channels, out_width, in_kernel_w, in_kernel_h, transpose_h_w);
|
||||
@@ -346,15 +348,29 @@ void GNAGraphCompiler::finalizeConvolution1DPrimitive(InferenceEngine::CNNLayerP
|
||||
|
||||
IE_ASSERT(convolution._kernel_y == 1);
|
||||
uint32_t total_conv_kernel_size = convolution._kernel_x * convolution._out_depth * in_channels;
|
||||
uint32_t single_conv_kernel_size = convolution._kernel_x * in_channels;
|
||||
const uint32_t single_conv_kernel_size = convolution._kernel_x * in_channels;
|
||||
auto actual_kernel_size = details::product(convolution._weights->getTensorDesc().getDims());
|
||||
if (total_conv_kernel_size != actual_kernel_size) {
|
||||
THROW_GNA_LAYER_EXCEPTION(&convolution) << "Weights size does not equal kernel size "
|
||||
<< actual_kernel_size << " vs " << total_conv_kernel_size;
|
||||
}
|
||||
|
||||
// GNA HW Convolution 1D layer natively supports single channel input and filter
|
||||
// to use it for multiple channels input and filter
|
||||
// the convolution stride must be multiplied accordingly
|
||||
auto effectiveStride = in_channels * convolution._stride_x;
|
||||
|
||||
if (convolution._stride_y == 1 && in_width == 1 && convolution._stride_x != 1) {
|
||||
// TODO: investigate whether this condition is needed at all
|
||||
// seams that if in_width == 1, then convolution._stride_x == 1 as well
|
||||
THROW_GNA_LAYER_EXCEPTION(&convolution) << "Convolution 1D Layer has horizontal stride != 1 despite input width == 1\n";
|
||||
}
|
||||
|
||||
// padding of convolution kernel to be multiply of 8
|
||||
uint32_t num_conv_kernel_padding = ALIGN(single_conv_kernel_size, 8) - single_conv_kernel_size;
|
||||
// additionally have to pad filter for stride > filter since
|
||||
// GNA HW supports CNN1D with convolution stride not greater than filter length
|
||||
const auto num_filter_coefficients = ALIGN(std::max(single_conv_kernel_size, effectiveStride), 8);
|
||||
const auto num_conv_kernel_padding = num_filter_coefficients - single_conv_kernel_size;
|
||||
if (num_conv_kernel_padding == 0) {
|
||||
gnalog() << LAYER_NAME(&convolution) << "Kernel is aligned \n";
|
||||
} else {
|
||||
@@ -363,23 +379,13 @@ void GNAGraphCompiler::finalizeConvolution1DPrimitive(InferenceEngine::CNNLayerP
|
||||
|
||||
// have to pad input to let last kernel meets it's corresponding input
|
||||
const auto num_inputs = in_width * in_channels;
|
||||
|
||||
uint32_t num_input_padding = ALIGN(num_inputs, 8) - num_inputs;
|
||||
|
||||
// convert to 2D and set GNA input feature map size
|
||||
auto convStride = convolution._stride_x * convolution._stride_y;
|
||||
if (convolution._stride_y != 1) {
|
||||
convStride = convolution._stride_x;
|
||||
} else if (in_width == 1 && convolution._stride_x != 1) {
|
||||
convStride = convolution._stride_y;
|
||||
}
|
||||
const auto effectiveStride = in_channels * convStride;
|
||||
|
||||
uint32_t num_filters = convolution._out_depth;
|
||||
uint32_t num_filter_coefficients = single_conv_kernel_size + num_conv_kernel_padding;
|
||||
uint32_t num_columns_in = num_inputs + num_input_padding;
|
||||
|
||||
uint32_t num_columns_out = (((num_inputs - num_filter_coefficients) / effectiveStride) + 1) * convolution._out_depth;
|
||||
uint32_t num_columns_out_unpadded = (((num_inputs - single_conv_kernel_size) / effectiveStride) + 1) * convolution._out_depth;
|
||||
const uint32_t num_filters = convolution._out_depth;
|
||||
uint32_t num_columns_out = (((num_inputs - num_filter_coefficients) / effectiveStride) + 1) * num_filters;
|
||||
uint32_t num_columns_out_unpadded = (((num_inputs - single_conv_kernel_size) / effectiveStride) + 1) * num_filters;
|
||||
|
||||
uint32_t original_input_padding = num_input_padding;
|
||||
uint32_t additional_padding = 0;
|
||||
@@ -388,7 +394,7 @@ void GNAGraphCompiler::finalizeConvolution1DPrimitive(InferenceEngine::CNNLayerP
|
||||
while (num_columns_out < out_batch * out_channels * out_width) {
|
||||
num_input_padding = original_input_padding + additional_padding;
|
||||
num_columns_in = num_inputs + num_input_padding;
|
||||
num_columns_out = (((num_inputs + num_input_padding - num_filter_coefficients) / effectiveStride) + 1) * convolution._out_depth;
|
||||
num_columns_out = (((num_inputs + num_input_padding - num_filter_coefficients) / effectiveStride) + 1) * num_filters;
|
||||
dnn->new_num_conv_columns = num_columns_out;
|
||||
additional_padding += 8;
|
||||
}
|
||||
@@ -476,7 +482,7 @@ void GNAGraphCompiler::finalizeConvolution1DPrimitive(InferenceEngine::CNNLayerP
|
||||
auto B = transpose_h_w ? in_kernel_w : convolution._kernel[X_AXIS];
|
||||
|
||||
std::vector<uint8_t> transposedWeights;
|
||||
for (uint32_t k = 0; k < convolution._out_depth; k++) {
|
||||
for (uint32_t k = 0; k < num_filters; k++) {
|
||||
uint8_t * ptr_filt_current
|
||||
= convolution._weights->cbuffer().as<uint8_t*>() +
|
||||
k * A * B * convolution.precision.size();
|
||||
@@ -495,7 +501,7 @@ void GNAGraphCompiler::finalizeConvolution1DPrimitive(InferenceEngine::CNNLayerP
|
||||
convolution._weights->byteSize(),
|
||||
64);
|
||||
} else {
|
||||
auto paddedWeights = (single_conv_kernel_size + num_conv_kernel_padding) * convolution._out_depth;
|
||||
auto paddedWeights = num_filter_coefficients * num_filters;
|
||||
auto paddedWeightsSize = paddedWeights * convolution.precision.size();
|
||||
auto initializer = [=](void* data, std::size_t size) {
|
||||
if (paddedWeightsSize > size) {
|
||||
@@ -504,7 +510,7 @@ void GNAGraphCompiler::finalizeConvolution1DPrimitive(InferenceEngine::CNNLayerP
|
||||
std::size_t offset = 0;
|
||||
std::vector<uint8_t> padding_zeros(num_conv_kernel_padding * convolution.precision.size(), 0);
|
||||
uint8_t* dstPtr = reinterpret_cast<uint8_t*>(data);
|
||||
for (int i = 0; i < convolution._out_depth; i++) {
|
||||
for (int i = 0; i < num_filters; i++) {
|
||||
ie_memcpy(dstPtr + offset,
|
||||
size - offset,
|
||||
transposedWeights.data() + single_conv_kernel_size * i * convolution.precision.size(),
|
||||
|
||||
@@ -41,6 +41,8 @@ const std::vector<std::vector<size_t >> kernelsH1 = {{1, 3},
|
||||
{1, 5}};
|
||||
const std::vector<std::vector<size_t >> stridesH1 = {{1, 1},
|
||||
{1, 3}};
|
||||
const std::vector<std::vector<size_t>> stridesH1Big = {{1, 9},
|
||||
{1, 16}};
|
||||
const std::vector<std::vector<ptrdiff_t>> padBeginsH1 = {{1, 0},
|
||||
{1, 3}};
|
||||
const std::vector<std::vector<ptrdiff_t>> padEndsH1 = {{1, 0},
|
||||
@@ -146,6 +148,14 @@ const auto conv2DParams_AutoPadValid_Height1 = ::testing::Combine(
|
||||
::testing::ValuesIn(numOutCannels),
|
||||
::testing::Values(ngraph::op::PadType::VALID)
|
||||
);
|
||||
const auto conv2DParams_AutoPadValid_Height1_BigStride = ::testing::Combine(
|
||||
::testing::ValuesIn(kernelsH1),
|
||||
::testing::ValuesIn(stridesH1Big),
|
||||
::testing::Values(std::vector<ptrdiff_t>({0, 0})),
|
||||
::testing::Values(std::vector<ptrdiff_t>({0, 0})),
|
||||
::testing::ValuesIn(dilationsH1),
|
||||
::testing::ValuesIn(numOutCannels),
|
||||
::testing::Values(ngraph::op::PadType::VALID));
|
||||
const auto conv2DParams_AutoPadValid_Width1 = ::testing::Combine(
|
||||
::testing::ValuesIn(kernelsW1),
|
||||
::testing::ValuesIn(stridesW1),
|
||||
@@ -202,6 +212,18 @@ INSTANTIATE_TEST_SUITE_P(smoke_Convolution2D_AutoPadValid_Height1, ConvolutionLa
|
||||
::testing::Values(CommonTestUtils::DEVICE_GNA)),
|
||||
ConvolutionLayerTest::getTestCaseName);
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(smoke_Convolution2D_AutoPadValid_Height1_BigStride,
|
||||
ConvolutionLayerTest,
|
||||
::testing::Combine(conv2DParams_AutoPadValid_Height1_BigStride,
|
||||
::testing::ValuesIn(netPrecisions),
|
||||
::testing::Values(InferenceEngine::Precision::UNSPECIFIED),
|
||||
::testing::Values(InferenceEngine::Precision::UNSPECIFIED),
|
||||
::testing::Values(InferenceEngine::Layout::ANY),
|
||||
::testing::Values(InferenceEngine::Layout::ANY),
|
||||
::testing::ValuesIn(inputShapesH1),
|
||||
::testing::Values(CommonTestUtils::DEVICE_GNA)),
|
||||
ConvolutionLayerTest::getTestCaseName);
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(smoke_Convolution2D_AutoPadValid_Width1, ConvolutionLayerTest,
|
||||
::testing::Combine(
|
||||
conv2DParams_AutoPadValid_Width1,
|
||||
|
||||
Reference in New Issue
Block a user