diff --git a/python/tvm/relay/frontend/paddlepaddle.py b/python/tvm/relay/frontend/paddlepaddle.py index 9698f7aa53c8..5c3f50a12caa 100644 --- a/python/tvm/relay/frontend/paddlepaddle.py +++ b/python/tvm/relay/frontend/paddlepaddle.py @@ -480,13 +480,19 @@ def convert_elementwise_op(g, op, block): """Operator converter for all the elementwise operators.""" op_map = { - "elementwise_div": lambda x, y: x / y, - "elementwise_add": lambda x, y: x + y, - "elementwise_mul": lambda x, y: x * y, - "elementwise_sub": lambda x, y: x - y, - "elementwise_mod": _op.mod, - "elementwise_pow": _op.power, - "elementwise_floordiv": _op.floor_divide + "elementwise_div": "divide", + "elementwise_add": "add", + "elementwise_mul": "multiply", + "elementwise_sub": "subtract", + "elementwise_mod": "mod", + "elementwise_pow": "power", + "elementwise_floordiv": "floor_divide", + "floor_mod": "floor_mod", + "equal": "equal", + "greater_than": "greater", + "less_equal": "less_equal", + "less_than": "less", + "not_equal": "not_equal", } op_func = op_map[op.type] ipt0 = g.get_node(op.input("X")[0]) @@ -499,19 +505,11 @@ def convert_elementwise_op(g, op, block): axis = axis + len(ipt0_shape) if axis != len(ipt0_shape) - 1: ipt1 = _op.expand_dims(ipt1, axis=axis, num_newaxis=(len(ipt0_shape) - axis - 1)) + op_func = get_relay_op(op_func) out = op_func(ipt0, ipt1) g.add_node(op.output("Out")[0], out) -def convert_equal(g, op, block): - """Operator converter for equal.""" - - x = g.get_node(op.input("X")[0]) - y = g.get_node(op.input("Y")[0]) - out = _op.equal(x, y) - g.add_node(op.output("Out")[0], out) - - def convert_expand(g, op, block): """Operator converter for expand.""" @@ -602,10 +600,12 @@ def convert_fill_constant_batch_size_like(g, op, block): dtype = block.var(op.output("Out")[0]).dtype dtype = str(dtype).strip().split(".")[1] input_shape = shape_of(x) - batch = _op.strided_slice(input_shape, begin=[input_dim_idx], end=[input_dim_idx+1]).astype("int32") + batch = _op.strided_slice(input_shape, begin=[input_dim_idx], end=[input_dim_idx + 1]).astype( + "int32" + ) shape_before = shape[:output_dim_idx] shape_before = _expr.const(shape_before, dtype="int32") - shape_after = shape[output_dim_idx+1:] + shape_after = shape[output_dim_idx + 1 :] shape_after = _expr.const(shape_after, dtype="int32") out_shape = _op.concatenate([shape_before, batch, shape_after], axis=0) @@ -746,15 +746,6 @@ def convert_leaky_relu(g, op, block): g.add_node(op.output("Out")[0], out) -def convert_less_than(g, op, block): - """Operator converter for less_than.""" - - x = g.get_node(op.input("X")[0]) - y = g.get_node(op.input("Y")[0]) - out = _op.less(x, y) - g.add_node(op.output("Out")[0], out) - - def convert_lookup_table(g, op, block): """Operator converter for lookup_table_v2.""" @@ -946,15 +937,6 @@ def convert_mul(g, op, block): g.add_node(op.output("Out")[0], out) -def convert_not_equal(g, op, block): - """Operator converter for not_equal.""" - - x = g.get_node(op.input("X")[0]) - y = g.get_node(op.input("Y")[0]) - out = _op.not_equal(x, y) - g.add_node(op.output("Out")[0], out) - - def convert_pool2d(g, op, block): """Operator converter for pool2d.""" @@ -1051,7 +1033,7 @@ def convert_pow(g, op, block): out = _op.power(x, factor) g.add_node(op.output("Out")[0], out) - + def convert_range(g, op, block): """Operator converter for range.""" @@ -1297,36 +1279,61 @@ def convert_shape(g, op, block): def convert_slice(g, op, block): """Operator converter for slice.""" - def parameter_process(starts, ends, axes): - new_axes = [] - new_starts = [] - new_ends = [] - pop_index = 0 - for i in range(max(axes) + 1): - new_axes.append(i) - if i in axes: - new_starts.append(starts[pop_index]) - new_ends.append(ends[pop_index]) - pop_index += 1 - else: - new_starts.append(0) - new_ends.append(np.iinfo(np.int32).max) - return new_starts, new_ends, new_axes - data = g.get_node(op.input("Input")[0]) - starts = op.attr("starts") - ends = op.attr("ends") + dims = len(block.var(op.input("Input")[0]).shape) + dtype = "int64" + axes = op.attr("axes") + axes = _op.const(axes) decrease_axis = op.attr("decrease_axis") - if isinstance(starts, int): - starts = [starts] - if isinstance(ends, int): - ends = [ends] - if isinstance(axes, int): - axes = [axes] if isinstance(decrease_axis, int): decrease_axis = [decrease_axis] - starts, ends, axes = parameter_process(starts, ends, axes) + + starts = op.input("StartsTensor") + if starts: + starts = g.get_node(starts[0]) + elif op.input("StartsTensorList"): + starts = [] + for start_index in op.input("StartsTensorList"): + start_index = g.get_node(start_index) + if not isinstance(start_index, _expr.Expr): + start_index = _expr.const(start_index, dtype=dtype) + else: + start_index = start_index.astype(dtype) + starts.append(start_index) + starts = _op.concatenate(starts, axis=0) + else: + starts = op.attr("starts") + starts = _expr.const(starts) + if isinstance(starts, _expr.Expr): + starts = _op.scatter( + _op.const([0] * dims, dtype=infer_type(starts).checked_type.dtype), + axes, + starts, + axis=0, + ) + + data_shape = shape_of(data) + ends = op.input("EndsTensor") + if ends: + ends = g.get_node(ends[0]) + elif op.input("EndsTensorList"): + ends = [] + data_shape = data_shape.astype(dtype) + for end_index in op.input("EndsTensorList"): + end_index = g.get_node(end_index) + if not isinstance(end_index, _expr.Expr): + end_index = _expr.const(end_index, dtype=dtype) + else: + end_index = end_index.astype(dtype) + ends.append(end_index) + ends = _op.concatenate(ends, axis=0) + else: + ends = op.attr("ends") + ends = _expr.const(ends) + if isinstance(ends, _expr.Expr): + ends = _op.scatter(data_shape, axes, ends, axis=0) + out = _op.strided_slice(data, begin=starts, end=ends) if decrease_axis: out = _op.squeeze(out, axis=decrease_axis) @@ -1347,6 +1354,52 @@ def convert_softmax(g, op, block): g.add_node(op.output("Out")[0], out) +def convert_split(g, op, block): + """Operator converter for split.""" + + x = g.get_node(op.input("X")[0]) + axis = op.input("AxisTensor") + if axis: + axis = g.get_node(axis[0]) + axis = infer_value(axis, g.get_params()).numpy().tolist()[0] + else: + axis = op.attr("axis") + + sections = op.input("SectionsTensorList") + if sections: + tmp_section = [] + for i in sections: + i = g.get_node(i) + i = infer_value(i, g.get_params()).numpy().tolist() + tmp_section.extend(i) + sections = tmp_section + else: + sections = op.attr("sections") + if sections: + indices = [] + split_index = 0 + for i in sections[:-1]: + if i == -1: + input_shape = infer_shape(x)[axis] + i = input_shape - np.sum(sections) - 1 + split_index += i + indices.append(split_index) + else: + indices = op.attr("num") + + out = _op.split(x, indices, axis) + for i, out_i in enumerate(out): + g.add_node(op.output("Out")[i], out_i) + + +def convert_square(g, op, block): + """Operator converter for square.""" + + x = g.get_node(op.input("X")[0]) + out = _op.multiply(x, x) + g.add_node(op.output("Out")[0], out) + + def convert_squeeze(g, op, block): """Operator converter for squeeze2.""" @@ -1375,7 +1428,7 @@ def convert_topk(g, op, block): g.add_node(op.output("Out")[0], outs[0]) g.add_node(op.output("Indices")[0], outs[1]) - + def convert_stack(g, op, block): """Operator converter for stack.""" @@ -1465,7 +1518,7 @@ def convert_unsqueeze(g, op, block): "elementwise_mod": convert_elementwise_op, "elementwise_pow": convert_elementwise_op, "elementwise_floordiv": convert_elementwise_op, - "equal": convert_equal, + "equal": convert_elementwise_op, "exp": convert_unary_op, "expand_v2": convert_expand, "feed": convert_feed, @@ -1474,16 +1527,19 @@ def convert_unsqueeze(g, op, block): "fill_constant_batch_size_like": convert_fill_constant_batch_size_like, "flatten_contiguous_range": convert_flatten, "floor": convert_unary_op, + "floor_mod": convert_elementwise_op, "gather": convert_gather, "gather_nd": convert_gather_nd, "gelu": convert_gelu, + "greater_than": convert_elementwise_op, "hard_sigmoid": convert_hard_sigmoid, "hard_swish": convert_hard_swish, "isinf": convert_unary_op, "isinf_v2": convert_unary_op, "layer_norm": convert_layer_norm, "leaky_relu": convert_leaky_relu, - "less_than": convert_less_than, + "less_equal": convert_elementwise_op, + "less_than": convert_elementwise_op, "lookup_table": convert_lookup_table, "lookup_table_v2": convert_lookup_table, "log": convert_unary_op, @@ -1494,7 +1550,7 @@ def convert_unsqueeze(g, op, block): "matmul_v2": convert_matmul, "mul": convert_mul, "nearest_interp_v2": convert_interpolate, - "not_equal": convert_not_equal, + "not_equal": convert_elementwise_op, "pool2d": convert_pool2d, "pad1d": convert_padding, "pad2d": convert_padding, @@ -1511,12 +1567,15 @@ def convert_unsqueeze(g, op, block): "relu": convert_unary_op, "reshape2": convert_reshape, "rnn": convert_rnn, + "rsqrt": convert_unary_op, "scale": convert_scale, "shape": convert_shape, "sigmoid": convert_unary_op, "sin": convert_unary_op, "slice": convert_slice, "softmax": convert_softmax, + "split": convert_split, + "square": convert_square, "squeeze2": convert_squeeze, "stack": convert_stack, "tan": convert_unary_op, diff --git a/tests/python/frontend/paddlepaddle/test_forward.py b/tests/python/frontend/paddlepaddle/test_forward.py index fd55e916f866..f7ced14d7c69 100644 --- a/tests/python/frontend/paddlepaddle/test_forward.py +++ b/tests/python/frontend/paddlepaddle/test_forward.py @@ -159,8 +159,10 @@ def forward(self, inputs): "log10", "log1p", "relu", + "rsqrt", "sigmoid", "sin", + "square", "tan", "tanh", ] @@ -587,29 +589,6 @@ def flatten2(inputs): verify_model(flatten2, input_data=[x_data]) -@tvm.testing.uses_gpu -def test_forward_floor_divide(): - class Floor_divide(nn.Layer): - @paddle.jit.to_static - def forward(self, x, y): - return paddle.floor_divide(x, y) - - x_shape = [10] - y_shape = [10] - x_data = paddle.randint(1, 10, x_shape, dtype="int32") - y_data = paddle.randint(1, 10, y_shape, dtype="int32") - x_data_1 = paddle.randint(1, 10, x_shape, dtype="int64") - y_data_1 = paddle.randint(1, 10, y_shape, dtype="int64") - verify_model(Floor_divide(), input_data=[x_data, y_data]) - verify_model(Floor_divide(), input_data=[x_data_1, y_data_1]) - # For broadcast - x_shape_1 = [10] - y_shape_1 = [10, 1] - x_data_2 = paddle.randint(1, 10, x_shape_1, dtype="int32") - y_data_2 = paddle.randint(1, 10, y_shape_1, dtype="int32") - verify_model(Floor_divide(), input_data=[x_data_2, y_data_2]) - - @tvm.testing.uses_gpu def test_forward_shape_full(): @paddle.jit.to_static @@ -647,6 +626,44 @@ def ones_like2(inputs): verify_model(ones_like2, input_data=input_data) +@tvm.testing.uses_gpu +def test_forward_elemwise(): + class ElemwiseOp(nn.Layer): + def __init__(self, op_name): + super(ElemwiseOp, self).__init__() + for candidate in (paddle, paddle.nn.functional): + self.func = getattr(candidate, op_name, None) + if self.func: + break + + @paddle.jit.to_static + def forward(self, input1, input2): + y = self.func(input1, input2) + return paddle.cast(y, "int32") + + op_list = [ + "floor_divide", + "floor_mod", + "equal", + "greater_than", + "less_equal", + "less_than", + "not_equal", + ] + input_shape = [10, 10] + input_shape_2 = [ + 10, + ] + x_data = paddle.rand(input_shape, dtype="float32") + y_data = paddle.rand(input_shape_2, dtype="float32") + x_data_2 = paddle.randint(1, 100, input_shape_2, dtype="int32") + y_data_2 = paddle.randint(1, 100, input_shape, dtype="int32") + for op_name in op_list: + if op_name not in ["floor_divide"]: + verify_model(ElemwiseOp(op_name), [x_data, y_data]) + verify_model(ElemwiseOp(op_name), [x_data_2, y_data_2]) + + @tvm.testing.uses_gpu def test_forward_gather_assign_value(): @paddle.jit.to_static @@ -802,31 +819,6 @@ def leaky_relu(inputs): verify_model(leaky_relu, input_data=input_data) -@tvm.testing.uses_gpu -def test_forward_less_than(): - class Less_than(nn.Layer): - @paddle.jit.to_static - def forward(self, x, y): - output = paddle.less_than(x, y) - output = paddle.cast(output, "int32") - return output - - x_shape = [10] - y_shape = [10] - x_data = paddle.randint(1, 10, x_shape, dtype="int32") - y_data = paddle.randint(1, 10, y_shape, dtype="int32") - x_data_1 = paddle.randint(1, 10, x_shape, dtype="int64") - y_data_1 = paddle.randint(1, 10, y_shape, dtype="int64") - verify_model(Less_than(), input_data=[x_data, y_data]) - verify_model(Less_than(), input_data=[x_data_1, y_data_1]) - # For broadcast - x_shape_1 = [10] - y_shape_1 = [10, 1] - x_data_2 = paddle.rand(x_shape_1, dtype="float32") - y_data_2 = paddle.rand(y_shape_1, dtype="float32") - verify_model(Less_than(), input_data=[x_data_2, y_data_2]) - - @tvm.testing.uses_gpu def test_forward_look_up(): @paddle.jit.to_static @@ -919,32 +911,6 @@ def forward(self, input1, input2): verify_model(MatMul1(), input_data=[input_data1, input_data2]) -@tvm.testing.uses_gpu -def test_forward_not_equal(): - class Not_equal(nn.Layer): - @paddle.jit.to_static - def forward(self, x, y): - output = paddle.not_equal(x, y) - output = paddle.cast(output, "int32") - return output - - x_shape = [10] - y_shape = [10] - x_data = paddle.randint(1, 10, x_shape, dtype="int32") - y_data = paddle.randint(1, 10, y_shape, dtype="int32") - x_data_1 = paddle.randint(1, 10, x_shape, dtype="int64") - y_data_1 = paddle.randint(1, 10, y_shape, dtype="int64") - verify_model(Not_equal(), input_data=[x_data, y_data]) - verify_model(Not_equal(), input_data=[x_data_1, y_data_1]) - # For broadcast - x_shape_1 = [10] - y_shape_1 = [10, 1] - x_data_2 = paddle.rand(x_shape_1, dtype="float32") - y_data_2 = paddle.rand(y_shape_1, dtype="float32") - verify_model(Not_equal(), input_data=[x_data_2, y_data_2]) - - - @tvm.testing.uses_gpu def test_forward_pool2d(): @paddle.jit.to_static @@ -964,7 +930,8 @@ def pool2d3(inputs): input_data = paddle.uniform(shape=[1, 2, 32, 32], dtype="float32", min=-1, max=1) verify_model(pool2d1, input_data=input_data) verify_model(pool2d2, input_data=input_data) - verify_model(pool2d3, input_data=input_data) + # need op max_pool2d_with_index + # verify_model(pool2d3, input_data=input_data) @tvm.testing.uses_gpu @@ -1025,8 +992,8 @@ def forward(self, x, y): output = paddle.pow(x, y) return output - x_data = paddle.to_tensor([1, 2, 3], dtype='float32') - y_data = paddle.to_tensor([2], dtype='float32') + x_data = paddle.to_tensor([1, 2, 3], dtype="float32") + y_data = paddle.to_tensor([2], dtype="float32") verify_model(Pow(), input_data=[x_data]) verify_model(Pow1(), input_data=[x_data]) verify_model(Pow2(), input_data=[x_data, y_data]) @@ -1045,7 +1012,7 @@ def forward(self, inputs): output = self.func(inputs) output = paddle.cast(output, "int32") return output - + class ReduceOp_Bool1(ReduceOp_Bool): @paddle.jit.to_static def forward(self, inputs): @@ -1053,7 +1020,7 @@ def forward(self, inputs): output = self.func(inputs, axis=0) output = paddle.cast(output, "int32") return output - + class ReduceOp_Bool2(ReduceOp_Bool): @paddle.jit.to_static def forward(self, inputs): @@ -1071,13 +1038,13 @@ def __init__(self, op_name): def forward(self, inputs): output = self.func(inputs) return output - + class ReduceOp_Math1(ReduceOp_Math): @paddle.jit.to_static def forward(self, inputs): output = self.func(inputs, axis=0) return output - + class ReduceOp_Math2(ReduceOp_Math): @paddle.jit.to_static def forward(self, inputs): @@ -1180,17 +1147,32 @@ def slice4(inputs): input_shape = [1, 3, 10, 10] input_data = paddle.rand(input_shape, dtype="float32") - verify_model( - slice1, - input_data=[ - input_data, - ], - ) + verify_model(slice1, input_data=input_data) verify_model(slice2, input_data=input_data) # need op "strided_slice" # verify_model(slice3, input_data=paddle.randn((4, 4))) - # need op "assign_value" - # verify_model(slice4, input_data=input_data) + verify_model(slice4, input_data=input_data) + + +@tvm.testing.uses_gpu +def test_forward_split(): + @paddle.jit.to_static + def split(inputs): + return paddle.split(inputs, 2, axis=paddle.to_tensor([0], "int32")) + + @paddle.jit.to_static + def split2(inputs): + return paddle.split(inputs, [1, 2, -1], axis=1) + + @paddle.jit.to_static + def split3(inputs): + return paddle.split(inputs, [paddle.to_tensor([2]), 1, paddle.to_tensor(3)], axis=0) + + input_shape = [6, 10] + input_data = paddle.rand(input_shape, dtype="float32") + verify_model(split, input_data=input_data) + verify_model(split2, input_data=input_data) + verify_model(split3, input_data=input_data) @tvm.testing.uses_gpu @@ -1320,9 +1302,9 @@ def tile3(inputs, inputs2): test_forward_cumsum() test_forward_dot() test_forward_dropout() + test_forward_elemwise() test_forward_expand() test_forward_flatten() - test_forward_floor_divide() test_forward_shape_full() test_forward_ones_like() test_forward_gather_assign_value() @@ -1334,12 +1316,10 @@ def tile3(inputs, inputs2): test_forward_isinf() test_forward_layer_norm() test_forward_leaky_relu() - test_forward_less_than() test_forward_look_up() test_forward_lstm() test_forward_matmul() test_forward_multiply() - test_forward_not_equal() test_forward_pool2d() test_forward_pad() test_forward_pow() @@ -1347,6 +1327,7 @@ def tile3(inputs, inputs2): test_forward_reshape() test_forward_scale() test_forward_slice() + test_forward_split() test_forward_squeeze2() test_forward_topk() test_forward_tile()