Slice-8 Reference implementation (#7749)
* Init template reference tests * Move output shape calculation to separate function * Add to evaluate_map (reuse old ref) * Add negative step test * Make slice evaluate template type independent * Enable typed tests for reference * Add more reference tests * Revert old slice ref changes * New Slice reference implementation POC * N-dim generalization * Code refactor * Style alignment * Add more checks * Add more tests * Add zero dims/empty output tests * Simplify typed tests generation * Slice op leftovers * Add unsigned types reference tests
This commit is contained in:
parent
a091201b67
commit
96df1a14ce
447
docs/template_plugin/tests/functional/op_reference/slice.cpp
Normal file
447
docs/template_plugin/tests/functional/op_reference/slice.cpp
Normal file
@ -0,0 +1,447 @@
|
||||
// Copyright (C) 2018-2021 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "base_reference_test.hpp"
|
||||
#include "openvino/opsets/opset8.hpp"
|
||||
|
||||
using namespace ov;
|
||||
|
||||
namespace reference_tests {
|
||||
namespace {
|
||||
struct SliceParams {
|
||||
SliceParams(const Tensor& data,
|
||||
const Tensor& start,
|
||||
const Tensor& stop,
|
||||
const Tensor& step,
|
||||
const Tensor& axes,
|
||||
const Tensor& output,
|
||||
const std::string& test_name = "")
|
||||
: m_data(data),
|
||||
m_start(start),
|
||||
m_stop(stop),
|
||||
m_step(step),
|
||||
m_axes(axes),
|
||||
m_output(output),
|
||||
m_test_name(test_name),
|
||||
m_default_axes(false) {}
|
||||
|
||||
// Default `axes` input
|
||||
SliceParams(const Tensor& data,
|
||||
const Tensor& start,
|
||||
const Tensor& stop,
|
||||
const Tensor& step,
|
||||
const Tensor& output,
|
||||
const std::string& test_name = "")
|
||||
: m_data(data),
|
||||
m_start(start),
|
||||
m_stop(stop),
|
||||
m_step(step),
|
||||
m_output(output),
|
||||
m_test_name(test_name),
|
||||
m_default_axes(true) {}
|
||||
|
||||
Tensor m_data;
|
||||
Tensor m_start;
|
||||
Tensor m_stop;
|
||||
Tensor m_step;
|
||||
Tensor m_axes;
|
||||
Tensor m_output;
|
||||
std::string m_test_name;
|
||||
bool m_default_axes = false;
|
||||
};
|
||||
|
||||
class ReferenceSliceLayerTest : public testing::TestWithParam<SliceParams>, public CommonReferenceTest {
|
||||
public:
|
||||
void SetUp() override {
|
||||
auto params = GetParam();
|
||||
if (params.m_default_axes) {
|
||||
function = CreateFunction(params.m_data, params.m_start, params.m_stop, params.m_step);
|
||||
inputData = {params.m_data.data, params.m_start.data, params.m_stop.data, params.m_step.data};
|
||||
|
||||
} else {
|
||||
function = CreateFunction(params.m_data, params.m_start, params.m_stop, params.m_step, params.m_axes);
|
||||
inputData = {params.m_data.data,
|
||||
params.m_start.data,
|
||||
params.m_stop.data,
|
||||
params.m_step.data,
|
||||
params.m_axes.data};
|
||||
}
|
||||
|
||||
refOutData = {params.m_output.data};
|
||||
}
|
||||
static std::string getTestCaseName(const testing::TestParamInfo<SliceParams>& obj) {
|
||||
auto param = obj.param;
|
||||
std::ostringstream result;
|
||||
result << "test_name=" << param.m_test_name << "__";
|
||||
result << "data_shape=" << param.m_data.shape << "_";
|
||||
result << "data_type=" << param.m_data.type << "_";
|
||||
result << "ind_type=" << param.m_start.type << "_";
|
||||
if (param.m_default_axes) {
|
||||
result << "axes_shape="
|
||||
<< "default"
|
||||
<< "_";
|
||||
result << "axes_type="
|
||||
<< "default"
|
||||
<< "_";
|
||||
} else {
|
||||
result << "axes_shape=" << param.m_axes.shape << "_";
|
||||
result << "axes_type=" << param.m_axes.type << "_";
|
||||
}
|
||||
|
||||
return result.str();
|
||||
}
|
||||
|
||||
private:
|
||||
static std::shared_ptr<Function> CreateFunction(const Tensor& data,
|
||||
const Tensor& start,
|
||||
const Tensor& stop,
|
||||
const Tensor& step,
|
||||
const Tensor& axes) {
|
||||
const auto data_param = std::make_shared<opset8::Parameter>(data.type, data.shape);
|
||||
const auto start_param = std::make_shared<opset8::Parameter>(start.type, start.shape);
|
||||
const auto stop_param = std::make_shared<opset8::Parameter>(stop.type, stop.shape);
|
||||
const auto step_param = std::make_shared<opset8::Parameter>(step.type, step.shape);
|
||||
const auto axes_param = std::make_shared<opset8::Parameter>(axes.type, axes.shape);
|
||||
|
||||
const auto slice = std::make_shared<opset8::Slice>(data_param, start_param, stop_param, step_param, axes_param);
|
||||
return std::make_shared<Function>(NodeVector{slice},
|
||||
ParameterVector{data_param, start_param, stop_param, step_param, axes_param});
|
||||
}
|
||||
|
||||
// Default `axes` input
|
||||
static std::shared_ptr<Function> CreateFunction(const Tensor& data,
|
||||
const Tensor& start,
|
||||
const Tensor& stop,
|
||||
const Tensor& step) {
|
||||
const auto data_param = std::make_shared<opset8::Parameter>(data.type, data.shape);
|
||||
const auto start_param = std::make_shared<opset8::Parameter>(start.type, start.shape);
|
||||
const auto stop_param = std::make_shared<opset8::Parameter>(stop.type, stop.shape);
|
||||
const auto step_param = std::make_shared<opset8::Parameter>(step.type, step.shape);
|
||||
|
||||
const auto slice = std::make_shared<opset8::Slice>(data_param, start_param, stop_param, step_param);
|
||||
return std::make_shared<Function>(NodeVector{slice},
|
||||
ParameterVector{data_param, start_param, stop_param, step_param});
|
||||
}
|
||||
};
|
||||
|
||||
TEST_P(ReferenceSliceLayerTest, CompareWithHardcodedRefs) {
|
||||
Exec();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
template <element::Type_t DATA_ET, element::Type_t IND_ET, element::Type_t AXIS_ET>
|
||||
std::vector<SliceParams> generateSliceParamsUnsigned() {
|
||||
using DATA_T = typename element_type_traits<DATA_ET>::value_type;
|
||||
using IND_T = typename element_type_traits<IND_ET>::value_type;
|
||||
using AXIS_T = typename element_type_traits<AXIS_ET>::value_type;
|
||||
|
||||
std::vector<SliceParams> test_params{
|
||||
SliceParams(Tensor{{4}, DATA_ET, std::vector<DATA_T>{1, 2, 3, 4}},
|
||||
Tensor{{1}, IND_ET, std::vector<IND_T>{0}},
|
||||
Tensor{{1}, IND_ET, std::vector<IND_T>{5}},
|
||||
Tensor{{1}, IND_ET, std::vector<IND_T>{1}},
|
||||
Tensor{{1}, AXIS_ET, std::vector<AXIS_T>{0}},
|
||||
Tensor{{4}, DATA_ET, std::vector<DATA_T>{1, 2, 3, 4}},
|
||||
"1D_full_axes"),
|
||||
SliceParams(Tensor{{4}, DATA_ET, std::vector<DATA_T>{1, 2, 3, 4}},
|
||||
Tensor{{1}, IND_ET, std::vector<IND_T>{0}},
|
||||
Tensor{{1}, IND_ET, std::vector<IND_T>{5}},
|
||||
Tensor{{1}, IND_ET, std::vector<IND_T>{1}},
|
||||
Tensor{{4}, DATA_ET, std::vector<DATA_T>{1, 2, 3, 4}},
|
||||
"1D_default_axes"),
|
||||
SliceParams(Tensor{{4}, DATA_ET, std::vector<DATA_T>{1, 2, 3, 4}},
|
||||
Tensor{{1}, IND_ET, std::vector<IND_T>{6}},
|
||||
Tensor{{1}, IND_ET, std::vector<IND_T>{5}},
|
||||
Tensor{{1}, IND_ET, std::vector<IND_T>{1}},
|
||||
Tensor{{1}, AXIS_ET, std::vector<AXIS_T>{0}},
|
||||
Tensor{{0}, DATA_ET, std::vector<DATA_T>{}},
|
||||
"1D_empty_output"),
|
||||
SliceParams(Tensor{{2, 2}, DATA_ET, std::vector<DATA_T>{1, 2, 3, 4}},
|
||||
Tensor{{2}, IND_ET, std::vector<IND_T>{0, 0}},
|
||||
Tensor{{2}, IND_ET, std::vector<IND_T>{2, 2}},
|
||||
Tensor{{2}, IND_ET, std::vector<IND_T>{1, 1}},
|
||||
Tensor{{2}, AXIS_ET, std::vector<AXIS_T>{0, 1}},
|
||||
Tensor{{2, 2}, DATA_ET, std::vector<DATA_T>{1, 2, 3, 4}},
|
||||
"2D_full_axes"),
|
||||
SliceParams(Tensor{{2, 2}, DATA_ET, std::vector<DATA_T>{1, 2, 3, 4}},
|
||||
Tensor{{2}, IND_ET, std::vector<IND_T>{0, 0}},
|
||||
Tensor{{2}, IND_ET, std::vector<IND_T>{2, 2}},
|
||||
Tensor{{2}, IND_ET, std::vector<IND_T>{1, 1}},
|
||||
Tensor{{2, 2}, DATA_ET, std::vector<DATA_T>{1, 2, 3, 4}},
|
||||
"2D_default_axes"),
|
||||
SliceParams(Tensor{{2, 4}, DATA_ET, std::vector<DATA_T>{1, 2, 3, 4, 5, 6, 7, 8}},
|
||||
Tensor{{2}, IND_ET, std::vector<IND_T>{1, 0}},
|
||||
Tensor{{2}, IND_ET, std::vector<IND_T>{2, 3}},
|
||||
Tensor{{2}, IND_ET, std::vector<IND_T>{1, 2}},
|
||||
Tensor{{2}, AXIS_ET, std::vector<AXIS_T>{0, 1}},
|
||||
Tensor{{1, 2}, DATA_ET, std::vector<DATA_T>{5, 7}},
|
||||
"2D_step_2"),
|
||||
SliceParams(Tensor{{3, 16}, DATA_ET, std::vector<DATA_T>{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
|
||||
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
|
||||
24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
|
||||
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}},
|
||||
Tensor{{2}, IND_ET, std::vector<IND_T>{0, 0}},
|
||||
Tensor{{2}, IND_ET, std::vector<IND_T>{3, 16}},
|
||||
Tensor{{2}, IND_ET, std::vector<IND_T>{1, 15}},
|
||||
Tensor{{2}, AXIS_ET, std::vector<AXIS_T>{0, 1}},
|
||||
Tensor{{3, 2}, DATA_ET, std::vector<DATA_T>{0, 15, 16, 31, 32, 47}},
|
||||
"2D_big_step"),
|
||||
SliceParams(Tensor{{2, 2}, DATA_ET, std::vector<DATA_T>{1, 2, 3, 4}},
|
||||
Tensor{{2}, IND_ET, std::vector<IND_T>{10, 0}},
|
||||
Tensor{{2}, IND_ET, std::vector<IND_T>{20, 2}},
|
||||
Tensor{{2}, IND_ET, std::vector<IND_T>{1, 1}},
|
||||
Tensor{{2}, AXIS_ET, std::vector<AXIS_T>{0, 1}},
|
||||
Tensor{{0, 2}, DATA_ET, std::vector<DATA_T>{}},
|
||||
"2D_empty_output"),
|
||||
SliceParams(Tensor{{2, 2, 2}, DATA_ET, std::vector<DATA_T>{1, 2, 3, 4, 5, 6, 7, 8}},
|
||||
Tensor{{3}, IND_ET, std::vector<IND_T>{0, 0, 0}},
|
||||
Tensor{{3}, IND_ET, std::vector<IND_T>{2, 2, 2}},
|
||||
Tensor{{3}, IND_ET, std::vector<IND_T>{1, 1, 1}},
|
||||
Tensor{{3}, AXIS_ET, std::vector<AXIS_T>{0, 1, 2}},
|
||||
Tensor{{2, 2, 2}, DATA_ET, std::vector<DATA_T>{1, 2, 3, 4, 5, 6, 7, 8}},
|
||||
"3D_full_axes"),
|
||||
SliceParams(Tensor{{2, 2, 2}, DATA_ET, std::vector<DATA_T>{1, 2, 3, 4, 5, 6, 7, 8}},
|
||||
Tensor{{3}, IND_ET, std::vector<IND_T>{0, 0, 0}},
|
||||
Tensor{{3}, IND_ET, std::vector<IND_T>{2, 2, 2}},
|
||||
Tensor{{3}, IND_ET, std::vector<IND_T>{1, 1, 1}},
|
||||
Tensor{{2, 2, 2}, DATA_ET, std::vector<DATA_T>{1, 2, 3, 4, 5, 6, 7, 8}},
|
||||
"3D_default_axes"),
|
||||
SliceParams(Tensor{{2, 2, 2}, DATA_ET, std::vector<DATA_T>{1, 2, 3, 4, 5, 6, 7, 8}},
|
||||
Tensor{{2}, IND_ET, std::vector<IND_T>{0, 0}},
|
||||
Tensor{{2}, IND_ET, std::vector<IND_T>{2, 2}},
|
||||
Tensor{{2}, IND_ET, std::vector<IND_T>{1, 1}},
|
||||
Tensor{{2}, AXIS_ET, std::vector<AXIS_T>{0, 1}},
|
||||
Tensor{{2, 2, 2}, DATA_ET, std::vector<DATA_T>{1, 2, 3, 4, 5, 6, 7, 8}},
|
||||
"3D_less_axes"),
|
||||
SliceParams(Tensor{{2, 2, 2}, DATA_ET, std::vector<DATA_T>{1, 2, 3, 4, 5, 6, 7, 8}},
|
||||
Tensor{{3}, IND_ET, std::vector<IND_T>{0, 2, 0}},
|
||||
Tensor{{3}, IND_ET, std::vector<IND_T>{2, 2, 2}},
|
||||
Tensor{{3}, IND_ET, std::vector<IND_T>{1, 1, 1}},
|
||||
Tensor{{3}, AXIS_ET, std::vector<AXIS_T>{0, 1, 2}},
|
||||
Tensor{{2, 0, 2}, DATA_ET, std::vector<DATA_T>{}},
|
||||
"3D_empty_output"),
|
||||
SliceParams(Tensor{{4, 2, 3, 2}, DATA_ET, std::vector<DATA_T>{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
|
||||
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
|
||||
24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
|
||||
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}},
|
||||
Tensor{{4}, IND_ET, std::vector<IND_T>{0, 0, 0, 0}},
|
||||
Tensor{{4}, IND_ET, std::vector<IND_T>{4, 2, 3, 2}},
|
||||
Tensor{{4}, IND_ET, std::vector<IND_T>{1, 1, 1, 1}},
|
||||
Tensor{{4}, AXIS_ET, std::vector<AXIS_T>{0, 1, 2, 3}},
|
||||
Tensor{{4, 2, 3, 2}, DATA_ET, std::vector<DATA_T>{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
|
||||
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
|
||||
24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
|
||||
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}},
|
||||
"4D_full_axes"),
|
||||
SliceParams(Tensor{{4, 2, 3, 2}, DATA_ET, std::vector<DATA_T>{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
|
||||
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
|
||||
24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
|
||||
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}},
|
||||
Tensor{{4}, IND_ET, std::vector<IND_T>{0, 0, 0, 0}},
|
||||
Tensor{{4}, IND_ET, std::vector<IND_T>{4, 2, 3, 2}},
|
||||
Tensor{{4}, IND_ET, std::vector<IND_T>{1, 1, 1, 1}},
|
||||
Tensor{{4, 2, 3, 2}, DATA_ET, std::vector<DATA_T>{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
|
||||
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
|
||||
24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
|
||||
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}},
|
||||
"4D_default_axes"),
|
||||
SliceParams(Tensor{{4, 2, 3, 2}, DATA_ET, std::vector<DATA_T>{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
|
||||
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
|
||||
24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
|
||||
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}},
|
||||
Tensor{{1}, IND_ET, std::vector<IND_T>{0}},
|
||||
Tensor{{1}, IND_ET, std::vector<IND_T>{2}},
|
||||
Tensor{{1}, IND_ET, std::vector<IND_T>{1}},
|
||||
Tensor{{1}, AXIS_ET, std::vector<AXIS_T>{0}},
|
||||
Tensor{{2, 2, 3, 2}, DATA_ET, std::vector<DATA_T>{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
|
||||
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}},
|
||||
"4D_half_dim"),
|
||||
SliceParams(Tensor{{4, 2, 3, 2}, DATA_ET, std::vector<DATA_T>{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
|
||||
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
|
||||
24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
|
||||
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}},
|
||||
Tensor{{1}, IND_ET, std::vector<IND_T>{0}},
|
||||
Tensor{{1}, IND_ET, std::vector<IND_T>{4}},
|
||||
Tensor{{1}, IND_ET, std::vector<IND_T>{2}},
|
||||
Tensor{{1}, AXIS_ET, std::vector<AXIS_T>{0}},
|
||||
Tensor{{2, 2, 3, 2}, DATA_ET, std::vector<DATA_T>{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
|
||||
24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35}},
|
||||
"4D_half_dim_step"),
|
||||
SliceParams(
|
||||
Tensor{{2, 4, 2, 2, 3},
|
||||
DATA_ET,
|
||||
std::vector<DATA_T>{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
|
||||
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
|
||||
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
|
||||
60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
|
||||
80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95}},
|
||||
Tensor{{5}, IND_ET, std::vector<IND_T>{0, 0, 0, 0, 0}},
|
||||
Tensor{{5}, IND_ET, std::vector<IND_T>{2, 4, 2, 2, 3}},
|
||||
Tensor{{5}, IND_ET, std::vector<IND_T>{1, 1, 1, 1, 1}},
|
||||
Tensor{{5}, AXIS_ET, std::vector<AXIS_T>{0, 1, 2, 3, 4}},
|
||||
Tensor{{2, 2, 2, 1, 2},
|
||||
DATA_ET,
|
||||
std::vector<DATA_T>{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
|
||||
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
|
||||
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
|
||||
60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
|
||||
80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95}},
|
||||
"5D_full_axes"),
|
||||
};
|
||||
return test_params;
|
||||
}
|
||||
|
||||
template <element::Type_t DATA_ET, element::Type_t IND_ET, element::Type_t AXIS_ET>
|
||||
std::vector<SliceParams> generateSliceParams() {
|
||||
using DATA_T = typename element_type_traits<DATA_ET>::value_type;
|
||||
using IND_T = typename element_type_traits<IND_ET>::value_type;
|
||||
using AXIS_T = typename element_type_traits<AXIS_ET>::value_type;
|
||||
|
||||
std::vector<SliceParams> test_params{
|
||||
SliceParams(Tensor{{4}, DATA_ET, std::vector<DATA_T>{1, 2, 3, 4}},
|
||||
Tensor{{1}, IND_ET, std::vector<IND_T>{5}},
|
||||
Tensor{{1}, IND_ET, std::vector<IND_T>{-6}},
|
||||
Tensor{{1}, IND_ET, std::vector<IND_T>{-1}},
|
||||
Tensor{{4}, DATA_ET, std::vector<DATA_T>{4, 3, 2, 1}},
|
||||
"1D_negative_step"),
|
||||
SliceParams(Tensor{{4}, DATA_ET, std::vector<DATA_T>{1, 2, 3, 4}},
|
||||
Tensor{{1}, IND_ET, std::vector<IND_T>{0}},
|
||||
Tensor{{1}, IND_ET, std::vector<IND_T>{5}},
|
||||
Tensor{{1}, IND_ET, std::vector<IND_T>{-1}},
|
||||
Tensor{{1}, AXIS_ET, std::vector<AXIS_T>{0}},
|
||||
Tensor{{0}, DATA_ET, std::vector<DATA_T>{}},
|
||||
"1D_empty_output_negative_step"),
|
||||
SliceParams(Tensor{{2, 2}, DATA_ET, std::vector<DATA_T>{1, 2, 3, 4}},
|
||||
Tensor{{2}, IND_ET, std::vector<IND_T>{0, 3}},
|
||||
Tensor{{2}, IND_ET, std::vector<IND_T>{2, -4}},
|
||||
Tensor{{2}, IND_ET, std::vector<IND_T>{1, -1}},
|
||||
Tensor{{2}, AXIS_ET, std::vector<AXIS_T>{0, 1}},
|
||||
Tensor{{2, 2}, DATA_ET, std::vector<DATA_T>{2, 1, 4, 3}},
|
||||
"2D_negative_step_mix"),
|
||||
SliceParams(Tensor{{2, 2}, DATA_ET, std::vector<DATA_T>{1, 2, 3, 4}},
|
||||
Tensor{{2}, IND_ET, std::vector<IND_T>{-1, 3}},
|
||||
Tensor{{2}, IND_ET, std::vector<IND_T>{-4, -4}},
|
||||
Tensor{{2}, IND_ET, std::vector<IND_T>{-1, -1}},
|
||||
Tensor{{2}, AXIS_ET, std::vector<AXIS_T>{0, 1}},
|
||||
Tensor{{2, 2}, DATA_ET, std::vector<DATA_T>{4, 3, 2, 1}},
|
||||
"2D_negative_step_only"),
|
||||
SliceParams(Tensor{{3, 16}, DATA_ET, std::vector<DATA_T>{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
|
||||
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
|
||||
24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
|
||||
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}},
|
||||
Tensor{{2}, IND_ET, std::vector<IND_T>{2, 15}},
|
||||
Tensor{{2}, IND_ET, std::vector<IND_T>{-4, -17}},
|
||||
Tensor{{2}, IND_ET, std::vector<IND_T>{-1, -15}},
|
||||
Tensor{{2}, AXIS_ET, std::vector<AXIS_T>{0, 1}},
|
||||
Tensor{{3, 2}, DATA_ET, std::vector<DATA_T>{47, 32, 31, 16, 15, 0}},
|
||||
"2D_negative_big_step"),
|
||||
SliceParams(Tensor{{2, 2, 2}, DATA_ET, std::vector<DATA_T>{1, 2, 3, 4, 5, 6, 7, 8}},
|
||||
Tensor{{3}, IND_ET, std::vector<IND_T>{0, 0, 0}},
|
||||
Tensor{{3}, IND_ET, std::vector<IND_T>{2, 2, 2}},
|
||||
Tensor{{3}, IND_ET, std::vector<IND_T>{1, 1, 1}},
|
||||
Tensor{{3}, AXIS_ET, std::vector<AXIS_T>{-3, -2, -1}},
|
||||
Tensor{{2, 2, 2}, DATA_ET, std::vector<DATA_T>{1, 2, 3, 4, 5, 6, 7, 8}},
|
||||
"3D_negative_axes"),
|
||||
SliceParams(Tensor{{2, 4, 3}, DATA_ET, std::vector<DATA_T>{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
|
||||
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}},
|
||||
Tensor{{3}, IND_ET, std::vector<IND_T>{0, 0, 4}},
|
||||
Tensor{{3}, IND_ET, std::vector<IND_T>{2, 4, -5}},
|
||||
Tensor{{3}, IND_ET, std::vector<IND_T>{3, 2, -2}},
|
||||
Tensor{{3}, AXIS_ET, std::vector<AXIS_T>{0, 1, 2}},
|
||||
Tensor{{1, 2, 2}, DATA_ET, std::vector<DATA_T>{2, 0, 8, 6}},
|
||||
"3D_mixed_step"),
|
||||
SliceParams(Tensor{{4, 2, 3, 2}, DATA_ET, std::vector<DATA_T>{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
|
||||
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
|
||||
24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
|
||||
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}},
|
||||
Tensor{{4},
|
||||
IND_ET,
|
||||
std::vector<IND_T>{std::numeric_limits<IND_T>::min(),
|
||||
std::numeric_limits<IND_T>::max(),
|
||||
std::numeric_limits<IND_T>::max(),
|
||||
std::numeric_limits<IND_T>::min()}},
|
||||
Tensor{{4},
|
||||
IND_ET,
|
||||
std::vector<IND_T>{std::numeric_limits<IND_T>::max(),
|
||||
std::numeric_limits<IND_T>::min(),
|
||||
std::numeric_limits<IND_T>::min(),
|
||||
std::numeric_limits<IND_T>::max()}},
|
||||
Tensor{{4}, IND_ET, std::vector<IND_T>{1, -1, -1, 1}},
|
||||
Tensor{{4}, AXIS_ET, std::vector<AXIS_T>{0, 1, 2, 3}},
|
||||
Tensor{{4, 2, 3, 2}, DATA_ET, std::vector<DATA_T>{10, 11, 8, 9, 6, 7, 4, 5, 2, 3, 0, 1,
|
||||
22, 23, 20, 21, 18, 19, 16, 17, 14, 15, 12, 13,
|
||||
34, 35, 32, 33, 30, 31, 28, 29, 26, 27, 24, 25,
|
||||
46, 47, 44, 45, 42, 43, 40, 41, 38, 39, 36, 37}},
|
||||
"4D_INT_MIN_MAX_index"),
|
||||
SliceParams(Tensor{{4, 2, 3, 2}, DATA_ET, std::vector<DATA_T>{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
|
||||
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
|
||||
24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
|
||||
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}},
|
||||
Tensor{{2}, IND_ET, std::vector<IND_T>{100, -100}},
|
||||
Tensor{{2}, IND_ET, std::vector<IND_T>{-100, 100}},
|
||||
Tensor{{2}, IND_ET, std::vector<IND_T>{-1, 2}},
|
||||
Tensor{{2}, AXIS_ET, std::vector<AXIS_T>{2, 0}},
|
||||
Tensor{{2, 2, 3, 2}, DATA_ET, std::vector<DATA_T>{4, 5, 2, 3, 0, 1, 10, 11, 8, 9, 6, 7,
|
||||
28, 29, 26, 27, 24, 25, 34, 35, 32, 33, 30, 31}},
|
||||
"4D_mixed"),
|
||||
SliceParams(
|
||||
Tensor{{2, 4, 2, 2, 3},
|
||||
DATA_ET,
|
||||
std::vector<DATA_T>{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
|
||||
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
|
||||
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
|
||||
60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
|
||||
80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95}},
|
||||
Tensor{{5}, IND_ET, std::vector<IND_T>{0, 1, -5, 100, 1}},
|
||||
Tensor{{5}, IND_ET, std::vector<IND_T>{2, 6, 3, -100, 2}},
|
||||
Tensor{{5}, IND_ET, std::vector<IND_T>{1, 2, 2, -1, 1}},
|
||||
Tensor{{5}, AXIS_ET, std::vector<AXIS_T>{-5, 1, 4, 2, 3}},
|
||||
Tensor{{2, 2, 2, 1, 2},
|
||||
DATA_ET,
|
||||
std::vector<DATA_T>{21, 23, 15, 17, 45, 47, 39, 41, 69, 71, 63, 65, 93, 95, 87, 89}},
|
||||
"5D_mixed"),
|
||||
};
|
||||
const auto& unsigned_test_params = generateSliceParamsUnsigned<DATA_ET, IND_ET, AXIS_ET>();
|
||||
test_params.insert(test_params.end(), unsigned_test_params.begin(), unsigned_test_params.end());
|
||||
return test_params;
|
||||
}
|
||||
|
||||
std::vector<SliceParams> generateSliceCombinedParams() {
|
||||
const std::vector<std::vector<SliceParams>> opTypeParams{
|
||||
// Mixed types
|
||||
generateSliceParams<element::Type_t::f16, element::Type_t::i32, element::Type_t::i8>(),
|
||||
generateSliceParams<element::Type_t::bf16, element::Type_t::i32, element::Type_t::i16>(),
|
||||
generateSliceParams<element::Type_t::f32, element::Type_t::i64, element::Type_t::i32>(),
|
||||
generateSliceParams<element::Type_t::i8, element::Type_t::i16, element::Type_t::i8>(),
|
||||
generateSliceParams<element::Type_t::i16, element::Type_t::i8, element::Type_t::i16>(),
|
||||
generateSliceParams<element::Type_t::i32, element::Type_t::i64, element::Type_t::i32>(),
|
||||
generateSliceParams<element::Type_t::i64, element::Type_t::i32, element::Type_t::i64>(),
|
||||
generateSliceParams<element::Type_t::u32, element::Type_t::i32, element::Type_t::i16>(),
|
||||
|
||||
// Unsigned types
|
||||
generateSliceParamsUnsigned<element::Type_t::u8, element::Type_t::u8, element::Type_t::u8>(),
|
||||
generateSliceParamsUnsigned<element::Type_t::u16, element::Type_t::u16, element::Type_t::u16>(),
|
||||
generateSliceParamsUnsigned<element::Type_t::u32, element::Type_t::u32, element::Type_t::u32>(),
|
||||
generateSliceParamsUnsigned<element::Type_t::u64, element::Type_t::u64, element::Type_t::u64>(),
|
||||
generateSliceParamsUnsigned<element::Type_t::u16, element::Type_t::u8, element::Type_t::u32>(),
|
||||
generateSliceParamsUnsigned<element::Type_t::u32, element::Type_t::u16, element::Type_t::u8>(),
|
||||
};
|
||||
std::vector<SliceParams> combinedParams;
|
||||
std::for_each(opTypeParams.begin(), opTypeParams.end(), [&](std::vector<SliceParams> params) {
|
||||
combinedParams.insert(combinedParams.end(), params.begin(), params.end());
|
||||
});
|
||||
return combinedParams;
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(smoke_Slice_With_Hardcoded_Refs,
|
||||
ReferenceSliceLayerTest,
|
||||
::testing::ValuesIn(generateSliceCombinedParams()),
|
||||
ReferenceSliceLayerTest::getTestCaseName);
|
||||
|
||||
} // namespace reference_tests
|
@ -1,4 +1,3 @@
|
||||
|
||||
// Copyright (C) 2018-2021 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
@ -32,6 +31,12 @@ public:
|
||||
bool visit_attributes(AttributeVisitor& visitor) override;
|
||||
|
||||
std::shared_ptr<Node> clone_with_new_inputs(const OutputVector& new_args) const override;
|
||||
|
||||
PartialShape calculate_output_shape(const std::vector<int64_t>& starts,
|
||||
const std::vector<int64_t>& stops,
|
||||
const std::vector<int64_t>& steps,
|
||||
const std::vector<int64_t>& axes,
|
||||
const PartialShape& data_shape) const;
|
||||
};
|
||||
} // namespace v8
|
||||
} // namespace op
|
||||
|
@ -10,6 +10,17 @@
|
||||
namespace ngraph {
|
||||
namespace runtime {
|
||||
namespace reference {
|
||||
// Slice-8 reference implementation
|
||||
void slice(const char* data,
|
||||
const Shape& data_shape,
|
||||
char* out,
|
||||
const Shape& out_shape,
|
||||
size_t elem_size,
|
||||
const std::vector<int64_t>& starts,
|
||||
const std::vector<int64_t>& steps,
|
||||
const std::vector<int64_t>& axes);
|
||||
|
||||
// Part of StridedSlice implementation
|
||||
void slice(const char* arg,
|
||||
char* out,
|
||||
const Shape& arg_shape,
|
||||
@ -18,6 +29,6 @@ void slice(const char* arg,
|
||||
const Strides& strides,
|
||||
const Shape& out_shape,
|
||||
size_t elem_size);
|
||||
}
|
||||
} // namespace reference
|
||||
} // namespace runtime
|
||||
} // namespace ngraph
|
||||
|
@ -8,10 +8,54 @@
|
||||
|
||||
#include "ngraph/check.hpp"
|
||||
#include "ngraph/coordinate_range.hpp"
|
||||
#include "openvino/core/except.hpp"
|
||||
|
||||
namespace ngraph {
|
||||
namespace runtime {
|
||||
namespace reference {
|
||||
|
||||
void slice(const char* data,
|
||||
const Shape& data_shape,
|
||||
char* out,
|
||||
const Shape& out_shape,
|
||||
size_t elem_size,
|
||||
const std::vector<int64_t>& starts,
|
||||
const std::vector<int64_t>& steps,
|
||||
const std::vector<int64_t>& axes) {
|
||||
const auto ind_size = starts.size();
|
||||
OPENVINO_ASSERT(steps.size() == ind_size && axes.size() == ind_size,
|
||||
"Slice starts, steps, axes args need to have the same size.");
|
||||
OPENVINO_ASSERT(data_shape.size() == out_shape.size(),
|
||||
"Slice output data rank need to be equal to input data rank.");
|
||||
|
||||
// Align inputs rank with data shape and normalize
|
||||
const auto data_rank = data_shape.size();
|
||||
std::vector<int64_t> aligned_starts(data_rank, 0);
|
||||
std::vector<int64_t> aligned_steps(data_rank, 1);
|
||||
for (size_t i = 0; i < axes.size(); ++i) {
|
||||
const auto axis = axes[i] >= 0 ? axes[i] : axes[i] + data_rank;
|
||||
OPENVINO_ASSERT(axis >= 0 && axis < data_rank, "Slice `axes` arg has out of range value.");
|
||||
const auto& dim = data_shape[axis];
|
||||
aligned_starts[axis] = starts[i] >= 0 ? std::min<int64_t>(starts[i], steps[i] < 0 ? dim - 1 : dim)
|
||||
: std::min<int64_t>(std::max<int64_t>(0, starts[i] + dim), dim - 1);
|
||||
aligned_steps[axis] = steps[i];
|
||||
}
|
||||
|
||||
// Slice elements
|
||||
const auto in_data_strides = row_major_strides(data_shape);
|
||||
const auto out_data_strides = row_major_strides(out_shape);
|
||||
std::vector<int64_t> in_data_coord(aligned_starts);
|
||||
for (size_t out_idx = 0; out_idx < shape_size(out_shape); ++out_idx) {
|
||||
for (size_t i = 0; i < in_data_coord.size(); ++i) {
|
||||
in_data_coord[i] = aligned_starts[i] + (out_idx / out_data_strides[i] % out_shape[i]) * aligned_steps[i];
|
||||
}
|
||||
const auto in_idx = std::inner_product(in_data_coord.begin(), in_data_coord.end(), in_data_strides.begin(), 0);
|
||||
const auto in_mem = data + in_idx * elem_size;
|
||||
std::memcpy(out, in_mem, elem_size);
|
||||
out += elem_size;
|
||||
}
|
||||
}
|
||||
|
||||
void slice(const char* arg,
|
||||
char* out,
|
||||
const Shape& arg_shape,
|
||||
|
@ -133,13 +133,13 @@ void op::v8::Slice::validate_and_infer_types() {
|
||||
if (data_rank.is_static()) {
|
||||
const auto data_rank_length = data_rank.get_length();
|
||||
NODE_VALIDATION_CHECK(this,
|
||||
start_rank.is_dynamic() || start_shape[0].get_max_length() <= data_rank_length,
|
||||
start_rank.is_dynamic() || start_shape[0].get_min_length() <= data_rank_length,
|
||||
"Slice `start` input dim size can't be bigger than `data` rank.");
|
||||
NODE_VALIDATION_CHECK(this,
|
||||
stop_rank.is_dynamic() || stop_shape[0].get_max_length() <= data_rank_length,
|
||||
stop_rank.is_dynamic() || stop_shape[0].get_min_length() <= data_rank_length,
|
||||
"Slice `stop` input dim size can't be bigger than `data` rank.");
|
||||
NODE_VALIDATION_CHECK(this,
|
||||
step_rank.is_dynamic() || step_shape[0].get_max_length() <= data_rank_length,
|
||||
step_rank.is_dynamic() || step_shape[0].get_min_length() <= data_rank_length,
|
||||
"Slice `step` input dim size can't be bigger than `data` rank.");
|
||||
}
|
||||
|
||||
@ -186,7 +186,6 @@ void op::v8::Slice::validate_and_infer_types() {
|
||||
set_output_type(0, get_input_element_type(0), output_shape);
|
||||
return;
|
||||
}
|
||||
const auto data_static_rank = data_shape.rank().get_length();
|
||||
|
||||
if (start_const && stop_const && step_const && axes_const) {
|
||||
const auto& starts = start_const->cast_vector<int64_t>();
|
||||
@ -194,55 +193,9 @@ void op::v8::Slice::validate_and_infer_types() {
|
||||
const auto& steps = step_const->cast_vector<int64_t>();
|
||||
const auto& axes = axes_const->cast_vector<int64_t>();
|
||||
|
||||
std::unordered_set<int64_t> axes_set(axes.begin(), axes.end());
|
||||
NODE_VALIDATION_CHECK(this, axes_set.size() == axes.size(), "Slice values in `axes` input must be unique.");
|
||||
|
||||
for (size_t i = 0; i < axes.size(); ++i) {
|
||||
const auto norm_axis = axes[i] < 0 ? data_static_rank + axes[i] : axes[i];
|
||||
NODE_VALIDATION_CHECK(this,
|
||||
norm_axis >= 0 && norm_axis < data_static_rank,
|
||||
"Values in the `axes` input must be in range of the `data` input rank: [-",
|
||||
data_static_rank,
|
||||
", ",
|
||||
data_static_rank - 1,
|
||||
"]. Got: ",
|
||||
axes[i]);
|
||||
|
||||
auto start = starts[i];
|
||||
auto stop = stops[i];
|
||||
auto step = steps[i];
|
||||
|
||||
NODE_VALIDATION_CHECK(this, step != 0, "Slice 'step' value can't be zero.");
|
||||
|
||||
const auto& axis_dim = data_shape[norm_axis];
|
||||
const auto axis_min_dim_length = axis_dim.get_min_length();
|
||||
const auto min_dim_size = get_sliced_dim_size(start, stop, step, axis_min_dim_length);
|
||||
if (axis_dim.is_static()) {
|
||||
output_shape[norm_axis] = min_dim_size;
|
||||
}
|
||||
|
||||
// Avoid negative index normalization without upper bounds
|
||||
if (!axis_dim.get_interval().has_upper_bound()) {
|
||||
if ((step < 0 && start < 0 && stop > 0) || (step > 0 && stop < 0 && start > 0)) {
|
||||
output_shape[norm_axis] = Dimension(-1);
|
||||
continue;
|
||||
} else if (step < 0 && start > 0 && stop < 0) {
|
||||
int64_t max_out_dim = start >= INT32_MAX ? INT64_MAX : start + 1;
|
||||
output_shape[norm_axis] = Dimension(0, max_out_dim);
|
||||
continue;
|
||||
} else if (step > 0 && stop > 0 && start < 0) {
|
||||
int64_t max_out_dim = stop >= INT32_MAX ? INT64_MAX : stop;
|
||||
output_shape[norm_axis] = Dimension(0, max_out_dim);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate max dim length (upper bound)
|
||||
auto axis_max_dim_length = axis_dim.get_interval().get_max_val();
|
||||
const auto max_dim_size = get_sliced_dim_size(start, stop, step, axis_max_dim_length);
|
||||
output_shape[norm_axis] = Dimension(min_dim_size, max_dim_size);
|
||||
}
|
||||
output_shape = calculate_output_shape(starts, stops, steps, axes, data_shape);
|
||||
} else {
|
||||
const auto data_static_rank = data_shape.rank().get_length();
|
||||
if (axes_const) {
|
||||
// If we know only `axes` values, we should update lower_bound to 0 value,
|
||||
// for the specified dims by the axes. For unspecified dims, bounds as in data_shape.
|
||||
@ -256,12 +209,12 @@ void op::v8::Slice::validate_and_infer_types() {
|
||||
data_static_rank - 1,
|
||||
"]. Got: ",
|
||||
axis);
|
||||
output_shape[axis] = Dimension(0, data_shape[axis].get_max_length());
|
||||
output_shape[norm_axis] = Dimension(0, data_shape[norm_axis].get_max_length());
|
||||
}
|
||||
} else {
|
||||
// Otherwise `axes` values are also unknown,
|
||||
// then all of the output dims can be 0, so have lower bound = 0.
|
||||
for (size_t i = 0; i < data_shape.rank().get_length(); ++i) {
|
||||
for (size_t i = 0; i < data_static_rank; ++i) {
|
||||
output_shape[i] = Dimension(0, data_shape[i].get_max_length());
|
||||
}
|
||||
}
|
||||
@ -269,7 +222,7 @@ void op::v8::Slice::validate_and_infer_types() {
|
||||
set_output_type(0, get_input_element_type(0), output_shape);
|
||||
}
|
||||
|
||||
shared_ptr<Node> op::v8::Slice::clone_with_new_inputs(const OutputVector& new_args) const {
|
||||
std::shared_ptr<Node> op::v8::Slice::clone_with_new_inputs(const OutputVector& new_args) const {
|
||||
NGRAPH_OP_SCOPE(v8_Slice_clone_with_new_inputs);
|
||||
check_new_args_count(this, new_args);
|
||||
if (new_args.size() == 4) {
|
||||
@ -282,3 +235,72 @@ shared_ptr<Node> op::v8::Slice::clone_with_new_inputs(const OutputVector& new_ar
|
||||
new_args.at(4));
|
||||
}
|
||||
}
|
||||
|
||||
PartialShape op::v8::Slice::calculate_output_shape(const std::vector<int64_t>& starts,
|
||||
const std::vector<int64_t>& stops,
|
||||
const std::vector<int64_t>& steps,
|
||||
const std::vector<int64_t>& axes,
|
||||
const PartialShape& data_shape) const {
|
||||
NGRAPH_OP_SCOPE(v8_Slice_calculate_output_shape);
|
||||
const auto ind_size = starts.size();
|
||||
NODE_VALIDATION_CHECK(this,
|
||||
stops.size() == ind_size && steps.size() == ind_size && axes.size() == ind_size,
|
||||
"Slice `start`, `stop`, `step`, `axes` inputs need to have the same size.");
|
||||
|
||||
std::unordered_set<int64_t> axes_set(axes.begin(), axes.end());
|
||||
NODE_VALIDATION_CHECK(this, axes_set.size() == axes.size(), "Slice values in `axes` input must be unique.");
|
||||
|
||||
PartialShape output_shape(data_shape);
|
||||
if (data_shape.rank().is_dynamic()) {
|
||||
return output_shape;
|
||||
}
|
||||
|
||||
const auto data_static_rank = data_shape.rank().get_length();
|
||||
for (size_t i = 0; i < axes.size(); ++i) {
|
||||
const auto norm_axis = axes[i] < 0 ? data_static_rank + axes[i] : axes[i];
|
||||
NODE_VALIDATION_CHECK(this,
|
||||
norm_axis >= 0 && norm_axis < data_static_rank,
|
||||
"Values in the `axes` input must be in range of the `data` input rank: [-",
|
||||
data_static_rank,
|
||||
", ",
|
||||
data_static_rank - 1,
|
||||
"]. Got: ",
|
||||
axes[i]);
|
||||
|
||||
auto start = starts[i];
|
||||
auto stop = stops[i];
|
||||
auto step = steps[i];
|
||||
|
||||
NODE_VALIDATION_CHECK(this, step != 0, "Slice 'step' value can't be zero.");
|
||||
|
||||
const auto& axis_dim = data_shape[norm_axis];
|
||||
const auto axis_min_dim_length = axis_dim.get_min_length();
|
||||
const auto min_dim_size = get_sliced_dim_size(start, stop, step, axis_min_dim_length);
|
||||
if (axis_dim.is_static()) {
|
||||
output_shape[norm_axis] = min_dim_size;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Avoid negative index normalization without upper bounds
|
||||
if (!axis_dim.get_interval().has_upper_bound()) {
|
||||
if ((step < 0 && start < 0 && stop > 0) || (step > 0 && stop < 0 && start > 0)) {
|
||||
output_shape[norm_axis] = Dimension(-1);
|
||||
continue;
|
||||
} else if (step < 0 && start > 0 && stop < 0) {
|
||||
int64_t max_out_dim = start >= INT32_MAX ? INT64_MAX : start + 1;
|
||||
output_shape[norm_axis] = Dimension(0, max_out_dim);
|
||||
continue;
|
||||
} else if (step > 0 && stop > 0 && start < 0) {
|
||||
int64_t max_out_dim = stop >= INT32_MAX ? INT64_MAX : stop;
|
||||
output_shape[norm_axis] = Dimension(0, max_out_dim);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate max dim length (upper bound)
|
||||
auto axis_max_dim_length = axis_dim.get_interval().get_max_val();
|
||||
const auto max_dim_size = get_sliced_dim_size(start, stop, step, axis_max_dim_length);
|
||||
output_shape[norm_axis] = Dimension(min_dim_size, max_dim_size);
|
||||
}
|
||||
return output_shape;
|
||||
}
|
||||
|
@ -67,6 +67,7 @@
|
||||
#include <ngraph/runtime/reference/selu.hpp>
|
||||
#include <ngraph/runtime/reference/sequences.hpp>
|
||||
#include <ngraph/runtime/reference/sign.hpp>
|
||||
#include <ngraph/runtime/reference/slice.hpp>
|
||||
#include <ngraph/runtime/reference/squared_difference.hpp>
|
||||
#include <ngraph/runtime/reference/tensor_iterator.hpp>
|
||||
#include <ngraph/runtime/reference/utils/nms_common.hpp>
|
||||
@ -1480,6 +1481,43 @@ bool evaluate(const shared_ptr<op::v1::AvgPool>& op, const HostTensorVector& out
|
||||
return true;
|
||||
}
|
||||
|
||||
template <element::Type_t ET>
|
||||
bool evaluate(const std::shared_ptr<op::v8::Slice>& op,
|
||||
const HostTensorVector& outputs,
|
||||
const HostTensorVector& inputs) {
|
||||
OPENVINO_ASSERT(inputs.size() >= 4, "Slice evaluate needs at least 4 inputs.");
|
||||
std::vector<int64_t> starts = host_tensor_2_vector<int64_t>(inputs[1]);
|
||||
std::vector<int64_t> stops = host_tensor_2_vector<int64_t>(inputs[2]);
|
||||
std::vector<int64_t> steps = host_tensor_2_vector<int64_t>(inputs[3]);
|
||||
|
||||
std::vector<int64_t> axes(starts.size());
|
||||
if (inputs.size() < 5) {
|
||||
std::iota(axes.begin(), axes.end(), 0);
|
||||
} else {
|
||||
axes = host_tensor_2_vector<int64_t>(inputs[4]);
|
||||
}
|
||||
|
||||
// Static HostTensor data shape is needed to clamp and normalize `start` values
|
||||
const auto data_shape = inputs[0]->get_partial_shape();
|
||||
OPENVINO_ASSERT(data_shape.is_static(), "Can't evaluate Slice elements without static HostTensor data shape.");
|
||||
// We need calculate static output shape based on HostTensor inputs
|
||||
PartialShape output_shape = op->calculate_output_shape(starts, stops, steps, axes, data_shape);
|
||||
OPENVINO_ASSERT(output_shape.is_static(), "Can't calculate static output shape for Slice evaluation.");
|
||||
|
||||
outputs[0]->set_shape(output_shape.to_shape());
|
||||
outputs[0]->set_element_type(inputs[0]->get_element_type());
|
||||
|
||||
runtime::reference::slice(inputs[0]->get_data_ptr<char>(),
|
||||
data_shape.to_shape(),
|
||||
outputs[0]->get_data_ptr<char>(),
|
||||
output_shape.to_shape(),
|
||||
inputs[0]->get_element_type().size(),
|
||||
starts,
|
||||
steps,
|
||||
axes);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <element::Type_t ET>
|
||||
bool evaluate(const shared_ptr<op::v0::HardSigmoid>& op,
|
||||
const HostTensorVector& outputs,
|
||||
|
@ -103,3 +103,4 @@ NGRAPH_OP(AdaptiveMaxPool, ngraph::op::v8)
|
||||
NGRAPH_OP(Gather, op::v8)
|
||||
NGRAPH_OP(MatrixNms, op::v8)
|
||||
NGRAPH_OP(MulticlassNms, op::v8)
|
||||
NGRAPH_OP(Slice, op::v8)
|
||||
|
@ -103,6 +103,23 @@ TEST(type_prop, slice_v8_basic_const_inputs_default_axes) {
|
||||
EXPECT_EQ(op->get_output_partial_shape(0), expected_out_shape);
|
||||
}
|
||||
|
||||
TEST(type_prop, slice_v8_const_inputs_output_zero_dims) {
|
||||
PartialShape data_shape{5, 5, 5, 5, 9, 9};
|
||||
PartialShape expected_out_shape{3, 0, 5, 0, 5, 0};
|
||||
|
||||
std::vector<int32_t> start_val{0, 0, 0, 5, 0, 10};
|
||||
std::vector<int32_t> stop_val{5, 5, 5, 5, 9, 9};
|
||||
std::vector<int32_t> step_val{2, -3, 1, 5, 2, 1};
|
||||
|
||||
element::Type_t et = element::i32;
|
||||
|
||||
std::vector<std::vector<int32_t>> input_vals{start_val, stop_val, step_val};
|
||||
const auto op = make_slice_op_const_inputs(input_vals, data_shape, et);
|
||||
|
||||
EXPECT_EQ(op->get_element_type(), et);
|
||||
EXPECT_EQ(op->get_output_partial_shape(0), expected_out_shape);
|
||||
}
|
||||
|
||||
TEST(type_prop, slice_v8_basic_const_inputs_unordered_axes) {
|
||||
PartialShape data_shape{10, 10, 10, 10, 10, 10, 10, 10};
|
||||
PartialShape expected_out_shape{4, 9, 7, 10, 10, 9, 5, 10};
|
||||
@ -219,6 +236,56 @@ TEST(type_prop, slice_v8_basic_param_inputs_default_axes) {
|
||||
EXPECT_EQ(op->get_output_partial_shape(0), expected_out_shape);
|
||||
}
|
||||
|
||||
TEST(type_prop, slice_v8_sss_param_inputs_mixed_neg_const_axes) {
|
||||
PartialShape data_shape{Dimension(5, 10), 2, 7, Dimension(0, 4)};
|
||||
PartialShape expected_out_shape{Dimension(0, 10), Dimension(0, 2), 7, Dimension(0, 4)};
|
||||
|
||||
PartialShape start_shape{3};
|
||||
PartialShape stop_shape{3};
|
||||
PartialShape step_shape{3};
|
||||
|
||||
element::Type_t et = element::i32;
|
||||
|
||||
Shape axes_shape{3};
|
||||
std::vector<int32_t> axes_val{0, 3, 1};
|
||||
|
||||
const auto data = std::make_shared<op::v0::Parameter>(et, data_shape);
|
||||
const auto start = std::make_shared<op::v0::Parameter>(et, start_shape);
|
||||
const auto stop = std::make_shared<op::v0::Parameter>(et, stop_shape);
|
||||
const auto step = std::make_shared<op::v0::Parameter>(et, step_shape);
|
||||
const auto axes = std::make_shared<op::v0::Constant>(et, axes_shape, axes_val);
|
||||
|
||||
const auto op = std::make_shared<op::v8::Slice>(data, start, stop, step, axes);
|
||||
|
||||
EXPECT_EQ(op->get_element_type(), et);
|
||||
EXPECT_EQ(op->get_output_partial_shape(0), expected_out_shape);
|
||||
}
|
||||
|
||||
TEST(type_prop, slice_v8_sss_param_inputs_mixed_const_axes) {
|
||||
PartialShape data_shape{Dimension(5, 10), 2, 7, Dimension(0, 4)};
|
||||
PartialShape expected_out_shape{Dimension(0, 10), Dimension(0, 2), 7, Dimension(0, 4)};
|
||||
|
||||
PartialShape start_shape{3};
|
||||
PartialShape stop_shape{3};
|
||||
PartialShape step_shape{3};
|
||||
|
||||
element::Type_t et = element::i32;
|
||||
|
||||
Shape axes_shape{3};
|
||||
std::vector<int32_t> axes_val{-4, -1, -3};
|
||||
|
||||
const auto data = std::make_shared<op::v0::Parameter>(et, data_shape);
|
||||
const auto start = std::make_shared<op::v0::Parameter>(et, start_shape);
|
||||
const auto stop = std::make_shared<op::v0::Parameter>(et, stop_shape);
|
||||
const auto step = std::make_shared<op::v0::Parameter>(et, step_shape);
|
||||
const auto axes = std::make_shared<op::v0::Constant>(et, axes_shape, axes_val);
|
||||
|
||||
const auto op = std::make_shared<op::v8::Slice>(data, start, stop, step, axes);
|
||||
|
||||
EXPECT_EQ(op->get_element_type(), et);
|
||||
EXPECT_EQ(op->get_output_partial_shape(0), expected_out_shape);
|
||||
}
|
||||
|
||||
TEST(type_prop, slice_v8_basic_sss_param_inputs_const_axes) {
|
||||
PartialShape data_shape{Dimension(0, 10),
|
||||
Dimension(1, 10),
|
||||
|
Loading…
Reference in New Issue
Block a user