Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

【PaddlePaddle Hackathon 3】Add Paddle gather_nd operator #12355

Merged
merged 14 commits into from
Sep 13, 2022
8 changes: 8 additions & 0 deletions src/core/tests/frontend/paddle/op_fuzzy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,14 @@ static const std::vector<std::string> models{
std::string("gather_one_dimension2"),
// gather_axis_input
// (CVS-82724: not support Axis as input),
std::string("gather_nd_float32"),
std::string("gather_nd_int64"),
std::string("gather_nd_int32"),
// Not support index zero dimension
// std::string("gather_nd_empty"),
std::string("gather_nd_low_index"),
std::string("gather_nd_high_rank1"),
std::string("gather_nd_high_rank2"),
std::string("gelu_erf"),
std::string("gelu_tanh"),
std::string("generate_proposals_v2_0"),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#
# gather_nd paddle model generator
#
import numpy as np
from save_model import saveModel
import paddle
import sys


def gather_nd(name: str, x, y):
paddle.enable_static()

with paddle.static.program_guard(paddle.static.Program(), paddle.static.Program()):
data = paddle.static.data(name="x", shape=x.shape, dtype=x.dtype)
index = paddle.static.data(name="index", shape=y.shape, dtype=y.dtype)
out = paddle.gather_nd(data, index)

cpu = paddle.static.cpu_places(1)
exe = paddle.static.Executor(cpu[0])
# startup program will call initializer to initialize the parameters.
exe.run(paddle.static.default_startup_program())
outs = exe.run(feed={"x": x, "index": y}, fetch_list=[out])

saveModel(
name,
exe,
feedkeys=["x", "index"],
fetchlist=[out],
inputs=[x, y],
outputs=[outs[0]],
target_dir=sys.argv[1],
)

return outs[0]


def main():
tests_cases = [
liubo-intel marked this conversation as resolved.
Show resolved Hide resolved
"float32",
"int32",
"int64",
]
x_shape = (10, 20)

for test in tests_cases:
x = np.random.rand(*x_shape).astype(test)
y = np.array([[0, 1], [1, 1]]).astype("int32")
gather_nd("gather_nd_" + test, x, y)

x = np.random.rand(*x_shape).astype("float32")
y = np.array([[], []]).astype("int32")
gather_nd("gather_nd_empty", x, y)

y = np.array([[1], [2]]).astype("int32")
gather_nd("gather_nd_low_index", x, y)

x_shape = (5, 2, 3, 1, 10)
x = np.random.rand(*x_shape).astype("float32")
y = np.array(
[
[np.random.randint(0, s) for s in x_shape],
[np.random.randint(0, s) for s in x_shape],
]
).astype("int32")
gather_nd("gather_nd_high_rank1", x, y)

index = (
np.array([np.random.randint(0, s, size=100) for s in x_shape]).astype("int32").T
)
y = index.reshape([10, 5, 2, 5])
gather_nd("gather_nd_high_rank2", x, y)


if __name__ == "__main__":
main()
26 changes: 26 additions & 0 deletions src/frontends/paddle/src/op/gather_nd.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (C) 2018-2022 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//

#include "default_opset.hpp"
#include "openvino/frontend/paddle/node_context.hpp"

namespace ov {
namespace frontend {
namespace paddle {
namespace op {
NamedOutputs gather_nd(const NodeContext& node) {
const auto data_node = node.get_input("X");
const auto index_node = node.get_input("Index");
auto shape = index_node.get_partial_shape();
for (const auto& dim : shape) {
if (dim.is_static() && dim.get_length() == 0)
PADDLE_OP_CHECK(node, false, "zero dimension is not allowed for gather_nd Index");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

@liubo-intel liubo-intel Sep 5, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, @ilyachur : thanks for taking your time to help have a look at this PR. the 'indices' input value of OV 'gather_nd' can be '0', but as its specification describes 'A tensor of a rank not less than 1'. the 'indices' input rank should not be '0'(@AndPuQing has created an commented test case 'gather_nd_empty' to cover this).
Maybe we should change it to the following way?

    if (shape.is_static() && shape.rank().get_length() == 0)
        PADDLE_OP_CHECK(node, false, "zero 'indices' input rank is not allowed for gather_nd");

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I think it will be more aligned with the specification

}
return node.default_single_output_mapping({std::make_shared<default_opset::GatherND>(data_node, index_node)},
{"Out"});
}
} // namespace op
} // namespace paddle
} // namespace frontend
} // namespace ov
2 changes: 2 additions & 0 deletions src/frontends/paddle/src/op_table.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ OP_CONVERTER(fill_constant);
OP_CONVERTER(flatten_contiguous_range);
OP_CONVERTER(floor);
OP_CONVERTER(gather);
OP_CONVERTER(gather_nd);
OP_CONVERTER(gelu);
OP_CONVERTER(greater_than);
OP_CONVERTER(hard_sigmoid);
Expand Down Expand Up @@ -132,6 +133,7 @@ std::map<std::string, CreatorFunction> get_supported_ops() {
{"flatten_contiguous_range", op::flatten_contiguous_range},
{"floor", op::floor},
{"gather", op::gather},
{"gather_nd", op::gather_nd},
{"gelu", op::gelu},
{"greater_equal", op::elementwise_greater_equal},
{"greater_than", op::greater_than},
Expand Down