diff --git a/docs/template_plugin/tests/functional/op_reference/grid_sample.cpp b/docs/template_plugin/tests/functional/op_reference/grid_sample.cpp new file mode 100644 index 00000000000..6093be86859 --- /dev/null +++ b/docs/template_plugin/tests/functional/op_reference/grid_sample.cpp @@ -0,0 +1,519 @@ +// Copyright (C) 2022 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "openvino/op/grid_sample.hpp" + +#include "base_reference_test.hpp" +#include "gtest/gtest.h" + +using namespace ov; +using namespace reference_tests; + +namespace { +struct GridSampleParams { + GridSampleParams(const reference_tests::Tensor& data, + const reference_tests::Tensor& grid, + const op::v9::GridSample::Attributes& attrs, + const reference_tests::Tensor& expected, + const std::string& name) + : data_tensor{data}, + grid_tensor{grid}, + attributes{attrs}, + expected_tensor{expected}, + test_case_name{name} {} + + reference_tests::Tensor data_tensor; + reference_tests::Tensor grid_tensor; + op::v9::GridSample::Attributes attributes; + reference_tests::Tensor expected_tensor; + std::string test_case_name; +}; + +class ReferenceGridSample : public testing::TestWithParam, public CommonReferenceTest { +public: + void SetUp() override { + const auto& params = GetParam(); + function = CreateFunction(params.data_tensor, params.grid_tensor, params.attributes); + inputData = {params.data_tensor.data, params.grid_tensor.data}; + refOutData = {params.expected_tensor.data}; + } + + static std::string getTestCaseName(const testing::TestParamInfo& obj) { + return obj.param.test_case_name; + } + +private: + static std::shared_ptr CreateFunction(const reference_tests::Tensor& data, + const reference_tests::Tensor& grid, + const op::v9::GridSample::Attributes& attributes) { + const auto in1 = std::make_shared(data.type, data.shape); + const auto in2 = std::make_shared(grid.type, grid.shape); + const auto grid_sample = std::make_shared(in1, in2, attributes); + return std::make_shared(NodeVector{grid_sample}, ParameterVector{in1, in2}); + } +}; + +constexpr auto GS_BICUBIC{op::v9::GridSample::InterpolationMode::BICUBIC}; +constexpr auto GS_BILINEAR{op::v9::GridSample::InterpolationMode::BILINEAR}; +constexpr auto GS_NEAREST{op::v9::GridSample::InterpolationMode::NEAREST}; + +constexpr auto GS_BORDER{op::v9::GridSample::PaddingMode::BORDER}; +constexpr auto GS_REFLECTION{op::v9::GridSample::PaddingMode::REFLECTION}; +constexpr auto GS_ZEROS{op::v9::GridSample::PaddingMode::ZEROS}; + +constexpr std::array padding_modes{GS_ZEROS, GS_BORDER, GS_REFLECTION}; +constexpr std::array align_corners_modes{false, true}; + +std::vector generateNearestParamsOddDimensionsInnerGrids() { + std::vector params; + + reference_tests::Tensor data_odd_dims{{1, 1, 3, 5}, + element::f32, + std::vector{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}}; + reference_tests::Tensor grid_inner{ + {1, 3, 4, 2}, + element::f32, + std::vector{-0.1, -0.1, -0.1, 0.1, 0.1, -0.1, 0.1, 0.1, -0.5, -0.5, -0.5, 0.5, + 0.5, -0.5, 0.5, 0.5, -1., -1., -1., 1., 1., -1., 1., 1.}}; + reference_tests::Tensor output{{1, 1, 3, 4}, + element::f32, + std::vector{8, 8, 8, 8, 2, 12, 4, 14, 1, 11, 5, 15}}; + for (const auto& padding : padding_modes) { + for (const auto align : align_corners_modes) { + std::stringstream name; + name << "nearest_" << padding << (align ? "_align" : "_noalign") << "_odd_dims_inner"; + params.emplace_back(data_odd_dims, + grid_inner, + op::v9::GridSample::Attributes{align, GS_NEAREST, padding}, + output, + name.str()); + } + } + return params; +} + +std::vector generateNearestParamsOddDimensionsOuterGrids() { + std::vector params; + reference_tests::Tensor data_odd_dims{{1, 1, 3, 5}, + element::f32, + std::vector{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}}; + reference_tests::Tensor grid_outer{ + {1, 1, 7, 2}, + element::f32, + std::vector{-10.1, -9.7, -7.55, 0.37, -77., 11.56, 0.5, 2.55, 1.7, 1.1, 3., -0.17, 1.301, -1.001}}; + + params.emplace_back(data_odd_dims, + grid_outer, + op::v9::GridSample::Attributes{false, GS_NEAREST, GS_ZEROS}, + reference_tests::Tensor{{1, 1, 1, 7}, element::f32, std::vector{0, 0, 0, 0, 0, 0, 0}}, + "nearest_zeros_noalign_odd_dims_outer"); + + params.emplace_back(data_odd_dims, + grid_outer, + op::v9::GridSample::Attributes{true, GS_NEAREST, GS_ZEROS}, + reference_tests::Tensor{{1, 1, 1, 7}, element::f32, std::vector{0, 0, 0, 0, 0, 0, 0}}, + "nearest_zeros_align_odd_dims_outer"); + + params.emplace_back( + data_odd_dims, + grid_outer, + op::v9::GridSample::Attributes{false, GS_NEAREST, GS_BORDER}, + reference_tests::Tensor{{1, 1, 1, 7}, element::f32, std::vector{1, 11, 11, 14, 15, 10, 5}}, + "nearest_border_noalign_odd_dims_outer"); + + params.emplace_back( + data_odd_dims, + grid_outer, + op::v9::GridSample::Attributes{true, GS_NEAREST, GS_BORDER}, + reference_tests::Tensor{{1, 1, 1, 7}, element::f32, std::vector{1, 6, 11, 14, 15, 10, 5}}, + "nearest_border_align_odd_dims_outer"); + + params.emplace_back(data_odd_dims, + grid_outer, + op::v9::GridSample::Attributes{false, GS_NEAREST, GS_REFLECTION}, + reference_tests::Tensor{{1, 1, 1, 7}, element::f32, std::vector{8, 14, 1, 4, 14, 6, 5}}, + "nearest_reflection_noalign_odd_dims_outer"); + + params.emplace_back(data_odd_dims, + grid_outer, + op::v9::GridSample::Attributes{true, GS_NEAREST, GS_REFLECTION}, + reference_tests::Tensor{{1, 1, 1, 7}, element::f32, std::vector{8, 9, 6, 4, 14, 6, 4}}, + "nearest_reflection_align_odd_dims_outer"); + + return params; +} + +std::vector generateNearestParamsEvenDimensions() { + std::vector params; + reference_tests::Tensor data_even_dims{ + {1, 1, 4, 6}, + element::f32, + std::vector{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24}}; + reference_tests::Tensor grid_inner{ + {1, 1, 8, 2}, + element::f32, + std::vector{-0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, 0.5, -1, 1, 1, -1, -0.1, -0.1, 0.1, 0.1}}; + + reference_tests::Tensor output_align{{1, 1, 1, 8}, element::f32, std::vector{8, 14, 11, 17, 19, 6, 9, 16}}; + reference_tests::Tensor output_noalign{{1, 1, 1, 8}, element::f32, std::vector{2, 14, 5, 17, 19, 6, 9, 16}}; + reference_tests::Tensor output_zeros_noalign{{1, 1, 1, 8}, + element::f32, + std::vector{2, 14, 5, 17, 0, 0, 9, 16}}; + + for (const auto& padding : padding_modes) { + std::stringstream name1, name2; + name1 << "nearest_" << padding << "_noalign" + << "_even_dims_inner"; + params.emplace_back(data_even_dims, + grid_inner, + op::v9::GridSample::Attributes{false, GS_NEAREST, padding}, + padding == GS_ZEROS ? output_zeros_noalign : output_noalign, + name1.str()); + + name2 << "nearest_" << padding << "_align" + << "_even_dims_inner"; + params.emplace_back(data_even_dims, + grid_inner, + op::v9::GridSample::Attributes{true, GS_NEAREST, padding}, + output_align, + name2.str()); + } + + return params; +} + +std::vector generateBilinearParamsOddDimensionsInnerGrids() { + std::vector params; + reference_tests::Tensor data_odd_dims{{1, 1, 3, 5}, + element::f32, + std::vector{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}}; + reference_tests::Tensor grid_inner{ + {1, 3, 4, 2}, + element::f32, + std::vector{-0.1, -0.1, -0.1, 0.1, 0.1, -0.1, 0.1, 0.1, -0.5, -0.5, -0.5, 0.5, + 0.5, -0.5, 0.5, 0.5, -1., -1., -1., 1., 1., -1., 1., 1.}}; + + reference_tests::Tensor output_align{{1, 1, 3, 4}, + element::f32, + std::vector{7.3, 8.3, 7.7, 8.7, 4.5, 9.5, 6.5, 11.5, 1, 11, 5, 15}}; + reference_tests::Tensor output_noalign{{1, 1, 3, 4}, + element::f32, + std::vector{7, 8.5, 7.5, 9, 3, 10.5, 5.5, 13, 1, 11, 5, 15}}; + reference_tests::Tensor output_zeros_noalign{ + {1, 1, 3, 4}, + element::f32, + std::vector{7, 8.5, 7.5, 9, 3, 10.5, 5.5, 13, 0.25, 2.75, 1.25, 3.75}}; + + params.emplace_back(data_odd_dims, + grid_inner, + op::v9::GridSample::Attributes{false, GS_BILINEAR, GS_ZEROS}, + output_zeros_noalign, + "bilinear_zeros_noalign_odd_dims_inner"); + + params.emplace_back(data_odd_dims, + grid_inner, + op::v9::GridSample::Attributes{true, GS_BILINEAR, GS_ZEROS}, + output_align, + "bilinear_zeros_align_odd_dims_inner"); + + params.emplace_back(data_odd_dims, + grid_inner, + op::v9::GridSample::Attributes{false, GS_BILINEAR, GS_BORDER}, + output_noalign, + "bilinear_border_noalign_odd_dims_inner"); + + params.emplace_back(data_odd_dims, + grid_inner, + op::v9::GridSample::Attributes{true, GS_BILINEAR, GS_BORDER}, + output_align, + "bilinear_border_align_odd_dims_inner"); + + params.emplace_back(data_odd_dims, + grid_inner, + op::v9::GridSample::Attributes{false, GS_BILINEAR, GS_REFLECTION}, + output_noalign, + "bilinear_reflection_noalign_odd_dims_inner"); + + params.emplace_back(data_odd_dims, + grid_inner, + op::v9::GridSample::Attributes{true, GS_BILINEAR, GS_REFLECTION}, + output_align, + "bilinear_reflection_align_odd_dims_inner"); + + return params; +} + +std::vector generateBilinearParamsOddDimensionsOuterGrids() { + std::vector params; + + reference_tests::Tensor data_odd_dims{{1, 1, 3, 5}, + element::f32, + std::vector{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}}; + + reference_tests::Tensor grid_outer{ + {1, 1, 7, 2}, + element::f32, + std::vector{-10.1, -9.7, -7.55, 0.37, -77., 11.56, 0.5, 2.55, 1.7, 1.1, 3., -0.17, 1.301, -1.001}}; + + params.emplace_back(data_odd_dims, + grid_outer, + op::v9::GridSample::Attributes{false, GS_BILINEAR, GS_ZEROS}, + reference_tests::Tensor{{1, 1, 1, 7}, element::f32, std::vector{0, 0, 0, 0, 0, 0, 0}}, + "bilinear_zeros_noalign_odd_dims_outer"); + + params.emplace_back( + data_odd_dims, + grid_outer, + op::v9::GridSample::Attributes{true, GS_BILINEAR, GS_ZEROS}, + reference_tests::Tensor{{1, 1, 1, 7}, element::f32, std::vector{0, 0, 0, 0, 0, 0, 1.9880099}}, + "bilinear_zeros_align_odd_dims_outer"); + + params.emplace_back( + data_odd_dims, + grid_outer, + op::v9::GridSample::Attributes{false, GS_BILINEAR, GS_BORDER}, + reference_tests::Tensor{{1, 1, 1, 7}, element::f32, std::vector{1, 8.775, 11, 14.25, 15, 8.725, 5}}, + "bilinear_border_noalign_odd_dims_outer"); + + params.emplace_back( + data_odd_dims, + grid_outer, + op::v9::GridSample::Attributes{true, GS_BILINEAR, GS_BORDER}, + reference_tests::Tensor{{1, 1, 1, 7}, element::f32, std::vector{1, 7.85, 11, 14, 15, 9.15, 5}}, + "bilinear_border_align_odd_dims_outer"); + + params.emplace_back( + data_odd_dims, + grid_outer, + op::v9::GridSample::Attributes{false, GS_BILINEAR, GS_REFLECTION}, + reference_tests::Tensor{{1, 1, 1, 7}, + element::f32, + std::vector{5.9999995, 11.9, 2.7000031, 5.1250005, 13.75, 4.725, 4.7475}}, + "bilinear_reflection_noalign_odd_dims_outer"); + + params.emplace_back( + data_odd_dims, + grid_outer, + op::v9::GridSample::Attributes{true, GS_BILINEAR, GS_REFLECTION}, + reference_tests::Tensor{{1, 1, 1, 7}, + element::f32, + std::vector{6.7, 10.75, 3.800002, 6.25, 13.099999, 5.15, 4.4030004}}, + "bilinear_reflection_align_odd_dims_outer"); + + return params; +} + +std::vector generateBilinearParamsEvenDimensions() { + std::vector params; + reference_tests::Tensor data_even_dims{ + {1, 1, 4, 6}, + element::f32, + std::vector{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24}}; + reference_tests::Tensor grid_inner{ + {1, 1, 8, 2}, + element::f32, + std::vector{-0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, 0.5, -1, 1, 1, -1, -0.1, -0.1, 0.1, 0.1}}; + + params.emplace_back( + data_even_dims, + grid_inner, + op::v9::GridSample::Attributes{false, GS_BILINEAR, GS_ZEROS}, + reference_tests::Tensor{{1, 1, 1, 7}, element::f32, std::vector{5, 17, 8, 20, 4.75, 1.5, 11, 14}}, + "bilinear_zeros_noalign_even_dims_inner"); + + params.emplace_back(data_even_dims, + grid_inner, + op::v9::GridSample::Attributes{true, GS_BILINEAR, GS_ZEROS}, + reference_tests::Tensor{{1, 1, 1, 7}, + element::f32, + std::vector{6.75, 15.75, 9.25, 18.25, 19, 6, 11.35, 13.65}}, + "bilinear_zeros_align_even_dims_inner"); + + params.emplace_back( + data_even_dims, + grid_inner, + op::v9::GridSample::Attributes{false, GS_BILINEAR, GS_BORDER}, + reference_tests::Tensor{{1, 1, 1, 7}, element::f32, std::vector{5, 17, 8, 20, 19, 6, 11, 14}}, + "bilinear_border_noalign_even_dims_inner"); + + params.emplace_back(data_even_dims, + grid_inner, + op::v9::GridSample::Attributes{true, GS_BILINEAR, GS_BORDER}, + reference_tests::Tensor{{1, 1, 1, 7}, + element::f32, + std::vector{6.75, 15.75, 9.25, 18.25, 19, 6, 11.35, 13.65}}, + "bilinear_border_align_even_dims_inner"); + + params.emplace_back( + data_even_dims, + grid_inner, + op::v9::GridSample::Attributes{false, GS_BILINEAR, GS_REFLECTION}, + reference_tests::Tensor{{1, 1, 1, 7}, element::f32, std::vector{5, 17, 8, 20, 19, 6, 11, 14}}, + "bilinear_reflection_noalign_even_dims_inner"); + + params.emplace_back(data_even_dims, + grid_inner, + op::v9::GridSample::Attributes{true, GS_BILINEAR, GS_REFLECTION}, + reference_tests::Tensor{{1, 1, 1, 7}, + element::f32, + std::vector{6.75, 15.75, 9.25, 18.25, 19, 6, 11.35, 13.65}}, + "bilinear_reflection_align_even_dims_inner"); + + return params; +} + +std::vector generateBicubicParams() { + std::vector params; + + // clang-format off + reference_tests::Tensor data_even_dims{{1, 1, 4, 7}, element::f32, + std::vector{ 1, 1, 1, 1, 1, 1, 1, + 1, 2, 2, 2, 2, 2, 1, + 1, 2, 3, 5, 3, 2, 1, + 1, 2, 5, 9, 5, 2, 1}}; + reference_tests::Tensor grid{ + {1, 4, 4, 2}, + element::f32, + std::vector{ -0.1, -0.1, -0.1, 0.1, 0.1, -0.1, 0.1, 0.1, + -0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, 0.5, + -0.9, -0.9, -0.9, 0.9, 0.9, -0.9, 0.9, 0.9, + -1.75, 0.7, 1.33, -1.11, 0.965, 1.007, 21, 37}}; + + params.emplace_back(data_even_dims, + grid, + op::v9::GridSample::Attributes{false, GS_BICUBIC, GS_ZEROS}, + reference_tests::Tensor{{1, 1, 4, 4}, + element::f32, + std::vector{2.6663566, 3.527928, 2.6663566, 3.527928, + 1.6318359, 2.7156982, 1.6318359, 2.7156982, + 0.6378987, 0.57033366, 0.6378987, 0.57033366, + 0, -0.01507522, 0.25528803, 0 }}, + "bicubic_zeros_noalign"); + + params.emplace_back(data_even_dims, + grid, + op::v9::GridSample::Attributes{true, GS_BICUBIC, GS_ZEROS}, + reference_tests::Tensor{{1, 1, 4, 4}, + element::f32, + std::vector{ 2.7887204, 3.4506166, 2.7887204, 3.4506166, + 1.8481445, 2.7364502, 1.8481445, 2.7364502, + 1.2367951, 1.3602872, 1.2367951, 1.3602872, + 0, 0.00650583, 1.1182348, 0 }}, + "bicubic_zeros_align"); + + params.emplace_back(data_even_dims, + grid, + op::v9::GridSample::Attributes{false, GS_BICUBIC, GS_BORDER}, + reference_tests::Tensor{{1, 1, 4, 4}, + element::f32, + std::vector{ 2.6663566, 3.527928, 2.6663566, 3.527928, + 1.5380859, 2.4677734, 1.5380859, 2.4677734, + 1.0089612, 0.91871876, 1.0089612, 0.91871876, + 1, 1, 0.8902873, 1 }}, + "bicubic_border_noalign"); + + params.emplace_back(data_even_dims, + grid, + op::v9::GridSample::Attributes{true, GS_BICUBIC, GS_BORDER}, + reference_tests::Tensor{{1, 1, 4, 4}, + element::f32, + std::vector{ 2.7887204, 3.4506166, 2.7887204, 3.4506166, + 1.8129883, 2.623291, 1.8129883, 2.623291, + 1.0363026, 1.1486388, 1.0363026, 1.1486388, + 1, 1.0000064, 1.0641243, 1 }}, + "bicubic_border_align"); + + params.emplace_back(data_even_dims, + grid, + op::v9::GridSample::Attributes{false, GS_BICUBIC, GS_REFLECTION}, + reference_tests::Tensor{{1, 1, 4, 4}, + element::f32, + std::vector{ 2.6663566, 3.527928, 2.6663566, 3.527928, + 1.5380859, 2.4677734, 1.5380859, 2.4677734, + 1.0150609, 0.904375, 1.0150609, 0.904375, + 5.48851, 0.898316, 0.8237547, 0.8125 }}, + "bicubic_reflection_noalign"); + + params.emplace_back(data_even_dims, + grid, + op::v9::GridSample::Attributes{true, GS_BICUBIC, GS_REFLECTION}, + reference_tests::Tensor{{1, 1, 4, 4}, + element::f32, + std::vector{ 2.7887204, 3.4506166, 2.7887204, 3.4506166, + 1.7745361, 2.6518555, 1.7745361, 2.6518555, + 1.0085088, 1.0307077, 1.0085088, 1.0307077, + 5.5649586, 1.0553409, 1.0011607, 1 }}, + "bicubic_reflection_align"); + // clang-format on + + return params; +} + +std::vector generateBicubicBatchesParams() { + std::vector params; + + reference_tests::Tensor data{{2, 2, 4, 3}, + element::f32, + std::vector{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}}; + reference_tests::Tensor grid{{2, 2, 4, 2}, + element::f32, + std::vector{-0.1, -0.1, -0.1, 0.1, 0.1, -0.1, 0.1, 0.1, -0.5, -0.5, -0.5, + 0.5, 0.5, -0.5, 0.5, 0.5, -0.9, -0.9, -0.9, 0.9, 0.9, -0.9, + 0.9, 0.9, -1.75, 0.7, 1.33, -1.11, 0.965, 1.007, 21, 37}}; + + params.emplace_back( + data, + grid, + op::v9::GridSample::Attributes{true, GS_BICUBIC, GS_BORDER}, + reference_tests::Tensor{ + {2, 2, 2, 4}, + element::f32, + std::vector{6.0096254, 6.7048755, 6.2951245, 6.9903746, 3.4101562, 8.402344, 4.5976562, 9.589844, + 18.009624, 18.704876, 18.295124, 18.990376, 15.410156, 20.402344, 16.597656, 21.589844, + 25.415281, 33.735218, 27.26478, 35.58472, 32.884, 26.852259, 35.996872, 36., + 37.41528, 45.735218, 39.264782, 47.58472, 44.884, 38.852257, 47.996872, 48.}}, + "bicubic_border_align_batches"); + + params.emplace_back( + data, + grid, + op::v9::GridSample::Attributes{false, GS_BICUBIC, GS_REFLECTION}, + reference_tests::Tensor{ + {2, 2, 2, 4}, + element::f32, + std::vector{5.8170314, 6.7650313, 6.2349687, 7.182969, 2.4101562, 8.972656, 4.0273438, 10.589844, + 17.81703, 18.765032, 18.234968, 19.18297, 14.410156, 20.972656, 16.027344, 22.589844, + 24.356874, 34.301876, 26.698126, 36.643124, 34.304035, 26.55013, 36.74749, 36.75, + 36.356876, 46.301876, 38.698124, 48.643124, 46.304035, 38.55013, 48.74749, 48.75}}, + "bicubic_reflection_noalign_batches"); + + return params; +} + +std::vector generateGridSampleParams() { + std::vector> combo_params{generateNearestParamsOddDimensionsInnerGrids(), + generateNearestParamsOddDimensionsOuterGrids(), + generateNearestParamsEvenDimensions(), + generateBilinearParamsOddDimensionsInnerGrids(), + generateBilinearParamsOddDimensionsOuterGrids(), + generateBilinearParamsEvenDimensions(), + generateBicubicParams(), + generateBicubicBatchesParams()}; + std::vector test_params; + for (auto& params : combo_params) + std::move(params.begin(), params.end(), std::back_inserter(test_params)); + return test_params; +} +} // namespace + +TEST_P(ReferenceGridSample, LayerTest) { + Exec(); +} + +INSTANTIATE_TEST_SUITE_P(smoke, + ReferenceGridSample, + ::testing::ValuesIn(generateGridSampleParams()), + ReferenceGridSample::getTestCaseName); diff --git a/src/bindings/python/tests/__init__.py b/src/bindings/python/tests/__init__.py index 7ab5668089d..a300186a551 100644 --- a/src/bindings/python/tests/__init__.py +++ b/src/bindings/python/tests/__init__.py @@ -127,10 +127,6 @@ xfail_issue_68212 = xfail_test(reason="Unsupported reading model with bytes stre xfail_issue_78843 = xfail_test(reason="Missing reference output files for ssd mobilenet models") -xfail_issue_81974 = xfail_test(reason="RuntimeError: OpenVINO does not support the following ONNX " - "operations: GridSample, Optional, SequenceConstruct, " - "OptionalHasElement, SequenceInsert") - xfail_issue_81976 = xfail_test(reason="RuntimeError: z node not found in graph cache") xfail_issue_82038 = xfail_test(reason="ScatterElements, ScatterND, AssertionError: Result mismatch") xfail_issue_82039 = xfail_test(reason="Unsupported data type Optional, RuntimeError: [ NOT_IMPLEMENTED ] " diff --git a/src/bindings/python/tests/test_onnx/test_backend.py b/src/bindings/python/tests/test_onnx/test_backend.py index 1238d30cecd..a7234f09a8f 100644 --- a/src/bindings/python/tests/test_onnx/test_backend.py +++ b/src/bindings/python/tests/test_onnx/test_backend.py @@ -45,7 +45,6 @@ from tests import ( xfail_issue_63137, xfail_issue_63138, xfail_issue_69444, - xfail_issue_81974, xfail_issue_81976, skip_segfault, xfail_issue_82038, @@ -368,17 +367,6 @@ tests_expected_to_fail = [ "OnnxBackendNodeModelTest.test_sce_NCd1d2d3d4d5_mean_weight_cpu", # ticket: 81976 "OnnxBackendNodeModelTest.test_sce_NCd1d2d3d4d5_mean_weight_log_prob_cpu", # ticket: 81976 ), - ( - xfail_issue_81974, - "OnnxBackendNodeModelTest.test_gridsample_aligncorners_true_cpu", - "OnnxBackendNodeModelTest.test_gridsample_bicubic_cpu", - "OnnxBackendNodeModelTest.test_gridsample_bilinear_cpu", - "OnnxBackendNodeModelTest.test_gridsample_border_padding_cpu", - "OnnxBackendNodeModelTest.test_gridsample_cpu", - "OnnxBackendNodeModelTest.test_gridsample_nearest_cpu", - "OnnxBackendNodeModelTest.test_gridsample_reflection_padding_cpu", - "OnnxBackendNodeModelTest.test_gridsample_zeros_padding_cpu", - ), ( xfail_issue_81976, # SoftmaxCrossEntropyLoss operator "OnnxBackendNodeModelTest.test_sce_NCd1d2d3_none_no_weight_negative_ii_cpu", diff --git a/src/bindings/python/tests_compatibility/__init__.py b/src/bindings/python/tests_compatibility/__init__.py index 887f2195e29..03abebd5af4 100644 --- a/src/bindings/python/tests_compatibility/__init__.py +++ b/src/bindings/python/tests_compatibility/__init__.py @@ -138,10 +138,6 @@ xfail_issue_78843 = xfail_test(reason="Missing reference output files for ssd mo xfail_issue_78741 = xfail_test(reason="Cannot get dims for non-static shapes. " "Requires dynamism support enabled.") -xfail_issue_81974 = xfail_test(reason="RuntimeError: OpenVINO does not support the following ONNX " - "operations: GridSample, Optional, SequenceConstruct, " - "OptionalHasElement, SequenceInsert") - xfail_issue_81976 = xfail_test(reason="RuntimeError: z node not found in graph cache") xfail_issue_82038 = xfail_test(reason="ScatterElements, ScatterND, AssertionError: Result mismatch") xfail_issue_82039 = xfail_test(reason="Unsupported data type Optional, RuntimeError: [ NOT_IMPLEMENTED ] " diff --git a/src/bindings/python/tests_compatibility/test_onnx/test_backend.py b/src/bindings/python/tests_compatibility/test_onnx/test_backend.py index 7c5e4ff2e96..e6eb50a54eb 100644 --- a/src/bindings/python/tests_compatibility/test_onnx/test_backend.py +++ b/src/bindings/python/tests_compatibility/test_onnx/test_backend.py @@ -45,7 +45,6 @@ from tests_compatibility import ( xfail_issue_63138, xfail_issue_69444, xfail_issue_78741, - xfail_issue_81974, xfail_issue_81976, skip_segfault, xfail_issue_82038, @@ -450,17 +449,6 @@ tests_expected_to_fail = [ "OnnxBackendNodeModelTest.test_sce_NCd1d2d3d4d5_mean_weight_cpu", # ticket: 81976 "OnnxBackendNodeModelTest.test_sce_NCd1d2d3d4d5_mean_weight_log_prob_cpu", # ticket: 81976 ), - ( - xfail_issue_81974, - "OnnxBackendNodeModelTest.test_gridsample_aligncorners_true_cpu", - "OnnxBackendNodeModelTest.test_gridsample_bicubic_cpu", - "OnnxBackendNodeModelTest.test_gridsample_bilinear_cpu", - "OnnxBackendNodeModelTest.test_gridsample_border_padding_cpu", - "OnnxBackendNodeModelTest.test_gridsample_cpu", - "OnnxBackendNodeModelTest.test_gridsample_nearest_cpu", - "OnnxBackendNodeModelTest.test_gridsample_reflection_padding_cpu", - "OnnxBackendNodeModelTest.test_gridsample_zeros_padding_cpu", - ), ( xfail_issue_81976, # SoftmaxCrossEntropyLoss operator "OnnxBackendNodeModelTest.test_sce_NCd1d2d3_none_no_weight_negative_ii_cpu", diff --git a/src/core/include/openvino/op/grid_sample.hpp b/src/core/include/openvino/op/grid_sample.hpp index 4dbe261e689..03bfa685296 100644 --- a/src/core/include/openvino/op/grid_sample.hpp +++ b/src/core/include/openvino/op/grid_sample.hpp @@ -30,6 +30,12 @@ public: InterpolationMode mode = InterpolationMode::BILINEAR; // Specifies how the out-of-bounds coordinates should be handled: `zeros`, `border`, `reflection` PaddingMode padding_mode = PaddingMode::ZEROS; + + Attributes() = default; + Attributes(bool align_corners, InterpolationMode mode, PaddingMode padding_mode) + : align_corners{align_corners}, + mode{mode}, + padding_mode{padding_mode} {} }; GridSample() = default; @@ -49,6 +55,11 @@ public: return m_attributes; } + OPENVINO_SUPPRESS_DEPRECATED_START + bool evaluate(const HostTensorVector& outputs, const HostTensorVector& inputs) const override; + OPENVINO_SUPPRESS_DEPRECATED_END + bool has_evaluate() const override; + private: Attributes m_attributes = {}; }; diff --git a/src/core/reference/include/ngraph/runtime/reference/grid_sample.hpp b/src/core/reference/include/ngraph/runtime/reference/grid_sample.hpp new file mode 100644 index 00000000000..ce13658b056 --- /dev/null +++ b/src/core/reference/include/ngraph/runtime/reference/grid_sample.hpp @@ -0,0 +1,295 @@ +// Copyright (C) 2022 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include +#include +#include +#include +#include + +#include "ngraph/shape.hpp" +#include "openvino/op/grid_sample.hpp" + +namespace ngraph { +namespace runtime { +namespace reference { +namespace { + +using index_4D_t = typename std::array; + +template +using denormalize_fn_t = typename std::function; + +template +using get_padded_fn_t = typename std::function; + +template +T& get_single_value(T* buffer, const Shape& shape, const index_4D_t& index) { + // In this context below assertion is guaranteed by grid_sample(..) function. + // assert(shape.size() == index.size()); + auto sx = shape.back(); + auto offset = index.back(); + for (auto i = index.size() - 2; i > 0; --i) { + offset += index[i] * sx; + sx *= shape[i]; + } + offset += index[0] * sx; + return buffer[offset]; +} + +template +GRID_ET rescale_align(GRID_ET value, size_t range) { + return (value + 1) * (static_cast(range) - 1) / 2; +} + +template +GRID_ET rescale_noalign(GRID_ET value, size_t range) { + return ((value + 1) * static_cast(range) - 1) / 2; +} + +template +DATA_ET zeros_padding(const DATA_ET* data, + const Shape& data_shape, + const size_t n, + const size_t c, + const long y_d, + const long x_d) { + const auto H = static_cast(data_shape[2]); + const auto W = static_cast(data_shape[3]); + if (y_d < 0 || x_d < 0 || y_d >= H || x_d >= W) { + return 0; + } else { + const auto y = static_cast(y_d); + const auto x = static_cast(x_d); + return get_single_value(data, data_shape, index_4D_t{n, c, y, x}); + } +} + +template +DATA_ET border_padding(const DATA_ET* data, + const Shape& data_shape, + const size_t n, + const size_t c, + const long y_d, + const long x_d) { + const auto H = static_cast(data_shape[2]); + const auto W = static_cast(data_shape[3]); + const auto y = static_cast(std::min(std::max(y_d, 0l), H - 1)); + const auto x = static_cast(std::min(std::max(x_d, 0l), W - 1)); + return get_single_value(data, data_shape, index_4D_t{n, c, y, x}); +} + +template +DATA_ET reflection_data_no_align(const DATA_ET* data, + const Shape& data_shape, + const size_t n, + const size_t c, + long y_d, + long x_d) { + const auto H = static_cast(data_shape[2]); + const auto W = static_cast(data_shape[3]); + const auto H_2 = static_cast(data_shape[2]) * 2l; + const auto W_2 = static_cast(data_shape[3]) * 2l; + y_d = (y_d % H_2 + H_2) % H_2; + x_d = (x_d % W_2 + W_2) % W_2; + const auto y = static_cast(y_d >= H ? H_2 - 1 - y_d : y_d); + const auto x = static_cast(x_d >= W ? W_2 - 1 - x_d : x_d); + return get_single_value(data, data_shape, index_4D_t{n, c, y, x}); +} + +template +DATA_ET reflection_data_with_align(const DATA_ET* data, + const Shape& data_shape, + const size_t n, + const size_t c, + long y_d, + long x_d) { + const auto H = static_cast(data_shape[2]); + const auto W = static_cast(data_shape[3]); + const auto H_2_2 = 2 * (H - 1); + const auto W_2_2 = 2 * (W - 1); + y_d = std::abs(y_d) % H_2_2; + x_d = std::abs(x_d) % W_2_2; + const auto y = static_cast(y_d >= H ? H_2_2 - y_d : y_d); + const auto x = static_cast(x_d >= W ? W_2_2 - x_d : x_d); + return get_single_value(data, data_shape, index_4D_t{n, c, y, x}); +} + +template +DATA_ET bilinear(const DATA_ET* data, + const Shape& data_shape, + const size_t n, + const size_t c, + const GRID_ET y_n, + const GRID_ET x_n, + const get_padded_fn_t& get_padded, + const denormalize_fn_t& denormalize) { + const auto y_d = denormalize(y_n, data_shape[2]); + const auto x_d = denormalize(x_n, data_shape[3]); + const auto y_topleft = std::floor(y_d); + const auto x_topleft = std::floor(x_d); + const auto dy = y_d - y_topleft; + const auto dx = x_d - x_topleft; + const auto v00 = get_padded(data, data_shape, n, c, y_topleft, x_topleft); + const auto v01 = get_padded(data, data_shape, n, c, y_topleft, x_topleft + 1); + const auto v10 = get_padded(data, data_shape, n, c, y_topleft + 1, x_topleft); + const auto v11 = get_padded(data, data_shape, n, c, y_topleft + 1, x_topleft + 1); + + const auto q0 = (1 - dx) * v00 + dx * v01; + const auto q1 = (1 - dx) * v10 + dx * v11; + return dy * q1 + (1 - dy) * q0; +} + +template +DATA_ET nearest(const DATA_ET* data, + const Shape& data_shape, + const size_t n, + const size_t c, + const GRID_ET y_n, + const GRID_ET x_n, + const get_padded_fn_t& get_padded, + const denormalize_fn_t& denormalize) { + const auto y_nearest = std::lrint(denormalize(y_n, data_shape[2])); + const auto x_nearest = std::lrint(denormalize(x_n, data_shape[3])); + return get_padded(data, data_shape, n, c, y_nearest, x_nearest); +} + +template +using vector_4_t = typename std::array; +template +using matrix_4x4_t = typename std::array, 4>; + +// formula taken from +// https://github.com/onnx/onnx/blob/a92870cdf359297495a118184dca2eaecee4b717/onnx/backend/test/case/node/resize.py#L201-L207 +template +vector_4_t cubic_coeffs(const T r, const T A = -0.75) { + vector_4_t v; + v[0] = ((A * (r + 1) - 5 * A) * (r + 1) + 8 * A) * (r + 1) - 4 * A; + v[1] = ((A + 2) * r - (A + 3)) * r * r + 1; + v[2] = ((A + 2) * (1 - r) - (A + 3)) * (1 - r) * (1 - r) + 1; + v[3] = ((A * (2 - r) - 5 * A) * (2 - r) + 8 * A) * (2 - r) - 4 * A; + return v; +} + +template +matrix_4x4_t gather_4x4(const DATA_ET* data, + const Shape& data_shape, + const size_t n, + const size_t c, + const long y_topleft, + const long x_topleft, + const get_padded_fn_t& get_padded) { + matrix_4x4_t s; + for (int j = 0; j < 4; ++j) + for (int i = 0; i < 4; ++i) + s[j][i] = get_padded(data, data_shape, n, c, y_topleft + j, x_topleft + i); + return s; +} + +template +DATA_ET bicubic(const DATA_ET* data, + const Shape& data_shape, + const size_t n, + const size_t c, + const GRID_ET y_n, + const GRID_ET x_n, + const get_padded_fn_t& get_padded, + const denormalize_fn_t& denormalize) { + const auto y_d = denormalize(y_n, data_shape[2]); + const auto x_d = denormalize(x_n, data_shape[3]); + const auto y_topleft = std::floor(y_d); + const auto x_topleft = std::floor(x_d); + const auto dy = y_d - y_topleft; + const auto dx = x_d - x_topleft; + const auto s = gather_4x4(data, data_shape, n, c, y_topleft - 1, x_topleft - 1, get_padded); + + const auto cy = cubic_coeffs(dy); + const auto cx = cubic_coeffs(dx); + vector_4_t p; + std::transform(s.begin(), s.end(), p.begin(), [&cx](const vector_4_t& v) { + return std::inner_product(cx.begin(), cx.end(), v.begin(), static_cast(0)); + }); + return std::inner_product(cy.begin(), cy.end(), p.begin(), static_cast(0)); +} +} // namespace + +template +void grid_sample(DATA_ET* output, + const DATA_ET* data, + const GRID_ET* grid, + const Shape& data_shape, + const Shape& grid_shape, + const bool align_corners, + const ov::op::v9::GridSample::InterpolationMode interpolation_mode, + const ov::op::v9::GridSample::PaddingMode padding_mode) { + assert(data_shape.size() == 4 && grid_shape.size() == 4); + assert(data_shape[0] == grid_shape[0] and grid_shape[3] == 2); + + const auto N = data_shape[0]; + const auto C = data_shape[1]; + const auto H_out = grid_shape[1]; + const auto W_out = grid_shape[2]; + const Shape output_shape{N, C, H_out, W_out}; + + const auto prev_rounding_mode = std::fegetround(); + std::fesetround(FE_TONEAREST); + + get_padded_fn_t get_padded_fn; + switch (padding_mode) { + default: + case ov::op::v9::GridSample::PaddingMode::ZEROS: + get_padded_fn = zeros_padding; + break; + case ov::op::v9::GridSample::PaddingMode::BORDER: + get_padded_fn = border_padding; + break; + case ov::op::v9::GridSample::PaddingMode::REFLECTION: + if (align_corners) + get_padded_fn = reflection_data_with_align; + else + get_padded_fn = reflection_data_no_align; + break; + } + + denormalize_fn_t denormalize_fn; + if (align_corners) + denormalize_fn = rescale_align; + else + denormalize_fn = rescale_noalign; + + for (size_t n = 0; n < N; ++n) { + for (size_t c = 0; c < C; ++c) { + for (size_t y = 0; y < H_out; ++y) { + for (size_t x = 0; x < W_out; ++x) { + const auto y_n = get_single_value(grid, grid_shape, index_4D_t{n, y, x, 1}); + const auto x_n = get_single_value(grid, grid_shape, index_4D_t{n, y, x, 0}); + + auto& out = get_single_value(output, output_shape, index_4D_t{n, c, y, x}); + + switch (interpolation_mode) { + case ov::op::v9::GridSample::InterpolationMode::BILINEAR: + out = + bilinear(data, data_shape, n, c, y_n, x_n, get_padded_fn, denormalize_fn); + break; + case ov::op::v9::GridSample::InterpolationMode::NEAREST: + out = + nearest(data, data_shape, n, c, y_n, x_n, get_padded_fn, denormalize_fn); + break; + case ov::op::v9::GridSample::InterpolationMode::BICUBIC: + out = + bicubic(data, data_shape, n, c, y_n, x_n, get_padded_fn, denormalize_fn); + break; + } + } + } + } + } + + std::fesetround(prev_rounding_mode); +} +} // namespace reference +} // namespace runtime +} // namespace ngraph diff --git a/src/core/src/op/grid_sample.cpp b/src/core/src/op/grid_sample.cpp index e25463b37d3..7659d476d31 100644 --- a/src/core/src/op/grid_sample.cpp +++ b/src/core/src/op/grid_sample.cpp @@ -6,6 +6,8 @@ #include "grid_sample_shape_inference.hpp" #include "itt.hpp" +#include "ngraph/runtime/reference/grid_sample.hpp" +#include "ngraph/validation_util.hpp" namespace ov { op::v9::GridSample::GridSample(const Output& data, const Output& grid, const Attributes& attributes) @@ -43,6 +45,10 @@ std::ostream& operator<<(std::ostream& s, const op::v9::GridSample::Interpolatio return s << as_string(mode); } +std::ostream& operator<<(std::ostream& s, const op::v9::GridSample::PaddingMode& padding_mode) { + return s << as_string(padding_mode); +} + template <> NGRAPH_API EnumNames& EnumNames::get() { static auto enum_names = @@ -62,4 +68,70 @@ NGRAPH_API EnumNames& EnumNames +bool evaluate_exec(const HostTensorPtr& output, + const HostTensorPtr& data, + const HostTensorPtr& grid, + const op::v9::GridSample::Attributes& attributes) { + ngraph::runtime::reference::grid_sample(output->get_data_ptr(), + data->get_data_ptr(), + grid->get_data_ptr(), + data->get_shape(), + grid->get_shape(), + attributes.align_corners, + attributes.mode, + attributes.padding_mode); + return true; +} + +#define GRID_SAMPLE_TYPE_CASE(a, ...) \ + case element::Type_t::a: { \ + NGRAPH_OP_SCOPE(OV_PP_CAT3(evaluate_exec_grid_sample, _, a)); \ + rc = evaluate_exec(__VA_ARGS__); \ + } break + +template +bool evaluate(const HostTensorPtr& output, + const HostTensorPtr& data, + const HostTensorPtr& grid, + const op::v9::GridSample::Attributes& attributes) { + auto rc = true; + switch (grid->get_element_type()) { + GRID_SAMPLE_TYPE_CASE(f32, output, data, grid, attributes); + default: + rc = false; + break; + } + return rc; +} + +bool evaluate_grid_sample(const HostTensorPtr& output, + const HostTensorPtr& data, + const HostTensorPtr& grid, + const op::v9::GridSample::Attributes& attributes) { + auto rc = true; + switch (output->get_element_type()) { + NGRAPH_TYPE_CASE(evaluate_grid_sample, f32, output, data, grid, attributes); + default: + rc = false; + break; + } + return rc; +} +} // namespace + +bool op::v9::GridSample::evaluate(const HostTensorVector& outputs, const HostTensorVector& inputs) const { + NGRAPH_OP_SCOPE(v9_GridSample_evaluate); + OPENVINO_ASSERT(ngraph::validate_host_tensor_vector(inputs, 2), "Invalid GridSample input TensorVector."); + OPENVINO_ASSERT(ngraph::validate_host_tensor_vector(outputs, 1), "Invalid GridSample output TensorVector."); + + return evaluate_grid_sample(outputs[0], inputs[0], inputs[1], m_attributes); +} + +bool op::v9::GridSample::has_evaluate() const { + return get_input_element_type(0) == element::f32 && get_input_element_type(1) == element::f32; +} } // namespace ov diff --git a/src/frontends/tests/onnx/runtime/ie/unit_test.manifest b/src/frontends/tests/onnx/runtime/ie/unit_test.manifest index c8d21501766..f839dcf5fa3 100644 --- a/src/frontends/tests/onnx/runtime/ie/unit_test.manifest +++ b/src/frontends/tests/onnx/runtime/ie/unit_test.manifest @@ -425,5 +425,3 @@ IE_CPU.onnx_softmax_crossentropy_loss_mean # Cannot find blob with name: Y IE_CPU.onnx_bool_init_and - -onnx_grid_sample diff --git a/src/frontends/tests/onnx/runtime/interpreter/unit_test.manifest b/src/frontends/tests/onnx/runtime/interpreter/unit_test.manifest index bf427ce8257..53819b14a8d 100644 --- a/src/frontends/tests/onnx/runtime/interpreter/unit_test.manifest +++ b/src/frontends/tests/onnx/runtime/interpreter/unit_test.manifest @@ -82,5 +82,3 @@ onnx_clip_no_min_no_max_int64 # z node not found in graph cache - ticket: 81976 INTERPRETER.onnx_expand_context_dependent_function INTERPRETER.onnx_softmax_crossentropy_loss_mean - -onnx_grid_sample