diff --git a/ngraph/frontend/paddlepaddle/src/op/slice.cpp b/ngraph/frontend/paddlepaddle/src/op/slice.cpp index fcffbb8c4e5ff9..873695a8fc8e8c 100644 --- a/ngraph/frontend/paddlepaddle/src/op/slice.cpp +++ b/ngraph/frontend/paddlepaddle/src/op/slice.cpp @@ -77,9 +77,24 @@ NamedOutputs slice(const NodeContext& node) { auto decrease_axis = node.get_attribute>("decrease_axis"); if (decrease_axis.size() > 0) { - auto squeeze_index_node = Constant::create(element::i32, {}, decrease_axis); + // according to paddle slice_op, when all axes are decreased, output shape is [1], instead of scalar. + // Ref: paddle/fluid/operators/slice_op.h + PartialShape input_shape = data.get_partial_shape(); + PDPD_OP_VALIDATION_CHECK(node, + input_shape.rank().is_static(), + "input rank of slice must be static when decrease_axis is set."); + + auto squeeze_index_node = Constant::create(element::i32, {decrease_axis.size()}, decrease_axis); auto decreased_node = std::make_shared(stride_slice_node, squeeze_index_node); + auto input_rank = input_shape.rank().get_length(); + if (input_rank == decrease_axis.size()) { + auto restore_node = std::make_shared(decreased_node, + std::make_shared(element::i64, Shape{1}, 1), + false); // restore to shape (1,) + return node.default_single_output_mapping({restore_node}, {"Out"}); + } + return node.default_single_output_mapping({decreased_node}, {"Out"}); } diff --git a/ngraph/test/frontend/paddlepaddle/op_fuzzy.cpp b/ngraph/test/frontend/paddlepaddle/op_fuzzy.cpp index c944c67d7d3123..0a01edccbc1c9b 100644 --- a/ngraph/test/frontend/paddlepaddle/op_fuzzy.cpp +++ b/ngraph/test/frontend/paddlepaddle/op_fuzzy.cpp @@ -202,6 +202,9 @@ static const std::vector models{std::string("argmax"), std::string("sigmoid"), std::string("slice"), std::string("slice_1d"), + std::string("slice_decrease_axis/slice_decrease_axis.pdmodel"), + std::string("slice_decrease_axis_all/slice_decrease_axis_all.pdmodel"), + std::string("slice_reshape/slice_reshape.pdmodel"), std::string("softmax"), std::string("softmax_minus"), std::string("split_test1"), diff --git a/ngraph/test/frontend/paddlepaddle/test_models/gen_scripts/generate_slice.py b/ngraph/test/frontend/paddlepaddle/test_models/gen_scripts/generate_slice.py index bcfabdd28c428d..8c6b5fd1eeb28e 100644 --- a/ngraph/test/frontend/paddlepaddle/test_models/gen_scripts/generate_slice.py +++ b/ngraph/test/frontend/paddlepaddle/test_models/gen_scripts/generate_slice.py @@ -1,10 +1,14 @@ # # slice paddle model generator # +import sys +import os + import numpy as np -from save_model import saveModel import paddle as pdpd -import sys + +from save_model import exportModel +from save_model import saveModel data_type = 'float32' @@ -28,6 +32,59 @@ def slice(name : str, x, axes : list, start : list, end : list): return outs[0] + +def slice_dyn(test_shape=[2,8,10,10]): + pdpd.disable_static() + + data = pdpd.rand(shape=test_shape, dtype='float32') + + ''' + slice w/ decrease_axis + ''' + @pdpd.jit.to_static + def test_slice_decrease_axis(x): + return x[0, 1:3, :, 5] + exportModel('slice_decrease_axis', test_slice_decrease_axis, [data], target_dir=sys.argv[1]) # output shape (2, 10) + + ''' + slice w/o decrease_axis + ''' + @pdpd.jit.to_static + def test_slice(x): + return pdpd.slice(x, axes=[0,1,3], starts=[0,1,5], ends=[1,3,6]) + # exportModel('slice_dyn', test_slice, [data], target_dir=sys.argv[1]) # output shape (1, 2, 10, 1) # disable it by default as this kind of test model already there. It's for comparsion only. + + ''' + slice w/ decrease_axis of all dims + ''' + @pdpd.jit.to_static + def test_slice_decrease_axis_all(x): + return x[0, 0, 0, 0] + exportModel('slice_decrease_axis_all', test_slice_decrease_axis_all, [data], target_dir=sys.argv[1]) # output shape (1,) + + ''' + slice w/o decrease_axis of all dims + ''' + @pdpd.jit.to_static + def test_slice_alldim(x): + return pdpd.slice(x, axes=[0,1,2,3], starts=[0,0,0,0], ends=[1,1,1,1]) + # exportModel('slice_alldim', test_slice_alldim, [data], target_dir=sys.argv[1]) # output shape (1, 1, 1, 1) # disable it by default as this kind of test model already there. It's for comparsion only. + +''' +a test case simulating the last reshape2 of ocrnet which accepts slice (with decrease_axes in all dims) as its parents. +''' +def slice_reshape(B=1, C=256, H=16, W=32): + pdpd.disable_static() + + data = pdpd.rand(shape=[B, C, H*W], dtype='float32') + + @pdpd.jit.to_static + def test_model(x): + x2 = pdpd.assign([-1, -1, 16, 32]).astype('int32') + node_reshape = pdpd.reshape(x, [0, 256, x2[2], x2[3]]) + return node_reshape + exportModel('slice_reshape', test_model, [data], target_dir=sys.argv[1]) + def main(): x = np.linspace(1, 60, num = 60, dtype=np.int32).reshape(4, 3, 5).astype(data_type) slice("slice", x, axes=[1, 2], start=(0, 1), end=(-1, 3)) @@ -36,4 +93,6 @@ def main(): slice("slice_1d", x, axes=[0], start=[0], end=[1]) if __name__ == "__main__": - main() \ No newline at end of file + main() + slice_dyn() + slice_reshape() \ No newline at end of file diff --git a/ngraph/test/frontend/paddlepaddle/test_models/gen_scripts/save_model.py b/ngraph/test/frontend/paddlepaddle/test_models/gen_scripts/save_model.py index 95727ac9632797..3512fb2fd14fe6 100644 --- a/ngraph/test/frontend/paddlepaddle/test_models/gen_scripts/save_model.py +++ b/ngraph/test/frontend/paddlepaddle/test_models/gen_scripts/save_model.py @@ -1,4 +1,5 @@ import os +import sys import numpy as np import paddle as pdpd @@ -55,6 +56,42 @@ def saveModel(name, exe, feedkeys:list, fetchlist:list, inputs:list, outputs:lis pdpd.fluid.io.save_inference_model(model_dir, feedkeys, fetchlist, exe, model_filename=name+".pdmodel", params_filename=name+".pdiparams") +''' +export dyn model, along with input and output for reference. +input_data: list of all inputs +''' +def exportModel(name, dyn_func, input_data:list, target_dir:str): + model_dir = os.path.join(target_dir, name) + if not os.path.exists(model_dir): + os.makedirs(model_dir) + save_path = '{}/{}'.format(model_dir, name) + + input_specs = [] + for idx, data in enumerate(input_data): + input_name = 'input{}'.format(idx) + input_specs.append( + pdpd.static.InputSpec(shape=data.shape, dtype=data.dtype, name=input_name) + ) + + # dump input + np.save(os.path.join(model_dir, "input{}".format(idx)), data) + + pdpd.jit.save(dyn_func, save_path, input_specs) + print('saved exported model to {}'.format(save_path)) + + # infer + model = pdpd.jit.load(save_path) + + result = model(*[input[:] for input in input_data]) + + # dump output for reference + if isinstance(result, (tuple, list)): + for idx, out in enumerate(result): + np.save(os.path.join(model_dir, "output{}".format(idx)), out.numpy()) + else: + np.save(os.path.join(model_dir, "output{}".format(0)), result.numpy()) + + if __name__ == "__main__": np.set_printoptions(precision=2) np.set_printoptions(suppress=True)