3501 lines
119 KiB
C++
3501 lines
119 KiB
C++
// Copyright (c) 2019 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.
|
|
|
|
#include "paddle/fluid/inference/tensorrt/op_teller.h"
|
|
|
|
#include <bitset>
|
|
|
|
#include "paddle/fluid/framework/block_desc.h"
|
|
#include "paddle/fluid/framework/data_layout.h"
|
|
#include "paddle/fluid/framework/phi_utils.h"
|
|
#include "paddle/fluid/inference/tensorrt/dynamic_shape_infermeta_factory.h"
|
|
#include "paddle/phi/api/ext/op_meta_info.h"
|
|
#include "paddle/phi/core/compat/op_utils.h"
|
|
#include "paddle/phi/core/kernel_factory.h"
|
|
|
|
namespace paddle::framework {
|
|
class OpDesc;
|
|
} // namespace paddle::framework
|
|
|
|
namespace paddle::inference::tensorrt {
|
|
|
|
// Check if it is a dynamic shape. If it is a dynamic shape, return true;
|
|
// otherwise, return false
|
|
bool IsDynamicShapeOp(const framework::OpDesc& desc) {
|
|
VLOG(3) << "forbid_dynamic_op_enter_into_trt is open";
|
|
auto* block = desc.Block();
|
|
auto inputs = desc.Inputs();
|
|
for (auto iter : inputs) {
|
|
for (auto var_name : iter.second) {
|
|
if (block) {
|
|
auto* var_desc = block->FindVar(var_name);
|
|
const auto shape = var_desc->GetShape();
|
|
for (auto ele : shape) {
|
|
if (ele < 0) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
auto outputs = desc.Outputs();
|
|
for (auto iter : outputs) {
|
|
for (auto var_name : iter.second) {
|
|
if (block) {
|
|
auto* var_desc = block->FindVar(var_name);
|
|
const auto shape = var_desc->GetShape();
|
|
for (auto ele : shape) {
|
|
if (ele < 0) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Just tell by the op_types.
|
|
struct SimpleOpTypeSetTeller : public Teller {
|
|
SimpleOpTypeSetTeller() { // NOLINT
|
|
// use TensorRT plugin
|
|
teller_set.insert("group_norm");
|
|
teller_set.insert("multiclass_nms3");
|
|
teller_set.insert("multiclass_nms");
|
|
int8_teller_set.insert("multiclass_nms3");
|
|
int8_teller_set.insert("multiclass_nms");
|
|
teller_set.insert("tile");
|
|
int8_teller_set.insert("tile");
|
|
teller_set.insert("flatten_contiguous_range");
|
|
int8_teller_set.insert("flatten_contiguous_range");
|
|
teller_set.insert("rnn");
|
|
int8_teller_set.insert("rnn");
|
|
teller_set.insert("fill_constant_batch_size_like");
|
|
int8_teller_set.insert("fill_constant_batch_size_like");
|
|
teller_set.insert("reshape");
|
|
teller_set.insert("reshape2");
|
|
int8_teller_set.insert("reshape");
|
|
int8_teller_set.insert("reshape2");
|
|
teller_set.insert("sparse_fc");
|
|
int8_teller_set.insert("sparse_fc");
|
|
teller_set.insert("sparse_multihead_matmul");
|
|
int8_teller_set.insert("sparse_multihead_matmul");
|
|
#if IS_TRT_VERSION_GE(8522)
|
|
teller_set.insert("flash_multihead_matmul");
|
|
int8_teller_set.insert("flash_multihead_matmul");
|
|
teller_set.insert("cross_multihead_matmul");
|
|
int8_teller_set.insert("cross_multihead_matmul");
|
|
teller_set.insert("qk_multihead_matmul");
|
|
int8_teller_set.insert("qk_multihead_matmul");
|
|
#endif
|
|
#if IS_TRT_VERSION_GE(8200)
|
|
teller_set.insert("round");
|
|
int8_teller_set.insert("round");
|
|
teller_set.insert("set_value");
|
|
teller_set.insert("index_select");
|
|
int8_teller_set.insert("index_select");
|
|
int8_teller_set.insert("einsum");
|
|
teller_set.insert("einsum");
|
|
#endif
|
|
}
|
|
|
|
bool operator()(const framework::OpDesc& desc,
|
|
bool use_no_calib_int8 = false,
|
|
bool with_dynamic_shape = false,
|
|
bool forbid_dynamic_op_enter_into_trt = false,
|
|
bool use_explicit_quantization = false) override {
|
|
const std::string op_type = desc.Type();
|
|
|
|
std::unordered_set<std::string> control_set = {"conditional_block",
|
|
"while"};
|
|
std::unordered_set<std::string> feed_fetch_set = {"feed", "fetch"};
|
|
if (control_set.find(op_type) != control_set.end()) {
|
|
return false;
|
|
}
|
|
|
|
if (feed_fetch_set.find(op_type) != feed_fetch_set.end()) {
|
|
return false;
|
|
}
|
|
if (forbid_dynamic_op_enter_into_trt && IsDynamicShapeOp(desc)) {
|
|
return false;
|
|
}
|
|
|
|
// do not support the op which is labeled the `skip_quant`
|
|
if ((desc.HasAttr("namescope") &&
|
|
PADDLE_GET_CONST(std::string, desc.GetAttr("op_namescope")) ==
|
|
"/skip_quant_2/") ||
|
|
desc.HasAttr("skip_quant"))
|
|
return false;
|
|
std::unordered_set<std::string> act_op_list = {
|
|
"relu", "relu6", "sigmoid",
|
|
"elu", "selu", "softsign",
|
|
"softplus", "stanh", "thresholded_relu",
|
|
"exp", "log", "sqrt",
|
|
"abs", "sin", "cos",
|
|
"tan", "tanh", "sinh",
|
|
"cosh", "asin", "acos",
|
|
"atan", "asinh", "acosh",
|
|
"atanh", "ceil", "celu",
|
|
"erf", "floor", "round",
|
|
"sign", "silu", "logical_not",
|
|
"reciprocal", "tanh_shrink", "logsigmoid",
|
|
"rsqrt", "swish", "hard_sigmoid",
|
|
"hard_swish", "leaky_relu"};
|
|
std::unordered_set<std::string> unary_list = {
|
|
"exp", "log", "sqrt", "abs", "sin",
|
|
"cos", "tan", "tanh", "sinh", "cosh",
|
|
"asin", "acos", "atan", "asinh", "acosh",
|
|
"atanh", "ceil", "celu", "floor", "round",
|
|
"sign", "logical_not", "reciprocal", "tanh_shrink", "logsigmoid",
|
|
"erf", "bitwise_not", "equal", "not_equal", "rsqrt"};
|
|
|
|
// Static shape does not support 0 or 1 dim's input.
|
|
if (!with_dynamic_shape) {
|
|
auto inputs = desc.Inputs();
|
|
for (auto iter : inputs) {
|
|
for (auto var_name : iter.second) {
|
|
auto* block = desc.Block();
|
|
if (block) {
|
|
auto* var_desc = block->FindVarRecursive(var_name);
|
|
// Can't get feed op's TensorDesc
|
|
if (op_type != "feed" && var_desc && !var_desc->Persistable()) {
|
|
const auto shape = var_desc->GetShape();
|
|
if (shape.size() == 1 || shape.empty()) return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (act_op_list.find(op_type) != act_op_list.end()) {
|
|
auto* block = desc.Block();
|
|
if (block == nullptr) {
|
|
VLOG(3) << "The block desc is nullptr, we can't continue to analyze. "
|
|
"Developers need to check whether block_desc is passed in "
|
|
"the pass.";
|
|
return false;
|
|
}
|
|
auto x_var_name = desc.Input("X")[0];
|
|
auto* x_var_desc = block->FindVarRecursive(x_var_name);
|
|
auto x_dtype = x_var_desc->GetDataType();
|
|
if (x_dtype == framework::proto::VarType::COMPLEX64 ||
|
|
x_dtype == framework::proto::VarType::COMPLEX128) {
|
|
VLOG(3) << op_type
|
|
<< " op does not support COMPLEX64 or COMPLEX128 input";
|
|
return false;
|
|
}
|
|
#if !IS_TRT_VERSION_GE(8600)
|
|
const auto x_shape = x_var_desc->GetShape();
|
|
if (x_shape.empty() && unary_list.find(op_type) != unary_list.end()) {
|
|
VLOG(3) << op_type
|
|
<< " op does not support 0 dim input when TensorRT < 8.6.";
|
|
return false;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (op_type == "dropout") {
|
|
/*
|
|
* Some OpDescs Attribute support both constant value and dynamic
|
|
* runtime value (which is a Variable(s) type). But TensorRT maybe
|
|
* only support constant value Attribute, so we shall distinguish
|
|
* this case in time and return False in OpTeller.Tell().
|
|
* If Attribute is Variable(s), HasAttr() will return False
|
|
*/
|
|
if (!desc.HasAttr("dropout_prob", /*with_attr_var=*/false)) {
|
|
VLOG(3)
|
|
<< "Skip to convert into TRT while found Attribute('dropout_prob') "
|
|
"is Variable type in dropout.";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (op_type == "pool2d") {
|
|
// If Attribute is Variable(s), HasAttr() will return False
|
|
if (!desc.HasAttr("ksize", /*with_attr_var=*/false)) {
|
|
VLOG(3) << "Skip to convert into TRT while found Attribute('ksize') is "
|
|
"Variable type in pool2d.";
|
|
return false;
|
|
}
|
|
|
|
std::vector<int> paddings =
|
|
PADDLE_GET_CONST(std::vector<int>, desc.GetAttr("paddings"));
|
|
if (paddings.size() > 2) {
|
|
return false;
|
|
}
|
|
if (desc.Input("X").size() != 1) {
|
|
VLOG(3) << "TRT Pool2d expect 1 input, but got "
|
|
<< desc.Input("X").size();
|
|
return false;
|
|
}
|
|
if (desc.Output("Out").size() != 1) {
|
|
VLOG(3) << "TRT Pool2d has only 1 output, but got "
|
|
<< desc.Output("Out").size();
|
|
return false;
|
|
}
|
|
if (desc.HasAttr("data_format")) {
|
|
std::string data_format =
|
|
PADDLE_GET_CONST(std::string, desc.GetAttr("data_format"));
|
|
if (data_format == "NHWC" || data_format == "NDHWC") {
|
|
return false;
|
|
}
|
|
}
|
|
if (!desc.HasAttr("pooling_type")) {
|
|
return false;
|
|
} else {
|
|
std::string pool_type =
|
|
PADDLE_GET_CONST(std::string, desc.GetAttr("pooling_type"));
|
|
if (pool_type != "max" && pool_type != "avg") {
|
|
VLOG(3) << "Wrong pool op type, the trt do not support the "
|
|
<< pool_type << " pool type.";
|
|
return false;
|
|
}
|
|
if (pool_type == "avg") {
|
|
if (desc.HasAttr("global_pooling")) {
|
|
if (!PADDLE_GET_CONST(bool, desc.GetAttr("global_pooling"))) {
|
|
if (desc.HasAttr("exclusive")) {
|
|
if (PADDLE_GET_CONST(bool, desc.GetAttr("exclusive"))) {
|
|
std::vector<int> ksize =
|
|
PADDLE_GET_CONST(std::vector<int>, desc.GetAttr("ksize"));
|
|
for (size_t i = 0; i < ksize.size(); i++) {
|
|
if (ksize[i] <= paddings[i]) {
|
|
VLOG(3) << "the padding size should be less than the "
|
|
"filter size "
|
|
"for exclusive-counting pooling.";
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (op_type == "conv2d" || op_type == "conv2d_transpose" ||
|
|
op_type == "fused_conv2d_add_act" || op_type == "depthwise_conv2d" ||
|
|
op_type == "depthwise_conv2d_transpose") {
|
|
if (desc.Input("Input").size() != 1) {
|
|
VLOG(3) << "TRT Conv2d expect 1 input, but got "
|
|
<< desc.Input("Input").size() << " input.";
|
|
return false;
|
|
}
|
|
|
|
if (desc.Input("Filter").size() != 1) {
|
|
VLOG(3) << "TRT Conv2d expect 1 filter, but got "
|
|
<< desc.Input("Filter").size() << " filter.";
|
|
return false;
|
|
}
|
|
|
|
if (desc.HasAttr("enable_int8")) {
|
|
if (op_type == "conv2d" || op_type == "fused_conv2d_add_act") {
|
|
if (!desc.HasAttr("Input_scale")) {
|
|
VLOG(3) << "Input scale not found. TRT int8"
|
|
" requires conv/deconv to have "
|
|
"input quantization scales.";
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (op_type == "conv2d_transpose" ||
|
|
op_type == "depthwise_conv2d_transpose") {
|
|
if (!desc.HasAttr("dilations")) {
|
|
return false;
|
|
} else {
|
|
const std::vector<int> dilations =
|
|
PADDLE_GET_CONST(std::vector<int>, desc.GetAttr("dilations"));
|
|
if (dilations[0] != 1 || dilations[1] != 1) {
|
|
VLOG(3) << "In conv2d_transpose, Dilations must be (1, 1) for "
|
|
"tensorRT, but given ("
|
|
<< dilations[0] << ", " << dilations[1] << ")";
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (desc.Output("Output").size() != 1) {
|
|
VLOG(3) << "TRT Conv2d expect 1 output, but got "
|
|
<< desc.Output("Output").size() << " output.";
|
|
return false;
|
|
}
|
|
|
|
auto* block = desc.Block();
|
|
if (block) {
|
|
auto* filter_var_desc =
|
|
block->FindVarRecursive(desc.Input("Filter")[0]);
|
|
if (!filter_var_desc->Persistable()) {
|
|
#if IS_TRT_VERSION_GE(8600)
|
|
#else
|
|
LOG(INFO)
|
|
<< "Trt below 8.6 not support conv2d's filter is a intermediate "
|
|
"tensor in conv2d op, please upgrade your TensorRT.";
|
|
return false;
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
if (op_type == "deformable_conv") {
|
|
if (!desc.HasAttr("groups") || !desc.HasAttr("strides") ||
|
|
!desc.HasAttr("paddings"))
|
|
return false;
|
|
auto* block = desc.Block();
|
|
auto input_name = desc.Input("Input")[0];
|
|
auto* input_desc = block->FindVarRecursive(input_name);
|
|
const auto input_shape = input_desc->GetShape();
|
|
|
|
if (input_shape.size() != 4) {
|
|
VLOG(3) << "Input of deformable conv should be 4-D Tensor, but got "
|
|
<< input_shape.size();
|
|
return false;
|
|
}
|
|
|
|
auto filter_name = desc.Input("Filter")[0];
|
|
auto* filter_desc = block->FindVarRecursive(filter_name);
|
|
const auto filter_shape = filter_desc->GetShape();
|
|
|
|
int groups = PADDLE_GET_CONST(int, desc.GetAttr("groups"));
|
|
if (input_shape[1] != filter_shape[1] * groups) {
|
|
VLOG(3) << "The number of input channels should be equal to filter "
|
|
<< "channels * groups. But got input channels "
|
|
<< input_shape[1] << "filter channels " << filter_shape[1];
|
|
return false;
|
|
}
|
|
|
|
const std::vector<int> strides =
|
|
PADDLE_GET_CONST(std::vector<int>, desc.GetAttr("strides"));
|
|
if (strides.size() != 2) {
|
|
VLOG(3) << "The size of strides should be 2, but got "
|
|
<< strides.size();
|
|
return false;
|
|
}
|
|
|
|
const std::vector<int> paddings =
|
|
PADDLE_GET_CONST(std::vector<int>, desc.GetAttr("paddings"));
|
|
if (paddings.size() != 2) {
|
|
VLOG(3) << "The size of paddings should be 2, but got "
|
|
<< paddings.size();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (op_type == "bmm") {
|
|
if (!with_dynamic_shape) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (op_type == "range") {
|
|
if (!with_dynamic_shape) {
|
|
return false;
|
|
}
|
|
#if IS_TRT_VERSION_LT(8400)
|
|
auto* block = desc.Block();
|
|
auto start_var_name = desc.Input("Start")[0];
|
|
auto* start_var_desc = block->FindVarRecursive(start_var_name);
|
|
auto start_dtype = start_var_desc->GetDataType();
|
|
if (start_dtype == framework::proto::VarType::FP32 ||
|
|
start_dtype == framework::proto::VarType::FP64) {
|
|
return false;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (op_type == "sign") {
|
|
#if IS_TRT_VERSION_GE(8200)
|
|
if (!with_dynamic_shape) {
|
|
return false;
|
|
}
|
|
#else
|
|
VLOG(3) << "sign op is only supported by trt8.2 above ";
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
if (op_type == "logical_not") {
|
|
#if IS_TRT_VERSION_GE(8400)
|
|
if (!with_dynamic_shape) {
|
|
return false;
|
|
}
|
|
#else
|
|
VLOG(3) << "logical_not op is only supported by trt8.4 above because of "
|
|
"cast op";
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
if (op_type == "softmax") {
|
|
auto* block = desc.Block();
|
|
if (block == nullptr) {
|
|
VLOG(3) << "The block desc is nullptr, we can't continue to analyze. "
|
|
"Developers need to check whether block_desc is passed in "
|
|
"the pass.";
|
|
return false;
|
|
}
|
|
auto x_var_name = desc.Input("X")[0];
|
|
auto* x_var_desc = block->FindVarRecursive(x_var_name);
|
|
const auto x_shape = x_var_desc->GetShape();
|
|
|
|
if (with_dynamic_shape && (x_shape.size() == 1 || x_shape.empty())) {
|
|
int axis = desc.HasAttr("axis")
|
|
? PADDLE_GET_CONST(int, desc.GetAttr("axis"))
|
|
: -1;
|
|
if (axis > 0) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (op_type == "group_norm") {
|
|
if (!desc.HasAttr("epsilon") || !desc.HasAttr("groups") ||
|
|
!desc.HasAttr("data_layout"))
|
|
return false;
|
|
|
|
auto registry = GetPluginRegistry();
|
|
if (registry == nullptr) return false;
|
|
std::string layout_str =
|
|
PADDLE_GET_CONST(std::string, desc.GetAttr("data_layout"));
|
|
if (layout_str != "NCHW") {
|
|
VLOG(3) << "Group norm trt plugin only support NCHW layout, but got "
|
|
<< layout_str;
|
|
return false;
|
|
}
|
|
}
|
|
if (op_type == "concat") {
|
|
if (!desc.HasAttr("axis")) {
|
|
return false;
|
|
}
|
|
int axis = PADDLE_GET_CONST(int, desc.GetAttr("axis"));
|
|
if (!with_dynamic_shape) {
|
|
if (axis == 0) return false;
|
|
}
|
|
auto concat_inputs = desc.Inputs();
|
|
if (concat_inputs.find("AxisTensor") != concat_inputs.end()) {
|
|
if (!desc.Input("AxisTensor").empty()) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
if (op_type == "transpose2" || op_type == "transpose") {
|
|
if (!desc.HasAttr("axis")) {
|
|
return false;
|
|
}
|
|
std::vector<int> axis =
|
|
PADDLE_GET_CONST(std::vector<int>, desc.GetAttr("axis"));
|
|
if (!with_dynamic_shape && axis[0] != 0) return false;
|
|
if (axis.size() >= nvinfer1::Dims::MAX_DIMS) return false;
|
|
|
|
auto* block = desc.Block();
|
|
if (block == nullptr) {
|
|
VLOG(3) << "The block desc is nullptr, we can't continue to analyze. "
|
|
"Developers need to check whether block_desc is passed in "
|
|
"the pass.";
|
|
return false;
|
|
}
|
|
auto x_var_name = desc.Input("X")[0];
|
|
auto* x_var_desc = block->FindVarRecursive(x_var_name);
|
|
const auto x_shape = x_var_desc->GetShape();
|
|
if (axis.size() != x_shape.size()) return false;
|
|
int dims = x_shape.size();
|
|
|
|
std::vector<int> perm(nvinfer1::Dims::MAX_DIMS);
|
|
for (int i = 0; i < dims; i++) {
|
|
perm[i] = axis[i];
|
|
}
|
|
auto is_valid_permutation = [&](int dims,
|
|
const std::vector<int>& permutation) {
|
|
std::bitset<nvinfer1::Dims::MAX_DIMS> found;
|
|
for (int i = 0; i < dims; ++i) {
|
|
const int x = permutation[i];
|
|
if ((x < 0) || (x >= dims) || found[x])
|
|
return false; // Out of bounds or duplicate
|
|
found.set(x);
|
|
}
|
|
return true;
|
|
};
|
|
if (!is_valid_permutation(dims, perm)) {
|
|
VLOG(3) << "Invalid permutation dimensions for trt transpose op "
|
|
"converter: duplicate or out of bound.";
|
|
return false;
|
|
}
|
|
}
|
|
if (op_type == "flatten2" || op_type == "flatten") {
|
|
if (!desc.HasAttr("axis")) {
|
|
return false;
|
|
} else {
|
|
int axis = PADDLE_GET_CONST(int, desc.GetAttr("axis"));
|
|
if (axis != 1) return false;
|
|
}
|
|
}
|
|
if (op_type == "flatten_contiguous_range") {
|
|
if (!with_dynamic_shape) {
|
|
if (!desc.HasAttr("start_axis") || !desc.HasAttr("stop_axis")) {
|
|
return false;
|
|
}
|
|
int start_axis = PADDLE_GET_CONST(int, desc.GetAttr("start_axis"));
|
|
int stop_axis = PADDLE_GET_CONST(int, desc.GetAttr("stop_axis"));
|
|
auto x_var_name = desc.Input("X")[0];
|
|
auto* block = desc.Block();
|
|
if (block == nullptr) {
|
|
VLOG(3) << "The block desc is nullptr, we can't continue to analyze. "
|
|
"Developers need to check whether block_desc is passed in "
|
|
"the pass.";
|
|
return false;
|
|
}
|
|
auto* x_var_desc = block->FindVarRecursive(x_var_name);
|
|
const auto x_shape = x_var_desc->GetShape();
|
|
int dims = x_shape.size();
|
|
if (dims == 0) {
|
|
VLOG(3) << op_type
|
|
<< " op does not support input's dim is 0 in tensorrt "
|
|
"static shape mode.";
|
|
return false;
|
|
}
|
|
if (start_axis < 0) start_axis += dims;
|
|
if (start_axis == 0) {
|
|
VLOG(3) << "TRT flatten_contiguous_range not support the "
|
|
"batch-dimension being changed";
|
|
return false;
|
|
}
|
|
if (stop_axis < 0) stop_axis += dims;
|
|
for (int i = start_axis; i <= stop_axis; ++i) {
|
|
if (x_shape[i] < 0) {
|
|
VLOG(3) << "On TRT static shape,flatten_contiguous_range input dim "
|
|
"should be > 0";
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (op_type == "gather") {
|
|
auto gather_inputs = desc.Inputs();
|
|
if (gather_inputs.find("Axis") != gather_inputs.end()) {
|
|
if (!desc.Input("Axis").empty()) {
|
|
return false;
|
|
}
|
|
}
|
|
if (!with_dynamic_shape) {
|
|
return false;
|
|
} else {
|
|
auto* block = desc.Block();
|
|
if (block == nullptr) {
|
|
VLOG(3) << "The block desc is nullptr, we can't continue to analyze. "
|
|
"Developers need to check whether block_desc is passed in "
|
|
"the pass.";
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (op_type == "gather_nd") {
|
|
if (!with_dynamic_shape) return false;
|
|
|
|
auto* block = desc.Block();
|
|
if (block == nullptr) {
|
|
VLOG(3) << "The block desc is nullptr, we can't continue to analyze. "
|
|
"Developers need to check whether block_desc is passed in "
|
|
"the pass.";
|
|
return false;
|
|
}
|
|
#if IS_TRT_VERSION_LT(8200)
|
|
auto index_var_name = desc.Input("Index")[0];
|
|
auto* index_var_desc = block->FindVarRecursive(index_var_name);
|
|
auto x_var_name = desc.Input("X")[0];
|
|
auto* x_var_desc = block->FindVarRecursive(x_var_name);
|
|
const auto index_shape = index_var_desc->GetShape();
|
|
const auto x_shape = x_var_desc->GetShape();
|
|
if (x_shape.size() <= 2) {
|
|
VLOG(3) << "gather_nd op requires the input's dimension to be greater "
|
|
"than 2";
|
|
return false;
|
|
}
|
|
|
|
if (x_shape.size() != index_shape.size()) {
|
|
VLOG(3) << "gather_nd op Index input dims size [" << index_shape.size()
|
|
<< " ] not equal to x dims size [" << x_shape.size() << "]";
|
|
return false;
|
|
}
|
|
#endif
|
|
}
|
|
if (op_type == "index_select") {
|
|
#if !IS_TRT_VERSION_GE(8200)
|
|
return false;
|
|
#endif
|
|
auto gather_inputs = desc.Inputs();
|
|
if (!with_dynamic_shape) {
|
|
return false;
|
|
} else {
|
|
auto* block = desc.Block();
|
|
if (block == nullptr) {
|
|
VLOG(3) << "The block desc is nullptr, we can't continue to analyze. "
|
|
"Developers need to check whether block_desc is passed in "
|
|
"the pass.";
|
|
return false;
|
|
}
|
|
|
|
auto index_var_name = desc.Input("Index")[0];
|
|
auto* index_var_desc = block->FindVarRecursive(index_var_name);
|
|
|
|
// The index input must be int32 or int64 datatype.
|
|
if (index_var_desc->GetDataType() !=
|
|
paddle::framework::proto::VarType_Type::VarType_Type_INT32 &&
|
|
index_var_desc->GetDataType() !=
|
|
paddle::framework::proto::VarType_Type::VarType_Type_INT64) {
|
|
VLOG(3)
|
|
<< "Index select op Index input data type must be int32 or int64";
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
if (op_type == "take_along_axis") {
|
|
#if IS_TRT_VERSION_GE(8200)
|
|
if (!with_dynamic_shape) return false;
|
|
auto* block = desc.Block();
|
|
auto input_var_name = desc.Input("Input")[0];
|
|
auto index_var_name = desc.Input("Index")[0];
|
|
auto* input_var_desc = block->FindVarRecursive(input_var_name);
|
|
auto* index_var_desc = block->FindVarRecursive(index_var_name);
|
|
|
|
const auto input_shape = input_var_desc->GetShape();
|
|
const auto index_shape = index_var_desc->GetShape();
|
|
if (input_shape.size() != index_shape.size()) {
|
|
VLOG(3) << "take_along_axis op Index input dims size ["
|
|
<< index_shape.size() << " ] not equal to input dims size ["
|
|
<< input_shape.size() << "]";
|
|
return false;
|
|
}
|
|
#else
|
|
VLOG(3) << "take_along_axis op is only supported by trt8.2 above ";
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
if (op_type == "anchor_generator") {
|
|
if (!with_dynamic_shape) return false;
|
|
}
|
|
|
|
if (op_type == "yolo_box") {
|
|
return false;
|
|
}
|
|
|
|
if (op_type == "yolo_box_head") {
|
|
return false;
|
|
}
|
|
|
|
if (op_type == "arg_max" || op_type == "arg_min") {
|
|
if (!desc.HasAttr("axis", /*with_attr_var=*/false)) {
|
|
VLOG(3) << "Skip to convert into TRT while found Attribute('axis') is "
|
|
"Variable type in arg_max.";
|
|
return false;
|
|
}
|
|
|
|
auto* block = desc.Block();
|
|
if (block == nullptr) {
|
|
VLOG(3) << "The block desc is nullptr, we can't continue to analyze. "
|
|
"Developers need to check whether block_desc is passed in "
|
|
"the pass.";
|
|
return false;
|
|
}
|
|
auto x_var_name = desc.Input("X")[0];
|
|
auto* x_var_desc = block->FindVarRecursive(x_var_name);
|
|
auto x_dtype = x_var_desc->GetDataType();
|
|
|
|
if (!(x_dtype == framework::proto::VarType::FP32 ||
|
|
x_dtype == framework::proto::VarType::FP16 ||
|
|
x_dtype == framework::proto::VarType::FP64)) {
|
|
return false;
|
|
}
|
|
|
|
int axis = desc.HasAttr("axis")
|
|
? PADDLE_GET_CONST(int64_t, desc.GetAttr("axis"))
|
|
: -1;
|
|
bool flatten = desc.HasAttr("flatten")
|
|
? PADDLE_GET_CONST(bool, desc.GetAttr("flatten"))
|
|
: false;
|
|
int dtype = desc.HasAttr("dtype")
|
|
? PADDLE_GET_CONST(int, desc.GetAttr("dtype"))
|
|
: 3;
|
|
if (axis == 0 || flatten || (dtype != 2 && dtype != 3)) return false;
|
|
}
|
|
|
|
if (op_type == "affine_channel") {
|
|
if (!desc.HasAttr("data_layout")) return false;
|
|
auto data_layout = common::StringToDataLayout(
|
|
PADDLE_GET_CONST(std::string, desc.GetAttr("data_layout")));
|
|
if (data_layout != phi::DataLayout::NCHW) return false;
|
|
|
|
auto* block = desc.Block();
|
|
if (block == nullptr) {
|
|
VLOG(3) << "The block desc is nullptr, we can't continue to analyze. "
|
|
"Developers need to check whether block_desc is passed in "
|
|
"the pass.";
|
|
return false;
|
|
}
|
|
auto x_var_name = desc.Input("X")[0];
|
|
auto* x_var_desc = block->FindVarRecursive(x_var_name);
|
|
const auto x_shape = x_var_desc->GetShape();
|
|
if (x_shape.size() == 2) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (op_type == "multiclass_nms" || op_type == "multiclass_nms3") {
|
|
auto* block = desc.Block();
|
|
if (block == nullptr) {
|
|
VLOG(3) << "The block desc is nullptr, we can't continue to analyze. "
|
|
"Developers need to check whether block_desc is passed in "
|
|
"the pass.";
|
|
return false;
|
|
}
|
|
auto multiclass_nms_inputs = desc.Inputs();
|
|
if (multiclass_nms_inputs.find("RoisNum") !=
|
|
multiclass_nms_inputs.end()) {
|
|
if (!desc.Input("RoisNum").empty()) {
|
|
return false;
|
|
}
|
|
}
|
|
for (auto& param_name : multiclass_nms_inputs) {
|
|
for (auto& var_name : param_name.second) {
|
|
auto* var_desc = block->FindVarRecursive(var_name);
|
|
const auto shape = var_desc->GetShape();
|
|
if (shape.size() != 3) {
|
|
VLOG(3) << "multiclass_nms op dims != 3 not supported in tensorrt, "
|
|
"but got dims "
|
|
<< shape.size() << ", so jump it.";
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
bool has_attrs =
|
|
(desc.HasAttr("background_label") &&
|
|
desc.HasAttr("score_threshold") && desc.HasAttr("nms_top_k") &&
|
|
desc.HasAttr("keep_top_k") && desc.HasAttr("normalized"));
|
|
if (has_attrs == false) return false;
|
|
|
|
// TODO(wangxinxin08): tricky solution because the outputs of batchedNMS
|
|
// plugin are not constient with those of multiclass_nms3
|
|
if (desc.HasAttr("nms_eta") == false) return false;
|
|
auto nms_eta = PADDLE_GET_CONST(float, desc.GetAttr("nms_eta"));
|
|
if (nms_eta <= 1.0) return false;
|
|
|
|
auto nms_top_k = PADDLE_GET_CONST(int, desc.GetAttr("nms_top_k"));
|
|
if (nms_top_k < 0) return false;
|
|
|
|
auto keep_top_k = PADDLE_GET_CONST(int, desc.GetAttr("keep_top_k"));
|
|
if (keep_top_k < 0) return false;
|
|
|
|
auto registry = GetPluginRegistry();
|
|
if (registry == nullptr) return false;
|
|
}
|
|
|
|
if (op_type == "nearest_interp") {
|
|
std::vector<std::string> attrs{
|
|
"interp_method", "align_corners", "scale", "out_h", "out_w"};
|
|
for (auto const& attr : attrs) {
|
|
if (!desc.HasAttr(attr)) return false;
|
|
}
|
|
if (desc.HasAttr("data_layout")) {
|
|
auto data_layout = common::StringToDataLayout(
|
|
PADDLE_GET_CONST(std::string, desc.GetAttr("data_layout")));
|
|
if (data_layout != phi::DataLayout::NCHW &&
|
|
data_layout != phi::DataLayout::NHWC)
|
|
return false;
|
|
}
|
|
auto interp_method =
|
|
PADDLE_GET_CONST(std::string, desc.GetAttr("interp_method"));
|
|
if (interp_method != "nearest") return false;
|
|
auto scale = PADDLE_GET_CONST(float, desc.GetAttr("scale"));
|
|
auto out_h = PADDLE_GET_CONST(int, desc.GetAttr("out_h"));
|
|
auto out_w = PADDLE_GET_CONST(int, desc.GetAttr("out_w"));
|
|
auto align_corners =
|
|
PADDLE_GET_CONST(bool, desc.GetAttr("align_corners"));
|
|
if (!(scale > 0.f && (out_h <= 0 && out_w <= 0))) {
|
|
if (out_h <= 0) {
|
|
VLOG(3) << "out_h must be greater than 0 if scale is not set.";
|
|
return false;
|
|
}
|
|
if (out_w <= 0) {
|
|
VLOG(3) << "out_w must be greater than 0 if scale is not set.";
|
|
return false;
|
|
}
|
|
}
|
|
if ((scale <= 0.f) && with_dynamic_shape) {
|
|
VLOG(3) << "dynamic shape not support scale not set.";
|
|
return false;
|
|
}
|
|
// When align_corners = true, the paddle's and trt_layer's results has
|
|
// diff
|
|
if (align_corners && scale != 1) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (op_type == "nearest_interp_v2") {
|
|
std::vector<std::string> attrs{"data_layout",
|
|
"interp_method",
|
|
"align_corners",
|
|
"scale",
|
|
"out_h",
|
|
"out_w"};
|
|
for (auto const& attr : attrs) {
|
|
if (!desc.HasAttr(attr)) return false;
|
|
}
|
|
auto data_layout = common::StringToDataLayout(
|
|
PADDLE_GET_CONST(std::string, desc.GetAttr("data_layout")));
|
|
if (data_layout != phi::DataLayout::NCHW &&
|
|
data_layout != phi::DataLayout::NHWC)
|
|
return false;
|
|
auto interp_method =
|
|
PADDLE_GET_CONST(std::string, desc.GetAttr("interp_method"));
|
|
if (interp_method != "nearest") return false;
|
|
|
|
#if IS_TRT_VERSION_GE(8200)
|
|
auto resize_inputs = desc.Inputs();
|
|
if (with_dynamic_shape &&
|
|
resize_inputs.find("SizeTensor") != resize_inputs.end() &&
|
|
desc.Input("SizeTensor").size() == 2) {
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
auto scale = PADDLE_GET_CONST(std::vector<float>, desc.GetAttr("scale"));
|
|
auto out_h = PADDLE_GET_CONST(int, desc.GetAttr("out_h"));
|
|
auto out_w = PADDLE_GET_CONST(int, desc.GetAttr("out_w"));
|
|
if (!(out_h > 0 && out_w > 0)) {
|
|
if (scale.size() < 2) return false;
|
|
if (scale[0] <= 0.f || scale[1] <= 0.f) {
|
|
VLOG(3) << "scale factor must be greater than 0 if out_h or out_w is "
|
|
"not set.";
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (op_type == "bilinear_interp_v2") {
|
|
std::vector<std::string> attrs{"data_layout",
|
|
"interp_method",
|
|
"align_corners",
|
|
"scale",
|
|
"out_h",
|
|
"out_w"};
|
|
for (auto const& attr : attrs) {
|
|
if (!desc.HasAttr(attr)) {
|
|
VLOG(3) << "The op_type " << op_type << " doesn't have the attr "
|
|
<< attr << " and return false";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
auto resize_inputs = desc.Inputs();
|
|
if (resize_inputs.find("SizeTensor") != resize_inputs.end()) {
|
|
#if IS_TRT_VERSION_GE(8200)
|
|
if (desc.Input("SizeTensor").size() == 2) {
|
|
// TODO(lizexu123): When SizeTensor exists, at least one of the input
|
|
// variable names must contain 'shape' in order for TRT conversion to
|
|
// proceed; otherwise, TRT conversion will be disallowed."
|
|
auto* block = desc.Block();
|
|
if (block == nullptr) {
|
|
VLOG(3)
|
|
<< "The block desc is nullptr,we can't continue to analyze.";
|
|
return false;
|
|
}
|
|
bool valid_source = false;
|
|
//
|
|
std::vector<std::string> size_tensor_names = desc.Input("SizeTensor");
|
|
for (const auto& tensor_name : size_tensor_names) {
|
|
auto* var_desc = block->FindVarRecursive(tensor_name);
|
|
if (!var_desc) continue;
|
|
if (tensor_name.find("shape") != std::string::npos) {
|
|
valid_source = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!valid_source) {
|
|
VLOG(3) << "The SizeTensor for bilinear_interp_v2 doesn't come "
|
|
"from a valid source.";
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
#else
|
|
if (!desc.Input("SizeTensor").empty()) {
|
|
VLOG(3)
|
|
<< "The Paddle-TRT doesn't support the SizeTensor for op_type "
|
|
<< op_type;
|
|
return false;
|
|
}
|
|
#endif
|
|
}
|
|
if (resize_inputs.find("OutSize") != resize_inputs.end()) {
|
|
if (!with_dynamic_shape) {
|
|
VLOG(3) << "Static shape don't support the OutSize for op_type "
|
|
<< op_type;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
auto data_layout = common::StringToDataLayout(
|
|
PADDLE_GET_CONST(std::string, desc.GetAttr("data_layout")));
|
|
if (data_layout != phi::DataLayout::NCHW &&
|
|
data_layout != phi::DataLayout::NHWC) {
|
|
VLOG(3) << "The op_type " << op_type
|
|
<< " is not NCHW or NHWC return false";
|
|
return false;
|
|
}
|
|
auto interp_method =
|
|
PADDLE_GET_CONST(std::string, desc.GetAttr("interp_method"));
|
|
if (interp_method != "bilinear") {
|
|
VLOG(3) << "The interp_method of op_type " << op_type
|
|
<< " is not bilinear";
|
|
return false;
|
|
}
|
|
|
|
bool has_scale_input_size =
|
|
(resize_inputs.find("Scale") != resize_inputs.end());
|
|
|
|
if (!has_scale_input_size ||
|
|
(has_scale_input_size && desc.Input("Scale").size() != 1)) {
|
|
const std::vector<float> scale =
|
|
PADDLE_GET_CONST(std::vector<float>, desc.GetAttr("scale"));
|
|
if (scale.size() <= 1) {
|
|
if (!desc.HasAttr("out_h") || !desc.HasAttr("out_w")) {
|
|
VLOG(3) << "The op_type " << op_type
|
|
<< " doesn't have Scale and the scale size <=1 and without "
|
|
"out_h / out_w, it will return false";
|
|
return false;
|
|
}
|
|
auto out_h = PADDLE_GET_CONST(int, desc.GetAttr("out_h"));
|
|
auto out_w = PADDLE_GET_CONST(int, desc.GetAttr("out_w"));
|
|
if (!(out_h <= 0 && out_w <= 0)) {
|
|
if (out_h <= 0) {
|
|
VLOG(3) << "The op_type " << op_type
|
|
<< "'s out_h must be greater than 0 if scale is not set.";
|
|
return false;
|
|
}
|
|
if (out_w <= 0) {
|
|
VLOG(3) << "The op_type " << op_type
|
|
<< "'s out_w must be greater than 0 if scale is not set.";
|
|
return false;
|
|
}
|
|
}
|
|
} else {
|
|
for (size_t i = 0; i < scale.size(); i++) {
|
|
if (scale[i] <= 0 && with_dynamic_shape) {
|
|
VLOG(3) << "dynamic shape not support Attr(scale[" << i << "]) "
|
|
<< scale[i]
|
|
<< " less than 1 and Input(Scale) vector not set.";
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (op_type == "linear_interp_v2") {
|
|
std::vector<std::string> attrs{"data_layout",
|
|
"interp_method",
|
|
"align_corners",
|
|
"scale",
|
|
"out_h",
|
|
"out_w"};
|
|
for (auto const& attr : attrs) {
|
|
if (!desc.HasAttr(attr)) {
|
|
VLOG(3) << "The op_type " << op_type << " doesn't have the attr "
|
|
<< attr << " and return false";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
auto resize_inputs = desc.Inputs();
|
|
if (resize_inputs.find("SizeTensor") != resize_inputs.end()) {
|
|
#if IS_TRT_VERSION_GE(8200)
|
|
if (desc.Input("SizeTensor").size() == 1) {
|
|
return true;
|
|
}
|
|
#else
|
|
if (!desc.Input("SizeTensor").empty()) {
|
|
VLOG(3)
|
|
<< "The Paddle-TRT doesn't support the SizeTensor for op_type "
|
|
<< op_type;
|
|
return false;
|
|
}
|
|
#endif
|
|
}
|
|
if (resize_inputs.find("OutSize") != resize_inputs.end()) {
|
|
if (!with_dynamic_shape) {
|
|
VLOG(3) << "Static shape don't support the OutSize for op_type "
|
|
<< op_type;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
auto data_layout = common::StringToDataLayout(
|
|
PADDLE_GET_CONST(std::string, desc.GetAttr("data_layout")));
|
|
if (data_layout != phi::DataLayout::NCHW &&
|
|
data_layout != phi::DataLayout::NHWC) {
|
|
VLOG(3) << "The op_type " << op_type
|
|
<< " is not NCHW or NHWC return false";
|
|
return false;
|
|
}
|
|
auto interp_method =
|
|
PADDLE_GET_CONST(std::string, desc.GetAttr("interp_method"));
|
|
if (interp_method != "linear") {
|
|
VLOG(3) << "The interp_method of op_type " << op_type
|
|
<< " is not linear";
|
|
return false;
|
|
}
|
|
bool has_scale_input_size =
|
|
(resize_inputs.find("Scale") != resize_inputs.end());
|
|
if (!has_scale_input_size ||
|
|
(has_scale_input_size && desc.Input("Scale").size() != 1)) {
|
|
const std::vector<float> scale =
|
|
PADDLE_GET_CONST(std::vector<float>, desc.GetAttr("scale"));
|
|
if (scale.size() == 0) {
|
|
if (!desc.HasAttr("out_w")) {
|
|
VLOG(3) << "The op_type " << op_type
|
|
<< " doesn't have Scale and the scale size <=1 and without "
|
|
" out_w, it will return false";
|
|
return false;
|
|
}
|
|
auto out_w = PADDLE_GET_CONST(int, desc.GetAttr("out_w"));
|
|
if (out_w <= 0) {
|
|
VLOG(3) << "The op_type " << op_type
|
|
<< "'s out_w must be greater than 0 if scale is not set.";
|
|
return false;
|
|
}
|
|
} else {
|
|
for (size_t i = 0; i < scale.size(); i++) {
|
|
if (scale[i] <= 0 && with_dynamic_shape) {
|
|
VLOG(3) << "dynamic shape not support Attr(scale[" << i << "]) "
|
|
<< scale[i]
|
|
<< " less than 1 and Input(Scale) vector not set.";
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (op_type == "unsqueeze2") {
|
|
std::vector<int> axes;
|
|
if (desc.HasAttr("axes")) {
|
|
axes = PADDLE_GET_CONST(std::vector<int>, desc.GetAttr("axes"));
|
|
}
|
|
if (axes.empty()) {
|
|
VLOG(3) << "The necessary attributes of the squeeze2 operator axes is "
|
|
"missing.";
|
|
return false;
|
|
}
|
|
if (!with_dynamic_shape) {
|
|
if (std::find(axes.begin(), axes.end(), 0) != axes.end()) {
|
|
VLOG(3) << "Invalid squeeze axes. Axes having batch axis is not "
|
|
"supported in static shape";
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (op_type == "batch_norm") {
|
|
const std::vector<std::string> bn_inputs = {
|
|
"X", "Bias", "Mean", "Scale", "Variance"};
|
|
for (unsigned int i = 0; i < bn_inputs.size(); i++) {
|
|
if (desc.Input(bn_inputs[i]).size() != 1) {
|
|
VLOG(3) << "Invalid " << bn_inputs[i]
|
|
<< "'s size of batch_norm TRT "
|
|
"converter. Expected 1, received "
|
|
<< desc.Input(bn_inputs[i]).size() << ".";
|
|
return false;
|
|
}
|
|
}
|
|
auto batch_norm_inputs = desc.Inputs();
|
|
if (batch_norm_inputs.find("MomentumTensor") != batch_norm_inputs.end()) {
|
|
if (!desc.Input("MomentumTensor").empty()) {
|
|
return false;
|
|
}
|
|
}
|
|
if (desc.Output("Y").size() != 1) {
|
|
VLOG(3) << "Invalid output Y's size of batch_norm TRT "
|
|
"converter. Expected 1, received "
|
|
<< desc.Output("Y").size() << ".";
|
|
return false;
|
|
}
|
|
auto* block = desc.Block();
|
|
if (block == nullptr) {
|
|
VLOG(3) << "The block desc is nullptr, we can't continue to analyze. "
|
|
"Developers need to check whether block_desc is passed in "
|
|
"the pass.";
|
|
return false;
|
|
}
|
|
auto x_var_name = desc.Input("X")[0];
|
|
auto* x_var_desc = block->FindVarRecursive(x_var_name);
|
|
const auto x_shape = x_var_desc->GetShape();
|
|
}
|
|
|
|
if (op_type == "split") {
|
|
if (desc.Input("X").size() != 1) {
|
|
VLOG(3) << "Invalid input X's size of split TRT converter. "
|
|
"Expected 1, received "
|
|
<< desc.Input("X").size() << ".";
|
|
return false;
|
|
}
|
|
auto split_inputs = desc.Inputs();
|
|
if (split_inputs.find("AxisTensor") != split_inputs.end()) {
|
|
if (!desc.Input("AxisTensor").empty()) {
|
|
return false;
|
|
}
|
|
}
|
|
if (split_inputs.find("SectionsTensorList") != split_inputs.end()) {
|
|
if (!desc.Input("SectionsTensorList").empty()) {
|
|
if (!with_dynamic_shape) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
if (!desc.HasAttr("axis")) {
|
|
return false;
|
|
}
|
|
int axis = PADDLE_GET_CONST(int, desc.GetAttr("axis"));
|
|
|
|
if (!with_dynamic_shape && axis == 0) {
|
|
VLOG(3) << "Invalid split axis. Split on batch is not supported in "
|
|
"TensorRT with static shape";
|
|
return false;
|
|
}
|
|
auto* block = desc.Block();
|
|
if (block == nullptr) {
|
|
VLOG(3) << "The block desc is nullptr, we can't continue to analyze. "
|
|
"Developers need to check whether block_desc is passed in "
|
|
"the pass.";
|
|
return false;
|
|
}
|
|
auto x_var_name = desc.Input("X")[0];
|
|
auto* x_var_desc = block->FindVarRecursive(x_var_name);
|
|
const auto x_shape = x_var_desc->GetShape();
|
|
size_t output_num = desc.Output("Out").size();
|
|
std::vector<int> output_lengths;
|
|
int num = 0;
|
|
if (desc.HasAttr("num")) {
|
|
num = PADDLE_GET_CONST(int, desc.GetAttr("num"));
|
|
}
|
|
if (desc.HasAttr("sections")) {
|
|
output_lengths =
|
|
PADDLE_GET_CONST(std::vector<int>, desc.GetAttr("sections"));
|
|
}
|
|
if (output_lengths.empty() && num == 0) {
|
|
VLOG(3) << "sections and num cannot be equal to 0 at the same time";
|
|
return false;
|
|
}
|
|
axis += (axis < 0) ? x_shape.size() : 0;
|
|
if (x_shape[axis] == -1) {
|
|
VLOG(3) << "The (" << axis << ") dim of input should not be -1";
|
|
return false;
|
|
}
|
|
if (output_lengths.empty()) {
|
|
if (num > 0) {
|
|
int64_t in_axis_dim = x_shape[axis];
|
|
if (in_axis_dim % num != 0) {
|
|
VLOG(3) << "Invalid number to split. Tensor split does not result"
|
|
" in an equal division of dimensions. Axis dim = "
|
|
<< in_axis_dim << " num = " << num << "!= 0";
|
|
return false;
|
|
}
|
|
size_t out_axis_dim = in_axis_dim / num;
|
|
for (int i = 0; i < num; ++i) {
|
|
output_lengths.push_back(out_axis_dim);
|
|
}
|
|
}
|
|
}
|
|
if (output_lengths.size() != output_num) {
|
|
VLOG(3) << "The output_length should be equal to the output size.";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (op_type == "scale") {
|
|
auto scale_inputs = desc.Inputs();
|
|
if (scale_inputs.find("ScaleTensor") != scale_inputs.end()) {
|
|
if (!desc.Input("ScaleTensor").empty()) {
|
|
return false;
|
|
}
|
|
}
|
|
auto* block = desc.Block();
|
|
if (block == nullptr) {
|
|
VLOG(3) << "The block desc is nullptr, we can't continue to analyze. "
|
|
"Developers need to check whether block_desc is passed in "
|
|
"the pass.";
|
|
return false;
|
|
}
|
|
auto x_var_name = desc.Input("X")[0];
|
|
auto* x_var_desc = block->FindVarRecursive(x_var_name);
|
|
const auto x_shape = x_var_desc->GetShape();
|
|
auto dtype = x_var_desc->GetDataType();
|
|
if (!with_dynamic_shape) {
|
|
// At present, only support float32 or float16 or float64 into trt.
|
|
if (!(dtype == framework::proto::VarType::FP32 ||
|
|
dtype == framework::proto::VarType::FP64 ||
|
|
dtype == framework::proto::VarType::FP16)) {
|
|
return false;
|
|
}
|
|
} else {
|
|
// At present, only support float32 or float16 or float64 or int32 or
|
|
// int64 into trt.
|
|
if (!(dtype == framework::proto::VarType::FP32 ||
|
|
dtype == framework::proto::VarType::FP16 ||
|
|
dtype == framework::proto::VarType::FP64 ||
|
|
dtype == framework::proto::VarType::INT32 ||
|
|
dtype == framework::proto::VarType::INT64)) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (op_type == "roll") {
|
|
if (!with_dynamic_shape) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (op_type == "strided_slice") {
|
|
if (!desc.HasAttr("axes") || !desc.HasAttr("starts") ||
|
|
!desc.HasAttr("ends") || !desc.HasAttr("strides")) {
|
|
VLOG(3)
|
|
<< "The necessary attributes of the strided_slice operator miss ";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (op_type == "rnn") {
|
|
if (!with_dynamic_shape) {
|
|
return false;
|
|
}
|
|
if (desc.HasAttr("mode")) {
|
|
std::string mode = PADDLE_GET_CONST(std::string, desc.GetAttr("mode"));
|
|
if (mode != "LSTM") return false;
|
|
}
|
|
if (desc.HasAttr("dropout_prob")) {
|
|
float dropout_prob =
|
|
PADDLE_GET_CONST(float, desc.GetAttr("dropout_prob"));
|
|
if (dropout_prob > 1e-5) return false;
|
|
}
|
|
// not support following four inputs for rnn in paddle-trt
|
|
auto rnn_inputs = desc.Inputs();
|
|
if (rnn_inputs.find("SequenceLength") != rnn_inputs.end()) {
|
|
if (!desc.Input("SequenceLength").empty()) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (op_type == "fill_constant_batch_size_like") {
|
|
if (!with_dynamic_shape) {
|
|
return false;
|
|
}
|
|
if (!desc.HasAttr("input_dim_idx")) {
|
|
return false;
|
|
}
|
|
if (!desc.HasAttr("output_dim_idx")) {
|
|
return false;
|
|
}
|
|
if (!desc.HasAttr("shape")) {
|
|
return false;
|
|
}
|
|
auto* block = desc.Block();
|
|
if (block == nullptr) {
|
|
VLOG(3) << "The block desc is nullptr, we can't continue to analyze. "
|
|
"Developers need to check whether block_desc is passed in "
|
|
"the pass.";
|
|
return false;
|
|
}
|
|
auto x_var_name = desc.Input("Input")[0];
|
|
auto* x_var_desc = block->FindVarRecursive(x_var_name);
|
|
auto dtype = x_var_desc->GetDataType();
|
|
// At present, only support float32 into trt.
|
|
if (dtype != 5) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (op_type == "fill_any_like") {
|
|
if (!with_dynamic_shape) {
|
|
VLOG(3) << "the fill_any_like does not support static shape yet";
|
|
return false;
|
|
}
|
|
int dtype = desc.HasAttr("dtype")
|
|
? PADDLE_GET_CONST(int, desc.GetAttr("dtype"))
|
|
: -1;
|
|
auto* block = desc.Block();
|
|
auto* x_var_desc = block->FindVarRecursive(desc.Input("X")[0]);
|
|
auto input_type = x_var_desc->GetDataType();
|
|
#if IS_TRT_VERSION_GE(8400)
|
|
if (dtype == 0 ||
|
|
(dtype == -1 && input_type == framework::proto::VarType::BOOL)) {
|
|
VLOG(3) << "the fill_any_like supports input of BOOL by trt8.4 above";
|
|
return true;
|
|
}
|
|
#endif
|
|
if (dtype != -1 && dtype != 2 && dtype != 3 && dtype != 5 && dtype != 6) {
|
|
VLOG(3)
|
|
<< "the fill_any_like only supports int32/int64/float32/float64 by "
|
|
"trt8.4 below";
|
|
return false;
|
|
}
|
|
if (dtype == -1) {
|
|
if (input_type != framework::proto::VarType::INT32 &&
|
|
input_type != framework::proto::VarType::INT64 &&
|
|
input_type != framework::proto::VarType::FP32 &&
|
|
input_type != framework::proto::VarType::FP64) {
|
|
VLOG(3) << "the fill_any_like only supports "
|
|
"int32/int64/float32/float64 by "
|
|
"trt8.4 below";
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (op_type == "slice") {
|
|
if (desc.HasAttr("decrease_axis")) {
|
|
std::vector<int> decrease_axis =
|
|
PADDLE_GET_CONST(std::vector<int>, desc.GetAttr("decrease_axis"));
|
|
if (!with_dynamic_shape) {
|
|
if (decrease_axis.end() !=
|
|
std::find(decrease_axis.begin(), decrease_axis.end(), 0)) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
std::vector<int> axes;
|
|
if (!desc.HasAttr("axes")) {
|
|
VLOG(3) << "The necessary attributes of the slice operator axes "
|
|
" are missing.";
|
|
return false;
|
|
} else {
|
|
axes = PADDLE_GET_CONST(std::vector<int>, desc.GetAttr("axes"));
|
|
if (!with_dynamic_shape) {
|
|
for (size_t i = 0; i < axes.size(); i++) {
|
|
if (axes[i] == 0) {
|
|
VLOG(3) << "Invalid slice axis. Slice on batch axis is not "
|
|
"supported in TensorRT";
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// not support following four inputs for slice in paddle-trt
|
|
auto slice_inputs = desc.Inputs(); // its size == 5
|
|
if (slice_inputs.find("StartsTensor") != slice_inputs.end() &&
|
|
!desc.Input("StartsTensor").empty()) {
|
|
VLOG(3) << "The Slice has StartsTensor input.";
|
|
} else {
|
|
if (!desc.HasAttr("starts")) {
|
|
VLOG(3) << "The necessary attributes of the slice operator starts or "
|
|
"StartsTensor"
|
|
" are missing.";
|
|
return false;
|
|
} else {
|
|
std::vector<int> starts =
|
|
PADDLE_GET_CONST(std::vector<int>, desc.GetAttr("starts"));
|
|
if (axes.size() != starts.size()) {
|
|
VLOG(3) << "The shape of attributes of the slice operator axes "
|
|
"and starts are not equal.";
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
if (slice_inputs.find("EndsTensor") != slice_inputs.end() &&
|
|
!desc.Input("EndsTensor").empty()) {
|
|
VLOG(3) << "The Slice has EndsTensor input.";
|
|
} else {
|
|
if (!desc.HasAttr("ends")) {
|
|
VLOG(3) << "The necessary attributes of the slice operator ends or "
|
|
"EndsTensor"
|
|
" are missing.";
|
|
return false;
|
|
} else {
|
|
std::vector<int> ends =
|
|
PADDLE_GET_CONST(std::vector<int>, desc.GetAttr("ends"));
|
|
if (axes.size() != ends.size()) {
|
|
VLOG(3) << "The shape of attributes of the slice operator axes "
|
|
"and ends are not equal.";
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
if (slice_inputs.find("StartsTensorList") != slice_inputs.end()) {
|
|
VLOG(3) << "The Slice has StartsTensorList input.";
|
|
}
|
|
if (slice_inputs.find("EndsTensorList") != slice_inputs.end()) {
|
|
VLOG(3) << "The Slice has EndsTensorList input.";
|
|
}
|
|
}
|
|
|
|
if (op_type == "less_than" || op_type == "greater_than" ||
|
|
op_type == "logical_or" || op_type == "logical_xor" ||
|
|
op_type == "logical_and" || op_type == "less_equal" ||
|
|
op_type == "greater_equal") {
|
|
#if IS_TRT_VERSION_GE(8400)
|
|
// TRT does not support kEQUAL/kGREATER/kLESS work with implicit batch
|
|
if (!with_dynamic_shape) {
|
|
VLOG(3) << "Ops(" << op_type << ") do not support static shape yet.";
|
|
return false;
|
|
}
|
|
auto* block = desc.Block();
|
|
auto* x_var_desc = block->FindVarRecursive(desc.Input("X")[0]);
|
|
auto* y_var_desc = block->FindVarRecursive(desc.Input("Y")[0]);
|
|
auto x_dtype = x_var_desc->GetDataType();
|
|
auto y_dtype = y_var_desc->GetDataType();
|
|
if (op_type == "logical_or" || op_type == "logical_xor" ||
|
|
op_type == "logical_and") {
|
|
if (x_dtype != framework::proto::VarType::BOOL ||
|
|
y_dtype != framework::proto::VarType::BOOL) {
|
|
VLOG(3) << "the op (" << op_type << ") only support input of BOOL.";
|
|
return false;
|
|
}
|
|
}
|
|
if (op_type == "less_than" || op_type == "greater_than" ||
|
|
op_type == "less_equal" || op_type == "greater_equal") {
|
|
if (x_dtype == framework::proto::VarType::BOOL ||
|
|
y_dtype == framework::proto::VarType::BOOL) {
|
|
VLOG(3)
|
|
<< "ElementWiseOperation::kLESS/ElementWiseOperation::kGREATER "
|
|
"do not support boolean datatype.";
|
|
return false;
|
|
}
|
|
}
|
|
#else
|
|
VLOG(3) << "these are not supported when TensorRT < 8.4";
|
|
return false;
|
|
#endif
|
|
}
|
|
if (op_type == "elementwise_add" || op_type == "elementwise_mul" ||
|
|
op_type == "elementwise_sub" || op_type == "elementwise_div" ||
|
|
op_type == "elementwise_pow" || op_type == "elementwise_min" ||
|
|
op_type == "elementwise_max" || op_type == "elementwise_floordiv" ||
|
|
op_type == "elementwise_mod") {
|
|
if (desc.Input("X").size() != 1) {
|
|
VLOG(3) << "The input op's Input(\"X\").size() "
|
|
"should equal to 1, but received Input(\"X\").size() = "
|
|
<< desc.Input("X").size() << ".";
|
|
return false;
|
|
}
|
|
if (desc.Input("Y").size() != 1) {
|
|
VLOG(3) << "The input op's Input(\"Y\").size() "
|
|
"should equal to 1, but received Input(\"Y\").size() = "
|
|
<< desc.Input("Y").size() << ".";
|
|
return false;
|
|
}
|
|
if (desc.Output("Out").size() != 1) {
|
|
VLOG(3) << "The input op's Output(\"Out\").size() "
|
|
"should equal to 1, but received Output(\"Out\").size() = "
|
|
<< desc.Output("Out").size() << ".";
|
|
return false;
|
|
}
|
|
auto* block = desc.Block();
|
|
if (block == nullptr) {
|
|
VLOG(3) << "The block desc is nullptr, we can't continue to analyze. "
|
|
"Developers need to check whether block_desc is passed in "
|
|
"the pass.";
|
|
return false;
|
|
}
|
|
auto* x_var_desc = block->FindVarRecursive(desc.Input("X")[0]);
|
|
auto* y_var_desc = block->FindVarRecursive(desc.Input("Y")[0]);
|
|
const auto x_shape = x_var_desc->GetShape();
|
|
const auto y_shape = y_var_desc->GetShape();
|
|
|
|
// These operations do not support boolean datatype.
|
|
if (op_type == "elementwise_add" || op_type == "elementwise_mul" ||
|
|
op_type == "elementwise_sub" || op_type == "elementwise_div" ||
|
|
op_type == "elementwise_pow" || op_type == "elementwise_min" ||
|
|
op_type == "elementwise_max" || op_type == "elementwise_floordiv" ||
|
|
op_type == "elementwise_mod") {
|
|
if (x_var_desc->GetDataType() ==
|
|
paddle::framework::proto::VarType_Type::VarType_Type_BOOL) {
|
|
VLOG(3)
|
|
<< "These operations "
|
|
"(elementwise_add/mul/sub/div/pow/min/max/floordiv/mod) do "
|
|
"not support boolean datatype.";
|
|
return false;
|
|
}
|
|
}
|
|
// These operations input do not support int32 datatype.
|
|
if (op_type == "elementwise_pow") {
|
|
if (x_var_desc->GetDataType() ==
|
|
paddle::framework::proto::VarType_Type::VarType_Type_INT32) {
|
|
VLOG(3) << "These operations (elementwise_pow) do not support int32 "
|
|
"datatype.";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// The case when x_shape.size() == 1 is dealt with in common case
|
|
if (!with_dynamic_shape && (!y_var_desc->Persistable()) &&
|
|
y_shape.size() == 1) {
|
|
VLOG(3) << "Static shape in trt not support y is a 1D intermediate "
|
|
"tensor in "
|
|
"elementwise op.";
|
|
return false;
|
|
}
|
|
|
|
if (x_var_desc->Persistable() && !with_dynamic_shape) {
|
|
VLOG(3)
|
|
<< "Input X is a parameter which is not supported for "
|
|
"elementwise in tensorrt's static shape, swap x and y will work";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (op_type == "pow") {
|
|
auto* block = desc.Block();
|
|
if (block == nullptr) {
|
|
VLOG(3) << "The block desc is nullptr, we can't continue to analyze. "
|
|
"Developers need to check whether block_desc is passed in "
|
|
"the pass.";
|
|
return false;
|
|
}
|
|
auto* x_var_desc = block->FindVarRecursive(desc.Input("X")[0]);
|
|
|
|
// the same as `elementwise_pow`.
|
|
if (x_var_desc->GetDataType() ==
|
|
paddle::framework::proto::VarType_Type::VarType_Type_INT32) {
|
|
VLOG(3) << "These operations (pow) do not support int32 "
|
|
"datatype.";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (op_type == "stack") {
|
|
if (!with_dynamic_shape) {
|
|
VLOG(3)
|
|
<< "static shape mode is not supported for TRT stack.\n"
|
|
"You can use the config.SetTRTDynamicShapeInfo(...) interface"
|
|
" to set the shape information to run the dynamic shape "
|
|
"mode.";
|
|
return false;
|
|
}
|
|
|
|
auto* block = desc.Block();
|
|
if (block == nullptr) {
|
|
VLOG(3) << "The block desc is nullptr, we can't continue to analyze. "
|
|
"Developers need to check whether block_desc is passed in "
|
|
"the pass.";
|
|
return false;
|
|
}
|
|
auto x_var_name = desc.Input("X")[0];
|
|
auto* x_var_desc = block->FindVarRecursive(x_var_name);
|
|
const auto x_shape = x_var_desc->GetShape();
|
|
int rank = x_shape.size();
|
|
int axis = desc.HasAttr("axis")
|
|
? PADDLE_GET_CONST(int, desc.GetAttr("axis"))
|
|
: -1;
|
|
if (axis > rank || axis < -(rank + 1)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (op_type == "shape" && !with_dynamic_shape) {
|
|
return false;
|
|
}
|
|
|
|
if (op_type == "fused_embedding_eltwise_layernorm") {
|
|
if (!with_dynamic_shape) {
|
|
VLOG(3) << "fused_embedding_eltwise_layernorm should run on dynamic "
|
|
"shape mode.";
|
|
return false;
|
|
}
|
|
if (desc.Input("Ids").size() != desc.Input("Embs").size()) {
|
|
return false;
|
|
}
|
|
}
|
|
if (op_type == "fused_bias_dropout_residual_layer_norm") {
|
|
if (!with_dynamic_shape) {
|
|
VLOG(3) << "fused_bias_dropout_residual_layer_norm should run on "
|
|
"dynamic shape mode.";
|
|
return false;
|
|
}
|
|
float dropout_rate =
|
|
PADDLE_GET_CONST(float, desc.GetAttr("dropout_rate"));
|
|
if (dropout_rate != 0.0f) {
|
|
VLOG(4) << "preln_residual_bias trt layer can not work with "
|
|
"fused_bias_dropout_residual_layer_norm op in which the "
|
|
"dropout_rate != 0, stop convert";
|
|
return false;
|
|
}
|
|
}
|
|
if (op_type == "fused_preln_embedding_eltwise_layernorm") {
|
|
if (!with_dynamic_shape) {
|
|
VLOG(3) << "fused_preln_embedding_eltwise_layernorm should run on "
|
|
"dynamic "
|
|
"shape mode.";
|
|
return false;
|
|
}
|
|
if (desc.Input("Ids").size() != desc.Input("Embs").size()) {
|
|
VLOG(3) << "The id and emb size of fused PrelnEmbEltwiseLayerNormOp "
|
|
"should be same ";
|
|
return false;
|
|
}
|
|
if (!desc.HasAttr("enable_int8")) {
|
|
VLOG(3) << "PrelnEmbEltwiseLayerNormOp must use int8 mode.";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (op_type == "gelu") {
|
|
if (desc.Input("X").size() != 1) {
|
|
VLOG(3) << "gelu op has only 1 input, but got "
|
|
<< desc.Input("X").size();
|
|
return false;
|
|
}
|
|
if (desc.Output("Out").size() != 1) {
|
|
VLOG(3) << "gelu op has only 1 output, but got "
|
|
<< desc.Output("Out").size();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (op_type == "layer_norm") {
|
|
if (desc.Input("X").size() != 1) {
|
|
VLOG(3) << "input of layer_norm op converter should be 1, got "
|
|
<< desc.Input("X").size();
|
|
return false;
|
|
}
|
|
if (desc.Input("Bias").size() != 1) {
|
|
VLOG(3) << "Bias of layer_norm op converter should be 1, got "
|
|
<< desc.Input("Bias").size();
|
|
return false;
|
|
}
|
|
if (desc.Input("Scale").size() != 1) {
|
|
VLOG(3) << "Scale of layer_norm op converter should be 1, got "
|
|
<< desc.Input("Scale").size();
|
|
return false;
|
|
}
|
|
if (desc.Output("Y").size() != 1) {
|
|
VLOG(3) << "output of layer_norm op converter should be 1, got "
|
|
<< desc.Output("Y").size();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (op_type == "fill_constant") {
|
|
auto fill_constant_inputs = desc.Inputs();
|
|
if (fill_constant_inputs.find("ValueTensor") !=
|
|
fill_constant_inputs.end()) {
|
|
if (!desc.Input("ValueTensor").empty()) return false;
|
|
}
|
|
|
|
if (desc.HasInput("ShapeTensor")) {
|
|
if (desc.Input("ShapeTensor").size() > 1) return false;
|
|
if (desc.Input("ShapeTensor").size() == 1) {
|
|
#if IS_TRT_VERSION_LT(8500)
|
|
VLOG(3) << "fill_constant ShapeTensor is not supported when TensorRT "
|
|
"< 8.5.0";
|
|
return false;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
#if IS_TRT_VERSION_LT(8500)
|
|
if (desc.HasInput("ShapeTensorList")) {
|
|
if (desc.Input("ShapeTensorList").size() >= 1) {
|
|
VLOG(3) << "fill_constant ShapeTensorList is not supported when "
|
|
"TensorRT < 8.5.0";
|
|
return false;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
int dtype = desc.HasAttr("dtype")
|
|
? PADDLE_GET_CONST(int, desc.GetAttr("dtype"))
|
|
: 5;
|
|
// only support int32, int64, float32
|
|
if (!(dtype == 2 || dtype == 3 || dtype == 5)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (op_type == "instance_norm") {
|
|
if (desc.Input("X").size() != 1) {
|
|
VLOG(3) << "input of instance_norm op converter should be 1, got "
|
|
<< desc.Input("X").size();
|
|
return false;
|
|
}
|
|
if (desc.Input("Bias").size() != 1) {
|
|
VLOG(3) << "Bias of instance_norm op converter should be 1, got "
|
|
<< desc.Input("Bias").size();
|
|
return false;
|
|
}
|
|
if (desc.Input("Scale").size() != 1) {
|
|
VLOG(3) << "Scale of instance_norm op converter should be 1, got "
|
|
<< desc.Input("Scale").size();
|
|
return false;
|
|
}
|
|
if (desc.Output("Y").size() != 1) {
|
|
VLOG(3) << "output of layer_norm op converter should be 1, got "
|
|
<< desc.Output("Y").size();
|
|
return false;
|
|
}
|
|
|
|
auto* block = desc.Block();
|
|
if (block == nullptr) {
|
|
VLOG(3) << "The block desc is nullptr, we can't continue to analyze. "
|
|
"Developers need to check whether block_desc is passed in "
|
|
"the pass.";
|
|
return false;
|
|
}
|
|
auto x_var_name = desc.Input("X")[0];
|
|
auto* x_var_desc = block->FindVarRecursive(x_var_name);
|
|
const auto x_shape = x_var_desc->GetShape();
|
|
if (x_shape.size() != 4) {
|
|
VLOG(3) << "The instance_norm op only support 4-dimensional input in "
|
|
"tensorrt.";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (op_type == "pad") {
|
|
if (!desc.HasAttr("pad_value") || !desc.HasAttr("paddings")) return false;
|
|
const float pad_value =
|
|
PADDLE_GET_CONST(float, desc.GetAttr("pad_value"));
|
|
if (pad_value != 0.0f) {
|
|
VLOG(3) << "The pad layer of TRT only support zero.";
|
|
return false;
|
|
}
|
|
std::vector<int64_t> shape;
|
|
auto* block = desc.Block();
|
|
if (block == nullptr) {
|
|
VLOG(3) << "The block desc is nullptr, we can't continue to analyze. "
|
|
"Developers need to check whether block_desc is passed in "
|
|
"the pass.";
|
|
return false;
|
|
}
|
|
for (auto& param_name : desc.Inputs()) {
|
|
for (auto& var_name : param_name.second) {
|
|
auto* var_desc = block->FindVarRecursive(var_name);
|
|
shape = var_desc->GetShape();
|
|
}
|
|
}
|
|
int nbDims = shape.size();
|
|
std::vector<int> paddings =
|
|
PADDLE_GET_CONST(std::vector<int>, desc.GetAttr("paddings"));
|
|
int pad_size = paddings.size();
|
|
if (nbDims < 2) {
|
|
return false;
|
|
}
|
|
if (nbDims * 2 != pad_size) {
|
|
return false;
|
|
}
|
|
for (int i = 0; i < pad_size - 4; i++) {
|
|
if (paddings[i] != 0) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (op_type == "bitwise_and") {
|
|
#if IS_TRT_VERSION_LT(8400)
|
|
VLOG(3) << "bitwise_and is not supported when TensorRT < 8.4";
|
|
return false;
|
|
#endif
|
|
if (!with_dynamic_shape) {
|
|
VLOG(3) << "Ops(" << op_type << ") do not support static shape yet.";
|
|
return false;
|
|
}
|
|
auto x_var_name = desc.Input("X")[0];
|
|
auto y_var_name = desc.Input("Y")[0];
|
|
auto* block = desc.Block();
|
|
if (block == nullptr) {
|
|
VLOG(3) << "The block desc is nullptr, we can't continue to analyze. "
|
|
"Developers need to check whether block_desc is passed in "
|
|
"the pass.";
|
|
return false;
|
|
}
|
|
auto* x_var_desc = block->FindVarRecursive(x_var_name);
|
|
auto* y_var_desc = block->FindVarRecursive(y_var_name);
|
|
auto x_dtype = x_var_desc->GetDataType();
|
|
auto y_dtype = y_var_desc->GetDataType();
|
|
if (x_dtype != framework::proto::VarType::BOOL ||
|
|
y_dtype != framework::proto::VarType::BOOL) {
|
|
VLOG(3) << "the bitwise_and only support input of BOOL.";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (op_type == "bitwise_or") {
|
|
#if IS_TRT_VERSION_LT(8400)
|
|
VLOG(3) << "bitwise_or is not supported when TensorRT < 8.4";
|
|
return false;
|
|
#endif
|
|
if (!with_dynamic_shape) {
|
|
VLOG(3) << "Ops(" << op_type << ") do not support static shape yet.";
|
|
return false;
|
|
}
|
|
auto x_var_name = desc.Input("X")[0];
|
|
auto y_var_name = desc.Input("Y")[0];
|
|
auto* block = desc.Block();
|
|
if (block == nullptr) {
|
|
VLOG(3) << "The block desc is nullptr, we can't continue to analyze. "
|
|
"Developers need to check whether block_desc is passed in "
|
|
"the pass.";
|
|
return false;
|
|
}
|
|
auto* x_var_desc = block->FindVarRecursive(x_var_name);
|
|
auto* y_var_desc = block->FindVarRecursive(y_var_name);
|
|
auto x_dtype = x_var_desc->GetDataType();
|
|
auto y_dtype = y_var_desc->GetDataType();
|
|
if (x_dtype != framework::proto::VarType::BOOL ||
|
|
y_dtype != framework::proto::VarType::BOOL) {
|
|
VLOG(3) << "the bitwise_or only support input of BOOL.";
|
|
return false;
|
|
}
|
|
}
|
|
if (op_type == "size") {
|
|
if (!with_dynamic_shape) {
|
|
VLOG(3) << "Ops(" << op_type << ") do not support static shape yet.";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (op_type == "pad3d") {
|
|
#if !IS_TRT_VERSION_GE(8200)
|
|
VLOG(3) << "pad3d is not supported when TensorRT < 8.2";
|
|
return false;
|
|
#endif
|
|
if (!with_dynamic_shape) {
|
|
VLOG(3) << "pad3d is not supported static shape";
|
|
return false;
|
|
}
|
|
if (!desc.HasAttr("paddings") && !desc.HasInput("Paddings")) {
|
|
return false;
|
|
}
|
|
if (desc.HasAttr("mode")) {
|
|
std::string mode = PADDLE_GET_CONST(std::string, desc.GetAttr("mode"));
|
|
if (mode != "constant" && mode != "reflect" && mode != "replicate") {
|
|
VLOG(3) << "The pad3d layer of TRT only support "
|
|
"constant/reflect/replicate mode.";
|
|
return false;
|
|
}
|
|
}
|
|
if (desc.HasAttr("data_format")) {
|
|
std::string data_format =
|
|
PADDLE_GET_CONST(std::string, desc.GetAttr("data_format"));
|
|
if (data_format != "NCDHW") {
|
|
VLOG(3) << "The pad3d layer of TRT only support NCDHW data format.";
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (op_type == "prelu") {
|
|
if (desc.Input("X").size() != 1) {
|
|
VLOG(3) << "Invalid input X's size of prelu TRT converter. "
|
|
"Expected 1, received "
|
|
<< desc.Input("X").size() << ".";
|
|
return false;
|
|
}
|
|
if (desc.Output("Out").size() != 1) {
|
|
VLOG(3) << "Invalid output Out's size of prelu TRT converter. "
|
|
"Expected 1, received "
|
|
<< desc.Output("Out").size() << ".";
|
|
return false;
|
|
}
|
|
|
|
auto* block = desc.Block();
|
|
if (block == nullptr) {
|
|
VLOG(3) << "The block desc is nullptr, we can't continue to analyze. "
|
|
"Developers need to check whether block_desc is passed in "
|
|
"the pass.";
|
|
return false;
|
|
}
|
|
auto* alpha_var = block->FindVarRecursive(desc.Input("Alpha")[0]);
|
|
if (!alpha_var) {
|
|
VLOG(3) << "Variable Alpha of prelu TRT converter not found.";
|
|
return false;
|
|
}
|
|
auto alpha_shape = alpha_var->GetShape();
|
|
if (!with_dynamic_shape && alpha_shape.empty()) {
|
|
VLOG(3) << op_type
|
|
<< " op does not support alpha's dim is 0 in tensorrt "
|
|
"static shape mode.";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (op_type == "mish") {
|
|
if (desc.Input("X").size() != 1) {
|
|
VLOG(3) << "Invalid input X's size of mish TRT converter. "
|
|
"Expected 1, received "
|
|
<< desc.Input("X").size() << ".";
|
|
return false;
|
|
}
|
|
if (desc.Output("Out").size() != 1) {
|
|
VLOG(3) << "Invalid output Out's size of mish TRT converter. "
|
|
"Expected 1, received "
|
|
<< desc.Output("Out").size() << ".";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (op_type == "roi_align") {
|
|
if (!with_dynamic_shape) {
|
|
VLOG(3) << "TRT roi align plugin only accept the dynamic shape, "
|
|
"because that "
|
|
"the roi_align will change the batch size.";
|
|
return false;
|
|
}
|
|
std::vector<std::string> attrs{"pooled_height",
|
|
"pooled_width",
|
|
"spatial_scale",
|
|
"sampling_ratio",
|
|
"aligned"};
|
|
for (auto const& attr : attrs) {
|
|
if (!desc.HasAttr(attr)) return false;
|
|
}
|
|
|
|
const auto pooled_height =
|
|
PADDLE_GET_CONST(int, desc.GetAttr("pooled_height"));
|
|
if (pooled_height <= 0) return false;
|
|
|
|
const auto pooled_width =
|
|
PADDLE_GET_CONST(int, desc.GetAttr("pooled_width"));
|
|
if (pooled_width <= 0) return false;
|
|
|
|
const auto spatial_scale =
|
|
PADDLE_GET_CONST(float, desc.GetAttr("spatial_scale"));
|
|
if (spatial_scale <= 0.f) return false;
|
|
|
|
auto roi_align_inputs = desc.Inputs();
|
|
if (roi_align_inputs.find("RoisNum") != roi_align_inputs.end()) {
|
|
if (!desc.Input("RoisNum").empty()) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (op_type == "shuffle_channel") {
|
|
#if !IS_TRT_VERSION_GE(8000)
|
|
if (with_dynamic_shape) {
|
|
VLOG(3) << "You are running the TRT Dynamic Shape mode, "
|
|
"the shuffle_channel op does not support dynamic shape "
|
|
"trt versions below 8.0 yet";
|
|
return false;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (op_type == "where") {
|
|
#if !IS_TRT_VERSION_GE(8400)
|
|
VLOG(3) << "where is not supported when TensorRT < 8.4";
|
|
return false;
|
|
#endif
|
|
if (!with_dynamic_shape) {
|
|
VLOG(3) << "the where op does not support static shape yet";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (op_type == "bitwise_not") {
|
|
auto* block = desc.Block();
|
|
auto x_var_name = desc.Input("X")[0];
|
|
auto* x_var_desc = block->FindVarRecursive(x_var_name);
|
|
auto dtype = x_var_desc->GetDataType();
|
|
if (dtype == framework::proto::VarType::INT8 ||
|
|
dtype == framework::proto::VarType::UINT8) {
|
|
VLOG(3) << "INT8 / UINT8 type convert to trt is not supported";
|
|
return false;
|
|
}
|
|
if (dtype == framework::proto::VarType::BOOL) {
|
|
#if !IS_TRT_VERSION_GE(8400)
|
|
VLOG(3) << "BOOL type support requires TensorRT 8.4";
|
|
return false;
|
|
#elif !IS_TRT_VERSION_GE(8600)
|
|
const auto x_shape = x_var_desc->GetShape();
|
|
if (x_shape.empty()) {
|
|
VLOG(3) << "BOOL type does not support 0 dim input when TensorRT < "
|
|
"8.6.";
|
|
return false;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if (op_type == "one_hot" || op_type == "one_hot_v2") {
|
|
#if IS_TRT_VERSION_LT(8510)
|
|
VLOG(3) << "one_hot/one_hot_v2 is not supported when TensorRT < 8.5.1";
|
|
return false;
|
|
#endif
|
|
if (!with_dynamic_shape) {
|
|
VLOG(3)
|
|
<< "the one_hot/one_hot_v2 op does not support static shape yet";
|
|
return false;
|
|
}
|
|
if (desc.HasAttr("allow_out_of_range")) {
|
|
VLOG(3) << "allow_out_of_range one_hot/one_hot_v2 op is not "
|
|
"supported now.";
|
|
if (PADDLE_GET_CONST(bool, desc.GetAttr("allow_out_of_range")))
|
|
return false;
|
|
}
|
|
if (desc.HasAttr("dtype")) {
|
|
const int dtype = PADDLE_GET_CONST(int, desc.GetAttr("dtype"));
|
|
if (dtype != 2 && dtype != 3 && dtype != 5) {
|
|
VLOG(3) << "one_hot/one_hot_v2 op only support int32, int64, float.";
|
|
return false;
|
|
}
|
|
}
|
|
auto one_hot_inputs = desc.Inputs();
|
|
if (one_hot_inputs.find("depth_tensor") != one_hot_inputs.end()) {
|
|
if (!desc.Input("depth_tensor").empty()) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (desc.HasAttr("depth")) {
|
|
const int depth = PADDLE_GET_CONST(int, desc.GetAttr("depth"));
|
|
if (depth <= 0) {
|
|
VLOG(3) << "depth only support positive in one_hot/one_hot_v2 op.";
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (op_type == "skip_layernorm") {
|
|
if (!with_dynamic_shape) {
|
|
VLOG(3) << "the skip_layernorm does not support static shape yet";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (op_type == "preln_skip_layernorm") {
|
|
if (!with_dynamic_shape) {
|
|
VLOG(3) << "the preln_skip_layernorm does not support static shape yet";
|
|
return false;
|
|
}
|
|
if (!desc.HasAttr("enable_int8")) {
|
|
VLOG(3) << "PrelnEmbEltwiseLayerNormOp must use int8 mode.";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (op_type == "multihead_matmul") {
|
|
if (!with_dynamic_shape) {
|
|
VLOG(3) << "the multihead_matmul does not support static shape yet";
|
|
return false;
|
|
}
|
|
|
|
if (desc.HasAttr("enable_int8") && !desc.HasAttr("Input_scale")) {
|
|
VLOG(3) << "Multihead layers must have input scale in int8 mode.";
|
|
return false;
|
|
}
|
|
|
|
auto* block = desc.Block();
|
|
if (block == nullptr) {
|
|
VLOG(3) << "The block desc is nullptr, we can't continue to analyze. "
|
|
"Developers need to check whether block_desc is passed in "
|
|
"the pass.";
|
|
return false;
|
|
}
|
|
auto* input_desc = block->FindVarRecursive(desc.Input("Input").front());
|
|
const auto input_shape = input_desc->GetShape();
|
|
const auto head_number =
|
|
PADDLE_GET_CONST(int, desc.GetAttr("head_number"));
|
|
auto inputs = desc.Inputs();
|
|
bool has_bias_qk = (inputs.find("BiasQK") == inputs.end()) ? false : true;
|
|
if (has_bias_qk) {
|
|
auto* bias_qk_desc =
|
|
block->FindVarRecursive(desc.Input("BiasQK").front());
|
|
const auto bias_qk_shape = bias_qk_desc->GetShape();
|
|
// The BiasQK's shape requires to be
|
|
// [batch, 1, 1, length] or [batch, head, length, length].
|
|
bool has_same_shape = head_number == bias_qk_shape[1] &&
|
|
input_shape[1] == bias_qk_shape[2] &&
|
|
input_shape[1] == bias_qk_shape[3];
|
|
bool is_broadcastable = bias_qk_shape[1] == 1 &&
|
|
bias_qk_shape[2] == 1 &&
|
|
input_shape[1] == bias_qk_shape[3];
|
|
is_broadcastable = is_broadcastable ||
|
|
(bias_qk_shape[0] == 1 && bias_qk_shape[1] == 1 &&
|
|
input_shape[1] == bias_qk_shape[2] &&
|
|
input_shape[1] == bias_qk_shape[3]);
|
|
if (!(has_same_shape || is_broadcastable)) {
|
|
VLOG(3) << "The BiasQK's shape is invalid, expect [" << input_shape[0]
|
|
<< ", 1, 1, " << input_shape[1] << "] "
|
|
<< "or [" << input_shape[0] << ", " << head_number << ", "
|
|
<< input_shape[1] << ", " << input_shape[1] << "] "
|
|
<< "or [" << input_shape[0] << "/1, " << 1 << ", "
|
|
<< input_shape[1] << ", " << input_shape[1] << "] "
|
|
<< "but got [" << bias_qk_shape[0] << ", " << bias_qk_shape[1]
|
|
<< ", " << bias_qk_shape[2] << ", " << bias_qk_shape[3]
|
|
<< "].";
|
|
return false;
|
|
}
|
|
} else {
|
|
#if (IS_TRT_VERSION_GE(8000) && IS_TRT_VERSION_LT(8100))
|
|
VLOG(3) << "There are some bugs with trt 8.0";
|
|
return false;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if (op_type == "multihead_matmul_roformer") {
|
|
if (!with_dynamic_shape) {
|
|
VLOG(3) << "the multihead_matmul_roformer does not support static "
|
|
"shape yet";
|
|
return false;
|
|
}
|
|
|
|
if (desc.HasAttr("enable_int8") && !desc.HasAttr("Input_scale")) {
|
|
VLOG(3) << "Multihead layers must have input scale in int8 mode.";
|
|
return false;
|
|
}
|
|
|
|
auto* block = desc.Block();
|
|
if (block == nullptr) {
|
|
VLOG(3) << "The block desc is nullptr, we can't continue to analyze. "
|
|
"Developers need to check whether block_desc is passed in "
|
|
"the pass.";
|
|
return false;
|
|
}
|
|
auto* input_desc = block->FindVarRecursive(desc.Input("Input").front());
|
|
const auto input_shape = input_desc->GetShape();
|
|
const auto head_number =
|
|
PADDLE_GET_CONST(int, desc.GetAttr("head_number"));
|
|
auto inputs = desc.Inputs();
|
|
bool has_bias_qk = (inputs.find("BiasQK") == inputs.end()) ? false : true;
|
|
if (has_bias_qk) {
|
|
auto* bias_qk_desc =
|
|
block->FindVarRecursive(desc.Input("BiasQK").front());
|
|
const auto bias_qk_shape = bias_qk_desc->GetShape();
|
|
// The BiasQK's shape requires to be
|
|
// [batch, 1, 1, length] or [batch, head, length, length].
|
|
bool has_same_shape = head_number == bias_qk_shape[1] &&
|
|
input_shape[1] == bias_qk_shape[2] &&
|
|
input_shape[1] == bias_qk_shape[3];
|
|
bool is_broadcastable = bias_qk_shape[1] == 1 &&
|
|
bias_qk_shape[2] == 1 &&
|
|
input_shape[1] == bias_qk_shape[3];
|
|
if (!(has_same_shape || is_broadcastable)) {
|
|
VLOG(3) << "The BiasQK's shape is invalid, expect [" << input_shape[0]
|
|
<< ", 1, 1, " << input_shape[1] << "] or [" << input_shape[0]
|
|
<< ", " << head_number << ", " << input_shape[1] << ", "
|
|
<< input_shape[1] << "] but [" << bias_qk_shape[0] << ", "
|
|
<< bias_qk_shape[1] << ", " << bias_qk_shape[2] << ", "
|
|
<< bias_qk_shape[3] << "].";
|
|
return false;
|
|
}
|
|
} else {
|
|
#if !IS_TRT_VERSION_GE(8000)
|
|
VLOG(3) << "The version of TRT must be greater than 8000";
|
|
return false;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if (op_type == "reshape" || op_type == "reshape2") {
|
|
if (!desc.HasAttr("shape")) {
|
|
return false;
|
|
}
|
|
if (with_dynamic_shape) {
|
|
return true;
|
|
}
|
|
// Static shape does not support the input tensors: Shape and
|
|
// ShapeTensor
|
|
auto reshape_inputs = desc.Inputs();
|
|
if (reshape_inputs.find("Shape") != reshape_inputs.end()) {
|
|
if (!desc.Input("Shape").empty()) {
|
|
return false;
|
|
}
|
|
}
|
|
if (reshape_inputs.find("ShapeTensor") != reshape_inputs.end()) {
|
|
if (!desc.Input("ShapeTensor").empty()) {
|
|
return false;
|
|
}
|
|
}
|
|
std::vector<int> shape =
|
|
PADDLE_GET_CONST(std::vector<int>, desc.GetAttr("shape"));
|
|
if (shape.size() >= nvinfer1::Dims::MAX_DIMS) return false;
|
|
if (!with_dynamic_shape) {
|
|
if (shape.size() == 1) {
|
|
return false;
|
|
}
|
|
if (shape[0] == 0) {
|
|
return true;
|
|
} else {
|
|
auto* block = desc.Block();
|
|
auto x_var_name = desc.Input("X")[0];
|
|
auto* x_var_desc = block->FindVarRecursive(x_var_name);
|
|
const auto x_shape = x_var_desc->GetShape();
|
|
int input_num = std::accumulate(
|
|
x_shape.begin() + 1, x_shape.end(), 1, std::multiplies<int>());
|
|
int shape_num = std::accumulate(
|
|
shape.begin() + 1, shape.end(), 1, std::multiplies<int>());
|
|
if (input_num == shape_num) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (op_type == "clip") {
|
|
if (!with_dynamic_shape) {
|
|
VLOG(3) << "the clip does not support static "
|
|
"shape yet";
|
|
return false;
|
|
}
|
|
// Paddle-TRT does not support the input tensors: Min and Max
|
|
auto clip_inputs = desc.Inputs();
|
|
if (clip_inputs.find("Min") != clip_inputs.end()) {
|
|
if (!desc.Input("Min").empty()) {
|
|
return false;
|
|
}
|
|
}
|
|
if (clip_inputs.find("Max") != clip_inputs.end()) {
|
|
if (!desc.Input("Max").empty()) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
auto* block = desc.Block();
|
|
if (block == nullptr) {
|
|
VLOG(3) << "The block desc is nullptr, we can't continue to analyze. "
|
|
"Developers need to check whether block_desc is passed in "
|
|
"the pass.";
|
|
return false;
|
|
}
|
|
auto x_var_name = desc.Input("X")[0];
|
|
auto* x_var_desc = block->FindVarRecursive(x_var_name);
|
|
const auto x_shape = x_var_desc->GetShape();
|
|
if (x_shape.empty()) {
|
|
VLOG(3) << op_type
|
|
<< " op does not support input's dim is 0 in tensorrt.";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (op_type == "reduce_sum" || op_type == "reduce_mean" ||
|
|
op_type == "reduce_max" || op_type == "reduce_min" ||
|
|
op_type == "reduce_prod" || op_type == "reduce_any" ||
|
|
op_type == "reduce_all") {
|
|
if (!desc.HasAttr("dim", /*with_attr_var=*/false)) {
|
|
VLOG(3) << "Skip to convert into TRT while found Attribute('dim') is "
|
|
"Variable type in "
|
|
<< desc.Type();
|
|
return false;
|
|
}
|
|
|
|
if (!(desc.HasAttr("keep_dim") && desc.HasAttr("dim") &&
|
|
desc.HasAttr("reduce_all"))) {
|
|
VLOG(3) << "the " << op_type
|
|
<< " does not have attr (keep_dim or dim or "
|
|
"reduce_all)";
|
|
return false;
|
|
}
|
|
|
|
auto* block = desc.Block();
|
|
if (block == nullptr) {
|
|
VLOG(3) << "The block desc is nullptr, we can't continue to analyze. "
|
|
"Developers need to check whether block_desc is passed in "
|
|
"the pass.";
|
|
return false;
|
|
}
|
|
|
|
// The batch size dimension cannot be reduced if it's not dynamic shape.
|
|
auto* x_var_desc = block->FindVarRecursive(desc.Input("X")[0]);
|
|
if (!with_dynamic_shape) {
|
|
if (PADDLE_GET_CONST(bool, desc.GetAttr("reduce_all"))) return false;
|
|
std::vector<int32_t> dim =
|
|
PADDLE_GET_CONST(std::vector<int32_t>, desc.GetAttr("dim"));
|
|
const auto input_shape = x_var_desc->GetShape();
|
|
for (auto x : dim) {
|
|
if (x == 0 || (x + input_shape.size() == 0)) return false;
|
|
}
|
|
}
|
|
|
|
auto dtype = x_var_desc->GetDataType();
|
|
if (op_type == "reduce_all" || op_type == "reduce_any") {
|
|
if (dtype != framework::proto::VarType::BOOL) {
|
|
VLOG(3)
|
|
<< "reduce_all and reduce_any op input data type must be bool";
|
|
return false;
|
|
}
|
|
} else {
|
|
if (dtype != framework::proto::VarType::INT32 &&
|
|
dtype != framework::proto::VarType::INT64 &&
|
|
dtype != framework::proto::VarType::FP32 &&
|
|
dtype != framework::proto::VarType::FP64) {
|
|
VLOG(3) << "reduce op input data type must be int32 or int64 or "
|
|
"float32 or "
|
|
"float64";
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
if (op_type == "tile") {
|
|
// Paddle-TRT does not support the input tensors.
|
|
auto tile_inputs = desc.Inputs();
|
|
if (!with_dynamic_shape) {
|
|
if (tile_inputs.find("repeat_times_tensor") != tile_inputs.end()) {
|
|
if (!desc.Input("repeat_times_tensor").empty()) {
|
|
VLOG(3) << "Tile op: repeat_times_tensor is not empty.";
|
|
return false;
|
|
}
|
|
}
|
|
if (tile_inputs.find("RepeatTimes") != tile_inputs.end()) {
|
|
if (!desc.Input("RepeatTimes").empty()) {
|
|
VLOG(3) << "Tile op: RepeatTimes is not empty.";
|
|
return false;
|
|
}
|
|
}
|
|
if (!desc.HasAttr("repeat_times")) {
|
|
VLOG(3) << "Tile op:`repeat_times` is not set.";
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// conv3d_transpose
|
|
if (op_type == "conv3d_transpose") {
|
|
// trt doesn't support output_padding when < 8406
|
|
// output_padding is usually set when stride > 1
|
|
#if !IS_TRT_VERSION_GE(8400)
|
|
if (desc.HasAttr("output_padding")) {
|
|
const std::vector<int> output_padding =
|
|
PADDLE_GET_CONST(std::vector<int>, desc.GetAttr("output_padding"));
|
|
if (output_padding.size() > 0) {
|
|
int max_padding =
|
|
*std::max_element(output_padding.begin(), output_padding.end());
|
|
if (max_padding > 0) return false;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (op_type == "conv3d" || op_type == "conv3d_transpose") {
|
|
if (desc.HasAttr("padding_algorithm")) {
|
|
std::string padding_algorithm =
|
|
PADDLE_GET_CONST(std::string, desc.GetAttr("padding_algorithm"));
|
|
|
|
// trt error is raised if conv3d_transpose and SAME
|
|
if (op_type == "conv3d_transpose" && padding_algorithm == "SAME" &&
|
|
!with_dynamic_shape) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
std::vector<int> paddings =
|
|
PADDLE_GET_CONST(std::vector<int>, desc.GetAttr("paddings"));
|
|
|
|
// conv3d and conv3d_transpose need padding check
|
|
if (paddings.size() > 3) return false;
|
|
|
|
if (desc.Input("Input").size() != 1) {
|
|
VLOG(3) << "TRT Conv3d expect 1 input, but got "
|
|
<< desc.Input("Input").size() << " input.";
|
|
return false;
|
|
}
|
|
|
|
if (desc.Input("Filter").size() != 1) {
|
|
VLOG(3) << "TRT Conv3d expect 1 filter, but got "
|
|
<< desc.Input("Filter").size() << " filter.";
|
|
return false;
|
|
}
|
|
|
|
if (op_type == "conv3d_transpose") {
|
|
if (!desc.HasAttr("dilations")) {
|
|
return false;
|
|
} else {
|
|
const std::vector<int> dilations =
|
|
PADDLE_GET_CONST(std::vector<int>, desc.GetAttr("dilations"));
|
|
if (dilations[0] != 1 || dilations[1] != 1 || dilations[2] != 1) {
|
|
VLOG(3) << "In conv3d_transpose, Dilations must be (1, 1, 1) for "
|
|
"tensorRT, but given ("
|
|
<< dilations[0] << ", " << dilations[1] << ", "
|
|
<< dilations[2] << ")";
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (desc.Output("Output").size() != 1) {
|
|
VLOG(3) << "TRT Conv3d expect 1 output, but got "
|
|
<< desc.Output("Output").size() << " output.";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (op_type == "cast") {
|
|
if (!(desc.HasAttr("in_dtype") && desc.HasAttr("out_dtype"))) {
|
|
VLOG(3) << "the " << op_type
|
|
<< " does not have attr (in_dtype or "
|
|
"out_dtype)";
|
|
return false;
|
|
}
|
|
int in_dtype = PADDLE_GET_CONST(int, desc.GetAttr("in_dtype"));
|
|
int out_dtype = PADDLE_GET_CONST(int, desc.GetAttr("out_dtype"));
|
|
|
|
if (in_dtype == 0 || out_dtype == 0) {
|
|
#if IS_TRT_VERSION_GE(8400)
|
|
if (with_dynamic_shape) {
|
|
VLOG(3) << "the cast op supports inputs and outputs of BOOL by "
|
|
"trt8.4 above ";
|
|
return true;
|
|
}
|
|
#endif
|
|
return false;
|
|
}
|
|
auto* block = desc.Block();
|
|
if (block == nullptr) {
|
|
VLOG(3) << "The block desc is nullptr, we can't continue to analyze. "
|
|
"Developers need to check whether block_desc is passed in "
|
|
"the pass.";
|
|
return false;
|
|
}
|
|
auto x_var_name = desc.Input("X")[0];
|
|
auto* x_var_desc = block->FindVarRecursive(x_var_name);
|
|
const auto x_shape = x_var_desc->GetShape();
|
|
if (!with_dynamic_shape && (x_shape.size() == 1 || x_shape.empty())) {
|
|
VLOG(3) << op_type
|
|
<< " op does not support input's dim is 1 or 0 in tensorrt "
|
|
"static shape mode.";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (op_type == "set_value") {
|
|
#if !IS_TRT_VERSION_GE(8200)
|
|
return false;
|
|
#endif
|
|
auto inputs = desc.Inputs();
|
|
if (inputs.find("StartsTensorList") != inputs.end()) {
|
|
if (!desc.Input("StartsTensorList").empty()) {
|
|
return false;
|
|
}
|
|
}
|
|
if (inputs.find("EndsTensorList") != inputs.end()) {
|
|
if (!desc.Input("EndsTensorList").empty()) {
|
|
return false;
|
|
}
|
|
}
|
|
if (inputs.find("StepsTensorList") != inputs.end()) {
|
|
if (!desc.Input("StepsTensorList").empty()) {
|
|
return false;
|
|
}
|
|
}
|
|
if (!(desc.HasAttr("axes") && desc.HasAttr("starts") &&
|
|
desc.HasAttr("steps"))) {
|
|
VLOG(3) << "the " << op_type
|
|
<< " does not have attr (axes or "
|
|
"starts or steps)";
|
|
return false;
|
|
}
|
|
if (desc.HasAttr("axes")) {
|
|
auto axes =
|
|
PADDLE_GET_CONST(std::vector<int64_t>, desc.GetAttr("axes"));
|
|
if (axes.size() != 1UL) {
|
|
VLOG(3) << "the set_value op"
|
|
<< "has more than one element in attribute axes, it can not "
|
|
"enter into trt.";
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (op_type == "top_k_v2" || op_type == "top_k") {
|
|
if (desc.HasAttr("axis")) {
|
|
int axis = PADDLE_GET_CONST(int, desc.GetAttr("axis"));
|
|
if (!with_dynamic_shape && axis == 0) {
|
|
VLOG(3) << "top_k_v2 does not support axis == 0 in "
|
|
"tensorrt static shape.";
|
|
return false;
|
|
}
|
|
}
|
|
if (desc.HasAttr("sorted")) {
|
|
bool sorted = PADDLE_GET_CONST(bool, desc.GetAttr("sorted"));
|
|
if (!sorted) {
|
|
VLOG(3) << op_type
|
|
<< " does not support results not sorted in "
|
|
"tensorrt";
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
#if IS_TRT_VERSION_GE(8000)
|
|
if (op_type == "sparse_fc" || op_type == "sparse_multihead_matmul") {
|
|
if (!with_dynamic_shape) {
|
|
VLOG(3) << "the sparse_fc and sparse_multihead_matmul does not support "
|
|
"static shape yet";
|
|
return false;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (op_type == "equal" || op_type == "not_equal") {
|
|
#if !IS_TRT_VERSION_GE(8000)
|
|
VLOG(3) << "equal is not supported when TensorRT < 8.0";
|
|
return false;
|
|
#else
|
|
// TRT does not support kEQUAL/kGREATER/kLESS work with implicit batch
|
|
if (!with_dynamic_shape) {
|
|
VLOG(3) << "the equal does not support "
|
|
"static shape yet";
|
|
return false;
|
|
}
|
|
if (!desc.HasAttr("axis")) {
|
|
return false;
|
|
}
|
|
int axis = PADDLE_GET_CONST(int, desc.GetAttr("axis"));
|
|
if (axis == 0) {
|
|
return false;
|
|
}
|
|
auto* block = desc.Block();
|
|
if (block == nullptr) {
|
|
VLOG(3) << "The block desc is nullptr, we can't continue to analyze. "
|
|
"Developers need to check whether block_desc is passed in "
|
|
"the pass.";
|
|
return false;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (op_type == "layernorm_shift_partition") {
|
|
if (!with_dynamic_shape) {
|
|
VLOG(3) << "the layernorm_shift_partition does not support "
|
|
"static shape yet";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (op_type == "preln_layernorm_shift_partition") {
|
|
if (!with_dynamic_shape) {
|
|
VLOG(3) << "the layernorm_shift_partition does not support "
|
|
"static shape yet";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (op_type == "merge_layernorm") {
|
|
if (!with_dynamic_shape) {
|
|
VLOG(3) << "The merge_layernorm op does not support "
|
|
"static shape yet";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (op_type == "reverse_roll") {
|
|
if (!with_dynamic_shape) {
|
|
VLOG(3) << "The reverse roll fused op does not support static shape "
|
|
"mode yet.";
|
|
return false;
|
|
}
|
|
}
|
|
if (op_type == "skip_merge_layernorm") {
|
|
if (!with_dynamic_shape) {
|
|
VLOG(3) << "The merge_layernorm op does not support "
|
|
"static shape yet";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (op_type == "skip_groupnorm_act") {
|
|
if (!with_dynamic_shape) {
|
|
VLOG(3) << "The skip_groupnorm_act op does not support "
|
|
"static shape yet";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (op_type == "preln_groupnorm_act") {
|
|
if (!with_dynamic_shape) {
|
|
VLOG(3) << "The preln_groupnorm_act op does not support "
|
|
"static shape yet";
|
|
return false;
|
|
}
|
|
}
|
|
if (op_type == "trans_layernorm") {
|
|
if (!with_dynamic_shape) {
|
|
VLOG(3) << "The trans_layernorm op does not support "
|
|
"static shape yet";
|
|
return false;
|
|
}
|
|
}
|
|
if (op_type == "fuse_eleadd_transpose") {
|
|
if (!with_dynamic_shape) {
|
|
VLOG(3) << "The fuse_eleadd_transpose op does not support "
|
|
"static shape yet";
|
|
return false;
|
|
}
|
|
}
|
|
if (op_type == "lookup_table" || op_type == "lookup_table_v2") {
|
|
if (!with_dynamic_shape) {
|
|
VLOG(3) << "the lookup_table does not support "
|
|
"static shape yet";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (op_type == "expand_as_v2" || op_type == "expand_v2") {
|
|
if (!with_dynamic_shape) {
|
|
VLOG(3) << "the " << op_type
|
|
<< "does not support "
|
|
"static shape yet";
|
|
return false;
|
|
}
|
|
|
|
auto inputs = desc.Inputs();
|
|
if (op_type == "expand_as_v2") {
|
|
if (!desc.HasAttr("target_shape") && inputs.find("Y") == inputs.end()) {
|
|
VLOG(3)
|
|
<< "expand_as_v2 op need have input(Y) or attr(target_shape). ";
|
|
return false;
|
|
}
|
|
} else if (op_type == "expand_v2") {
|
|
if (!desc.HasAttr("shape") && inputs.find("Shape") == inputs.end() &&
|
|
inputs.find("expand_shapes_tensor") == inputs.end()) {
|
|
VLOG(3) << "expand_v2 op need have input(Shape) or "
|
|
"input(expand_shapes_tensor) or attr(shape) . ";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
auto* block = desc.Block();
|
|
if (block == nullptr) {
|
|
VLOG(3) << "The block desc is nullptr, we can't continue to analyze. "
|
|
"Developers need to check whether block_desc is passed in "
|
|
"the pass.";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (op_type == "grid_sampler") {
|
|
#if !IS_TRT_VERSION_GE(8510)
|
|
VLOG(3) << "grid_sampler is not supported when TensorRT < 8.5.1";
|
|
return false;
|
|
#else
|
|
if (!with_dynamic_shape) {
|
|
VLOG(3) << "the grid_sampler does not support "
|
|
"static shape yet";
|
|
return false;
|
|
}
|
|
|
|
if (!desc.HasAttr("mode") || !desc.HasAttr("padding_mode") ||
|
|
!desc.HasAttr("align_corners")) {
|
|
VLOG(3) << "grid_sampler need attributes : mode, padding_mode, "
|
|
"align_corners";
|
|
return false;
|
|
}
|
|
|
|
auto* block = desc.Block();
|
|
if (block == nullptr) {
|
|
VLOG(3) << "The block desc is nullptr, we can't continue to analyze. "
|
|
"Developers need to check whether block_desc is passed in "
|
|
"the pass.";
|
|
return false;
|
|
}
|
|
auto input_name = desc.Input("X")[0];
|
|
auto* input_desc = block->FindVarRecursive(input_name);
|
|
const auto input_shape = input_desc->GetShape();
|
|
|
|
auto grid_name = desc.Input("Grid")[0];
|
|
auto* grid_desc = block->FindVarRecursive(grid_name);
|
|
const auto grid_shape = grid_desc->GetShape();
|
|
|
|
if (input_shape.size() != 4 || grid_shape.size() != 4) {
|
|
VLOG(3) << "The input and grid tensors must be shape tensors of rank 4 "
|
|
"using TRT GridSample layer.";
|
|
return false;
|
|
}
|
|
|
|
#endif
|
|
}
|
|
|
|
if (op_type == "cumsum") {
|
|
if (!with_dynamic_shape) {
|
|
VLOG(3) << "the cumsum does not support "
|
|
"static shape yet";
|
|
return false;
|
|
}
|
|
auto* block = desc.Block();
|
|
if (block == nullptr) {
|
|
VLOG(3) << "The block desc is nullptr, we can't continue to analyze. "
|
|
"Developers need to check whether block_desc is passed in "
|
|
"the pass.";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (op_type == "argsort") {
|
|
auto* block = desc.Block();
|
|
if (block == nullptr) {
|
|
VLOG(3) << "The block desc is nullptr, we can't continue to analyze. "
|
|
"Developers need to check whether block_desc is passed in "
|
|
"the pass.";
|
|
return false;
|
|
}
|
|
if (!desc.HasAttr("descending") || !desc.HasAttr("axis")) {
|
|
VLOG(3) << op_type << " needs attributes: descending and axis.";
|
|
}
|
|
auto x_var_name = desc.Input("X")[0];
|
|
auto* x_var_desc = block->FindVarRecursive(x_var_name);
|
|
std::vector<int64_t> shape = x_var_desc->GetShape();
|
|
int axis = PADDLE_GET_CONST(int, desc.GetAttr("axis"));
|
|
if (axis < 0) {
|
|
axis += shape.size();
|
|
}
|
|
if (shape[axis] > 3840 || shape[axis] < 0) {
|
|
VLOG(3) << op_type << " shape[" << axis << "] = " << shape[axis]
|
|
<< " is invalid, it should less than 3840 and greater than "
|
|
"zero in TensorRT.";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (op_type == "unbind") {
|
|
if (!with_dynamic_shape) {
|
|
VLOG(3) << "the unbind does not support "
|
|
"static shape yet";
|
|
return false;
|
|
}
|
|
auto* block = desc.Block();
|
|
if (block == nullptr) {
|
|
VLOG(3) << "The block desc is nullptr, we can't continue to analyze. "
|
|
"Developers need to check whether block_desc is passed in "
|
|
"the pass.";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (op_type == "isnan_v2") {
|
|
if (!with_dynamic_shape) {
|
|
VLOG(3) << "the isnan_v2 does not support "
|
|
"static shape yet";
|
|
return false;
|
|
}
|
|
auto* block = desc.Block();
|
|
if (block == nullptr) {
|
|
VLOG(3) << "The block desc is nullptr, we can't continue to analyze. "
|
|
"Developers need to check whether block_desc is passed in "
|
|
"the pass.";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (op_type == "p_norm") {
|
|
auto* block = desc.Block();
|
|
if (block == nullptr) {
|
|
VLOG(3) << "The block desc is nullptr, we can't continue to analyze. "
|
|
"Developers need to check whether block_desc is passed in "
|
|
"the pass.";
|
|
return false;
|
|
}
|
|
if (!(desc.HasAttr("asvector") && desc.HasAttr("axis") &&
|
|
desc.HasAttr("porder") && desc.HasAttr("keepdim"))) {
|
|
VLOG(3) << op_type << " op need attrs asvector, porder, axis, keepdim.";
|
|
return false;
|
|
}
|
|
bool asvector = PADDLE_GET_CONST(bool, desc.GetAttr("asvector"));
|
|
int axis = PADDLE_GET_CONST(int, desc.GetAttr("axis"));
|
|
double porder = PADDLE_GET_CONST(double, desc.GetAttr("porder"));
|
|
if (asvector || porder != 2.0 || axis != -1) {
|
|
VLOG(3) << op_type
|
|
<< " op only support asvector=False, porder=2, axis = -1.";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (op_type == "index_put") {
|
|
#if IS_TRT_VERSION_LT(8510)
|
|
VLOG(3) << "index_put is not supported when TensorRT < 8.5.1";
|
|
return false;
|
|
#endif
|
|
if (!with_dynamic_shape) {
|
|
VLOG(3) << "the index_put does not support "
|
|
"static shape yet";
|
|
return false;
|
|
}
|
|
auto* block = desc.Block();
|
|
if (block == nullptr) {
|
|
VLOG(3) << "The block desc is nullptr, we can't continue to analyze. "
|
|
"Developers need to check whether block_desc is passed in "
|
|
"the pass.";
|
|
return false;
|
|
}
|
|
auto value_var_name = desc.Input("value")[0];
|
|
auto* value_var_desc = block->FindVarRecursive(value_var_name);
|
|
const auto value_shape = value_var_desc->GetShape();
|
|
int value_num = std::accumulate(
|
|
value_shape.begin(), value_shape.end(), 1, std::multiplies<int>());
|
|
if (value_num != 1) {
|
|
VLOG(3) << op_type << " op only support value_num = 1 in tensorrt.";
|
|
return false;
|
|
}
|
|
auto indices_var_name = desc.Input("indices")[0];
|
|
auto* indices_var_desc = block->FindVarRecursive(indices_var_name);
|
|
auto dtype = indices_var_desc->GetDataType();
|
|
if (dtype != framework::proto::VarType::BOOL) {
|
|
VLOG(3) << op_type << " op only support bool indices in tensorrt.";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (op_type == "temporal_shift") {
|
|
#if !IS_TRT_VERSION_GE(8200)
|
|
VLOG(3) << "temporal_shift is not supported when TensorRT < 8.2";
|
|
return false;
|
|
#endif
|
|
|
|
if (!with_dynamic_shape) {
|
|
VLOG(3) << "the temporal shift does not support "
|
|
"static shape yet";
|
|
return false;
|
|
}
|
|
|
|
if (!desc.HasAttr("shift_ratio") || !desc.HasAttr("seg_num")) {
|
|
VLOG(3) << "temporal shift need attributes : shift_ratio and seg_num";
|
|
return false;
|
|
}
|
|
|
|
auto* block = desc.Block();
|
|
if (block == nullptr) {
|
|
VLOG(3) << "The block desc is nullptr, we can't continue to analyze. "
|
|
"Developers need to check whether block_desc is passed in "
|
|
"the pass.";
|
|
return false;
|
|
}
|
|
|
|
auto input_name = desc.Input("X")[0];
|
|
auto* input_desc = block->FindVarRecursive(input_name);
|
|
const auto input_shape = input_desc->GetShape();
|
|
|
|
if (input_shape.size() != 4) {
|
|
VLOG(3) << "The input and grid tensors must be shape tensors of rank 4 "
|
|
"using TRT TemporalShift layer.";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (op_type == "einsum") {
|
|
#if !IS_TRT_VERSION_GE(8200)
|
|
VLOG(3) << "einsum is not supported when TensorRT < 8.2";
|
|
return false;
|
|
#else
|
|
if (!with_dynamic_shape) {
|
|
VLOG(3) << "the einsum does not support "
|
|
"static shape yet";
|
|
return false;
|
|
}
|
|
auto operand_inputs = desc.Input("Operands");
|
|
if (operand_inputs.size() > 2) {
|
|
VLOG(3) << "TensorRT currently supports up to 2 input tensors"
|
|
<< "to einsum but operation had" << operand_inputs.size()
|
|
<< "input tensors !";
|
|
return false;
|
|
}
|
|
|
|
auto* block = desc.Block();
|
|
if (block == nullptr) {
|
|
VLOG(3) << "The block desc is nullptr, we can't continue to analyze. "
|
|
"Developers need to check whether block_desc is passed in "
|
|
"the pass.";
|
|
return false;
|
|
}
|
|
auto equation = PADDLE_GET_CONST(std::string, desc.GetAttr("equation"));
|
|
if (equation.find("...") != std::string::npos) {
|
|
VLOG(3) << "TensorRT currently does not support ellipses !";
|
|
return false;
|
|
}
|
|
#endif
|
|
}
|
|
if (op_type == "quantize_linear" || op_type == "dequantize_linear") {
|
|
#if !IS_TRT_VERSION_GE(8000)
|
|
VLOG(3) << "quantize / dequantize linear is not supported when TensorRT "
|
|
"< 8.0";
|
|
return false;
|
|
#else
|
|
return true;
|
|
#endif
|
|
}
|
|
|
|
if (op_type == "flip") {
|
|
if (!with_dynamic_shape) {
|
|
VLOG(3) << "the flip does not support "
|
|
"static shape yet";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (use_no_calib_int8) {
|
|
return int8_teller_set.count(op_type);
|
|
} else {
|
|
return teller_set.count(op_type);
|
|
}
|
|
}
|
|
|
|
private:
|
|
// use this set for no calib int8.
|
|
std::unordered_set<std::string> int8_teller_set{
|
|
"matrix_multiply",
|
|
"bmm",
|
|
"range",
|
|
"conv2d",
|
|
"fused_conv2d_add_act",
|
|
"pool2d",
|
|
"relu",
|
|
"elu",
|
|
"selu",
|
|
"softsign",
|
|
"softplus",
|
|
"stanh",
|
|
"thresholded_relu",
|
|
"exp",
|
|
"log",
|
|
"sqrt",
|
|
"abs",
|
|
"sin",
|
|
"cos",
|
|
"tan",
|
|
"sinh",
|
|
"cosh",
|
|
"asin",
|
|
"acos",
|
|
"atan",
|
|
"asinh",
|
|
"acosh",
|
|
"atanh",
|
|
"ceil",
|
|
"floor",
|
|
"rsqrt",
|
|
"sign",
|
|
"reciprocal",
|
|
"logical_not",
|
|
"erf",
|
|
"square",
|
|
"softmax",
|
|
"sigmoid",
|
|
"hard_swish",
|
|
"depthwise_conv2d",
|
|
"batch_norm",
|
|
"concat",
|
|
"tanh",
|
|
"pad3d",
|
|
"pad",
|
|
"elementwise_add",
|
|
"elementwise_sub",
|
|
"elementwise_mul",
|
|
"elementwise_div",
|
|
"elementwise_pow",
|
|
"elementwise_min",
|
|
"elementwise_max",
|
|
"elementwise_floordiv",
|
|
"elementwise_mod",
|
|
"equal",
|
|
"not_equal",
|
|
"less_than",
|
|
"greater_than",
|
|
"logical_or",
|
|
"logical_xor",
|
|
"logical_and",
|
|
"less_equal",
|
|
"greater_equal",
|
|
"dropout",
|
|
"fill_any_like",
|
|
"prelu",
|
|
"conv2d_transpose",
|
|
"depthwise_conv2d_transpose",
|
|
"leaky_relu",
|
|
"shuffle_channel",
|
|
"where",
|
|
"bitwise_not",
|
|
"one_hot",
|
|
"one_hot_v2",
|
|
"swish",
|
|
"silu",
|
|
"celu",
|
|
"split",
|
|
"instance_norm",
|
|
"gelu",
|
|
"layer_norm",
|
|
"scale",
|
|
"stack",
|
|
"transpose2",
|
|
"transpose",
|
|
"top_k",
|
|
"top_k_v2",
|
|
"flatten2",
|
|
"flatten",
|
|
"gather",
|
|
"gather_nd",
|
|
"group_norm",
|
|
"yolo_box",
|
|
"yolo_box_head",
|
|
"arg_max",
|
|
"arg_min",
|
|
"roi_align",
|
|
"affine_channel",
|
|
"nearest_interp",
|
|
"anchor_generator",
|
|
"reduce_max",
|
|
"reduce_min",
|
|
"reduce_mean",
|
|
"reduce_sum",
|
|
"reduce_prod",
|
|
"reduce_any",
|
|
"reduce_all",
|
|
"conv3d",
|
|
"conv3d_transpose",
|
|
"mish",
|
|
"nearest_interp_v2",
|
|
"bilinear_interp_v2",
|
|
"linear_interp_v2",
|
|
"pool3d",
|
|
"deformable_conv",
|
|
"relu6",
|
|
"hard_sigmoid",
|
|
"clip",
|
|
"prompt_tuning_emb_eltwise_layernorm",
|
|
"fused_embedding_eltwise_layernorm",
|
|
"multihead_matmul",
|
|
"multihead_matmul_roformer",
|
|
"skip_layernorm",
|
|
"slice",
|
|
"strided_slice",
|
|
"fused_preln_embedding_eltwise_layernorm",
|
|
"fused_bias_dropout_residual_layer_norm",
|
|
"c_allreduce_sum",
|
|
"roll",
|
|
"cast",
|
|
"preln_skip_layernorm",
|
|
"transformer_input_convert",
|
|
"recover_padding",
|
|
"remove_padding",
|
|
"fill_constant",
|
|
"sum",
|
|
"shape",
|
|
"squeeze2",
|
|
"unsqueeze2",
|
|
"index_put",
|
|
"layernorm_shift_partition",
|
|
"reverse_roll",
|
|
"take_along_axis",
|
|
"tanh_shrink",
|
|
"logsigmoid",
|
|
"preln_layernorm_shift_partition",
|
|
"lookup_table",
|
|
"lookup_table_v2",
|
|
"trans_layernorm",
|
|
"merge_layernorm",
|
|
"skip_merge_layernorm",
|
|
"expand_v2",
|
|
"expand_as_v2",
|
|
"fuse_eleadd_transpose",
|
|
"skip_groupnorm_act",
|
|
"preln_groupnorm_act",
|
|
"temporal_shift",
|
|
"grid_sampler",
|
|
"cumsum",
|
|
"unbind",
|
|
"isnan_v2",
|
|
"p_norm",
|
|
"assign",
|
|
"flip",
|
|
"quantize_linear",
|
|
"dequantize_linear",
|
|
"share_data",
|
|
"argsort",
|
|
"bitwise_and",
|
|
"bitwise_or",
|
|
"size"};
|
|
|
|
std::unordered_set<std::string> teller_set{
|
|
"matrix_multiply",
|
|
"bmm",
|
|
"range",
|
|
"conv2d",
|
|
"fused_conv2d_add_act",
|
|
"pool2d",
|
|
"relu",
|
|
"elu",
|
|
"selu",
|
|
"softsign",
|
|
"softplus",
|
|
"stanh",
|
|
"thresholded_relu",
|
|
"exp",
|
|
"log",
|
|
"sqrt",
|
|
"abs",
|
|
"sin",
|
|
"cos",
|
|
"tan",
|
|
"sinh",
|
|
"cosh",
|
|
"asin",
|
|
"acos",
|
|
"atan",
|
|
"asinh",
|
|
"acosh",
|
|
"atanh",
|
|
"ceil",
|
|
"floor",
|
|
"rsqrt",
|
|
"sign",
|
|
"reciprocal",
|
|
"logical_not",
|
|
"erf",
|
|
"square",
|
|
"softmax",
|
|
"sigmoid",
|
|
"hard_swish",
|
|
"depthwise_conv2d",
|
|
"batch_norm",
|
|
"concat",
|
|
"tanh",
|
|
"pad3d",
|
|
"pad",
|
|
"elementwise_add",
|
|
"elementwise_sub",
|
|
"elementwise_mul",
|
|
"elementwise_div",
|
|
"elementwise_pow",
|
|
"pow",
|
|
"elementwise_min",
|
|
"elementwise_max",
|
|
"elementwise_floordiv",
|
|
"elementwise_mod",
|
|
"equal",
|
|
"not_equal",
|
|
"less_than",
|
|
"greater_than",
|
|
"logical_or",
|
|
"logical_xor",
|
|
"logical_and",
|
|
"less_equal",
|
|
"greater_equal",
|
|
"dropout",
|
|
"fill_any_like",
|
|
"prelu",
|
|
"conv2d_transpose",
|
|
"depthwise_conv2d_transpose",
|
|
"leaky_relu",
|
|
"shuffle_channel",
|
|
"where",
|
|
"bitwise_not",
|
|
"one_hot",
|
|
"one_hot_v2",
|
|
"swish",
|
|
"silu",
|
|
"celu",
|
|
"split",
|
|
"instance_norm",
|
|
"gelu",
|
|
"layer_norm",
|
|
"scale",
|
|
"stack",
|
|
"transpose2",
|
|
"transpose",
|
|
"top_k",
|
|
"top_k_v2",
|
|
"flatten2",
|
|
"flatten",
|
|
"gather",
|
|
"gather_nd",
|
|
"yolo_box",
|
|
"yolo_box_head",
|
|
"arg_max",
|
|
"arg_min",
|
|
"roi_align",
|
|
"affine_channel",
|
|
"nearest_interp",
|
|
"anchor_generator",
|
|
"reduce_max",
|
|
"reduce_min",
|
|
"reduce_mean",
|
|
"reduce_sum",
|
|
"reduce_prod",
|
|
"reduce_any",
|
|
"reduce_all",
|
|
"conv3d",
|
|
"conv3d_transpose",
|
|
"mish",
|
|
"bilinear_interp_v2",
|
|
"linear_interp_v2",
|
|
"nearest_interp_v2",
|
|
"pool3d",
|
|
"deformable_conv",
|
|
"relu6",
|
|
"hard_sigmoid",
|
|
"clip",
|
|
"prompt_tuning_emb_eltwise_layernorm",
|
|
"fused_embedding_eltwise_layernorm",
|
|
"multihead_matmul",
|
|
"multihead_matmul_roformer",
|
|
"skip_layernorm",
|
|
"slice",
|
|
"strided_slice",
|
|
"fused_preln_embedding_eltwise_layernorm",
|
|
"preln_skip_layernorm",
|
|
"fused_bias_dropout_residual_layer_norm",
|
|
"c_allreduce_sum",
|
|
"roll",
|
|
"cast",
|
|
"transformer_input_convert",
|
|
"recover_padding",
|
|
"remove_padding",
|
|
"fill_constant",
|
|
"sum",
|
|
"shape",
|
|
"squeeze2",
|
|
"unsqueeze2",
|
|
"fused_token_prune",
|
|
"layernorm_shift_partition",
|
|
"reverse_roll",
|
|
"tanh_shrink",
|
|
"index_put",
|
|
"take_along_axis",
|
|
"logsigmoid",
|
|
"preln_layernorm_shift_partition",
|
|
"trans_layernorm",
|
|
"merge_layernorm",
|
|
"skip_merge_layernorm",
|
|
"lookup_table",
|
|
"lookup_table_v2",
|
|
"expand_v2",
|
|
"expand_as_v2",
|
|
"fuse_eleadd_transpose",
|
|
"skip_groupnorm_act",
|
|
"preln_groupnorm_act",
|
|
"temporal_shift",
|
|
"grid_sampler",
|
|
"cumsum",
|
|
"unbind",
|
|
"isnan_v2",
|
|
"p_norm",
|
|
"assign",
|
|
"flip",
|
|
"quantize_linear",
|
|
"dequantize_linear",
|
|
"share_data",
|
|
"argsort",
|
|
"bitwise_and",
|
|
"bitwise_or",
|
|
"size"};
|
|
};
|
|
|
|
struct GenericPluginTeller : public Teller {
|
|
public:
|
|
GenericPluginTeller() = default;
|
|
bool operator()(const framework::OpDesc& desc,
|
|
bool use_no_calib_int8 = false,
|
|
bool with_dynamic_shape = false,
|
|
bool forbid_dynamic_op_enter_into_trt = false,
|
|
bool use_explicit_quantization = false) override {
|
|
const std::string op_type = desc.Type();
|
|
|
|
// only consider dynamic_shape mode
|
|
if (!with_dynamic_shape) {
|
|
return false;
|
|
}
|
|
if (op_type == "yolo_box") {
|
|
if (!desc.HasAttr("iou_aware") && !desc.HasAttr("iou_aware_factor"))
|
|
return false;
|
|
} else if (op_type == "solve") {
|
|
auto x_var_name = desc.Input("X")[0];
|
|
auto y_var_name = desc.Input("Y")[0];
|
|
auto* block = desc.Block();
|
|
if (block == nullptr) {
|
|
VLOG(3) << "The block desc is nullptr, we can't continue to analyze. "
|
|
"Developers need to check whether block_desc is passed in "
|
|
"the pass.";
|
|
return false;
|
|
}
|
|
auto* x_var_desc = block->FindVar(x_var_name);
|
|
auto* y_var_desc = block->FindVar(y_var_name);
|
|
auto x_dtype = x_var_desc->GetDataType();
|
|
auto y_dtype = y_var_desc->GetDataType();
|
|
if (x_dtype == framework::proto::VarType::FP64 ||
|
|
y_dtype == framework::proto::VarType::FP64) {
|
|
VLOG(3) << op_type << " not support input of FP64.";
|
|
return false;
|
|
}
|
|
}
|
|
// TODO(lizexu123): the tensorrt version on Windows supports low-level
|
|
// and inconsistent supportformation
|
|
if (op_type == "argsort") {
|
|
if (!with_dynamic_shape) {
|
|
VLOG(3) << "Ops(" << op_type << ") do not support static shape yet.";
|
|
return false;
|
|
}
|
|
}
|
|
if (use_no_calib_int8) {
|
|
return false;
|
|
} else {
|
|
framework::InitDefaultKernelSignatureMap();
|
|
bool res = phi::OpUtilsMap::Instance().HasArgumentMappingFn(op_type) ||
|
|
phi::DefaultKernelSignatureMap::Instance().Has(op_type);
|
|
if (!res) {
|
|
VLOG(3) << op_type << " has no KernelSignature";
|
|
return false;
|
|
}
|
|
res = phi::KernelFactory::Instance().HasCompatiblePhiKernel(op_type);
|
|
if (!res) {
|
|
VLOG(3) << op_type << " has no CompatiblePhiKernel in phi.";
|
|
return false;
|
|
}
|
|
auto& dynamic_infermeta_factory =
|
|
tensorrt::DynamicMetaFnFactory::Instance();
|
|
res = dynamic_infermeta_factory.Contains(op_type);
|
|
if (!res) {
|
|
VLOG(3) << op_type << " has no DynamicMetaFn.";
|
|
return false;
|
|
}
|
|
if (forbid_dynamic_op_enter_into_trt && IsDynamicShapeOp(desc)) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
};
|
|
|
|
struct CustomPluginTeller : public Teller {
|
|
public:
|
|
CustomPluginTeller() = default;
|
|
bool operator()(const framework::OpDesc& desc,
|
|
bool use_no_calib_int8 = false,
|
|
bool with_dynamic_shape = false,
|
|
bool forbid_dynamic_op_enter_into_trt = false,
|
|
bool use_explicit_quantization = false) override {
|
|
const std::string op_type = desc.Type();
|
|
std::string expect_plugin_name;
|
|
|
|
if (with_dynamic_shape) {
|
|
expect_plugin_name = op_type + "_paddle_trt_dynamic_plugin";
|
|
} else {
|
|
expect_plugin_name = op_type + "_paddle_trt_plugin";
|
|
}
|
|
|
|
int num = 0;
|
|
auto creators = GetPluginRegistry()->getPluginCreatorList(&num);
|
|
|
|
for (int i = 0; i < num; i++) {
|
|
if (std::string(creators[i]->getPluginName()) == expect_plugin_name)
|
|
return true;
|
|
}
|
|
return false;
|
|
if (forbid_dynamic_op_enter_into_trt && IsDynamicShapeOp(desc)) {
|
|
return false;
|
|
}
|
|
}
|
|
};
|
|
|
|
struct CustomGenericPluginTeller : public Teller {
|
|
CustomGenericPluginTeller() = default;
|
|
bool operator()(const framework::OpDesc& desc,
|
|
bool use_no_calib_int8 = false,
|
|
bool with_dynamic_shape = false,
|
|
bool forbid_dynamic_op_enter_into_trt = false,
|
|
bool use_explicit_quantization = false) override {
|
|
const std::string op_type = desc.Type();
|
|
|
|
auto& op_meta_info_map = OpMetaInfoMap::Instance();
|
|
const auto& meta_info_map = op_meta_info_map.GetMap();
|
|
if (meta_info_map.count(op_type) > 0) {
|
|
auto& op_info = meta_info_map.at(op_type).front();
|
|
auto& trt_infer_shape_fn = OpMetaInfoHelper::GetTrtInferShapeFn(op_info);
|
|
if (trt_infer_shape_fn == nullptr) {
|
|
VLOG(3) << op_type
|
|
<< " has no trt getOutputDimensions function. Please set by "
|
|
"SetTrtInferShapeFn.";
|
|
return false;
|
|
}
|
|
auto& trt_supports_format_config =
|
|
OpMetaInfoHelper::GetTrtSupportsFormatConfig(op_info);
|
|
if (trt_supports_format_config.empty()) {
|
|
VLOG(3)
|
|
<< op_type
|
|
<< " has no trt supportsFormatCombination config. Please set by "
|
|
"SetTrtSupportsFormatConfig.";
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
VLOG(3) << op_type << " has no meta info";
|
|
return false;
|
|
if (forbid_dynamic_op_enter_into_trt && IsDynamicShapeOp(desc)) {
|
|
return false;
|
|
}
|
|
}
|
|
};
|
|
|
|
bool OpTeller::Tell(const framework::ir::Node* node,
|
|
bool use_no_calib_int8,
|
|
bool with_dynamic_shape,
|
|
bool forbid_dynamic_op_enter_into_trt,
|
|
bool use_explicit_quantization) {
|
|
const std::string op_type = node->Op()->Type();
|
|
const framework::OpDesc desc = *node->Op();
|
|
|
|
// do not support the op which is labeled the `skip_quant`
|
|
if ((desc.HasAttr("namescope") &&
|
|
PADDLE_GET_CONST(std::string, desc.GetAttr("op_namescope")) ==
|
|
"/skip_quant_2/") ||
|
|
desc.HasAttr("skip_quant"))
|
|
return false;
|
|
auto& default_teller = GetDefaultTeller();
|
|
if ((*default_teller)(desc,
|
|
use_no_calib_int8,
|
|
with_dynamic_shape,
|
|
forbid_dynamic_op_enter_into_trt,
|
|
use_explicit_quantization)) {
|
|
SetOpConverterType(node->Op(), OpConverterType::Default);
|
|
return true;
|
|
}
|
|
auto& generic_plugin_teller = GetGenericPluginTeller();
|
|
if ((*generic_plugin_teller)(desc,
|
|
use_no_calib_int8,
|
|
with_dynamic_shape,
|
|
forbid_dynamic_op_enter_into_trt,
|
|
use_explicit_quantization)) {
|
|
SetOpConverterType(node->Op(), OpConverterType::GenericPluginCreator);
|
|
return true;
|
|
}
|
|
auto& custom_plugin_teller = GetCustomPluginTeller();
|
|
if ((*custom_plugin_teller)(desc,
|
|
use_no_calib_int8,
|
|
with_dynamic_shape,
|
|
forbid_dynamic_op_enter_into_trt,
|
|
use_explicit_quantization)) {
|
|
SetOpConverterType(node->Op(), OpConverterType::CustomPluginCreator);
|
|
return true;
|
|
}
|
|
auto& custom_generic_plugin_teller = GetCustomGenericPluginTeller();
|
|
if ((*custom_generic_plugin_teller)(desc,
|
|
use_no_calib_int8,
|
|
with_dynamic_shape,
|
|
forbid_dynamic_op_enter_into_trt,
|
|
use_explicit_quantization)) {
|
|
SetOpConverterType(node->Op(), OpConverterType::CustomGenericPluginCreator);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
OpTeller::OpTeller() { // NOLINT
|
|
tellers_.emplace_back(new tensorrt::SimpleOpTypeSetTeller);
|
|
tellers_.emplace_back(new tensorrt::GenericPluginTeller);
|
|
tellers_.emplace_back(new tensorrt::CustomPluginTeller);
|
|
tellers_.emplace_back(new tensorrt::CustomGenericPluginTeller);
|
|
}
|
|
|
|
} // namespace paddle::inference::tensorrt
|