[GPU Enable dynamism for grid_sample (#18953)

This commit is contained in:
Kelvin Choi
2023-08-04 03:09:07 +09:00
committed by GitHub
parent bdab260131
commit 561f71d86c
5 changed files with 358 additions and 3 deletions

View File

@@ -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

View File

@@ -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>;

View File

@@ -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

View File

@@ -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

View File

@@ -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