[GPU] Enable tile with dynamic input (#16364)
This commit is contained in:
1 parent
3f06a9b6fb
commit
a46fc47e6a
4 files changed
+286
-40
No files matched your search
@@ -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 =
|
||||
|
||||
@@ -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
|
||||
Reference in new issue
Block a user