Files
2026-07-13 12:40:42 +08:00

1634 lines
52 KiB
Python

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