From 22a20be3c373d578a39e50e7d4f77ac8c258b0bc Mon Sep 17 00:00:00 2001 From: root Date: Tue, 3 Aug 2021 13:49:34 +0000 Subject: [PATCH 01/51] fix some problems for matmul --- python/tvm/relay/frontend/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/python/tvm/relay/frontend/__init__.py b/python/tvm/relay/frontend/__init__.py index aa8ac4fc7434..aa49b63203f2 100644 --- a/python/tvm/relay/frontend/__init__.py +++ b/python/tvm/relay/frontend/__init__.py @@ -31,4 +31,5 @@ from .darknet import from_darknet from .pytorch import from_pytorch from .caffe import from_caffe +from .paddlepaddle import from_paddle from .change_datatype import ChangeDatatype From 1a7f180944949db25ac28eff3f48f2fe4738637b Mon Sep 17 00:00:00 2001 From: root Date: Tue, 3 Aug 2021 13:49:50 +0000 Subject: [PATCH 02/51] fix some problems for matmul --- python/tvm/relay/frontend/paddlepaddle.py | 768 ++++++++++++++++++++++ 1 file changed, 768 insertions(+) create mode 100644 python/tvm/relay/frontend/paddlepaddle.py diff --git a/python/tvm/relay/frontend/paddlepaddle.py b/python/tvm/relay/frontend/paddlepaddle.py new file mode 100644 index 000000000000..9326ba8a184e --- /dev/null +++ b/python/tvm/relay/frontend/paddlepaddle.py @@ -0,0 +1,768 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# pylint: disable=invalid-name, import-self, len-as-condition, unused-argument, too-many-lines +# pylint: disable=import-outside-toplevel +"""Paddle: PArallel Distributed Deep LEarning.""" +import copy +import warnings +import six + +import numpy as np + +import tvm +from tvm.ir import IRModule + +from .. import analysis +from .. import expr as _expr +from .. import function as _function +from .. import ty as _ty +from .. import op as _op +from .common import ( + fold_constant, + infer_shape, + infer_type, + infer_value, + new_var, +) + +__all__ = ["from_paddle"] + + +def shape_of(x, dtype='int32'): + ttype = infer_type(x).checked_type + if not _ty.is_dynamic(ttype): + shape = list(ttype.shape) + return _expr.const(shape, dtype) + return _op.shape_of(x, dtype) + + +def convert_arg_max(g, op, block): + """Operator converter for arg_max.""" + + axis = op.attr('axis') + keepdims = op.attr('keepdims') + flatten = op.attr('flatten') + assert not flatten, "Only flatten==True is supported for PaddlePaddle's arg_max" + + x = g.get_node(x.input('X')[0]) + out = _op.argmax(x, axis=axis, keepdims=keepdims) + g.add_node(op.output('Out')[0], out) + + +def convert_assign(g, op, block): + """Operator converter for assign.""" + + out = _op.copy(g.get_node(op.input('X')[0])) + g.add_node(op.output('Out')[0], out) + + +def convert_batch_norm(g, op, block): + """Operator converter for batch_norm.""" + + ipt_name = op.input('X')[0] + scale_name = op.input('Scale')[0] + bias_name = op.input('Bias')[0] + mean_name = op.input('Mean')[0] + variance_name = op.input('Variance')[0] + epsilon = op.attr('epsilon') + momentum = op.attr('momentum') + out = _op.nn.batch_norm(g.get_node(ipt_name), + g.get_node(scale_name), + g.get_node(bias_name), + g.get_node(mean_name), + g.get_node(variance_name), + epsilon=epsilon) + g.add_node(op.output('Y')[0], out[0]) + + +def convert_cast(g, op, block): + """Operator converter for cast.""" + + dtype = block.var(op.output('Out')[0]).dtype + dtype = str(dtype).strip().split('.')[1] + x = g.get_node(op.input('X')[0]) + out = _op.cast(x, dtype=dtype) + g.add_node(op.output('Out')[0], out) + + +def convert_concat(g, op, block): + """Operator converter for concat.""" + + inputs = [g.get_node(op.input('X')[i]) for i in range(len(op.input('X')))] + axis = op.attr('axis') + out = _op.concatenate(inputs, axis=axis) + g.add_node(op.output('Out')[0], out) + + +def convert_conv2d(g, op, block): + """Operator converter for conv2d.""" + def get_pad_size(in_size, dilated_kernel_size, stride_size): + if stride_size == 1 or in_size & stride_size == 0: + pad = max(dilated_kernel_size - stride_size, 0) + else: + pad = max(dilated_kernel_size - (in_size % stride_size), 0) + return [pad // 2, pad - pad // 2] + + assert op.attr( + 'data_format' + ) == 'NCHW', "Only NCHW format is support for PaddlePaddle's conv2d" + dilations = op.attr('dilations') + groups = op.attr('groups') + paddings = op.attr('paddings') + padding_algorithm = op.attr('padding_algorithm') + strides = op.attr('strides') + + kernel = g.get_node(op.input('Filter')[0]) + input = g.get_node(op.input('Input')[0]) + out_channels, _, k_h, k_w = infer_shape(kernel) + in_h, in_w = infer_shape(input)[2:] + assert len( + paddings + ) == 2, "Only support len(paddings)==2 for PaddlePaddle's conv2d" + assert len( + dilations + ) == 2, "Only support len(dilations)==2 for PaddlePaddle's conv2d" + if padding_algorithm == "SAME": + pad_h = get_pad_size(in_h, (k_h - 1) * dilations[0] + 1, strides[0]) + pad_w = get_pad_size(in_w, (k_w - 1) * dilations[1] + 1, strides[1]) + paddings = [pad_h[0], pad_w[0], pad_h[1], pad_w[1]] + out = _op.nn.conv2d(input, + kernel, + strides=strides, + padding=paddings, + dilation=dilations, + groups=groups, + channels=out_channels, + kernel_size=[k_h, k_w]) + g.add_node(op.output('Output')[0], out) + + +def convert_cumsum(g, op, block): + """Operator converter for cumsum.""" + + axis = op.attr('axis') + exclusive = op.attr('exclusive') + flatten = op.attr('flatten') + reverse = op.attr('reverse') + + assert not flatten, "Only flatten==False is supported for PaddlePaddle's cumsum" + + x = g.get_node(op.input('X')[0]) + if reverse: + x = _op.reverse(x, axis=axis) + out = _op.cumsum(x, axis=axis, exclusive=exclusive) + out = _op.reverse(out, axis=axis) + else: + out = _op.cumsum(x, axis=axis, exclusive=exclusive) + g.add_node(op.output('Out')[0], out) + + +def convert_dropout(g, op, block): + """Operator converter for dropout.""" + + x = g.get_node(op.input('X')[0]) + out = _op.copy(x) + g.add_node(op.output('Out')[0], out) + + +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': lambda x, y: x % y, + } + op_func = op_map[op.type] + ipt0 = g.get_node(op.input('X')[0]) + ipt1 = g.get_node(op.input('Y')[0]) + ipt0_shape = block.var(op.input('X')[0]).shape + ipt1_shape = block.var(op.input('Y')[0]).shape + axis = op.attr('axis') + if len(ipt0_shape) != len(ipt1_shape): + if axis < 0: + 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)) + 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_activation(g, op, block): + """Operator converter for all the activation.""" + + op_map = { + 'exp': _op.exp, + 'relu': _op.nn.relu, + 'tanh': _op.tanh, + 'sqrt': _op.sqrt, + 'erf': _op.erf, + 'abs': _op.abs, + } + act_func = op_map[op.type] + out = act_func(g.get_node(op.input('X')[0])) + g.add_node(op.output('Out')[0], out) + + +def convert_feed(g, op, block): + """Converter for model input node.""" + + ipt_name = op.output('Out')[0] + ipt_shape = block.var(ipt_name).shape + ipt_dtype = block.var(ipt_name).dtype + ipt_dtype = str(ipt_dtype).strip().split('.')[1] + if g.shape_dict is not None: + ipt_shape = g.shape_dict[ipt_name] + out = new_var(ipt_name, shape=ipt_shape, dtype=ipt_dtype) + g.add_node(ipt_name, out) + + +def convert_fill_any_like(g, op, block): + """Operator converter for fill_any_like.""" + + out_name = op.output('Out')[0] + out_dtype = block.var(out_name).dtype + out_dtype = str(out_dtype).strip().split('.')[1] + x = g.get_node(op.input('X')[0]) + ipt_shape = infer_shape(x) + if not is_fixed_shape(ipt_shape): + msg = "Only support fixed input shape of PaddlePaddle's fill_any_like" + raise tvm.error.OpNotImplemented(msg) + value = op.attr('value') + const = np.ones(ipt_shape) * value + out = _expr.const(const.astype(out_dtype)) + g.add_node(op.output('Out')[0], out) + + +def convert_fill_constant(g, op, block): + """Operator converter for fill_constant.""" + + value = op.attr('value') + shape = block.var(op.output('Out')[0]).shape + dtype = block.var(op.output('Out')[0]).dtype + dtype = str(dtype).strip().split('.')[1] + value = np.full(shape, value, dtype) + out = _expr.const(value.astype(dtype)).astype(dtype) + g.add_node(op.output('Out')[0], out) + + +def convert_gelu(g, op, block): + """Operator converter for gelu.""" + + x = g.get_node(op.input('X')[0]) + out = x * (_expr.const(0.5, dtype='float32') + + _op.erf(x * _expr.const(0.5**0.5, dtype='float32')) * + _expr.const(0.5, dtype='float32')) + g.add_node(op.output('Out')[0], out) + + +def convert_hard_sigmoid(g, op, block): + """Operator converter for hard_sigmoid.""" + + slope = op.attr('slope') + offset = op.attr('offset') + x = g.get_node(op.input('X')[0]) + out = x * _expr.const(slope) + _expr.const(0.5) + out = _op.clip(out, 0, 1) + g.add_node(op.output('Out')[0], out) + + +def convert_hard_swish(g, op, block): + """Operator converter for hard_swish.""" + + offset = op.attr('offset') + scale = op.attr('scale') + threshold = op.attr('threshold') + assert np.isclose( + offset, 3.0), "Only support offset==3.0 for PaddlePaddle's hard_swish" + assert np.isclose( + scale, 6.0), "Only support scale==6.0 for PaddlePaddle's hard_swish" + assert np.isclose( + threshold, + 6.0), "Only support threshold==6.0 for PaddlePaddle's hard_swish" + x = g.get_node(op.input('X')[0]) + out = _op.clip(x, -1 * offset, offset) + out = out / _expr.const(threshold) + _expr.const(0.5) + out = x * out + g.add_node(op.output('Out')[0], out) + + +def convert_layer_norm(g, op, block): + """Operator converter for layer_norm.""" + + begin_norm_axis = op.attr('begin_norm_axis') + epsilon = op.attr('epsilon') + x = g.get_node(op.input('X')[0]) + bias = g.get_node(op.input('Bias')[0]) + scale = g.get_node(op.input('Scale')[0]) + out = _op.nn.layer_norm(x, + gamma=scale, + beta=bias, + axis=begin_norm_axis, + epsilon=epsilon, + center=True, + scale=True) + g.add_node(op.output('Y')[0], out) + + +def convert_leaky_relu(g, op, block): + """Operator converter for leaky_relu.""" + + alpha = op.attr('alpha') + x = g.get_node(op.input('X')[0]) + out = _op.nn.leaky_relu(x, alpha=alpha) + g.add_node(op.output('Out')[0]) + + +def convert_lookup_table(g, op, block): + """Operator converter for lookup_table_v2.""" + + indices = g.get_node(op.input('Ids')[0]) + padding_idx = op.attr('padding_idx') + is_sparse = op.attr('is_sparse') + height_sections = op.attr('height_sections') + if padding_idx != -1: + g.get_params[op.input('W')[0]][padding_idx] = 0.0 + g.add_node(op.input('W')[0], _expr.const(g.params[op.input('W')[0]])) + weights = g.get_node(op.input('W')[0]) + out = _op.take(weights, indices.astype('int32'), axis=0) + g.add_node(op.output('Out')[0], out) + + +def convert_matmul(g, op, block): + """Operator converter for matmul.""" + + inputs = [g.get_node(op.input('X')[0]), g.get_node(op.input('Y')[0])] + a_shape = infer_shape(inputs[0]) + b_shape = infer_shape(inputs[1]) + try: + # for matmul_v2 + trans_x = op.attr('trans_x') + trans_y = op.attr('trans_y') + except: + # for matmul + trans_x = op.attr('transpose_X') + trans_y = op.attr('transpose_Y') + if trans_x: + perm = list(range(len(a_shape))) + perm[-2] = len(a_shape) - 1 + perm[-1] = len(a_shape) - 2 + inputs[0] = _op.transpose(inputs[0], axes=perm) + if trans_y: + perm = list(range(len(b_shape))) + perm[-2] = len(b_shape) - 1 + perm[-1] = len(b_shape) - 2 + inputs[1] = _op.transpose(inputs[1], axes=perm) + + # This implemention almost keeps same with ONNX + # Need to check input shape as batch matmul must be supported. + a_shape = shape_of(inputs[0]) + a_rank = infer_shape(a_shape)[0] + b_shape = shape_of(inputs[1]) + b_rank = infer_shape(b_shape)[0] + # When performing a batch matmul, we need to properly handle N-dim shapes. + if a_rank > 2 or b_rank > 2: + + def flatten_to_nd(x, x_shape, nd=3): + ndims = infer_shape(x_shape)[0] + if ndims == nd: + return x + newshape = _op.concatenate( + [ + _expr.const([-1], + dtype=infer_type(x_shape).checked_type.dtype), + _op.strided_slice(x_shape, [ndims - nd + 1], [ndims]), + ], + 0, + ) + out = _op.reshape(x, fold_constant(newshape)) + return out + + b_type = infer_type(inputs[1]) + # Convert to dense if the second matrix is 2d and non-dynamic + if b_rank == 2 and not _ty.is_dynamic(b_type.checked_type): + a = flatten_to_nd(inputs[0], a_shape, 2) + b = _op.transpose(inputs[1]) + output = _op.nn.dense(a, b) + else: + # Convert a and b into 3 dimensional tensors. + a = flatten_to_nd(inputs[0], a_shape, 3) + b = flatten_to_nd(inputs[1], b_shape, 3) + # Transpose matrix dimensions of b. + b = _op.transpose(b, [0, 2, 1]) + # Perform a batch matmul. + output = _op.nn.batch_matmul(a, b) + # Determine the output batch dimension. + if a_rank > b_rank: + out_batch = _op.strided_slice(a_shape, [0], [a_rank - 2]) + elif a_rank < b_rank: + out_batch = _op.strided_slice(b_shape, [0], [b_rank - 2]) + # If its unclear how broadcasting should be applied, the output + # shape is determined by choosing the maximum value from each input. + else: + out_batch = _op.concatenate( + [ + _op.maximum( + _op.strided_slice(a_shape, [i], [i + 1]), + _op.strided_slice(b_shape, [i], [i + 1]), + ) for i in range(a_rank - 2) + ], + 0, + ) + # Reshape output to original dimensions. + final_shape = _op.concatenate( + [ + out_batch, + _op.strided_slice(a_shape, [infer_shape(a_shape)[0] - 2], + [infer_shape(a_shape)[0] - 1]), + _op.strided_slice(b_shape, [infer_shape(b_shape)[0] - 1], + [infer_shape(b_shape)[0]]), + ], + 0, + ) + out = _op.reshape(output, fold_constant(final_shape)) + g.add_node(op.output('Out')[0], out) + return + # Otherwise a simple dense op will get the job done. + input_1_t = _op.transpose(inputs[1], axes=(1, 0)) + out = _op.nn.dense(inputs[0], input_1_t) + g.add_node(op.output('Out')[0], out) + + +def convert_pool2d(g, op, block): + """Operator converter for pool2d.""" + + layout = op.attr('data_format') + assert layout == 'NCHW', "Only support NCHW format for PaddlePaddle's pool2d." + adaptive = op.attr('adaptive') + ceil_mode = op.attr('ceil_mode') + exclusive = op.attr('exclusive') + global_pooling = op.attr('global_pooling') + ksize = op.attr('ksize') + paddings = op.attr('paddings') + padding_algorithm = op.attr('padding_algorithm') + pooling_type = op.attr('pooling_type') + + op_map = { + 'avg': 'avg_pool2d', + 'max': 'max_pool2d', + } + strides = op.attr('strides') + assert exclusive, "Only support exclusive==True for PaddlePaddle's pool2d" + assert padding_algorithm == "EXPLICIT", "Only support padding_algorithm==EXPLICIT for PaddlePaddle's pool2d" + if isinstance(strides, int): + strides = [strides, strides] + if isinstance(ksize, int): + ksize = [ksize, ksize] + if isinstance(paddings, six.string_types): + msg = "Setting paddings to `SAME` or `VALID` is not support for PaddlePaddle's pool2d" + raise tvm.error.OpNotImplemented(msg) + elif isinstance(paddings, int): + paddings = [paddings] * 2 + elif len(paddings) == 2: + pass + elif len(paddings) == 4: + msg = "Only support length of paddings equals to 2 for PaddlePaddle's pool2d" + raise tvm.error.OpNotImplemented(msg) + + x = g.get_node(op.input('X')[0]) + if not adaptive: + out = getattr(_op.nn, op_map[pooling_type])(x, + pool_size=ksize, + strides=strides, + padding=paddings, + ceil_mode=ceil_mode) + else: + out = getattr(_op.nn, + "adaptive_" + op_map[pooling_type])(x, output_size=ksize) + g.add_node(op.output('Out')[0], out) + + +def convert_reshape(g, op, block): + """Operator converter for reshape.""" + + shape = op.attr('shape') + out = _op.reshape(g.get_node(op.input('X')[0]), shape) + g.add_node(op.output('Out')[0], out) + + +def convert_scale(g, op, block): + """Operator converter for scale.""" + + scale = op.attr('scale') + bias = op.attr('bias') + bias_after_scale = op.attr('bias_after_scale') + x = g.get_node(op.input('X')[0]) + if np.isclose(scale, 1.0) and np.isclose(bias, 0.0): + out = _op.copy(x) + else: + if np.isclose(bias, 0.0): + out = x * _expr.const(np.array(scale).astype('float32')) + elif np.isclose(scale, 1.0): + out = x + _expr.const(np.array(bias).astype('float32')) + else: + if bias_after_scale: + out = x * _expr.const( + np.array(scale).astype('float32')) + _expr.const( + np.array(bias).astype('float32')) + else: + out = (x + _expr.const(np.array(bias).astype('float32')) + ) * _expr.const(np.array(scale).astype('float32')) + g.add_node(op.output('Out')[0], out) + + +def convert_shape(g, op, block): + """Operator converter for shape.""" + + x = g.get_node(op.input('Input')[0]) + out = shape_of(x) + g.add_node(op.output('Out')[0], out) + + +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 + + starts = op.attr('starts') + ends = op.attr('ends') + axes = op.attr('axes') + if isinstance(starts, int): + starts = [starts] + if isinstance(ends, int): + ends = [ends] + if isinstance(axes, int): + axes = [axes] + starts, ends, axes = parameter_process(starts, ends, axes) + out = _op.strided_slice(g.get_node(op.input('Input')[0]), + begin=starts, + end=ends) + g.add_node(op.output('Out')[0], out) + + +def convert_softmax(g, op, block): + """Operator converter for softmax.""" + + axis = op.attr('axis') + input_shape = block.var(op.input('X')[0]).shape + if axis < 0: + axis = len(input_shape) + axis + x = g.get_node(op.input('X')[0]) + m = _op.max(x, axis, keepdims=True) + e = _op.exp(x - m) + out = e / _op.sum(e, axis, keepdims=True) + g.add_node(op.output('Out')[0], out) + + +def convert_transpose(g, op, block): + """Operator converter for transpose.""" + + perm = op.attr('axis') + out = _op.transpose(g.get_node(op.input('X')[0]), axes=perm) + g.add_node(op.output('Out')[0], out) + + +def convert_unsqueeze(g, op, block): + """Operator converter for unsqueeze.""" + + x = g.get_node(op.input('X')[0]) + axes = sorted(op.attr('axes')) + for axis in axes: + x = _op.expand_dims(x, axis=axis, num_newaxis=1) + g.add_node(op.output('Out')[0], x) + + +_convert_map = { + 'arg_max': convert_arg_max, + 'assign': convert_assign, + 'batch_norm': convert_batch_norm, + 'cast': convert_cast, + 'concat': convert_concat, + 'conv2d': convert_conv2d, + 'cumsum': convert_cumsum, + 'depthwise_conv2d': convert_conv2d, + 'dropout': convert_dropout, + 'elementwise_add': convert_elementwise_op, + 'elementwise_div': convert_elementwise_op, + 'elementwise_mul': convert_elementwise_op, + 'elementwise_sub': convert_elementwise_op, + 'equal': convert_equal, + 'exp': convert_activation, + 'feed': convert_feed, + 'fill_any_like': convert_fill_any_like, + 'fill_constant': convert_fill_constant, + 'gelu': convert_gelu, + 'hard_sigmoid': convert_hard_sigmoid, + 'hard_swish': convert_hard_swish, + 'layer_norm': convert_layer_norm, + 'leaky_relu': convert_leaky_relu, + 'lookup_table_v2': convert_lookup_table, + 'matmul': convert_matmul, + 'matmul_v2': convert_matmul, + 'pool2d': convert_pool2d, + 'relu': convert_activation, + 'reshape2': convert_reshape, + 'scale': convert_scale, + 'shape': convert_shape, + 'slice': convert_slice, + 'softmax': convert_softmax, + 'tanh': convert_activation, + 'transpose2': convert_transpose, + 'unsqueeze2': convert_unsqueeze, +} + + +class GraphProto(object): + """ A helper class for handling relay functions from PaddlePaddle model.""" + def __init__(self): + self.nodes = {} + self.params = {} + self.shape_dict = None + + def get_node(self, name): + assert name in self.nodes + return self.nodes[name] + + def add_node(self, name, node): + self.nodes[name] = fold_constant(node) + + def get_params(self, name): + assert name in self.params + return self.params[name] + + def extract_parameters(self, program, scope): + """ Extract all the weights from PaddlePaddle program.""" + + self.params = {} + variables = program.global_block().vars + for name in variables: + var = program.global_block().var(name) + if name.endswith('feed') or name.endswith('fetch'): + continue + if not var.persistable: + continue + if isinstance(scope, dict): + self.params[name] = scope[name] + else: + self.params[name] = np.array(scope.var(name).get_tensor()) + self.nodes[name] = _expr.const(self.params[name]) + + def check_input_shape(self, op, block): + """ Check the shape information of model's inputs, fixed shape is recommended.""" + + ipt_name = op.input(op.input_names[0]) + ipt_shape = block.var(ipt_name).shape + for i in ipt_shape: + if i < 0: + warning_msg = ( + "Input {}(shape={}) has unkown dimension shapes. Specifying static values may improve performance" + .format(ipt_name, ipt_shape)) + warings.warn(warning_msg) + + def check_unsupported_ops(self, program): + """ Check whether all the operators are supported.""" + + unsupported_ops = set() + for block in program.blocks: + for i, op in enumerate(block.ops): + if op.type == 'fetch': + continue + if op.type not in _convert_map: + unsupported_ops.add(op.type) + if len(unsupported_ops) > 0: + msg = "The following operators are not supported for frontend Paddle: " + msg += ", ".join(unsupported_ops) + raise tvm.error.OpNotImplemented(msg) + + def ops_to_relay(self, program, scope): + """ Convert PaddlePaddle operators to TVM relay functions.""" + + for block in program.blocks: + for i, op in enumerate(block.ops): + if op.type == 'fetch': + continue + convert_func = _convert_map[op.type] + convert_func(self, op, block) + + def get_outputs(self, program): + """ Get outputs of PaddlePaddle model.""" + + outputs = list() + for block in program.blocks: + for i, op in enumerate(block.ops): + if op.type == "fetch": + outputs.append(op.input('X')[0]) + return outputs + + def from_paddle(self, program, shape_dict, scope): + """ Construct the TVM relay expression from PaddlePaddle program.""" + + self.shape_dict = shape_dict + if scope is None: + import paddle + scope = paddle.fluid.global_scope() + self.check_unsupported_ops(program) + self.extract_parameters(program, scope) + self.ops_to_relay(program, scope) + output_names = self.get_outputs(program) + + outputs = [self.nodes[name] for name in output_names] + outputs = outputs[0] if len(outputs) == 1 else _expr.Tuple(outputs) + + free_vars = analysis.free_vars(outputs) + func = _function.Function(free_vars, outputs) + mod = IRModule.from_expr(func) + return mod, self.params + + +def from_paddle(program, shape_dict=None, scope=None): + """ Convert a PaddlePaddle model into an equivalent Relay Function. + + PaddlePaddle Program represent the computation graph of PaddlePaddle model, + and PaddlePaddle scope stores all the weights of PaddlePaddle model. + """ + + import paddle + g = GraphProto() + mod, params = g.from_paddle(program, shape_dict, scope) + return mod, params From 3f604e925f04415ebc1bfae3e6a13b4014113bc2 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 4 Aug 2021 03:01:45 +0000 Subject: [PATCH 03/51] add alpha parameter for matmul --- python/tvm/relay/frontend/paddlepaddle.py | 28 ++++++++++++++--------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/python/tvm/relay/frontend/paddlepaddle.py b/python/tvm/relay/frontend/paddlepaddle.py index 9326ba8a184e..87a8679adcc2 100644 --- a/python/tvm/relay/frontend/paddlepaddle.py +++ b/python/tvm/relay/frontend/paddlepaddle.py @@ -251,13 +251,14 @@ def convert_fill_any_like(g, op, block): out_dtype = block.var(out_name).dtype out_dtype = str(out_dtype).strip().split('.')[1] x = g.get_node(op.input('X')[0]) - ipt_shape = infer_shape(x) - if not is_fixed_shape(ipt_shape): - msg = "Only support fixed input shape of PaddlePaddle's fill_any_like" - raise tvm.error.OpNotImplemented(msg) + ipt_type = infer_type(x).checked_type value = op.attr('value') - const = np.ones(ipt_shape) * value - out = _expr.const(const.astype(out_dtype)) + if not _ty.is_dynamic(ipt_type): + shape = infer_shape(x) + const = np.ones(shape) * value + out = _expr.const(const.astype(out_dtype)) + else: + out = _op.transform.full_like(x, value).astype(out_dtype) g.add_node(op.output('Out')[0], out) @@ -448,11 +449,16 @@ def flatten_to_nd(x, x_shape, nd=3): 0, ) out = _op.reshape(output, fold_constant(final_shape)) - g.add_node(op.output('Out')[0], out) - return - # Otherwise a simple dense op will get the job done. - input_1_t = _op.transpose(inputs[1], axes=(1, 0)) - out = _op.nn.dense(inputs[0], input_1_t) + else: + # Otherwise a simple dense op will get the job done. + input_1_t = _op.transpose(inputs[1], axes=(1, 0)) + out = _op.nn.dense(inputs[0], input_1_t) + try: + alpha = op.attr('alpha') + if not np.isclose(alpha, 1.0): + out = out * _expr.const(alpha).astype('float32') + except: + pass g.add_node(op.output('Out')[0], out) From fe6de07603bebbb7adb05df1f8dc89b5453562f3 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 4 Aug 2021 06:11:48 +0000 Subject: [PATCH 04/51] remove unnecessary condition --- python/tvm/relay/frontend/paddlepaddle.py | 28 +---------------------- 1 file changed, 1 insertion(+), 27 deletions(-) diff --git a/python/tvm/relay/frontend/paddlepaddle.py b/python/tvm/relay/frontend/paddlepaddle.py index 87a8679adcc2..e2beb3a15b0b 100644 --- a/python/tvm/relay/frontend/paddlepaddle.py +++ b/python/tvm/relay/frontend/paddlepaddle.py @@ -117,9 +117,6 @@ def get_pad_size(in_size, dilated_kernel_size, stride_size): pad = max(dilated_kernel_size - (in_size % stride_size), 0) return [pad // 2, pad - pad // 2] - assert op.attr( - 'data_format' - ) == 'NCHW', "Only NCHW format is support for PaddlePaddle's conv2d" dilations = op.attr('dilations') groups = op.attr('groups') paddings = op.attr('paddings') @@ -130,16 +127,6 @@ def get_pad_size(in_size, dilated_kernel_size, stride_size): input = g.get_node(op.input('Input')[0]) out_channels, _, k_h, k_w = infer_shape(kernel) in_h, in_w = infer_shape(input)[2:] - assert len( - paddings - ) == 2, "Only support len(paddings)==2 for PaddlePaddle's conv2d" - assert len( - dilations - ) == 2, "Only support len(dilations)==2 for PaddlePaddle's conv2d" - if padding_algorithm == "SAME": - pad_h = get_pad_size(in_h, (k_h - 1) * dilations[0] + 1, strides[0]) - pad_w = get_pad_size(in_w, (k_w - 1) * dilations[1] + 1, strides[1]) - paddings = [pad_h[0], pad_w[0], pad_h[1], pad_w[1]] out = _op.nn.conv2d(input, kernel, strides=strides, @@ -465,11 +452,8 @@ def flatten_to_nd(x, x_shape, nd=3): def convert_pool2d(g, op, block): """Operator converter for pool2d.""" - layout = op.attr('data_format') - assert layout == 'NCHW', "Only support NCHW format for PaddlePaddle's pool2d." adaptive = op.attr('adaptive') ceil_mode = op.attr('ceil_mode') - exclusive = op.attr('exclusive') global_pooling = op.attr('global_pooling') ksize = op.attr('ksize') paddings = op.attr('paddings') @@ -481,22 +465,12 @@ def convert_pool2d(g, op, block): 'max': 'max_pool2d', } strides = op.attr('strides') - assert exclusive, "Only support exclusive==True for PaddlePaddle's pool2d" - assert padding_algorithm == "EXPLICIT", "Only support padding_algorithm==EXPLICIT for PaddlePaddle's pool2d" if isinstance(strides, int): strides = [strides, strides] if isinstance(ksize, int): ksize = [ksize, ksize] - if isinstance(paddings, six.string_types): - msg = "Setting paddings to `SAME` or `VALID` is not support for PaddlePaddle's pool2d" - raise tvm.error.OpNotImplemented(msg) - elif isinstance(paddings, int): + if isinstance(paddings, int): paddings = [paddings] * 2 - elif len(paddings) == 2: - pass - elif len(paddings) == 4: - msg = "Only support length of paddings equals to 2 for PaddlePaddle's pool2d" - raise tvm.error.OpNotImplemented(msg) x = g.get_node(op.input('X')[0]) if not adaptive: From dfb9cb1e12f267fecea546002ef038bb84c3431d Mon Sep 17 00:00:00 2001 From: root Date: Wed, 4 Aug 2021 12:55:04 +0000 Subject: [PATCH 05/51] add TranslatedLayer which support model loaded by jit.load --- python/tvm/relay/frontend/paddlepaddle.py | 79 ++++++++++++++++------- 1 file changed, 57 insertions(+), 22 deletions(-) diff --git a/python/tvm/relay/frontend/paddlepaddle.py b/python/tvm/relay/frontend/paddlepaddle.py index e2beb3a15b0b..b517ab1969a3 100644 --- a/python/tvm/relay/frontend/paddlepaddle.py +++ b/python/tvm/relay/frontend/paddlepaddle.py @@ -221,10 +221,15 @@ def convert_activation(g, op, block): def convert_feed(g, op, block): """Converter for model input node.""" - ipt_name = op.output('Out')[0] - ipt_shape = block.var(ipt_name).shape - ipt_dtype = block.var(ipt_name).dtype - ipt_dtype = str(ipt_dtype).strip().split('.')[1] + if block is not None: + ipt_shape = block.var(ipt_name).shape + ipt_dtype = block.var(ipt_name).dtype + ipt_dtype = str(ipt_dtype).strip().split('.')[1] + ipt_name = op.output('Out')[0] + else: + ipt_shape = op.shape + ipt_dtype = str(op.dtype).strip().split('.')[1] + ipt_name = op.name if g.shape_dict is not None: ipt_shape = g.shape_dict[ipt_name] out = new_var(ipt_name, shape=ipt_shape, dtype=ipt_dtype) @@ -650,7 +655,7 @@ def get_params(self, name): assert name in self.params return self.params[name] - def extract_parameters(self, program, scope): + def extract_parameters(self, program, scope=None): """ Extract all the weights from PaddlePaddle program.""" self.params = {} @@ -694,9 +699,12 @@ def check_unsupported_ops(self, program): msg += ", ".join(unsupported_ops) raise tvm.error.OpNotImplemented(msg) - def ops_to_relay(self, program, scope): + def ops_to_relay(self, program, input_specs=None): """ Convert PaddlePaddle operators to TVM relay functions.""" + if input_specs is not None: + for input_spec in input_specs: + convert_feed(self, input_spec, None) for block in program.blocks: for i, op in enumerate(block.ops): if op.type == 'fetch': @@ -704,17 +712,7 @@ def ops_to_relay(self, program, scope): convert_func = _convert_map[op.type] convert_func(self, op, block) - def get_outputs(self, program): - """ Get outputs of PaddlePaddle model.""" - - outputs = list() - for block in program.blocks: - for i, op in enumerate(block.ops): - if op.type == "fetch": - outputs.append(op.input('X')[0]) - return outputs - - def from_paddle(self, program, shape_dict, scope): + def from_program(self, program, shape_dict, scope): """ Construct the TVM relay expression from PaddlePaddle program.""" self.shape_dict = shape_dict @@ -723,8 +721,37 @@ def from_paddle(self, program, shape_dict, scope): scope = paddle.fluid.global_scope() self.check_unsupported_ops(program) self.extract_parameters(program, scope) - self.ops_to_relay(program, scope) - output_names = self.get_outputs(program) + self.ops_to_relay(program) + + output_names = list() + for block in program.blocks: + for i, op in enumerate(block.ops): + if op.type == "fetch": + output_names.append(op.input('X')[0]) + + outputs = [self.nodes[name] for name in output_names] + outputs = outputs[0] if len(outputs) == 1 else _expr.Tuple(outputs) + + free_vars = analysis.free_vars(outputs) + func = _function.Function(free_vars, outputs) + mod = IRModule.from_expr(func) + return mod, self.params + + def from_translated_layer(self, layer, shape_dict): + """ Construct the TVM relay expression from PaddlePaddle TranslatedLayer.""" + + self.shape_dict = shape_dict + program = layer.program() + parameters = dict() + for param in layer.parameters(): + parameters[param.name] = np.array(param.value().get_tensor()) + self.check_unsupported_ops(program) + self.extract_parameters(program, parameters) + + input_specs = layer._input_spec() + self.ops_to_relay(program, input_specs) + + output_names = [x.name for x in layer._output_spec()] outputs = [self.nodes[name] for name in output_names] outputs = outputs[0] if len(outputs) == 1 else _expr.Tuple(outputs) @@ -735,14 +762,22 @@ def from_paddle(self, program, shape_dict, scope): return mod, self.params -def from_paddle(program, shape_dict=None, scope=None): +def from_paddle(program_or_layer, shape_dict=None, scope=None): """ Convert a PaddlePaddle model into an equivalent Relay Function. - PaddlePaddle Program represent the computation graph of PaddlePaddle model, + PaddlePaddle Program/TranslatedLayer represent the computation graph of PaddlePaddle model, and PaddlePaddle scope stores all the weights of PaddlePaddle model. """ import paddle g = GraphProto() - mod, params = g.from_paddle(program, shape_dict, scope) + if isinstance(program_or_layer, paddle.fluid.dygraph.TranslatedLayer): + # model is loaded by `paddle.jit.load` + mod, params = g.from_translated_layer(program_or_layer, shape_dict) + elif isinstance(program_or_layer, paddle.fluid.framework.Program): + # model is loaded by `paddle.static.load_inference_model` + mod, params = g.from_program(program_or_layer, shape_dict, scope) + else: + raise Exception( + "Only PaddlePaddle's Program and TranslatedLayer are supported.") return mod, params From 36ab16e8a58ffabb918bbe5d0f7debd9eb5c9743 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 5 Aug 2021 02:56:19 +0000 Subject: [PATCH 06/51] add mul operator support --- python/tvm/relay/frontend/paddlepaddle.py | 55 ++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/python/tvm/relay/frontend/paddlepaddle.py b/python/tvm/relay/frontend/paddlepaddle.py index b517ab1969a3..54c72ff9d628 100644 --- a/python/tvm/relay/frontend/paddlepaddle.py +++ b/python/tvm/relay/frontend/paddlepaddle.py @@ -222,10 +222,10 @@ def convert_feed(g, op, block): """Converter for model input node.""" if block is not None: + ipt_name = op.output('Out')[0] ipt_shape = block.var(ipt_name).shape ipt_dtype = block.var(ipt_name).dtype ipt_dtype = str(ipt_dtype).strip().split('.')[1] - ipt_name = op.output('Out')[0] else: ipt_shape = op.shape ipt_dtype = str(op.dtype).strip().split('.')[1] @@ -454,6 +454,55 @@ def flatten_to_nd(x, x_shape, nd=3): g.add_node(op.output('Out')[0], out) +def convert_mul(g, op, block): + """Operator converter for mul.""" + + x = g.get_node(op.input('X')[0]) + y = g.get_node(op.input('Y')[0]) + x_num_col_dims = op.attr('x_num_col_dims') + y_num_col_dims = op.attr('y_num_col_dims') + x_shape = shape_of(x) + y_shape = shape_of(y) + x_dim = infer_shape(x_shape)[0] + y_dim = infer_shape(y_shape)[0] + if x_num_col_dims < 0: + x_num_col_dims += x_dim + if y_num_col_dims < 0: + y_num_col_dims += y_dim + if x_num_col_dims == 1: + x = _op.nn.batch_flatten(x) + else: + pre_shape = _op.prod(_op.strided_slice(x_shape, [0], [x_num_col_dims], + [1]), + keepdims=True) + post_shape = _op.prod(_op.strided_slice(x_shape, [x_num_col_dims], + [x_dim], [1]), + keepdims=True) + new_shape = _op.concatenate([pre_shape, post_shape], axis=0) + new_shape = fold_constant(new_shape) + x = _op.reshape(x, new_shape) + if y_num_col_dims == 1: + y = _op.nn.batch_flatten(y) + else: + pre_shape = _op.prod(_op.strided_slice(y_shape, [0], [y_num_col_dims], + [1]), + keepdims=True) + post_shape = _op.prod(_op.strided_slice(y_shape, [y_num_col_dims], + [y_dim], [1]), + keepdims=True) + new_shape = _op.concatenate([pre_shape, post_shape], axis=0) + new_shape = fold_constant(new_shape) + y = _op.reshape(y, new_shape) + y = _op.transpose(y) + out = _op.nn.dense(x, y) + out_pre_shape = _op.strided_slice(x_shape, [0], [x_num_col_dims], [1]) + out_post_shape = _op.strided_slice(y_shape, [y_num_col_dims], [y_dim], [1]) + out_shape = _op.concatenate([out_pre_shape, out_post_shape], axis=0) + out_shape = fold_constant(out_shape) + out = _op.reshape(out, out_shape) + g.add_node(op.output('Out')[0], out) + + def convert_pool2d(g, op, block): """Operator converter for pool2d.""" @@ -464,6 +513,9 @@ def convert_pool2d(g, op, block): paddings = op.attr('paddings') padding_algorithm = op.attr('padding_algorithm') pooling_type = op.attr('pooling_type') + if global_pooling: + adaptive = True + ksize = [1, 1] op_map = { 'avg': 'avg_pool2d', @@ -624,6 +676,7 @@ def convert_unsqueeze(g, op, block): 'lookup_table_v2': convert_lookup_table, 'matmul': convert_matmul, 'matmul_v2': convert_matmul, + 'mul': convert_mul, 'pool2d': convert_pool2d, 'relu': convert_activation, 'reshape2': convert_reshape, From 63b0138e6f431fa6f5634594308b724e8f71d6cd Mon Sep 17 00:00:00 2001 From: wjj19950828 Date: Thu, 5 Aug 2021 11:37:52 +0800 Subject: [PATCH 07/51] Add padding mode support for conv/pool2d --- python/tvm/relay/frontend/paddlepaddle.py | 46 +++++++++++++++++++---- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/python/tvm/relay/frontend/paddlepaddle.py b/python/tvm/relay/frontend/paddlepaddle.py index e2beb3a15b0b..397b7dfb39f4 100644 --- a/python/tvm/relay/frontend/paddlepaddle.py +++ b/python/tvm/relay/frontend/paddlepaddle.py @@ -50,6 +50,18 @@ def shape_of(x, dtype='int32'): return _op.shape_of(x, dtype) +def _get_pad_size(in_size, dilated_kernel_size, stride_size): + if stride_size == 1 or in_size % stride_size == 0: + pad = max(dilated_kernel_size - stride_size, 0) + else: + pad = max(dilated_kernel_size - (in_size % stride_size), 0) + + pad_before = pad // 2 + pad_after = pad - pad_before + + return [pad_before, pad_after] + + def convert_arg_max(g, op, block): """Operator converter for arg_max.""" @@ -110,13 +122,6 @@ def convert_concat(g, op, block): def convert_conv2d(g, op, block): """Operator converter for conv2d.""" - def get_pad_size(in_size, dilated_kernel_size, stride_size): - if stride_size == 1 or in_size & stride_size == 0: - pad = max(dilated_kernel_size - stride_size, 0) - else: - pad = max(dilated_kernel_size - (in_size % stride_size), 0) - return [pad // 2, pad - pad // 2] - dilations = op.attr('dilations') groups = op.attr('groups') paddings = op.attr('paddings') @@ -127,6 +132,16 @@ def get_pad_size(in_size, dilated_kernel_size, stride_size): input = g.get_node(op.input('Input')[0]) out_channels, _, k_h, k_w = infer_shape(kernel) in_h, in_w = infer_shape(input)[2:] + if padding_algorithm == "VALID": + paddings = [0, 0] + elif padding_algorithm == "SAME": + pad_h = _get_pad_size(in_h, (k_h - 1) * dilations[0] + 1, strides[0]) + pad_w = _get_pad_size(in_w, (k_w - 1) * dilations[1] + 1, strides[1]) + paddings = [pad_h[0], pad_w[0], pad_h[1], pad_w[1]] + else: + msg = 'Value {} in attribute "padding" of operator Conv is not ' "valid." + raise tvm.error.OpAttributeInvalid(msg.format(padding_algorithm)) + out = _op.nn.conv2d(input, kernel, strides=strides, @@ -459,6 +474,12 @@ def convert_pool2d(g, op, block): paddings = op.attr('paddings') padding_algorithm = op.attr('padding_algorithm') pooling_type = op.attr('pooling_type') + if global_pooling: + adaptive = True + ksize = [1, 1] + + input = g.get_node(op.input('X')[0]) + in_h, in_w = infer_shape(input)[2:] op_map = { 'avg': 'avg_pool2d', @@ -472,6 +493,16 @@ def convert_pool2d(g, op, block): if isinstance(paddings, int): paddings = [paddings] * 2 + if padding_algorithm == "VALID": + paddings = [0, 0] + elif padding_algorithm == "SAME": + pad_h = _get_pad_size(in_h, ksize[0], strides[0]) + pad_w = _get_pad_size(in_w, ksize[1], strides[1]) + paddings = [pad_h[0], pad_w[0], pad_h[1], pad_w[1]] + else: + msg = 'Value {} in attribute "padding" of operator Pool2d is not ' "valid." + raise tvm.error.OpAttributeInvalid(msg.format(padding_algorithm)) + x = g.get_node(op.input('X')[0]) if not adaptive: out = getattr(_op.nn, op_map[pooling_type])(x, @@ -634,6 +665,7 @@ def convert_unsqueeze(g, op, block): class GraphProto(object): """ A helper class for handling relay functions from PaddlePaddle model.""" + def __init__(self): self.nodes = {} self.params = {} From 1967d461ddf82d7b12854cf33e3fb1d075ab532b Mon Sep 17 00:00:00 2001 From: wjj19950828 Date: Thu, 5 Aug 2021 15:22:34 +0800 Subject: [PATCH 08/51] support 4 two-tuples --- python/tvm/relay/frontend/paddlepaddle.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/python/tvm/relay/frontend/paddlepaddle.py b/python/tvm/relay/frontend/paddlepaddle.py index 397b7dfb39f4..2beca3a491db 100644 --- a/python/tvm/relay/frontend/paddlepaddle.py +++ b/python/tvm/relay/frontend/paddlepaddle.py @@ -138,6 +138,11 @@ def convert_conv2d(g, op, block): pad_h = _get_pad_size(in_h, (k_h - 1) * dilations[0] + 1, strides[0]) pad_w = _get_pad_size(in_w, (k_w - 1) * dilations[1] + 1, strides[1]) paddings = [pad_h[0], pad_w[0], pad_h[1], pad_w[1]] + elif padding_algorithm == "EXPLICIT": + if len(paddings) == 2: + paddings = [paddings[0],paddings[1],paddings[0],paddings[1]] + if len(paddings) == 4: + paddings = [paddings[0],paddings[2],paddings[1],paddings[3]] else: msg = 'Value {} in attribute "padding" of operator Conv is not ' "valid." raise tvm.error.OpAttributeInvalid(msg.format(padding_algorithm)) @@ -499,6 +504,11 @@ def convert_pool2d(g, op, block): pad_h = _get_pad_size(in_h, ksize[0], strides[0]) pad_w = _get_pad_size(in_w, ksize[1], strides[1]) paddings = [pad_h[0], pad_w[0], pad_h[1], pad_w[1]] + elif padding_algorithm == "EXPLICIT": + if len(paddings) == 2: + paddings = [paddings[0],paddings[1],paddings[0],paddings[1]] + if len(paddings) == 4: + paddings = [paddings[0],paddings[2],paddings[1],paddings[3]] else: msg = 'Value {} in attribute "padding" of operator Pool2d is not ' "valid." raise tvm.error.OpAttributeInvalid(msg.format(padding_algorithm)) From f4932bf5649e816650ef7381b9f75a85084fd1a9 Mon Sep 17 00:00:00 2001 From: heliqi <1101791222@qq.com> Date: Thu, 5 Aug 2021 20:00:48 +0800 Subject: [PATCH 09/51] add paddle test case --- .../frontend/paddlepaddle/test_forward.py | 124 ++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 tests/python/frontend/paddlepaddle/test_forward.py diff --git a/tests/python/frontend/paddlepaddle/test_forward.py b/tests/python/frontend/paddlepaddle/test_forward.py new file mode 100644 index 000000000000..1b4c960824dd --- /dev/null +++ b/tests/python/frontend/paddlepaddle/test_forward.py @@ -0,0 +1,124 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +import os +from pathlib import Path +import re + +import numpy as np +import tvm +import tvm.testing +import tvm.topi.testing +from tvm import relay +from tvm.contrib import graph_executor + +import paddle +import paddle.nn as nn + +PADDLE_TEST_DATA_ROOT_PATH = Path(Path("~").expanduser(), ".tvm_test_data", "paddle") +PADDLE_TEST_DATA_ROOT_PATH.mkdir(parents=True, exist_ok=True) + +def assert_shapes_match(tru, est): + if tru.shape != est.shape: + msg = "Output shapes {} and {} don't match" + raise AssertionError(msg.format(tru.shape, est.shape)) + +def get_paddle_model(func, input_spec): + global PADDLE_TEST_DATA_ROOT_PATH + model_path = Path(PADDLE_TEST_DATA_ROOT_PATH, "model") + + paddle.jit.save(func, str(model_path), input_spec=input_spec) + baseline_model = paddle.jit.load(str(model_path)) + + os.remove(str(model_path) + '.pdmodel') + return baseline_model + +def verify_model(func, input_data, rtol=1e-5, atol=1e-5): + if not (isinstance(input_data, list) or isinstance(input_data, tuple)): + input_data = [input_data] + + input_spec = [] + input_names = [] + input_shape_dict = {} + for idx, data in enumerate(input_data): + input_name = "input{}".format(idx) + input_spec.append(paddle.static.InputSpec(dtype=data.dtype, shape=data.shape, name=input_name)) + input_names.append(input_name) + input_shape_dict[input_name] = data.shape + + baseline_model = get_paddle_model(func, input_spec) + with paddle.no_grad(): + baseline_outputs = baseline_model(*[input.clone() for input in input_data]) + + # get paddle outputs + if isinstance(baseline_outputs, tuple): + baseline_outputs = tuple(out.numpy() for out in baseline_outputs) + else: + baseline_outputs = (baseline_outputs.numpy(),) + + mod, params = relay.frontend.from_paddle(baseline_model, input_shape_dict) + for arg in mod["main"].params[: len(input_names)]: + assert arg.name_hint in input_names + compiled_input = dict(zip(input_names, [inp.clone().numpy() for inp in input_data])) + + with tvm.transform.PassContext(opt_level=3): + for target, dev in tvm.testing.enabled_targets(): + lib = relay.build(mod, target=target, params=params) + gmod = graph_executor.GraphModule(lib["default"](dev)) + for name, inp in compiled_input.items(): + gmod.set_input(name, inp) + gmod.run() + + for i, baseline_output in enumerate(baseline_outputs): + compiled_output = gmod.get_output(i).numpy() + + assert_shapes_match(baseline_output, compiled_output) + tvm.testing.assert_allclose(baseline_output, compiled_output, rtol=rtol, atol=atol) + +@tvm.testing.uses_gpu +def test_forward_add(): + paddle.set_grad_enabled(False) + input_shape = [10] + + @paddle.jit.to_static + def add(inputs): + return paddle.add(inputs, inputs) + + @paddle.jit.to_static + def add2(inputs): + return inputs + 1 + + @paddle.jit.to_static + def add3(inputs): + ones = paddle.ones([10], dtype="float32") + return inputs + ones + + class add4(nn.Layer): + @paddle.jit.to_static + def forward(self, input1, input2): + return input1 + input2 + + input_data = paddle.rand(input_shape, dtype="float32") + verify_model(add, input_data) + verify_model(add2, input_data) + verify_model(add3, input_data) + input_data = paddle.rand([2, 3], dtype="float32") + input_data2 = paddle.rand([2, 3], dtype="float32") + model = add4() + verify_model(model, [input_data, input_data2]) + +if __name__ == "__main__": + test_forward_add() From 0c92955cb195376abe1781910601c1c6fba212b4 Mon Sep 17 00:00:00 2001 From: heliqi <1101791222@qq.com> Date: Thu, 5 Aug 2021 21:30:24 +0800 Subject: [PATCH 10/51] add paddle conv2d case --- .../frontend/paddlepaddle/test_forward.py | 69 +++++++++++++++---- 1 file changed, 56 insertions(+), 13 deletions(-) diff --git a/tests/python/frontend/paddlepaddle/test_forward.py b/tests/python/frontend/paddlepaddle/test_forward.py index 1b4c960824dd..786c0769c0d8 100644 --- a/tests/python/frontend/paddlepaddle/test_forward.py +++ b/tests/python/frontend/paddlepaddle/test_forward.py @@ -16,9 +16,10 @@ # under the License. import os from pathlib import Path -import re +import shutil import numpy as np +from paddle.fluid.layers.nn import pad import tvm import tvm.testing import tvm.topi.testing @@ -43,7 +44,7 @@ def get_paddle_model(func, input_spec): paddle.jit.save(func, str(model_path), input_spec=input_spec) baseline_model = paddle.jit.load(str(model_path)) - os.remove(str(model_path) + '.pdmodel') + shutil.rmtree(str(PADDLE_TEST_DATA_ROOT_PATH)) return baseline_model def verify_model(func, input_data, rtol=1e-5, atol=1e-5): @@ -60,8 +61,7 @@ def verify_model(func, input_data, rtol=1e-5, atol=1e-5): input_shape_dict[input_name] = data.shape baseline_model = get_paddle_model(func, input_spec) - with paddle.no_grad(): - baseline_outputs = baseline_model(*[input.clone() for input in input_data]) + baseline_outputs = baseline_model(*[input.clone() for input in input_data]) # get paddle outputs if isinstance(baseline_outputs, tuple): @@ -106,19 +106,62 @@ def add3(inputs): ones = paddle.ones([10], dtype="float32") return inputs + ones - class add4(nn.Layer): - @paddle.jit.to_static - def forward(self, input1, input2): - return input1 + input2 - input_data = paddle.rand(input_shape, dtype="float32") verify_model(add, input_data) verify_model(add2, input_data) verify_model(add3, input_data) - input_data = paddle.rand([2, 3], dtype="float32") - input_data2 = paddle.rand([2, 3], dtype="float32") - model = add4() - verify_model(model, [input_data, input_data2]) + +@tvm.testing.uses_gpu +def test_forward_conv(): + paddle.set_grad_enabled(False) + conv1d_input_shape = [1, 3, 10] + conv2d_input_shape = [1, 3, 10, 10] + + class Conv2D1(nn.Layer): + def __init__(self): + super(Conv2D1, self).__init__() + self.conv = nn.Conv2D(3, 6, 7, bias_attr=True) + self.softmax = nn.Softmax() + + @paddle.jit.to_static + def forward(self, inputs): + return self.softmax(self.conv(inputs)) + + class Conv2D2(nn.Layer): + def __init__(self): + super(Conv2D2, self).__init__() + self.conv = nn.Conv2D(3, 6, 7, groups=3, bias_attr=False) + self.softmax = nn.Softmax() + + @paddle.jit.to_static + def forward(self, inputs): + return self.softmax(self.conv(inputs)) + + class Conv1D1(nn.Layer): + def __init__(self): + super(Conv1D1, self).__init__() + self.conv = nn.Conv1D(3, 6, 7, bias_attr=True) + self.softmax = nn.Softmax() + + @paddle.jit.to_static + def forward(self, inputs): + return self.softmax(self.conv(inputs)) + + class Conv1D2(nn.Layer): + def __init__(self): + super(Conv1D2, self).__init__() + self.conv = nn.Conv1d(3, 6, 7, groups=3, bias_attr=False) + self.softmax = nn.Softmax() + + @paddle.jit.to_static + def forward(self, inputs): + return self.softmax(self.conv(inputs)) + + conv2d_input_data = paddle.rand(conv2d_input_shape, dtype="float32") + verify_model(Conv2D1(), input_data=conv2d_input_data) + verify_model(Conv2D2(), input_data=conv2d_input_data) + if __name__ == "__main__": test_forward_add() + test_forward_conv() From b0b80946ca1dda023c6c62e4dd1df092225a2a00 Mon Sep 17 00:00:00 2001 From: root Date: Fri, 6 Aug 2021 03:28:53 +0000 Subject: [PATCH 11/51] update test_forward.py --- .../frontend/paddlepaddle/test_forward.py | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/tests/python/frontend/paddlepaddle/test_forward.py b/tests/python/frontend/paddlepaddle/test_forward.py index 786c0769c0d8..1006cd799a35 100644 --- a/tests/python/frontend/paddlepaddle/test_forward.py +++ b/tests/python/frontend/paddlepaddle/test_forward.py @@ -90,7 +90,6 @@ def verify_model(func, input_data, rtol=1e-5, atol=1e-5): @tvm.testing.uses_gpu def test_forward_add(): - paddle.set_grad_enabled(False) input_shape = [10] @paddle.jit.to_static @@ -113,8 +112,6 @@ def add3(inputs): @tvm.testing.uses_gpu def test_forward_conv(): - paddle.set_grad_enabled(False) - conv1d_input_shape = [1, 3, 10] conv2d_input_shape = [1, 3, 10, 10] class Conv2D1(nn.Layer): @@ -137,26 +134,6 @@ def __init__(self): def forward(self, inputs): return self.softmax(self.conv(inputs)) - class Conv1D1(nn.Layer): - def __init__(self): - super(Conv1D1, self).__init__() - self.conv = nn.Conv1D(3, 6, 7, bias_attr=True) - self.softmax = nn.Softmax() - - @paddle.jit.to_static - def forward(self, inputs): - return self.softmax(self.conv(inputs)) - - class Conv1D2(nn.Layer): - def __init__(self): - super(Conv1D2, self).__init__() - self.conv = nn.Conv1d(3, 6, 7, groups=3, bias_attr=False) - self.softmax = nn.Softmax() - - @paddle.jit.to_static - def forward(self, inputs): - return self.softmax(self.conv(inputs)) - conv2d_input_data = paddle.rand(conv2d_input_shape, dtype="float32") verify_model(Conv2D1(), input_data=conv2d_input_data) verify_model(Conv2D2(), input_data=conv2d_input_data) From 35fccb2b16d9f583553f6586ee950333b4c8c00a Mon Sep 17 00:00:00 2001 From: heliqi <1101791222@qq.com> Date: Fri, 6 Aug 2021 16:44:41 +0800 Subject: [PATCH 12/51] fix paddle convert_matmul --- python/tvm/relay/frontend/paddlepaddle.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/python/tvm/relay/frontend/paddlepaddle.py b/python/tvm/relay/frontend/paddlepaddle.py index 54c72ff9d628..ec2cd945e456 100644 --- a/python/tvm/relay/frontend/paddlepaddle.py +++ b/python/tvm/relay/frontend/paddlepaddle.py @@ -442,9 +442,13 @@ def flatten_to_nd(x, x_shape, nd=3): ) out = _op.reshape(output, fold_constant(final_shape)) else: + if b_rank == 1: + inputs[1] = _op.expand_dims(inputs[1], 1, 1) # Otherwise a simple dense op will get the job done. input_1_t = _op.transpose(inputs[1], axes=(1, 0)) out = _op.nn.dense(inputs[0], input_1_t) + if b_rank == 1: + out = _op.squeeze(out, axis=[-1]) try: alpha = op.attr('alpha') if not np.isclose(alpha, 1.0): From 094f44ed8121e8145405699bd5f952aa17e21561 Mon Sep 17 00:00:00 2001 From: heliqi <1101791222@qq.com> Date: Fri, 6 Aug 2021 16:47:31 +0800 Subject: [PATCH 13/51] add paddle multiply and matmul op test case --- .../frontend/paddlepaddle/test_forward.py | 74 ++++++++++++++++--- 1 file changed, 63 insertions(+), 11 deletions(-) diff --git a/tests/python/frontend/paddlepaddle/test_forward.py b/tests/python/frontend/paddlepaddle/test_forward.py index 1006cd799a35..94a2c468b21a 100644 --- a/tests/python/frontend/paddlepaddle/test_forward.py +++ b/tests/python/frontend/paddlepaddle/test_forward.py @@ -89,26 +89,76 @@ def verify_model(func, input_data, rtol=1e-5, atol=1e-5): tvm.testing.assert_allclose(baseline_output, compiled_output, rtol=rtol, atol=atol) @tvm.testing.uses_gpu -def test_forward_add(): +def test_forward_add_subtract(): input_shape = [10] @paddle.jit.to_static - def add(inputs): - return paddle.add(inputs, inputs) + def add_subtract(inputs): + return paddle.subtract(paddle.add(inputs, inputs), inputs) @paddle.jit.to_static - def add2(inputs): - return inputs + 1 + def add_subtract2(inputs): + return inputs + 1 - 2 @paddle.jit.to_static - def add3(inputs): + def add_subtract3(inputs1, inputs2): ones = paddle.ones([10], dtype="float32") - return inputs + ones + return inputs1 + ones - inputs2 input_data = paddle.rand(input_shape, dtype="float32") - verify_model(add, input_data) - verify_model(add2, input_data) - verify_model(add3, input_data) + verify_model(add_subtract, input_data) + verify_model(add_subtract2, input_data) + input_data2 = paddle.rand(input_shape, dtype="float32") + verify_model(add_subtract3, [input_data, input_data2]) + +@tvm.testing.uses_gpu +def test_forward_multiply(): + input_shape = [10] + + @paddle.jit.to_static + def multiply1(inputs): + return inputs * inputs + + @paddle.jit.to_static + def multiply2(inputs): + return inputs * 1.0 + + @paddle.jit.to_static + def multiply3(inputs): + ones = paddle.ones([10], dtype="float32") + return inputs * ones + + input_data = paddle.rand(input_shape, dtype="float32") + verify_model(multiply1, input_data=input_data) + verify_model(multiply2, input_data=input_data) + verify_model(multiply3, input_data=input_data) + +@tvm.testing.uses_gpu +def test_forward_matmul(): + + class MatMul1(nn.Layer): + def forward(self, input1, input2): + return paddle.matmul(input1, input2) + + # matrix x vector + input_data1 = paddle.randn((3, 4), dtype="float32") + input_data2 = paddle.randn((4,), dtype="float32") + verify_model(MatMul1(), input_data=[input_data1, input_data2]) + + # matrix x matrix + input_data1 = paddle.randn((5, 4), dtype="float32") + input_data2 = paddle.randn((4, 5), dtype="float32") + verify_model(MatMul1(), input_data=[input_data1, input_data2]) + + # batched matrix x batched matrix + input_data1 = paddle.randn((10, 3, 4), dtype="float32") + input_data2 = paddle.randn((10, 4, 5), dtype="float32") + verify_model(MatMul1(), input_data=[input_data1, input_data2]) + + # batched matrix x broadcasted matrix + input_data1 = paddle.randn((10, 3, 4), dtype="float32") + input_data2 = paddle.randn((4, 5), dtype="float32") + verify_model(MatMul1(), input_data=[input_data1, input_data2]) @tvm.testing.uses_gpu def test_forward_conv(): @@ -140,5 +190,7 @@ def forward(self, inputs): if __name__ == "__main__": - test_forward_add() + test_forward_add_subtract() + test_forward_multiply() + test_forward_matmul() test_forward_conv() From 4520515996dba25662644a3160ce6ca661d9e6d4 Mon Sep 17 00:00:00 2001 From: heliqi <1101791222@qq.com> Date: Wed, 11 Aug 2021 20:12:10 +0800 Subject: [PATCH 14/51] add test case and fix bug --- python/tvm/relay/frontend/paddlepaddle.py | 94 +++- .../frontend/paddlepaddle/test_forward.py | 466 ++++++++++++++++-- 2 files changed, 497 insertions(+), 63 deletions(-) diff --git a/python/tvm/relay/frontend/paddlepaddle.py b/python/tvm/relay/frontend/paddlepaddle.py index 3d63826b6ea2..02f256ab3435 100644 --- a/python/tvm/relay/frontend/paddlepaddle.py +++ b/python/tvm/relay/frontend/paddlepaddle.py @@ -19,6 +19,7 @@ """Paddle: PArallel Distributed Deep LEarning.""" import copy import warnings +from pandas.core.dtypes.inference import is_scalar import six import numpy as np @@ -68,10 +69,13 @@ def convert_arg_max(g, op, block): axis = op.attr('axis') keepdims = op.attr('keepdims') flatten = op.attr('flatten') - assert not flatten, "Only flatten==True is supported for PaddlePaddle's arg_max" - x = g.get_node(x.input('X')[0]) - out = _op.argmax(x, axis=axis, keepdims=keepdims) + x = g.get_node(op.input('X')[0]) + if axis is None or flatten: + x = _op.reshape(x, [-1]) + out = _op.argmax(x, axis=None, keepdims=True) + else: + out = _op.argmax(x, axis=axis, keepdims=keepdims) g.add_node(op.output('Out')[0], out) @@ -166,9 +170,9 @@ def convert_cumsum(g, op, block): flatten = op.attr('flatten') reverse = op.attr('reverse') - assert not flatten, "Only flatten==False is supported for PaddlePaddle's cumsum" - x = g.get_node(op.input('X')[0]) + if axis is None or flatten: + x = _op.reshape(x, [-1]) if reverse: x = _op.reverse(x, axis=axis) out = _op.cumsum(x, axis=axis, exclusive=exclusive) @@ -281,6 +285,12 @@ def convert_fill_constant(g, op, block): shape = block.var(op.output('Out')[0]).shape dtype = block.var(op.output('Out')[0]).dtype dtype = str(dtype).strip().split('.')[1] + if op.input('ValueTensor'): + shape = g.get_node(op.input('ValueTensor')[0]) + shape = infer_value(shape, g.get_params()).numpy() + if op.input('ShapeTensor'): + shape = g.get_node(op.input('ShapeTensor')[0]) + shape = infer_value(shape, g.get_params()).numpy() value = np.full(shape, value, dtype) out = _expr.const(value.astype(dtype)).astype(dtype) g.add_node(op.output('Out')[0], out) @@ -333,8 +343,22 @@ def convert_layer_norm(g, op, block): begin_norm_axis = op.attr('begin_norm_axis') epsilon = op.attr('epsilon') x = g.get_node(op.input('X')[0]) - bias = g.get_node(op.input('Bias')[0]) - scale = g.get_node(op.input('Scale')[0]) + bias_input = op.input('Bias') + scale_input = op.input('Scale') + + x_shape = infer_shape(x) + assert begin_norm_axis == -1 or begin_norm_axis == len(x_shape) - 1, "Support only normalization over last one dimension." + + if bias_input: + bias = g.get_node(bias_input[0]) + else: + bias = _expr.const(np.zeros(x_shape[begin_norm_axis])) + + if scale_input: + scale = g.get_node(scale_input[0]) + else: + scale = _expr.const(np.ones(x_shape[begin_norm_axis])) + out = _op.nn.layer_norm(x, gamma=scale, beta=bias, @@ -351,7 +375,7 @@ def convert_leaky_relu(g, op, block): alpha = op.attr('alpha') x = g.get_node(op.input('X')[0]) out = _op.nn.leaky_relu(x, alpha=alpha) - g.add_node(op.output('Out')[0]) + g.add_node(op.output('Out')[0], out) def convert_lookup_table(g, op, block): @@ -540,7 +564,7 @@ def convert_pool2d(g, op, block): if global_pooling: adaptive = True ksize = [1, 1] - + input = g.get_node(op.input('X')[0]) in_h, in_w = infer_shape(input)[2:] @@ -587,8 +611,27 @@ def convert_pool2d(g, op, block): def convert_reshape(g, op, block): """Operator converter for reshape.""" - shape = op.attr('shape') - out = _op.reshape(g.get_node(op.input('X')[0]), shape) + shape_attr = op.input('Shape') + tensor_attr = op.input('ShapeTensor') + data = g.get_node(op.input('X')[0]) + if shape_attr: + new_shape = g.get_node(shape_attr[0]) + elif tensor_attr: + tmp_shape = [] + for shape_name in tensor_attr: + shape = g.get_node(shape_name) + if len(infer_shape(shape)) == 0: + shape = _op.reshape(shape, [-1]) + if isinstance(shape, _expr.Constant): + tmp_shape.append(shape) + elif isinstance(shape, _expr.Expr): + tmp_shape.append(shape) + else: + tmp_shape.append(_expr.const(np.array(shape).astype('int64'))) + new_shape = _op.concatenate(tmp_shape, axis=0) + else: + new_shape = op.attr('shape') + out = _op.reshape(data, new_shape) g.add_node(op.output('Out')[0], out) @@ -627,7 +670,7 @@ def convert_shape(g, op, block): def convert_slice(g, op, block): """Operator converter for slice.""" - def parameter_process(starts, ends, axes): + def parameter_process(starts, ends, axes, dshape): new_axes = [] new_starts = [] new_ends = [] @@ -640,22 +683,29 @@ def parameter_process(starts, ends, axes): pop_index += 1 else: new_starts.append(0) - new_ends.append(np.iinfo(np.int32).max) + new_ends.append(dshape[i]) return new_starts, new_ends, new_axes + data = g.get_node(op.input('Input')[0]) + dshape = infer_shape(data) starts = op.attr('starts') ends = op.attr('ends') axes = op.attr('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] - starts, ends, axes = parameter_process(starts, ends, axes) - out = _op.strided_slice(g.get_node(op.input('Input')[0]), + if isinstance(decrease_axis, int): + decrease_axis = [decrease_axis] + starts, ends, axes = parameter_process(starts, ends, axes, dshape) + out = _op.strided_slice(data, begin=starts, end=ends) + if decrease_axis: + out = _op.squeeze(out, axis=decrease_axis) g.add_node(op.output('Out')[0], out) @@ -672,15 +722,6 @@ def convert_softmax(g, op, block): out = e / _op.sum(e, axis, keepdims=True) g.add_node(op.output('Out')[0], out) - -def convert_transpose(g, op, block): - """Operator converter for transpose.""" - - perm = op.attr('axis') - out = _op.transpose(g.get_node(op.input('X')[0]), axes=perm) - g.add_node(op.output('Out')[0], out) - - def convert_unsqueeze(g, op, block): """Operator converter for unsqueeze.""" @@ -727,7 +768,6 @@ def convert_unsqueeze(g, op, block): 'slice': convert_slice, 'softmax': convert_softmax, 'tanh': convert_activation, - 'transpose2': convert_transpose, 'unsqueeze2': convert_unsqueeze, } @@ -747,7 +787,9 @@ def get_node(self, name): def add_node(self, name, node): self.nodes[name] = fold_constant(node) - def get_params(self, name): + def get_params(self, name=None): + if name is None: + return self.params assert name in self.params return self.params[name] diff --git a/tests/python/frontend/paddlepaddle/test_forward.py b/tests/python/frontend/paddlepaddle/test_forward.py index 94a2c468b21a..d4dea6cbe59a 100644 --- a/tests/python/frontend/paddlepaddle/test_forward.py +++ b/tests/python/frontend/paddlepaddle/test_forward.py @@ -19,7 +19,6 @@ import shutil import numpy as np -from paddle.fluid.layers.nn import pad import tvm import tvm.testing import tvm.topi.testing @@ -48,38 +47,45 @@ def get_paddle_model(func, input_spec): return baseline_model def verify_model(func, input_data, rtol=1e-5, atol=1e-5): - if not (isinstance(input_data, list) or isinstance(input_data, tuple)): + if not (isinstance(input_data, (tuple, list))): input_data = [input_data] input_spec = [] input_names = [] input_shape_dict = {} + compiled_input = {} for idx, data in enumerate(input_data): input_name = "input{}".format(idx) input_spec.append(paddle.static.InputSpec(dtype=data.dtype, shape=data.shape, name=input_name)) input_names.append(input_name) input_shape_dict[input_name] = data.shape + if isinstance(data, np.ndarray): + compiled_input[input_name] = data + else: + compiled_input[input_name] = data.numpy() baseline_model = get_paddle_model(func, input_spec) - baseline_outputs = baseline_model(*[input.clone() for input in input_data]) + baseline_outputs = baseline_model(*[input[:] for input in input_data]) # get paddle outputs - if isinstance(baseline_outputs, tuple): + if isinstance(baseline_outputs, (tuple, list)): baseline_outputs = tuple(out.numpy() for out in baseline_outputs) else: baseline_outputs = (baseline_outputs.numpy(),) mod, params = relay.frontend.from_paddle(baseline_model, input_shape_dict) - for arg in mod["main"].params[: len(input_names)]: + parms_num = min(len(input_names), len(mod["main"].params)) + compiled_names = [] + for arg in mod["main"].params[: parms_num]: assert arg.name_hint in input_names - compiled_input = dict(zip(input_names, [inp.clone().numpy() for inp in input_data])) + compiled_names.append(arg.name_hint) with tvm.transform.PassContext(opt_level=3): for target, dev in tvm.testing.enabled_targets(): lib = relay.build(mod, target=target, params=params) gmod = graph_executor.GraphModule(lib["default"](dev)) - for name, inp in compiled_input.items(): - gmod.set_input(name, inp) + for name in compiled_names: + gmod.set_input(name, compiled_input[name]) gmod.run() for i, baseline_output in enumerate(baseline_outputs): @@ -112,26 +118,310 @@ def add_subtract3(inputs1, inputs2): verify_model(add_subtract3, [input_data, input_data2]) @tvm.testing.uses_gpu -def test_forward_multiply(): - input_shape = [10] +def test_forward_argmax(): + input_shape = [1, 3, 10, 10] + + class ArgMax(nn.Layer): + @paddle.jit.to_static + def forward(self, inputs): + return paddle.argmax(inputs) + + class ArgMax1(nn.Layer): + @paddle.jit.to_static + def forward(self, inputs): + return inputs.argmax(axis=1) + + class ArgMax2(nn.Layer): + @paddle.jit.to_static + def forward(self, inputs): + return inputs.argmax(axis=1, keepdim=False) + + class ArgMax3(nn.Layer): + @paddle.jit.to_static + def forward(self, inputs): + return inputs.argmax(axis=2, keepdim=True) + + input_data = paddle.rand(input_shape, dtype="float32") + verify_model(ArgMax(), input_data=input_data) + verify_model(ArgMax1(), input_data=input_data) + verify_model(ArgMax2(), input_data=input_data) + verify_model(ArgMax3(), input_data=input_data) + +@tvm.testing.uses_gpu +def test_forward_assign(): + @paddle.jit.to_static + def assign(inputs): + return paddle.assign(inputs) + + input_shape = [2, 3] + input_data = paddle.rand(input_shape, dtype="float32") + verify_model(assign, [input_data,]) + input_data2 = np.random.randint(100, size=input_shape) + verify_model(assign, [input_data2,]) + +@tvm.testing.uses_gpu +def test_forward_batch_norm(): + class BatchNorm1D(nn.Layer): + def __init__(self): + super(BatchNorm1D, self).__init__() + self.batch_norm = nn.BatchNorm1D(2) + + @paddle.jit.to_static + def forward(self, input_data): + return self.batch_norm(input_data) + + class BatchNorm2D(nn.Layer): + def __init__(self): + super(BatchNorm2D, self).__init__() + self.batch_norm = nn.BatchNorm2D(2) + + @paddle.jit.to_static + def forward(self, input_data): + return self.batch_norm(input_data) + + class BatchNorm3D(nn.Layer): + def __init__(self): + super(BatchNorm3D, self).__init__() + self.batch_norm = nn.BatchNorm3D(2) + + @paddle.jit.to_static + def forward(self, input_data): + return self.batch_norm(input_data) + + input_data = paddle.rand((2, 2, 3), dtype="float32") + verify_model(BatchNorm1D(), input_data=input_data) + input_data = paddle.rand((2, 2, 2, 3), dtype="float32") + verify_model(BatchNorm2D(), input_data=input_data) + input_data = paddle.rand((2, 2, 2, 2, 3), dtype="float32") + verify_model(BatchNorm3D(), input_data=input_data) + +@tvm.testing.uses_gpu +def test_forward_cast(): + @paddle.jit.to_static + def cast1(inputs, dtype="uint8"): + return paddle.cast(inputs, dtype) + + @paddle.jit.to_static + def cast2(inputs, dtype="int64"): + return inputs.cast(dtype) + + input_shape = [2, 3] + input_data = paddle.rand(input_shape, dtype="float32") * 100 + verify_model(cast1, [input_data,]) + verify_model(cast2, [input_data,]) + +@tvm.testing.uses_gpu +def test_forward_concat_unsqueeze(): + @paddle.jit.to_static + def concat_unsqueeze1(inputs): + return paddle.concat([inputs[:, 0].unsqueeze(1), inputs[:, 1].unsqueeze(1)], axis=1) + + @paddle.jit.to_static + def concat_unsqueeze2(inputs): + a = (inputs[:, :, 0] + 2) * 7 + b = (inputs[:, :, 1] + 3) * 11 + c = (inputs[:, :, 2] + 5) * 13 + return paddle.concat([paddle.unsqueeze(t, axis=2) for t in [a, b, c]], axis=2) + + input_shape = [1, 3, 10, 10] + input_data = paddle.rand(input_shape, dtype="float32") + verify_model(concat_unsqueeze1, input_data=input_data) + verify_model(concat_unsqueeze2, input_data=input_data) + +@tvm.testing.uses_gpu +def test_forward_cumsum(): + @paddle.jit.to_static + def cusum1(inputs): + return paddle.cumsum(inputs) + + @paddle.jit.to_static + def cusum2(inputs): + return paddle.cumsum(inputs, axis=0) + + @paddle.jit.to_static + def cusum3(inputs): + return paddle.cumsum(inputs, axis=1) + + input_data = paddle.randint(0, 100, (10, 10), dtype=paddle.int32) + verify_model(cusum1, [input_data]) + verify_model(cusum1, [input_data.astype(paddle.int64)]) + verify_model(cusum2, [input_data, ]) + verify_model(cusum3, [input_data, ]) + +@tvm.testing.uses_gpu +def test_forward_conv(): + conv2d_input_shape = [1, 3, 10, 10] + + class Conv2D1(nn.Layer): + def __init__(self): + super(Conv2D1, self).__init__() + self.conv = nn.Conv2D(3, 6, 7, bias_attr=True) + self.softmax = nn.Softmax() + + @paddle.jit.to_static + def forward(self, inputs): + return self.softmax(self.conv(inputs)) + + class Conv2D2(nn.Layer): + def __init__(self): + super(Conv2D2, self).__init__() + self.conv = nn.Conv2D(3, 6, 7, groups=3, bias_attr=False) + self.softmax = nn.Softmax() + + @paddle.jit.to_static + def forward(self, inputs): + return self.softmax(self.conv(inputs)) + + conv2d_input_data = paddle.rand(conv2d_input_shape, dtype="float32") + verify_model(Conv2D1(), input_data=conv2d_input_data) + verify_model(Conv2D2(), input_data=conv2d_input_data) + +@tvm.testing.uses_gpu +def test_forward_dropout(): + @paddle.jit.to_static + def dropout(inputs): + return nn.functional.dropout(inputs) + + input_shape = [1, 3, 10, 10] + input_data = paddle.rand(input_shape, dtype="float32") + verify_model(dropout, input_data=input_data[0, 0]) + verify_model(dropout, input_data=input_data) + +@tvm.testing.uses_gpu +def test_forward_shape_full(): + @paddle.jit.to_static + def full1(inputs): + return paddle.full(paddle.shape(inputs), 3.14) + + @paddle.jit.to_static + def full2(inputs): + return paddle.full(paddle.shape(inputs), 1.0, dtype=inputs.dtype) + input_shape = [1, 3, 10, 10] + input_data = paddle.rand(input_shape, dtype="float32") + verify_model(full1, input_data=[input_data]) + verify_model(full2, input_data=[input_data]) + +@tvm.testing.uses_gpu +def test_forward_ones_like(): + @paddle.jit.to_static + def ones_like1(inputs): + return paddle.ones_like(inputs) + + @paddle.jit.to_static + def ones_like2(inputs): + return paddle.ones_like(inputs, dtype="int32") + + input_shape = [1, 3, 10, 10] + input_data = paddle.rand(input_shape, dtype="float32") + verify_model(ones_like1, input_data=input_data) + verify_model(ones_like2, input_data=input_data) + +@tvm.testing.uses_gpu +def test_forward_gelu(): + @paddle.jit.to_static + def gelu(inputs): + return nn.functional.gelu(inputs) + + input_shape = [1, 3, 10, 10] + input_data = paddle.rand(input_shape, dtype="float32") + verify_model(gelu, input_data=input_data) + +@tvm.testing.uses_gpu +def test_forward_hard_sigmoid(): + @paddle.jit.to_static + def hard_sigmoid(inputs): + return nn.functional.hardsigmoid(inputs) + + input_shape = [1, 3, 10, 10] + input_data = paddle.rand(input_shape, dtype="float32") + verify_model(hard_sigmoid, input_data=input_data) + +@tvm.testing.uses_gpu +def test_forward_hard_swish(): + @paddle.jit.to_static + def hard_swish(inputs): + return nn.functional.hardswish(inputs) + + input_shape = [1, 3, 10, 10] + input_data = paddle.rand(input_shape, dtype="float32") + verify_model(hard_swish, input_data=input_data) + +@tvm.testing.uses_gpu +def test_forward_layer_norm(): + @paddle.jit.to_static + def layer_norm(inputs, weight, bias): + return nn.functional.layer_norm(inputs, inputs.shape[-1], weight=weight, bias=bias) + + class LayerNorm(nn.Layer): + def __init__(self): + super(LayerNorm, self).__init__() + data_shape = [10] + self.layer_norm = nn.LayerNorm(data_shape) + + @paddle.jit.to_static + def forward(self, inputs): + return self.layer_norm(inputs) + + input_shape = [1, 3, 10, 10] + input_data = paddle.rand(input_shape, dtype="float32") + weight = paddle.rand([10], dtype="float32") + bias = paddle.rand([10], dtype="float32") + verify_model(layer_norm, input_data=[input_data, weight, bias]) + verify_model(LayerNorm(), input_data=input_data) + +@tvm.testing.uses_gpu +def test_forward_leaky_relu(): + @paddle.jit.to_static + def leaky_relu(inputs): + return nn.functional.leaky_relu(inputs) + + input_shape = [1, 3, 10, 10] + input_data = paddle.rand(input_shape, dtype="float32") + verify_model(leaky_relu, input_data=input_data) + +@tvm.testing.uses_gpu +def test_forward_look_up(): + @paddle.jit.to_static + def look_up(inputs, weight): + return nn.functional.embedding(inputs, weight) + + class LookUp(nn.Layer): + def __init__(self): + super(LookUp, self).__init__() + self.embedding = paddle.nn.Embedding(10, 4, sparse=True) + + @paddle.jit.to_static + def forward(self, inputs): + return self.embedding(inputs) + + input_shape = [1, 3, 10, 10] + input_data = paddle.randint(0, 10, input_shape, dtype="int32") + weight = paddle.rand([10, 4], dtype="float32") + verify_model(look_up, input_data=[input_data, weight]) + verify_model(LookUp(), input_data=input_data) + +@tvm.testing.uses_gpu +def test_forward_multiply(): @paddle.jit.to_static def multiply1(inputs): return inputs * inputs @paddle.jit.to_static def multiply2(inputs): - return inputs * 1.0 + return inputs * 1.0 / 2.0 @paddle.jit.to_static - def multiply3(inputs): + def multiply3(inputs, inputs2): ones = paddle.ones([10], dtype="float32") - return inputs * ones + return inputs * ones / inputs2 + input_shape = [10] input_data = paddle.rand(input_shape, dtype="float32") verify_model(multiply1, input_data=input_data) verify_model(multiply2, input_data=input_data) - verify_model(multiply3, input_data=input_data) + input_data2 = paddle.rand(input_shape, dtype="float32") + verify_model(multiply3, input_data=[input_data, input_data2]) @tvm.testing.uses_gpu def test_forward_matmul(): @@ -161,36 +451,138 @@ def forward(self, input1, input2): verify_model(MatMul1(), input_data=[input_data1, input_data2]) @tvm.testing.uses_gpu -def test_forward_conv(): - conv2d_input_shape = [1, 3, 10, 10] +def test_forward_pool2d(): + @paddle.jit.to_static + def pool2d1(inputs): + return nn.functional.avg_pool2d(inputs, kernel_size=2, stride=2, padding=0) - class Conv2D1(nn.Layer): - def __init__(self): - super(Conv2D1, self).__init__() - self.conv = nn.Conv2D(3, 6, 7, bias_attr=True) - self.softmax = nn.Softmax() - - @paddle.jit.to_static - def forward(self, inputs): - return self.softmax(self.conv(inputs)) + @paddle.jit.to_static + def pool2d2(inputs): + return nn.functional.adaptive_avg_pool2d(inputs, output_size=[3, 3]) - class Conv2D2(nn.Layer): - def __init__(self): - super(Conv2D2, self).__init__() - self.conv = nn.Conv2D(3, 6, 7, groups=3, bias_attr=False) - self.softmax = nn.Softmax() + @paddle.jit.to_static + def pool2d3(inputs): + return nn.functional.max_pool2d(inputs, kernel_size=2, stride=2, padding=0, return_mask=True) - @paddle.jit.to_static - def forward(self, inputs): - return self.softmax(self.conv(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) - conv2d_input_data = paddle.rand(conv2d_input_shape, dtype="float32") - verify_model(Conv2D1(), input_data=conv2d_input_data) - verify_model(Conv2D2(), input_data=conv2d_input_data) +@tvm.testing.uses_gpu +def test_forward_relu(): + @paddle.jit.to_static + def relu(inputs): + return nn.functional.relu(inputs) + input_shape = [10, 10] + input_data = paddle.rand(input_shape, dtype="float32") + verify_model(relu, input_data=input_data) + +@tvm.testing.uses_gpu +def test_forward_reshape(): + @paddle.jit.to_static + def reshape1(inputs, x): + new_shape = paddle.shape(x) + return paddle.reshape(inputs, new_shape) + + @paddle.jit.to_static + def reshape2(inputs): + return inputs.reshape([-1]) + + @paddle.jit.to_static + def reshape3(inputs): + data_shape = inputs.shape + return inputs.reshape([data_shape[0] * data_shape[1], data_shape[2]]) + + @paddle.jit.to_static + def reshape4(inputs, x): + new_shape = paddle.shape(x) + return paddle.reshape(inputs, [new_shape[2], 2, -1]) + + input_shape = [2, 1, 10, 1, 10] + input_data = paddle.rand(input_shape, dtype="float32") + input_data2 = paddle.randn([2, 1, 10, 10]) + verify_model(reshape1, input_data=[input_data, input_data2]) + verify_model(reshape2, input_data=input_data) + verify_model(reshape3, input_data=paddle.randn((2, 3, 4))) + verify_model(reshape4, input_data=[input_data, input_data2]) + +@tvm.testing.uses_gpu +def test_forward_scale(): + @paddle.jit.to_static + def scale1(inputs): + return paddle.scale(inputs, scale=2.0, bias=1.0) + + @paddle.jit.to_static + def scale2(inputs): + return paddle.scale(inputs, scale=3, bias=2.1, act="gelu") + + input_data = paddle.randn(shape=[2,3], dtype='float32') + verify_model(scale1, input_data=[input_data,]) + verify_model(scale2, input_data=input_data) + +@tvm.testing.uses_gpu +def test_forward_slice(): + @paddle.jit.to_static + def slice1(inputs): + return inputs[:, :, :, :3] + + @paddle.jit.to_static + def slice2(inputs): + return inputs[0, :, :-3, :] + + @paddle.jit.to_static + def slice3(inputs): + return inputs[0::2, 0::2] + inputs[1::2, 1::2] + + @paddle.jit.to_static + def slice4(inputs): + x0 = paddle.to_tensor([2]) - paddle.to_tensor([1]) + x1 = paddle.to_tensor([3]) + paddle.to_tensor([1]) + return inputs[:, x0:, 1:x1, :] + input_shape = [1, 3, 10, 10] + input_data = paddle.rand(input_shape, dtype="float32") + 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) + +@tvm.testing.uses_gpu +def test_forward_tanh(): + @paddle.jit.to_static + def tanh(inputs): + return paddle.tanh(inputs) + + input_shape = [1, 3, 10, 10] + input_data = paddle.rand(input_shape, dtype="float32") + verify_model(tanh, input_data=input_data) if __name__ == "__main__": test_forward_add_subtract() + test_forward_argmax() + test_forward_assign() + test_forward_batch_norm() + test_forward_cast() + test_forward_concat_unsqueeze() + test_forward_cumsum() + test_forward_conv() + test_forward_dropout() + test_forward_shape_full() + test_forward_ones_like() + test_forward_gelu() + test_forward_hard_sigmoid() + test_forward_hard_swish() + test_forward_layer_norm() + test_forward_leaky_relu() + test_forward_look_up() test_forward_multiply() test_forward_matmul() - test_forward_conv() + test_forward_pool2d() + test_forward_relu() + test_forward_reshape() + test_forward_scale() + test_forward_slice() + test_forward_tanh() From 1d599c1d2faf6284da38fdbc38fb2b29c419cb2a Mon Sep 17 00:00:00 2001 From: heliqi <1101791222@qq.com> Date: Wed, 11 Aug 2021 20:18:04 +0800 Subject: [PATCH 15/51] delete import pandas --- python/tvm/relay/frontend/paddlepaddle.py | 1 - 1 file changed, 1 deletion(-) diff --git a/python/tvm/relay/frontend/paddlepaddle.py b/python/tvm/relay/frontend/paddlepaddle.py index 02f256ab3435..5308c960b838 100644 --- a/python/tvm/relay/frontend/paddlepaddle.py +++ b/python/tvm/relay/frontend/paddlepaddle.py @@ -19,7 +19,6 @@ """Paddle: PArallel Distributed Deep LEarning.""" import copy import warnings -from pandas.core.dtypes.inference import is_scalar import six import numpy as np From 75ef19b0f143e3986fcf13d7fae5286d94eec5da Mon Sep 17 00:00:00 2001 From: heliqi <1101791222@qq.com> Date: Fri, 13 Aug 2021 14:45:34 +0800 Subject: [PATCH 16/51] add paddlepaddle tests --- tests/scripts/task_python_frontend.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/scripts/task_python_frontend.sh b/tests/scripts/task_python_frontend.sh index fb388a6b7edd..d25d52438daa 100755 --- a/tests/scripts/task_python_frontend.sh +++ b/tests/scripts/task_python_frontend.sh @@ -54,3 +54,6 @@ run_pytest cython python-frontend-darknet tests/python/frontend/darknet echo "Running relay PyTorch frontend test..." run_pytest cython python-frontend-pytorch tests/python/frontend/pytorch + +echo "Running relay PaddlePaddle frontend test..." +run_pytest cython python-frontend-paddlepaddle tests/python/frontend/paddlepaddle From 67ca20da4b4c921f7a1986733107b429c2e869eb Mon Sep 17 00:00:00 2001 From: heliqi <1101791222@qq.com> Date: Fri, 13 Aug 2021 15:15:22 +0800 Subject: [PATCH 17/51] modify the variable name of convert_reshape --- python/tvm/relay/frontend/paddlepaddle.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/python/tvm/relay/frontend/paddlepaddle.py b/python/tvm/relay/frontend/paddlepaddle.py index 5308c960b838..dc2e94c896b8 100644 --- a/python/tvm/relay/frontend/paddlepaddle.py +++ b/python/tvm/relay/frontend/paddlepaddle.py @@ -610,14 +610,14 @@ def convert_pool2d(g, op, block): def convert_reshape(g, op, block): """Operator converter for reshape.""" - shape_attr = op.input('Shape') - tensor_attr = op.input('ShapeTensor') + input_shape = op.input('Shape') + input_shape_tensor = op.input('ShapeTensor') data = g.get_node(op.input('X')[0]) - if shape_attr: - new_shape = g.get_node(shape_attr[0]) - elif tensor_attr: + if input_shape: + new_shape = g.get_node(input_shape[0]) + elif input_shape_tensor: tmp_shape = [] - for shape_name in tensor_attr: + for shape_name in input_shape_tensor: shape = g.get_node(shape_name) if len(infer_shape(shape)) == 0: shape = _op.reshape(shape, [-1]) From 6f91fc5150b773c542f4dd1d9cd2fb12c280df4c Mon Sep 17 00:00:00 2001 From: heliqi <1101791222@qq.com> Date: Fri, 13 Aug 2021 15:29:04 +0800 Subject: [PATCH 18/51] formatting --- python/tvm/relay/frontend/paddlepaddle.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/python/tvm/relay/frontend/paddlepaddle.py b/python/tvm/relay/frontend/paddlepaddle.py index dc2e94c896b8..c95ed0108b49 100644 --- a/python/tvm/relay/frontend/paddlepaddle.py +++ b/python/tvm/relay/frontend/paddlepaddle.py @@ -143,9 +143,9 @@ def convert_conv2d(g, op, block): paddings = [pad_h[0], pad_w[0], pad_h[1], pad_w[1]] elif padding_algorithm == "EXPLICIT": if len(paddings) == 2: - paddings = [paddings[0],paddings[1],paddings[0],paddings[1]] + paddings = [paddings[0], paddings[1], paddings[0], paddings[1]] if len(paddings) == 4: - paddings = [paddings[0],paddings[2],paddings[1],paddings[3]] + paddings = [paddings[0], paddings[2], paddings[1], paddings[3]] else: msg = 'Value {} in attribute "padding" of operator Conv is not ' "valid." raise tvm.error.OpAttributeInvalid(msg.format(padding_algorithm)) @@ -346,7 +346,8 @@ def convert_layer_norm(g, op, block): scale_input = op.input('Scale') x_shape = infer_shape(x) - assert begin_norm_axis == -1 or begin_norm_axis == len(x_shape) - 1, "Support only normalization over last one dimension." + assert begin_norm_axis == -1 or begin_norm_axis == len( + x_shape) - 1, "Support only normalization over last one dimension." if bias_input: bias = g.get_node(bias_input[0]) @@ -356,7 +357,7 @@ def convert_layer_norm(g, op, block): if scale_input: scale = g.get_node(scale_input[0]) else: - scale = _expr.const(np.ones(x_shape[begin_norm_axis])) + scale = _expr.const(np.ones(x_shape[begin_norm_axis])) out = _op.nn.layer_norm(x, gamma=scale, @@ -587,9 +588,9 @@ def convert_pool2d(g, op, block): paddings = [pad_h[0], pad_w[0], pad_h[1], pad_w[1]] elif padding_algorithm == "EXPLICIT": if len(paddings) == 2: - paddings = [paddings[0],paddings[1],paddings[0],paddings[1]] + paddings = [paddings[0], paddings[1], paddings[0], paddings[1]] if len(paddings) == 4: - paddings = [paddings[0],paddings[2],paddings[1],paddings[3]] + paddings = [paddings[0], paddings[2], paddings[1], paddings[3]] else: msg = 'Value {} in attribute "padding" of operator Pool2d is not ' "valid." raise tvm.error.OpAttributeInvalid(msg.format(padding_algorithm)) @@ -700,9 +701,7 @@ def parameter_process(starts, ends, axes, dshape): if isinstance(decrease_axis, int): decrease_axis = [decrease_axis] starts, ends, axes = parameter_process(starts, ends, axes, dshape) - out = _op.strided_slice(data, - begin=starts, - end=ends) + out = _op.strided_slice(data, begin=starts, end=ends) if decrease_axis: out = _op.squeeze(out, axis=decrease_axis) g.add_node(op.output('Out')[0], out) @@ -721,6 +720,7 @@ def convert_softmax(g, op, block): out = e / _op.sum(e, axis, keepdims=True) g.add_node(op.output('Out')[0], out) + def convert_unsqueeze(g, op, block): """Operator converter for unsqueeze.""" @@ -773,7 +773,6 @@ def convert_unsqueeze(g, op, block): class GraphProto(object): """ A helper class for handling relay functions from PaddlePaddle model.""" - def __init__(self): self.nodes = {} self.params = {} From a0aee15ccd26131d75ec45fd3f69a25c89816fc7 Mon Sep 17 00:00:00 2001 From: heliqi <1101791222@qq.com> Date: Fri, 13 Aug 2021 15:32:09 +0800 Subject: [PATCH 19/51] formatting --- .../frontend/paddlepaddle/test_forward.py | 117 ++++++++++++++---- 1 file changed, 92 insertions(+), 25 deletions(-) diff --git a/tests/python/frontend/paddlepaddle/test_forward.py b/tests/python/frontend/paddlepaddle/test_forward.py index d4dea6cbe59a..20a110f7d657 100644 --- a/tests/python/frontend/paddlepaddle/test_forward.py +++ b/tests/python/frontend/paddlepaddle/test_forward.py @@ -28,14 +28,17 @@ import paddle import paddle.nn as nn -PADDLE_TEST_DATA_ROOT_PATH = Path(Path("~").expanduser(), ".tvm_test_data", "paddle") +PADDLE_TEST_DATA_ROOT_PATH = Path( + Path("~").expanduser(), ".tvm_test_data", "paddle") PADDLE_TEST_DATA_ROOT_PATH.mkdir(parents=True, exist_ok=True) + def assert_shapes_match(tru, est): if tru.shape != est.shape: msg = "Output shapes {} and {} don't match" raise AssertionError(msg.format(tru.shape, est.shape)) + def get_paddle_model(func, input_spec): global PADDLE_TEST_DATA_ROOT_PATH model_path = Path(PADDLE_TEST_DATA_ROOT_PATH, "model") @@ -46,6 +49,7 @@ def get_paddle_model(func, input_spec): shutil.rmtree(str(PADDLE_TEST_DATA_ROOT_PATH)) return baseline_model + def verify_model(func, input_data, rtol=1e-5, atol=1e-5): if not (isinstance(input_data, (tuple, list))): input_data = [input_data] @@ -56,7 +60,10 @@ def verify_model(func, input_data, rtol=1e-5, atol=1e-5): compiled_input = {} for idx, data in enumerate(input_data): input_name = "input{}".format(idx) - input_spec.append(paddle.static.InputSpec(dtype=data.dtype, shape=data.shape, name=input_name)) + input_spec.append( + paddle.static.InputSpec(dtype=data.dtype, + shape=data.shape, + name=input_name)) input_names.append(input_name) input_shape_dict[input_name] = data.shape if isinstance(data, np.ndarray): @@ -71,15 +78,15 @@ def verify_model(func, input_data, rtol=1e-5, atol=1e-5): if isinstance(baseline_outputs, (tuple, list)): baseline_outputs = tuple(out.numpy() for out in baseline_outputs) else: - baseline_outputs = (baseline_outputs.numpy(),) + baseline_outputs = (baseline_outputs.numpy(), ) mod, params = relay.frontend.from_paddle(baseline_model, input_shape_dict) parms_num = min(len(input_names), len(mod["main"].params)) compiled_names = [] - for arg in mod["main"].params[: parms_num]: + for arg in mod["main"].params[:parms_num]: assert arg.name_hint in input_names compiled_names.append(arg.name_hint) - + with tvm.transform.PassContext(opt_level=3): for target, dev in tvm.testing.enabled_targets(): lib = relay.build(mod, target=target, params=params) @@ -92,7 +99,11 @@ def verify_model(func, input_data, rtol=1e-5, atol=1e-5): compiled_output = gmod.get_output(i).numpy() assert_shapes_match(baseline_output, compiled_output) - tvm.testing.assert_allclose(baseline_output, compiled_output, rtol=rtol, atol=atol) + tvm.testing.assert_allclose(baseline_output, + compiled_output, + rtol=rtol, + atol=atol) + @tvm.testing.uses_gpu def test_forward_add_subtract(): @@ -101,7 +112,7 @@ def test_forward_add_subtract(): @paddle.jit.to_static def add_subtract(inputs): return paddle.subtract(paddle.add(inputs, inputs), inputs) - + @paddle.jit.to_static def add_subtract2(inputs): return inputs + 1 - 2 @@ -117,6 +128,7 @@ def add_subtract3(inputs1, inputs2): input_data2 = paddle.rand(input_shape, dtype="float32") verify_model(add_subtract3, [input_data, input_data2]) + @tvm.testing.uses_gpu def test_forward_argmax(): input_shape = [1, 3, 10, 10] @@ -147,6 +159,7 @@ def forward(self, inputs): verify_model(ArgMax2(), input_data=input_data) verify_model(ArgMax3(), input_data=input_data) + @tvm.testing.uses_gpu def test_forward_assign(): @paddle.jit.to_static @@ -155,9 +168,14 @@ def assign(inputs): input_shape = [2, 3] input_data = paddle.rand(input_shape, dtype="float32") - verify_model(assign, [input_data,]) + verify_model(assign, [ + input_data, + ]) input_data2 = np.random.randint(100, size=input_shape) - verify_model(assign, [input_data2,]) + verify_model(assign, [ + input_data2, + ]) + @tvm.testing.uses_gpu def test_forward_batch_norm(): @@ -195,6 +213,7 @@ def forward(self, input_data): input_data = paddle.rand((2, 2, 2, 2, 3), dtype="float32") verify_model(BatchNorm3D(), input_data=input_data) + @tvm.testing.uses_gpu def test_forward_cast(): @paddle.jit.to_static @@ -207,27 +226,35 @@ def cast2(inputs, dtype="int64"): input_shape = [2, 3] input_data = paddle.rand(input_shape, dtype="float32") * 100 - verify_model(cast1, [input_data,]) - verify_model(cast2, [input_data,]) + verify_model(cast1, [ + input_data, + ]) + verify_model(cast2, [ + input_data, + ]) + @tvm.testing.uses_gpu def test_forward_concat_unsqueeze(): @paddle.jit.to_static def concat_unsqueeze1(inputs): - return paddle.concat([inputs[:, 0].unsqueeze(1), inputs[:, 1].unsqueeze(1)], axis=1) + return paddle.concat( + [inputs[:, 0].unsqueeze(1), inputs[:, 1].unsqueeze(1)], axis=1) @paddle.jit.to_static def concat_unsqueeze2(inputs): a = (inputs[:, :, 0] + 2) * 7 b = (inputs[:, :, 1] + 3) * 11 c = (inputs[:, :, 2] + 5) * 13 - return paddle.concat([paddle.unsqueeze(t, axis=2) for t in [a, b, c]], axis=2) + return paddle.concat([paddle.unsqueeze(t, axis=2) for t in [a, b, c]], + axis=2) input_shape = [1, 3, 10, 10] input_data = paddle.rand(input_shape, dtype="float32") verify_model(concat_unsqueeze1, input_data=input_data) verify_model(concat_unsqueeze2, input_data=input_data) + @tvm.testing.uses_gpu def test_forward_cumsum(): @paddle.jit.to_static @@ -245,8 +272,13 @@ def cusum3(inputs): input_data = paddle.randint(0, 100, (10, 10), dtype=paddle.int32) verify_model(cusum1, [input_data]) verify_model(cusum1, [input_data.astype(paddle.int64)]) - verify_model(cusum2, [input_data, ]) - verify_model(cusum3, [input_data, ]) + verify_model(cusum2, [ + input_data, + ]) + verify_model(cusum3, [ + input_data, + ]) + @tvm.testing.uses_gpu def test_forward_conv(): @@ -276,6 +308,7 @@ def forward(self, inputs): verify_model(Conv2D1(), input_data=conv2d_input_data) verify_model(Conv2D2(), input_data=conv2d_input_data) + @tvm.testing.uses_gpu def test_forward_dropout(): @paddle.jit.to_static @@ -287,6 +320,7 @@ def dropout(inputs): verify_model(dropout, input_data=input_data[0, 0]) verify_model(dropout, input_data=input_data) + @tvm.testing.uses_gpu def test_forward_shape_full(): @paddle.jit.to_static @@ -302,6 +336,7 @@ def full2(inputs): verify_model(full1, input_data=[input_data]) verify_model(full2, input_data=[input_data]) + @tvm.testing.uses_gpu def test_forward_ones_like(): @paddle.jit.to_static @@ -317,6 +352,7 @@ def ones_like2(inputs): verify_model(ones_like1, input_data=input_data) verify_model(ones_like2, input_data=input_data) + @tvm.testing.uses_gpu def test_forward_gelu(): @paddle.jit.to_static @@ -327,6 +363,7 @@ def gelu(inputs): input_data = paddle.rand(input_shape, dtype="float32") verify_model(gelu, input_data=input_data) + @tvm.testing.uses_gpu def test_forward_hard_sigmoid(): @paddle.jit.to_static @@ -337,6 +374,7 @@ def hard_sigmoid(inputs): input_data = paddle.rand(input_shape, dtype="float32") verify_model(hard_sigmoid, input_data=input_data) + @tvm.testing.uses_gpu def test_forward_hard_swish(): @paddle.jit.to_static @@ -347,11 +385,15 @@ def hard_swish(inputs): input_data = paddle.rand(input_shape, dtype="float32") verify_model(hard_swish, input_data=input_data) + @tvm.testing.uses_gpu def test_forward_layer_norm(): @paddle.jit.to_static def layer_norm(inputs, weight, bias): - return nn.functional.layer_norm(inputs, inputs.shape[-1], weight=weight, bias=bias) + return nn.functional.layer_norm(inputs, + inputs.shape[-1], + weight=weight, + bias=bias) class LayerNorm(nn.Layer): def __init__(self): @@ -370,6 +412,7 @@ def forward(self, inputs): verify_model(layer_norm, input_data=[input_data, weight, bias]) verify_model(LayerNorm(), input_data=input_data) + @tvm.testing.uses_gpu def test_forward_leaky_relu(): @paddle.jit.to_static @@ -380,6 +423,7 @@ def leaky_relu(inputs): input_data = paddle.rand(input_shape, dtype="float32") verify_model(leaky_relu, input_data=input_data) + @tvm.testing.uses_gpu def test_forward_look_up(): @paddle.jit.to_static @@ -401,6 +445,7 @@ def forward(self, inputs): verify_model(look_up, input_data=[input_data, weight]) verify_model(LookUp(), input_data=input_data) + @tvm.testing.uses_gpu def test_forward_multiply(): @paddle.jit.to_static @@ -423,16 +468,16 @@ def multiply3(inputs, inputs2): input_data2 = paddle.rand(input_shape, dtype="float32") verify_model(multiply3, input_data=[input_data, input_data2]) + @tvm.testing.uses_gpu def test_forward_matmul(): - class MatMul1(nn.Layer): def forward(self, input1, input2): return paddle.matmul(input1, input2) # matrix x vector input_data1 = paddle.randn((3, 4), dtype="float32") - input_data2 = paddle.randn((4,), dtype="float32") + input_data2 = paddle.randn((4, ), dtype="float32") verify_model(MatMul1(), input_data=[input_data1, input_data2]) # matrix x matrix @@ -450,11 +495,15 @@ def forward(self, input1, input2): input_data2 = paddle.randn((4, 5), dtype="float32") verify_model(MatMul1(), input_data=[input_data1, input_data2]) + @tvm.testing.uses_gpu def test_forward_pool2d(): @paddle.jit.to_static def pool2d1(inputs): - return nn.functional.avg_pool2d(inputs, kernel_size=2, stride=2, padding=0) + return nn.functional.avg_pool2d(inputs, + kernel_size=2, + stride=2, + padding=0) @paddle.jit.to_static def pool2d2(inputs): @@ -462,13 +511,21 @@ def pool2d2(inputs): @paddle.jit.to_static def pool2d3(inputs): - return nn.functional.max_pool2d(inputs, kernel_size=2, stride=2, padding=0, return_mask=True) - - input_data = paddle.uniform(shape=[1, 2, 32, 32], dtype='float32', min=-1, max=1) + return nn.functional.max_pool2d(inputs, + kernel_size=2, + stride=2, + padding=0, + return_mask=True) + + 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) + @tvm.testing.uses_gpu def test_forward_relu(): @paddle.jit.to_static @@ -479,6 +536,7 @@ def relu(inputs): input_data = paddle.rand(input_shape, dtype="float32") verify_model(relu, input_data=input_data) + @tvm.testing.uses_gpu def test_forward_reshape(): @paddle.jit.to_static @@ -508,6 +566,7 @@ def reshape4(inputs, x): verify_model(reshape3, input_data=paddle.randn((2, 3, 4))) verify_model(reshape4, input_data=[input_data, input_data2]) + @tvm.testing.uses_gpu def test_forward_scale(): @paddle.jit.to_static @@ -518,10 +577,13 @@ def scale1(inputs): def scale2(inputs): return paddle.scale(inputs, scale=3, bias=2.1, act="gelu") - input_data = paddle.randn(shape=[2,3], dtype='float32') - verify_model(scale1, input_data=[input_data,]) + input_data = paddle.randn(shape=[2, 3], dtype='float32') + verify_model(scale1, input_data=[ + input_data, + ]) verify_model(scale2, input_data=input_data) + @tvm.testing.uses_gpu def test_forward_slice(): @paddle.jit.to_static @@ -541,15 +603,19 @@ def slice4(inputs): x0 = paddle.to_tensor([2]) - paddle.to_tensor([1]) x1 = paddle.to_tensor([3]) + paddle.to_tensor([1]) return inputs[:, x0:, 1:x1, :] + 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) + @tvm.testing.uses_gpu def test_forward_tanh(): @paddle.jit.to_static @@ -560,6 +626,7 @@ def tanh(inputs): input_data = paddle.rand(input_shape, dtype="float32") verify_model(tanh, input_data=input_data) + if __name__ == "__main__": test_forward_add_subtract() test_forward_argmax() From 80d308a8e096e0ac1cd4781c8e69aa5267c25e0d Mon Sep 17 00:00:00 2001 From: root Date: Fri, 13 Aug 2021 07:55:21 +0000 Subject: [PATCH 20/51] use black to format python code --- python/tvm/relay/frontend/paddlepaddle.py | 563 +++++++++--------- .../frontend/paddlepaddle/test_forward.py | 122 ++-- 2 files changed, 343 insertions(+), 342 deletions(-) diff --git a/python/tvm/relay/frontend/paddlepaddle.py b/python/tvm/relay/frontend/paddlepaddle.py index c95ed0108b49..c67c8b9c39e0 100644 --- a/python/tvm/relay/frontend/paddlepaddle.py +++ b/python/tvm/relay/frontend/paddlepaddle.py @@ -42,7 +42,7 @@ __all__ = ["from_paddle"] -def shape_of(x, dtype='int32'): +def shape_of(x, dtype="int32"): ttype = infer_type(x).checked_type if not _ty.is_dynamic(ttype): shape = list(ttype.shape) @@ -65,74 +65,76 @@ def _get_pad_size(in_size, dilated_kernel_size, stride_size): def convert_arg_max(g, op, block): """Operator converter for arg_max.""" - axis = op.attr('axis') - keepdims = op.attr('keepdims') - flatten = op.attr('flatten') + axis = op.attr("axis") + keepdims = op.attr("keepdims") + flatten = op.attr("flatten") - x = g.get_node(op.input('X')[0]) + x = g.get_node(op.input("X")[0]) if axis is None or flatten: x = _op.reshape(x, [-1]) out = _op.argmax(x, axis=None, keepdims=True) else: out = _op.argmax(x, axis=axis, keepdims=keepdims) - g.add_node(op.output('Out')[0], out) + g.add_node(op.output("Out")[0], out) def convert_assign(g, op, block): """Operator converter for assign.""" - out = _op.copy(g.get_node(op.input('X')[0])) - g.add_node(op.output('Out')[0], out) + out = _op.copy(g.get_node(op.input("X")[0])) + g.add_node(op.output("Out")[0], out) def convert_batch_norm(g, op, block): """Operator converter for batch_norm.""" - ipt_name = op.input('X')[0] - scale_name = op.input('Scale')[0] - bias_name = op.input('Bias')[0] - mean_name = op.input('Mean')[0] - variance_name = op.input('Variance')[0] - epsilon = op.attr('epsilon') - momentum = op.attr('momentum') - out = _op.nn.batch_norm(g.get_node(ipt_name), - g.get_node(scale_name), - g.get_node(bias_name), - g.get_node(mean_name), - g.get_node(variance_name), - epsilon=epsilon) - g.add_node(op.output('Y')[0], out[0]) + ipt_name = op.input("X")[0] + scale_name = op.input("Scale")[0] + bias_name = op.input("Bias")[0] + mean_name = op.input("Mean")[0] + variance_name = op.input("Variance")[0] + epsilon = op.attr("epsilon") + momentum = op.attr("momentum") + out = _op.nn.batch_norm( + g.get_node(ipt_name), + g.get_node(scale_name), + g.get_node(bias_name), + g.get_node(mean_name), + g.get_node(variance_name), + epsilon=epsilon, + ) + g.add_node(op.output("Y")[0], out[0]) def convert_cast(g, op, block): """Operator converter for cast.""" - dtype = block.var(op.output('Out')[0]).dtype - dtype = str(dtype).strip().split('.')[1] - x = g.get_node(op.input('X')[0]) + dtype = block.var(op.output("Out")[0]).dtype + dtype = str(dtype).strip().split(".")[1] + x = g.get_node(op.input("X")[0]) out = _op.cast(x, dtype=dtype) - g.add_node(op.output('Out')[0], out) + g.add_node(op.output("Out")[0], out) def convert_concat(g, op, block): """Operator converter for concat.""" - inputs = [g.get_node(op.input('X')[i]) for i in range(len(op.input('X')))] - axis = op.attr('axis') + inputs = [g.get_node(op.input("X")[i]) for i in range(len(op.input("X")))] + axis = op.attr("axis") out = _op.concatenate(inputs, axis=axis) - g.add_node(op.output('Out')[0], out) + g.add_node(op.output("Out")[0], out) def convert_conv2d(g, op, block): """Operator converter for conv2d.""" - dilations = op.attr('dilations') - groups = op.attr('groups') - paddings = op.attr('paddings') - padding_algorithm = op.attr('padding_algorithm') - strides = op.attr('strides') - - kernel = g.get_node(op.input('Filter')[0]) - input = g.get_node(op.input('Input')[0]) + dilations = op.attr("dilations") + groups = op.attr("groups") + paddings = op.attr("paddings") + padding_algorithm = op.attr("padding_algorithm") + strides = op.attr("strides") + + kernel = g.get_node(op.input("Filter")[0]) + input = g.get_node(op.input("Input")[0]) out_channels, _, k_h, k_w = infer_shape(kernel) in_h, in_w = infer_shape(input)[2:] if padding_algorithm == "VALID": @@ -150,26 +152,28 @@ def convert_conv2d(g, op, block): msg = 'Value {} in attribute "padding" of operator Conv is not ' "valid." raise tvm.error.OpAttributeInvalid(msg.format(padding_algorithm)) - out = _op.nn.conv2d(input, - kernel, - strides=strides, - padding=paddings, - dilation=dilations, - groups=groups, - channels=out_channels, - kernel_size=[k_h, k_w]) - g.add_node(op.output('Output')[0], out) + out = _op.nn.conv2d( + input, + kernel, + strides=strides, + padding=paddings, + dilation=dilations, + groups=groups, + channels=out_channels, + kernel_size=[k_h, k_w], + ) + g.add_node(op.output("Output")[0], out) def convert_cumsum(g, op, block): """Operator converter for cumsum.""" - axis = op.attr('axis') - exclusive = op.attr('exclusive') - flatten = op.attr('flatten') - reverse = op.attr('reverse') + axis = op.attr("axis") + exclusive = op.attr("exclusive") + flatten = op.attr("flatten") + reverse = op.attr("reverse") - x = g.get_node(op.input('X')[0]) + x = g.get_node(op.input("X")[0]) if axis is None or flatten: x = _op.reshape(x, [-1]) if reverse: @@ -178,80 +182,78 @@ def convert_cumsum(g, op, block): out = _op.reverse(out, axis=axis) else: out = _op.cumsum(x, axis=axis, exclusive=exclusive) - g.add_node(op.output('Out')[0], out) + g.add_node(op.output("Out")[0], out) def convert_dropout(g, op, block): """Operator converter for dropout.""" - x = g.get_node(op.input('X')[0]) + x = g.get_node(op.input("X")[0]) out = _op.copy(x) - g.add_node(op.output('Out')[0], out) + g.add_node(op.output("Out")[0], out) 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': lambda x, y: x % y, + "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": lambda x, y: x % y, } op_func = op_map[op.type] - ipt0 = g.get_node(op.input('X')[0]) - ipt1 = g.get_node(op.input('Y')[0]) - ipt0_shape = block.var(op.input('X')[0]).shape - ipt1_shape = block.var(op.input('Y')[0]).shape - axis = op.attr('axis') + ipt0 = g.get_node(op.input("X")[0]) + ipt1 = g.get_node(op.input("Y")[0]) + ipt0_shape = block.var(op.input("X")[0]).shape + ipt1_shape = block.var(op.input("Y")[0]).shape + axis = op.attr("axis") if len(ipt0_shape) != len(ipt1_shape): if axis < 0: 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)) + ipt1 = _op.expand_dims(ipt1, axis=axis, num_newaxis=(len(ipt0_shape) - axis - 1)) out = op_func(ipt0, ipt1) - g.add_node(op.output('Out')[0], out) + 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]) + 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) + g.add_node(op.output("Out")[0], out) def convert_activation(g, op, block): """Operator converter for all the activation.""" op_map = { - 'exp': _op.exp, - 'relu': _op.nn.relu, - 'tanh': _op.tanh, - 'sqrt': _op.sqrt, - 'erf': _op.erf, - 'abs': _op.abs, + "exp": _op.exp, + "relu": _op.nn.relu, + "tanh": _op.tanh, + "sqrt": _op.sqrt, + "erf": _op.erf, + "abs": _op.abs, } act_func = op_map[op.type] - out = act_func(g.get_node(op.input('X')[0])) - g.add_node(op.output('Out')[0], out) + out = act_func(g.get_node(op.input("X")[0])) + g.add_node(op.output("Out")[0], out) def convert_feed(g, op, block): """Converter for model input node.""" if block is not None: - ipt_name = op.output('Out')[0] + ipt_name = op.output("Out")[0] ipt_shape = block.var(ipt_name).shape ipt_dtype = block.var(ipt_name).dtype - ipt_dtype = str(ipt_dtype).strip().split('.')[1] + ipt_dtype = str(ipt_dtype).strip().split(".")[1] else: ipt_shape = op.shape - ipt_dtype = str(op.dtype).strip().split('.')[1] + ipt_dtype = str(op.dtype).strip().split(".")[1] ipt_name = op.name if g.shape_dict is not None: ipt_shape = g.shape_dict[ipt_name] @@ -262,92 +264,90 @@ def convert_feed(g, op, block): def convert_fill_any_like(g, op, block): """Operator converter for fill_any_like.""" - out_name = op.output('Out')[0] + out_name = op.output("Out")[0] out_dtype = block.var(out_name).dtype - out_dtype = str(out_dtype).strip().split('.')[1] - x = g.get_node(op.input('X')[0]) + out_dtype = str(out_dtype).strip().split(".")[1] + x = g.get_node(op.input("X")[0]) ipt_type = infer_type(x).checked_type - value = op.attr('value') + value = op.attr("value") if not _ty.is_dynamic(ipt_type): shape = infer_shape(x) const = np.ones(shape) * value out = _expr.const(const.astype(out_dtype)) else: out = _op.transform.full_like(x, value).astype(out_dtype) - g.add_node(op.output('Out')[0], out) + g.add_node(op.output("Out")[0], out) def convert_fill_constant(g, op, block): """Operator converter for fill_constant.""" - value = op.attr('value') - shape = block.var(op.output('Out')[0]).shape - dtype = block.var(op.output('Out')[0]).dtype - dtype = str(dtype).strip().split('.')[1] - if op.input('ValueTensor'): - shape = g.get_node(op.input('ValueTensor')[0]) + value = op.attr("value") + shape = block.var(op.output("Out")[0]).shape + dtype = block.var(op.output("Out")[0]).dtype + dtype = str(dtype).strip().split(".")[1] + if op.input("ValueTensor"): + shape = g.get_node(op.input("ValueTensor")[0]) shape = infer_value(shape, g.get_params()).numpy() - if op.input('ShapeTensor'): - shape = g.get_node(op.input('ShapeTensor')[0]) + if op.input("ShapeTensor"): + shape = g.get_node(op.input("ShapeTensor")[0]) shape = infer_value(shape, g.get_params()).numpy() value = np.full(shape, value, dtype) out = _expr.const(value.astype(dtype)).astype(dtype) - g.add_node(op.output('Out')[0], out) + g.add_node(op.output("Out")[0], out) def convert_gelu(g, op, block): """Operator converter for gelu.""" - x = g.get_node(op.input('X')[0]) - out = x * (_expr.const(0.5, dtype='float32') + - _op.erf(x * _expr.const(0.5**0.5, dtype='float32')) * - _expr.const(0.5, dtype='float32')) - g.add_node(op.output('Out')[0], out) + x = g.get_node(op.input("X")[0]) + out = x * ( + _expr.const(0.5, dtype="float32") + + _op.erf(x * _expr.const(0.5 ** 0.5, dtype="float32")) * _expr.const(0.5, dtype="float32") + ) + g.add_node(op.output("Out")[0], out) def convert_hard_sigmoid(g, op, block): """Operator converter for hard_sigmoid.""" - slope = op.attr('slope') - offset = op.attr('offset') - x = g.get_node(op.input('X')[0]) + slope = op.attr("slope") + offset = op.attr("offset") + x = g.get_node(op.input("X")[0]) out = x * _expr.const(slope) + _expr.const(0.5) out = _op.clip(out, 0, 1) - g.add_node(op.output('Out')[0], out) + g.add_node(op.output("Out")[0], out) def convert_hard_swish(g, op, block): """Operator converter for hard_swish.""" - offset = op.attr('offset') - scale = op.attr('scale') - threshold = op.attr('threshold') - assert np.isclose( - offset, 3.0), "Only support offset==3.0 for PaddlePaddle's hard_swish" - assert np.isclose( - scale, 6.0), "Only support scale==6.0 for PaddlePaddle's hard_swish" - assert np.isclose( - threshold, - 6.0), "Only support threshold==6.0 for PaddlePaddle's hard_swish" - x = g.get_node(op.input('X')[0]) + offset = op.attr("offset") + scale = op.attr("scale") + threshold = op.attr("threshold") + assert np.isclose(offset, 3.0), "Only support offset==3.0 for PaddlePaddle's hard_swish" + assert np.isclose(scale, 6.0), "Only support scale==6.0 for PaddlePaddle's hard_swish" + assert np.isclose(threshold, 6.0), "Only support threshold==6.0 for PaddlePaddle's hard_swish" + x = g.get_node(op.input("X")[0]) out = _op.clip(x, -1 * offset, offset) out = out / _expr.const(threshold) + _expr.const(0.5) out = x * out - g.add_node(op.output('Out')[0], out) + g.add_node(op.output("Out")[0], out) def convert_layer_norm(g, op, block): """Operator converter for layer_norm.""" - begin_norm_axis = op.attr('begin_norm_axis') - epsilon = op.attr('epsilon') - x = g.get_node(op.input('X')[0]) - bias_input = op.input('Bias') - scale_input = op.input('Scale') + begin_norm_axis = op.attr("begin_norm_axis") + epsilon = op.attr("epsilon") + x = g.get_node(op.input("X")[0]) + bias_input = op.input("Bias") + scale_input = op.input("Scale") x_shape = infer_shape(x) - assert begin_norm_axis == -1 or begin_norm_axis == len( - x_shape) - 1, "Support only normalization over last one dimension." + assert ( + begin_norm_axis == -1 or begin_norm_axis == len(x_shape) - 1 + ), "Support only normalization over last one dimension." if bias_input: bias = g.get_node(bias_input[0]) @@ -359,54 +359,50 @@ def convert_layer_norm(g, op, block): else: scale = _expr.const(np.ones(x_shape[begin_norm_axis])) - out = _op.nn.layer_norm(x, - gamma=scale, - beta=bias, - axis=begin_norm_axis, - epsilon=epsilon, - center=True, - scale=True) - g.add_node(op.output('Y')[0], out) + out = _op.nn.layer_norm( + x, gamma=scale, beta=bias, axis=begin_norm_axis, epsilon=epsilon, center=True, scale=True + ) + g.add_node(op.output("Y")[0], out) def convert_leaky_relu(g, op, block): """Operator converter for leaky_relu.""" - alpha = op.attr('alpha') - x = g.get_node(op.input('X')[0]) + alpha = op.attr("alpha") + x = g.get_node(op.input("X")[0]) out = _op.nn.leaky_relu(x, alpha=alpha) - g.add_node(op.output('Out')[0], out) + g.add_node(op.output("Out")[0], out) def convert_lookup_table(g, op, block): """Operator converter for lookup_table_v2.""" - indices = g.get_node(op.input('Ids')[0]) - padding_idx = op.attr('padding_idx') - is_sparse = op.attr('is_sparse') - height_sections = op.attr('height_sections') + indices = g.get_node(op.input("Ids")[0]) + padding_idx = op.attr("padding_idx") + is_sparse = op.attr("is_sparse") + height_sections = op.attr("height_sections") if padding_idx != -1: - g.get_params[op.input('W')[0]][padding_idx] = 0.0 - g.add_node(op.input('W')[0], _expr.const(g.params[op.input('W')[0]])) - weights = g.get_node(op.input('W')[0]) - out = _op.take(weights, indices.astype('int32'), axis=0) - g.add_node(op.output('Out')[0], out) + g.get_params[op.input("W")[0]][padding_idx] = 0.0 + g.add_node(op.input("W")[0], _expr.const(g.params[op.input("W")[0]])) + weights = g.get_node(op.input("W")[0]) + out = _op.take(weights, indices.astype("int32"), axis=0) + g.add_node(op.output("Out")[0], out) def convert_matmul(g, op, block): """Operator converter for matmul.""" - inputs = [g.get_node(op.input('X')[0]), g.get_node(op.input('Y')[0])] + inputs = [g.get_node(op.input("X")[0]), g.get_node(op.input("Y")[0])] a_shape = infer_shape(inputs[0]) b_shape = infer_shape(inputs[1]) try: # for matmul_v2 - trans_x = op.attr('trans_x') - trans_y = op.attr('trans_y') + trans_x = op.attr("trans_x") + trans_y = op.attr("trans_y") except: # for matmul - trans_x = op.attr('transpose_X') - trans_y = op.attr('transpose_Y') + trans_x = op.attr("transpose_X") + trans_y = op.attr("transpose_Y") if trans_x: perm = list(range(len(a_shape))) perm[-2] = len(a_shape) - 1 @@ -433,8 +429,7 @@ def flatten_to_nd(x, x_shape, nd=3): return x newshape = _op.concatenate( [ - _expr.const([-1], - dtype=infer_type(x_shape).checked_type.dtype), + _expr.const([-1], dtype=infer_type(x_shape).checked_type.dtype), _op.strided_slice(x_shape, [ndims - nd + 1], [ndims]), ], 0, @@ -469,7 +464,8 @@ def flatten_to_nd(x, x_shape, nd=3): _op.maximum( _op.strided_slice(a_shape, [i], [i + 1]), _op.strided_slice(b_shape, [i], [i + 1]), - ) for i in range(a_rank - 2) + ) + for i in range(a_rank - 2) ], 0, ) @@ -477,10 +473,12 @@ def flatten_to_nd(x, x_shape, nd=3): final_shape = _op.concatenate( [ out_batch, - _op.strided_slice(a_shape, [infer_shape(a_shape)[0] - 2], - [infer_shape(a_shape)[0] - 1]), - _op.strided_slice(b_shape, [infer_shape(b_shape)[0] - 1], - [infer_shape(b_shape)[0]]), + _op.strided_slice( + a_shape, [infer_shape(a_shape)[0] - 2], [infer_shape(a_shape)[0] - 1] + ), + _op.strided_slice( + b_shape, [infer_shape(b_shape)[0] - 1], [infer_shape(b_shape)[0]] + ), ], 0, ) @@ -494,21 +492,21 @@ def flatten_to_nd(x, x_shape, nd=3): if b_rank == 1: out = _op.squeeze(out, axis=[-1]) try: - alpha = op.attr('alpha') + alpha = op.attr("alpha") if not np.isclose(alpha, 1.0): - out = out * _expr.const(alpha).astype('float32') + out = out * _expr.const(alpha).astype("float32") except: pass - g.add_node(op.output('Out')[0], out) + g.add_node(op.output("Out")[0], out) def convert_mul(g, op, block): """Operator converter for mul.""" - x = g.get_node(op.input('X')[0]) - y = g.get_node(op.input('Y')[0]) - x_num_col_dims = op.attr('x_num_col_dims') - y_num_col_dims = op.attr('y_num_col_dims') + x = g.get_node(op.input("X")[0]) + y = g.get_node(op.input("Y")[0]) + x_num_col_dims = op.attr("x_num_col_dims") + y_num_col_dims = op.attr("y_num_col_dims") x_shape = shape_of(x) y_shape = shape_of(y) x_dim = infer_shape(x_shape)[0] @@ -520,24 +518,20 @@ def convert_mul(g, op, block): if x_num_col_dims == 1: x = _op.nn.batch_flatten(x) else: - pre_shape = _op.prod(_op.strided_slice(x_shape, [0], [x_num_col_dims], - [1]), - keepdims=True) - post_shape = _op.prod(_op.strided_slice(x_shape, [x_num_col_dims], - [x_dim], [1]), - keepdims=True) + pre_shape = _op.prod(_op.strided_slice(x_shape, [0], [x_num_col_dims], [1]), keepdims=True) + post_shape = _op.prod( + _op.strided_slice(x_shape, [x_num_col_dims], [x_dim], [1]), keepdims=True + ) new_shape = _op.concatenate([pre_shape, post_shape], axis=0) new_shape = fold_constant(new_shape) x = _op.reshape(x, new_shape) if y_num_col_dims == 1: y = _op.nn.batch_flatten(y) else: - pre_shape = _op.prod(_op.strided_slice(y_shape, [0], [y_num_col_dims], - [1]), - keepdims=True) - post_shape = _op.prod(_op.strided_slice(y_shape, [y_num_col_dims], - [y_dim], [1]), - keepdims=True) + pre_shape = _op.prod(_op.strided_slice(y_shape, [0], [y_num_col_dims], [1]), keepdims=True) + post_shape = _op.prod( + _op.strided_slice(y_shape, [y_num_col_dims], [y_dim], [1]), keepdims=True + ) new_shape = _op.concatenate([pre_shape, post_shape], axis=0) new_shape = fold_constant(new_shape) y = _op.reshape(y, new_shape) @@ -548,31 +542,31 @@ def convert_mul(g, op, block): out_shape = _op.concatenate([out_pre_shape, out_post_shape], axis=0) out_shape = fold_constant(out_shape) out = _op.reshape(out, out_shape) - g.add_node(op.output('Out')[0], out) + g.add_node(op.output("Out")[0], out) def convert_pool2d(g, op, block): """Operator converter for pool2d.""" - adaptive = op.attr('adaptive') - ceil_mode = op.attr('ceil_mode') - global_pooling = op.attr('global_pooling') - ksize = op.attr('ksize') - paddings = op.attr('paddings') - padding_algorithm = op.attr('padding_algorithm') - pooling_type = op.attr('pooling_type') + adaptive = op.attr("adaptive") + ceil_mode = op.attr("ceil_mode") + global_pooling = op.attr("global_pooling") + ksize = op.attr("ksize") + paddings = op.attr("paddings") + padding_algorithm = op.attr("padding_algorithm") + pooling_type = op.attr("pooling_type") if global_pooling: adaptive = True ksize = [1, 1] - input = g.get_node(op.input('X')[0]) + input = g.get_node(op.input("X")[0]) in_h, in_w = infer_shape(input)[2:] op_map = { - 'avg': 'avg_pool2d', - 'max': 'max_pool2d', + "avg": "avg_pool2d", + "max": "max_pool2d", } - strides = op.attr('strides') + strides = op.attr("strides") if isinstance(strides, int): strides = [strides, strides] if isinstance(ksize, int): @@ -595,25 +589,22 @@ def convert_pool2d(g, op, block): msg = 'Value {} in attribute "padding" of operator Pool2d is not ' "valid." raise tvm.error.OpAttributeInvalid(msg.format(padding_algorithm)) - x = g.get_node(op.input('X')[0]) + x = g.get_node(op.input("X")[0]) if not adaptive: - out = getattr(_op.nn, op_map[pooling_type])(x, - pool_size=ksize, - strides=strides, - padding=paddings, - ceil_mode=ceil_mode) + out = getattr(_op.nn, op_map[pooling_type])( + x, pool_size=ksize, strides=strides, padding=paddings, ceil_mode=ceil_mode + ) else: - out = getattr(_op.nn, - "adaptive_" + op_map[pooling_type])(x, output_size=ksize) - g.add_node(op.output('Out')[0], out) + out = getattr(_op.nn, "adaptive_" + op_map[pooling_type])(x, output_size=ksize) + g.add_node(op.output("Out")[0], out) def convert_reshape(g, op, block): """Operator converter for reshape.""" - input_shape = op.input('Shape') - input_shape_tensor = op.input('ShapeTensor') - data = g.get_node(op.input('X')[0]) + input_shape = op.input("Shape") + input_shape_tensor = op.input("ShapeTensor") + data = g.get_node(op.input("X")[0]) if input_shape: new_shape = g.get_node(input_shape[0]) elif input_shape_tensor: @@ -627,49 +618,51 @@ def convert_reshape(g, op, block): elif isinstance(shape, _expr.Expr): tmp_shape.append(shape) else: - tmp_shape.append(_expr.const(np.array(shape).astype('int64'))) + tmp_shape.append(_expr.const(np.array(shape).astype("int64"))) new_shape = _op.concatenate(tmp_shape, axis=0) else: - new_shape = op.attr('shape') + new_shape = op.attr("shape") out = _op.reshape(data, new_shape) - g.add_node(op.output('Out')[0], out) + g.add_node(op.output("Out")[0], out) def convert_scale(g, op, block): """Operator converter for scale.""" - scale = op.attr('scale') - bias = op.attr('bias') - bias_after_scale = op.attr('bias_after_scale') - x = g.get_node(op.input('X')[0]) + scale = op.attr("scale") + bias = op.attr("bias") + bias_after_scale = op.attr("bias_after_scale") + x = g.get_node(op.input("X")[0]) if np.isclose(scale, 1.0) and np.isclose(bias, 0.0): out = _op.copy(x) else: if np.isclose(bias, 0.0): - out = x * _expr.const(np.array(scale).astype('float32')) + out = x * _expr.const(np.array(scale).astype("float32")) elif np.isclose(scale, 1.0): - out = x + _expr.const(np.array(bias).astype('float32')) + out = x + _expr.const(np.array(bias).astype("float32")) else: if bias_after_scale: - out = x * _expr.const( - np.array(scale).astype('float32')) + _expr.const( - np.array(bias).astype('float32')) + out = x * _expr.const(np.array(scale).astype("float32")) + _expr.const( + np.array(bias).astype("float32") + ) else: - out = (x + _expr.const(np.array(bias).astype('float32')) - ) * _expr.const(np.array(scale).astype('float32')) - g.add_node(op.output('Out')[0], out) + out = (x + _expr.const(np.array(bias).astype("float32"))) * _expr.const( + np.array(scale).astype("float32") + ) + g.add_node(op.output("Out")[0], out) def convert_shape(g, op, block): """Operator converter for shape.""" - x = g.get_node(op.input('Input')[0]) + x = g.get_node(op.input("Input")[0]) out = shape_of(x) - g.add_node(op.output('Out')[0], out) + g.add_node(op.output("Out")[0], out) def convert_slice(g, op, block): """Operator converter for slice.""" + def parameter_process(starts, ends, axes, dshape): new_axes = [] new_starts = [] @@ -686,12 +679,12 @@ def parameter_process(starts, ends, axes, dshape): new_ends.append(dshape[i]) return new_starts, new_ends, new_axes - data = g.get_node(op.input('Input')[0]) + data = g.get_node(op.input("Input")[0]) dshape = infer_shape(data) - starts = op.attr('starts') - ends = op.attr('ends') - axes = op.attr('axes') - decrease_axis = op.attr('decrease_axis') + starts = op.attr("starts") + ends = op.attr("ends") + axes = op.attr("axes") + decrease_axis = op.attr("decrease_axis") if isinstance(starts, int): starts = [starts] if isinstance(ends, int): @@ -704,75 +697,76 @@ def parameter_process(starts, ends, axes, dshape): out = _op.strided_slice(data, begin=starts, end=ends) if decrease_axis: out = _op.squeeze(out, axis=decrease_axis) - g.add_node(op.output('Out')[0], out) + g.add_node(op.output("Out")[0], out) def convert_softmax(g, op, block): """Operator converter for softmax.""" - axis = op.attr('axis') - input_shape = block.var(op.input('X')[0]).shape + axis = op.attr("axis") + input_shape = block.var(op.input("X")[0]).shape if axis < 0: axis = len(input_shape) + axis - x = g.get_node(op.input('X')[0]) + x = g.get_node(op.input("X")[0]) m = _op.max(x, axis, keepdims=True) e = _op.exp(x - m) out = e / _op.sum(e, axis, keepdims=True) - g.add_node(op.output('Out')[0], out) + g.add_node(op.output("Out")[0], out) def convert_unsqueeze(g, op, block): """Operator converter for unsqueeze.""" - x = g.get_node(op.input('X')[0]) - axes = sorted(op.attr('axes')) + x = g.get_node(op.input("X")[0]) + axes = sorted(op.attr("axes")) for axis in axes: x = _op.expand_dims(x, axis=axis, num_newaxis=1) - g.add_node(op.output('Out')[0], x) + g.add_node(op.output("Out")[0], x) _convert_map = { - 'arg_max': convert_arg_max, - 'assign': convert_assign, - 'batch_norm': convert_batch_norm, - 'cast': convert_cast, - 'concat': convert_concat, - 'conv2d': convert_conv2d, - 'cumsum': convert_cumsum, - 'depthwise_conv2d': convert_conv2d, - 'dropout': convert_dropout, - 'elementwise_add': convert_elementwise_op, - 'elementwise_div': convert_elementwise_op, - 'elementwise_mul': convert_elementwise_op, - 'elementwise_sub': convert_elementwise_op, - 'equal': convert_equal, - 'exp': convert_activation, - 'feed': convert_feed, - 'fill_any_like': convert_fill_any_like, - 'fill_constant': convert_fill_constant, - 'gelu': convert_gelu, - 'hard_sigmoid': convert_hard_sigmoid, - 'hard_swish': convert_hard_swish, - 'layer_norm': convert_layer_norm, - 'leaky_relu': convert_leaky_relu, - 'lookup_table_v2': convert_lookup_table, - 'matmul': convert_matmul, - 'matmul_v2': convert_matmul, - 'mul': convert_mul, - 'pool2d': convert_pool2d, - 'relu': convert_activation, - 'reshape2': convert_reshape, - 'scale': convert_scale, - 'shape': convert_shape, - 'slice': convert_slice, - 'softmax': convert_softmax, - 'tanh': convert_activation, - 'unsqueeze2': convert_unsqueeze, + "arg_max": convert_arg_max, + "assign": convert_assign, + "batch_norm": convert_batch_norm, + "cast": convert_cast, + "concat": convert_concat, + "conv2d": convert_conv2d, + "cumsum": convert_cumsum, + "depthwise_conv2d": convert_conv2d, + "dropout": convert_dropout, + "elementwise_add": convert_elementwise_op, + "elementwise_div": convert_elementwise_op, + "elementwise_mul": convert_elementwise_op, + "elementwise_sub": convert_elementwise_op, + "equal": convert_equal, + "exp": convert_activation, + "feed": convert_feed, + "fill_any_like": convert_fill_any_like, + "fill_constant": convert_fill_constant, + "gelu": convert_gelu, + "hard_sigmoid": convert_hard_sigmoid, + "hard_swish": convert_hard_swish, + "layer_norm": convert_layer_norm, + "leaky_relu": convert_leaky_relu, + "lookup_table_v2": convert_lookup_table, + "matmul": convert_matmul, + "matmul_v2": convert_matmul, + "mul": convert_mul, + "pool2d": convert_pool2d, + "relu": convert_activation, + "reshape2": convert_reshape, + "scale": convert_scale, + "shape": convert_shape, + "slice": convert_slice, + "softmax": convert_softmax, + "tanh": convert_activation, + "unsqueeze2": convert_unsqueeze, } class GraphProto(object): - """ A helper class for handling relay functions from PaddlePaddle model.""" + """A helper class for handling relay functions from PaddlePaddle model.""" + def __init__(self): self.nodes = {} self.params = {} @@ -792,13 +786,13 @@ def get_params(self, name=None): return self.params[name] def extract_parameters(self, program, scope=None): - """ Extract all the weights from PaddlePaddle program.""" + """Extract all the weights from PaddlePaddle program.""" self.params = {} variables = program.global_block().vars for name in variables: var = program.global_block().var(name) - if name.endswith('feed') or name.endswith('fetch'): + if name.endswith("feed") or name.endswith("fetch"): continue if not var.persistable: continue @@ -809,24 +803,24 @@ def extract_parameters(self, program, scope=None): self.nodes[name] = _expr.const(self.params[name]) def check_input_shape(self, op, block): - """ Check the shape information of model's inputs, fixed shape is recommended.""" + """Check the shape information of model's inputs, fixed shape is recommended.""" ipt_name = op.input(op.input_names[0]) ipt_shape = block.var(ipt_name).shape for i in ipt_shape: if i < 0: - warning_msg = ( - "Input {}(shape={}) has unkown dimension shapes. Specifying static values may improve performance" - .format(ipt_name, ipt_shape)) + warning_msg = "Input {}(shape={}) has unkown dimension shapes. Specifying static values may improve performance".format( + ipt_name, ipt_shape + ) warings.warn(warning_msg) def check_unsupported_ops(self, program): - """ Check whether all the operators are supported.""" + """Check whether all the operators are supported.""" unsupported_ops = set() for block in program.blocks: for i, op in enumerate(block.ops): - if op.type == 'fetch': + if op.type == "fetch": continue if op.type not in _convert_map: unsupported_ops.add(op.type) @@ -836,24 +830,25 @@ def check_unsupported_ops(self, program): raise tvm.error.OpNotImplemented(msg) def ops_to_relay(self, program, input_specs=None): - """ Convert PaddlePaddle operators to TVM relay functions.""" + """Convert PaddlePaddle operators to TVM relay functions.""" if input_specs is not None: for input_spec in input_specs: convert_feed(self, input_spec, None) for block in program.blocks: for i, op in enumerate(block.ops): - if op.type == 'fetch': + if op.type == "fetch": continue convert_func = _convert_map[op.type] convert_func(self, op, block) def from_program(self, program, shape_dict, scope): - """ Construct the TVM relay expression from PaddlePaddle program.""" + """Construct the TVM relay expression from PaddlePaddle program.""" self.shape_dict = shape_dict if scope is None: import paddle + scope = paddle.fluid.global_scope() self.check_unsupported_ops(program) self.extract_parameters(program, scope) @@ -863,7 +858,7 @@ def from_program(self, program, shape_dict, scope): for block in program.blocks: for i, op in enumerate(block.ops): if op.type == "fetch": - output_names.append(op.input('X')[0]) + output_names.append(op.input("X")[0]) outputs = [self.nodes[name] for name in output_names] outputs = outputs[0] if len(outputs) == 1 else _expr.Tuple(outputs) @@ -874,7 +869,7 @@ def from_program(self, program, shape_dict, scope): return mod, self.params def from_translated_layer(self, layer, shape_dict): - """ Construct the TVM relay expression from PaddlePaddle TranslatedLayer.""" + """Construct the TVM relay expression from PaddlePaddle TranslatedLayer.""" self.shape_dict = shape_dict program = layer.program() @@ -899,13 +894,14 @@ def from_translated_layer(self, layer, shape_dict): def from_paddle(program_or_layer, shape_dict=None, scope=None): - """ Convert a PaddlePaddle model into an equivalent Relay Function. + """Convert a PaddlePaddle model into an equivalent Relay Function. - PaddlePaddle Program/TranslatedLayer represent the computation graph of PaddlePaddle model, - and PaddlePaddle scope stores all the weights of PaddlePaddle model. + PaddlePaddle Program/TranslatedLayer represent the computation graph of PaddlePaddle model, + and PaddlePaddle scope stores all the weights of PaddlePaddle model. """ import paddle + g = GraphProto() if isinstance(program_or_layer, paddle.fluid.dygraph.TranslatedLayer): # model is loaded by `paddle.jit.load` @@ -914,6 +910,5 @@ def from_paddle(program_or_layer, shape_dict=None, scope=None): # model is loaded by `paddle.static.load_inference_model` mod, params = g.from_program(program_or_layer, shape_dict, scope) else: - raise Exception( - "Only PaddlePaddle's Program and TranslatedLayer are supported.") + raise Exception("Only PaddlePaddle's Program and TranslatedLayer are supported.") return mod, params diff --git a/tests/python/frontend/paddlepaddle/test_forward.py b/tests/python/frontend/paddlepaddle/test_forward.py index 20a110f7d657..db07e07f9d83 100644 --- a/tests/python/frontend/paddlepaddle/test_forward.py +++ b/tests/python/frontend/paddlepaddle/test_forward.py @@ -28,8 +28,7 @@ import paddle import paddle.nn as nn -PADDLE_TEST_DATA_ROOT_PATH = Path( - Path("~").expanduser(), ".tvm_test_data", "paddle") +PADDLE_TEST_DATA_ROOT_PATH = Path(Path("~").expanduser(), ".tvm_test_data", "paddle") PADDLE_TEST_DATA_ROOT_PATH.mkdir(parents=True, exist_ok=True) @@ -61,9 +60,8 @@ def verify_model(func, input_data, rtol=1e-5, atol=1e-5): for idx, data in enumerate(input_data): input_name = "input{}".format(idx) input_spec.append( - paddle.static.InputSpec(dtype=data.dtype, - shape=data.shape, - name=input_name)) + paddle.static.InputSpec(dtype=data.dtype, shape=data.shape, name=input_name) + ) input_names.append(input_name) input_shape_dict[input_name] = data.shape if isinstance(data, np.ndarray): @@ -78,7 +76,7 @@ def verify_model(func, input_data, rtol=1e-5, atol=1e-5): if isinstance(baseline_outputs, (tuple, list)): baseline_outputs = tuple(out.numpy() for out in baseline_outputs) else: - baseline_outputs = (baseline_outputs.numpy(), ) + baseline_outputs = (baseline_outputs.numpy(),) mod, params = relay.frontend.from_paddle(baseline_model, input_shape_dict) parms_num = min(len(input_names), len(mod["main"].params)) @@ -99,10 +97,7 @@ def verify_model(func, input_data, rtol=1e-5, atol=1e-5): compiled_output = gmod.get_output(i).numpy() assert_shapes_match(baseline_output, compiled_output) - tvm.testing.assert_allclose(baseline_output, - compiled_output, - rtol=rtol, - atol=atol) + tvm.testing.assert_allclose(baseline_output, compiled_output, rtol=rtol, atol=atol) @tvm.testing.uses_gpu @@ -168,13 +163,19 @@ def assign(inputs): input_shape = [2, 3] input_data = paddle.rand(input_shape, dtype="float32") - verify_model(assign, [ - input_data, - ]) + verify_model( + assign, + [ + input_data, + ], + ) input_data2 = np.random.randint(100, size=input_shape) - verify_model(assign, [ - input_data2, - ]) + verify_model( + assign, + [ + input_data2, + ], + ) @tvm.testing.uses_gpu @@ -226,28 +227,32 @@ def cast2(inputs, dtype="int64"): input_shape = [2, 3] input_data = paddle.rand(input_shape, dtype="float32") * 100 - verify_model(cast1, [ - input_data, - ]) - verify_model(cast2, [ - input_data, - ]) + verify_model( + cast1, + [ + input_data, + ], + ) + verify_model( + cast2, + [ + input_data, + ], + ) @tvm.testing.uses_gpu def test_forward_concat_unsqueeze(): @paddle.jit.to_static def concat_unsqueeze1(inputs): - return paddle.concat( - [inputs[:, 0].unsqueeze(1), inputs[:, 1].unsqueeze(1)], axis=1) + return paddle.concat([inputs[:, 0].unsqueeze(1), inputs[:, 1].unsqueeze(1)], axis=1) @paddle.jit.to_static def concat_unsqueeze2(inputs): a = (inputs[:, :, 0] + 2) * 7 b = (inputs[:, :, 1] + 3) * 11 c = (inputs[:, :, 2] + 5) * 13 - return paddle.concat([paddle.unsqueeze(t, axis=2) for t in [a, b, c]], - axis=2) + return paddle.concat([paddle.unsqueeze(t, axis=2) for t in [a, b, c]], axis=2) input_shape = [1, 3, 10, 10] input_data = paddle.rand(input_shape, dtype="float32") @@ -272,12 +277,18 @@ def cusum3(inputs): input_data = paddle.randint(0, 100, (10, 10), dtype=paddle.int32) verify_model(cusum1, [input_data]) verify_model(cusum1, [input_data.astype(paddle.int64)]) - verify_model(cusum2, [ - input_data, - ]) - verify_model(cusum3, [ - input_data, - ]) + verify_model( + cusum2, + [ + input_data, + ], + ) + verify_model( + cusum3, + [ + input_data, + ], + ) @tvm.testing.uses_gpu @@ -390,10 +401,7 @@ def hard_swish(inputs): def test_forward_layer_norm(): @paddle.jit.to_static def layer_norm(inputs, weight, bias): - return nn.functional.layer_norm(inputs, - inputs.shape[-1], - weight=weight, - bias=bias) + return nn.functional.layer_norm(inputs, inputs.shape[-1], weight=weight, bias=bias) class LayerNorm(nn.Layer): def __init__(self): @@ -477,7 +485,7 @@ def forward(self, input1, input2): # matrix x vector input_data1 = paddle.randn((3, 4), dtype="float32") - input_data2 = paddle.randn((4, ), dtype="float32") + input_data2 = paddle.randn((4,), dtype="float32") verify_model(MatMul1(), input_data=[input_data1, input_data2]) # matrix x matrix @@ -500,10 +508,7 @@ def forward(self, input1, input2): def test_forward_pool2d(): @paddle.jit.to_static def pool2d1(inputs): - return nn.functional.avg_pool2d(inputs, - kernel_size=2, - stride=2, - padding=0) + return nn.functional.avg_pool2d(inputs, kernel_size=2, stride=2, padding=0) @paddle.jit.to_static def pool2d2(inputs): @@ -511,16 +516,11 @@ def pool2d2(inputs): @paddle.jit.to_static def pool2d3(inputs): - return nn.functional.max_pool2d(inputs, - kernel_size=2, - stride=2, - padding=0, - return_mask=True) - - input_data = paddle.uniform(shape=[1, 2, 32, 32], - dtype='float32', - min=-1, - max=1) + return nn.functional.max_pool2d( + inputs, kernel_size=2, stride=2, padding=0, return_mask=True + ) + + 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) @@ -577,10 +577,13 @@ def scale1(inputs): def scale2(inputs): return paddle.scale(inputs, scale=3, bias=2.1, act="gelu") - input_data = paddle.randn(shape=[2, 3], dtype='float32') - verify_model(scale1, input_data=[ - input_data, - ]) + input_data = paddle.randn(shape=[2, 3], dtype="float32") + verify_model( + scale1, + input_data=[ + input_data, + ], + ) verify_model(scale2, input_data=input_data) @@ -606,9 +609,12 @@ 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))) From 618be3939b39d0a92edb446b2c3b162f435fc3b7 Mon Sep 17 00:00:00 2001 From: heliqi <1101791222@qq.com> Date: Tue, 17 Aug 2021 16:49:47 +0800 Subject: [PATCH 21/51] add interpolate op --- python/tvm/relay/frontend/paddlepaddle.py | 115 +++++++++++++++++- .../frontend/paddlepaddle/test_forward.py | 35 ++++++ 2 files changed, 149 insertions(+), 1 deletion(-) diff --git a/python/tvm/relay/frontend/paddlepaddle.py b/python/tvm/relay/frontend/paddlepaddle.py index c67c8b9c39e0..0757c368d1c7 100644 --- a/python/tvm/relay/frontend/paddlepaddle.py +++ b/python/tvm/relay/frontend/paddlepaddle.py @@ -25,6 +25,7 @@ import tvm from tvm.ir import IRModule +from tvm.script.intrin import float32 from .. import analysis from .. import expr as _expr @@ -105,7 +106,116 @@ def convert_batch_norm(g, op, block): ) g.add_node(op.output("Y")[0], out[0]) - +def bilinear_interp_v2_get_shape(input_shape, layout): + dims = len(input_shape) + assert ( + dims > 2 and dims < 6 + ), "input shape({}) error on PaddlePaddle's bilinear_interp_v2".format(dims) + if dims == 3: + if layout == "NCHW": + return None, 1, input_shape[2] + else: + return None, 1, input_shape[1] + elif dims == 4: + if layout == "NCHW": + return None, input_shape[2], input_shape[3] + else: + return None, input_shape[1], input_shape[2] + elif dims == 5: + if layout == "NCHW": + return input_shape[2:] + else: + return input_shape[1:4] + +def bilinear_interp_get_mod(op): + interp_method = op.attr('interp_method') + align_corners = op.attr('align_corners') + align_mode = op.attr('align_mode') + + rounding_method = "" + if interp_method == "nearest": + interp_method = "nearest_neighbor" + coordinate_transformation_mode = "asymmetric" + rounding_method = "floor" + elif interp_method == "bilinear": + interp_method = "linear" + if align_mode == 0 and align_corners == False: + coordinate_transformation_mode = "half_pixel" + else: + if align_corners: + coordinate_transformation_mode = "align_corners" + else: + coordinate_transformation_mode = "asymmetric" + elif interp_method == "bicubic": + interp_method = "cubic" + if align_corners: + coordinate_transformation_mode = "align_corners" + else: + coordinate_transformation_mode = "half_pixel" + else: + msg = "interp_method {} is not supported for PaddlePaddle's bilinear_interp_v2" + raise tvm.error.OpAttributeInvalid(msg.format(interp_method)) + return rounding_method, interp_method, coordinate_transformation_mode + +def convert_bilinear_interp2D(g, op, x, input_shape): + layout = op.attr('data_layout') + if layout == "NCHW": + in_h, in_w = input_shape[2], input_shape[3] + else: + in_h, in_w = input_shape[1], input_shape[2] + + out_h = op.attr('out_h') + out_w = op.attr('out_w') + + OutSize = op.input('OutSize') + SizeTensor = op.input('SizeTensor') + Scale = op.input("Scale") + if SizeTensor: + outsize = g.get_node(SizeTensor[0]) + outsize = infer_value(outsize, g.get_params()).numpy().tolist() + out_h, out_w = outsize + elif OutSize: + outsize = g.get_node(OutSize[0]) + outsize = infer_value(outsize, g.get_params()).numpy().tolist() + out_h, out_w = outsize + elif Scale: + scale_data = g.get_node(Scale[0]) + scale_data = infer_value(scale_data, g.get_params()).numpy().tolist() + if len(scale_data) > 1: + out_h = int(scale_data[0] * in_h) + out_w = int(scale_data[1] * in_w) + else: + out_h = int(scale_data[0] * in_h) + out_w = int(scale_data[0] * in_w) + else: + scale = op.attr('scale') + scale = [float(i) for i in scale] + if len(scale) > 1: + out_h = int(scale[0] * in_h) + out_w = int(scale[1] * in_w) + + rounding_method, interp_method, coordinate_transformation_mode = bilinear_interp_get_mod(op) + out = _op.image.resize2d( + x, + [out_h, out_w], + layout=layout, + method=interp_method, + coordinate_transformation_mode=coordinate_transformation_mode, + rounding_method=rounding_method, + cubic_alpha=-0.75) + g.add_node(op.output('Out')[0], out) + +def convert_bilinear_interp_v2(g, op, block): + """Operator converter for bilinear_interp_v2.""" + x = g.get_node(op.input('X')[0]) + input_shape = infer_shape(x) + dims = len(input_shape) + if dims == 4: + convert_bilinear_interp2D(g, op, x, input_shape) + else: + msg = "input_shape {} is not supported for PaddlePaddle's bilinear_interp_v2" + raise tvm.error.OpAttributeInvalid(msg.format(dims)) + def convert_cast(g, op, block): """Operator converter for cast.""" @@ -728,6 +838,8 @@ def convert_unsqueeze(g, op, block): "arg_max": convert_arg_max, "assign": convert_assign, "batch_norm": convert_batch_norm, + "bicubic_interp_v2": convert_bilinear_interp_v2, + "bilinear_interp_v2": convert_bilinear_interp_v2, "cast": convert_cast, "concat": convert_concat, "conv2d": convert_conv2d, @@ -752,6 +864,7 @@ def convert_unsqueeze(g, op, block): "matmul": convert_matmul, "matmul_v2": convert_matmul, "mul": convert_mul, + "nearest_interp_v2": convert_bilinear_interp_v2, "pool2d": convert_pool2d, "relu": convert_activation, "reshape2": convert_reshape, diff --git a/tests/python/frontend/paddlepaddle/test_forward.py b/tests/python/frontend/paddlepaddle/test_forward.py index db07e07f9d83..2c3f8642efa0 100644 --- a/tests/python/frontend/paddlepaddle/test_forward.py +++ b/tests/python/frontend/paddlepaddle/test_forward.py @@ -396,6 +396,40 @@ def hard_swish(inputs): input_data = paddle.rand(input_shape, dtype="float32") verify_model(hard_swish, input_data=input_data) +@tvm.testing.uses_gpu +def test_forward_interpolate(): + class TestBilinear(nn.Layer): + def __init__(self): + super(TestBilinear, self).__init__() + self.conv = nn.Conv2D(3, 5, 3, stride=2) + + def forward(self, x): + shape = paddle.shape(x)[2:] + y = self.conv(x) + return nn.functional.interpolate(y, size=shape, mode='nearest') + + def bilinear_interp1(inputs): + return nn.functional.interpolate(inputs, size=[12, 12], mode='bilinear') + + @paddle.jit.to_static + def bilinear_interp2(inputs): + return nn.functional.interpolate(inputs, scale_factor=[2.0, 1.0], mode='bilinear', align_corners=True, align_mode=1) + + @paddle.jit.to_static + def bilinear_interp3(inputs): + return nn.functional.interpolate(inputs, scale_factor=[1.0, 2.0], mode='bicubic') + + @paddle.jit.to_static + def bilinear_interp4(inputs): + return nn.functional.interpolate(inputs, scale_factor=3.0, mode='bicubic', align_corners=True, align_mode=0) + + input_shape = [2, 3, 6, 12] + input_data = paddle.rand(input_shape, dtype="float32") + verify_model(TestBilinear(), input_data=input_data) + verify_model(bilinear_interp1, input_data=input_data) + verify_model(bilinear_interp2, input_data=input_data) + verify_model(bilinear_interp3, input_data=input_data) + verify_model(bilinear_interp4, input_data=input_data) @tvm.testing.uses_gpu def test_forward_layer_norm(): @@ -648,6 +682,7 @@ def tanh(inputs): test_forward_gelu() test_forward_hard_sigmoid() test_forward_hard_swish() + test_forward_interpolate() test_forward_layer_norm() test_forward_leaky_relu() test_forward_look_up() From 72d75b738bc3af9c6aa23315144db785b4288d4e Mon Sep 17 00:00:00 2001 From: heliqi <1101791222@qq.com> Date: Tue, 17 Aug 2021 16:50:38 +0800 Subject: [PATCH 22/51] add interpolate op --- python/tvm/relay/frontend/paddlepaddle.py | 58 ++++++++++--------- .../frontend/paddlepaddle/test_forward.py | 16 +++-- 2 files changed, 43 insertions(+), 31 deletions(-) diff --git a/python/tvm/relay/frontend/paddlepaddle.py b/python/tvm/relay/frontend/paddlepaddle.py index 0757c368d1c7..afa1c8a17d41 100644 --- a/python/tvm/relay/frontend/paddlepaddle.py +++ b/python/tvm/relay/frontend/paddlepaddle.py @@ -106,10 +106,11 @@ def convert_batch_norm(g, op, block): ) g.add_node(op.output("Y")[0], out[0]) + def bilinear_interp_v2_get_shape(input_shape, layout): dims = len(input_shape) assert ( - dims > 2 and dims < 6 + dims > 2 and dims < 6 ), "input shape({}) error on PaddlePaddle's bilinear_interp_v2".format(dims) if dims == 3: if layout == "NCHW": @@ -127,11 +128,12 @@ def bilinear_interp_v2_get_shape(input_shape, layout): else: return input_shape[1:4] + def bilinear_interp_get_mod(op): - interp_method = op.attr('interp_method') - align_corners = op.attr('align_corners') - align_mode = op.attr('align_mode') - + interp_method = op.attr("interp_method") + align_corners = op.attr("align_corners") + align_mode = op.attr("align_mode") + rounding_method = "" if interp_method == "nearest": interp_method = "nearest_neighbor" @@ -157,18 +159,19 @@ def bilinear_interp_get_mod(op): raise tvm.error.OpAttributeInvalid(msg.format(interp_method)) return rounding_method, interp_method, coordinate_transformation_mode + def convert_bilinear_interp2D(g, op, x, input_shape): - layout = op.attr('data_layout') + layout = op.attr("data_layout") if layout == "NCHW": in_h, in_w = input_shape[2], input_shape[3] else: in_h, in_w = input_shape[1], input_shape[2] - out_h = op.attr('out_h') - out_w = op.attr('out_w') + out_h = op.attr("out_h") + out_w = op.attr("out_w") - OutSize = op.input('OutSize') - SizeTensor = op.input('SizeTensor') + OutSize = op.input("OutSize") + SizeTensor = op.input("SizeTensor") Scale = op.input("Scale") if SizeTensor: outsize = g.get_node(SizeTensor[0]) @@ -183,31 +186,33 @@ def convert_bilinear_interp2D(g, op, x, input_shape): scale_data = infer_value(scale_data, g.get_params()).numpy().tolist() if len(scale_data) > 1: out_h = int(scale_data[0] * in_h) - out_w = int(scale_data[1] * in_w) + out_w = int(scale_data[1] * in_w) else: out_h = int(scale_data[0] * in_h) - out_w = int(scale_data[0] * in_w) - else: - scale = op.attr('scale') + out_w = int(scale_data[0] * in_w) + else: + scale = op.attr("scale") scale = [float(i) for i in scale] if len(scale) > 1: out_h = int(scale[0] * in_h) - out_w = int(scale[1] * in_w) - + out_w = int(scale[1] * in_w) + rounding_method, interp_method, coordinate_transformation_mode = bilinear_interp_get_mod(op) out = _op.image.resize2d( - x, - [out_h, out_w], - layout=layout, - method=interp_method, - coordinate_transformation_mode=coordinate_transformation_mode, - rounding_method=rounding_method, - cubic_alpha=-0.75) - g.add_node(op.output('Out')[0], out) + x, + [out_h, out_w], + layout=layout, + method=interp_method, + coordinate_transformation_mode=coordinate_transformation_mode, + rounding_method=rounding_method, + cubic_alpha=-0.75, + ) + g.add_node(op.output("Out")[0], out) + def convert_bilinear_interp_v2(g, op, block): """Operator converter for bilinear_interp_v2.""" - x = g.get_node(op.input('X')[0]) + x = g.get_node(op.input("X")[0]) input_shape = infer_shape(x) dims = len(input_shape) if dims == 4: @@ -215,7 +220,8 @@ def convert_bilinear_interp_v2(g, op, block): else: msg = "input_shape {} is not supported for PaddlePaddle's bilinear_interp_v2" raise tvm.error.OpAttributeInvalid(msg.format(dims)) - + + def convert_cast(g, op, block): """Operator converter for cast.""" diff --git a/tests/python/frontend/paddlepaddle/test_forward.py b/tests/python/frontend/paddlepaddle/test_forward.py index 2c3f8642efa0..2aa2db6b8c3c 100644 --- a/tests/python/frontend/paddlepaddle/test_forward.py +++ b/tests/python/frontend/paddlepaddle/test_forward.py @@ -396,6 +396,7 @@ def hard_swish(inputs): input_data = paddle.rand(input_shape, dtype="float32") verify_model(hard_swish, input_data=input_data) + @tvm.testing.uses_gpu def test_forward_interpolate(): class TestBilinear(nn.Layer): @@ -406,22 +407,26 @@ def __init__(self): def forward(self, x): shape = paddle.shape(x)[2:] y = self.conv(x) - return nn.functional.interpolate(y, size=shape, mode='nearest') + return nn.functional.interpolate(y, size=shape, mode="nearest") def bilinear_interp1(inputs): - return nn.functional.interpolate(inputs, size=[12, 12], mode='bilinear') + return nn.functional.interpolate(inputs, size=[12, 12], mode="bilinear") @paddle.jit.to_static def bilinear_interp2(inputs): - return nn.functional.interpolate(inputs, scale_factor=[2.0, 1.0], mode='bilinear', align_corners=True, align_mode=1) + return nn.functional.interpolate( + inputs, scale_factor=[2.0, 1.0], mode="bilinear", align_corners=True, align_mode=1 + ) @paddle.jit.to_static def bilinear_interp3(inputs): - return nn.functional.interpolate(inputs, scale_factor=[1.0, 2.0], mode='bicubic') + return nn.functional.interpolate(inputs, scale_factor=[1.0, 2.0], mode="bicubic") @paddle.jit.to_static def bilinear_interp4(inputs): - return nn.functional.interpolate(inputs, scale_factor=3.0, mode='bicubic', align_corners=True, align_mode=0) + return nn.functional.interpolate( + inputs, scale_factor=3.0, mode="bicubic", align_corners=True, align_mode=0 + ) input_shape = [2, 3, 6, 12] input_data = paddle.rand(input_shape, dtype="float32") @@ -431,6 +436,7 @@ def bilinear_interp4(inputs): verify_model(bilinear_interp3, input_data=input_data) verify_model(bilinear_interp4, input_data=input_data) + @tvm.testing.uses_gpu def test_forward_layer_norm(): @paddle.jit.to_static From e0aa61545b90fbdf861d6ae47d61d171e616e343 Mon Sep 17 00:00:00 2001 From: heliqi <1101791222@qq.com> Date: Tue, 17 Aug 2021 17:04:30 +0800 Subject: [PATCH 23/51] add interpolate op --- python/tvm/relay/frontend/paddlepaddle.py | 1 - 1 file changed, 1 deletion(-) diff --git a/python/tvm/relay/frontend/paddlepaddle.py b/python/tvm/relay/frontend/paddlepaddle.py index afa1c8a17d41..fbd1a72aa2ce 100644 --- a/python/tvm/relay/frontend/paddlepaddle.py +++ b/python/tvm/relay/frontend/paddlepaddle.py @@ -25,7 +25,6 @@ import tvm from tvm.ir import IRModule -from tvm.script.intrin import float32 from .. import analysis from .. import expr as _expr From 202893c453d612fcdf268ca1210d186d34f8ee4c Mon Sep 17 00:00:00 2001 From: heliqi <1101791222@qq.com> Date: Tue, 17 Aug 2021 19:55:30 +0800 Subject: [PATCH 24/51] pylint check --- python/tvm/relay/frontend/paddlepaddle.py | 59 ++++++++++++----------- 1 file changed, 31 insertions(+), 28 deletions(-) diff --git a/python/tvm/relay/frontend/paddlepaddle.py b/python/tvm/relay/frontend/paddlepaddle.py index c67c8b9c39e0..ab17c3b6daa4 100644 --- a/python/tvm/relay/frontend/paddlepaddle.py +++ b/python/tvm/relay/frontend/paddlepaddle.py @@ -17,9 +17,7 @@ # pylint: disable=invalid-name, import-self, len-as-condition, unused-argument, too-many-lines # pylint: disable=import-outside-toplevel """Paddle: PArallel Distributed Deep LEarning.""" -import copy import warnings -import six import numpy as np @@ -43,6 +41,8 @@ def shape_of(x, dtype="int32"): + """Get shape of a tensor""" + ttype = infer_type(x).checked_type if not _ty.is_dynamic(ttype): shape = list(ttype.shape) @@ -51,6 +51,8 @@ def shape_of(x, dtype="int32"): def _get_pad_size(in_size, dilated_kernel_size, stride_size): + """calculate the paddings size""" + if stride_size == 1 or in_size % stride_size == 0: pad = max(dilated_kernel_size - stride_size, 0) else: @@ -94,7 +96,6 @@ def convert_batch_norm(g, op, block): mean_name = op.input("Mean")[0] variance_name = op.input("Variance")[0] epsilon = op.attr("epsilon") - momentum = op.attr("momentum") out = _op.nn.batch_norm( g.get_node(ipt_name), g.get_node(scale_name), @@ -127,6 +128,7 @@ def convert_concat(g, op, block): def convert_conv2d(g, op, block): """Operator converter for conv2d.""" + dilations = op.attr("dilations") groups = op.attr("groups") paddings = op.attr("paddings") @@ -134,9 +136,9 @@ def convert_conv2d(g, op, block): strides = op.attr("strides") kernel = g.get_node(op.input("Filter")[0]) - input = g.get_node(op.input("Input")[0]) + input_x = g.get_node(op.input("Input")[0]) out_channels, _, k_h, k_w = infer_shape(kernel) - in_h, in_w = infer_shape(input)[2:] + in_h, in_w = infer_shape(input_x)[2:] if padding_algorithm == "VALID": paddings = [0, 0] elif padding_algorithm == "SAME": @@ -149,11 +151,11 @@ def convert_conv2d(g, op, block): if len(paddings) == 4: paddings = [paddings[0], paddings[2], paddings[1], paddings[3]] else: - msg = 'Value {} in attribute "padding" of operator Conv is not ' "valid." + msg = 'Value {} in attribute "padding" of operator Conv is not "valid."' raise tvm.error.OpAttributeInvalid(msg.format(padding_algorithm)) out = _op.nn.conv2d( - input, + input_x, kernel, strides=strides, padding=paddings, @@ -312,7 +314,6 @@ def convert_hard_sigmoid(g, op, block): """Operator converter for hard_sigmoid.""" slope = op.attr("slope") - offset = op.attr("offset") x = g.get_node(op.input("X")[0]) out = x * _expr.const(slope) + _expr.const(0.5) out = _op.clip(out, 0, 1) @@ -346,7 +347,7 @@ def convert_layer_norm(g, op, block): x_shape = infer_shape(x) assert ( - begin_norm_axis == -1 or begin_norm_axis == len(x_shape) - 1 + begin_norm_axis in (len(x_shape) - 1, -1) ), "Support only normalization over last one dimension." if bias_input: @@ -379,8 +380,6 @@ def convert_lookup_table(g, op, block): indices = g.get_node(op.input("Ids")[0]) padding_idx = op.attr("padding_idx") - is_sparse = op.attr("is_sparse") - height_sections = op.attr("height_sections") if padding_idx != -1: g.get_params[op.input("W")[0]][padding_idx] = 0.0 g.add_node(op.input("W")[0], _expr.const(g.params[op.input("W")[0]])) @@ -395,11 +394,11 @@ def convert_matmul(g, op, block): inputs = [g.get_node(op.input("X")[0]), g.get_node(op.input("Y")[0])] a_shape = infer_shape(inputs[0]) b_shape = infer_shape(inputs[1]) - try: + if op.has_attr("trans_x"): # for matmul_v2 trans_x = op.attr("trans_x") trans_y = op.attr("trans_y") - except: + else: # for matmul trans_x = op.attr("transpose_X") trans_y = op.attr("transpose_Y") @@ -491,12 +490,10 @@ def flatten_to_nd(x, x_shape, nd=3): out = _op.nn.dense(inputs[0], input_1_t) if b_rank == 1: out = _op.squeeze(out, axis=[-1]) - try: + if op.has_attr("alpha"): alpha = op.attr("alpha") if not np.isclose(alpha, 1.0): out = out * _expr.const(alpha).astype("float32") - except: - pass g.add_node(op.output("Out")[0], out) @@ -559,8 +556,8 @@ def convert_pool2d(g, op, block): adaptive = True ksize = [1, 1] - input = g.get_node(op.input("X")[0]) - in_h, in_w = infer_shape(input)[2:] + input_x = g.get_node(op.input("X")[0]) + in_h, in_w = infer_shape(input_x)[2:] op_map = { "avg": "avg_pool2d", @@ -586,16 +583,15 @@ def convert_pool2d(g, op, block): if len(paddings) == 4: paddings = [paddings[0], paddings[2], paddings[1], paddings[3]] else: - msg = 'Value {} in attribute "padding" of operator Pool2d is not ' "valid." + msg = 'Value {} in attribute "padding" of operator Pool2d is not "valid."' raise tvm.error.OpAttributeInvalid(msg.format(padding_algorithm)) - x = g.get_node(op.input("X")[0]) if not adaptive: out = getattr(_op.nn, op_map[pooling_type])( - x, pool_size=ksize, strides=strides, padding=paddings, ceil_mode=ceil_mode + input_x, pool_size=ksize, strides=strides, padding=paddings, ceil_mode=ceil_mode ) else: - out = getattr(_op.nn, "adaptive_" + op_map[pooling_type])(x, output_size=ksize) + out = getattr(_op.nn, "adaptive_" + op_map[pooling_type])(input_x, output_size=ksize) g.add_node(op.output("Out")[0], out) @@ -764,7 +760,7 @@ def convert_unsqueeze(g, op, block): } -class GraphProto(object): +class GraphProto: """A helper class for handling relay functions from PaddlePaddle model.""" def __init__(self): @@ -773,13 +769,19 @@ def __init__(self): self.shape_dict = None def get_node(self, name): + """get node from graph""" + assert name in self.nodes return self.nodes[name] def add_node(self, name, node): + """add a node to graph""" + self.nodes[name] = fold_constant(node) def get_params(self, name=None): + """get params from graph""" + if name is None: return self.params assert name in self.params @@ -809,17 +811,18 @@ def check_input_shape(self, op, block): ipt_shape = block.var(ipt_name).shape for i in ipt_shape: if i < 0: - warning_msg = "Input {}(shape={}) has unkown dimension shapes. Specifying static values may improve performance".format( + warning_msg = "Input {}(shape={}) has unkown dimension shapes. \ + Specifying static values may improve performance".format( ipt_name, ipt_shape ) - warings.warn(warning_msg) + warnings.warn(warning_msg) def check_unsupported_ops(self, program): """Check whether all the operators are supported.""" unsupported_ops = set() for block in program.blocks: - for i, op in enumerate(block.ops): + for op in block.ops: if op.type == "fetch": continue if op.type not in _convert_map: @@ -836,7 +839,7 @@ def ops_to_relay(self, program, input_specs=None): for input_spec in input_specs: convert_feed(self, input_spec, None) for block in program.blocks: - for i, op in enumerate(block.ops): + for op in block.ops: if op.type == "fetch": continue convert_func = _convert_map[op.type] @@ -856,7 +859,7 @@ def from_program(self, program, shape_dict, scope): output_names = list() for block in program.blocks: - for i, op in enumerate(block.ops): + for op in block.ops: if op.type == "fetch": output_names.append(op.input("X")[0]) From a281d602eca0a8a307e2788bcc388d14c9f94af8 Mon Sep 17 00:00:00 2001 From: jiangjiajun <928090362@qq.com> Date: Wed, 18 Aug 2021 02:27:59 +0000 Subject: [PATCH 25/51] Remove fluid api --- python/tvm/relay/frontend/paddlepaddle.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/tvm/relay/frontend/paddlepaddle.py b/python/tvm/relay/frontend/paddlepaddle.py index ab17c3b6daa4..0b59f1d8ea58 100644 --- a/python/tvm/relay/frontend/paddlepaddle.py +++ b/python/tvm/relay/frontend/paddlepaddle.py @@ -906,10 +906,10 @@ def from_paddle(program_or_layer, shape_dict=None, scope=None): import paddle g = GraphProto() - if isinstance(program_or_layer, paddle.fluid.dygraph.TranslatedLayer): + if isinstance(program_or_layer, paddle.jit.TranslatedLayer): # model is loaded by `paddle.jit.load` mod, params = g.from_translated_layer(program_or_layer, shape_dict) - elif isinstance(program_or_layer, paddle.fluid.framework.Program): + elif isinstance(program_or_layer, paddle.static.Program): # model is loaded by `paddle.static.load_inference_model` mod, params = g.from_program(program_or_layer, shape_dict, scope) else: From be0e04ece30672c86b44009b27d1d253ee79e8a5 Mon Sep 17 00:00:00 2001 From: heliqi <1101791222@qq.com> Date: Wed, 18 Aug 2021 10:40:24 +0800 Subject: [PATCH 26/51] black format --- python/tvm/relay/frontend/paddlepaddle.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/python/tvm/relay/frontend/paddlepaddle.py b/python/tvm/relay/frontend/paddlepaddle.py index 0b59f1d8ea58..76a12691d2bf 100644 --- a/python/tvm/relay/frontend/paddlepaddle.py +++ b/python/tvm/relay/frontend/paddlepaddle.py @@ -346,8 +346,9 @@ def convert_layer_norm(g, op, block): scale_input = op.input("Scale") x_shape = infer_shape(x) - assert ( - begin_norm_axis in (len(x_shape) - 1, -1) + assert begin_norm_axis in ( + len(x_shape) - 1, + -1, ), "Support only normalization over last one dimension." if bias_input: From a7470aba4c4d4ddccb0beae888702052d3ffa177 Mon Sep 17 00:00:00 2001 From: heliqi <1101791222@qq.com> Date: Wed, 18 Aug 2021 15:44:46 +0800 Subject: [PATCH 27/51] formatting and add squeeze2 op --- python/tvm/relay/frontend/paddlepaddle.py | 64 +++++++++---------- .../frontend/paddlepaddle/test_forward.py | 29 ++++++++- 2 files changed, 56 insertions(+), 37 deletions(-) diff --git a/python/tvm/relay/frontend/paddlepaddle.py b/python/tvm/relay/frontend/paddlepaddle.py index 98475c8e92da..831e5cf146e7 100644 --- a/python/tvm/relay/frontend/paddlepaddle.py +++ b/python/tvm/relay/frontend/paddlepaddle.py @@ -107,29 +107,9 @@ def convert_batch_norm(g, op, block): g.add_node(op.output("Y")[0], out[0]) -def bilinear_interp_v2_get_shape(input_shape, layout): - dims = len(input_shape) - assert ( - dims > 2 and dims < 6 - ), "input shape({}) error on PaddlePaddle's bilinear_interp_v2".format(dims) - if dims == 3: - if layout == "NCHW": - return None, 1, input_shape[2] - else: - return None, 1, input_shape[1] - elif dims == 4: - if layout == "NCHW": - return None, input_shape[2], input_shape[3] - else: - return None, input_shape[1], input_shape[2] - elif dims == 5: - if layout == "NCHW": - return input_shape[2:] - else: - return input_shape[1:4] +def interpolate_get_mode(op): + """conver 'interp_method' attr of paddle to tvm""" - -def bilinear_interp_get_mod(op): interp_method = op.attr("interp_method") align_corners = op.attr("align_corners") align_mode = op.attr("align_mode") @@ -141,7 +121,7 @@ def bilinear_interp_get_mod(op): rounding_method = "floor" elif interp_method == "bilinear": interp_method = "linear" - if align_mode == 0 and align_corners == False: + if not align_corners and align_mode == 0: coordinate_transformation_mode = "half_pixel" else: if align_corners: @@ -155,12 +135,14 @@ def bilinear_interp_get_mod(op): else: coordinate_transformation_mode = "half_pixel" else: - msg = "interp_method {} is not supported for PaddlePaddle's bilinear_interp_v2" + msg = "interp_method {} is not supported for PaddlePaddle's interpolate" raise tvm.error.OpAttributeInvalid(msg.format(interp_method)) return rounding_method, interp_method, coordinate_transformation_mode -def convert_bilinear_interp2D(g, op, x, input_shape): +def convert_interpolate2D(g, op, x, input_shape): + """Operator converter for interpolate 2D(dims == 4).""" + layout = op.attr("data_layout") if layout == "NCHW": in_h, in_w = input_shape[2], input_shape[3] @@ -210,15 +192,16 @@ def convert_bilinear_interp2D(g, op, x, input_shape): g.add_node(op.output("Out")[0], out) -def convert_bilinear_interp_v2(g, op, block): - """Operator converter for bilinear_interp_v2.""" +def convert_interpolate(g, op, block): + """Operator converter for interpolate.""" + x = g.get_node(op.input("X")[0]) input_shape = infer_shape(x) dims = len(input_shape) if dims == 4: - convert_bilinear_interp2D(g, op, x, input_shape) + convert_interpolate2D(g, op, x, input_shape) else: - msg = "input_shape {} is not supported for PaddlePaddle's bilinear_interp_v2" + msg = "input_shape {} is not supported for PaddlePaddle's interpolate" raise tvm.error.OpAttributeInvalid(msg.format(dims)) @@ -461,8 +444,9 @@ def convert_layer_norm(g, op, block): scale_input = op.input("Scale") x_shape = infer_shape(x) - assert ( - begin_norm_axis in (len(x_shape) - 1, -1) + assert begin_norm_axis in ( + len(x_shape) - 1, + -1, ), "Support only normalization over last one dimension." if bias_input: @@ -825,6 +809,17 @@ def convert_softmax(g, op, block): g.add_node(op.output("Out")[0], out) +def convert_squeeze(g, op, block): + """Operator converter for squeeze2.""" + + x = g.get_node(op.input("X")[0]) + axes = op.attr("axes") + if not axes: + axes = None + x = _op.squeeze(x, axis=axes) + g.add_node(op.output("Out")[0], x) + + def convert_unsqueeze(g, op, block): """Operator converter for unsqueeze.""" @@ -839,8 +834,8 @@ def convert_unsqueeze(g, op, block): "arg_max": convert_arg_max, "assign": convert_assign, "batch_norm": convert_batch_norm, - "bicubic_interp_v2": convert_bilinear_interp_v2, - "bilinear_interp_v2": convert_bilinear_interp_v2, + "bicubic_interp_v2": convert_interpolate, + "bilinear_interp_v2": convert_interpolate, "cast": convert_cast, "concat": convert_concat, "conv2d": convert_conv2d, @@ -865,7 +860,7 @@ def convert_unsqueeze(g, op, block): "matmul": convert_matmul, "matmul_v2": convert_matmul, "mul": convert_mul, - "nearest_interp_v2": convert_bilinear_interp_v2, + "nearest_interp_v2": convert_interpolate, "pool2d": convert_pool2d, "relu": convert_activation, "reshape2": convert_reshape, @@ -873,6 +868,7 @@ def convert_unsqueeze(g, op, block): "shape": convert_shape, "slice": convert_slice, "softmax": convert_softmax, + "squeeze2": convert_squeeze, "tanh": convert_activation, "unsqueeze2": convert_unsqueeze, } diff --git a/tests/python/frontend/paddlepaddle/test_forward.py b/tests/python/frontend/paddlepaddle/test_forward.py index 2aa2db6b8c3c..85c6c610724f 100644 --- a/tests/python/frontend/paddlepaddle/test_forward.py +++ b/tests/python/frontend/paddlepaddle/test_forward.py @@ -14,19 +14,20 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import os from pathlib import Path import shutil import numpy as np + +import paddle +import paddle.nn as nn + import tvm import tvm.testing import tvm.topi.testing from tvm import relay from tvm.contrib import graph_executor -import paddle -import paddle.nn as nn PADDLE_TEST_DATA_ROOT_PATH = Path(Path("~").expanduser(), ".tvm_test_data", "paddle") PADDLE_TEST_DATA_ROOT_PATH.mkdir(parents=True, exist_ok=True) @@ -662,6 +663,27 @@ def slice4(inputs): # verify_model(slice4, input_data=input_data) +@tvm.testing.uses_gpu +def test_forward_squeeze2(): + @paddle.jit.to_static + def squeeze(inputs): + return paddle.squeeze(inputs) + + @paddle.jit.to_static + def squeeze2(inputs): + return paddle.squeeze(inputs, axis=0) + + @paddle.jit.to_static + def squeeze3(inputs): + return paddle.squeeze(inputs, axis=[0, -1]) + + input_shape = [1, 2, 1, 3, 1] + input_data = paddle.rand(input_shape, dtype="float32") + verify_model(squeeze, input_data=input_data) + verify_model(squeeze2, input_data=input_data) + verify_model(squeeze3, input_data=input_data) + + @tvm.testing.uses_gpu def test_forward_tanh(): @paddle.jit.to_static @@ -699,4 +721,5 @@ def tanh(inputs): test_forward_reshape() test_forward_scale() test_forward_slice() + test_forward_squeeze2() test_forward_tanh() From 3c4ce68e92a213c748a9a5dda0e78d3e3042d479 Mon Sep 17 00:00:00 2001 From: heliqi <1101791222@qq.com> Date: Wed, 18 Aug 2021 15:48:19 +0800 Subject: [PATCH 28/51] formatting --- python/tvm/relay/frontend/paddlepaddle.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/tvm/relay/frontend/paddlepaddle.py b/python/tvm/relay/frontend/paddlepaddle.py index 831e5cf146e7..3af1d4f496ec 100644 --- a/python/tvm/relay/frontend/paddlepaddle.py +++ b/python/tvm/relay/frontend/paddlepaddle.py @@ -107,7 +107,7 @@ def convert_batch_norm(g, op, block): g.add_node(op.output("Y")[0], out[0]) -def interpolate_get_mode(op): +def get_interpolate_mode(op): """conver 'interp_method' attr of paddle to tvm""" interp_method = op.attr("interp_method") @@ -179,7 +179,7 @@ def convert_interpolate2D(g, op, x, input_shape): out_h = int(scale[0] * in_h) out_w = int(scale[1] * in_w) - rounding_method, interp_method, coordinate_transformation_mode = bilinear_interp_get_mod(op) + rounding_method, interp_method, coordinate_transformation_mode = get_interpolate_mode(op) out = _op.image.resize2d( x, [out_h, out_w], From ff893f45c8dd0143d09b3c04b3b38a603ed48fff Mon Sep 17 00:00:00 2001 From: heliqi <1101791222@qq.com> Date: Fri, 20 Aug 2021 11:34:20 +0800 Subject: [PATCH 29/51] add pad op --- python/tvm/relay/frontend/paddlepaddle.py | 34 ++++++++++++++++ .../frontend/paddlepaddle/test_forward.py | 39 +++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/python/tvm/relay/frontend/paddlepaddle.py b/python/tvm/relay/frontend/paddlepaddle.py index 3af1d4f496ec..db363e4512c8 100644 --- a/python/tvm/relay/frontend/paddlepaddle.py +++ b/python/tvm/relay/frontend/paddlepaddle.py @@ -694,6 +694,39 @@ def convert_pool2d(g, op, block): g.add_node(op.output("Out")[0], out) +def convert_padding(g, op, block): + """Operator converter for padding.""" + + input_x = g.get_node(op.input("X")[0]) + input_padding = op.input("Paddings") + if input_padding: + padding = g.get_node(input_padding[0]) + padding = infer_value(padding, g.get_params()).numpy().tolist() + else: + padding = op.attr("paddings") + padding = op.attr("paddings") + value = op.attr("value") + data_format = op.attr("data_format") + mode = op.attr("mode") + assert mode != "circular", "Don't support mod='circular' for PaddlePaddle's padding" + if mode == "replicate": + mode = "edge" + + new_pad_len = len(infer_shape(input_x)) * 2 + new_paddings = [0] * new_pad_len + for i in range(0, len(padding), 2): + index = -1 - i + if data_format[:2] != "NC": + index = -3 - i + new_paddings[index] = padding[i + 1] + new_paddings[index - 1] = padding[i] + + new_paddings = [new_paddings[i : i + 2] for i in range(0, len(new_paddings), 2)] + + out = _op.nn.pad(input_x, new_paddings, pad_value=value, pad_mode=mode) + g.add_node(op.output("Out")[0], out) + + def convert_reshape(g, op, block): """Operator converter for reshape.""" @@ -862,6 +895,7 @@ def convert_unsqueeze(g, op, block): "mul": convert_mul, "nearest_interp_v2": convert_interpolate, "pool2d": convert_pool2d, + "pad3d": convert_padding, "relu": convert_activation, "reshape2": convert_reshape, "scale": convert_scale, diff --git a/tests/python/frontend/paddlepaddle/test_forward.py b/tests/python/frontend/paddlepaddle/test_forward.py index 85c6c610724f..662cf268c667 100644 --- a/tests/python/frontend/paddlepaddle/test_forward.py +++ b/tests/python/frontend/paddlepaddle/test_forward.py @@ -567,6 +567,44 @@ def pool2d3(inputs): # verify_model(pool2d3, input_data=input_data) +@tvm.testing.uses_gpu +def test_forward_pad(): + class Pad1(nn.Layer): + def __init__(self): + super(Pad, self).__init__() + self.pad = nn.Pad3D(padding=[1, 2, 3, 4, 5, 6], mode="replicate", value=0.5) + + @paddle.jit.to_static + def forward(self, inputs): + return self.pad(inputs) + + @paddle.jit.to_static + def pad2(inputs): + return paddle.nn.functional.pad( + inputs, [1, 3, 1, 4, 1, 0], mode="constant", value=2.2, data_format="NDHWC" + ) + + @paddle.jit.to_static + def pad3(inputs): + return paddle.nn.functional.pad( + inputs, [2, 3, 1, 0], mode="reflect", value=2.0, data_format="NCHW" + ) + + @paddle.jit.to_static + def pad4(inputs): + return paddle.nn.functional.pad( + inputs, [2, 1], mode="replicate", value=2.0, data_format="NLC" + ) + + input_data = paddle.rand([2, 3, 6, 7, 8], dtype="float32") + verify_model(Pad1(), input_data=input_data) + verify_model(pad2, input_data=input_data) + input_data = paddle.rand([2, 4, 3, 5], dtype="float32") + verify_model(pad3, input_data=input_data) + input_data = paddle.rand([2, 4, 5], dtype="float32") + verify_model(pad4, input_data=input_data) + + @tvm.testing.uses_gpu def test_forward_relu(): @paddle.jit.to_static @@ -717,6 +755,7 @@ def tanh(inputs): test_forward_multiply() test_forward_matmul() test_forward_pool2d() + test_forward_pad() test_forward_relu() test_forward_reshape() test_forward_scale() From b31be857bf1f0c6c8108fc1513b04b33aed8feec Mon Sep 17 00:00:00 2001 From: heliqi <1101791222@qq.com> Date: Fri, 20 Aug 2021 11:38:37 +0800 Subject: [PATCH 30/51] add pad1d padd2d --- python/tvm/relay/frontend/paddlepaddle.py | 2 ++ tests/python/frontend/paddlepaddle/test_forward.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/python/tvm/relay/frontend/paddlepaddle.py b/python/tvm/relay/frontend/paddlepaddle.py index db363e4512c8..702457ac71e6 100644 --- a/python/tvm/relay/frontend/paddlepaddle.py +++ b/python/tvm/relay/frontend/paddlepaddle.py @@ -895,6 +895,8 @@ def convert_unsqueeze(g, op, block): "mul": convert_mul, "nearest_interp_v2": convert_interpolate, "pool2d": convert_pool2d, + "pad1d": convert_padding, + "pad2d": convert_padding, "pad3d": convert_padding, "relu": convert_activation, "reshape2": convert_reshape, diff --git a/tests/python/frontend/paddlepaddle/test_forward.py b/tests/python/frontend/paddlepaddle/test_forward.py index 662cf268c667..e4756b040aa1 100644 --- a/tests/python/frontend/paddlepaddle/test_forward.py +++ b/tests/python/frontend/paddlepaddle/test_forward.py @@ -571,7 +571,7 @@ def pool2d3(inputs): def test_forward_pad(): class Pad1(nn.Layer): def __init__(self): - super(Pad, self).__init__() + super(Pad1, self).__init__() self.pad = nn.Pad3D(padding=[1, 2, 3, 4, 5, 6], mode="replicate", value=0.5) @paddle.jit.to_static From f7fcd84f868e36df3eaa6b9e201c120f5b913bd2 Mon Sep 17 00:00:00 2001 From: heliqi <1101791222@qq.com> Date: Fri, 20 Aug 2021 15:08:06 +0800 Subject: [PATCH 31/51] foramtting --- python/tvm/relay/frontend/paddlepaddle.py | 30 +++++++++++------------ 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/python/tvm/relay/frontend/paddlepaddle.py b/python/tvm/relay/frontend/paddlepaddle.py index 702457ac71e6..447b3a645a09 100644 --- a/python/tvm/relay/frontend/paddlepaddle.py +++ b/python/tvm/relay/frontend/paddlepaddle.py @@ -140,7 +140,7 @@ def get_interpolate_mode(op): return rounding_method, interp_method, coordinate_transformation_mode -def convert_interpolate2D(g, op, x, input_shape): +def convert_interpolate2d(g, op, x, input_shape): """Operator converter for interpolate 2D(dims == 4).""" layout = op.attr("data_layout") @@ -152,19 +152,19 @@ def convert_interpolate2D(g, op, x, input_shape): out_h = op.attr("out_h") out_w = op.attr("out_w") - OutSize = op.input("OutSize") - SizeTensor = op.input("SizeTensor") - Scale = op.input("Scale") - if SizeTensor: - outsize = g.get_node(SizeTensor[0]) - outsize = infer_value(outsize, g.get_params()).numpy().tolist() - out_h, out_w = outsize - elif OutSize: - outsize = g.get_node(OutSize[0]) - outsize = infer_value(outsize, g.get_params()).numpy().tolist() - out_h, out_w = outsize - elif Scale: - scale_data = g.get_node(Scale[0]) + input_out_size = op.input("OutSize") + input_size_tensor = op.input("SizeTensor") + input_scale = op.input("Scale") + if input_size_tensor: + out_size = g.get_node(input_size_tensor[0]) + out_size = infer_value(out_size, g.get_params()).numpy().tolist() + out_h, out_w = out_size + elif input_out_size: + out_size = g.get_node(input_out_size[0]) + out_size = infer_value(out_size, g.get_params()).numpy().tolist() + out_h, out_w = out_size + elif input_scale: + scale_data = g.get_node(input_scale[0]) scale_data = infer_value(scale_data, g.get_params()).numpy().tolist() if len(scale_data) > 1: out_h = int(scale_data[0] * in_h) @@ -199,7 +199,7 @@ def convert_interpolate(g, op, block): input_shape = infer_shape(x) dims = len(input_shape) if dims == 4: - convert_interpolate2D(g, op, x, input_shape) + convert_interpolate2d(g, op, x, input_shape) else: msg = "input_shape {} is not supported for PaddlePaddle's interpolate" raise tvm.error.OpAttributeInvalid(msg.format(dims)) From 272c8f970d91127bd13c3085596c5a962f0db6ab Mon Sep 17 00:00:00 2001 From: wjj19950828 Date: Fri, 20 Aug 2021 17:50:15 +0800 Subject: [PATCH 32/51] Add conv_transpose and sigmoid --- python/tvm/relay/frontend/paddlepaddle.py | 150 +++++++++++++----- .../frontend/paddlepaddle/test_forward.py | 107 ++++++++++--- 2 files changed, 192 insertions(+), 65 deletions(-) diff --git a/python/tvm/relay/frontend/paddlepaddle.py b/python/tvm/relay/frontend/paddlepaddle.py index c67c8b9c39e0..7116bc2ad13e 100644 --- a/python/tvm/relay/frontend/paddlepaddle.py +++ b/python/tvm/relay/frontend/paddlepaddle.py @@ -17,9 +17,7 @@ # pylint: disable=invalid-name, import-self, len-as-condition, unused-argument, too-many-lines # pylint: disable=import-outside-toplevel """Paddle: PArallel Distributed Deep LEarning.""" -import copy import warnings -import six import numpy as np @@ -43,6 +41,8 @@ def shape_of(x, dtype="int32"): + """Get shape of a tensor""" + ttype = infer_type(x).checked_type if not _ty.is_dynamic(ttype): shape = list(ttype.shape) @@ -51,6 +51,8 @@ def shape_of(x, dtype="int32"): def _get_pad_size(in_size, dilated_kernel_size, stride_size): + """calculate the paddings size""" + if stride_size == 1 or in_size % stride_size == 0: pad = max(dilated_kernel_size - stride_size, 0) else: @@ -94,7 +96,6 @@ def convert_batch_norm(g, op, block): mean_name = op.input("Mean")[0] variance_name = op.input("Variance")[0] epsilon = op.attr("epsilon") - momentum = op.attr("momentum") out = _op.nn.batch_norm( g.get_node(ipt_name), g.get_node(scale_name), @@ -127,6 +128,7 @@ def convert_concat(g, op, block): def convert_conv2d(g, op, block): """Operator converter for conv2d.""" + dilations = op.attr("dilations") groups = op.attr("groups") paddings = op.attr("paddings") @@ -134,9 +136,9 @@ def convert_conv2d(g, op, block): strides = op.attr("strides") kernel = g.get_node(op.input("Filter")[0]) - input = g.get_node(op.input("Input")[0]) + input_x = g.get_node(op.input("Input")[0]) out_channels, _, k_h, k_w = infer_shape(kernel) - in_h, in_w = infer_shape(input)[2:] + in_h, in_w = infer_shape(input_x)[2:] if padding_algorithm == "VALID": paddings = [0, 0] elif padding_algorithm == "SAME": @@ -149,11 +151,54 @@ def convert_conv2d(g, op, block): if len(paddings) == 4: paddings = [paddings[0], paddings[2], paddings[1], paddings[3]] else: - msg = 'Value {} in attribute "padding" of operator Conv is not ' "valid." + msg = 'Value {} in attribute "padding" of operator Conv is not "valid."' raise tvm.error.OpAttributeInvalid(msg.format(padding_algorithm)) out = _op.nn.conv2d( - input, + input_x, + kernel, + strides=strides, + padding=paddings, + dilation=dilations, + groups=groups, + channels=out_channels, + kernel_size=[k_h, k_w], + ) + g.add_node(op.output("Output")[0], out) + + +def convert_conv2d_transpose(g, op, block): + """Operator converter for conv2d_transpose.""" + + dilations = op.attr("dilations") + groups = op.attr("groups") + paddings = op.attr("paddings") + padding_algorithm = op.attr("padding_algorithm") + strides = op.attr("strides") + output_padding = op.attr("output_padding") if op.attr( + "output_padding") else [0, 0] + + kernel = g.get_node(op.input("Filter")[0]) + input_x = g.get_node(op.input("Input")[0]) + _, out_channels, k_h, k_w = infer_shape(kernel) + in_h, in_w = infer_shape(input_x)[2:] + if padding_algorithm == "VALID": + paddings = [0, 0] + elif padding_algorithm == "SAME": + pad_h = _get_pad_size(in_h, (k_h - 1) * dilations[0] + 1, strides[0]) + pad_w = _get_pad_size(in_w, (k_w - 1) * dilations[1] + 1, strides[1]) + paddings = [pad_h[0], pad_w[0], pad_h[1], pad_w[1]] + elif padding_algorithm == "EXPLICIT": + if len(paddings) == 2: + paddings = [paddings[0], paddings[1], paddings[0], paddings[1]] + if len(paddings) == 4: + paddings = [paddings[0], paddings[2], paddings[1], paddings[3]] + else: + msg = 'Value {} in attribute "padding" of operator Conv is not "valid."' + raise tvm.error.OpAttributeInvalid(msg.format(padding_algorithm)) + + out = _op.nn.conv2d_transpose( + input_x, kernel, strides=strides, padding=paddings, @@ -161,6 +206,7 @@ def convert_conv2d(g, op, block): groups=groups, channels=out_channels, kernel_size=[k_h, k_w], + output_padding=output_padding, ) g.add_node(op.output("Output")[0], out) @@ -213,7 +259,8 @@ def convert_elementwise_op(g, op, block): if axis < 0: 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)) + ipt1 = _op.expand_dims( + ipt1, axis=axis, num_newaxis=(len(ipt0_shape) - axis - 1)) out = op_func(ipt0, ipt1) g.add_node(op.output("Out")[0], out) @@ -303,7 +350,8 @@ def convert_gelu(g, op, block): x = g.get_node(op.input("X")[0]) out = x * ( _expr.const(0.5, dtype="float32") - + _op.erf(x * _expr.const(0.5 ** 0.5, dtype="float32")) * _expr.const(0.5, dtype="float32") + + _op.erf(x * _expr.const(0.5 ** 0.5, dtype="float32")) * + _expr.const(0.5, dtype="float32") ) g.add_node(op.output("Out")[0], out) @@ -312,7 +360,6 @@ def convert_hard_sigmoid(g, op, block): """Operator converter for hard_sigmoid.""" slope = op.attr("slope") - offset = op.attr("offset") x = g.get_node(op.input("X")[0]) out = x * _expr.const(slope) + _expr.const(0.5) out = _op.clip(out, 0, 1) @@ -325,9 +372,12 @@ def convert_hard_swish(g, op, block): offset = op.attr("offset") scale = op.attr("scale") threshold = op.attr("threshold") - assert np.isclose(offset, 3.0), "Only support offset==3.0 for PaddlePaddle's hard_swish" - assert np.isclose(scale, 6.0), "Only support scale==6.0 for PaddlePaddle's hard_swish" - assert np.isclose(threshold, 6.0), "Only support threshold==6.0 for PaddlePaddle's hard_swish" + assert np.isclose( + offset, 3.0), "Only support offset==3.0 for PaddlePaddle's hard_swish" + assert np.isclose( + scale, 6.0), "Only support scale==6.0 for PaddlePaddle's hard_swish" + assert np.isclose( + threshold, 6.0), "Only support threshold==6.0 for PaddlePaddle's hard_swish" x = g.get_node(op.input("X")[0]) out = _op.clip(x, -1 * offset, offset) out = out / _expr.const(threshold) + _expr.const(0.5) @@ -345,8 +395,9 @@ def convert_layer_norm(g, op, block): scale_input = op.input("Scale") x_shape = infer_shape(x) - assert ( - begin_norm_axis == -1 or begin_norm_axis == len(x_shape) - 1 + assert begin_norm_axis in ( + len(x_shape) - 1, + -1, ), "Support only normalization over last one dimension." if bias_input: @@ -379,8 +430,6 @@ def convert_lookup_table(g, op, block): indices = g.get_node(op.input("Ids")[0]) padding_idx = op.attr("padding_idx") - is_sparse = op.attr("is_sparse") - height_sections = op.attr("height_sections") if padding_idx != -1: g.get_params[op.input("W")[0]][padding_idx] = 0.0 g.add_node(op.input("W")[0], _expr.const(g.params[op.input("W")[0]])) @@ -395,11 +444,11 @@ def convert_matmul(g, op, block): inputs = [g.get_node(op.input("X")[0]), g.get_node(op.input("Y")[0])] a_shape = infer_shape(inputs[0]) b_shape = infer_shape(inputs[1]) - try: + if op.has_attr("trans_x"): # for matmul_v2 trans_x = op.attr("trans_x") trans_y = op.attr("trans_y") - except: + else: # for matmul trans_x = op.attr("transpose_X") trans_y = op.attr("transpose_Y") @@ -429,7 +478,8 @@ def flatten_to_nd(x, x_shape, nd=3): return x newshape = _op.concatenate( [ - _expr.const([-1], dtype=infer_type(x_shape).checked_type.dtype), + _expr.const( + [-1], dtype=infer_type(x_shape).checked_type.dtype), _op.strided_slice(x_shape, [ndims - nd + 1], [ndims]), ], 0, @@ -474,10 +524,12 @@ def flatten_to_nd(x, x_shape, nd=3): [ out_batch, _op.strided_slice( - a_shape, [infer_shape(a_shape)[0] - 2], [infer_shape(a_shape)[0] - 1] + a_shape, [infer_shape(a_shape)[0] - + 2], [infer_shape(a_shape)[0] - 1] ), _op.strided_slice( - b_shape, [infer_shape(b_shape)[0] - 1], [infer_shape(b_shape)[0]] + b_shape, [infer_shape(b_shape)[0] - + 1], [infer_shape(b_shape)[0]] ), ], 0, @@ -491,12 +543,10 @@ def flatten_to_nd(x, x_shape, nd=3): out = _op.nn.dense(inputs[0], input_1_t) if b_rank == 1: out = _op.squeeze(out, axis=[-1]) - try: + if op.has_attr("alpha"): alpha = op.attr("alpha") if not np.isclose(alpha, 1.0): out = out * _expr.const(alpha).astype("float32") - except: - pass g.add_node(op.output("Out")[0], out) @@ -518,7 +568,8 @@ def convert_mul(g, op, block): if x_num_col_dims == 1: x = _op.nn.batch_flatten(x) else: - pre_shape = _op.prod(_op.strided_slice(x_shape, [0], [x_num_col_dims], [1]), keepdims=True) + pre_shape = _op.prod(_op.strided_slice( + x_shape, [0], [x_num_col_dims], [1]), keepdims=True) post_shape = _op.prod( _op.strided_slice(x_shape, [x_num_col_dims], [x_dim], [1]), keepdims=True ) @@ -528,7 +579,8 @@ def convert_mul(g, op, block): if y_num_col_dims == 1: y = _op.nn.batch_flatten(y) else: - pre_shape = _op.prod(_op.strided_slice(y_shape, [0], [y_num_col_dims], [1]), keepdims=True) + pre_shape = _op.prod(_op.strided_slice( + y_shape, [0], [y_num_col_dims], [1]), keepdims=True) post_shape = _op.prod( _op.strided_slice(y_shape, [y_num_col_dims], [y_dim], [1]), keepdims=True ) @@ -559,8 +611,8 @@ def convert_pool2d(g, op, block): adaptive = True ksize = [1, 1] - input = g.get_node(op.input("X")[0]) - in_h, in_w = infer_shape(input)[2:] + input_x = g.get_node(op.input("X")[0]) + in_h, in_w = infer_shape(input_x)[2:] op_map = { "avg": "avg_pool2d", @@ -586,16 +638,16 @@ def convert_pool2d(g, op, block): if len(paddings) == 4: paddings = [paddings[0], paddings[2], paddings[1], paddings[3]] else: - msg = 'Value {} in attribute "padding" of operator Pool2d is not ' "valid." + msg = 'Value {} in attribute "padding" of operator Pool2d is not "valid."' raise tvm.error.OpAttributeInvalid(msg.format(padding_algorithm)) - x = g.get_node(op.input("X")[0]) if not adaptive: out = getattr(_op.nn, op_map[pooling_type])( - x, pool_size=ksize, strides=strides, padding=paddings, ceil_mode=ceil_mode + input_x, pool_size=ksize, strides=strides, padding=paddings, ceil_mode=ceil_mode ) else: - out = getattr(_op.nn, "adaptive_" + op_map[pooling_type])(x, output_size=ksize) + out = getattr(_op.nn, "adaptive_" + + op_map[pooling_type])(input_x, output_size=ksize) g.add_node(op.output("Out")[0], out) @@ -724,13 +776,23 @@ def convert_unsqueeze(g, op, block): g.add_node(op.output("Out")[0], x) +def convert_sigmoid(g, op, block): + """Operator converter for sigmoid.""" + + x = g.get_node(op.input("X")[0]) + out = _op.sigmoid(x) + g.add_node(op.output("Out")[0], out) + + _convert_map = { + "sigmoid": convert_sigmoid, "arg_max": convert_arg_max, "assign": convert_assign, "batch_norm": convert_batch_norm, "cast": convert_cast, "concat": convert_concat, "conv2d": convert_conv2d, + "conv2d_transpose": convert_conv2d_transpose, "cumsum": convert_cumsum, "depthwise_conv2d": convert_conv2d, "dropout": convert_dropout, @@ -764,7 +826,7 @@ def convert_unsqueeze(g, op, block): } -class GraphProto(object): +class GraphProto: """A helper class for handling relay functions from PaddlePaddle model.""" def __init__(self): @@ -773,13 +835,19 @@ def __init__(self): self.shape_dict = None def get_node(self, name): + """get node from graph""" + assert name in self.nodes return self.nodes[name] def add_node(self, name, node): + """add a node to graph""" + self.nodes[name] = fold_constant(node) def get_params(self, name=None): + """get params from graph""" + if name is None: return self.params assert name in self.params @@ -809,17 +877,18 @@ def check_input_shape(self, op, block): ipt_shape = block.var(ipt_name).shape for i in ipt_shape: if i < 0: - warning_msg = "Input {}(shape={}) has unkown dimension shapes. Specifying static values may improve performance".format( + warning_msg = "Input {}(shape={}) has unkown dimension shapes. \ + Specifying static values may improve performance".format( ipt_name, ipt_shape ) - warings.warn(warning_msg) + warnings.warn(warning_msg) def check_unsupported_ops(self, program): """Check whether all the operators are supported.""" unsupported_ops = set() for block in program.blocks: - for i, op in enumerate(block.ops): + for op in block.ops: if op.type == "fetch": continue if op.type not in _convert_map: @@ -836,7 +905,7 @@ def ops_to_relay(self, program, input_specs=None): for input_spec in input_specs: convert_feed(self, input_spec, None) for block in program.blocks: - for i, op in enumerate(block.ops): + for op in block.ops: if op.type == "fetch": continue convert_func = _convert_map[op.type] @@ -856,7 +925,7 @@ def from_program(self, program, shape_dict, scope): output_names = list() for block in program.blocks: - for i, op in enumerate(block.ops): + for op in block.ops: if op.type == "fetch": output_names.append(op.input("X")[0]) @@ -910,5 +979,6 @@ def from_paddle(program_or_layer, shape_dict=None, scope=None): # model is loaded by `paddle.static.load_inference_model` mod, params = g.from_program(program_or_layer, shape_dict, scope) else: - raise Exception("Only PaddlePaddle's Program and TranslatedLayer are supported.") + raise Exception( + "Only PaddlePaddle's Program and TranslatedLayer are supported.") return mod, params diff --git a/tests/python/frontend/paddlepaddle/test_forward.py b/tests/python/frontend/paddlepaddle/test_forward.py index db07e07f9d83..af925bd81ceb 100644 --- a/tests/python/frontend/paddlepaddle/test_forward.py +++ b/tests/python/frontend/paddlepaddle/test_forward.py @@ -320,6 +320,50 @@ def forward(self, inputs): verify_model(Conv2D2(), input_data=conv2d_input_data) +@tvm.testing.uses_gpu +def test_forward_conv_transpose(): + # Note we do not test with groups > 1 because that is not supported + # in tvm for conv transpose operations + + class Conv2DTranspose1(nn.Layer): + def __init__(self): + super(Conv2DTranspose1, self).__init__() + self.conv_transpose = nn.Conv2DTranspose(3, 5, 3) + + @paddle.jit.to_static + def forward(self, inputs): + return self.conv_transpose(inputs) + + class Conv2DTranspose2(nn.Layer): + def __init__(self): + super(Conv2DTranspose2, self).__init__() + self.conv_transpose = nn.Conv2DTranspose( + 3, 5, 3, stride=2, output_padding=1, bias_attr=True + ) + + @paddle.jit.to_static + def forward(self, inputs): + return self.conv_transpose(inputs) + + class Conv2DTranspose3(nn.Layer): + def __init__(self): + super(Conv2DTranspose3, self).__init__() + self.conv_transpose = nn.Conv2DTranspose( + 3, 5, 3, stride=3, output_padding=2, bias_attr=True + ) + + @paddle.jit.to_static + def forward(self, inputs): + return self.conv_transpose(inputs) + + # Conv 2D Transpose Tests + conv2d_transpose_input_shape = [1, 3, 128, 256] + conv2d_transpose_input_data = paddle.rand(conv2d_transpose_input_shape, dtype="float32") + verify_model(Conv2DTranspose1(), input_data=conv2d_transpose_input_data) + verify_model(Conv2DTranspose2(), input_data=conv2d_transpose_input_data) + verify_model(Conv2DTranspose3(), input_data=conv2d_transpose_input_data) + + @tvm.testing.uses_gpu def test_forward_dropout(): @paddle.jit.to_static @@ -633,29 +677,42 @@ def tanh(inputs): verify_model(tanh, input_data=input_data) +@tvm.testing.uses_gpu +def test_forward_sigmoid(): + @paddle.jit.to_static + def sigmoid(inputs): + return nn.functional.sigmoid(inputs) + + input_shape = [10, 10] + input_data = paddle.rand(input_shape, dtype="float32") + verify_model(sigmoid, input_data=input_data) + + if __name__ == "__main__": - test_forward_add_subtract() - test_forward_argmax() - test_forward_assign() - test_forward_batch_norm() - test_forward_cast() - test_forward_concat_unsqueeze() - test_forward_cumsum() - test_forward_conv() - test_forward_dropout() - test_forward_shape_full() - test_forward_ones_like() - test_forward_gelu() - test_forward_hard_sigmoid() - test_forward_hard_swish() - test_forward_layer_norm() - test_forward_leaky_relu() - test_forward_look_up() - test_forward_multiply() - test_forward_matmul() - test_forward_pool2d() - test_forward_relu() - test_forward_reshape() - test_forward_scale() - test_forward_slice() - test_forward_tanh() + # test_forward_add_subtract() + # test_forward_argmax() + # test_forward_assign() + # test_forward_batch_norm() + # test_forward_cast() + # test_forward_concat_unsqueeze() + # test_forward_cumsum() + # test_forward_conv() + # test_forward_dropout() + # test_forward_shape_full() + # test_forward_ones_like() + # test_forward_gelu() + # test_forward_hard_sigmoid() + # test_forward_hard_swish() + # test_forward_layer_norm() + # test_forward_leaky_relu() + # test_forward_look_up() + # test_forward_multiply() + # test_forward_matmul() + # test_forward_pool2d() + # test_forward_relu() + # test_forward_reshape() + # test_forward_scale() + # test_forward_slice() + # test_forward_tanh() + test_forward_conv_transpose() + test_forward_sigmoid() From e116cd5aefc67de31aa826f8f656c9f9e3bdb638 Mon Sep 17 00:00:00 2001 From: wjj19950828 Date: Fri, 20 Aug 2021 17:58:00 +0800 Subject: [PATCH 33/51] fixed bug --- .../frontend/paddlepaddle/test_forward.py | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/tests/python/frontend/paddlepaddle/test_forward.py b/tests/python/frontend/paddlepaddle/test_forward.py index af925bd81ceb..38609cc7a609 100644 --- a/tests/python/frontend/paddlepaddle/test_forward.py +++ b/tests/python/frontend/paddlepaddle/test_forward.py @@ -689,30 +689,30 @@ def sigmoid(inputs): if __name__ == "__main__": - # test_forward_add_subtract() - # test_forward_argmax() - # test_forward_assign() - # test_forward_batch_norm() - # test_forward_cast() - # test_forward_concat_unsqueeze() - # test_forward_cumsum() - # test_forward_conv() - # test_forward_dropout() - # test_forward_shape_full() - # test_forward_ones_like() - # test_forward_gelu() - # test_forward_hard_sigmoid() - # test_forward_hard_swish() - # test_forward_layer_norm() - # test_forward_leaky_relu() - # test_forward_look_up() - # test_forward_multiply() - # test_forward_matmul() - # test_forward_pool2d() - # test_forward_relu() - # test_forward_reshape() - # test_forward_scale() - # test_forward_slice() - # test_forward_tanh() + test_forward_add_subtract() + test_forward_argmax() + test_forward_assign() + test_forward_batch_norm() + test_forward_cast() + test_forward_concat_unsqueeze() + test_forward_cumsum() + test_forward_conv() + test_forward_dropout() + test_forward_shape_full() + test_forward_ones_like() + test_forward_gelu() + test_forward_hard_sigmoid() + test_forward_hard_swish() + test_forward_layer_norm() + test_forward_leaky_relu() + test_forward_look_up() + test_forward_multiply() + test_forward_matmul() + test_forward_pool2d() + test_forward_relu() + test_forward_reshape() + test_forward_scale() + test_forward_slice() + test_forward_tanh() test_forward_conv_transpose() test_forward_sigmoid() From dd8d08c45c33e458bb40be1165126bd1816f6ed6 Mon Sep 17 00:00:00 2001 From: wjj19950828 Date: Sun, 22 Aug 2021 15:30:04 +0800 Subject: [PATCH 34/51] fixed conflicts --- python/tvm/relay/frontend/paddlepaddle.py | 186 +++++++++++++++++++--- 1 file changed, 161 insertions(+), 25 deletions(-) diff --git a/python/tvm/relay/frontend/paddlepaddle.py b/python/tvm/relay/frontend/paddlepaddle.py index 7116bc2ad13e..68b09bba5447 100644 --- a/python/tvm/relay/frontend/paddlepaddle.py +++ b/python/tvm/relay/frontend/paddlepaddle.py @@ -107,6 +107,104 @@ def convert_batch_norm(g, op, block): g.add_node(op.output("Y")[0], out[0]) +def get_interpolate_mode(op): + """conver 'interp_method' attr of paddle to tvm""" + + interp_method = op.attr("interp_method") + align_corners = op.attr("align_corners") + align_mode = op.attr("align_mode") + + rounding_method = "" + if interp_method == "nearest": + interp_method = "nearest_neighbor" + coordinate_transformation_mode = "asymmetric" + rounding_method = "floor" + elif interp_method == "bilinear": + interp_method = "linear" + if not align_corners and align_mode == 0: + coordinate_transformation_mode = "half_pixel" + else: + if align_corners: + coordinate_transformation_mode = "align_corners" + else: + coordinate_transformation_mode = "asymmetric" + elif interp_method == "bicubic": + interp_method = "cubic" + if align_corners: + coordinate_transformation_mode = "align_corners" + else: + coordinate_transformation_mode = "half_pixel" + else: + msg = "interp_method {} is not supported for PaddlePaddle's interpolate" + raise tvm.error.OpAttributeInvalid(msg.format(interp_method)) + return rounding_method, interp_method, coordinate_transformation_mode + + +def convert_interpolate2d(g, op, x, input_shape): + """Operator converter for interpolate 2D(dims == 4).""" + + layout = op.attr("data_layout") + if layout == "NCHW": + in_h, in_w = input_shape[2], input_shape[3] + else: + in_h, in_w = input_shape[1], input_shape[2] + + out_h = op.attr("out_h") + out_w = op.attr("out_w") + + input_out_size = op.input("OutSize") + input_size_tensor = op.input("SizeTensor") + input_scale = op.input("Scale") + if input_size_tensor: + out_size = g.get_node(input_size_tensor[0]) + out_size = infer_value(out_size, g.get_params()).numpy().tolist() + out_h, out_w = out_size + elif input_out_size: + out_size = g.get_node(input_out_size[0]) + out_size = infer_value(out_size, g.get_params()).numpy().tolist() + out_h, out_w = out_size + elif input_scale: + scale_data = g.get_node(input_scale[0]) + scale_data = infer_value(scale_data, g.get_params()).numpy().tolist() + if len(scale_data) > 1: + out_h = int(scale_data[0] * in_h) + out_w = int(scale_data[1] * in_w) + else: + out_h = int(scale_data[0] * in_h) + out_w = int(scale_data[0] * in_w) + else: + scale = op.attr("scale") + scale = [float(i) for i in scale] + if len(scale) > 1: + out_h = int(scale[0] * in_h) + out_w = int(scale[1] * in_w) + + rounding_method, interp_method, coordinate_transformation_mode = get_interpolate_mode(op) + out = _op.image.resize2d( + x, + [out_h, out_w], + layout=layout, + method=interp_method, + coordinate_transformation_mode=coordinate_transformation_mode, + rounding_method=rounding_method, + cubic_alpha=-0.75, + ) + g.add_node(op.output("Out")[0], out) + + +def convert_interpolate(g, op, block): + """Operator converter for interpolate.""" + + x = g.get_node(op.input("X")[0]) + input_shape = infer_shape(x) + dims = len(input_shape) + if dims == 4: + convert_interpolate2d(g, op, x, input_shape) + else: + msg = "input_shape {} is not supported for PaddlePaddle's interpolate" + raise tvm.error.OpAttributeInvalid(msg.format(dims)) + + def convert_cast(g, op, block): """Operator converter for cast.""" @@ -259,8 +357,7 @@ def convert_elementwise_op(g, op, block): if axis < 0: 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)) + ipt1 = _op.expand_dims(ipt1, axis=axis, num_newaxis=(len(ipt0_shape) - axis - 1)) out = op_func(ipt0, ipt1) g.add_node(op.output("Out")[0], out) @@ -350,8 +447,7 @@ def convert_gelu(g, op, block): x = g.get_node(op.input("X")[0]) out = x * ( _expr.const(0.5, dtype="float32") - + _op.erf(x * _expr.const(0.5 ** 0.5, dtype="float32")) * - _expr.const(0.5, dtype="float32") + + _op.erf(x * _expr.const(0.5 ** 0.5, dtype="float32")) * _expr.const(0.5, dtype="float32") ) g.add_node(op.output("Out")[0], out) @@ -372,12 +468,9 @@ def convert_hard_swish(g, op, block): offset = op.attr("offset") scale = op.attr("scale") threshold = op.attr("threshold") - assert np.isclose( - offset, 3.0), "Only support offset==3.0 for PaddlePaddle's hard_swish" - assert np.isclose( - scale, 6.0), "Only support scale==6.0 for PaddlePaddle's hard_swish" - assert np.isclose( - threshold, 6.0), "Only support threshold==6.0 for PaddlePaddle's hard_swish" + assert np.isclose(offset, 3.0), "Only support offset==3.0 for PaddlePaddle's hard_swish" + assert np.isclose(scale, 6.0), "Only support scale==6.0 for PaddlePaddle's hard_swish" + assert np.isclose(threshold, 6.0), "Only support threshold==6.0 for PaddlePaddle's hard_swish" x = g.get_node(op.input("X")[0]) out = _op.clip(x, -1 * offset, offset) out = out / _expr.const(threshold) + _expr.const(0.5) @@ -478,8 +571,7 @@ def flatten_to_nd(x, x_shape, nd=3): return x newshape = _op.concatenate( [ - _expr.const( - [-1], dtype=infer_type(x_shape).checked_type.dtype), + _expr.const([-1], dtype=infer_type(x_shape).checked_type.dtype), _op.strided_slice(x_shape, [ndims - nd + 1], [ndims]), ], 0, @@ -524,12 +616,10 @@ def flatten_to_nd(x, x_shape, nd=3): [ out_batch, _op.strided_slice( - a_shape, [infer_shape(a_shape)[0] - - 2], [infer_shape(a_shape)[0] - 1] + a_shape, [infer_shape(a_shape)[0] - 2], [infer_shape(a_shape)[0] - 1] ), _op.strided_slice( - b_shape, [infer_shape(b_shape)[0] - - 1], [infer_shape(b_shape)[0]] + b_shape, [infer_shape(b_shape)[0] - 1], [infer_shape(b_shape)[0]] ), ], 0, @@ -568,8 +658,7 @@ def convert_mul(g, op, block): if x_num_col_dims == 1: x = _op.nn.batch_flatten(x) else: - pre_shape = _op.prod(_op.strided_slice( - x_shape, [0], [x_num_col_dims], [1]), keepdims=True) + pre_shape = _op.prod(_op.strided_slice(x_shape, [0], [x_num_col_dims], [1]), keepdims=True) post_shape = _op.prod( _op.strided_slice(x_shape, [x_num_col_dims], [x_dim], [1]), keepdims=True ) @@ -579,8 +668,7 @@ def convert_mul(g, op, block): if y_num_col_dims == 1: y = _op.nn.batch_flatten(y) else: - pre_shape = _op.prod(_op.strided_slice( - y_shape, [0], [y_num_col_dims], [1]), keepdims=True) + pre_shape = _op.prod(_op.strided_slice(y_shape, [0], [y_num_col_dims], [1]), keepdims=True) post_shape = _op.prod( _op.strided_slice(y_shape, [y_num_col_dims], [y_dim], [1]), keepdims=True ) @@ -646,8 +734,40 @@ def convert_pool2d(g, op, block): input_x, pool_size=ksize, strides=strides, padding=paddings, ceil_mode=ceil_mode ) else: - out = getattr(_op.nn, "adaptive_" + - op_map[pooling_type])(input_x, output_size=ksize) + out = getattr(_op.nn, "adaptive_" + op_map[pooling_type])(input_x, output_size=ksize) + g.add_node(op.output("Out")[0], out) + + +def convert_padding(g, op, block): + """Operator converter for padding.""" + + input_x = g.get_node(op.input("X")[0]) + input_padding = op.input("Paddings") + if input_padding: + padding = g.get_node(input_padding[0]) + padding = infer_value(padding, g.get_params()).numpy().tolist() + else: + padding = op.attr("paddings") + padding = op.attr("paddings") + value = op.attr("value") + data_format = op.attr("data_format") + mode = op.attr("mode") + assert mode != "circular", "Don't support mod='circular' for PaddlePaddle's padding" + if mode == "replicate": + mode = "edge" + + new_pad_len = len(infer_shape(input_x)) * 2 + new_paddings = [0] * new_pad_len + for i in range(0, len(padding), 2): + index = -1 - i + if data_format[:2] != "NC": + index = -3 - i + new_paddings[index] = padding[i + 1] + new_paddings[index - 1] = padding[i] + + new_paddings = [new_paddings[i : i + 2] for i in range(0, len(new_paddings), 2)] + + out = _op.nn.pad(input_x, new_paddings, pad_value=value, pad_mode=mode) g.add_node(op.output("Out")[0], out) @@ -766,6 +886,17 @@ def convert_softmax(g, op, block): g.add_node(op.output("Out")[0], out) +def convert_squeeze(g, op, block): + """Operator converter for squeeze2.""" + + x = g.get_node(op.input("X")[0]) + axes = op.attr("axes") + if not axes: + axes = None + x = _op.squeeze(x, axis=axes) + g.add_node(op.output("Out")[0], x) + + def convert_unsqueeze(g, op, block): """Operator converter for unsqueeze.""" @@ -789,6 +920,8 @@ def convert_sigmoid(g, op, block): "arg_max": convert_arg_max, "assign": convert_assign, "batch_norm": convert_batch_norm, + "bicubic_interp_v2": convert_interpolate, + "bilinear_interp_v2": convert_interpolate, "cast": convert_cast, "concat": convert_concat, "conv2d": convert_conv2d, @@ -814,13 +947,18 @@ def convert_sigmoid(g, op, block): "matmul": convert_matmul, "matmul_v2": convert_matmul, "mul": convert_mul, + "nearest_interp_v2": convert_interpolate, "pool2d": convert_pool2d, + "pad1d": convert_padding, + "pad2d": convert_padding, + "pad3d": convert_padding, "relu": convert_activation, "reshape2": convert_reshape, "scale": convert_scale, "shape": convert_shape, "slice": convert_slice, "softmax": convert_softmax, + "squeeze2": convert_squeeze, "tanh": convert_activation, "unsqueeze2": convert_unsqueeze, } @@ -964,7 +1102,6 @@ def from_translated_layer(self, layer, shape_dict): def from_paddle(program_or_layer, shape_dict=None, scope=None): """Convert a PaddlePaddle model into an equivalent Relay Function. - PaddlePaddle Program/TranslatedLayer represent the computation graph of PaddlePaddle model, and PaddlePaddle scope stores all the weights of PaddlePaddle model. """ @@ -979,6 +1116,5 @@ def from_paddle(program_or_layer, shape_dict=None, scope=None): # model is loaded by `paddle.static.load_inference_model` mod, params = g.from_program(program_or_layer, shape_dict, scope) else: - raise Exception( - "Only PaddlePaddle's Program and TranslatedLayer are supported.") + raise Exception("Only PaddlePaddle's Program and TranslatedLayer are supported.") return mod, params From 094e8ccd401e527d136fabede06d6da56984bf54 Mon Sep 17 00:00:00 2001 From: wjj19950828 Date: Sun, 22 Aug 2021 15:44:19 +0800 Subject: [PATCH 35/51] fixed bugs --- python/tvm/relay/frontend/paddlepaddle.py | 149 ---------------------- 1 file changed, 149 deletions(-) diff --git a/python/tvm/relay/frontend/paddlepaddle.py b/python/tvm/relay/frontend/paddlepaddle.py index 68b09bba5447..2e7d62e5b448 100644 --- a/python/tvm/relay/frontend/paddlepaddle.py +++ b/python/tvm/relay/frontend/paddlepaddle.py @@ -107,104 +107,6 @@ def convert_batch_norm(g, op, block): g.add_node(op.output("Y")[0], out[0]) -def get_interpolate_mode(op): - """conver 'interp_method' attr of paddle to tvm""" - - interp_method = op.attr("interp_method") - align_corners = op.attr("align_corners") - align_mode = op.attr("align_mode") - - rounding_method = "" - if interp_method == "nearest": - interp_method = "nearest_neighbor" - coordinate_transformation_mode = "asymmetric" - rounding_method = "floor" - elif interp_method == "bilinear": - interp_method = "linear" - if not align_corners and align_mode == 0: - coordinate_transformation_mode = "half_pixel" - else: - if align_corners: - coordinate_transformation_mode = "align_corners" - else: - coordinate_transformation_mode = "asymmetric" - elif interp_method == "bicubic": - interp_method = "cubic" - if align_corners: - coordinate_transformation_mode = "align_corners" - else: - coordinate_transformation_mode = "half_pixel" - else: - msg = "interp_method {} is not supported for PaddlePaddle's interpolate" - raise tvm.error.OpAttributeInvalid(msg.format(interp_method)) - return rounding_method, interp_method, coordinate_transformation_mode - - -def convert_interpolate2d(g, op, x, input_shape): - """Operator converter for interpolate 2D(dims == 4).""" - - layout = op.attr("data_layout") - if layout == "NCHW": - in_h, in_w = input_shape[2], input_shape[3] - else: - in_h, in_w = input_shape[1], input_shape[2] - - out_h = op.attr("out_h") - out_w = op.attr("out_w") - - input_out_size = op.input("OutSize") - input_size_tensor = op.input("SizeTensor") - input_scale = op.input("Scale") - if input_size_tensor: - out_size = g.get_node(input_size_tensor[0]) - out_size = infer_value(out_size, g.get_params()).numpy().tolist() - out_h, out_w = out_size - elif input_out_size: - out_size = g.get_node(input_out_size[0]) - out_size = infer_value(out_size, g.get_params()).numpy().tolist() - out_h, out_w = out_size - elif input_scale: - scale_data = g.get_node(input_scale[0]) - scale_data = infer_value(scale_data, g.get_params()).numpy().tolist() - if len(scale_data) > 1: - out_h = int(scale_data[0] * in_h) - out_w = int(scale_data[1] * in_w) - else: - out_h = int(scale_data[0] * in_h) - out_w = int(scale_data[0] * in_w) - else: - scale = op.attr("scale") - scale = [float(i) for i in scale] - if len(scale) > 1: - out_h = int(scale[0] * in_h) - out_w = int(scale[1] * in_w) - - rounding_method, interp_method, coordinate_transformation_mode = get_interpolate_mode(op) - out = _op.image.resize2d( - x, - [out_h, out_w], - layout=layout, - method=interp_method, - coordinate_transformation_mode=coordinate_transformation_mode, - rounding_method=rounding_method, - cubic_alpha=-0.75, - ) - g.add_node(op.output("Out")[0], out) - - -def convert_interpolate(g, op, block): - """Operator converter for interpolate.""" - - x = g.get_node(op.input("X")[0]) - input_shape = infer_shape(x) - dims = len(input_shape) - if dims == 4: - convert_interpolate2d(g, op, x, input_shape) - else: - msg = "input_shape {} is not supported for PaddlePaddle's interpolate" - raise tvm.error.OpAttributeInvalid(msg.format(dims)) - - def convert_cast(g, op, block): """Operator converter for cast.""" @@ -738,39 +640,6 @@ def convert_pool2d(g, op, block): g.add_node(op.output("Out")[0], out) -def convert_padding(g, op, block): - """Operator converter for padding.""" - - input_x = g.get_node(op.input("X")[0]) - input_padding = op.input("Paddings") - if input_padding: - padding = g.get_node(input_padding[0]) - padding = infer_value(padding, g.get_params()).numpy().tolist() - else: - padding = op.attr("paddings") - padding = op.attr("paddings") - value = op.attr("value") - data_format = op.attr("data_format") - mode = op.attr("mode") - assert mode != "circular", "Don't support mod='circular' for PaddlePaddle's padding" - if mode == "replicate": - mode = "edge" - - new_pad_len = len(infer_shape(input_x)) * 2 - new_paddings = [0] * new_pad_len - for i in range(0, len(padding), 2): - index = -1 - i - if data_format[:2] != "NC": - index = -3 - i - new_paddings[index] = padding[i + 1] - new_paddings[index - 1] = padding[i] - - new_paddings = [new_paddings[i : i + 2] for i in range(0, len(new_paddings), 2)] - - out = _op.nn.pad(input_x, new_paddings, pad_value=value, pad_mode=mode) - g.add_node(op.output("Out")[0], out) - - def convert_reshape(g, op, block): """Operator converter for reshape.""" @@ -886,17 +755,6 @@ def convert_softmax(g, op, block): g.add_node(op.output("Out")[0], out) -def convert_squeeze(g, op, block): - """Operator converter for squeeze2.""" - - x = g.get_node(op.input("X")[0]) - axes = op.attr("axes") - if not axes: - axes = None - x = _op.squeeze(x, axis=axes) - g.add_node(op.output("Out")[0], x) - - def convert_unsqueeze(g, op, block): """Operator converter for unsqueeze.""" @@ -920,8 +778,6 @@ def convert_sigmoid(g, op, block): "arg_max": convert_arg_max, "assign": convert_assign, "batch_norm": convert_batch_norm, - "bicubic_interp_v2": convert_interpolate, - "bilinear_interp_v2": convert_interpolate, "cast": convert_cast, "concat": convert_concat, "conv2d": convert_conv2d, @@ -947,18 +803,13 @@ def convert_sigmoid(g, op, block): "matmul": convert_matmul, "matmul_v2": convert_matmul, "mul": convert_mul, - "nearest_interp_v2": convert_interpolate, "pool2d": convert_pool2d, - "pad1d": convert_padding, - "pad2d": convert_padding, - "pad3d": convert_padding, "relu": convert_activation, "reshape2": convert_reshape, "scale": convert_scale, "shape": convert_shape, "slice": convert_slice, "softmax": convert_softmax, - "squeeze2": convert_squeeze, "tanh": convert_activation, "unsqueeze2": convert_unsqueeze, } From 26858fd742345c59e43579393b458b36317e88b3 Mon Sep 17 00:00:00 2001 From: wjj19950828 Date: Tue, 24 Aug 2021 20:10:52 +0800 Subject: [PATCH 36/51] fixed comments --- .../frontend/paddlepaddle/test_forward.py | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/tests/python/frontend/paddlepaddle/test_forward.py b/tests/python/frontend/paddlepaddle/test_forward.py index 38609cc7a609..0a98e1b82644 100644 --- a/tests/python/frontend/paddlepaddle/test_forward.py +++ b/tests/python/frontend/paddlepaddle/test_forward.py @@ -338,7 +338,7 @@ class Conv2DTranspose2(nn.Layer): def __init__(self): super(Conv2DTranspose2, self).__init__() self.conv_transpose = nn.Conv2DTranspose( - 3, 5, 3, stride=2, output_padding=1, bias_attr=True + 3, 5, 3, stride=2, padding=[[0,0],[0,0],[1,2],[3,4]], output_padding=1, bias_attr=True ) @paddle.jit.to_static @@ -349,7 +349,7 @@ class Conv2DTranspose3(nn.Layer): def __init__(self): super(Conv2DTranspose3, self).__init__() self.conv_transpose = nn.Conv2DTranspose( - 3, 5, 3, stride=3, output_padding=2, bias_attr=True + 3, 5, 3, stride=3, padding='VALID', output_padding=2, bias_attr=True ) @paddle.jit.to_static @@ -689,30 +689,30 @@ def sigmoid(inputs): if __name__ == "__main__": - test_forward_add_subtract() - test_forward_argmax() - test_forward_assign() - test_forward_batch_norm() - test_forward_cast() - test_forward_concat_unsqueeze() - test_forward_cumsum() - test_forward_conv() - test_forward_dropout() - test_forward_shape_full() - test_forward_ones_like() - test_forward_gelu() - test_forward_hard_sigmoid() - test_forward_hard_swish() - test_forward_layer_norm() - test_forward_leaky_relu() - test_forward_look_up() - test_forward_multiply() - test_forward_matmul() - test_forward_pool2d() - test_forward_relu() - test_forward_reshape() - test_forward_scale() - test_forward_slice() - test_forward_tanh() + # test_forward_add_subtract() + # test_forward_argmax() + # test_forward_assign() + # test_forward_batch_norm() + # test_forward_cast() + # test_forward_concat_unsqueeze() + # test_forward_cumsum() + # test_forward_conv() + # test_forward_dropout() + # test_forward_shape_full() + # test_forward_ones_like() + # test_forward_gelu() + # test_forward_hard_sigmoid() + # test_forward_hard_swish() + # test_forward_layer_norm() + # test_forward_leaky_relu() + # test_forward_look_up() + # test_forward_multiply() + # test_forward_matmul() + # test_forward_pool2d() + # test_forward_relu() + # test_forward_reshape() + # test_forward_scale() + # test_forward_slice() + # test_forward_tanh() test_forward_conv_transpose() test_forward_sigmoid() From 428edac56047df13a3502df3742eb6beaab39d3e Mon Sep 17 00:00:00 2001 From: root Date: Mon, 30 Aug 2021 11:15:38 +0000 Subject: [PATCH 37/51] fix fill_constant --- python/tvm/relay/frontend/paddlepaddle.py | 56 ++++++++++------------- 1 file changed, 25 insertions(+), 31 deletions(-) diff --git a/python/tvm/relay/frontend/paddlepaddle.py b/python/tvm/relay/frontend/paddlepaddle.py index f0686408047e..cdf3d9cc188c 100644 --- a/python/tvm/relay/frontend/paddlepaddle.py +++ b/python/tvm/relay/frontend/paddlepaddle.py @@ -64,6 +64,23 @@ def _get_pad_size(in_size, dilated_kernel_size, stride_size): return [pad_before, pad_after] +def convert_activation(g, op, block): + """Operator converter for all the activation.""" + + op_map = { + "exp": _op.exp, + "relu": _op.nn.relu, + "tanh": _op.tanh, + "sqrt": _op.sqrt, + "erf": _op.erf, + "abs": _op.abs, + "sigmoid": _op.sigmoid, + } + act_func = op_map[op.type] + out = act_func(g.get_node(op.input("X")[0])) + g.add_node(op.output("Out")[0], out) + + def convert_arg_max(g, op, block): """Operator converter for arg_max.""" @@ -371,22 +388,6 @@ def convert_equal(g, op, block): g.add_node(op.output("Out")[0], out) -def convert_activation(g, op, block): - """Operator converter for all the activation.""" - - op_map = { - "exp": _op.exp, - "relu": _op.nn.relu, - "tanh": _op.tanh, - "sqrt": _op.sqrt, - "erf": _op.erf, - "abs": _op.abs, - } - act_func = op_map[op.type] - out = act_func(g.get_node(op.input("X")[0])) - g.add_node(op.output("Out")[0], out) - - def convert_feed(g, op, block): """Converter for model input node.""" @@ -430,12 +431,13 @@ def convert_fill_constant(g, op, block): shape = block.var(op.output("Out")[0]).shape dtype = block.var(op.output("Out")[0]).dtype dtype = str(dtype).strip().split(".")[1] - if op.input("ValueTensor"): - shape = g.get_node(op.input("ValueTensor")[0]) - shape = infer_value(shape, g.get_params()).numpy() - if op.input("ShapeTensor"): - shape = g.get_node(op.input("ShapeTensor")[0]) - shape = infer_value(shape, g.get_params()).numpy() + if len(op.input_names) > 0: + if op.input("ValueTensor"): + shape = g.get_node(op.input("ValueTensor")[0]) + shape = infer_value(shape, g.get_params()).numpy() + if op.input("ShapeTensor"): + shape = g.get_node(op.input("ShapeTensor")[0]) + shape = infer_value(shape, g.get_params()).numpy() value = np.full(shape, value, dtype) out = _expr.const(value.astype(dtype)).astype(dtype) g.add_node(op.output("Out")[0], out) @@ -907,16 +909,7 @@ def convert_unsqueeze(g, op, block): g.add_node(op.output("Out")[0], x) -def convert_sigmoid(g, op, block): - """Operator converter for sigmoid.""" - - x = g.get_node(op.input("X")[0]) - out = _op.sigmoid(x) - g.add_node(op.output("Out")[0], out) - - _convert_map = { - "sigmoid": convert_sigmoid, "arg_max": convert_arg_max, "assign": convert_assign, "batch_norm": convert_batch_norm, @@ -956,6 +949,7 @@ def convert_sigmoid(g, op, block): "reshape2": convert_reshape, "scale": convert_scale, "shape": convert_shape, + "sigmoid": convert_activation, "slice": convert_slice, "softmax": convert_softmax, "squeeze2": convert_squeeze, From 4c83872561456c2fa9218198c8ed5ebc0394e2dd Mon Sep 17 00:00:00 2001 From: jiangjiajun Date: Mon, 30 Aug 2021 11:28:01 +0000 Subject: [PATCH 38/51] update paddlepaddle frontend --- python/tvm/relay/frontend/paddlepaddle.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/python/tvm/relay/frontend/paddlepaddle.py b/python/tvm/relay/frontend/paddlepaddle.py index cdf3d9cc188c..a01c2158bd31 100644 --- a/python/tvm/relay/frontend/paddlepaddle.py +++ b/python/tvm/relay/frontend/paddlepaddle.py @@ -1096,8 +1096,9 @@ def from_translated_layer(self, layer, shape_dict): def from_paddle(program_or_layer, shape_dict=None, scope=None): """Convert a PaddlePaddle model into an equivalent Relay Function. - PaddlePaddle Program/TranslatedLayer represent the computation graph of PaddlePaddle model, - and PaddlePaddle scope stores all the weights of PaddlePaddle model. + PaddlePaddle Program/TranslatedLayer represent the computation + graph of PaddlePaddle model, and PaddlePaddle scope stores all the + weights of PaddlePaddle model. """ import paddle From 07ae88877a0026b3b523a87b44d26070a88e0021 Mon Sep 17 00:00:00 2001 From: jiangjiajun Date: Mon, 30 Aug 2021 13:11:55 +0000 Subject: [PATCH 39/51] add bmm and transpose --- python/tvm/relay/frontend/paddlepaddle.py | 89 +++++++++++++++-------- 1 file changed, 59 insertions(+), 30 deletions(-) diff --git a/python/tvm/relay/frontend/paddlepaddle.py b/python/tvm/relay/frontend/paddlepaddle.py index a01c2158bd31..f8173c1e784f 100644 --- a/python/tvm/relay/frontend/paddlepaddle.py +++ b/python/tvm/relay/frontend/paddlepaddle.py @@ -124,42 +124,61 @@ def convert_batch_norm(g, op, block): g.add_node(op.output("Y")[0], out[0]) -def get_interpolate_mode(op): - """conver 'interp_method' attr of paddle to tvm""" - - interp_method = op.attr("interp_method") - align_corners = op.attr("align_corners") - align_mode = op.attr("align_mode") - - rounding_method = "" - if interp_method == "nearest": - interp_method = "nearest_neighbor" - coordinate_transformation_mode = "asymmetric" - rounding_method = "floor" - elif interp_method == "bilinear": - interp_method = "linear" - if not align_corners and align_mode == 0: - coordinate_transformation_mode = "half_pixel" - else: - if align_corners: - coordinate_transformation_mode = "align_corners" - else: - coordinate_transformation_mode = "asymmetric" - elif interp_method == "bicubic": - interp_method = "cubic" - if align_corners: - coordinate_transformation_mode = "align_corners" - else: - coordinate_transformation_mode = "half_pixel" +def convert_bmm(g, op, block): + """Operator converter for bmm.""" + + x = g.get_node(op.input('X')[0]) + y = g.get_node(op.input('Y')[0]) + x_shape = infer_shape(x) + y_shape = infer_shape(y) + if x_shape[0] == 1 and y_shape == 1: + x = _op.reshape(x, x_shape[1:]) + y = _op.reshape(y, y_shape[1:]) + y = _op.transpose(y, [1, 0]) + out = _op.nn.dense(x, y) + out = _op.expand_dims(out, axis=0) + g.add_node(op.output('Out')[0], out) else: - msg = "interp_method {} is not supported for PaddlePaddle's interpolate" - raise tvm.error.OpAttributeInvalid(msg.format(interp_method)) - return rounding_method, interp_method, coordinate_transformation_mode + y = _op.transpose(y, [0, 2, 1]) + out = _op.nn.batch_matmul(x, y) + g.add_node(op.output('Out')[0], out) def convert_interpolate2d(g, op, x, input_shape): """Operator converter for interpolate 2D(dims == 4).""" + def get_interpolate_mode(op): + """conver 'interp_method' attr of paddle to tvm""" + + interp_method = op.attr("interp_method") + align_corners = op.attr("align_corners") + align_mode = op.attr("align_mode") + + rounding_method = "" + if interp_method == "nearest": + interp_method = "nearest_neighbor" + coordinate_transformation_mode = "asymmetric" + rounding_method = "floor" + elif interp_method == "bilinear": + interp_method = "linear" + if not align_corners and align_mode == 0: + coordinate_transformation_mode = "half_pixel" + else: + if align_corners: + coordinate_transformation_mode = "align_corners" + else: + coordinate_transformation_mode = "asymmetric" + elif interp_method == "bicubic": + interp_method = "cubic" + if align_corners: + coordinate_transformation_mode = "align_corners" + else: + coordinate_transformation_mode = "half_pixel" + else: + msg = "interp_method {} is not supported for PaddlePaddle's interpolate" + raise tvm.error.OpAttributeInvalid(msg.format(interp_method)) + return rounding_method, interp_method, coordinate_transformation_mode + layout = op.attr("data_layout") if layout == "NCHW": in_h, in_w = input_shape[2], input_shape[3] @@ -899,6 +918,14 @@ def convert_squeeze(g, op, block): g.add_node(op.output("Out")[0], x) +def convert_transpose(g, op, block): + """Operator converter for transpose.""" + + perm = op.attr('axis') + out = _op.transpose(g.get_node(op.input('X')[0]), axes=perm) + g.add_node(op.output('Out')[0], out) + + def convert_unsqueeze(g, op, block): """Operator converter for unsqueeze.""" @@ -915,6 +942,7 @@ def convert_unsqueeze(g, op, block): "batch_norm": convert_batch_norm, "bicubic_interp_v2": convert_interpolate, "bilinear_interp_v2": convert_interpolate, + "bmm": convert_bmm, "cast": convert_cast, "concat": convert_concat, "conv2d": convert_conv2d, @@ -954,6 +982,7 @@ def convert_unsqueeze(g, op, block): "softmax": convert_softmax, "squeeze2": convert_squeeze, "tanh": convert_activation, + "transpose2": convert_transpose, "unsqueeze2": convert_unsqueeze, } From 38417d9d09f5003420e60dba2435824929b3bc13 Mon Sep 17 00:00:00 2001 From: heliqi <1101791222@qq.com> Date: Tue, 31 Aug 2021 16:49:21 +0800 Subject: [PATCH 40/51] add vm excutor --- python/tvm/relay/frontend/paddlepaddle.py | 130 +++++++++++------- .../frontend/paddlepaddle/test_forward.py | 56 ++++++-- 2 files changed, 122 insertions(+), 64 deletions(-) diff --git a/python/tvm/relay/frontend/paddlepaddle.py b/python/tvm/relay/frontend/paddlepaddle.py index 447b3a645a09..8da1a3d7c17f 100644 --- a/python/tvm/relay/frontend/paddlepaddle.py +++ b/python/tvm/relay/frontend/paddlepaddle.py @@ -43,10 +43,10 @@ def shape_of(x, dtype="int32"): """Get shape of a tensor""" - ttype = infer_type(x).checked_type - if not _ty.is_dynamic(ttype): - shape = list(ttype.shape) - return _expr.const(shape, dtype) + # ttype = infer_type(x).checked_type + # if not _ty.is_dynamic(ttype): + # shape = list(ttype.shape) + # return _expr.const(shape, dtype) return _op.shape_of(x, dtype) @@ -64,6 +64,26 @@ def _get_pad_size(in_size, dilated_kernel_size, stride_size): return [pad_before, pad_after] +def _infer_value(x, params): + try: + if isinstance(x, _expr.Constant): + return np.atleast_1d(x.data.numpy()) + return params[x.name_hint].numpy() + except (IndexError, KeyError, AttributeError): + try: + return infer_value(x, params).numpy().tolist() + except Exception: + return x + + +def _infer_shape(x, mod=None): + try: + shape = infer_shape(x, mod) + return (shape, True) + except Exception as e: + return (e, False) + + def convert_arg_max(g, op, block): """Operator converter for arg_max.""" @@ -140,49 +160,51 @@ def get_interpolate_mode(op): return rounding_method, interp_method, coordinate_transformation_mode -def convert_interpolate2d(g, op, x, input_shape): +def convert_interpolate2d(g, op, x): """Operator converter for interpolate 2D(dims == 4).""" layout = op.attr("data_layout") - if layout == "NCHW": - in_h, in_w = input_shape[2], input_shape[3] - else: - in_h, in_w = input_shape[1], input_shape[2] - out_h = op.attr("out_h") out_w = op.attr("out_w") + out_size = [out_h, out_w] input_out_size = op.input("OutSize") input_size_tensor = op.input("SizeTensor") input_scale = op.input("Scale") if input_size_tensor: out_size = g.get_node(input_size_tensor[0]) - out_size = infer_value(out_size, g.get_params()).numpy().tolist() - out_h, out_w = out_size + out_size = _infer_value(out_size, g.get_params()) elif input_out_size: out_size = g.get_node(input_out_size[0]) - out_size = infer_value(out_size, g.get_params()).numpy().tolist() - out_h, out_w = out_size - elif input_scale: - scale_data = g.get_node(input_scale[0]) - scale_data = infer_value(scale_data, g.get_params()).numpy().tolist() - if len(scale_data) > 1: - out_h = int(scale_data[0] * in_h) - out_w = int(scale_data[1] * in_w) - else: - out_h = int(scale_data[0] * in_h) - out_w = int(scale_data[0] * in_w) + out_size = _infer_value(out_size, g.get_params()) else: - scale = op.attr("scale") - scale = [float(i) for i in scale] - if len(scale) > 1: - out_h = int(scale[0] * in_h) - out_w = int(scale[1] * in_w) + input_shape = infer_shape(x) + if layout == "NCHW": + in_h, in_w = input_shape[2], input_shape[3] + else: + in_h, in_w = input_shape[1], input_shape[2] + if input_scale: + scale_data = g.get_node(input_scale[0]) + scale_data = infer_value(scale_data, g.get_params()).numpy().tolist() + if len(scale_data) > 1: + out_h = int(scale_data[0] * in_h) + out_w = int(scale_data[1] * in_w) + else: + out_h = int(scale_data[0] * in_h) + out_w = int(scale_data[0] * in_w) + out_size = [out_h, out_w] + else: + scale = op.attr("scale") + scale = [float(i) for i in scale] + if len(scale) > 1: + out_h = int(scale[0] * in_h) + out_w = int(scale[1] * in_w) + out_size = [out_h, out_w] rounding_method, interp_method, coordinate_transformation_mode = get_interpolate_mode(op) out = _op.image.resize2d( x, - [out_h, out_w], + size=out_size, layout=layout, method=interp_method, coordinate_transformation_mode=coordinate_transformation_mode, @@ -196,13 +218,12 @@ def convert_interpolate(g, op, block): """Operator converter for interpolate.""" x = g.get_node(op.input("X")[0]) - input_shape = infer_shape(x) - dims = len(input_shape) - if dims == 4: - convert_interpolate2d(g, op, x, input_shape) + layout = op.attr("data_layout") + if layout in ("NCHW", "NHWC"): + convert_interpolate2d(g, op, x) else: - msg = "input_shape {} is not supported for PaddlePaddle's interpolate" - raise tvm.error.OpAttributeInvalid(msg.format(dims)) + msg = "layout {} is not supported for PaddlePaddle's interpolate" + raise tvm.error.OpAttributeInvalid(msg.format(layout)) def convert_cast(g, op, block): @@ -236,12 +257,20 @@ def convert_conv2d(g, op, block): kernel = g.get_node(op.input("Filter")[0]) input_x = g.get_node(op.input("Input")[0]) out_channels, _, k_h, k_w = infer_shape(kernel) - in_h, in_w = infer_shape(input_x)[2:] if padding_algorithm == "VALID": paddings = [0, 0] elif padding_algorithm == "SAME": - pad_h = _get_pad_size(in_h, (k_h - 1) * dilations[0] + 1, strides[0]) - pad_w = _get_pad_size(in_w, (k_w - 1) * dilations[1] + 1, strides[1]) + if strides[0] == 0 and strides[1] == 0: + pad_h = _get_pad_size(0, (k_h - 1) * dilations[0] + 1, strides[0]) + pad_w = _get_pad_size(0, (k_w - 1) * dilations[1] + 1, strides[1]) + else: + input_shape, is_succeed = _infer_shape(input_x) + assert is_succeed, "{} \n SAME Padding of conv2d only support fixed shape.".format( + input_shape + ) + in_h, in_w = input_shape[2:] + pad_h = _get_pad_size(in_h, (k_h - 1) * dilations[0] + 1, strides[0]) + pad_w = _get_pad_size(in_w, (k_w - 1) * dilations[1] + 1, strides[1]) paddings = [pad_h[0], pad_w[0], pad_h[1], pad_w[1]] elif padding_algorithm == "EXPLICIT": if len(paddings) == 2: @@ -388,12 +417,14 @@ def convert_fill_constant(g, op, block): dtype = str(dtype).strip().split(".")[1] if op.input("ValueTensor"): shape = g.get_node(op.input("ValueTensor")[0]) - shape = infer_value(shape, g.get_params()).numpy() + shape = _infer_value(shape, g.get_params()) if op.input("ShapeTensor"): shape = g.get_node(op.input("ShapeTensor")[0]) - shape = infer_value(shape, g.get_params()).numpy() - value = np.full(shape, value, dtype) - out = _expr.const(value.astype(dtype)).astype(dtype) + shape = _infer_value(shape, g.get_params()) + print("------", dtype) + out = _op.full(value, shape, dtype="float") + # value = np.full(shape, value, dtype) + # out = _expr.const(value.astype(dtype)).astype(dtype) g.add_node(op.output("Out")[0], out) @@ -656,7 +687,6 @@ def convert_pool2d(g, op, block): ksize = [1, 1] input_x = g.get_node(op.input("X")[0]) - in_h, in_w = infer_shape(input_x)[2:] op_map = { "avg": "avg_pool2d", @@ -673,6 +703,7 @@ def convert_pool2d(g, op, block): if padding_algorithm == "VALID": paddings = [0, 0] elif padding_algorithm == "SAME": + in_h, in_w = infer_shape(input_x)[2:] pad_h = _get_pad_size(in_h, ksize[0], strides[0]) pad_w = _get_pad_size(in_w, ksize[1], strides[1]) paddings = [pad_h[0], pad_w[0], pad_h[1], pad_w[1]] @@ -712,9 +743,9 @@ def convert_padding(g, op, block): if mode == "replicate": mode = "edge" - new_pad_len = len(infer_shape(input_x)) * 2 - new_paddings = [0] * new_pad_len - for i in range(0, len(padding), 2): + pad_len = len(padding) + new_paddings = [0] * (pad_len + 4) + for i in range(0, pad_len, 2): index = -1 - i if data_format[:2] != "NC": index = -3 - i @@ -791,7 +822,7 @@ def convert_shape(g, op, block): def convert_slice(g, op, block): """Operator converter for slice.""" - def parameter_process(starts, ends, axes, dshape): + def parameter_process(starts, ends, axes): new_axes = [] new_starts = [] new_ends = [] @@ -804,11 +835,10 @@ def parameter_process(starts, ends, axes, dshape): pop_index += 1 else: new_starts.append(0) - new_ends.append(dshape[i]) + new_ends.append(np.iinfo(np.int32).max) return new_starts, new_ends, new_axes data = g.get_node(op.input("Input")[0]) - dshape = infer_shape(data) starts = op.attr("starts") ends = op.attr("ends") axes = op.attr("axes") @@ -821,7 +851,7 @@ def parameter_process(starts, ends, axes, dshape): axes = [axes] if isinstance(decrease_axis, int): decrease_axis = [decrease_axis] - starts, ends, axes = parameter_process(starts, ends, axes, dshape) + starts, ends, axes = parameter_process(starts, ends, axes) out = _op.strided_slice(data, begin=starts, end=ends) if decrease_axis: out = _op.squeeze(out, axis=decrease_axis) diff --git a/tests/python/frontend/paddlepaddle/test_forward.py b/tests/python/frontend/paddlepaddle/test_forward.py index e4756b040aa1..eb8b654eb346 100644 --- a/tests/python/frontend/paddlepaddle/test_forward.py +++ b/tests/python/frontend/paddlepaddle/test_forward.py @@ -50,7 +50,34 @@ def get_paddle_model(func, input_spec): return baseline_model -def verify_model(func, input_data, rtol=1e-5, atol=1e-5): +def get_tvm_output_with_vm(mod, params, target, device, input_data): + """Generic function to execute and get tvm output with vm executor""" + + ex = relay.create_executor("vm", mod=mod, device=device, target=target) + params.update(input_data) + result = ex.evaluate()(**params) + if isinstance(result, tvm.runtime.NDArray): + return [ + result.numpy(), + ] + return [r.numpy() for r in result] + + +def get_tvm_output(mod, params, target, device, input_data, compiled_names, num): + """Generic function to execute and get tvm output""" + + lib = relay.build(mod, target=target, params=params) + gmod = graph_executor.GraphModule(lib["default"](device)) + for name in compiled_names: + gmod.set_input(name, input_data[name]) + gmod.run() + outputs = [] + for i in range(num): + outputs.append(gmod.get_output(i).numpy()) + return outputs + + +def verify_model(func, input_data, rtol=1e-5, atol=1e-5, input_shape=None): if not (isinstance(input_data, (tuple, list))): input_data = [input_data] @@ -60,11 +87,13 @@ def verify_model(func, input_data, rtol=1e-5, atol=1e-5): compiled_input = {} for idx, data in enumerate(input_data): input_name = "input{}".format(idx) - input_spec.append( - paddle.static.InputSpec(dtype=data.dtype, shape=data.shape, name=input_name) - ) + if input_shape: + shape = input_shape[idx] + else: + shape = data.shape + input_shape_dict[input_name] = shape + input_spec.append(paddle.static.InputSpec(dtype=data.dtype, shape=shape, name=input_name)) input_names.append(input_name) - input_shape_dict[input_name] = data.shape if isinstance(data, np.ndarray): compiled_input[input_name] = data else: @@ -88,15 +117,14 @@ def verify_model(func, input_data, rtol=1e-5, atol=1e-5): with tvm.transform.PassContext(opt_level=3): for target, dev in tvm.testing.enabled_targets(): - lib = relay.build(mod, target=target, params=params) - gmod = graph_executor.GraphModule(lib["default"](dev)) - for name in compiled_names: - gmod.set_input(name, compiled_input[name]) - gmod.run() - - for i, baseline_output in enumerate(baseline_outputs): - compiled_output = gmod.get_output(i).numpy() - + if input_shape: + tvm_output = get_tvm_output_with_vm(mod, params, target, dev, compiled_input) + else: + tvm_output = get_tvm_output( + mod, params, target, dev, compiled_input, compiled_names, len(baseline_outputs) + ) + + for baseline_output, compiled_output in zip(baseline_outputs, tvm_output): assert_shapes_match(baseline_output, compiled_output) tvm.testing.assert_allclose(baseline_output, compiled_output, rtol=rtol, atol=atol) From 30e433b23e8abd301b167cc7c3669eac7e2cf4ba Mon Sep 17 00:00:00 2001 From: heliqi <1101791222@qq.com> Date: Wed, 1 Sep 2021 15:12:01 +0800 Subject: [PATCH 41/51] add vm excutor --- python/tvm/relay/frontend/paddlepaddle.py | 40 +++++-------------- .../frontend/paddlepaddle/test_forward.py | 14 +++++-- 2 files changed, 20 insertions(+), 34 deletions(-) diff --git a/python/tvm/relay/frontend/paddlepaddle.py b/python/tvm/relay/frontend/paddlepaddle.py index 8da1a3d7c17f..b247497f9338 100644 --- a/python/tvm/relay/frontend/paddlepaddle.py +++ b/python/tvm/relay/frontend/paddlepaddle.py @@ -43,10 +43,6 @@ def shape_of(x, dtype="int32"): """Get shape of a tensor""" - # ttype = infer_type(x).checked_type - # if not _ty.is_dynamic(ttype): - # shape = list(ttype.shape) - # return _expr.const(shape, dtype) return _op.shape_of(x, dtype) @@ -65,10 +61,13 @@ def _get_pad_size(in_size, dilated_kernel_size, stride_size): def _infer_value(x, params): + """Try running infer_value, and if successful, return the inferred value. + Otherwise, return input""" + try: if isinstance(x, _expr.Constant): - return np.atleast_1d(x.data.numpy()) - return params[x.name_hint].numpy() + return x.data.numpy().tolist() + return params[x.name_hint].numpy().tolist() except (IndexError, KeyError, AttributeError): try: return infer_value(x, params).numpy().tolist() @@ -76,14 +75,6 @@ def _infer_value(x, params): return x -def _infer_shape(x, mod=None): - try: - shape = infer_shape(x, mod) - return (shape, True) - except Exception as e: - return (e, False) - - def convert_arg_max(g, op, block): """Operator converter for arg_max.""" @@ -264,11 +255,7 @@ def convert_conv2d(g, op, block): pad_h = _get_pad_size(0, (k_h - 1) * dilations[0] + 1, strides[0]) pad_w = _get_pad_size(0, (k_w - 1) * dilations[1] + 1, strides[1]) else: - input_shape, is_succeed = _infer_shape(input_x) - assert is_succeed, "{} \n SAME Padding of conv2d only support fixed shape.".format( - input_shape - ) - in_h, in_w = input_shape[2:] + in_h, in_w = infer_shape(input_x)[2:] pad_h = _get_pad_size(in_h, (k_h - 1) * dilations[0] + 1, strides[0]) pad_w = _get_pad_size(in_w, (k_w - 1) * dilations[1] + 1, strides[1]) paddings = [pad_h[0], pad_w[0], pad_h[1], pad_w[1]] @@ -397,14 +384,8 @@ def convert_fill_any_like(g, op, block): out_dtype = block.var(out_name).dtype out_dtype = str(out_dtype).strip().split(".")[1] x = g.get_node(op.input("X")[0]) - ipt_type = infer_type(x).checked_type value = op.attr("value") - if not _ty.is_dynamic(ipt_type): - shape = infer_shape(x) - const = np.ones(shape) * value - out = _expr.const(const.astype(out_dtype)) - else: - out = _op.transform.full_like(x, value).astype(out_dtype) + out = _op.transform.full_like(x, value).astype(out_dtype) g.add_node(op.output("Out")[0], out) @@ -415,16 +396,15 @@ def convert_fill_constant(g, op, block): shape = block.var(op.output("Out")[0]).shape dtype = block.var(op.output("Out")[0]).dtype dtype = str(dtype).strip().split(".")[1] + value = _expr.const(value).astype(dtype) if op.input("ValueTensor"): shape = g.get_node(op.input("ValueTensor")[0]) shape = _infer_value(shape, g.get_params()) if op.input("ShapeTensor"): shape = g.get_node(op.input("ShapeTensor")[0]) shape = _infer_value(shape, g.get_params()) - print("------", dtype) - out = _op.full(value, shape, dtype="float") - # value = np.full(shape, value, dtype) - # out = _expr.const(value.astype(dtype)).astype(dtype) + + out = _op.full(value, shape=shape, dtype=dtype) g.add_node(op.output("Out")[0], out) diff --git a/tests/python/frontend/paddlepaddle/test_forward.py b/tests/python/frontend/paddlepaddle/test_forward.py index eb8b654eb346..ce86b10a807f 100644 --- a/tests/python/frontend/paddlepaddle/test_forward.py +++ b/tests/python/frontend/paddlepaddle/test_forward.py @@ -89,6 +89,7 @@ def verify_model(func, input_data, rtol=1e-5, atol=1e-5, input_shape=None): input_name = "input{}".format(idx) if input_shape: shape = input_shape[idx] + input_shape_dict[input_name] = [relay.Any()] * len(shape) else: shape = data.shape input_shape_dict[input_name] = shape @@ -371,10 +372,15 @@ def full1(inputs): def full2(inputs): return paddle.full(paddle.shape(inputs), 1.0, dtype=inputs.dtype) + @paddle.jit.to_static + def shape1(inputs): + return paddle.shape(inputs) + input_shape = [1, 3, 10, 10] input_data = paddle.rand(input_shape, dtype="float32") - verify_model(full1, input_data=[input_data]) - verify_model(full2, input_data=[input_data]) + verify_model(shape1, input_data=[input_data], input_shape=[[-1, 3, 10, 10]]) + # verify_model(full1, input_data=[input_data]) + verify_model(full2, input_data=[input_data], input_shape=[[-1, 3, 10, 10]]) @tvm.testing.uses_gpu @@ -641,7 +647,7 @@ def relu(inputs): input_shape = [10, 10] input_data = paddle.rand(input_shape, dtype="float32") - verify_model(relu, input_data=input_data) + verify_model(relu, input_data=input_data, input_shape=[[-1, -1]]) @tvm.testing.uses_gpu @@ -658,7 +664,7 @@ def reshape2(inputs): @paddle.jit.to_static def reshape3(inputs): data_shape = inputs.shape - return inputs.reshape([data_shape[0] * data_shape[1], data_shape[2]]) + return inputs.reshape([data_shape[1], data_shape[2], data_shape[0]]) @paddle.jit.to_static def reshape4(inputs, x): From 771e3c90f3aa463a17d1037c205dc2c6c872a970 Mon Sep 17 00:00:00 2001 From: heliqi <1101791222@qq.com> Date: Wed, 1 Sep 2021 17:06:42 +0800 Subject: [PATCH 42/51] delete input_shape params on test case --- python/tvm/relay/frontend/paddlepaddle.py | 2 +- tests/python/frontend/paddlepaddle/test_forward.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/python/tvm/relay/frontend/paddlepaddle.py b/python/tvm/relay/frontend/paddlepaddle.py index 7c035f1dfdba..60c8e4937742 100644 --- a/python/tvm/relay/frontend/paddlepaddle.py +++ b/python/tvm/relay/frontend/paddlepaddle.py @@ -448,7 +448,7 @@ def convert_fill_any_like(g, op, block): out_dtype = block.var(out_name).dtype out_dtype = str(out_dtype).strip().split(".")[1] x = g.get_node(op.input("X")[0]) - value = op.attr("value") + value = _expr.const(op.attr("value")) out = _op.transform.full_like(x, value).astype(out_dtype) g.add_node(op.output("Out")[0], out) diff --git a/tests/python/frontend/paddlepaddle/test_forward.py b/tests/python/frontend/paddlepaddle/test_forward.py index 38be3f78ba9d..51534f3f5f2f 100644 --- a/tests/python/frontend/paddlepaddle/test_forward.py +++ b/tests/python/frontend/paddlepaddle/test_forward.py @@ -422,9 +422,9 @@ def shape1(inputs): input_shape = [1, 3, 10, 10] input_data = paddle.rand(input_shape, dtype="float32") - verify_model(shape1, input_data=[input_data], input_shape=[[-1, 3, 10, 10]]) + verify_model(shape1, input_data=[input_data]) # verify_model(full1, input_data=[input_data]) - verify_model(full2, input_data=[input_data], input_shape=[[-1, 3, 10, 10]]) + verify_model(full2, input_data=[input_data]) @tvm.testing.uses_gpu @@ -691,7 +691,7 @@ def relu(inputs): input_shape = [10, 10] input_data = paddle.rand(input_shape, dtype="float32") - verify_model(relu, input_data=input_data, input_shape=[[-1, -1]]) + verify_model(relu, input_data=input_data) @tvm.testing.uses_gpu From 7fa1e1740fe5571d92504ad69f6ccece1753d41b Mon Sep 17 00:00:00 2001 From: heliqi <1101791222@qq.com> Date: Thu, 2 Sep 2021 14:37:49 +0800 Subject: [PATCH 43/51] add unary_op test case --- python/tvm/relay/frontend/paddlepaddle.py | 48 ++++++------ .../frontend/paddlepaddle/test_forward.py | 73 +++++++++---------- 2 files changed, 57 insertions(+), 64 deletions(-) diff --git a/python/tvm/relay/frontend/paddlepaddle.py b/python/tvm/relay/frontend/paddlepaddle.py index 60c8e4937742..c684a67b57a8 100644 --- a/python/tvm/relay/frontend/paddlepaddle.py +++ b/python/tvm/relay/frontend/paddlepaddle.py @@ -31,6 +31,7 @@ from .. import op as _op from .common import ( fold_constant, + get_relay_op, infer_shape, infer_type, infer_value, @@ -75,19 +76,14 @@ def _infer_value(x, params): return x -def convert_activation(g, op, block): +def convert_unary_op(g, op, block): """Operator converter for all the activation.""" - op_map = { - "exp": _op.exp, - "relu": _op.nn.relu, - "tanh": _op.tanh, - "sqrt": _op.sqrt, - "erf": _op.erf, - "abs": _op.abs, - "sigmoid": _op.sigmoid, - } - act_func = op_map[op.type] + op_map = {} + if op.type in op_map: + act_func = op_map[op.type] + else: + act_func = get_relay_op(op.type) out = act_func(g.get_node(op.input("X")[0])) g.add_node(op.output("Out")[0], out) @@ -138,8 +134,8 @@ def convert_batch_norm(g, op, block): def convert_bmm(g, op, block): """Operator converter for bmm.""" - x = g.get_node(op.input('X')[0]) - y = g.get_node(op.input('Y')[0]) + x = g.get_node(op.input("X")[0]) + y = g.get_node(op.input("Y")[0]) x_shape = infer_shape(x) y_shape = infer_shape(y) if x_shape[0] == 1 and y_shape == 1: @@ -148,11 +144,11 @@ def convert_bmm(g, op, block): y = _op.transpose(y, [1, 0]) out = _op.nn.dense(x, y) out = _op.expand_dims(out, axis=0) - g.add_node(op.output('Out')[0], out) + g.add_node(op.output("Out")[0], out) else: y = _op.transpose(y, [0, 2, 1]) out = _op.nn.batch_matmul(x, y) - g.add_node(op.output('Out')[0], out) + g.add_node(op.output("Out")[0], out) def convert_interpolate2d(g, op, x): @@ -160,11 +156,11 @@ def convert_interpolate2d(g, op, x): def get_interpolate_mode(op): """conver 'interp_method' attr of paddle to tvm""" - + interp_method = op.attr("interp_method") align_corners = op.attr("align_corners") align_mode = op.attr("align_mode") - + rounding_method = "" if interp_method == "nearest": interp_method = "nearest_neighbor" @@ -325,8 +321,7 @@ def convert_conv2d_transpose(g, op, block): paddings = op.attr("paddings") padding_algorithm = op.attr("padding_algorithm") strides = op.attr("strides") - output_padding = op.attr("output_padding") if op.attr( - "output_padding") else [0, 0] + output_padding = op.attr("output_padding") if op.attr("output_padding") else [0, 0] kernel = g.get_node(op.input("Filter")[0]) input_x = g.get_node(op.input("Input")[0]) @@ -930,9 +925,9 @@ def convert_squeeze(g, op, block): def convert_transpose(g, op, block): """Operator converter for transpose.""" - perm = op.attr('axis') - out = _op.transpose(g.get_node(op.input('X')[0]), axes=perm) - g.add_node(op.output('Out')[0], out) + perm = op.attr("axis") + out = _op.transpose(g.get_node(op.input("X")[0]), axes=perm) + g.add_node(op.output("Out")[0], out) def convert_unsqueeze(g, op, block): @@ -946,6 +941,7 @@ def convert_unsqueeze(g, op, block): _convert_map = { + "abs": convert_unary_op, "arg_max": convert_arg_max, "assign": convert_assign, "batch_norm": convert_batch_norm, @@ -964,7 +960,7 @@ def convert_unsqueeze(g, op, block): "elementwise_mul": convert_elementwise_op, "elementwise_sub": convert_elementwise_op, "equal": convert_equal, - "exp": convert_activation, + "exp": convert_unary_op, "feed": convert_feed, "fill_any_like": convert_fill_any_like, "fill_constant": convert_fill_constant, @@ -982,15 +978,15 @@ def convert_unsqueeze(g, op, block): "pad1d": convert_padding, "pad2d": convert_padding, "pad3d": convert_padding, - "relu": convert_activation, + "relu": convert_unary_op, "reshape2": convert_reshape, "scale": convert_scale, "shape": convert_shape, - "sigmoid": convert_activation, + "sigmoid": convert_unary_op, "slice": convert_slice, "softmax": convert_softmax, "squeeze2": convert_squeeze, - "tanh": convert_activation, + "tanh": convert_unary_op, "transpose2": convert_transpose, "unsqueeze2": convert_unsqueeze, } diff --git a/tests/python/frontend/paddlepaddle/test_forward.py b/tests/python/frontend/paddlepaddle/test_forward.py index 51534f3f5f2f..a11f947449ad 100644 --- a/tests/python/frontend/paddlepaddle/test_forward.py +++ b/tests/python/frontend/paddlepaddle/test_forward.py @@ -130,6 +130,32 @@ def verify_model(func, input_data, rtol=1e-5, atol=1e-5, input_shape=None): tvm.testing.assert_allclose(baseline_output, compiled_output, rtol=rtol, atol=atol) +@tvm.testing.uses_gpu +def test_forward_unary_op(): + class UnaryOp(nn.Layer): + def __init__(self, op_name): + super(UnaryOp, self).__init__() + for candidate in (paddle, paddle.nn.functional): + self.func = getattr(candidate, op_name, None) + if not self.func: + break + + @paddle.jit.to_static + def forward(self, inputs): + return self.func(inputs) + + input_data = paddle.rand([1, 2, 5, 5], dtype="float32") + op_list = [ + "abs", + "exp", + "relu", + "sigmoid", + "tanh", + ] + for op_name in op_list: + verify_model(UnaryOp(op_name), input_data) + + @tvm.testing.uses_gpu def test_forward_add_subtract(): input_shape = [10] @@ -368,7 +394,13 @@ class Conv2DTranspose2(nn.Layer): def __init__(self): super(Conv2DTranspose2, self).__init__() self.conv_transpose = nn.Conv2DTranspose( - 3, 5, 3, stride=2, padding=[[0,0],[0,0],[1,2],[3,4]], output_padding=1, bias_attr=True + 3, + 5, + 3, + stride=2, + padding=[[0, 0], [0, 0], [1, 2], [3, 4]], + output_padding=1, + bias_attr=True, ) @paddle.jit.to_static @@ -379,7 +411,7 @@ class Conv2DTranspose3(nn.Layer): def __init__(self): super(Conv2DTranspose3, self).__init__() self.conv_transpose = nn.Conv2DTranspose( - 3, 5, 3, stride=3, padding='VALID', output_padding=2, bias_attr=True + 3, 5, 3, stride=3, padding="VALID", output_padding=2, bias_attr=True ) @paddle.jit.to_static @@ -683,17 +715,6 @@ def pad4(inputs): verify_model(pad4, input_data=input_data) -@tvm.testing.uses_gpu -def test_forward_relu(): - @paddle.jit.to_static - def relu(inputs): - return nn.functional.relu(inputs) - - input_shape = [10, 10] - input_data = paddle.rand(input_shape, dtype="float32") - verify_model(relu, input_data=input_data) - - @tvm.testing.uses_gpu def test_forward_reshape(): @paddle.jit.to_static @@ -800,28 +821,6 @@ def squeeze3(inputs): verify_model(squeeze3, input_data=input_data) -@tvm.testing.uses_gpu -def test_forward_tanh(): - @paddle.jit.to_static - def tanh(inputs): - return paddle.tanh(inputs) - - input_shape = [1, 3, 10, 10] - input_data = paddle.rand(input_shape, dtype="float32") - verify_model(tanh, input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_sigmoid(): - @paddle.jit.to_static - def sigmoid(inputs): - return nn.functional.sigmoid(inputs) - - input_shape = [10, 10] - input_data = paddle.rand(input_shape, dtype="float32") - verify_model(sigmoid, input_data=input_data) - - if __name__ == "__main__": test_forward_add_subtract() test_forward_argmax() @@ -845,11 +844,9 @@ def sigmoid(inputs): test_forward_matmul() test_forward_pool2d() test_forward_pad() - test_forward_relu() test_forward_reshape() test_forward_scale() test_forward_slice() test_forward_squeeze2() - test_forward_tanh() test_forward_conv_transpose() - test_forward_sigmoid() + test_forward_unary_op() From d45eac0f4406885fbee33a99fe4db8419fbf887a Mon Sep 17 00:00:00 2001 From: heliqi <1101791222@qq.com> Date: Thu, 2 Sep 2021 15:01:02 +0800 Subject: [PATCH 44/51] fix judge bug --- tests/python/frontend/paddlepaddle/test_forward.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/python/frontend/paddlepaddle/test_forward.py b/tests/python/frontend/paddlepaddle/test_forward.py index a11f947449ad..2e9cc113fe85 100644 --- a/tests/python/frontend/paddlepaddle/test_forward.py +++ b/tests/python/frontend/paddlepaddle/test_forward.py @@ -137,7 +137,7 @@ def __init__(self, op_name): super(UnaryOp, self).__init__() for candidate in (paddle, paddle.nn.functional): self.func = getattr(candidate, op_name, None) - if not self.func: + if self.func: break @paddle.jit.to_static From 6f3cdc11449dac46aa64c70c9ca929c7213ad014 Mon Sep 17 00:00:00 2001 From: heliqi <1101791222@qq.com> Date: Thu, 2 Sep 2021 15:28:22 +0800 Subject: [PATCH 45/51] add abs isinf sin tan op --- python/tvm/relay/frontend/paddlepaddle.py | 5 +++++ tests/python/frontend/paddlepaddle/test_forward.py | 7 +++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/python/tvm/relay/frontend/paddlepaddle.py b/python/tvm/relay/frontend/paddlepaddle.py index c684a67b57a8..72a46b113f06 100644 --- a/python/tvm/relay/frontend/paddlepaddle.py +++ b/python/tvm/relay/frontend/paddlepaddle.py @@ -952,6 +952,7 @@ def convert_unsqueeze(g, op, block): "concat": convert_concat, "conv2d": convert_conv2d, "conv2d_transpose": convert_conv2d_transpose, + "cosh": convert_unary_op, "cumsum": convert_cumsum, "depthwise_conv2d": convert_conv2d, "dropout": convert_dropout, @@ -964,9 +965,11 @@ def convert_unsqueeze(g, op, block): "feed": convert_feed, "fill_any_like": convert_fill_any_like, "fill_constant": convert_fill_constant, + "floor": convert_unary_op, "gelu": convert_gelu, "hard_sigmoid": convert_hard_sigmoid, "hard_swish": convert_hard_swish, + "isinf": convert_unary_op, "layer_norm": convert_layer_norm, "leaky_relu": convert_leaky_relu, "lookup_table_v2": convert_lookup_table, @@ -983,10 +986,12 @@ def convert_unsqueeze(g, op, block): "scale": convert_scale, "shape": convert_shape, "sigmoid": convert_unary_op, + "sin": convert_unary_op, "slice": convert_slice, "softmax": convert_softmax, "squeeze2": convert_squeeze, "tanh": convert_unary_op, + "tan": convert_unary_op, "transpose2": convert_transpose, "unsqueeze2": convert_unsqueeze, } diff --git a/tests/python/frontend/paddlepaddle/test_forward.py b/tests/python/frontend/paddlepaddle/test_forward.py index 2e9cc113fe85..7c5140c50788 100644 --- a/tests/python/frontend/paddlepaddle/test_forward.py +++ b/tests/python/frontend/paddlepaddle/test_forward.py @@ -147,10 +147,13 @@ def forward(self, inputs): input_data = paddle.rand([1, 2, 5, 5], dtype="float32") op_list = [ "abs", - "exp", + "cosh" "exp", + "floor", + "isinf", "relu", "sigmoid", - "tanh", + "sin" "tanh", + "tan", ] for op_name in op_list: verify_model(UnaryOp(op_name), input_data) From 0ac6d2f91c12ca9b1d05941ccfddf2705c4edc91 Mon Sep 17 00:00:00 2001 From: heliqi <1101791222@qq.com> Date: Thu, 2 Sep 2021 16:25:38 +0800 Subject: [PATCH 46/51] add log log10 log1p op --- python/tvm/relay/frontend/paddlepaddle.py | 21 +++++++++++++----- .../frontend/paddlepaddle/test_forward.py | 22 ++++++++++++++++--- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/python/tvm/relay/frontend/paddlepaddle.py b/python/tvm/relay/frontend/paddlepaddle.py index 72a46b113f06..42bba6084226 100644 --- a/python/tvm/relay/frontend/paddlepaddle.py +++ b/python/tvm/relay/frontend/paddlepaddle.py @@ -79,12 +79,8 @@ def _infer_value(x, params): def convert_unary_op(g, op, block): """Operator converter for all the activation.""" - op_map = {} - if op.type in op_map: - act_func = op_map[op.type] - else: - act_func = get_relay_op(op.type) - out = act_func(g.get_node(op.input("X")[0])) + unary_func = get_relay_op(op.type) + out = unary_func(g.get_node(op.input("X")[0])) g.add_node(op.output("Out")[0], out) @@ -557,6 +553,16 @@ def convert_lookup_table(g, op, block): g.add_node(op.output("Out")[0], out) +def convert_log1p(g, op, block): + """Operator converter for log1p.""" + + x = g.get_node(op.input("X")[0]) + dtype = infer_type(x).checked_type.dtype + one = _expr.const(1, dtype=dtype) + out = _op.log(x + one) + g.add_node(op.output("Out")[0], out) + + def convert_matmul(g, op, block): """Operator converter for matmul.""" @@ -973,6 +979,9 @@ def convert_unsqueeze(g, op, block): "layer_norm": convert_layer_norm, "leaky_relu": convert_leaky_relu, "lookup_table_v2": convert_lookup_table, + "log": convert_unary_op, + "log10": convert_unary_op, + "log1p": convert_log1p, "matmul": convert_matmul, "matmul_v2": convert_matmul, "mul": convert_mul, diff --git a/tests/python/frontend/paddlepaddle/test_forward.py b/tests/python/frontend/paddlepaddle/test_forward.py index 7c5140c50788..0e5919bd2ccb 100644 --- a/tests/python/frontend/paddlepaddle/test_forward.py +++ b/tests/python/frontend/paddlepaddle/test_forward.py @@ -147,12 +147,16 @@ def forward(self, inputs): input_data = paddle.rand([1, 2, 5, 5], dtype="float32") op_list = [ "abs", - "cosh" "exp", + "cosh", + "exp", "floor", - "isinf", + "log", + "log10", + "log1p", "relu", "sigmoid", - "sin" "tanh", + "sin", + "tanh", "tan", ] for op_name in op_list: @@ -511,6 +515,17 @@ def hard_swish(inputs): verify_model(hard_swish, input_data=input_data) +@tvm.testing.uses_gpu +def test_forward_isinf(): + @paddle.jit.to_static + def isinf(inputs): + return paddle.cast(paddle.isinf(inputs), "int") + + input_shape = [5, 5] + input_data = paddle.rand(input_shape, dtype="float32") + verify_model(isinf, input_data=input_data) + + @tvm.testing.uses_gpu def test_forward_interpolate(): class TestBilinear(nn.Layer): @@ -840,6 +855,7 @@ def squeeze3(inputs): test_forward_hard_sigmoid() test_forward_hard_swish() test_forward_interpolate() + test_forward_isinf() test_forward_layer_norm() test_forward_leaky_relu() test_forward_look_up() From cccef531f7a9a9388d8dfcab052df76dfdb94e43 Mon Sep 17 00:00:00 2001 From: heliqi <1101791222@qq.com> Date: Thu, 2 Sep 2021 16:44:00 +0800 Subject: [PATCH 47/51] add isinf isinf_v2 op --- python/tvm/relay/frontend/paddlepaddle.py | 9 ++++++++- tests/python/frontend/paddlepaddle/test_forward.py | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/python/tvm/relay/frontend/paddlepaddle.py b/python/tvm/relay/frontend/paddlepaddle.py index 42bba6084226..eb20581a2df4 100644 --- a/python/tvm/relay/frontend/paddlepaddle.py +++ b/python/tvm/relay/frontend/paddlepaddle.py @@ -79,7 +79,13 @@ def _infer_value(x, params): def convert_unary_op(g, op, block): """Operator converter for all the activation.""" - unary_func = get_relay_op(op.type) + op_map = { + "isinf_v2": _op.isinf, + } + if op.type in op_map: + unary_func = op_map[op.type] + else: + unary_func = get_relay_op(op.type) out = unary_func(g.get_node(op.input("X")[0])) g.add_node(op.output("Out")[0], out) @@ -976,6 +982,7 @@ def convert_unsqueeze(g, op, block): "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, "lookup_table_v2": convert_lookup_table, diff --git a/tests/python/frontend/paddlepaddle/test_forward.py b/tests/python/frontend/paddlepaddle/test_forward.py index 0e5919bd2ccb..f2922075fe71 100644 --- a/tests/python/frontend/paddlepaddle/test_forward.py +++ b/tests/python/frontend/paddlepaddle/test_forward.py @@ -519,7 +519,7 @@ def hard_swish(inputs): def test_forward_isinf(): @paddle.jit.to_static def isinf(inputs): - return paddle.cast(paddle.isinf(inputs), "int") + return paddle.cast(paddle.isinf(inputs), "int32") input_shape = [5, 5] input_data = paddle.rand(input_shape, dtype="float32") From 03f4f5d8f9297cb89cf1cf54d5e6f154c9b24c30 Mon Sep 17 00:00:00 2001 From: heliqi <1101791222@qq.com> Date: Fri, 3 Sep 2021 14:58:53 +0800 Subject: [PATCH 48/51] delete infer_shape of bmm --- python/tvm/relay/frontend/paddlepaddle.py | 20 +++++-------------- .../frontend/paddlepaddle/test_forward.py | 2 +- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/python/tvm/relay/frontend/paddlepaddle.py b/python/tvm/relay/frontend/paddlepaddle.py index eb20581a2df4..968059e1a4d8 100644 --- a/python/tvm/relay/frontend/paddlepaddle.py +++ b/python/tvm/relay/frontend/paddlepaddle.py @@ -138,19 +138,9 @@ def convert_bmm(g, op, block): x = g.get_node(op.input("X")[0]) y = g.get_node(op.input("Y")[0]) - x_shape = infer_shape(x) - y_shape = infer_shape(y) - if x_shape[0] == 1 and y_shape == 1: - x = _op.reshape(x, x_shape[1:]) - y = _op.reshape(y, y_shape[1:]) - y = _op.transpose(y, [1, 0]) - out = _op.nn.dense(x, y) - out = _op.expand_dims(out, axis=0) - g.add_node(op.output("Out")[0], out) - else: - y = _op.transpose(y, [0, 2, 1]) - out = _op.nn.batch_matmul(x, y) - g.add_node(op.output("Out")[0], out) + y = _op.transpose(y, [0, 2, 1]) + out = _op.nn.batch_matmul(x, y) + g.add_node(op.output("Out")[0], out) def convert_interpolate2d(g, op, x): @@ -328,10 +318,10 @@ def convert_conv2d_transpose(g, op, block): kernel = g.get_node(op.input("Filter")[0]) input_x = g.get_node(op.input("Input")[0]) _, out_channels, k_h, k_w = infer_shape(kernel) - in_h, in_w = infer_shape(input_x)[2:] if padding_algorithm == "VALID": paddings = [0, 0] elif padding_algorithm == "SAME": + in_h, in_w = infer_shape(input_x)[2:] pad_h = _get_pad_size(in_h, (k_h - 1) * dilations[0] + 1, strides[0]) pad_w = _get_pad_size(in_w, (k_w - 1) * dilations[1] + 1, strides[1]) paddings = [pad_h[0], pad_w[0], pad_h[1], pad_w[1]] @@ -1006,8 +996,8 @@ def convert_unsqueeze(g, op, block): "slice": convert_slice, "softmax": convert_softmax, "squeeze2": convert_squeeze, - "tanh": convert_unary_op, "tan": convert_unary_op, + "tanh": convert_unary_op, "transpose2": convert_transpose, "unsqueeze2": convert_unsqueeze, } diff --git a/tests/python/frontend/paddlepaddle/test_forward.py b/tests/python/frontend/paddlepaddle/test_forward.py index f2922075fe71..cb5c17f758f8 100644 --- a/tests/python/frontend/paddlepaddle/test_forward.py +++ b/tests/python/frontend/paddlepaddle/test_forward.py @@ -156,8 +156,8 @@ def forward(self, inputs): "relu", "sigmoid", "sin", - "tanh", "tan", + "tanh", ] for op_name in op_list: verify_model(UnaryOp(op_name), input_data) From 9d8de1963ee5f6fcf73581d76a310f77b8be7e87 Mon Sep 17 00:00:00 2001 From: wjj19950828 Date: Mon, 6 Sep 2021 12:46:16 +0800 Subject: [PATCH 49/51] Add paddle_frontend ops --- python/tvm/relay/frontend/paddlepaddle.py | 283 ++++++++++++++++++ .../frontend/paddlepaddle/test_forward.py | 150 +++++++++- 2 files changed, 432 insertions(+), 1 deletion(-) diff --git a/python/tvm/relay/frontend/paddlepaddle.py b/python/tvm/relay/frontend/paddlepaddle.py index 968059e1a4d8..769213fbe335 100644 --- a/python/tvm/relay/frontend/paddlepaddle.py +++ b/python/tvm/relay/frontend/paddlepaddle.py @@ -90,6 +90,32 @@ def convert_unary_op(g, op, block): g.add_node(op.output("Out")[0], out) +def convert_addmm(g, op, block): + """Operator converter for addmm.""" + + input = g.get_node(op.input('Input')[0]) + x = g.get_node(op.input('X')[0]) + y = g.get_node(op.input('Y')[0]) + + alpha = op.attr('Alpha') + beta = op.attr('Beta') + dtype = block.var(op.output('Out')[0]).dtype + dtype = str(dtype).strip().split('.')[1] + + if not isinstance(alpha, _expr.Expr) and alpha != 1: + alpha = _expr.const(alpha, dtype) + x *= alpha + + if not isinstance(beta, _expr.Expr) and beta != 1: + beta = _expr.const(beta, dtype) + input *= beta + + transposed_y = _op.transpose(y, axes=[1, 0]) + dense_out = _op.nn.dense(x, transposed_y) + out = dense_out + input + g.add_node(op.output('Out')[0], out) + + def convert_arg_max(g, op, block): """Operator converter for arg_max.""" @@ -106,6 +132,22 @@ def convert_arg_max(g, op, block): g.add_node(op.output("Out")[0], out) +def convert_arg_min(g, op, block): + """Operator converter for arg_min.""" + + axis = op.attr("axis") + keepdims = op.attr("keepdims") + flatten = op.attr("flatten") + + x = g.get_node(op.input("X")[0]) + if axis is None or flatten: + x = _op.reshape(x, [-1]) + out = _op.argmin(x, axis=None, keepdims=True) + else: + out = _op.argmin(x, axis=axis, keepdims=keepdims) + g.add_node(op.output("Out")[0], out) + + def convert_assign(g, op, block): """Operator converter for assign.""" @@ -348,6 +390,23 @@ def convert_conv2d_transpose(g, op, block): g.add_node(op.output("Output")[0], out) +def convert_crop(g, op, block): + """Operator converter for crop.""" + + x = g.get_node(op.input('X')[0]) + offsets = op.attr('offsets') + shape = op.attr('shape') + + crop_len = len(shape) + slice_start = [0] * crop_len + slice_end = shape + for i in range(crop_len): + slice_start[i] += offsets[i] + slice_end[i] += offsets[i] + out = _op.strided_slice(x, slice_start, slice_end) + g.add_node(op.output('Out')[0], out) + + def convert_cumsum(g, op, block): """Operator converter for cumsum.""" @@ -376,6 +435,16 @@ def convert_dropout(g, op, block): g.add_node(op.output("Out")[0], out) +def convert_dot(g, op, block): + """Operator converter for dot.""" + + x = g.get_node(op.input('X')[0]) + y = g.get_node(op.input('Y')[0]) + + out = _op.sum(_op.multiply(x, y), axis=[-1], keepdims=True) + g.add_node(op.output('Out')[0], out) + + def convert_elementwise_op(g, op, block): """Operator converter for all the elementwise operators.""" @@ -410,6 +479,31 @@ def convert_equal(g, op, block): g.add_node(op.output("Out")[0], out) +def convert_expand(g, op, block): + """Operator converter for expand.""" + + x = g.get_node(op.input('X')[0]) + input_shape = list(infer_shape(x)) + + ndims = len(input_shape) + sizes = op.attr('shape') + out = x + + out_dims = len(sizes) + if ndims < out_dims: + num_newaxis = out_dims - ndims + out = _op.expand_dims(out, axis=0, num_newaxis=num_newaxis) + input_shape = [1] * num_newaxis + input_shape + + for i in range(out_dims): + if sizes[i] != -1 and input_shape[i] == 1: + if not isinstance(sizes[i], int): + sizes[i] = int(infer_value(sizes[i], {}).numpy()) + out = _op.repeat(out, sizes[i], axis=i) + + g.add_node(op.output('Out')[0], out) + + def convert_feed(g, op, block): """Converter for model input node.""" @@ -459,6 +553,50 @@ def convert_fill_constant(g, op, block): g.add_node(op.output("Out")[0], out) +def convert_fill_constant_batch_size_like(g, op, block): + """Operator converter for fill_constant_batch_size_like.""" + + x = g.get_node(op.input('Input')[0]) + input_shape = infer_shape(x) + out_shape = op.attr('shape') + input_dim_idx = op.attr('input_dim_idx') + output_dim_idx = op.attr('output_dim_idx') + value = op.attr('value') + dtype = block.var(op.output('Out')[0]).dtype + dtype = str(dtype).strip().split('.')[1] + out_shape[output_dim_idx] = input_shape[input_dim_idx] + value = np.full(out_shape, value, dtype) + out = _expr.const(value.astype(dtype)).astype(dtype) + g.add_node(op.output('Out')[0], out) + + +def convert_flatten(g, op, block): + """Operator converter for flatten.""" + + x = g.get_node(op.input('X')[0]) + input_shape = list(infer_shape(x)) + + start = op.attr('start_axis') + end = op.attr('stop_axis') + ndim = len(input_shape) + if end < 0: + end += ndim + new_shape = [0] * start + + new_shape.append(-1) + squeeze_axes = [] + for i in range(start + 1, end + 1): + new_shape.append(1) + squeeze_axes.append(i) + for _ in range(end + 1, ndim): + new_shape.append(0) + out = _op.reshape(x, new_shape) + if squeeze_axes: + out = _op.squeeze(out, axis=squeeze_axes) + + g.add_node(op.output('Out')[0], out) + + def convert_gelu(g, op, block): """Operator converter for gelu.""" @@ -826,6 +964,137 @@ def convert_reshape(g, op, block): g.add_node(op.output("Out")[0], out) +def convert_rnn(g, op, block): + """Operator converter for rnn.""" + + def generate_lstm(X_steps, H_t, C_t, W, R, WB, RB, f_act, g_act, h_act, backwards=False): + h_list = [] + seq_length = len(X_steps) + for i in range(seq_length): + step = X_steps[i] if not backwards else X_steps[seq_length - (i + 1)] + step = _op.squeeze(step, axis=[0]) + gates = _op.nn.dense(step, W) + _op.nn.dense(H_t, R) + if WB is not None: + gates += WB + if RB is not None: + gates += RB + i, f, c, o = _op.split(gates, 4, axis=-1) + + i = f_act(i) + f = f_act(f) + + c = g_act(c) + C = f * C_t + i * c + + o = f_act(o) + + H = o * h_act(C) + + H_t = H + C_t = C + h_list.append(_op.expand_dims(H, axis=0)) + + if backwards: + h_list = h_list[::-1] + + # Concatenate outputs and add back in direction axis. + concatenated = _op.concatenate(h_list, 0) + output = _op.expand_dims(concatenated, axis=1) + H_t = _op.expand_dims(H_t, axis=0) + C_t = _op.expand_dims(C_t, axis=0) + + return output, H_t, C_t + + def make_param_inputs(g, node, layer, hidden_size, num_layers): + bidirect_len = 4 if node.attr('is_bidirec') else 2 + all_layer_param_len = len(node.input('WeightList')) + weight_list = node.input('WeightList')[:all_layer_param_len // 2] + bias_list = node.input('WeightList')[all_layer_param_len // 2:] + single_layer_param_len = all_layer_param_len // num_layers + + layer_weight_list = weight_list[layer * bidirect_len:layer * + bidirect_len + bidirect_len] + layer_bias_list = bias_list[layer * bidirect_len:layer * bidirect_len + + bidirect_len] + param_list = layer_weight_list + layer_bias_list + param_list_len = len(param_list) + + input_weights = param_list[0:param_list_len // 2:2] + hidden_weights = param_list[1:param_list_len // 2:2] + + input_bias = param_list[param_list_len // 2:param_list_len:2] + hidden_bias = param_list[param_list_len // 2 + 1:param_list_len:2] + + return input_weights, hidden_weights, input_bias, hidden_bias + + def make_init_param_inputs(g, node, layer): + all_init_h, all_init_c = node.input('PreState') + bidirect_len = 2 if node.attr('is_bidirec') else 1 + init_h = _op.strided_slice(g.get_node(all_init_h), [layer * bidirect_len], + [layer * bidirect_len + bidirect_len], axes=[0]) + init_c = _op.strided_slice(g.get_node(all_init_c), [layer * bidirect_len], + [layer * bidirect_len + bidirect_len], axes=[0]) + return init_h, init_c + + dropout_prob = op.attr('dropout_prob') + hidden_size = op.attr('hidden_size') + input_size = op.attr('input_size') + num_layers = op.attr('num_layers') + is_bidirec = op.attr('is_bidirec') + + input_x = g.get_node(op.input('Input')[0]) + + num_directions = 1 + if is_bidirec: + num_directions = 2 + + X_shape = infer_shape(input_x) + time_steps = X_shape[0] + X_steps = _op.split(input_x, indices_or_sections=time_steps, axis=0) + for layer in range(num_layers): + input_weights, hidden_weights, input_bias, hidden_bias = make_param_inputs(g, op, layer, hidden_size, num_layers) + + init_h, init_c = make_init_param_inputs(g, op, layer) + init_hs = _op.split(init_h, num_directions) + init_cs = _op.split(init_c, num_directions) + result_output = [] + result_H = [] + result_C = [] + for i in range(num_directions): + H_t = _op.squeeze(init_hs[i], axis=[0]) + C_t = _op.squeeze(init_cs[i], axis=[0]) + W = g.get_node(input_weights[i]) + R = g.get_node(hidden_weights[i]) + WB = g.get_node(input_bias[i]) + RB = g.get_node(hidden_bias[i]) + output, H, C = generate_lstm( + X_steps=X_steps, + H_t=H_t, + C_t=C_t, + W=W, + R=R, + WB=WB, + RB=RB, + f_act=_op.sigmoid, + g_act=_op.tanh, + h_act=_op.tanh, + backwards=i == 1 + ) + result_output.append(output) + result_H.append(H) + result_C.append(C) + output = _op.concatenate(result_output, axis=1) + H = _op.concatenate(result_H, axis=0) + C = _op.concatenate(result_C, axis=0) + + output = _op.transpose(output, axes=[0, 2, 1, 3]) + output = _op.reshape(output, newshape=(0, 0, -1)) + X_steps = output + X_steps = _op.split(X_steps, indices_or_sections=time_steps, axis=0) + + g.add_node(op.output('Out')[0], output) + + def convert_scale(g, op, block): """Operator converter for scale.""" @@ -944,19 +1213,28 @@ def convert_unsqueeze(g, op, block): _convert_map = { "abs": convert_unary_op, + "acos": convert_unary_op, + "addmm": convert_addmm, "arg_max": convert_arg_max, + "arg_min": convert_arg_min, + "asin": convert_unary_op, "assign": convert_assign, + "atan": convert_unary_op, "batch_norm": convert_batch_norm, "bicubic_interp_v2": convert_interpolate, "bilinear_interp_v2": convert_interpolate, "bmm": convert_bmm, "cast": convert_cast, + "ceil": convert_unary_op, "concat": convert_concat, "conv2d": convert_conv2d, "conv2d_transpose": convert_conv2d_transpose, + "cos": convert_unary_op, "cosh": convert_unary_op, + "crop_tensor": convert_crop, "cumsum": convert_cumsum, "depthwise_conv2d": convert_conv2d, + "dot": convert_dot, "dropout": convert_dropout, "elementwise_add": convert_elementwise_op, "elementwise_div": convert_elementwise_op, @@ -964,9 +1242,12 @@ def convert_unsqueeze(g, op, block): "elementwise_sub": convert_elementwise_op, "equal": convert_equal, "exp": convert_unary_op, + "expand_v2": convert_expand, "feed": convert_feed, "fill_any_like": convert_fill_any_like, "fill_constant": convert_fill_constant, + 'fill_constant_batch_size_like': convert_fill_constant_batch_size_like, + "flatten_contiguous_range": convert_flatten, "floor": convert_unary_op, "gelu": convert_gelu, "hard_sigmoid": convert_hard_sigmoid, @@ -975,6 +1256,7 @@ def convert_unsqueeze(g, op, block): "isinf_v2": convert_unary_op, "layer_norm": convert_layer_norm, "leaky_relu": convert_leaky_relu, + "lookup_table": convert_lookup_table, "lookup_table_v2": convert_lookup_table, "log": convert_unary_op, "log10": convert_unary_op, @@ -989,6 +1271,7 @@ def convert_unsqueeze(g, op, block): "pad3d": convert_padding, "relu": convert_unary_op, "reshape2": convert_reshape, + "rnn": convert_rnn, "scale": convert_scale, "shape": convert_shape, "sigmoid": convert_unary_op, diff --git a/tests/python/frontend/paddlepaddle/test_forward.py b/tests/python/frontend/paddlepaddle/test_forward.py index cb5c17f758f8..88c279974d58 100644 --- a/tests/python/frontend/paddlepaddle/test_forward.py +++ b/tests/python/frontend/paddlepaddle/test_forward.py @@ -147,6 +147,11 @@ def forward(self, inputs): input_data = paddle.rand([1, 2, 5, 5], dtype="float32") op_list = [ "abs", + "acos", + "asin", + "atan", + "ceil", + "cos", "cosh", "exp", "floor", @@ -187,6 +192,21 @@ def add_subtract3(inputs1, inputs2): verify_model(add_subtract3, [input_data, input_data2]) +@tvm.testing.uses_gpu +def test_forward_addmm(): + @paddle.jit.to_static + def addmm(input, x, y, alpha=1, beta=1): + return paddle.addmm(input, x, y, alpha, beta) + + input_shape = [10, 10] + x_shape = [10, 3] + y_shape = [3, 10] + input_data = paddle.rand(input_shape, dtype="float32") + x_data = paddle.rand(x_shape, dtype="float32") + y_data = paddle.rand(y_shape, dtype="float32") + verify_model(addmm, input_data=[input_data, x_data, y_data]) + + @tvm.testing.uses_gpu def test_forward_argmax(): input_shape = [1, 3, 10, 10] @@ -218,6 +238,37 @@ def forward(self, inputs): verify_model(ArgMax3(), input_data=input_data) +@tvm.testing.uses_gpu +def test_forward_argmin(): + input_shape = [1, 3, 10, 10] + + class ArgMin(nn.Layer): + @paddle.jit.to_static + def forward(self, inputs): + return paddle.argmin(inputs) + + class ArgMin1(nn.Layer): + @paddle.jit.to_static + def forward(self, inputs): + return inputs.argmin(axis=1) + + class ArgMin2(nn.Layer): + @paddle.jit.to_static + def forward(self, inputs): + return inputs.argmin(axis=1, keepdim=False) + + class ArgMin3(nn.Layer): + @paddle.jit.to_static + def forward(self, inputs): + return inputs.argmin(axis=2, keepdim=True) + + input_data = paddle.rand(input_shape, dtype="float32") + verify_model(ArgMin(), input_data=input_data) + verify_model(ArgMin1(), input_data=input_data) + verify_model(ArgMin2(), input_data=input_data) + verify_model(ArgMin3(), input_data=input_data) + + @tvm.testing.uses_gpu def test_forward_assign(): @paddle.jit.to_static @@ -323,6 +374,37 @@ def concat_unsqueeze2(inputs): verify_model(concat_unsqueeze2, input_data=input_data) +@tvm.testing.uses_gpu +def test_forward_crop(): + input_shape = [10, 10] + + class Crop(nn.Layer): + @paddle.jit.to_static + def forward(self, inputs): + return paddle.crop(inputs, shape=[2, 2]) + + class Crop1(nn.Layer): + @paddle.jit.to_static + def forward(self, inputs): + return paddle.crop(inputs, shape=[3, 3], offsets=[0, 1]) + + class Crop2(nn.Layer): + @paddle.jit.to_static + def forward(self, inputs): + return paddle.crop(inputs, shape=[3, 3], offsets=[1, 0]) + + class Crop3(nn.Layer): + @paddle.jit.to_static + def forward(self, inputs): + return paddle.crop(inputs, shape=[3, 3], offsets=[1, 1]) + + input_data = paddle.rand(input_shape, dtype="float32") + verify_model(Crop(), input_data=input_data) + verify_model(Crop1(), input_data=input_data) + verify_model(Crop2(), input_data=input_data) + verify_model(Crop3(), input_data=input_data) + + @tvm.testing.uses_gpu def test_forward_cumsum(): @paddle.jit.to_static @@ -433,6 +515,19 @@ def forward(self, inputs): verify_model(Conv2DTranspose3(), input_data=conv2d_transpose_input_data) +@tvm.testing.uses_gpu +def test_forward_dot(): + @paddle.jit.to_static + def dot(x, y): + return paddle.dot(x, y) + + x_shape = [10, 3] + y_shape = [10, 3] + x_data = paddle.rand(x_shape, dtype="float32") + y_data = paddle.rand(y_shape, dtype="float32") + verify_model(dot, input_data=[x_data, y_data]) + + @tvm.testing.uses_gpu def test_forward_dropout(): @paddle.jit.to_static @@ -445,6 +540,32 @@ def dropout(inputs): verify_model(dropout, input_data=input_data) +@tvm.testing.uses_gpu +def test_forward_expand(): + @paddle.jit.to_static + def expand(inputs): + return paddle.expand(inputs, shape=[2, 3]) + + x_shape = [3] + x_data = paddle.rand(x_shape, dtype="float32") + verify_model(expand, input_data=[x_data]) + + +@tvm.testing.uses_gpu +def test_forward_flatten(): + @paddle.jit.to_static + def flatten1(inputs): + return paddle.flatten(inputs, start_axis=1, stop_axis=2) + + def flatten2(inputs): + return paddle.flatten(inputs, start_axis=0, stop_axis=-1) + + x_shape = [3, 100, 100, 4] + x_data = paddle.rand(x_shape, dtype="float32") + verify_model(flatten1, input_data=[x_data]) + verify_model(flatten2, input_data=[x_data]) + + @tvm.testing.uses_gpu def test_forward_shape_full(): @paddle.jit.to_static @@ -623,6 +744,26 @@ def forward(self, inputs): verify_model(LookUp(), input_data=input_data) +@tvm.testing.uses_gpu +def test_forward_lstm(): + lstm_input_shape = [25, 1, 288] + + class LSTM1(nn.Layer): + def __init__(self): + super(LSTM1, self).__init__() + self.lstm = nn.LSTM(288, 48, 2, direction="bidirect", time_major=True) + + @paddle.jit.to_static + def forward(self, inputs, prev_h, prev_c): + y, (h, c) = self.lstm(inputs, (prev_h, prev_c)) + return y + + lstm_input_data = paddle.rand(lstm_input_shape, dtype="float32") + prev_h = paddle.rand([4, 1, 48], dtype="float32") + prev_c = paddle.rand([4, 1, 48], dtype="float32") + verify_model(LSTM1(), input_data=[lstm_input_data, prev_h, prev_c]) + + @tvm.testing.uses_gpu def test_forward_multiply(): @paddle.jit.to_static @@ -841,14 +982,20 @@ def squeeze3(inputs): if __name__ == "__main__": test_forward_add_subtract() + test_forward_addmm() test_forward_argmax() + test_forward_argmin() test_forward_assign() test_forward_batch_norm() test_forward_cast() test_forward_concat_unsqueeze() - test_forward_cumsum() test_forward_conv() + test_forward_crop() + test_forward_cumsum() + test_forward_dot() test_forward_dropout() + test_forward_expand() + test_forward_flatten() test_forward_shape_full() test_forward_ones_like() test_forward_gelu() @@ -859,6 +1006,7 @@ def squeeze3(inputs): test_forward_layer_norm() test_forward_leaky_relu() test_forward_look_up() + test_forward_lstm() test_forward_multiply() test_forward_matmul() test_forward_pool2d() From 406e16cedd6a59d2395bab13cc616587a0cf0013 Mon Sep 17 00:00:00 2001 From: wjj19950828 Date: Mon, 6 Sep 2021 13:52:22 +0800 Subject: [PATCH 50/51] fixed for pylint --- python/tvm/relay/frontend/paddlepaddle.py | 81 ++++++++++++++--------- 1 file changed, 49 insertions(+), 32 deletions(-) diff --git a/python/tvm/relay/frontend/paddlepaddle.py b/python/tvm/relay/frontend/paddlepaddle.py index 769213fbe335..eac11738a7f9 100644 --- a/python/tvm/relay/frontend/paddlepaddle.py +++ b/python/tvm/relay/frontend/paddlepaddle.py @@ -93,7 +93,7 @@ def convert_unary_op(g, op, block): def convert_addmm(g, op, block): """Operator converter for addmm.""" - input = g.get_node(op.input('Input')[0]) + input_x = g.get_node(op.input('Input')[0]) x = g.get_node(op.input('X')[0]) y = g.get_node(op.input('Y')[0]) @@ -108,11 +108,11 @@ def convert_addmm(g, op, block): if not isinstance(beta, _expr.Expr) and beta != 1: beta = _expr.const(beta, dtype) - input *= beta + input_x *= beta transposed_y = _op.transpose(y, axes=[1, 0]) dense_out = _op.nn.dense(x, transposed_y) - out = dense_out + input + out = dense_out + input_x g.add_node(op.output('Out')[0], out) @@ -242,7 +242,8 @@ def get_interpolate_mode(op): in_h, in_w = input_shape[1], input_shape[2] if input_scale: scale_data = g.get_node(input_scale[0]) - scale_data = infer_value(scale_data, g.get_params()).numpy().tolist() + scale_data = infer_value( + scale_data, g.get_params()).numpy().tolist() if len(scale_data) > 1: out_h = int(scale_data[0] * in_h) out_w = int(scale_data[1] * in_w) @@ -258,7 +259,8 @@ def get_interpolate_mode(op): out_w = int(scale[1] * in_w) out_size = [out_h, out_w] - rounding_method, interp_method, coordinate_transformation_mode = get_interpolate_mode(op) + rounding_method, interp_method, coordinate_transformation_mode = get_interpolate_mode( + op) out = _op.image.resize2d( x, size=out_size, @@ -322,8 +324,10 @@ def convert_conv2d(g, op, block): pad_w = _get_pad_size(0, (k_w - 1) * dilations[1] + 1, strides[1]) else: in_h, in_w = infer_shape(input_x)[2:] - pad_h = _get_pad_size(in_h, (k_h - 1) * dilations[0] + 1, strides[0]) - pad_w = _get_pad_size(in_w, (k_w - 1) * dilations[1] + 1, strides[1]) + pad_h = _get_pad_size( + in_h, (k_h - 1) * dilations[0] + 1, strides[0]) + pad_w = _get_pad_size( + in_w, (k_w - 1) * dilations[1] + 1, strides[1]) paddings = [pad_h[0], pad_w[0], pad_h[1], pad_w[1]] elif padding_algorithm == "EXPLICIT": if len(paddings) == 2: @@ -355,7 +359,8 @@ def convert_conv2d_transpose(g, op, block): paddings = op.attr("paddings") padding_algorithm = op.attr("padding_algorithm") strides = op.attr("strides") - output_padding = op.attr("output_padding") if op.attr("output_padding") else [0, 0] + output_padding = op.attr("output_padding") if op.attr( + "output_padding") else [0, 0] kernel = g.get_node(op.input("Filter")[0]) input_x = g.get_node(op.input("Input")[0]) @@ -465,7 +470,8 @@ def convert_elementwise_op(g, op, block): if axis < 0: 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)) + ipt1 = _op.expand_dims( + ipt1, axis=axis, num_newaxis=(len(ipt0_shape) - axis - 1)) out = op_func(ipt0, ipt1) g.add_node(op.output("Out")[0], out) @@ -603,7 +609,8 @@ def convert_gelu(g, op, block): x = g.get_node(op.input("X")[0]) out = x * ( _expr.const(0.5, dtype="float32") - + _op.erf(x * _expr.const(0.5 ** 0.5, dtype="float32")) * _expr.const(0.5, dtype="float32") + + _op.erf(x * _expr.const(0.5 ** 0.5, dtype="float32")) * + _expr.const(0.5, dtype="float32") ) g.add_node(op.output("Out")[0], out) @@ -624,9 +631,12 @@ def convert_hard_swish(g, op, block): offset = op.attr("offset") scale = op.attr("scale") threshold = op.attr("threshold") - assert np.isclose(offset, 3.0), "Only support offset==3.0 for PaddlePaddle's hard_swish" - assert np.isclose(scale, 6.0), "Only support scale==6.0 for PaddlePaddle's hard_swish" - assert np.isclose(threshold, 6.0), "Only support threshold==6.0 for PaddlePaddle's hard_swish" + assert np.isclose( + offset, 3.0), "Only support offset==3.0 for PaddlePaddle's hard_swish" + assert np.isclose( + scale, 6.0), "Only support scale==6.0 for PaddlePaddle's hard_swish" + assert np.isclose( + threshold, 6.0), "Only support threshold==6.0 for PaddlePaddle's hard_swish" x = g.get_node(op.input("X")[0]) out = _op.clip(x, -1 * offset, offset) out = out / _expr.const(threshold) + _expr.const(0.5) @@ -737,7 +747,8 @@ def flatten_to_nd(x, x_shape, nd=3): return x newshape = _op.concatenate( [ - _expr.const([-1], dtype=infer_type(x_shape).checked_type.dtype), + _expr.const( + [-1], dtype=infer_type(x_shape).checked_type.dtype), _op.strided_slice(x_shape, [ndims - nd + 1], [ndims]), ], 0, @@ -782,10 +793,12 @@ def flatten_to_nd(x, x_shape, nd=3): [ out_batch, _op.strided_slice( - a_shape, [infer_shape(a_shape)[0] - 2], [infer_shape(a_shape)[0] - 1] + a_shape, [infer_shape(a_shape)[0] - + 2], [infer_shape(a_shape)[0] - 1] ), _op.strided_slice( - b_shape, [infer_shape(b_shape)[0] - 1], [infer_shape(b_shape)[0]] + b_shape, [infer_shape(b_shape)[0] - + 1], [infer_shape(b_shape)[0]] ), ], 0, @@ -824,7 +837,8 @@ def convert_mul(g, op, block): if x_num_col_dims == 1: x = _op.nn.batch_flatten(x) else: - pre_shape = _op.prod(_op.strided_slice(x_shape, [0], [x_num_col_dims], [1]), keepdims=True) + pre_shape = _op.prod(_op.strided_slice( + x_shape, [0], [x_num_col_dims], [1]), keepdims=True) post_shape = _op.prod( _op.strided_slice(x_shape, [x_num_col_dims], [x_dim], [1]), keepdims=True ) @@ -834,7 +848,8 @@ def convert_mul(g, op, block): if y_num_col_dims == 1: y = _op.nn.batch_flatten(y) else: - pre_shape = _op.prod(_op.strided_slice(y_shape, [0], [y_num_col_dims], [1]), keepdims=True) + pre_shape = _op.prod(_op.strided_slice( + y_shape, [0], [y_num_col_dims], [1]), keepdims=True) post_shape = _op.prod( _op.strided_slice(y_shape, [y_num_col_dims], [y_dim], [1]), keepdims=True ) @@ -900,7 +915,8 @@ def convert_pool2d(g, op, block): input_x, pool_size=ksize, strides=strides, padding=paddings, ceil_mode=ceil_mode ) else: - out = getattr(_op.nn, "adaptive_" + op_map[pooling_type])(input_x, output_size=ksize) + out = getattr(_op.nn, "adaptive_" + + op_map[pooling_type])(input_x, output_size=ksize) g.add_node(op.output("Out")[0], out) @@ -931,7 +947,8 @@ def convert_padding(g, op, block): new_paddings[index] = padding[i + 1] new_paddings[index - 1] = padding[i] - new_paddings = [new_paddings[i : i + 2] for i in range(0, len(new_paddings), 2)] + new_paddings = [new_paddings[i: i + 2] + for i in range(0, len(new_paddings), 2)] out = _op.nn.pad(input_x, new_paddings, pad_value=value, pad_mode=mode) g.add_node(op.output("Out")[0], out) @@ -966,12 +983,13 @@ def convert_reshape(g, op, block): def convert_rnn(g, op, block): """Operator converter for rnn.""" - + def generate_lstm(X_steps, H_t, C_t, W, R, WB, RB, f_act, g_act, h_act, backwards=False): h_list = [] seq_length = len(X_steps) for i in range(seq_length): - step = X_steps[i] if not backwards else X_steps[seq_length - (i + 1)] + step = X_steps[i] if not backwards else X_steps[seq_length - + (i + 1)] step = _op.squeeze(step, axis=[0]) gates = _op.nn.dense(step, W) + _op.nn.dense(H_t, R) if WB is not None: @@ -985,7 +1003,7 @@ def generate_lstm(X_steps, H_t, C_t, W, R, WB, RB, f_act, g_act, h_act, backward c = g_act(c) C = f * C_t + i * c - + o = f_act(o) H = o * h_act(C) @@ -1010,7 +1028,6 @@ def make_param_inputs(g, node, layer, hidden_size, num_layers): all_layer_param_len = len(node.input('WeightList')) weight_list = node.input('WeightList')[:all_layer_param_len // 2] bias_list = node.input('WeightList')[all_layer_param_len // 2:] - single_layer_param_len = all_layer_param_len // num_layers layer_weight_list = weight_list[layer * bidirect_len:layer * bidirect_len + bidirect_len] @@ -1031,14 +1048,12 @@ def make_init_param_inputs(g, node, layer): all_init_h, all_init_c = node.input('PreState') bidirect_len = 2 if node.attr('is_bidirec') else 1 init_h = _op.strided_slice(g.get_node(all_init_h), [layer * bidirect_len], - [layer * bidirect_len + bidirect_len], axes=[0]) + [layer * bidirect_len + bidirect_len], axes=[0]) init_c = _op.strided_slice(g.get_node(all_init_c), [layer * bidirect_len], - [layer * bidirect_len + bidirect_len], axes=[0]) + [layer * bidirect_len + bidirect_len], axes=[0]) return init_h, init_c - dropout_prob = op.attr('dropout_prob') hidden_size = op.attr('hidden_size') - input_size = op.attr('input_size') num_layers = op.attr('num_layers') is_bidirec = op.attr('is_bidirec') @@ -1047,12 +1062,13 @@ def make_init_param_inputs(g, node, layer): num_directions = 1 if is_bidirec: num_directions = 2 - + X_shape = infer_shape(input_x) time_steps = X_shape[0] X_steps = _op.split(input_x, indices_or_sections=time_steps, axis=0) for layer in range(num_layers): - input_weights, hidden_weights, input_bias, hidden_bias = make_param_inputs(g, op, layer, hidden_size, num_layers) + input_weights, hidden_weights, input_bias, hidden_bias = make_param_inputs( + g, op, layer, hidden_size, num_layers) init_h, init_c = make_init_param_inputs(g, op, layer) init_hs = _op.split(init_h, num_directions) @@ -1091,7 +1107,7 @@ def make_init_param_inputs(g, node, layer): output = _op.reshape(output, newshape=(0, 0, -1)) X_steps = output X_steps = _op.split(X_steps, indices_or_sections=time_steps, axis=0) - + g.add_node(op.output('Out')[0], output) @@ -1439,5 +1455,6 @@ def from_paddle(program_or_layer, shape_dict=None, scope=None): # model is loaded by `paddle.static.load_inference_model` mod, params = g.from_program(program_or_layer, shape_dict, scope) else: - raise Exception("Only PaddlePaddle's Program and TranslatedLayer are supported.") + raise Exception( + "Only PaddlePaddle's Program and TranslatedLayer are supported.") return mod, params From baf11fe3072e972727b603b51be158f3f344cdb6 Mon Sep 17 00:00:00 2001 From: jiangjiajun Date: Mon, 6 Sep 2021 07:18:25 +0000 Subject: [PATCH 51/51] add gather, gather_nd, assign_value --- python/tvm/relay/frontend/paddlepaddle.py | 236 ++++++++++-------- .../frontend/paddlepaddle/test_forward.py | 38 +++ 2 files changed, 168 insertions(+), 106 deletions(-) diff --git a/python/tvm/relay/frontend/paddlepaddle.py b/python/tvm/relay/frontend/paddlepaddle.py index eac11738a7f9..3d3264b6c592 100644 --- a/python/tvm/relay/frontend/paddlepaddle.py +++ b/python/tvm/relay/frontend/paddlepaddle.py @@ -41,12 +41,6 @@ __all__ = ["from_paddle"] -def shape_of(x, dtype="int32"): - """Get shape of a tensor""" - - return _op.shape_of(x, dtype) - - def _get_pad_size(in_size, dilated_kernel_size, stride_size): """calculate the paddings size""" @@ -93,14 +87,14 @@ def convert_unary_op(g, op, block): def convert_addmm(g, op, block): """Operator converter for addmm.""" - input_x = g.get_node(op.input('Input')[0]) - x = g.get_node(op.input('X')[0]) - y = g.get_node(op.input('Y')[0]) + input_x = g.get_node(op.input("Input")[0]) + x = g.get_node(op.input("X")[0]) + y = g.get_node(op.input("Y")[0]) - alpha = op.attr('Alpha') - beta = op.attr('Beta') - dtype = block.var(op.output('Out')[0]).dtype - dtype = str(dtype).strip().split('.')[1] + alpha = op.attr("Alpha") + beta = op.attr("Beta") + dtype = block.var(op.output("Out")[0]).dtype + dtype = str(dtype).strip().split(".")[1] if not isinstance(alpha, _expr.Expr) and alpha != 1: alpha = _expr.const(alpha, dtype) @@ -113,7 +107,7 @@ def convert_addmm(g, op, block): transposed_y = _op.transpose(y, axes=[1, 0]) dense_out = _op.nn.dense(x, transposed_y) out = dense_out + input_x - g.add_node(op.output('Out')[0], out) + g.add_node(op.output("Out")[0], out) def convert_arg_max(g, op, block): @@ -155,6 +149,22 @@ def convert_assign(g, op, block): g.add_node(op.output("Out")[0], out) +def convert_assign_value(g, op, block): + """Operator converter for assign_value.""" + + keys = ["fp32_values", "int32_values", "int64_values"] + for key in keys: + value = np.array(op.attr(key)) + if value is not None and value.size >= 1: + break + shape = op.attr("shape") + dtype = block.var(op.output("Out")[0]).dtype + dtype = str(dtype).strip().split(".")[1] + value = value.reshape(shape) + out = _op.const(value) + g.add_node(op.output("Out")[0], out) + + def convert_batch_norm(g, op, block): """Operator converter for batch_norm.""" @@ -242,8 +252,7 @@ def get_interpolate_mode(op): in_h, in_w = input_shape[1], input_shape[2] if input_scale: scale_data = g.get_node(input_scale[0]) - scale_data = infer_value( - scale_data, g.get_params()).numpy().tolist() + scale_data = infer_value(scale_data, g.get_params()).numpy().tolist() if len(scale_data) > 1: out_h = int(scale_data[0] * in_h) out_w = int(scale_data[1] * in_w) @@ -259,8 +268,7 @@ def get_interpolate_mode(op): out_w = int(scale[1] * in_w) out_size = [out_h, out_w] - rounding_method, interp_method, coordinate_transformation_mode = get_interpolate_mode( - op) + rounding_method, interp_method, coordinate_transformation_mode = get_interpolate_mode(op) out = _op.image.resize2d( x, size=out_size, @@ -324,10 +332,8 @@ def convert_conv2d(g, op, block): pad_w = _get_pad_size(0, (k_w - 1) * dilations[1] + 1, strides[1]) else: in_h, in_w = infer_shape(input_x)[2:] - pad_h = _get_pad_size( - in_h, (k_h - 1) * dilations[0] + 1, strides[0]) - pad_w = _get_pad_size( - in_w, (k_w - 1) * dilations[1] + 1, strides[1]) + pad_h = _get_pad_size(in_h, (k_h - 1) * dilations[0] + 1, strides[0]) + pad_w = _get_pad_size(in_w, (k_w - 1) * dilations[1] + 1, strides[1]) paddings = [pad_h[0], pad_w[0], pad_h[1], pad_w[1]] elif padding_algorithm == "EXPLICIT": if len(paddings) == 2: @@ -359,8 +365,7 @@ def convert_conv2d_transpose(g, op, block): paddings = op.attr("paddings") padding_algorithm = op.attr("padding_algorithm") strides = op.attr("strides") - output_padding = op.attr("output_padding") if op.attr( - "output_padding") else [0, 0] + output_padding = op.attr("output_padding") if op.attr("output_padding") else [0, 0] kernel = g.get_node(op.input("Filter")[0]) input_x = g.get_node(op.input("Input")[0]) @@ -398,9 +403,9 @@ def convert_conv2d_transpose(g, op, block): def convert_crop(g, op, block): """Operator converter for crop.""" - x = g.get_node(op.input('X')[0]) - offsets = op.attr('offsets') - shape = op.attr('shape') + x = g.get_node(op.input("X")[0]) + offsets = op.attr("offsets") + shape = op.attr("shape") crop_len = len(shape) slice_start = [0] * crop_len @@ -409,7 +414,7 @@ def convert_crop(g, op, block): slice_start[i] += offsets[i] slice_end[i] += offsets[i] out = _op.strided_slice(x, slice_start, slice_end) - g.add_node(op.output('Out')[0], out) + g.add_node(op.output("Out")[0], out) def convert_cumsum(g, op, block): @@ -443,11 +448,11 @@ def convert_dropout(g, op, block): def convert_dot(g, op, block): """Operator converter for dot.""" - x = g.get_node(op.input('X')[0]) - y = g.get_node(op.input('Y')[0]) + x = g.get_node(op.input("X")[0]) + y = g.get_node(op.input("Y")[0]) out = _op.sum(_op.multiply(x, y), axis=[-1], keepdims=True) - g.add_node(op.output('Out')[0], out) + g.add_node(op.output("Out")[0], out) def convert_elementwise_op(g, op, block): @@ -470,8 +475,7 @@ def convert_elementwise_op(g, op, block): if axis < 0: 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)) + ipt1 = _op.expand_dims(ipt1, axis=axis, num_newaxis=(len(ipt0_shape) - axis - 1)) out = op_func(ipt0, ipt1) g.add_node(op.output("Out")[0], out) @@ -488,11 +492,11 @@ def convert_equal(g, op, block): def convert_expand(g, op, block): """Operator converter for expand.""" - x = g.get_node(op.input('X')[0]) + x = g.get_node(op.input("X")[0]) input_shape = list(infer_shape(x)) ndims = len(input_shape) - sizes = op.attr('shape') + sizes = op.attr("shape") out = x out_dims = len(sizes) @@ -507,7 +511,7 @@ def convert_expand(g, op, block): sizes[i] = int(infer_value(sizes[i], {}).numpy()) out = _op.repeat(out, sizes[i], axis=i) - g.add_node(op.output('Out')[0], out) + g.add_node(op.output("Out")[0], out) def convert_feed(g, op, block): @@ -562,28 +566,28 @@ def convert_fill_constant(g, op, block): def convert_fill_constant_batch_size_like(g, op, block): """Operator converter for fill_constant_batch_size_like.""" - x = g.get_node(op.input('Input')[0]) + x = g.get_node(op.input("Input")[0]) input_shape = infer_shape(x) - out_shape = op.attr('shape') - input_dim_idx = op.attr('input_dim_idx') - output_dim_idx = op.attr('output_dim_idx') - value = op.attr('value') - dtype = block.var(op.output('Out')[0]).dtype - dtype = str(dtype).strip().split('.')[1] + out_shape = op.attr("shape") + input_dim_idx = op.attr("input_dim_idx") + output_dim_idx = op.attr("output_dim_idx") + value = op.attr("value") + dtype = block.var(op.output("Out")[0]).dtype + dtype = str(dtype).strip().split(".")[1] out_shape[output_dim_idx] = input_shape[input_dim_idx] value = np.full(out_shape, value, dtype) out = _expr.const(value.astype(dtype)).astype(dtype) - g.add_node(op.output('Out')[0], out) + g.add_node(op.output("Out")[0], out) def convert_flatten(g, op, block): """Operator converter for flatten.""" - x = g.get_node(op.input('X')[0]) + x = g.get_node(op.input("X")[0]) input_shape = list(infer_shape(x)) - start = op.attr('start_axis') - end = op.attr('stop_axis') + start = op.attr("start_axis") + end = op.attr("stop_axis") ndim = len(input_shape) if end < 0: end += ndim @@ -600,7 +604,30 @@ def convert_flatten(g, op, block): if squeeze_axes: out = _op.squeeze(out, axis=squeeze_axes) - g.add_node(op.output('Out')[0], out) + g.add_node(op.output("Out")[0], out) + + +def convert_gather(g, op, block): + """Operator converter for gather.""" + + x = g.get_node(op.input("X")[0]) + index = g.get_node(op.input("Index")[0]) + axis = op.attr("axis") + out = _op.take(x, index, axis) + g.add_node(op.output("Out")[0], out) + + +def convert_gather_nd(g, op, block): + """Operator converter for gather_nd.""" + + x = g.get_node(op.input("X")[0]) + index = g.get_node(op.input("Index")[0]) + shape = infer_shape(index) + perm = list(range(0, len(shape) - 1)) + perm.insert(0, len(shape) - 1) + index = _op.transpose(index, axes=perm) + out = _op.gather_nd(x, index, 0, shape[-1]) + g.add_node(op.output("Out")[0], out) def convert_gelu(g, op, block): @@ -609,8 +636,7 @@ def convert_gelu(g, op, block): x = g.get_node(op.input("X")[0]) out = x * ( _expr.const(0.5, dtype="float32") - + _op.erf(x * _expr.const(0.5 ** 0.5, dtype="float32")) * - _expr.const(0.5, dtype="float32") + + _op.erf(x * _expr.const(0.5 ** 0.5, dtype="float32")) * _expr.const(0.5, dtype="float32") ) g.add_node(op.output("Out")[0], out) @@ -631,12 +657,9 @@ def convert_hard_swish(g, op, block): offset = op.attr("offset") scale = op.attr("scale") threshold = op.attr("threshold") - assert np.isclose( - offset, 3.0), "Only support offset==3.0 for PaddlePaddle's hard_swish" - assert np.isclose( - scale, 6.0), "Only support scale==6.0 for PaddlePaddle's hard_swish" - assert np.isclose( - threshold, 6.0), "Only support threshold==6.0 for PaddlePaddle's hard_swish" + assert np.isclose(offset, 3.0), "Only support offset==3.0 for PaddlePaddle's hard_swish" + assert np.isclose(scale, 6.0), "Only support scale==6.0 for PaddlePaddle's hard_swish" + assert np.isclose(threshold, 6.0), "Only support threshold==6.0 for PaddlePaddle's hard_swish" x = g.get_node(op.input("X")[0]) out = _op.clip(x, -1 * offset, offset) out = out / _expr.const(threshold) + _expr.const(0.5) @@ -734,9 +757,9 @@ def convert_matmul(g, op, block): # This implemention almost keeps same with ONNX # Need to check input shape as batch matmul must be supported. - a_shape = shape_of(inputs[0]) + a_shape = _op.shape_of(inputs[0]) a_rank = infer_shape(a_shape)[0] - b_shape = shape_of(inputs[1]) + b_shape = _op.shape_of(inputs[1]) b_rank = infer_shape(b_shape)[0] # When performing a batch matmul, we need to properly handle N-dim shapes. if a_rank > 2 or b_rank > 2: @@ -747,8 +770,7 @@ def flatten_to_nd(x, x_shape, nd=3): return x newshape = _op.concatenate( [ - _expr.const( - [-1], dtype=infer_type(x_shape).checked_type.dtype), + _expr.const([-1], dtype=infer_type(x_shape).checked_type.dtype), _op.strided_slice(x_shape, [ndims - nd + 1], [ndims]), ], 0, @@ -793,12 +815,10 @@ def flatten_to_nd(x, x_shape, nd=3): [ out_batch, _op.strided_slice( - a_shape, [infer_shape(a_shape)[0] - - 2], [infer_shape(a_shape)[0] - 1] + a_shape, [infer_shape(a_shape)[0] - 2], [infer_shape(a_shape)[0] - 1] ), _op.strided_slice( - b_shape, [infer_shape(b_shape)[0] - - 1], [infer_shape(b_shape)[0]] + b_shape, [infer_shape(b_shape)[0] - 1], [infer_shape(b_shape)[0]] ), ], 0, @@ -826,8 +846,8 @@ def convert_mul(g, op, block): y = g.get_node(op.input("Y")[0]) x_num_col_dims = op.attr("x_num_col_dims") y_num_col_dims = op.attr("y_num_col_dims") - x_shape = shape_of(x) - y_shape = shape_of(y) + x_shape = _op.shape_of(x) + y_shape = _op.shape_of(y) x_dim = infer_shape(x_shape)[0] y_dim = infer_shape(y_shape)[0] if x_num_col_dims < 0: @@ -837,8 +857,7 @@ def convert_mul(g, op, block): if x_num_col_dims == 1: x = _op.nn.batch_flatten(x) else: - pre_shape = _op.prod(_op.strided_slice( - x_shape, [0], [x_num_col_dims], [1]), keepdims=True) + pre_shape = _op.prod(_op.strided_slice(x_shape, [0], [x_num_col_dims], [1]), keepdims=True) post_shape = _op.prod( _op.strided_slice(x_shape, [x_num_col_dims], [x_dim], [1]), keepdims=True ) @@ -848,8 +867,7 @@ def convert_mul(g, op, block): if y_num_col_dims == 1: y = _op.nn.batch_flatten(y) else: - pre_shape = _op.prod(_op.strided_slice( - y_shape, [0], [y_num_col_dims], [1]), keepdims=True) + pre_shape = _op.prod(_op.strided_slice(y_shape, [0], [y_num_col_dims], [1]), keepdims=True) post_shape = _op.prod( _op.strided_slice(y_shape, [y_num_col_dims], [y_dim], [1]), keepdims=True ) @@ -915,8 +933,7 @@ def convert_pool2d(g, op, block): input_x, pool_size=ksize, strides=strides, padding=paddings, ceil_mode=ceil_mode ) else: - out = getattr(_op.nn, "adaptive_" + - op_map[pooling_type])(input_x, output_size=ksize) + out = getattr(_op.nn, "adaptive_" + op_map[pooling_type])(input_x, output_size=ksize) g.add_node(op.output("Out")[0], out) @@ -947,8 +964,7 @@ def convert_padding(g, op, block): new_paddings[index] = padding[i + 1] new_paddings[index - 1] = padding[i] - new_paddings = [new_paddings[i: i + 2] - for i in range(0, len(new_paddings), 2)] + new_paddings = [new_paddings[i : i + 2] for i in range(0, len(new_paddings), 2)] out = _op.nn.pad(input_x, new_paddings, pad_value=value, pad_mode=mode) g.add_node(op.output("Out")[0], out) @@ -988,8 +1004,7 @@ def generate_lstm(X_steps, H_t, C_t, W, R, WB, RB, f_act, g_act, h_act, backward h_list = [] seq_length = len(X_steps) for i in range(seq_length): - step = X_steps[i] if not backwards else X_steps[seq_length - - (i + 1)] + step = X_steps[i] if not backwards else X_steps[seq_length - (i + 1)] step = _op.squeeze(step, axis=[0]) gates = _op.nn.dense(step, W) + _op.nn.dense(H_t, R) if WB is not None: @@ -1024,40 +1039,46 @@ def generate_lstm(X_steps, H_t, C_t, W, R, WB, RB, f_act, g_act, h_act, backward return output, H_t, C_t def make_param_inputs(g, node, layer, hidden_size, num_layers): - bidirect_len = 4 if node.attr('is_bidirec') else 2 - all_layer_param_len = len(node.input('WeightList')) - weight_list = node.input('WeightList')[:all_layer_param_len // 2] - bias_list = node.input('WeightList')[all_layer_param_len // 2:] - - layer_weight_list = weight_list[layer * bidirect_len:layer * - bidirect_len + bidirect_len] - layer_bias_list = bias_list[layer * bidirect_len:layer * bidirect_len + - bidirect_len] + bidirect_len = 4 if node.attr("is_bidirec") else 2 + all_layer_param_len = len(node.input("WeightList")) + weight_list = node.input("WeightList")[: all_layer_param_len // 2] + bias_list = node.input("WeightList")[all_layer_param_len // 2 :] + + layer_weight_list = weight_list[layer * bidirect_len : layer * bidirect_len + bidirect_len] + layer_bias_list = bias_list[layer * bidirect_len : layer * bidirect_len + bidirect_len] param_list = layer_weight_list + layer_bias_list param_list_len = len(param_list) - input_weights = param_list[0:param_list_len // 2:2] - hidden_weights = param_list[1:param_list_len // 2:2] + input_weights = param_list[0 : param_list_len // 2 : 2] + hidden_weights = param_list[1 : param_list_len // 2 : 2] - input_bias = param_list[param_list_len // 2:param_list_len:2] - hidden_bias = param_list[param_list_len // 2 + 1:param_list_len:2] + input_bias = param_list[param_list_len // 2 : param_list_len : 2] + hidden_bias = param_list[param_list_len // 2 + 1 : param_list_len : 2] return input_weights, hidden_weights, input_bias, hidden_bias def make_init_param_inputs(g, node, layer): - all_init_h, all_init_c = node.input('PreState') - bidirect_len = 2 if node.attr('is_bidirec') else 1 - init_h = _op.strided_slice(g.get_node(all_init_h), [layer * bidirect_len], - [layer * bidirect_len + bidirect_len], axes=[0]) - init_c = _op.strided_slice(g.get_node(all_init_c), [layer * bidirect_len], - [layer * bidirect_len + bidirect_len], axes=[0]) + all_init_h, all_init_c = node.input("PreState") + bidirect_len = 2 if node.attr("is_bidirec") else 1 + init_h = _op.strided_slice( + g.get_node(all_init_h), + [layer * bidirect_len], + [layer * bidirect_len + bidirect_len], + axes=[0], + ) + init_c = _op.strided_slice( + g.get_node(all_init_c), + [layer * bidirect_len], + [layer * bidirect_len + bidirect_len], + axes=[0], + ) return init_h, init_c - hidden_size = op.attr('hidden_size') - num_layers = op.attr('num_layers') - is_bidirec = op.attr('is_bidirec') + hidden_size = op.attr("hidden_size") + num_layers = op.attr("num_layers") + is_bidirec = op.attr("is_bidirec") - input_x = g.get_node(op.input('Input')[0]) + input_x = g.get_node(op.input("Input")[0]) num_directions = 1 if is_bidirec: @@ -1068,7 +1089,8 @@ def make_init_param_inputs(g, node, layer): X_steps = _op.split(input_x, indices_or_sections=time_steps, axis=0) for layer in range(num_layers): input_weights, hidden_weights, input_bias, hidden_bias = make_param_inputs( - g, op, layer, hidden_size, num_layers) + g, op, layer, hidden_size, num_layers + ) init_h, init_c = make_init_param_inputs(g, op, layer) init_hs = _op.split(init_h, num_directions) @@ -1094,7 +1116,7 @@ def make_init_param_inputs(g, node, layer): f_act=_op.sigmoid, g_act=_op.tanh, h_act=_op.tanh, - backwards=i == 1 + backwards=i == 1, ) result_output.append(output) result_H.append(H) @@ -1108,7 +1130,7 @@ def make_init_param_inputs(g, node, layer): X_steps = output X_steps = _op.split(X_steps, indices_or_sections=time_steps, axis=0) - g.add_node(op.output('Out')[0], output) + g.add_node(op.output("Out")[0], output) def convert_scale(g, op, block): @@ -1141,7 +1163,7 @@ def convert_shape(g, op, block): """Operator converter for shape.""" x = g.get_node(op.input("Input")[0]) - out = shape_of(x) + out = _op.shape_of(x) g.add_node(op.output("Out")[0], out) @@ -1235,6 +1257,7 @@ def convert_unsqueeze(g, op, block): "arg_min": convert_arg_min, "asin": convert_unary_op, "assign": convert_assign, + "assign_value": convert_assign_value, "atan": convert_unary_op, "batch_norm": convert_batch_norm, "bicubic_interp_v2": convert_interpolate, @@ -1262,9 +1285,11 @@ def convert_unsqueeze(g, op, block): "feed": convert_feed, "fill_any_like": convert_fill_any_like, "fill_constant": convert_fill_constant, - 'fill_constant_batch_size_like': convert_fill_constant_batch_size_like, + "fill_constant_batch_size_like": convert_fill_constant_batch_size_like, "flatten_contiguous_range": convert_flatten, "floor": convert_unary_op, + "gather": convert_gather, + "gather_nd": convert_gather_nd, "gelu": convert_gelu, "hard_sigmoid": convert_hard_sigmoid, "hard_swish": convert_hard_swish, @@ -1455,6 +1480,5 @@ def from_paddle(program_or_layer, shape_dict=None, scope=None): # model is loaded by `paddle.static.load_inference_model` mod, params = g.from_program(program_or_layer, shape_dict, scope) else: - raise Exception( - "Only PaddlePaddle's Program and TranslatedLayer are supported.") + raise Exception("Only PaddlePaddle's Program and TranslatedLayer are supported.") return mod, params diff --git a/tests/python/frontend/paddlepaddle/test_forward.py b/tests/python/frontend/paddlepaddle/test_forward.py index 88c279974d58..6ba0e10ff3bd 100644 --- a/tests/python/frontend/paddlepaddle/test_forward.py +++ b/tests/python/frontend/paddlepaddle/test_forward.py @@ -603,6 +603,42 @@ def ones_like2(inputs): verify_model(ones_like2, input_data=input_data) +@tvm.testing.uses_gpu +def test_forward_gather_assign_value(): + @paddle.jit.to_static + def gather1(x): + index = paddle.to_tensor(np.array([1, 3, 5, 7, 9]).astype("int64")) + return paddle.gather(x, index, axis=None) + + @paddle.jit.to_static + def gather2(x): + index = paddle.to_tensor(np.array([1, 3, 5, 7, 9]).astype("int64")) + return paddle.gather(x, index, axis=1) + + x_shape = [30, 40] + x_data = paddle.rand(x_shape, dtype="float32") + verify_model(gather1, input_data=[x_data]) + verify_model(gather2, input_data=[x_data]) + + +@tvm.testing.uses_gpu +def test_forward_gather_nd(): + @paddle.jit.to_static + def gather_nd1(x): + index = paddle.to_tensor(np.array([[0, 1]]).astype("int64")) + return paddle.gather_nd(x, index) + + @paddle.jit.to_static + def gather_nd2(x): + index = paddle.to_tensor(np.array([[0, 1], [1, 2]]).astype("int32")) + return paddle.gather_nd(x, index) + + x_shape = [30, 40, 20] + x_data = paddle.rand(x_shape, dtype="float32") + verify_model(gather_nd1, input_data=[x_data]) + verify_model(gather_nd2, input_data=[x_data]) + + @tvm.testing.uses_gpu def test_forward_gelu(): @paddle.jit.to_static @@ -998,6 +1034,8 @@ def squeeze3(inputs): test_forward_flatten() test_forward_shape_full() test_forward_ones_like() + test_forward_gather_assign_value() + test_forward_gather_nd() test_forward_gelu() test_forward_hard_sigmoid() test_forward_hard_swish()