Cecilia/fix/slice decrease axis (#8342)

* 1. fix for CVS-69011 2.add more test cases for slice w/ decrease_axis

* add test case simulating the last reshape2 of ocrnet which accepts slice (with decrease_axes in all dims) as its parents.

* exportModel as a helper function.

* fix: rank get_length type
This commit is contained in:
cecilia peng 2021-11-17 12:25:10 +08:00 committed by GitHub
parent 51b9dff1bc
commit d587fb2844
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 119 additions and 5 deletions

View File

@ -77,9 +77,24 @@ NamedOutputs slice(const NodeContext& node) {
auto decrease_axis = node.get_attribute<std::vector<int32_t>>("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<Squeeze>(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<Reshape>(decreased_node,
std::make_shared<Constant>(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"});
}

View File

@ -202,6 +202,9 @@ static const std::vector<std::string> 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"),

View File

@ -1,10 +1,14 @@
#
# slice paddle model generator
#
import numpy as np
from save_model import saveModel
import paddle as pdpd
import sys
import os
import numpy as np
import paddle as pdpd
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()
main()
slice_dyn()
slice_reshape()

View File

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