[GPU Enable dynamism for grid_sample (#18953)
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2022 Intel Corporation
|
||||
// Copyright (C) 2022-2023 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "grid_sample_inst.hpp"
|
||||
#include "json_object.h"
|
||||
#include "primitive_type_base.h"
|
||||
#include "grid_sample_shape_inference.hpp"
|
||||
|
||||
namespace cldnn {
|
||||
GPU_DEFINE_PRIMITIVE_TYPE_ID(grid_sample)
|
||||
@@ -25,6 +26,25 @@ layout grid_sample_inst::calc_output_layout(const grid_sample_node& node, const
|
||||
return {data_layout.data_type, data_layout.format, tensor(data_layout.format, {N, C, H, W})};
|
||||
}
|
||||
|
||||
template<typename ShapeType>
|
||||
std::vector<layout> grid_sample_inst::calc_output_layouts(grid_sample_node const& /*node*/, const kernel_impl_params& impl_param) {
|
||||
auto prim = impl_param.typed_desc<grid_sample>();
|
||||
auto input0_layout = impl_param.get_input_layout(0);
|
||||
auto input1_layout = impl_param.get_input_layout(1);
|
||||
|
||||
ov::op::v9::GridSample op;
|
||||
std::vector<ShapeType> input_shapes = {
|
||||
input0_layout.get<ShapeType>(),
|
||||
input1_layout.get<ShapeType>()
|
||||
};
|
||||
|
||||
std::vector<ShapeType> output_shapes = ov::op::v9::shape_infer(&op, input_shapes);
|
||||
|
||||
return { layout{output_shapes[0], input0_layout.data_type, input0_layout.format} };
|
||||
}
|
||||
|
||||
template std::vector<layout> grid_sample_inst::calc_output_layouts<ov::PartialShape>(grid_sample_node const& node, const kernel_impl_params& impl_param);
|
||||
|
||||
std::string grid_sample_inst::to_string(const grid_sample_node& node) {
|
||||
auto primitive = node.get_primitive();
|
||||
json_composite grid_sample_info;
|
||||
@@ -42,4 +62,5 @@ std::string grid_sample_inst::to_string(const grid_sample_node& node) {
|
||||
return primitive_description.str();
|
||||
}
|
||||
|
||||
grid_sample_inst::typed_primitive_inst(network& network, grid_sample_node const& node) : parent(network, node) {}
|
||||
} // namespace cldnn
|
||||
|
||||
@@ -8,17 +8,31 @@
|
||||
#include "primitive_inst.h"
|
||||
|
||||
namespace cldnn {
|
||||
template <>
|
||||
struct typed_program_node<grid_sample> : public typed_program_node_base<grid_sample> {
|
||||
using parent = typed_program_node_base<grid_sample>;
|
||||
|
||||
public:
|
||||
using parent::parent;
|
||||
|
||||
program_node& input(size_t idx = 0) const { return get_dependency(idx); }
|
||||
std::vector<size_t> get_shape_infer_dependencies() const override { return {}; }
|
||||
};
|
||||
|
||||
using grid_sample_node = typed_program_node<grid_sample>;
|
||||
|
||||
template <>
|
||||
class typed_primitive_inst<grid_sample> : public typed_primitive_inst_base<grid_sample> {
|
||||
public:
|
||||
using parent = typed_primitive_inst_base<grid_sample>;
|
||||
using parent::parent;
|
||||
|
||||
public:
|
||||
template<typename ShapeType>
|
||||
static std::vector<layout> calc_output_layouts(grid_sample_node const& /*node*/, const kernel_impl_params& impl_param);
|
||||
static layout calc_output_layout(const grid_sample_node& node, const kernel_impl_params& impl_param);
|
||||
static std::string to_string(const grid_sample_node& node);
|
||||
|
||||
typed_primitive_inst(network& network, grid_sample_node const& node);
|
||||
};
|
||||
|
||||
using grid_sample_inst = typed_primitive_inst<grid_sample>;
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
// Copyright (C) 2023 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#include "shared_test_classes/single_layer/select.hpp"
|
||||
#include "shared_test_classes/base/ov_subgraph.hpp"
|
||||
#include "ie_precision.hpp"
|
||||
#include "ngraph_functions/builders.hpp"
|
||||
#include <string>
|
||||
#include <common_test_utils/ov_tensor_utils.hpp>
|
||||
|
||||
using namespace ngraph;
|
||||
using namespace InferenceEngine;
|
||||
using namespace ov::test;
|
||||
using ov::op::v9::GridSample;
|
||||
|
||||
namespace GPULayerTestsDefinitions {
|
||||
|
||||
typedef std::tuple<
|
||||
std::vector<InputShape>, // Input shapes
|
||||
GridSample::InterpolationMode, // Interpolation mode
|
||||
GridSample::PaddingMode, // Padding mode
|
||||
bool, // Align corners
|
||||
ElementType, // Data precision
|
||||
ElementType // Grid precision
|
||||
> GridSampleLayerTestGPUParams;
|
||||
|
||||
class GridSampleLayerTestGPU : public testing::WithParamInterface<GridSampleLayerTestGPUParams>,
|
||||
virtual public SubgraphBaseTest {
|
||||
public:
|
||||
static std::string getTestCaseName(testing::TestParamInfo<GridSampleLayerTestGPUParams> obj) {
|
||||
std::vector<InputShape> inputShapes;
|
||||
GridSample::InterpolationMode interpolateMode;
|
||||
GridSample::PaddingMode paddingMode;
|
||||
bool alignCorners;
|
||||
ElementType dataPrecision, gridPrecision;
|
||||
|
||||
std::tie(inputShapes, interpolateMode, paddingMode, alignCorners, dataPrecision, gridPrecision) = obj.param;
|
||||
|
||||
std::ostringstream result;
|
||||
result << "IS=(";
|
||||
for (size_t i = 0lu; i < inputShapes.size(); i++) {
|
||||
result << ov::test::utils::partialShape2str({inputShapes[i].first}) << (i < inputShapes.size() - 1lu ? "_" : "");
|
||||
}
|
||||
result << ")_TS=";
|
||||
for (size_t i = 0lu; i < inputShapes.front().second.size(); i++) {
|
||||
result << "{";
|
||||
for (size_t j = 0lu; j < inputShapes.size(); j++) {
|
||||
result << ov::test::utils::vec2str(inputShapes[j].second[i]) << (j < inputShapes.size() - 1lu ? "_" : "");
|
||||
}
|
||||
result << "}_";
|
||||
}
|
||||
|
||||
result << "interpMode=" << (interpolateMode == GridSample::InterpolationMode::BILINEAR ? "BILINEAR" :
|
||||
interpolateMode == GridSample::InterpolationMode::BICUBIC ? "BICUBIC" : "NEAREST") << "_";
|
||||
result << "padMode=" << (paddingMode == GridSample::PaddingMode::ZEROS ? "ZEROS" :
|
||||
paddingMode == GridSample::PaddingMode::BORDER ? "BORDER" : "REFLECTION") << "_";
|
||||
result << "alignCorners=" << (alignCorners ? "True" : "False") << "_";
|
||||
result << "dataPrc=" << dataPrecision << "_";
|
||||
result << "gridPrc=" << gridPrecision;
|
||||
|
||||
return result.str();
|
||||
}
|
||||
|
||||
protected:
|
||||
void SetUp() override {
|
||||
abs_threshold = 0.0005;
|
||||
std::vector<InputShape> inputShapes;
|
||||
GridSample::InterpolationMode interpolateMode;
|
||||
GridSample::PaddingMode paddingMode;
|
||||
bool alignCorners;
|
||||
ElementType dataPrecision, gridPrecision;
|
||||
|
||||
std::tie(inputShapes, interpolateMode, paddingMode, alignCorners, dataPrecision, gridPrecision) = this->GetParam();
|
||||
targetDevice = ov::test::utils::DEVICE_GPU;
|
||||
init_input_shapes(inputShapes);
|
||||
|
||||
if (gridPrecision == ov::element::bf16) {
|
||||
rel_threshold = 0.01f;
|
||||
}
|
||||
|
||||
auto params = ngraph::builder::makeDynamicParams({dataPrecision, gridPrecision}, inputDynamicShapes);
|
||||
params[0]->set_friendly_name("data");
|
||||
params[1]->set_friendly_name("grid");
|
||||
auto paramOuts = ngraph::helpers::convert2OutputVector(ngraph::helpers::castOps2Nodes<ov::op::v0::Parameter>(params));
|
||||
GridSample::Attributes attributes = {alignCorners, interpolateMode, paddingMode};
|
||||
auto gridSampleNode = std::make_shared<GridSample>(paramOuts[0], paramOuts[1], attributes);
|
||||
|
||||
ngraph::ResultVector results;
|
||||
for (size_t i = 0; i < gridSampleNode->get_output_size(); i++) {
|
||||
results.push_back(std::make_shared<ngraph::opset1::Result>(gridSampleNode->output(i)));
|
||||
}
|
||||
|
||||
function = std::make_shared<ngraph::Function>(results, params, "GridSampleGPU");
|
||||
}
|
||||
|
||||
void generate_inputs(const std::vector<ov::Shape>& targetInputStaticShapes) override {
|
||||
inputs.clear();
|
||||
const auto& funcInputs = function->inputs();
|
||||
|
||||
for (size_t i = 0; i < funcInputs.size(); ++i) {
|
||||
const auto& funcInput = funcInputs[i];
|
||||
ov::runtime::Tensor tensor;
|
||||
|
||||
if (funcInput.get_node()->get_friendly_name() == "data") {
|
||||
int32_t range = std::accumulate(targetInputStaticShapes[0].begin(), targetInputStaticShapes[0].end(), 1u, std::multiplies<uint32_t>());
|
||||
tensor = utils::create_and_fill_tensor(
|
||||
funcInput.get_element_type(), targetInputStaticShapes[0], range, -range / 2, 1);
|
||||
} else if (funcInput.get_node()->get_friendly_name() == "grid") {
|
||||
int32_t range = std::max(targetInputStaticShapes[0][2], targetInputStaticShapes[0][3]) + 2;
|
||||
int32_t resolution = range / 2;
|
||||
tensor = utils::create_and_fill_tensor(
|
||||
funcInput.get_element_type(), targetInputStaticShapes[1], range, -1, resolution == 0 ? 1 : resolution);
|
||||
}
|
||||
inputs.insert({funcInput.get_node_shared_ptr(), tensor});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TEST_P(GridSampleLayerTestGPU, CompareWithRefs) {
|
||||
SKIP_IF_CURRENT_TEST_IS_DISABLED()
|
||||
run();
|
||||
}
|
||||
|
||||
std::vector<GridSample::InterpolationMode> interpolateMode {
|
||||
GridSample::InterpolationMode::BILINEAR,
|
||||
GridSample::InterpolationMode::BICUBIC,
|
||||
GridSample::InterpolationMode::NEAREST };
|
||||
|
||||
std::vector<GridSample::PaddingMode> paddingMode {
|
||||
GridSample::PaddingMode::ZEROS,
|
||||
GridSample::PaddingMode::BORDER,
|
||||
GridSample::PaddingMode::REFLECTION };
|
||||
|
||||
std::vector<bool> alignCorners { true, false };
|
||||
|
||||
|
||||
const std::vector<std::vector<InputShape>> dynamicInSapes = {
|
||||
{
|
||||
{
|
||||
{ 3, -1, -1, -1 }, { {3, 2, 1, 23}, {3, 4, 3, 8}, {3, 6, 5, 5} }
|
||||
},
|
||||
{
|
||||
{ -1, -1, -1, 2 }, { {3, 31, 1, 2}, {3, 6, 4, 2}, {3, 23, 1, 2} }
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(smoke_dynamic, GridSampleLayerTestGPU,
|
||||
::testing::Combine(
|
||||
::testing::ValuesIn(dynamicInSapes),
|
||||
::testing::ValuesIn(interpolateMode),
|
||||
::testing::ValuesIn(paddingMode),
|
||||
::testing::ValuesIn(alignCorners),
|
||||
::testing::Values(ElementType::f32),
|
||||
::testing::Values(ElementType::f32)),
|
||||
GridSampleLayerTestGPU::getTestCaseName);
|
||||
|
||||
} // namespace GPULayerTestsDefinitions
|
||||
@@ -0,0 +1,81 @@
|
||||
// Copyright (C) 2023 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#include "test_utils.h"
|
||||
|
||||
#include <intel_gpu/primitives/input_layout.hpp>
|
||||
#include <intel_gpu/primitives/grid_sample.hpp>
|
||||
#include <intel_gpu/primitives/data.hpp>
|
||||
|
||||
#include "grid_sample_inst.hpp"
|
||||
|
||||
#include "program_wrapper.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace cldnn;
|
||||
using namespace ::tests;
|
||||
|
||||
namespace shape_infer_tests {
|
||||
|
||||
struct grid_sample_test_params {
|
||||
layout input0_layout; // data
|
||||
layout input1_layout; // grid
|
||||
bool align_corners;
|
||||
GridSampleOp::InterpolationMode mode; // BILINEAR, BICUBIC, NEAREST
|
||||
GridSampleOp::PaddingMode padding_mode; // ZEROS, BORDER, REFLECTION
|
||||
layout expected_layout;
|
||||
};
|
||||
|
||||
class grid_sample_test : public testing::TestWithParam<grid_sample_test_params> { };
|
||||
|
||||
TEST_P(grid_sample_test, shape_infer) {
|
||||
auto p = GetParam();
|
||||
const GridSampleOp::Attributes attributes(p.align_corners, p.mode, p.padding_mode);
|
||||
|
||||
auto& engine = get_test_engine();
|
||||
auto input0_prim = std::make_shared<input_layout>("data", p.input0_layout);
|
||||
auto input1_prim = std::make_shared<input_layout>("grid", p.input1_layout);
|
||||
|
||||
std::vector<input_info> inputs;
|
||||
inputs.push_back(input_info("data"));
|
||||
inputs.push_back(input_info("grid"));
|
||||
auto grid_sample_prim = std::make_shared<grid_sample>("grid_sample_output", inputs, attributes);
|
||||
|
||||
cldnn::program prog(engine);
|
||||
auto& input0_node = prog.get_or_create(input0_prim);
|
||||
auto& input1_node = prog.get_or_create(input1_prim);
|
||||
auto& grid_sample_node = prog.get_or_create(grid_sample_prim);
|
||||
|
||||
program_wrapper::add_connection(prog, input0_node, grid_sample_node);
|
||||
program_wrapper::add_connection(prog, input1_node, grid_sample_node);
|
||||
|
||||
auto res = grid_sample_inst::calc_output_layouts<ov::PartialShape>(grid_sample_node, *grid_sample_node.get_kernel_impl_params());
|
||||
|
||||
ASSERT_EQ(res.size(), 1);
|
||||
ASSERT_EQ(res[0], p.expected_layout);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(smoke, grid_sample_test,
|
||||
testing::ValuesIn(std::vector<grid_sample_test_params>{
|
||||
{
|
||||
layout{{1, -1, -1, -1}, data_types::f32, format::bfyx},
|
||||
layout{{1, -1, -1, 2}, data_types::f32, format::bfyx},
|
||||
false,
|
||||
GridSampleOp::InterpolationMode::BILINEAR,
|
||||
GridSampleOp::PaddingMode::ZEROS,
|
||||
layout{{1, -1, -1, -1}, data_types::f32, format::bfyx}
|
||||
},
|
||||
{
|
||||
layout{{1, 2, 3, 4}, data_types::f32, format::bfyx},
|
||||
layout{{1, 5, 6, 2}, data_types::f32, format::bfyx},
|
||||
false,
|
||||
GridSampleOp::InterpolationMode::BICUBIC,
|
||||
GridSampleOp::PaddingMode::BORDER,
|
||||
layout{{1, 2, 5, 6}, data_types::f32, format::bfyx}
|
||||
},
|
||||
}));
|
||||
|
||||
} // namespace shape_infer_tests
|
||||
@@ -14,7 +14,7 @@
|
||||
#endif
|
||||
|
||||
using namespace cldnn;
|
||||
using namespace tests;
|
||||
using namespace ::tests;
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -701,4 +701,84 @@ INSTANTIATE_TEST_SUITE_P(smoke_grid_sample_gpu_test_FLOAT16_FLOAT16_cached,
|
||||
testing::Values(true)),
|
||||
grid_sample_gpu_test_FLOAT16_FLOAT16::PrintToStringParamName);
|
||||
#endif
|
||||
|
||||
class grid_sample_gpu_dynamic : public ::testing::TestWithParam<grid_sample_test_params<float, float>> {};
|
||||
TEST_P(grid_sample_gpu_dynamic, basic) {
|
||||
bool is_caching_test;
|
||||
format::type fmt;
|
||||
grid_sample_test_inputs<float, float> p;
|
||||
std::tie(p, fmt, is_caching_test) = testing::TestWithParam<grid_sample_test_params<float, float>>::GetParam();
|
||||
|
||||
auto& engine = get_test_engine();
|
||||
const auto data_data_type = data_types::f32;
|
||||
const auto grid_data_type = data_types::f32;
|
||||
const auto plane_format = format::bfyx;
|
||||
|
||||
auto in0_layout = layout{{-1, -1, -1, -1}, data_data_type, fmt};
|
||||
auto in1_layout = layout{{-1, -1, -1, 2}, grid_data_type, fmt};
|
||||
|
||||
ov::Shape in0_shape = ov::Shape();
|
||||
ov::Shape in1_shape = ov::Shape();
|
||||
for (auto shape : p.data_shape) {
|
||||
in0_shape.push_back(shape);
|
||||
}
|
||||
for (auto shape : p.grid_shape) {
|
||||
in1_shape.push_back(shape);
|
||||
}
|
||||
auto input0 = engine.allocate_memory(layout{ov::PartialShape(in0_shape), data_data_type, fmt});
|
||||
auto input1 = engine.allocate_memory(layout{ov::PartialShape(in1_shape), grid_data_type, fmt});
|
||||
|
||||
set_values(input0, p.data);
|
||||
set_values(input1, p.grid);
|
||||
|
||||
topology topology;
|
||||
topology.add(input_layout("data", in0_layout));
|
||||
topology.add(input_layout("grid", in1_layout));
|
||||
topology.add(reorder("reordered_data", input_info("data"), fmt, data_data_type));
|
||||
topology.add(reorder("reordered_grid", input_info("grid"), fmt, grid_data_type));
|
||||
topology.add(grid_sample("grid_sample", { input_info("reordered_data"), input_info("reordered_grid") }, p.attributes));
|
||||
topology.add(reorder("plane_grid_sample", input_info("grid_sample"), plane_format, data_data_type));
|
||||
|
||||
ExecutionConfig config = get_test_default_config(engine);
|
||||
config.set_property(ov::intel_gpu::optimize_data(true));
|
||||
config.set_property(ov::intel_gpu::allow_new_shape_infer(true));
|
||||
|
||||
network network(engine, topology, config);
|
||||
network.set_input_data("data", input0);
|
||||
network.set_input_data("grid", input1);
|
||||
|
||||
const auto outputs = network.execute();
|
||||
auto output = outputs.at("plane_grid_sample").get_memory();
|
||||
cldnn::mem_lock<float> output_ptr(output, get_test_stream());
|
||||
|
||||
ASSERT_EQ(output_ptr.size(), p.expected_values.size());
|
||||
for (size_t i = 0; i < output_ptr.size(); ++i) {
|
||||
ASSERT_NEAR(p.expected_values[i], output_ptr[i], getError<float>());
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<format::type> dynamic_layout_formats = {
|
||||
format::bfyx
|
||||
};
|
||||
|
||||
std::vector<grid_sample_test_inputs<float, float>> dynamicGridSampleTestInputs() {
|
||||
return {
|
||||
{
|
||||
{1, 1, 3, 5},
|
||||
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
|
||||
{1, 1, 7, 2},
|
||||
{-10.1f, -9.7f, -7.55f, 0.37f, -77.f, 11.56f, 0.5f, 2.55f, 1.7f, 1.1f, 3.f, -0.17f, 1.301f, -1.001f},
|
||||
{true, GridSampleOp::InterpolationMode::NEAREST, GridSampleOp::PaddingMode::BORDER},
|
||||
{1, 6, 11, 14, 15, 10, 5},
|
||||
"nearest_border_align_odd_dims_outer"
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(smoke_grid_sample_gpu_dynamic_test,
|
||||
grid_sample_gpu_dynamic,
|
||||
testing::Combine(testing::ValuesIn(dynamicGridSampleTestInputs()),
|
||||
testing::ValuesIn(dynamic_layout_formats),
|
||||
testing::Values(false)));
|
||||
|
||||
} // namespace
|
||||
|
||||
Reference in New Issue
Block a user