# Copyright (c) 2024 PaddlePaddle Authors. All Rights Reserved # # Licensed 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 numpy as np import tensorrt as trt from paddle.tensorrt.converter_utils import ( add_1D_constant_layer, build_size_tensor, build_start_tensor, cast_tensor, fix_negative_indices, generic_plugin_converter, get_axes_for_reduce_op, get_input_constant_value, get_shape_tensor_element, has_dynamic_shape, resize_to_1d, set_layer_name, trt_cast, trt_concat, trt_expand, trt_floor_div, trt_gather, trt_less, trt_max, trt_min, trt_prod, trt_reshape, trt_shape, trt_sub, trt_sum, ) from paddle.tensorrt.register import converter_registry from ..util import get_trt_version_list @converter_registry.register("pd_op.reshape") def reshape_converter(network, paddle_op, inputs): x = inputs[0] is_constant_shape = False shape = get_input_constant_value(paddle_op, inputs, 1) if shape is not None: reshape_dim = shape is_constant_shape = True elif isinstance(inputs[1], list): # shape tensor is a list value shape_tensor = trt_concat( network, inputs[1], name=[paddle_op.name(), "shape_tensor"] ) else: # shape tensor is a value shape_tensor = inputs[1] if not is_constant_shape: shape_tensor = resize_to_1d( network, shape_tensor, name=[paddle_op.name(), "shape_tensor"] ) layer = network.add_shuffle(x) if is_constant_shape: layer.reshape_dims = reshape_dim else: layer.set_input(1, shape_tensor) set_layer_name(layer, paddle_op) assert len(layer.get_output(0).shape) >= 0, ( 'When convert reshape op to TRT reshape layer, the rank of trt reshape output dims is less than 0, ' 'you should modify trt_config(a TensorRTConfig object) and set trt_config.disable_ops = ["pd_op.reshape"] to forbid this op.' ) return layer.get_output(0) @converter_registry.register("pd_op.gather") def gather_converter(network, paddle_op, inputs): input_tensor = inputs[0] index_tensor = inputs[1] axis_value = get_input_constant_value(paddle_op, inputs, 2)[0] axis_value = int(axis_value) reshape_layer = network.add_shuffle(index_tensor) reshape_layer.reshape_dims = (-1,) set_layer_name(reshape_layer, paddle_op) gather_layer = network.add_gather( input_tensor, reshape_layer.get_output(0), axis_value ) set_layer_name(gather_layer, paddle_op) return gather_layer.get_output(0) @converter_registry.register("pd_op.gather_nd") def gather_nd_converter(network, paddle_op, inputs): input_tensor, indices_tensor = inputs non_zero_layer = network.add_gather_v2( input_tensor, indices_tensor, trt.GatherMode.ND ) non_zero_layer.num_elementwise_dims = 0 set_layer_name(non_zero_layer, paddle_op) return non_zero_layer.get_output(0) @converter_registry.register("pd_op.flatten") def flatten_converter(network, paddle_op, inputs): input_val = inputs[0] input_val_shape = paddle_op.operands()[0].source().shape dims = len(input_val_shape) start_axis = paddle_op.attrs().get("start_axis") stop_axis = paddle_op.attrs().get("stop_axis") flatten_layer = network.add_shuffle(input_val) set_layer_name(flatten_layer, paddle_op) if not has_dynamic_shape(input_val_shape): if start_axis < 0: start_axis += dims + 1 if stop_axis < 0: stop_axis += dims + 1 flatten_dim = 1 final_shape = [] for i, s in enumerate(input_val_shape): if i >= start_axis and i <= stop_axis: flatten_dim *= s elif i == stop_axis + 1: final_shape.append(flatten_dim) final_shape.append(s) else: final_shape.append(s) if stop_axis == len(input_val.shape) - 1: final_shape.append(flatten_dim) flatten_layer.reshape_dims = tuple(final_shape) set_layer_name(flatten_layer, paddle_op) else: input_shape_layer = network.add_shape(input_val) set_layer_name(input_shape_layer, paddle_op) final_shapes = [] # Shapes before start_axis if start_axis > 0: prefix_shape_layer = network.add_slice( input_shape_layer.get_output(0), start=(0,), shape=(start_axis,), stride=(1,), ) set_layer_name(prefix_shape_layer, paddle_op) final_shapes.append(prefix_shape_layer.get_output(0)) flatten_shape_layer = network.add_slice( input_shape_layer.get_output(0), start=(start_axis,), shape=(stop_axis - start_axis + 1,), stride=(1,), ) set_layer_name(flatten_shape_layer, paddle_op) flatten_shape_layer = network.add_reduce( flatten_shape_layer.get_output(0), trt.ReduceOperation.PROD, axes=get_axes_for_reduce_op(0, False), keep_dims=True, ) set_layer_name(flatten_shape_layer, paddle_op) final_shapes.append(flatten_shape_layer.get_output(0)) # Shapes after stop_axis if stop_axis < len(input_val_shape) - 1: suffix_shape_layer = network.add_slice( input_shape_layer.get_output(0), start=(stop_axis + 1,), shape=(len(input_val_shape) - stop_axis - 1,), stride=(1,), ) set_layer_name(suffix_shape_layer, paddle_op) final_shapes.append(suffix_shape_layer.get_output(0)) final_shape_layer = network.add_concatenation(final_shapes) final_shape_layer.axis = 0 set_layer_name(final_shape_layer, paddle_op) flatten_layer.set_input(1, final_shape_layer.get_output(0)) return flatten_layer.get_output(0) # In the converter, pd_op.concat has three inputs, because builtin.combine has two inputs. @converter_registry.register("pd_op.concat") def concat_converter(network, paddle_op, inputs): input_tensors = inputs[0] concat_layer = network.add_concatenation(inputs=input_tensors) axis = get_input_constant_value(paddle_op, inputs, 1)[0] axis = int(axis) if axis < 0: axis = len(input_tensors[0].shape) + axis concat_layer.axis = axis set_layer_name(concat_layer, paddle_op) return concat_layer.get_output(0) @converter_registry.register("pd_op.unsqueeze") @converter_registry.register("pd_op.unsqueeze_") def unsqueeze_converter(network, paddle_op, inputs): x = inputs[0] input_dims = x.shape axes = get_input_constant_value(paddle_op, inputs, 1) assert len(axes) > 0, ( f"axes size should be > 0 in when convert unsqueeze op in TensorRT, but received len(axes) = {len(axes)}." ) should_unsqueeze = [False] * (len(input_dims) + len(axes)) cur_out_rank = len(input_dims) for i in range(len(axes)): cur_out_rank += 1 if axes[i] < 0: axes[i] += cur_out_rank # axes[i] is relative to cur_out_rank # we make [axes[i], cur_out_rank - 2] shift right # and make (axes[i]) to true! for j in range(cur_out_rank - 1, axes[i], -1): should_unsqueeze[j] = should_unsqueeze[j - 1] if axes[i] >= cur_out_rank: should_unsqueeze[cur_out_rank - 1] = True else: should_unsqueeze[axes[i]] = True gather_indices = [] in_rank_i = 0 for i in range(len(should_unsqueeze)): if should_unsqueeze[i]: gather_indices.append(len(input_dims)) continue gather_indices.append(in_rank_i) in_rank_i += 1 shape_tensor = trt_shape( network, x, name=[paddle_op.name(), "shape_tensor"] ) all_one = [1] * len(axes) all_one_tensor = add_1D_constant_layer( network, all_one, name=[paddle_op.name(), "all_one_tensor"] ) concat_inputs = [shape_tensor, all_one_tensor] real_shape_tensor = trt_gather( network, trt_concat( network, concat_inputs, name=[paddle_op.name(), "trt_concat"] ), gather_indices, name=[paddle_op.name(), "real_shape_tensor"], ) layer = network.add_shuffle(x) layer.set_input(1, real_shape_tensor) set_layer_name(layer, paddle_op) return layer.get_output(0) @converter_registry.register("pd_op.squeeze") @converter_registry.register("pd_op.squeeze_") def squeeze_converter(network, paddle_op, inputs): input_val = inputs[0] input_shape = input_val.shape input_shape_size = len(input_shape) # If input is weights, convert to TensorRT tensor if isinstance(input_val, trt.Weights): input_val = network.add_constant(input_shape, input_val) set_layer_name(input_val, paddle_op) input_val = input_val.get_output(0) # Get axis axis = get_input_constant_value(paddle_op, inputs, 1) if len(axis) == 0: for i in range(input_shape_size): if input_shape[i] == -1: raise RuntimeError( "The necessary attributes of the squeeze operator axis is missing" ) elif input_shape[i] == 1: axis.append(i) else: # Verify that each axis to squeeze has size 1 for a in axis: if a < 0: a += input_shape_size if input_shape[a] != 1: raise RuntimeError( f"Cannot squeeze dimension {a} with size {input_shape[a]}. Only dimensions with size 1 can be squeezed." ) axes_size = len(axis) if axes_size == 0: raise RuntimeError( f"axis.size should be >0 in pd_op.squeeze op in TensorRT, but received {axes_size}" ) # Mark which dimensions to squeeze should_squeeze = [False] * input_shape_size for a in axis: should_squeeze[a] = True # Get dimensions to keep gather_indices = [ i for i, squeeze in enumerate(should_squeeze) if not squeeze ] # Add Shuffle layer shape_tensor = trt_shape( network, input_val, name=[paddle_op.name(), 'shape_tensor'] ) real_shape_tensor = trt_gather( network, shape_tensor, gather_indices, name=[paddle_op.name(), 'real_shape_tensor'], ) layer = network.add_shuffle(input_val) layer.set_input(1, real_shape_tensor) set_layer_name(layer, paddle_op) return layer.get_output(0) @converter_registry.register("pd_op.expand") def expand_converter(network, paddle_op, inputs): input = inputs[0] input_dims = input.shape rank = len(input_dims) paddle_shape_tensor = paddle_op.operands()[1].source() shape = get_input_constant_value(paddle_op, inputs, 1) if shape is not None: shape_tensor = add_1D_constant_layer( network, shape, name=[paddle_op.name(), 'shape_tensor'] ) shape_rank = len(shape) elif paddle_shape_tensor.type().as_vec_type(): shape_tensors = inputs[1] shape_rank = len(shape_tensors) shape_tensor = trt_concat( network, shape_tensors, name=[paddle_op.name(), 'shape_tensor'] ) else: shape_tensor = inputs[1] shape_rank = shape_tensor.shape[0] return trt_expand( network, input, rank, shape_tensor, shape_rank, name=[paddle_op.name(), 'trt_expand'], ) @converter_registry.register("pd_op.expand_as") def expand_as_converter(network, paddle_op, inputs): input = inputs[0] input_dims = input.shape rank = len(input_dims) y = paddle_op.operands()[1].source() if y.initialized(): y_t = inputs[1] shape_tensor = trt_shape( network, y_t, name=[paddle_op.name(), 'shape_tensor'] ) shape_rank = len(y_t.shape) else: shape = paddle_op.attrs().get("target_shape") shape_tensor = add_1D_constant_layer( network, shape, name=[paddle_op.name(), 'shape_tensor'] ) shape_rank = len(shape) return trt_expand( network, input, rank, shape_tensor, shape_rank, name=[paddle_op.name(), 'trt_expand'], ) @converter_registry.register("pd_op.cast") @converter_registry.register("pd_op.cast_") def cast_converter(network, paddle_op, inputs): input_tensor = inputs[0] out_dtype = int(paddle_op.attrs().get("dtype")) # Reference paddle/phi/common/data_type.h enum DataType if out_dtype == 1: out_dtype = trt.bool elif out_dtype == 7: out_dtype = trt.int32 elif out_dtype == 9: out_dtype = trt.int32 elif out_dtype == 10: out_dtype = trt.float32 elif out_dtype == 11: out_dtype = trt.float32 elif out_dtype == 15: out_dtype = trt.float16 else: raise RuntimeError( f"cast converter currently doesn't support dtype: {out_dtype}" ) cast_layer = network.add_identity(input_tensor) cast_layer.set_output_type(0, out_dtype) cast_layer.get_output(0).dtype = out_dtype set_layer_name(cast_layer, paddle_op) return cast_layer.get_output(0) @converter_registry.register("pd_op.slice") def slice_converter(network, paddle_op, inputs): input_tensor = inputs[0] axes = paddle_op.attrs()["axes"] decrease_axis = paddle_op.attrs().get("decrease_axis") input_shape_tensor = trt_shape( network, input_tensor, name=[paddle_op.name(), "input_shape_tensor"] ) input_rank = len(input_tensor.shape) starts_tensor = [] ends_tensor = [] for i in range(input_rank): starts_tensor.append( add_1D_constant_layer( network, 0, name=[paddle_op.name(), f'starts_tensor_{i}'] ) ) ends_tensor.append( get_shape_tensor_element( network, input_shape_tensor, i, name=[paddle_op.name(), f'end_tensor_{i}'], ) ) starts = get_input_constant_value(paddle_op, inputs, 1) if starts is not None: assert len(starts) == len(axes), ( f"The size of this starts: {len(starts)} must be equal to the axes: {len(axes)}." ) for idx in range(len(axes)): if starts[idx] < 0: starts_tensor[axes[idx]] = trt_max( network, trt_sum( network, add_1D_constant_layer( network, starts[idx], name=[paddle_op.name(), f'starts[idx]_{idx}'], ), get_shape_tensor_element( network, input_shape_tensor, axes[idx], name=[paddle_op.name(), f'axes[idx]_{idx}'], ), name=[paddle_op.name(), 'trt_sum'], ), add_1D_constant_layer( network, 0, name=[paddle_op.name(), 'zero_tensor'] ), name=[ paddle_op.name(), f'starts_tensor[axes[idx]]_{axes[idx]}', ], ) else: starts_tensor[axes[idx]] = trt_min( network, add_1D_constant_layer( network, starts[idx], name=[paddle_op.name(), f'starts[idx]_{idx}'], ), get_shape_tensor_element( network, input_shape_tensor, axes[idx], name=[paddle_op.name(), f'axes[idx]_{idx}'], ), ) else: starts = inputs[1] for idx in range(len(axes)): starts_tensor[axes[idx]] = get_shape_tensor_element( network, starts, idx, name=[paddle_op.name(), f'starts_tensor_{idx}'], ) ends = get_input_constant_value(paddle_op, inputs, 2) if ends is not None: assert len(ends) == len(axes), ( f"The size of this ends: {len(ends)} must be equal to the axes: {len(axes)}." ) for idx in range(len(axes)): if ends[idx] < 0: ends_tensor[axes[idx]] = trt_max( network, trt_sum( network, add_1D_constant_layer( network, ends[idx], name=[paddle_op.name(), f'ends[idx]_{idx}'], ), get_shape_tensor_element( network, input_shape_tensor, axes[idx], name=[paddle_op.name(), f'axes[idx]_{idx}'], ), name=[paddle_op.name(), 'trt_sum'], ), add_1D_constant_layer( network, 0, name=[paddle_op.name(), 'zero_tensor'] ), name=[ paddle_op.name(), f'ends_tensor[axes[idx]]_{axes[idx]}', ], ) else: ends_tensor[axes[idx]] = trt_min( network, add_1D_constant_layer( network, ends[idx], name=[paddle_op.name(), f'ends[idx]_{idx}'], ), get_shape_tensor_element( network, input_shape_tensor, axes[idx], name=[paddle_op.name(), f'axes[idx]_{idx}'], ), ) else: ends = inputs[2] for idx in range(len(axes)): ends_tensor[axes[idx]] = get_shape_tensor_element( network, ends, idx, name=[paddle_op.name(), f'ends_tensor_{idx}'], ) start_tensor_layer = network.add_concatenation(starts_tensor) start_tensor_layer.axis = 0 set_layer_name(start_tensor_layer, paddle_op) start_tensor = start_tensor_layer.get_output(0) end_tensor_layer = network.add_concatenation(ends_tensor) end_tensor_layer.axis = 0 set_layer_name(end_tensor_layer, paddle_op) end_tensor = end_tensor_layer.get_output(0) size_tensor = trt_sub( network, end_tensor, start_tensor, name=[paddle_op.name(), 'size_tensor'], ) # Create Slice layer slice_layer = network.add_slice( input_tensor, [0] * input_rank, [0] * input_rank, [1] * input_rank ) slice_layer.set_input(1, start_tensor) slice_layer.set_input(2, size_tensor) set_layer_name(slice_layer, paddle_op) output_tensor = slice_layer.get_output(0) # Handle decrease_axis if len(decrease_axis) > 0: gather_indices = [] for i in range(input_rank): if i in decrease_axis: continue gather_indices.append(i) if len(gather_indices) == 0: # 0-dim tensor situation and shuffle layer will make its shape (1,) -> () shuffle_layer = network.add_shuffle(output_tensor) shuffle_layer.reshape_dims = () else: real_size_tensor = trt_gather(network, size_tensor, gather_indices) shuffle_layer = network.add_shuffle(output_tensor) shuffle_layer.set_input(1, real_size_tensor) set_layer_name(shuffle_layer, paddle_op) output_tensor = shuffle_layer.get_output(0) return output_tensor @converter_registry.register("pd_op.split_with_num") def split_with_num_converter(network, paddle_op, inputs): input_tensor = inputs[0] input_shape_size = len(input_tensor.shape) # Handle the case where axis is of type pir::Value axis_value = get_input_constant_value(paddle_op, inputs, 1) if axis_value is not None: axis_tensor = add_1D_constant_layer( network, axis_value, name=[paddle_op.name(), 'axis_tensor'] ) else: axis_tensor = inputs[1] axis_tensor = cast_tensor( network, axis_tensor, trt.int32, name=[paddle_op.name(), 'axis_tensor'], ) num_splits = paddle_op.attrs().get("num") num_splits_tensor = add_1D_constant_layer( network, num_splits, name=[paddle_op.name(), 'num_splits_tensor'] ) # Get the dynamic shape of the input tensor input_shape_tensor = network.add_shape(input_tensor) set_layer_name(input_shape_tensor, paddle_op) input_shape_tensor = input_shape_tensor.get_output(0) # Handle negative axis index input_shape_size_tensor = add_1D_constant_layer( network, input_shape_size, name=[paddle_op.name(), 'input_shape_size_tensor'], ) zero_tensor = add_1D_constant_layer( network, 0, name=[paddle_op.name(), 'zero_tensor'] ) is_negative_axis = trt_less( network, axis_tensor, zero_tensor, name=[paddle_op.name(), 'is_negative_axis'], ) is_negative_axis_int = cast_tensor( network, is_negative_axis, trt.int32, name=[paddle_op.name(), 'is_negative_axis_int'], ) axis_adjustment = trt_prod( network, is_negative_axis_int, input_shape_size_tensor, name=[paddle_op.name(), 'axis_adjustment'], ) axis_tensor = trt_sum( network, axis_tensor, axis_adjustment, name=[paddle_op.name(), 'axis_tensor'], ) # Get the size of the dimension specified by axis input_axis_size = network.add_gather( input_shape_tensor, axis_tensor, axis=0 ) set_layer_name(input_axis_size, paddle_op) input_axis_size = input_axis_size.get_output(0) # Compute the size of each split split_size = trt_floor_div( network, input_axis_size, num_splits_tensor, name=[paddle_op.name(), 'split_size'], ) outputs = [] current_offset = add_1D_constant_layer( network, 0, name=[paddle_op.name(), 'current_offset'] ) for idx in range(num_splits): idx_tensor = add_1D_constant_layer( network, idx, name=[paddle_op.name(), f'idx_tensor_{idx}'] ) # Calculate the slice start and size start_tensor = build_start_tensor( network, input_shape_size, axis_tensor, current_offset, name=[paddle_op.name(), f'start_tensor_{idx}'], ) size_tensor = build_size_tensor( network, input_shape_size, axis_tensor, split_size, input_shape_tensor, name=[paddle_op.name(), f'size_tensor_{idx}'], ) # Create Slice layer slice_layer = network.add_slice( input_tensor, [0] * input_shape_size, [0] * input_shape_size, [1] * input_shape_size, ) slice_layer.set_input(1, start_tensor) slice_layer.set_input(2, size_tensor) set_layer_name(slice_layer, paddle_op) outputs.append(slice_layer.get_output(0)) # Update current_offset for the next slice current_offset = trt_sum( network, current_offset, split_size, name=[paddle_op.name(), 'current_offset'], ) return outputs @converter_registry.register("pd_op.split") def split_converter(network, paddle_op, inputs): input_tensor = inputs[0] input_shape = input_tensor.shape input_shape_size = len(input_shape) axis_value = get_input_constant_value(paddle_op, inputs, 2) if axis_value is not None: axis_tensor = add_1D_constant_layer( network, axis_value, name=[paddle_op.name(), 'axis_tensor'] ) else: axis_tensor = inputs[2] axis_tensor = cast_tensor( network, axis_tensor, trt.int32, name=[paddle_op.name(), 'axis_tensor'], ) # Retrieve and process sections sections_value = get_input_constant_value(paddle_op, inputs, 1) if sections_value is not None: section_list = [int(s) for s in sections_value] dynamic_sections = False else: sections_tensor = inputs[1] dynamic_sections = True # Get the dynamic shape of the input tensor input_shape_tensor = network.add_shape(input_tensor) set_layer_name(input_shape_tensor, paddle_op) input_shape_tensor = input_shape_tensor.get_output(0) # Handle negative axis index input_shape_size_tensor = add_1D_constant_layer( network, input_shape_size, name=[paddle_op.name(), 'input_shape_size_tensor'], ) zero_tensor = add_1D_constant_layer( network, 0, name=[paddle_op.name(), 'zero_tensor'] ) is_negative_axis = trt_less( network, axis_tensor, zero_tensor, name=[paddle_op.name(), 'is_negative_axis'], ) is_negative_axis_int = cast_tensor( network, is_negative_axis, trt.int32, name=[paddle_op.name(), 'is_negative_axis_int'], ) axis_adjustment = trt_prod( network, is_negative_axis_int, input_shape_size_tensor, name=[paddle_op.name(), 'axis_adjustment'], ) axis_tensor = trt_sum( network, axis_tensor, axis_adjustment, name=[paddle_op.name(), 'axis_tensor'], ) # Initialize output list outputs = [] offset = add_1D_constant_layer( network, 0, name=[paddle_op.name(), 'offset'] ) if not dynamic_sections: for section_size in section_list: section_size_tensor = add_1D_constant_layer( network, section_size, name=[paddle_op.name(), f'section_size_tensor_{section_size}'], ) # Build start_tensor start_tensor = build_start_tensor( network, input_shape_size, axis_tensor, offset, name=[paddle_op.name(), f'start_tensor_{section_size}'], ) # Build size_tensor size_tensor = build_size_tensor( network, input_shape_size, axis_tensor, section_size_tensor, input_shape_tensor, name=[paddle_op.name(), f'size_tensor_{section_size}'], ) # Create Slice layer slice_layer = network.add_slice( input_tensor, [0] * input_shape_size, [0] * input_shape_size, [1] * input_shape_size, ) slice_layer.set_input(1, start_tensor) slice_layer.set_input(2, size_tensor) set_layer_name(slice_layer, paddle_op) outputs.append(slice_layer.get_output(0)) # Update offset offset = network.add_elementwise( offset, section_size_tensor, trt.ElementWiseOperation.SUM ) set_layer_name(offset, paddle_op) offset = offset.get_output(0) else: # If sections is a dynamic tensor num_sections = sections_tensor.shape[0] if num_sections == -1: raise NotImplementedError("dynamic sections not support") num_sections = int(num_sections) for idx in range(num_sections): idx_tensor = add_1D_constant_layer( network, idx, name=[paddle_op.name(), f'idx_tensor_{idx}'] ) # Get section_size_tensor = sections_tensor[idx] section_size_tensor = network.add_gather( sections_tensor, idx_tensor, axis=0 ) set_layer_name(section_size_tensor, paddle_op) section_size_tensor = section_size_tensor.get_output(0) # Build start_tensor start_tensor = build_start_tensor( network, input_shape_size, axis_tensor, offset, name=[paddle_op.name(), f'start_tensor_{idx}'], ) # Build size_tensor size_tensor = build_size_tensor( network, input_shape_size, axis_tensor, section_size_tensor, input_shape_tensor, name=[paddle_op.name(), f'size_tensor_{idx}'], ) # Create Slice layer slice_layer = network.add_slice( input_tensor, [0] * input_shape_size, [0] * input_shape_size, [1] * input_shape_size, ) slice_layer.set_input(1, start_tensor) slice_layer.set_input(2, size_tensor) set_layer_name(slice_layer, paddle_op) outputs.append(slice_layer.get_output(0)) # Update offset offset = network.add_elementwise( offset, section_size_tensor, trt.ElementWiseOperation.SUM ) set_layer_name(offset, paddle_op) offset = offset.get_output(0) return outputs @converter_registry.register("pd_op.stack") def stack_converter(network, paddle_op, inputs): input_tensors = inputs[0] input_num = len(input_tensors) inputs = [] for i in range(input_num): inputs.append(input_tensors[i]) input_rank = len(input_tensors[0].shape) output_rank = input_rank + 1 axis = paddle_op.attrs().get("axis") if axis < 0: axis += output_rank shape_tensor = network.add_shape(input_tensors[0]) set_layer_name(shape_tensor, paddle_op) shape_tensor = shape_tensor.get_output(0) shape_tensor_vec = [] for i in range(output_rank): if i < axis: shape_tensor_vec.append( get_shape_tensor_element( network, shape_tensor, i, name=[paddle_op.name(), f'shape_tensor_vec_{i}'], ) ) elif i > axis: shape_tensor_vec.append( get_shape_tensor_element( network, shape_tensor, i - 1, name=[paddle_op.name(), f'shape_tensor_vec_{i}'], ) ) else: shape_tensor_vec.append( add_1D_constant_layer( network, 1, name=[paddle_op.name(), f'shape_tensor_vec_{i}'] ) ) after_shape_tensor = network.add_concatenation(shape_tensor_vec) set_layer_name(after_shape_tensor, paddle_op) after_shape_tensor = after_shape_tensor.get_output(0) for i in range(input_num): shuffle_layer = network.add_shuffle(inputs[i]) shuffle_layer.set_input(1, after_shape_tensor) set_layer_name(shuffle_layer, [paddle_op.name(), f'shuffle_layer_{i}']) reshaped_tensor = shuffle_layer.get_output(0) inputs[i] = reshaped_tensor concat_layer = network.add_concatenation(inputs) concat_layer.axis = axis set_layer_name(concat_layer, paddle_op) output_tensor = concat_layer.get_output(0) # Because we change tensor to 1-dim in 0-dim tensor situation when use trt, # so after stack, output will become 2-dim, if paddle output is a 1d tensor, we need reshape it. if ( len(paddle_op.results()[0].shape) == 1 and paddle_op.results()[0].shape[0] != -1 ): output_tensor = resize_to_1d( network, output_tensor, name=[paddle_op.name(), 'output_tensor'] ) return output_tensor @converter_registry.register("pd_op.tile") def tile_converter(network, paddle_op, inputs): input = inputs[0] input_shape = input.shape input_shape_tensor = network.add_shape(input) set_layer_name(input_shape_tensor, paddle_op) input_shape_tensor = input_shape_tensor.get_output(0) rank = len(input_shape) repeat_times = get_input_constant_value(paddle_op, inputs, 1) if repeat_times is not None: repeat_tensor = add_1D_constant_layer( network, repeat_times, name=[paddle_op.name(), 'repeat_tensor'] ) repeat_rank = len(repeat_times) else: repeat_tensor = inputs[1] if isinstance(repeat_tensor, list): repeat_rank = len(repeat_tensor) repeat_tensor = trt_concat( network, repeat_tensor, name=[paddle_op.name(), 'repeat_tensor'] ) else: repeat_tensor = resize_to_1d( network, repeat_tensor, name=[paddle_op.name(), 'repeat_tensor'] ) repeat_shape = paddle_op.operands()[1].source().shape repeat_rank = repeat_shape[0] if rank > repeat_rank: one_rank_tensor = add_1D_constant_layer( network, [1] * (rank - repeat_rank), name=[paddle_op.name(), 'one_rank_tensor'], ) repeat_expand_tensor = trt_concat( network, [one_rank_tensor, repeat_tensor], name=[paddle_op.name(), 'repeat_expand_tensor'], ) elif rank < repeat_rank: one_rank_tensor = add_1D_constant_layer( network, [1] * (repeat_rank - rank), name=[paddle_op.name(), 'one_rank_tensor'], ) input_shape_tensor = trt_concat( network, [one_rank_tensor, input_shape_tensor], name=[paddle_op.name(), 'input_shape_tensor'], ) input = trt_reshape( network, input, input_shape_tensor, name=[paddle_op.name(), 'input_shape_tensor'], is_shape_tensor=True, ) repeat_expand_tensor = repeat_tensor else: repeat_expand_tensor = repeat_tensor start = [0] * max(rank, repeat_rank) stride = [1] * max(rank, repeat_rank) output_shape = [0] * max(rank, repeat_rank) output_shape_tensor = trt_prod( network, input_shape_tensor, repeat_expand_tensor, name=[paddle_op.name(), 'output_shape_tensor'], ) slice_layer = network.add_slice(input, start, output_shape, stride) slice_layer.set_input(2, output_shape_tensor) set_layer_name(slice_layer, paddle_op) version_list = get_trt_version_list() if version_list >= [8, 6, 0]: slice_layer.mode = trt.SampleMode.WRAP else: slice_layer.mode = trt.SliceMode.WRAP return slice_layer.get_output(0) @converter_registry.register( "pd_op.take_along_axis", trt_version="trt_version_ge=8.2" ) def take_along_axis_converter(network, paddle_op, inputs): axis = paddle_op.attrs().get("axis", 0) input_tensor = inputs[0] index_tensor = inputs[1] input_dims = input_tensor.shape if axis < 0: axis += len(input_dims) gather_layer = network.add_gather_v2( input_tensor, index_tensor, trt.GatherMode.ELEMENT ) gather_layer.axis = axis set_layer_name(gather_layer, paddle_op) output_tensor = gather_layer.get_output(0) return output_tensor @converter_registry.register("pd_op.strided_slice") def strided_slice_converter(network, paddle_op, inputs): input_tensor = inputs[0] axes = paddle_op.attrs()["axes"] starts = get_input_constant_value(paddle_op, inputs, 1) ends = get_input_constant_value(paddle_op, inputs, 2) strides = get_input_constant_value(paddle_op, inputs, 3) input_shape = input_tensor.shape nchw_input_dims = len(input_shape) trt_start_dims = [0] * nchw_input_dims trt_end_dims = [0] * nchw_input_dims trt_size_dims = [0] * nchw_input_dims trt_step_dims = [1] * nchw_input_dims has_neg_indices = False for i, trt_axis in enumerate(axes): trt_start_dims[trt_axis] = starts[i] trt_end_dims[trt_axis] = ends[i] trt_step_dims[trt_axis] = strides[i] if starts[i] < 0 or ends[i] < 0: has_neg_indices = True shape_tensor = trt_shape( network, input_tensor, name=[paddle_op.name(), 'shape_tensor'] ) start_tensor = add_1D_constant_layer( network, trt_start_dims, name=[paddle_op.name(), 'start_tensor'] ) if has_neg_indices: start_tensor = fix_negative_indices( network, shape_tensor, start_tensor, name=[paddle_op.name(), 'start_tensor'], ) end_vec_tensor = [] for i in range(len(trt_end_dims)): end_vec_tensor.append( get_shape_tensor_element( network, shape_tensor, i, name=[paddle_op.name(), f'end_vec_tensor{i}'], ) ) for i, trt_axis in enumerate(axes): if ends[i] >= 0: end_vec_tensor[trt_axis] = add_1D_constant_layer( network, ends[i], name=[paddle_op.name(), f'end_vec_tensor{i}'] ) else: end_vec_tensor[trt_axis] = trt_sum( network, end_vec_tensor[trt_axis], add_1D_constant_layer( network, ends[i], name=[paddle_op.name(), f'end_vec_tensor{i}'], ), name=[paddle_op.name(), f'end_vec_tensor{i}'], ) size_tensor = trt_sub( network, start_tensor, trt_min( network, trt_concat( network, end_vec_tensor, name=[paddle_op.name(), 'trt_concat'] ), shape_tensor, name=[paddle_op.name(), 'trt_min'], ), name=[paddle_op.name(), 'size_tensor'], ) zero_t = add_1D_constant_layer( network, 0, name=[paddle_op.name(), 'zero_t'] ) step_tensor = add_1D_constant_layer( network, trt_step_dims, name=[paddle_op.name(), 'step_tensor'] ) size_tensor = trt_sub( network, zero_t, trt_floor_div( network, size_tensor, step_tensor, name=[paddle_op.name(), 'trt_floor_div'], ), name=[paddle_op.name(), 'size_tensor'], ) layer = network.add_slice( input_tensor, trt_start_dims, trt_size_dims, trt_step_dims ) layer.set_input(1, start_tensor) layer.set_input(2, size_tensor) layer.set_input(3, step_tensor) set_layer_name(layer, paddle_op) return layer.get_output(0) @converter_registry.register("pd_op.roll") def roll_converter(network, paddle_op, inputs): input_tensor = inputs[0] axis = paddle_op.attrs()["axis"] shifts = get_input_constant_value(paddle_op, inputs, 1) if shifts is None: shifts = inputs[1] axis_size = len(axis) input_shape_tensor = trt_shape( network, input_tensor, name=[paddle_op.name(), 'input_shape_tensor'] ) for i in range(axis_size): axi = axis[i] if isinstance(shifts, trt.ITensor): shift = get_shape_tensor_element( network, shifts, i, name=[paddle_op.name(), f'shift_{i}'] ) input_shift = shift else: shift = shifts[i] input_shift = add_1D_constant_layer( network, shift, name=[paddle_op.name(), f'input_shift_{i}'] ) input_axis = get_shape_tensor_element( network, input_shape_tensor, axi, name=[paddle_op.name(), f'input_axis_{i}'], ) # 1.sub_value mod input_axis input1 = trt_sub( network, input_axis, input_shift, name=[paddle_op.name(), f'input1_{i}'], ) tmp_div_res = trt_floor_div( network, input1, input_axis, name=[paddle_op.name(), f'tmp_div_res_{i}'], ) tmp_prod_res = trt_prod( network, tmp_div_res, input_axis, name=[paddle_op.name(), f'tmp_prod_res_{i}'], ) start = trt_sub( network, input1, tmp_prod_res, name=[paddle_op.name(), f'start_{i}'] ) # 2.avoid start less than 0,start mod input_axis start = trt_sum( network, start, input_axis, name=[paddle_op.name(), f'start_{i}'] ) tmp_div_res1 = trt_floor_div( network, start, input_axis, name=[paddle_op.name(), f'tmp_div_res1_{i}'], ) tmp_prod_res1 = trt_prod( network, tmp_div_res1, input_axis, name=[paddle_op.name(), f'tmp_prod_res1_{i}'], ) start = trt_sub( network, start, tmp_prod_res1, name=[paddle_op.name(), f'start_{i}'] ) zero_tensor = add_1D_constant_layer( network, 0, name=[paddle_op.name(), f'zero_tensor_{i}'] ) step = add_1D_constant_layer( network, 1, name=[paddle_op.name(), f'step_{i}'] ) # 3.make index_tensor0 sub_qutient = trt_sub( network, input_axis, start, name=[paddle_op.name(), f'sub_qutient_{i}'], ) quotient_tensor = trt_floor_div( network, sub_qutient, step, name=[paddle_op.name(), f'quotient_tensor_{i}'], ) start1 = get_shape_tensor_element( network, start, 0, is_scalar=True, name=[paddle_op.name(), f'start1_{i}'], ) fill_layer0 = network.add_fill(shape=(), op=trt.FillOperation.LINSPACE) fill_layer0.set_input(0, quotient_tensor) fill_layer0.set_input(1, start1) fill_layer0.set_input(2, step) set_layer_name(fill_layer0, paddle_op) index_tensor0 = fill_layer0.get_output(0) # 4.make index_tensor1 sub_qutient_tensor = trt_sub( network, start, zero_tensor, name=[paddle_op.name(), f'sub_qutient_tensor_{i}'], ) quotient_tensor = trt_floor_div( network, sub_qutient_tensor, step, name=[paddle_op.name(), f'quotient_tensor_{i}'], ) start2 = add_1D_constant_layer( network, 0, is_scalar=True, name=[paddle_op.name(), f'start2_{i}'] ) fill_layer1 = network.add_fill(shape=(), op=trt.FillOperation.LINSPACE) fill_layer1.set_input(0, quotient_tensor) fill_layer1.set_input(1, start2) fill_layer1.set_input(2, step) set_layer_name(fill_layer1, paddle_op) index_tensor1 = fill_layer1.get_output(0) itensors = [index_tensor0, index_tensor1] concat_input_tensor = trt_concat( network, itensors, name=[paddle_op.name(), 'concat_input_tensor'] ) if i == 0: layer = network.add_gather( input=input_tensor, indices=concat_input_tensor, axis=axi ) else: layer = network.add_gather( input=layer.get_output(0), indices=concat_input_tensor, axis=axi ) set_layer_name(layer, paddle_op) return layer.get_output(0) @converter_registry.register("pd_op.pad") def pad_converter(network, paddle_op, inputs): input_tensor = inputs[0] paddings = paddle_op.attrs()["paddings"] pad_size = len(paddings) pre_pad = [paddings[pad_size - 4], paddings[pad_size - 2]] post_pad = [paddings[pad_size - 3], paddings[pad_size - 1]] layer = network.add_padding_nd(input_tensor, pre_pad, post_pad) set_layer_name(layer, paddle_op) return layer.get_output(0) @converter_registry.register("pd_op.pad3d") def pad3d_converter(network, paddle_op, inputs): input_tensor, paddings = inputs value = paddle_op.attrs().get("pad_value", 0.0) padding_mode = paddle_op.attrs().get("mode", "constant") data_format = paddle_op.attrs().get("data_format") if padding_mode == "circular" or data_format == "NDHWC": attrs = paddle_op.attrs() value_attr = get_input_constant_value(paddle_op, inputs, 1) attrs["paddings"] = value_attr layer = generic_plugin_converter(network, paddle_op, inputs, attrs) return layer.get_output(0) else: input_dim = len(input_tensor.shape) pad_size = paddings.shape[0] assert input_dim * 2 - 4 == pad_size, ( f"Expected paddings size is {input_dim * 2 - 4}, but received {pad_size}." ) shuffle_index = [4, 2, 0, 5, 3, 1] shuffle_inputs = [ get_shape_tensor_element( network, paddings, shuffle_index[i], name=[paddle_op.name(), f'shuffle_inputs_{i}'], ) for i in range(pad_size) ] paddings = trt_concat( network, shuffle_inputs, name=[paddle_op.name(), 'paddings'] ) pre_zeros = add_1D_constant_layer( network, [0, 0], name=[paddle_op.name(), 'pre_zeros'] ) start_slice1 = [0] start_slice2 = [3] size_slice = [3] stride_slice = [1] pre_pad = network.add_slice( paddings, start_slice1, size_slice, stride_slice ) set_layer_name(pre_pad, paddle_op) pre_pad = pre_pad.get_output(0) pre_pad = trt_concat( network, [pre_zeros, pre_pad], name=[paddle_op.name(), 'pre_pad'] ) post_pad = network.add_slice( paddings, start_slice2, size_slice, stride_slice ) set_layer_name(post_pad, paddle_op) post_pad = post_pad.get_output(0) post_pad = trt_concat( network, [pre_zeros, post_pad], name=[paddle_op.name(), 'post_pad'] ) zeros = add_1D_constant_layer( network, [0] * input_dim, name=[paddle_op.name(), 'zeros'] ) start = trt_sub( network, zeros, pre_pad, name=[paddle_op.name(), 'start'] ) total_padding = trt_sum( network, pre_pad, post_pad, name=[paddle_op.name(), 'total_padding'] ) input_shape = trt_shape( network, input_tensor, name=[paddle_op.name(), 'input_shape'] ) size = trt_sum( network, input_shape, total_padding, name=[paddle_op.name(), 'size'] ) # Add slice layer stride = [1] * input_dim dummy = stride slice_layer = network.add_slice(input_tensor, dummy, dummy, stride) slice_layer.set_input(1, start) slice_layer.set_input(2, size) set_layer_name(slice_layer, paddle_op) # Set padding mode if padding_mode == "constant": slice_layer.mode = trt.SampleMode.FILL if value != 0.0: if input_tensor.dtype in ( trt.DataType.FLOAT, trt.DataType.HALF, trt.DataType.INT8, ): fill_value = add_1D_constant_layer( network, value, dtype=np.float32, name=[paddle_op.name(), 'fill_value'], ) else: value_int = int(value) fill_value = add_1D_constant_layer( network, value_int, dtype=np.int32, name=[paddle_op.name(), 'fill_value'], ) slice_layer.set_input(4, fill_value) elif padding_mode == "reflect": slice_layer.mode = trt.SampleMode.REFLECT elif padding_mode == "replicate": slice_layer.mode = trt.SampleMode.CLAMP else: raise ValueError(f"Unsupported padding mode: {padding_mode}") return slice_layer.get_output(0) @converter_registry.register("pd_op.numel") def numel_converter(network, paddle_op, inputs): input_tensor = inputs[0] shape_tensor = network.add_shape(input_tensor) set_layer_name(shape_tensor, paddle_op) shape_tensor = shape_tensor.get_output(0) layer = network.add_reduce( shape_tensor, trt.ReduceOperation.PROD, axes=1, keep_dims=False ) set_layer_name(layer, paddle_op) return layer.get_output(0) @converter_registry.register("pd_op.index_put") def index_put_converter(network, paddle_op, inputs): input_tensor, indices_list, value_tensor = inputs indices_tensor = indices_list[0] input_shape_tensor = trt_shape( network, input_tensor, name=[paddle_op.name(), 'input_shape_tensor'] ) input_dims = input_tensor.shape indices_dims = indices_tensor.shape rank = len(input_dims) # indices indices_shape_vec = [ add_1D_constant_layer( network, indices_dims[i] if i < len(indices_dims) else 1, name=[paddle_op.name(), f'indices_shape_vec_{i}'], ) for i in range(rank) ] start_tensor_vec = [ add_1D_constant_layer( network, 0, name=[paddle_op.name(), f'start_tensor_vec_{i}'] ) for i in range(rank) ] stride_tensor_vec = [ add_1D_constant_layer( network, 1, name=[paddle_op.name(), f'stride_tensor_vec_{i}'] ) for i in range(rank) ] indices_tensor_temp = trt_reshape( network, indices_tensor, trt_concat( network, indices_shape_vec, name=[paddle_op.name(), 'indices_shape_vec'], ), name=[paddle_op.name(), 'indices_tensor_temp'], is_shape_tensor=True, ) start_tensor = trt_concat( network, start_tensor_vec, name=[paddle_op.name(), 'start_tensor'] ) stride_tensor = trt_concat( network, stride_tensor_vec, name=[paddle_op.name(), 'stride_tensor'] ) # slice stride = [1] * rank indices_slice_layer = network.add_slice( trt_cast( network, indices_tensor_temp, trt.float32, name=[paddle_op.name(), 'indices_tensor_temp'], ), stride, stride, stride, ) indices_slice_layer.set_input(1, start_tensor) indices_slice_layer.set_input(2, input_shape_tensor) indices_slice_layer.set_input(3, stride_tensor) indices_slice_layer.mode = trt.SampleMode.CLAMP set_layer_name(indices_slice_layer, paddle_op) bool_indices_tensor = trt_cast( network, indices_slice_layer.get_output(0), trt.bool, name=[paddle_op.name(), 'bool_indices_tensor'], ) # nonzero nonzero_layer = network.add_non_zero(bool_indices_tensor) set_layer_name(nonzero_layer, paddle_op) indices_tensor = nonzero_layer.get_output(0) permutation = trt.Permutation([1, 0]) trans_layer = network.add_shuffle(indices_tensor) trans_layer.first_transpose = permutation set_layer_name(trans_layer, paddle_op) indices_tensor = trans_layer.get_output(0) indices_new_shape_tensor = trt_shape( network, indices_tensor, name=[paddle_op.name(), 'indices_new_shape_tensor'], ) indices_count_tensor = get_shape_tensor_element( network, indices_new_shape_tensor, 0, name=[paddle_op.name(), 'indices_count_tensor'], ) # value value_stride = [1] value_slice_layer = network.add_slice( value_tensor, value_stride, value_stride, value_stride ) value_slice_layer.set_input( 1, add_1D_constant_layer( network, 0, name=[paddle_op.name(), 'value_slice_layer_start'] ), ) value_slice_layer.set_input(2, indices_count_tensor) value_slice_layer.set_input( 3, add_1D_constant_layer( network, 1, name=[paddle_op.name(), 'value_slice_layer_stride'] ), ) value_slice_layer.mode = trt.SampleMode.CLAMP set_layer_name(value_slice_layer, paddle_op) value_tensor = value_slice_layer.get_output(0) layer = network.add_scatter( input_tensor, indices_tensor, value_tensor, trt.ScatterMode.ND ) set_layer_name(layer, paddle_op) return layer.get_output(0)