[GPU] Enable tile with dynamic input (#16364)

This commit is contained in:
Vladimir Paramuzov authored and GitHub committed 2023-03-20 12:49:35 +04:00
1 parent 3f06a9b6fb
commit a46fc47e6a
4 files changed
+286 -40

No files matched your search

+13 -7
View File
@@ -51,13 +51,19 @@ std::vector<layout> tile_inst::calc_output_layouts(tile_node const& /*node*/, co
};
auto& constant_mem = impl_param.memory_deps;
if (constant_mem.count(1)) {
auto repeats_mem = constant_mem.at(1);
cldnn::mem_lock<uint8_t, mem_lock_type::read> repeats_lock(repeats_mem, impl_param.prog->get_stream());
const auto& layout = repeats_mem->get_layout();
const auto repeats_tensor =
ov::Tensor(data_type_to_element_type(layout.data_type), layout.get_shape(), repeats_lock.data());
output_shapes = ov::op::v0::shape_infer(&op, input_shapes, {{1, repeats_tensor}});
if (desc->input_size() == 2) {
if (constant_mem.count(1)) {
auto repeats_mem = constant_mem.at(1);
cldnn::mem_lock<uint8_t, mem_lock_type::read> repeats_lock(repeats_mem, impl_param.prog->get_stream());
const auto& layout = repeats_mem->get_layout();
const auto repeats_tensor =
ov::Tensor(data_type_to_element_type(layout.data_type), layout.get_shape(), repeats_lock.data());
output_shapes = ov::op::v0::shape_infer(&op, input_shapes, {{1, repeats_tensor}});
} else if (repeats_shape.size() > 0 && repeats_shape[0].is_static()) {
output_shapes = { ov::PartialShape::dynamic(std::max<size_t>(input_shapes[0].size(), repeats_shape[0].get_length())) };
} else {
output_shapes = { ov::PartialShape::dynamic() };
}
} else {
auto repeats_data = desc->repeats;
const auto repeats_tensor =
+31 -32
View File
@@ -17,43 +17,42 @@ static void CreateTileOp(Program& p, const std::shared_ptr<ngraph::op::v0::Tile>
validate_inputs_count(op, {2});
auto inputs = p.GetInputInfo(op);
std::string layerName = layer_type_name_ID(op);
if (auto repeats_const = std::dynamic_pointer_cast<ngraph::op::Constant>(op->get_input_node_shared_ptr(1))) {
std::vector<int64_t> repeats = repeats_const->cast_vector<int64_t>();
auto repeatsNode = std::dynamic_pointer_cast<ngraph::op::Constant>(op->get_input_node_shared_ptr(1));
if (!repeatsNode)
IE_THROW() << "Unsupported parameter nodes type in " << op->get_friendly_name() <<
" (" << op->get_type_name() << ")";
std::vector<int64_t> repeats = repeatsNode->cast_vector<int64_t>();
// TODO: Remove code below once new shape infer is enabled
if (!op->is_dynamic() && !p.use_new_shape_infer()) {
size_t rank = op->get_input_shape(0).size();
int64_t defaultSize = 1;
for (size_t i = repeats.size(); i < rank; ++i) {
repeats.insert(repeats.begin(), defaultSize);
}
// TODO: Remove code below once new shape infer is enabled
if (!op->is_dynamic() && !p.use_new_shape_infer()) {
size_t rank = op->get_input_shape(0).size();
int64_t defaultSize = 1;
for (size_t i = repeats.size(); i < rank; ++i) {
repeats.insert(repeats.begin(), defaultSize);
if (repeats.size() > rank) {
std::string reshapeName = layerName + "_reshape";
auto inputDims = op->get_input_shape(0);
// Extend input dimensions to the same size as repeats dimensions by prepending ones
inputDims.insert(inputDims.begin(), repeats.size() - rank, defaultSize);
auto targetShape = tensor_from_dims(inputDims);
auto reshapePrim = cldnn::reshape(reshapeName, inputs[0], targetShape);
p.add_primitive(*op, reshapePrim);
inputs[0] = cldnn::input_info(reshapeName);
}
}
if (repeats.size() > rank) {
std::string reshapeName = layerName + "_reshape";
auto inputDims = op->get_input_shape(0);
// Extend input dimensions to the same size as repeats dimensions by prepending ones
inputDims.insert(inputDims.begin(), repeats.size() - rank, defaultSize);
auto targetShape = tensor_from_dims(inputDims);
auto reshapePrim = cldnn::reshape(reshapeName, inputs[0], targetShape);
p.add_primitive(*op, reshapePrim);
inputs[0] = cldnn::input_info(reshapeName);
}
p.add_primitive(*op, cldnn::tile(layerName,
inputs[0],
repeats));
} else {
p.add_primitive(*op, cldnn::tile(layerName,
inputs[0],
inputs[1]));
}
auto tilePrim = cldnn::tile(layerName,
inputs[0],
repeats);
p.add_primitive(*op, tilePrim);
}
REGISTER_FACTORY_IMPL(v0, Tile);
@@ -50,9 +50,16 @@ TEST_P(tile_test_two_inputs, shape_infer) {
program_wrapper::add_connection(prog, repeats_node, tile_node);
auto params = tile_node.get_kernel_impl_params();
params->memory_deps = {{1, repeats_mem}};
auto res = tile_inst::calc_output_layouts<ov::PartialShape>(tile_node, *params);
auto expected_layout_dyn = p.expected_layout;
expected_layout_dyn.set_partial_shape(ov::PartialShape::dynamic(expected_layout_dyn.get_partial_shape().size()));
ASSERT_EQ(res.size(), 1);
ASSERT_EQ(res[0], expected_layout_dyn);
params->memory_deps = {{1, repeats_mem}};
res = tile_inst::calc_output_layouts<ov::PartialShape>(tile_node, *params);
ASSERT_EQ(res.size(), 1);
ASSERT_EQ(res[0], p.expected_layout);
}
@@ -0,0 +1,234 @@
// Copyright (C) 2023 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <tuple>
#include <string>
#include <vector>
#include <memory>
#include "ngraph_functions/utils/ngraph_helpers.hpp"
#include "ngraph_functions/builders.hpp"
#include "shared_test_classes/base/ov_subgraph.hpp"
#include "shared_test_classes/single_layer/tile.hpp"
#include "common_test_utils/test_constants.hpp"
#include "common_test_utils/ov_tensor_utils.hpp"
using namespace InferenceEngine;
using namespace ov::test;
namespace GPULayerTestsDefinitions {
using TileLayerTestParamsSet = typename std::tuple<
std::vector<ov::test::InputShape>, // Input shapes
std::vector<int64_t>, // Repeats
ov::element::Type_t, // Network precision
bool, // Is Repeats input constant
std::string>; // Device name
class TileLayerGPUTest : public testing::WithParamInterface<TileLayerTestParamsSet>,
public ov::test::SubgraphBaseTest {
public:
static std::string getTestCaseName(testing::TestParamInfo<TileLayerTestParamsSet> obj) {
TileLayerTestParamsSet basicParamsSet = obj.param;
std::vector<ov::test::InputShape> inputShapes;
std::vector<int64_t> repeats;
ov::element::Type_t netPrecision;
bool isRepeatsConst;
std::string deviceName;
std::tie(inputShapes, repeats, netPrecision, isRepeatsConst, deviceName) = basicParamsSet;
std::ostringstream result;
result << "IS=(";
for (const auto& shape : inputShapes) {
result << CommonTestUtils::partialShape2str({shape.first}) << "_";
}
result << ")_TS=(";
for (const auto& shape : inputShapes) {
for (const auto& item : shape.second) {
result << CommonTestUtils::vec2str(item) << "_";
}
}
result << "Repeats=" << CommonTestUtils::vec2str(repeats) << "_";
result << "netPrec=" << netPrecision << "_";
result << "constRepeats=" << (isRepeatsConst ? "True" : "False") << "_";
result << "trgDev=" << deviceName;
return result.str();
}
protected:
void SetUp() override {
TileLayerTestParamsSet basicParamsSet = this->GetParam();
std::vector<ov::test::InputShape> inputShapes;
ov::element::Type_t netPrecision;
bool isRepeatsConst;
std::tie(inputShapes, repeatsData, netPrecision, isRepeatsConst, targetDevice) = basicParamsSet;
if (inputShapes.front().first.rank() != 0) {
inputDynamicShapes.push_back(inputShapes.front().first);
if (!isRepeatsConst) {
inputDynamicShapes.push_back({ static_cast<int64_t>(repeatsData.size()) });
}
}
const size_t targetStaticShapeSize = inputShapes.front().second.size();
targetStaticShapes.resize(targetStaticShapeSize);
for (size_t i = 0lu; i < targetStaticShapeSize; ++i) {
targetStaticShapes[i].push_back(inputShapes.front().second[i]);
if (!isRepeatsConst)
targetStaticShapes[i].push_back({ repeatsData.size() });
}
ov::ParameterVector functionParams;
if (inputDynamicShapes.empty()) {
functionParams.push_back(std::make_shared<ov::op::v0::Parameter>(netPrecision, targetStaticShapes.front().front()));
} else {
functionParams.push_back(std::make_shared<ov::op::v0::Parameter>(netPrecision, inputDynamicShapes.front()));
if (!isRepeatsConst) {
functionParams.push_back(std::make_shared<ov::op::v0::Parameter>(ov::element::i64, inputDynamicShapes[1]));
functionParams.back()->set_friendly_name("repeats");
}
}
functionParams.front()->set_friendly_name("data");
auto paramOuts = ngraph::helpers::convert2OutputVector(ngraph::helpers::castOps2Nodes<ov::op::v0::Parameter>(functionParams));
std::shared_ptr<ov::Node> tileNode;
if (isRepeatsConst) {
tileNode = std::make_shared<ov::op::v0::Tile>(paramOuts[0],
ov::op::v0::Constant::create(ov::element::i64, { repeatsData.size() }, repeatsData));
} else {
tileNode = std::make_shared<ov::op::v0::Tile>(paramOuts[0], paramOuts[1]);
}
ngraph::ResultVector results;
for (size_t i = 0; i < tileNode->get_output_size(); i++) {
results.push_back(std::make_shared<ngraph::opset4::Result>(tileNode->output(i)));
}
function = std::make_shared<ngraph::Function>(results, functionParams, "Tile");
}
void generate_inputs(const std::vector<ngraph::Shape>& targetInputStaticShapes) override {
inputs.clear();
const auto& funcInputs = function->inputs();
for (size_t i = 0lu; i < funcInputs.size(); i++) {
const auto& funcInput = funcInputs[i];
ov::Tensor tensor;
if (funcInput.get_node()->get_friendly_name() == "repeats") {
tensor = ov::Tensor{ov::element::i64, targetInputStaticShapes[i]};
auto data = tensor.data<ov::element_type_traits<ov::element::i64>::value_type>();
for (size_t i = 0lu; i < repeatsData.size(); i++) {
data[i] = repeatsData[i];
}
} else {
if (funcInput.get_element_type().is_real()) {
tensor = ov::test::utils::create_and_fill_tensor(
funcInput.get_element_type(), targetInputStaticShapes[i], 10, 0, 1000);
} else {
tensor = ov::test::utils::create_and_fill_tensor(funcInput.get_element_type(), targetInputStaticShapes[i]);
}
}
inputs.insert({funcInput.get_node_shared_ptr(), tensor});
}
}
std::vector<int64_t> repeatsData;
};
TEST_P(TileLayerGPUTest, CompareWithRefs) {
run();
}
namespace {
const std::vector<ov::element::Type_t> netPrecisions = {
ov::element::f32,
ov::element::f16,
};
const std::vector<std::vector<ov::test::InputShape>> dynamicInputShapes4D = {
{
{ // Origin dynamic shapes
{ov::Dimension(1, 20), ov::Dimension(10, 20), ov::Dimension(1, 20), ov::Dimension(1, 20)},
{ // Dynamic shapes instances
{2, 16, 3, 4},
{1, 16, 1, 1},
{1, 16, 2, 3}
}
}
},
{
{ // Origin dynamic shapes
{-1, -1, -1, -1},
{ // Dynamic shapes instances
{3, 15, 5, 7},
{4, 55, 8, 24}
}
}
}
};
const std::vector<std::vector<ov::test::InputShape>> dynamicInputShapes5D = {
{
{ // Origin dynamic shapes
{ov::Dimension(1, 20), ov::Dimension(1, 20), ov::Dimension(1, 20), ov::Dimension(1, 20), ov::Dimension(1, 70)},
{ // Dynamic shapes instances
{2, 16, 2, 3, 4},
{1, 16, 8, 5, 4},
{8, 1, 2, 3, 64}
}
}
},
{
{ // Origin dynamic shapes
{-1, -1, -1, -1, -1},
{ // Dynamic shapes instances
{2, 16, 2, 3, 4},
{1, 16, 8, 5, 4},
{8, 1, 2, 3, 64}
}
}
}
};
const std::vector<std::vector<int64_t>> repeats4D = {
{2, 3},
{1, 2, 3},
{1, 1, 1, 1},
{1, 1, 2, 3},
{1, 2, 1, 3},
{2, 1, 1, 1},
{2, 3, 1, 1}
};
const std::vector<std::vector<int64_t>> repeats5D = {
{1, 2, 3},
{1, 1, 2, 3},
{1, 1, 1, 2, 3},
{1, 2, 1, 1, 3},
{2, 1, 1, 1, 1},
{2, 3, 1, 1, 1}
};
INSTANTIATE_TEST_CASE_P(DynamicShape4D, TileLayerGPUTest,
::testing::Combine(
::testing::ValuesIn(dynamicInputShapes4D),
::testing::ValuesIn(repeats4D),
::testing::ValuesIn(netPrecisions),
::testing::Values(true, false),
::testing::Values(CommonTestUtils::DEVICE_GPU)),
TileLayerGPUTest::getTestCaseName);
INSTANTIATE_TEST_CASE_P(DynamicShape5D, TileLayerGPUTest,
::testing::Combine(
::testing::ValuesIn(dynamicInputShapes5D),
::testing::ValuesIn(repeats5D),
::testing::ValuesIn(netPrecisions),
::testing::Values(true, false),
::testing::Values(CommonTestUtils::DEVICE_GPU)),
TileLayerGPUTest::getTestCaseName);
} // namespace
} // namespace GPULayerTestsDefinitions