557 lines
20 KiB
Python
557 lines
20 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 import pir
|
|
from paddle.tensorrt.converter_utils import (
|
|
add_1D_constant_layer,
|
|
get_input_constant_value,
|
|
get_shape_tensor_element,
|
|
set_layer_name,
|
|
trt_concat,
|
|
trt_reshape,
|
|
trt_shape,
|
|
)
|
|
from paddle.tensorrt.register import converter_registry
|
|
from paddle.tensorrt.util import get_trt_version_list
|
|
|
|
|
|
@converter_registry.register("pd_op.dropout")
|
|
def dropout_converter(network, paddle_op, inputs):
|
|
input_x = inputs[0]
|
|
dropout_prob = get_input_constant_value(paddle_op, inputs, 2)[0]
|
|
downgrade_in_infer = paddle_op.attrs().get("mode")
|
|
|
|
if downgrade_in_infer == "upscale_in_train":
|
|
shuffle_layer = network.add_shuffle(input_x)
|
|
set_layer_name(shuffle_layer, paddle_op)
|
|
return shuffle_layer.get_output(0)
|
|
|
|
weight_data = np.array([1 - dropout_prob]).astype("float32")
|
|
scale_weights = trt.Weights(weight_data)
|
|
shift_weights = trt.Weights(np.array([0]).astype("float32"))
|
|
power_weights = trt.Weights(np.array([1]).astype("float32"))
|
|
|
|
scale_layer = network.add_scale(
|
|
input_x,
|
|
mode=trt.ScaleMode.UNIFORM,
|
|
shift=shift_weights,
|
|
scale=scale_weights,
|
|
power=power_weights,
|
|
)
|
|
set_layer_name(scale_layer, paddle_op)
|
|
|
|
return scale_layer.get_output(0)
|
|
|
|
|
|
@converter_registry.register("pd_op.bilinear_interp")
|
|
def bilinear_interp_converter(network, paddle_op, inputs):
|
|
input_tensor = inputs[0]
|
|
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)
|
|
|
|
input_rank = input_shape_tensor.shape # The reason is unknown that adding this unused code make input_shape_tensor maintain the correct result.
|
|
data_format = paddle_op.attrs().get("data_format")
|
|
interp_method = paddle_op.attrs().get("interp_method")
|
|
align_corners = paddle_op.attrs().get("align_corners")
|
|
align_mode = paddle_op.attrs().get("align_mode")
|
|
out_h = paddle_op.attrs().get("out_h")
|
|
out_w = paddle_op.attrs().get("out_w")
|
|
out_d = paddle_op.attrs().get("out_d")
|
|
scale_attr = paddle_op.attrs().get("scale")
|
|
|
|
trt_major = get_trt_version_list()[0]
|
|
trt_minor = get_trt_version_list()[1]
|
|
trt_version_float = float(f"{trt_major}.{trt_minor}")
|
|
|
|
resize_layer = network.add_resize(input_tensor)
|
|
set_layer_name(resize_layer, paddle_op)
|
|
# Set resize mode to LINEAR unconditionally
|
|
if trt_version_float >= 8.6:
|
|
resize_layer.resize_mode = trt.InterpolationMode.LINEAR
|
|
else:
|
|
resize_layer.resize_mode = trt.ResizeMode.LINEAR
|
|
|
|
# Set coordinate transformation based on align_corners and align_mode
|
|
if align_corners:
|
|
resize_layer.coordinate_transformation = (
|
|
trt.ResizeCoordinateTransformation.ALIGN_CORNERS
|
|
)
|
|
else:
|
|
if align_mode == 0:
|
|
resize_layer.coordinate_transformation = (
|
|
trt.ResizeCoordinateTransformation.HALF_PIXEL
|
|
)
|
|
else: # align_mode == 1
|
|
resize_layer.coordinate_transformation = (
|
|
trt.ResizeCoordinateTransformation.ASYMMETRIC
|
|
)
|
|
|
|
if data_format == "NCHW":
|
|
h_axis = 2
|
|
w_axis = 3
|
|
elif data_format == "NHWC":
|
|
h_axis = 1
|
|
w_axis = 2
|
|
|
|
in_dim = input_tensor.shape
|
|
|
|
outsize_tensor = None
|
|
if trt_version_float >= 8.2:
|
|
if not pir.is_fake_value(paddle_op.operands()[1].source()):
|
|
size_tensor_operand = paddle_op.operands()[1].source()
|
|
if len(inputs) > 1 and inputs[1] is not None:
|
|
outsize_tensor = inputs[1]
|
|
elif not pir.is_fake_value(paddle_op.operands()[2].source()):
|
|
size_tensor_operand = paddle_op.operands()[2].source()
|
|
size_tensor = inputs[2]
|
|
if size_tensor_operand.is_combine():
|
|
size_tensors = []
|
|
if not isinstance(size_tensor, list):
|
|
size_tensors = [size_tensor]
|
|
else:
|
|
size_tensors = size_tensor
|
|
if len(size_tensors) >= 2:
|
|
# Extract the first two elements representing height and width
|
|
outsize_h = size_tensors[0]
|
|
outsize_w = size_tensors[1]
|
|
outsize_tensor = network.add_concatenation(
|
|
[outsize_h, outsize_w]
|
|
)
|
|
set_layer_name(outsize_tensor, paddle_op)
|
|
outsize_tensor = outsize_tensor.get_output(0)
|
|
else:
|
|
size_tensor_shape = size_tensor_operand.source().shape
|
|
if size_tensor_shape.size >= 2:
|
|
outsize_h = network.add_slice(
|
|
size_tensor, start=[0], shape=[1], stride=[1]
|
|
)
|
|
set_layer_name(outsize_h, paddle_op)
|
|
outsize_h = outsize_h.get_output(0)
|
|
outsize_w = network.add_slice(
|
|
size_tensor, start=[1], shape=[1], stride=[1]
|
|
)
|
|
set_layer_name(outsize_w, paddle_op)
|
|
outsize_w = outsize_w.get_output(0)
|
|
outsize_tensor = network.add_concatenation(
|
|
[outsize_h, outsize_w]
|
|
)
|
|
set_layer_name(outsize_tensor, paddle_op)
|
|
outsize_tensor = outsize_tensor.get_output(0)
|
|
use_scales = True
|
|
if outsize_tensor is not None:
|
|
use_scales = False
|
|
if outsize_tensor is None and len(scale_attr) == 0:
|
|
use_scales = False
|
|
|
|
if use_scales:
|
|
scale_h = -1.0
|
|
scale_w = -1.0
|
|
|
|
if scale_attr and len(scale_attr) > 1:
|
|
scale_h = scale_attr[0]
|
|
scale_w = scale_attr[1]
|
|
elif scale_attr and len(scale_attr) == 1:
|
|
scale_h = scale_w = scale_attr[0]
|
|
|
|
if scale_w > 0 and scale_h > 0:
|
|
if in_dim[h_axis] > 0 and in_dim[w_axis] > 0:
|
|
out_h = int(in_dim[h_axis] * scale_h)
|
|
out_w = int(in_dim[w_axis] * scale_w)
|
|
else:
|
|
if out_h > 0 and out_w > 0 and not (scale_w > 0 and scale_h > 0):
|
|
if in_dim[h_axis] > 0 and in_dim[w_axis] > 0:
|
|
scale_h = float(out_h) / float(in_dim[h_axis])
|
|
scale_w = float(out_w) / float(in_dim[w_axis])
|
|
|
|
scales = [1.0] * len(input_tensor.shape)
|
|
if data_format == "NCHW":
|
|
scales[2] = scale_h
|
|
scales[3] = scale_w
|
|
elif data_format == "NHWC":
|
|
scales[1] = scale_h
|
|
scales[2] = scale_w
|
|
|
|
resize_layer.scales = scales
|
|
else:
|
|
if outsize_tensor is not None:
|
|
outsize_itensors = []
|
|
batch_dim = get_shape_tensor_element(
|
|
network,
|
|
input_shape_tensor,
|
|
0,
|
|
name=[paddle_op.name(), "batch_dim"],
|
|
)
|
|
outsize_itensors.append(batch_dim)
|
|
if data_format == "NCHW":
|
|
channel_dim = get_shape_tensor_element(
|
|
network,
|
|
input_shape_tensor,
|
|
1,
|
|
name=[paddle_op.name(), "channel_dim"],
|
|
)
|
|
outsize_itensors.append(channel_dim)
|
|
outsize_itensors.append(outsize_tensor)
|
|
elif data_format == "NHWC":
|
|
channel_dim = get_shape_tensor_element(
|
|
network,
|
|
input_shape_tensor,
|
|
3,
|
|
name=[paddle_op.name(), "channel_dim"],
|
|
)
|
|
outsize_itensors.append(outsize_tensor)
|
|
outsize_itensors.append(channel_dim)
|
|
output_size_tensor = network.add_concatenation(outsize_itensors)
|
|
set_layer_name(output_size_tensor, paddle_op)
|
|
output_size_tensor = output_size_tensor.get_output(0)
|
|
resize_layer.set_input(1, output_size_tensor)
|
|
else:
|
|
if data_format == "NCHW":
|
|
shape_layer = network.add_shape(input_tensor)
|
|
shape_output = shape_layer.get_output(0)
|
|
# Get N and C from slice_layer output
|
|
slice_layer = network.add_slice(
|
|
shape_output, start=[0], shape=[2], stride=[1]
|
|
)
|
|
# Create H and W
|
|
hw_constant = network.add_constant(
|
|
shape=(2,),
|
|
weights=trt.Weights(
|
|
np.array([out_h, out_w], dtype=np.int32)
|
|
),
|
|
).get_output(0)
|
|
# Create output shape(NCHW)
|
|
concat_layer = network.add_concatenation(
|
|
[slice_layer.get_output(0), hw_constant]
|
|
)
|
|
concat_layer.axis = 0
|
|
resize_layer.set_input(1, concat_layer.get_output(0))
|
|
elif data_format == "NHWC":
|
|
shape_layer = network.add_shape(input_tensor)
|
|
shape_output = shape_layer.get_output(0)
|
|
# Get N and C from slice_layer output
|
|
n_layer = network.add_slice(
|
|
shape_output, start=[0], shape=[1], stride=[1]
|
|
)
|
|
c_layer = network.add_slice(
|
|
shape_output, start=[3], shape=[1], stride=[1]
|
|
)
|
|
# Create H and W
|
|
hw_constant = network.add_constant(
|
|
shape=(2,),
|
|
weights=trt.Weights(
|
|
np.array([out_h, out_w], dtype=np.int32)
|
|
),
|
|
).get_output(0)
|
|
# Create output shape(NHWC)
|
|
concat_layer = network.add_concatenation(
|
|
[n_layer.get_output(0), hw_constant, c_layer.get_output(0)]
|
|
)
|
|
concat_layer.axis = 0
|
|
resize_layer.set_input(1, concat_layer.get_output(0))
|
|
else:
|
|
raise NotImplementedError(
|
|
"Converter for bilinear_interp not support data_format {}.",
|
|
data_format,
|
|
)
|
|
return resize_layer.get_output(0)
|
|
|
|
|
|
@converter_registry.register("pd_op.embedding")
|
|
def embedding_converter(network, paddle_op, inputs):
|
|
x = inputs[0]
|
|
weight = inputs[1]
|
|
gather_layer = network.add_gather(weight, x, 0)
|
|
set_layer_name(gather_layer, paddle_op)
|
|
return gather_layer.get_output(0)
|
|
|
|
|
|
@converter_registry.register("pd_op.unbind")
|
|
def unbind_converter(network, paddle_op, inputs):
|
|
x = inputs[0]
|
|
input_shape = x.shape
|
|
axis = paddle_op.attrs().get("axis")
|
|
rank = len(input_shape)
|
|
if axis < 0:
|
|
axis += rank
|
|
axis = int(axis)
|
|
# Input for the add_slice layer
|
|
start_tensors = []
|
|
size_tensors = []
|
|
# Input for the add_shuffle layer
|
|
new_shape_tensors = []
|
|
for i in range(rank):
|
|
if axis == i:
|
|
size_tensors.append(
|
|
add_1D_constant_layer(
|
|
network, 1, name=[paddle_op.name(), "size_tensor"]
|
|
)
|
|
)
|
|
else:
|
|
size_tensors.append(
|
|
get_shape_tensor_element(
|
|
network,
|
|
trt_shape(network, x, name=[paddle_op.name(), "trt_shape"]),
|
|
i,
|
|
name=[paddle_op.name(), f"size_tensor_{i}"],
|
|
)
|
|
)
|
|
new_shape_tensors.append(
|
|
get_shape_tensor_element(
|
|
network,
|
|
trt_shape(network, x, name=[paddle_op.name(), "trt_shape"]),
|
|
i,
|
|
name=[paddle_op.name(), f"new_shape_tensor_{i}"],
|
|
)
|
|
)
|
|
start_tensors.append(
|
|
add_1D_constant_layer(
|
|
network, 0, name=[paddle_op.name(), "start_tensor"]
|
|
)
|
|
)
|
|
|
|
new_shape_tensor = trt_concat(
|
|
network, new_shape_tensors, name=[paddle_op.name(), "new_shape_tensor"]
|
|
)
|
|
stride = trt.Dims([1] * rank)
|
|
outputs = []
|
|
output_size = len(paddle_op.results()[0].type().as_vec_type().as_list())
|
|
for i in range(output_size):
|
|
start_tensors[axis] = add_1D_constant_layer(
|
|
network, i, name=[paddle_op.name(), f"start_{i}_tensor"]
|
|
)
|
|
# Create Slice layer
|
|
slice_layer = network.add_slice(
|
|
x,
|
|
stride,
|
|
stride,
|
|
stride,
|
|
)
|
|
slice_layer.set_input(1, trt_concat(network, start_tensors))
|
|
slice_layer.set_input(2, trt_concat(network, size_tensors))
|
|
set_layer_name(slice_layer, paddle_op)
|
|
shuffle_layer = trt_reshape(
|
|
network,
|
|
slice_layer.get_output(0),
|
|
new_shape_tensor,
|
|
is_shape_tensor=True,
|
|
name=[paddle_op.name(), f"shuffle_tensor_{i}"],
|
|
)
|
|
outputs.append(shuffle_layer)
|
|
return outputs
|
|
|
|
|
|
@converter_registry.register("pd_op.nearest_interp")
|
|
def nearest_interp_converter(network, paddle_op, inputs):
|
|
input_tensor = inputs[0]
|
|
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)
|
|
input_rank = input_shape_tensor.shape # The reason is unknown that adding this unused code make input_shape_tensor maintain the correct result.
|
|
data_format = paddle_op.attrs().get("data_format")
|
|
interp_method = paddle_op.attrs().get("interp_method")
|
|
align_corners = paddle_op.attrs().get("align_corners")
|
|
out_h = paddle_op.attrs().get("out_h")
|
|
out_w = paddle_op.attrs().get("out_w")
|
|
out_d = paddle_op.attrs().get("out_d")
|
|
scale_attr = paddle_op.attrs().get("scale")
|
|
|
|
# Parse TensorRT version
|
|
trt_major = get_trt_version_list()[0]
|
|
trt_minor = get_trt_version_list()[1]
|
|
trt_version_float = float(f"{trt_major}.{trt_minor}")
|
|
|
|
# Create Resize layer
|
|
resize_layer = network.add_resize(input_tensor)
|
|
set_layer_name(resize_layer, paddle_op)
|
|
|
|
if trt_version_float >= 8.6:
|
|
if align_corners:
|
|
resize_layer.coordinate_transformation = (
|
|
trt.ResizeCoordinateTransformation.ASYMMETRIC
|
|
)
|
|
else:
|
|
resize_layer.coordinate_transformation = (
|
|
trt.ResizeCoordinateTransformation.ASYMMETRIC
|
|
)
|
|
|
|
in_dim = input_tensor.shape
|
|
scale_h = 1.0
|
|
scale_w = 1.0
|
|
|
|
if scale_attr is not None and len(scale_attr) >= 2:
|
|
scale_h = scale_attr[0]
|
|
scale_w = scale_attr[1]
|
|
else:
|
|
if out_h > 0 and out_w > 0:
|
|
if data_format == "NCHW":
|
|
h_axis = 2
|
|
w_axis = 3
|
|
elif data_format == "NHWC":
|
|
h_axis = 1
|
|
w_axis = 2
|
|
|
|
scale_h = float(out_h) / float(in_dim[h_axis])
|
|
scale_w = float(out_w) / float(in_dim[w_axis])
|
|
|
|
outsize_tensor = None
|
|
if inputs[2] is not None:
|
|
outsize_tensor = network.add_concatenation(inputs[2])
|
|
set_layer_name(outsize_tensor, paddle_op)
|
|
outsize_tensor = outsize_tensor.get_output(0)
|
|
|
|
scales = [1.0] * len(input_tensor.shape)
|
|
if data_format == "NCHW":
|
|
scales[1] = 1.0
|
|
scales[2] = scale_h
|
|
scales[3] = scale_w
|
|
elif data_format == "NHWC":
|
|
scales[1] = scale_h
|
|
scales[2] = scale_w
|
|
scales[3] = 1.0
|
|
else:
|
|
raise ValueError(
|
|
f"Unsupported data format {data_format}, only NCHW or NHWC are supported."
|
|
)
|
|
if outsize_tensor is not None:
|
|
outsize_itensors = []
|
|
batch_dim = get_shape_tensor_element(
|
|
network, input_shape_tensor, 0, name=[paddle_op.name(), "batch_dim"]
|
|
)
|
|
outsize_itensors.append(batch_dim)
|
|
if data_format == "NCHW":
|
|
channel_dim = get_shape_tensor_element(
|
|
network,
|
|
input_shape_tensor,
|
|
1,
|
|
name=[paddle_op.name(), "channel_dim"],
|
|
)
|
|
outsize_itensors.append(channel_dim)
|
|
outsize_itensors.append(outsize_tensor)
|
|
elif data_format == "NHWC":
|
|
channel_dim = get_shape_tensor_element(
|
|
network,
|
|
input_shape_tensor,
|
|
3,
|
|
name=[paddle_op.name(), "channel_dim"],
|
|
)
|
|
outsize_itensors.append(outsize_tensor)
|
|
outsize_itensors.append(channel_dim)
|
|
resize_layer.set_input(
|
|
1, network.add_concatenation(outsize_itensors).get_output(0)
|
|
)
|
|
else:
|
|
resize_layer.scales = scales
|
|
|
|
return resize_layer.get_output(0)
|
|
|
|
|
|
@converter_registry.register("pd_op.linear_interp")
|
|
def linear_interp_converter(network, paddle_op, inputs):
|
|
input_tensor = inputs[0]
|
|
data_layout = paddle_op.attrs().get("data_format")
|
|
interp_method = paddle_op.attrs().get("interp_method")
|
|
align_corners = paddle_op.attrs().get("align_corners")
|
|
out_w = paddle_op.attrs().get("out_w")
|
|
scale_attr = paddle_op.attrs().get("scale")
|
|
layer = network.add_resize(input_tensor)
|
|
set_layer_name(layer, paddle_op)
|
|
trt_major = get_trt_version_list()[0]
|
|
trt_minor = get_trt_version_list()[1]
|
|
trt_version_float = float(f"{trt_major}.{trt_minor}")
|
|
|
|
if trt_version_float >= 8.6:
|
|
layer.resize_mode = trt.InterpolationMode.LINEAR
|
|
else:
|
|
layer.resize_mode = trt.ResizeMode.LINEAR
|
|
|
|
if align_corners:
|
|
layer.coordinate_transformation = (
|
|
trt.ResizeCoordinateTransformation.ALIGN_CORNERS
|
|
)
|
|
else:
|
|
layer.coordinate_transformation = (
|
|
trt.ResizeCoordinateTransformation.HALF_PIXEL
|
|
)
|
|
|
|
in_dim = input_tensor.shape
|
|
scale_w = -1.0
|
|
|
|
if scale_attr and len(scale_attr) > 0:
|
|
scale_w = scale_attr[0]
|
|
|
|
w_axis = 2 if data_layout == "NCHW" else 1
|
|
|
|
if float(scale_w) > 0.0:
|
|
out_w = int(in_dim[w_axis] * scale_w)
|
|
|
|
outsize_tensor = None
|
|
if len(inputs) > 1 and inputs[1] is not None:
|
|
outsize_tensor = inputs[1]
|
|
|
|
if outsize_tensor is None:
|
|
if len(inputs) > 2 and inputs[2] is not None:
|
|
outsize_tensor = inputs[2][0]
|
|
|
|
if out_w > 0 and scale_w <= 0:
|
|
scale_w = float(out_w) / float(in_dim[w_axis])
|
|
|
|
scales = [1.0]
|
|
if data_layout == "NCHW":
|
|
scales.append(1.0)
|
|
scales.append(scale_w)
|
|
elif data_layout == "NHWC":
|
|
scales.append(scale_w)
|
|
scales.append(1.0)
|
|
|
|
if outsize_tensor is not None:
|
|
outsize_itensors = []
|
|
input_shape = trt_shape(
|
|
network, input_tensor, name=[paddle_op.name(), "input_shape"]
|
|
)
|
|
batch_dim = get_shape_tensor_element(
|
|
network, input_shape, 0, name=[paddle_op.name(), "batch_dim"]
|
|
)
|
|
outsize_itensors.append(batch_dim)
|
|
|
|
if data_layout == "NCHW":
|
|
channel_dim = get_shape_tensor_element(
|
|
network, input_shape, 1, name=[paddle_op.name(), "channel_dim"]
|
|
)
|
|
outsize_itensors.append(channel_dim)
|
|
outsize_itensors.append(outsize_tensor)
|
|
elif data_layout == "NHWC":
|
|
outsize_itensors.append(outsize_tensor)
|
|
channel_dim = get_shape_tensor_element(
|
|
network, input_shape, 2, name=[paddle_op.name(), "channel_dim"]
|
|
)
|
|
outsize_itensors.append(channel_dim)
|
|
|
|
layer.set_input(
|
|
1,
|
|
trt_concat(
|
|
network,
|
|
outsize_itensors,
|
|
name=[paddle_op.name(), "outsize_itensors"],
|
|
),
|
|
)
|
|
else:
|
|
layer.scales = scales
|
|
|
|
return layer.get_output(0)
|