chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:40:42 +08:00
commit e25996e7db
15472 changed files with 3536181 additions and 0 deletions
@@ -0,0 +1,74 @@
list(
APPEND
TRT_FILES
trt_plugin.cc
split_op_plugin.cu
elementwise_op_plugin.cu
gelu_op_plugin.cu
pool_op_plugin.cu
swish_op_plugin.cu
group_norm_op_plugin.cu
layer_norm_op_plugin.cu
instance_norm_op_plugin.cu
qkv_to_context_plugin.cu
hard_swish_op_plugin.cu
stack_op_plugin.cu
anchor_generator_op_plugin.cu
yolo_box_op_plugin.cu
yolo_box_head_op_plugin.cu
roi_align_op_plugin.cu
gather_nd_op_plugin.cu
mish_op_plugin.cu
pool3d_op_plugin.cu
deformable_conv_op_plugin.cu
matmul_op_int8_plugin.cu
multihead_matmul_roformer_plugin.cu
transformer_input_output_convert_plugin.cu
remove_padding_plugin.cu
recover_padding_plugin.cu
c_allreduce_op_plugin.cu
preln_residual_bias_plugin.cu
fused_token_prune_op_plugin.cu
layernorm_shift_partition_op.cu
reverse_roll_op_plugin.cu
preln_layernorm_shift_partition_op.cu
trans_layernorm_op_plugin.cu
merge_layernorm_op_plugin.cu
skip_merge_layernorm_op_plugin.cu
skip_groupnorm_act_op_plugin.cu
preln_groupnorm_act_op_plugin.cu
elementwiseadd_transpose_op_plugin.cu
generic_plugin.cu
custom_generic_plugin.cu
many_emb_layernorm_plugin.cu
many_emb_layernorm_kernel.cu
prompt_tuning_emb_layernorm_varseqlen_kernel_hface.cu
prompt_tuning_emb_layernorm_varseqlen_plugin.cu)
list(APPEND TRT_FILES many_emb_layernorm_varseqlen_plugin.cu
many_emb_layernorm_varseqlen_kernel_mtron.cu
many_emb_layernorm_varseqlen_kernel_hface.cu)
if(CUSPARSELT_FOUND)
list(APPEND TRT_FILES spmm_plugin.cu)
endif()
if(WIN32)
nv_library(
tensorrt_plugin
SRCS ${TRT_FILES}
DEPS phi
tensorrt_engine
tensor
common
tensorrt_dynamic_shape_infermeta_factory
tensorrt_plugin_arg_mapping_context
dynload_tensorrt)
else()
nv_library(
tensorrt_plugin
SRCS ${TRT_FILES}
DEPS phi tensorrt_engine tensor common
tensorrt_dynamic_shape_infermeta_factory
tensorrt_plugin_arg_mapping_context)
endif()
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,326 @@
// Copyright (c) 2018 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.
#pragma once
#include <string>
#include <vector>
#include "paddle/fluid/inference/tensorrt/engine.h"
#include "paddle/fluid/inference/tensorrt/plugin/trt_plugin.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
class AnchorGeneratorPlugin : public nvinfer1::IPluginV2Ext {
public:
explicit AnchorGeneratorPlugin(const nvinfer1::DataType,
const std::vector<float>& anchor_sizes,
const std::vector<float>& aspect_ratios,
const std::vector<float>& stride,
const std::vector<float>& variances,
const float offset,
const int height,
const int width,
const int num_anchors,
const int box_num);
AnchorGeneratorPlugin(const void* data, size_t length);
~AnchorGeneratorPlugin() override;
const char* getPluginType() const TRT_NOEXCEPT override;
const char* getPluginVersion() const TRT_NOEXCEPT override;
int getNbOutputs() const TRT_NOEXCEPT override;
nvinfer1::Dims getOutputDimensions(int index,
const nvinfer1::Dims* inputs,
int nb_input_dims) TRT_NOEXCEPT override;
bool supportsFormat(nvinfer1::DataType type, nvinfer1::TensorFormat format)
const TRT_NOEXCEPT override;
size_t getWorkspaceSize(int max_batch_size) const TRT_NOEXCEPT override;
int enqueue(int batch_size,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
int initialize() TRT_NOEXCEPT override;
void terminate() TRT_NOEXCEPT override;
size_t getSerializationSize() const TRT_NOEXCEPT override;
void serialize(void* buffer) const TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override;
void setPluginNamespace(const char* lib_namespace) TRT_NOEXCEPT override;
const char* getPluginNamespace() const TRT_NOEXCEPT override;
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* input_type,
int nb_inputs) const
TRT_NOEXCEPT override;
bool isOutputBroadcastAcrossBatch(int output_index,
const bool* input_is_broadcast,
int nb_inputs) const TRT_NOEXCEPT override;
bool canBroadcastInputAcrossBatch(int input_index) const
TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::Dims* input_dims,
int nb_inputs,
const nvinfer1::Dims* output_dims,
int nb_outputs,
const nvinfer1::DataType* input_types,
const nvinfer1::DataType* output_types,
const bool* input_is_broadcast,
const bool* output_is_broadcast,
nvinfer1::PluginFormat float_format,
int max_batch_size) TRT_NOEXCEPT override;
nvinfer1::IPluginV2Ext* clone() const TRT_NOEXCEPT override;
private:
template <typename T>
int enqueue_impl(int batch_size,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream);
nvinfer1::DataType data_type_;
std::vector<float> anchor_sizes_;
std::vector<float> aspect_ratios_;
std::vector<float> stride_;
std::vector<float> variances_;
float offset_;
void* anchor_sizes_device_;
void* aspect_ratios_device_;
void* stride_device_;
void* variances_device_;
int height_;
int width_;
int num_anchors_;
int box_num_;
std::string namespace_;
};
class AnchorGeneratorPluginCreator : public nvinfer1::IPluginCreator {
public:
AnchorGeneratorPluginCreator() = default;
~AnchorGeneratorPluginCreator() override = default;
void setPluginNamespace(const char* lib_namespace) TRT_NOEXCEPT override;
const char* getPluginNamespace() const TRT_NOEXCEPT override;
const char* getPluginName() const TRT_NOEXCEPT override;
const char* getPluginVersion() const TRT_NOEXCEPT override;
const nvinfer1::PluginFieldCollection* getFieldNames() TRT_NOEXCEPT override;
nvinfer1::IPluginV2Ext* createPlugin(
const char* name,
const nvinfer1::PluginFieldCollection* fc) TRT_NOEXCEPT override;
nvinfer1::IPluginV2Ext* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override;
private:
std::string namespace_;
nvinfer1::PluginFieldCollection field_collection_;
};
REGISTER_TRT_PLUGIN_V2(AnchorGeneratorPluginCreator);
class AnchorGeneratorPluginDynamic : public DynamicPluginTensorRT {
public:
explicit AnchorGeneratorPluginDynamic(const nvinfer1::DataType data_type,
const std::vector<float>& anchor_sizes,
const std::vector<float>& aspect_ratios,
const std::vector<float>& stride,
const std::vector<float>& variances,
const float offset,
const int num_anchors);
AnchorGeneratorPluginDynamic(void const* data, size_t length);
~AnchorGeneratorPluginDynamic();
nvinfer1::IPluginV2DynamicExt* clone() const TRT_NOEXCEPT override;
nvinfer1::DimsExprs getOutputDimensions(
int outputIndex,
const nvinfer1::DimsExprs* inputs,
int nbInputs,
nvinfer1::IExprBuilder& exprBuilder) // NOLINT
TRT_NOEXCEPT override;
bool supportsFormatCombination(int pos,
const nvinfer1::PluginTensorDesc* inOut,
int nbInputs,
int nbOutputs) TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::DynamicPluginTensorDesc* in,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc* out,
int nbOutputs) TRT_NOEXCEPT override;
size_t getWorkspaceSize(const nvinfer1::PluginTensorDesc* inputs,
int nbInputs,
const nvinfer1::PluginTensorDesc* outputs,
int nbOutputs) const TRT_NOEXCEPT override;
int enqueue(const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* inputTypes,
int nbInputs) const
TRT_NOEXCEPT override;
const char* getPluginType() const TRT_NOEXCEPT override;
int getNbOutputs() const TRT_NOEXCEPT override;
int initialize() TRT_NOEXCEPT override;
void terminate() TRT_NOEXCEPT override;
size_t getSerializationSize() const TRT_NOEXCEPT override;
void serialize(void* buffer) const TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override;
private:
template <typename T>
int enqueue_impl(const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream);
nvinfer1::DataType data_type_;
std::vector<float> anchor_sizes_;
std::vector<float> aspect_ratios_;
std::vector<float> stride_;
std::vector<float> variances_;
float offset_;
void* anchor_sizes_device_;
void* aspect_ratios_device_;
void* stride_device_;
void* variances_device_;
int num_anchors_;
std::string namespace_;
};
class AnchorGeneratorPluginDynamicCreator : public nvinfer1::IPluginCreator {
public:
AnchorGeneratorPluginDynamicCreator() = default;
~AnchorGeneratorPluginDynamicCreator() override = default;
void setPluginNamespace(const char* lib_namespace) TRT_NOEXCEPT override;
const char* getPluginNamespace() const TRT_NOEXCEPT override;
const char* getPluginName() const TRT_NOEXCEPT override;
const char* getPluginVersion() const TRT_NOEXCEPT override;
const nvinfer1::PluginFieldCollection* getFieldNames() TRT_NOEXCEPT override;
nvinfer1::IPluginV2Ext* createPlugin(
const char* name,
const nvinfer1::PluginFieldCollection* fc) TRT_NOEXCEPT override;
nvinfer1::IPluginV2Ext* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override;
private:
std::string namespace_;
nvinfer1::PluginFieldCollection field_collection_;
};
class PIRAnchorGeneratorPluginDynamic : public DynamicPluginTensorRT {
public:
explicit PIRAnchorGeneratorPluginDynamic(
const nvinfer1::DataType data_type,
const std::vector<float>& anchor_sizes,
const std::vector<float>& aspect_ratios,
const std::vector<float>& stride,
const std::vector<float>& variances,
const float offset,
const int num_anchors);
PIRAnchorGeneratorPluginDynamic(void const* data, size_t length);
~PIRAnchorGeneratorPluginDynamic();
nvinfer1::IPluginV2DynamicExt* clone() const TRT_NOEXCEPT override;
nvinfer1::DimsExprs getOutputDimensions(
int outputIndex,
const nvinfer1::DimsExprs* inputs,
int nbInputs,
nvinfer1::IExprBuilder& exprBuilder) // NOLINT
TRT_NOEXCEPT override;
bool supportsFormatCombination(int pos,
const nvinfer1::PluginTensorDesc* inOut,
int nbInputs,
int nbOutputs) TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::DynamicPluginTensorDesc* in,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc* out,
int nbOutputs) TRT_NOEXCEPT override;
size_t getWorkspaceSize(const nvinfer1::PluginTensorDesc* inputs,
int nbInputs,
const nvinfer1::PluginTensorDesc* outputs,
int nbOutputs) const TRT_NOEXCEPT override;
int enqueue(const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* inputTypes,
int nbInputs) const
TRT_NOEXCEPT override;
const char* getPluginType() const TRT_NOEXCEPT override;
int getNbOutputs() const TRT_NOEXCEPT override;
int initialize() TRT_NOEXCEPT override;
void terminate() TRT_NOEXCEPT override;
size_t getSerializationSize() const TRT_NOEXCEPT override;
void serialize(void* buffer) const TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override;
private:
template <typename T>
int enqueue_impl(const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream);
nvinfer1::DataType data_type_;
std::vector<float> anchor_sizes_;
std::vector<float> aspect_ratios_;
std::vector<float> stride_;
std::vector<float> variances_;
float offset_;
void* anchor_sizes_device_;
void* aspect_ratios_device_;
void* stride_device_;
void* variances_device_;
int num_anchors_;
std::string namespace_;
};
class PIRAnchorGeneratorPluginDynamicCreator : public nvinfer1::IPluginCreator {
public:
PIRAnchorGeneratorPluginDynamicCreator() = default;
~PIRAnchorGeneratorPluginDynamicCreator() override = default;
void setPluginNamespace(const char* lib_namespace) TRT_NOEXCEPT override;
const char* getPluginNamespace() const TRT_NOEXCEPT override;
const char* getPluginName() const TRT_NOEXCEPT override;
const char* getPluginVersion() const TRT_NOEXCEPT override;
const nvinfer1::PluginFieldCollection* getFieldNames() TRT_NOEXCEPT override;
nvinfer1::IPluginV2Ext* createPlugin(
const char* name,
const nvinfer1::PluginFieldCollection* fc) TRT_NOEXCEPT override;
nvinfer1::IPluginV2Ext* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override;
private:
std::string namespace_;
nvinfer1::PluginFieldCollection field_collection_;
};
REGISTER_TRT_PLUGIN_V2(AnchorGeneratorPluginDynamicCreator);
REGISTER_TRT_PLUGIN_V2(PIRAnchorGeneratorPluginDynamicCreator);
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,234 @@
// Copyright (c) 2021 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 <cstring>
#include "glog/logging.h"
#include "paddle/fluid/inference/tensorrt/plugin/c_allreduce_op_plugin.h"
#include "paddle/phi/core/distributed/comm_context_manager.h"
#include "paddle/phi/core/distributed/utils.h"
#include "paddle/phi/core/platform/collective_helper.h"
#if defined(PADDLE_WITH_NCCL) || defined(PADDLE_WITH_RCCL)
#include "paddle/phi/core/distributed/nccl_comm_context.h"
#endif
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
#if defined(PADDLE_WITH_NCCL)
inline ncclDataType_t NvInferDtypeToNCCLDType(nvinfer1::DataType type) {
if (type == nvinfer1::DataType::kFLOAT) {
return ncclFloat;
} else if (type == nvinfer1::DataType::kHALF) {
return ncclFloat16;
} else if (type == nvinfer1::DataType::kINT8) {
return ncclInt8;
} else if (type == nvinfer1::DataType::kINT32) {
return ncclInt32;
} else {
PADDLE_THROW(common::errors::Unimplemented(
"This datatype in nccl is not supported."));
}
}
#endif
CAllReducePluginDynamic::CAllReducePluginDynamic(void const* serialData,
size_t serialLength) {
DeserializeValue(&serialData, &serialLength, &ring_id_);
DeserializeValue(&serialData, &serialLength, &use_calc_stream_);
DeserializeValue(&serialData, &serialLength, &red_type_);
DeserializeValue(&serialData, &serialLength, &with_fp16_);
}
nvinfer1::IPluginV2DynamicExt* CAllReducePluginDynamic::clone() const
TRT_NOEXCEPT {
return new CAllReducePluginDynamic(
ring_id_, use_calc_stream_, red_type_, with_fp16_);
}
const char* CAllReducePluginDynamic::getPluginType() const TRT_NOEXCEPT {
return "c_allreduce_plugin_dynamic";
}
int CAllReducePluginDynamic::getNbOutputs() const TRT_NOEXCEPT { return 1; }
int CAllReducePluginDynamic::initialize() TRT_NOEXCEPT { return 0; };
size_t CAllReducePluginDynamic::getSerializationSize() const TRT_NOEXCEPT {
return SerializedSize(ring_id_) + SerializedSize(use_calc_stream_) +
SerializedSize(red_type_);
+SerializedSize(with_fp16_);
}
void CAllReducePluginDynamic::serialize(void* buffer) const TRT_NOEXCEPT {
SerializeValue(&buffer, ring_id_);
SerializeValue(&buffer, use_calc_stream_);
SerializeValue(&buffer, red_type_);
SerializeValue(&buffer, with_fp16_);
}
nvinfer1::DimsExprs CAllReducePluginDynamic::getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs* inputs,
int nb_inputs,
nvinfer1::IExprBuilder& expr_builder) TRT_NOEXCEPT {
return inputs[0];
}
bool CAllReducePluginDynamic::supportsFormatCombination(
int pos,
const nvinfer1::PluginTensorDesc* in_out,
int nb_inputs,
int nb_outputs) TRT_NOEXCEPT {
PADDLE_ENFORCE_NOT_NULL(
in_out,
common::errors::InvalidArgument(
"The input of CAllReduce plugin should not be nullptr."));
PADDLE_ENFORCE_LT(
pos,
nb_inputs + nb_outputs,
common::errors::InvalidArgument("The pos(%d) should be less than the "
"num(%d) of the input and the output.",
pos,
nb_inputs + nb_outputs));
const nvinfer1::PluginTensorDesc& in = in_out[pos];
if (pos == 0 || pos == 1) {
if (with_fp16_) {
return (in.type == nvinfer1::DataType::kHALF) &&
(in.format == nvinfer1::TensorFormat::kLINEAR);
} else {
return (in.type == nvinfer1::DataType::kFLOAT) &&
(in.format == nvinfer1::TensorFormat::kLINEAR);
}
}
}
void CAllReducePluginDynamic::configurePlugin(
const nvinfer1::DynamicPluginTensorDesc* in,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc* out,
int nbOutputs) TRT_NOEXCEPT {}
size_t CAllReducePluginDynamic::getWorkspaceSize(
const nvinfer1::PluginTensorDesc* inputs,
int nbInputs,
const nvinfer1::PluginTensorDesc* outputs,
int nbOutputs) const TRT_NOEXCEPT {
return 0;
}
void CAllReducePluginDynamic::destroy() TRT_NOEXCEPT { delete this; }
nvinfer1::DataType CAllReducePluginDynamic::getOutputDataType(
int index,
const nvinfer1::DataType* input_types,
int nb_inputs) const TRT_NOEXCEPT {
PADDLE_ENFORCE_EQ(index,
0,
common::errors::InvalidArgument(
"The CAllReduce Plugin only has one input, so the "
"index value should be 0, but get %d.",
index));
return input_types[0];
}
int CAllReducePluginDynamic::enqueue(
const nvinfer1::PluginTensorDesc* input_desc,
const nvinfer1::PluginTensorDesc* output_desc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT {
#if defined(PADDLE_WITH_NCCL)
auto input_dims = input_desc[0].dims;
size_t numel = ProductDim(input_dims);
auto input_type = input_desc[0].type;
void* sendbuff = const_cast<void*>(inputs[0]);
void* recvbuff = outputs[0];
ncclDataType_t dtype = NvInferDtypeToNCCLDType(input_type);
ncclRedOp_t nccl_red_type = ncclSum;
switch (red_type_) {
case kRedSum:
nccl_red_type = ncclSum;
break;
case kRedMax:
nccl_red_type = ncclMax;
break;
case kRedMin:
nccl_red_type = ncclMin;
break;
case kRedProd:
nccl_red_type = ncclProd;
break;
default:
PADDLE_THROW(common::errors::InvalidArgument("Invalid reduce type: %d",
red_type_));
}
const auto& comm_context_manager =
phi::distributed::CommContextManager::GetInstance();
PADDLE_ENFORCE_EQ(comm_context_manager.Has(std::to_string(ring_id_)),
true,
common::errors::InvalidArgument(
"You choose to use new communication library. "
"But ring_id(%d) is "
"not found in comm_context_manager.",
std::to_string(ring_id_)));
auto comm_ctx = static_cast<phi::distributed::NCCLCommContext*>(
comm_context_manager.Get(std::to_string(ring_id_)));
PADDLE_ENFORCE_NE(comm_ctx,
nullptr,
common::errors::Unavailable(
"NCCLCommContext is nullptr, collective op should "
"has ring_id attr."));
auto stream2 = comm_ctx->GetStream();
// ncclRedOp_t nccl_red_type = ncclSum;
// comm_ctx->AllReduce(&inputs[0], inputs[0], nccl_red_type, stream);
phi::dynload::ncclAllReduce(sendbuff,
recvbuff,
numel,
dtype,
nccl_red_type,
comm_ctx->GetNcclComm(),
stream2);
VLOG(3) << "new NCCLCommContext has ring_id_ " << ring_id_;
#endif
return (cudaGetLastError() != cudaSuccess);
}
const char* CAllReducePluginDynamicCreator::getPluginName() const TRT_NOEXCEPT {
return "c_allreduce_plugin_dynamic";
}
const char* CAllReducePluginDynamicCreator::getPluginVersion() const
TRT_NOEXCEPT {
return "1";
}
nvinfer1::IPluginV2* CAllReducePluginDynamicCreator::deserializePlugin(
const char* name,
const void* serial_data,
size_t serial_length) TRT_NOEXCEPT {
auto plugin = new CAllReducePluginDynamic(serial_data, serial_length);
return plugin;
}
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,112 @@
// Copyright (c) 2021 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.
#pragma once
#include <stdio.h>
#include <string>
#include <vector>
#include "paddle/fluid/inference/tensorrt/engine.h"
#include "paddle/fluid/inference/tensorrt/plugin/trt_plugin.h"
#include "paddle/fluid/platform/enforce.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
enum ReduceType { kRedSum, kRedMax, kRedMin, kRedProd };
class CAllReducePluginDynamic : public DynamicPluginTensorRT {
private:
int ring_id_;
bool use_calc_stream_;
ReduceType red_type_;
public:
explicit CAllReducePluginDynamic(const int ring_id,
const bool use_calc_stream,
const ReduceType red_type,
const bool with_fp16) {
ring_id_ = ring_id;
use_calc_stream_ = use_calc_stream;
red_type_ = red_type;
with_fp16_ = with_fp16;
}
CAllReducePluginDynamic(void const* serialData, size_t serialLength);
nvinfer1::IPluginV2DynamicExt* clone() const TRT_NOEXCEPT override;
const char* getPluginType() const TRT_NOEXCEPT override;
int getNbOutputs() const TRT_NOEXCEPT override;
int initialize() TRT_NOEXCEPT override;
size_t getSerializationSize() const TRT_NOEXCEPT override;
void serialize(void* buffer) const TRT_NOEXCEPT override;
nvinfer1::DimsExprs getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs* inputs,
int nb_inputs,
nvinfer1::IExprBuilder& expr_builder) // NOLINT
TRT_NOEXCEPT override;
bool supportsFormatCombination(int pos,
const nvinfer1::PluginTensorDesc* inOut,
int nbInputs,
int nbOutputs) TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::DynamicPluginTensorDesc* in,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc* out,
int nbOutputs) TRT_NOEXCEPT override;
size_t getWorkspaceSize(const nvinfer1::PluginTensorDesc* inputs,
int nbInputs,
const nvinfer1::PluginTensorDesc* outputs,
int nbOutputs) const TRT_NOEXCEPT override;
int enqueue(const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* inputTypes,
int nbInputs) const
TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override;
};
class CAllReducePluginDynamicCreator : public TensorRTPluginCreator {
public:
const char* getPluginName() const TRT_NOEXCEPT override;
const char* getPluginVersion() const TRT_NOEXCEPT override;
nvinfer1::IPluginV2* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override;
};
REGISTER_TRT_PLUGIN_V2(CAllReducePluginDynamicCreator);
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,222 @@
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
// SPDX-FileCopyrightText: Copyright (c) 1993-2022 NVIDIA CORPORATION &
// AFFILIATES. 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.
#pragma once
#include <cublas_v2.h>
#include <cuda_fp16.h>
#include <cuda_runtime_api.h>
#include <algorithm>
#include <cassert>
#include <memory>
#include <numeric>
#include <stdexcept>
#include <vector>
#include "NvInfer.h"
#include "NvInferRuntimeCommon.h"
#include "paddle/fluid/inference/tensorrt/plugin/common/plugin.h"
#define TRT_UNUSED (void)
#define BERT_PRINT_DEBUG_MSG 0
#if BERT_PRINT_DEBUG_MSG
#define TRANSFORMER_DEBUG_MSG(msg) (gLogVerbose << (msg) << std::endl)
#define BERT_DEBUG_VALUE(key, value) (gLogVerbose << key << value << std::endl)
#else
#define TRANSFORMER_DEBUG_MSG(msg) TRT_UNUSED(msg)
#define BERT_DEBUG_VALUE(key, value) \
TRT_UNUSED(key); \
TRT_UNUSED(value)
#endif
using half = __half;
constexpr uint32_t BDIM = 1; // batch dimension
constexpr uint32_t SDIM = 0; // seq len dimension
constexpr uint32_t HDIM = 2; // hidden dimension
constexpr int32_t kSM_53 = 53;
constexpr int32_t kSM_70 = 70;
constexpr int32_t kSM_72 = 72;
constexpr int32_t kSM_75 = 75;
constexpr int32_t kSM_80 = 80;
constexpr int32_t kSM_86 = 86;
constexpr int32_t kSM_87 = 87;
constexpr size_t threadsPerCta128 = 2 * 2 * 32;
constexpr size_t threadsPerCta384 = 1 * 8 * 32;
// The number of xmmas in the M dimension. We use one uint32_t per XMMA in the M
// dimension: (s + 16*warps_m - 1) / (16*warps_m);
constexpr size_t xmmasM128 = 4;
constexpr size_t xmmasM384 = 24;
// Packed mask size per batch. Layout is XMMAS_M * THREADS_PER_CTA.
constexpr size_t unfusedMaskSize = 1;
constexpr size_t packedMaskSize64 = xmmasM128 * threadsPerCta128;
constexpr size_t packedMaskSize96 = xmmasM128 * threadsPerCta128;
constexpr size_t packedMaskSize128 = xmmasM128 * threadsPerCta128;
constexpr size_t packedMaskSize384 = xmmasM384 * threadsPerCta384;
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
inline uint32_t getElementSize(nvinfer1::DataType t) noexcept {
switch (t) {
case nvinfer1::DataType::kINT32:
return 4;
case nvinfer1::DataType::kFLOAT:
return 4;
case nvinfer1::DataType::kHALF:
return 2;
case nvinfer1::DataType::kBOOL:
case nvinfer1::DataType::kINT8:
return 1;
default:
return 0;
}
}
inline int64_t getWeightsSize(const nvinfer1::Weights& w,
nvinfer1::DataType type) {
return w.count * getElementSize(type);
}
template <typename T>
inline void serFromDev(char** buffer, const T* data, size_t nbElem) {
const size_t len = sizeof(T) * nbElem;
cudaMemcpy(
*buffer, static_cast<const void*>(data), len, cudaMemcpyDeviceToHost);
*buffer += len;
}
template <typename T>
struct CudaDeleter {
void operator()(T* buf) { cudaFree(buf); }
};
template <typename T>
using cuda_unique_ptr = std::unique_ptr<T, CudaDeleter<T>>;
template <typename T>
using cuda_shared_ptr = std::shared_ptr<T>;
template <typename T>
void make_cuda_shared(cuda_shared_ptr<T>* ptr, void* cudaMem) {
ptr->reset(static_cast<T*>(cudaMem), CudaDeleter<T>());
}
struct WeightsWithOwnership : public nvinfer1::Weights {
WeightsWithOwnership() {
values = nullptr;
count = 0;
}
~WeightsWithOwnership() { operator delete[](const_cast<void*>(values)); }
WeightsWithOwnership(const WeightsWithOwnership&) = delete;
WeightsWithOwnership operator=(const WeightsWithOwnership&) = delete;
WeightsWithOwnership(const WeightsWithOwnership&&) = delete;
WeightsWithOwnership operator=(const WeightsWithOwnership&&) = delete;
void convertAndCopy(const nvinfer1::Weights& src, nvinfer1::DataType type) {
this->type = type;
this->count = src.count;
if (type == nvinfer1::DataType::kFLOAT) {
auto destBuf = new float[src.count];
this->values = destBuf;
if (src.type == nvinfer1::DataType::kFLOAT) {
TRANSFORMER_DEBUG_MSG("Float Weights(Host) => Float Array(Host)");
std::copy_n(static_cast<const float*>(src.values), src.count, destBuf);
} else {
assert(src.type == nvinfer1::DataType::kHALF);
TRANSFORMER_DEBUG_MSG("Half Weights(Host) => Float Array(Host)");
const auto s = static_cast<const half*>(src.values);
auto d = static_cast<float*>(const_cast<void*>(this->values));
for (auto it = 0; it < src.count; it++) {
d[it] = __half2float(s[it]);
}
}
} else if (type == nvinfer1::DataType::kHALF) {
auto destBuf = new half[src.count];
this->values = destBuf;
if (src.type == nvinfer1::DataType::kHALF) {
TRANSFORMER_DEBUG_MSG("Half Weights(Host) => Half Array(Host)");
std::copy_n(static_cast<const half*>(src.values), src.count, destBuf);
} else {
assert(src.type == nvinfer1::DataType::kFLOAT);
TRANSFORMER_DEBUG_MSG("Float Weights(Host) => Half Array(Host)");
const auto s = static_cast<const float*>(src.values);
auto d = static_cast<half*>(const_cast<void*>(this->values));
for (auto it = 0; it < src.count; it++) {
d[it] = __float2half(s[it]);
}
}
} else {
throw std::runtime_error("Unsupported DataType specified for plugin.");
}
}
void convertAndCopy(const char** srcBuf,
size_t count,
nvinfer1::DataType type) noexcept {
this->type = type;
this->count = count;
const auto nbBytes = getWeightsSize(*this, type);
auto destBuf = new char[nbBytes];
this->values = destBuf;
std::copy_n(*srcBuf, nbBytes, destBuf);
*srcBuf += nbBytes;
}
};
template <typename T>
inline void copyToDevice(WeightsWithOwnership* hostWeights,
size_t nbBytes,
cuda_unique_ptr<T>* cudaWeights) {
if (hostWeights->values) {
void* cudaMem{nullptr};
cudaMalloc(&cudaMem, nbBytes);
cudaMemcpy(cudaMem, hostWeights->values, nbBytes, cudaMemcpyHostToDevice);
cudaWeights->reset(static_cast<T*>(cudaMem));
}
}
inline nvinfer1::DataType fieldTypeToDataType(
const nvinfer1::PluginFieldType ftype) {
switch (ftype) {
case nvinfer1::PluginFieldType::kFLOAT32: {
TRANSFORMER_DEBUG_MSG("PluginFieldType is Float32");
return nvinfer1::DataType::kFLOAT;
}
case nvinfer1::PluginFieldType::kFLOAT16: {
TRANSFORMER_DEBUG_MSG("PluginFieldType is Float16");
return nvinfer1::DataType::kHALF;
}
case nvinfer1::PluginFieldType::kINT32: {
TRANSFORMER_DEBUG_MSG("PluginFieldType is Int32");
return nvinfer1::DataType::kINT32;
}
case nvinfer1::PluginFieldType::kINT8: {
TRANSFORMER_DEBUG_MSG("PluginFieldType is Int8");
return nvinfer1::DataType::kINT8;
}
default:
TRANSFORMER_DEBUG_MSG("PluginFieldType is Float32");
return nvinfer1::DataType::kFLOAT;
}
}
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,301 @@
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
// SPDX-FileCopyrightText: Copyright (c) 1993-2022 NVIDIA CORPORATION &
// AFFILIATES. 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.
#pragma once
#include <cublas_v2.h>
#include <cub/cub.cuh>
#include "paddle/phi/core/platform/device_context.h"
using kv_float = cub::KeyValuePair<float, float>;
using kv_half = cub::KeyValuePair<half, half>;
using kv_half2 = cub::KeyValuePair<half2, half2>;
template <typename T>
__device__ inline T rsqrt(const T& x);
template <>
__device__ inline float rsqrt(const float& x) {
return rsqrtf(x);
}
namespace cub {
__host__ __device__ inline kv_float operator+(const kv_float& a,
const kv_float& b) {
return kv_float(a.key + b.key, a.value + b.value);
}
} // namespace cub
// Half Operations
__device__ inline half2 __hadd2_with_fallback(const half2 a, const half2 b) {
#if __CUDA_ARCH__ >= 530
return __hadd2(a, b);
#else
float2 out{};
out.x = __half2float(a.x) + __half2float(b.x);
out.y = __half2float(a.y) + __half2float(b.y);
return __float22half2_rn(out);
#endif
}
#if __CUDA_ARCH__ < 530
template <typename T>
__device__ inline T operator+(const T& a, const T& b);
template <typename T>
__device__ inline T operator*(const T& a, const T& b);
template <>
__device__ inline half2 operator+(const half2& a, const half2& b) {
return __hadd2_with_fallback(a, b);
}
template <>
__device__ inline half2 operator*(const half2& a, const half2& b) {
float2 out{};
out.x = __half2float(a.x) * __half2float(b.x);
out.y = __half2float(a.y) * __half2float(b.y);
return __float22half2_rn(out);
}
template <typename T>
__device__ inline T operator+(const T& a, const T& b);
template <typename T>
__device__ inline T operator/(const T& a, const T& b);
template <typename T>
__device__ inline T& operator+=(T& a, const T& b); // NOLINT
template <typename T>
__device__ inline T operator-(const T& a, const T& b);
template <typename T>
__device__ inline T operator*(const T& a, const T& b);
template <>
__device__ inline half operator+(const half& a, const half& b) {
return __float2half(__half2float(a) + __half2float(b));
}
template <>
__device__ inline half& operator+=(half& a, const half& b) { // NOLINT
a = __float2half(__half2float(a) + __half2float(b));
return a;
}
template <>
__device__ inline half operator-(const half& a, const half& b) {
return __float2half(__half2float(a) - __half2float(b));
}
template <>
__device__ inline half operator*(const half& a, const half& b) {
return __float2half(__half2float(a) * __half2float(b));
}
template <>
__device__ inline half operator/(const half& a, const half& b) {
return __float2half(__half2float(a) / __half2float(b));
}
#endif
template <>
__device__ inline half rsqrt(const half& x) {
#if __CUDA_ARCH__ >= 530
return hrsqrt(x);
#else
return __float2half(rsqrt(__half2float(x)));
#endif
}
__device__ inline kv_half operator+(const kv_half& a, const kv_half& b) {
const half2 a2 = __halves2half2(a.key, a.value);
const half2 b2 = __halves2half2(b.key, b.value);
const half2 res = __hadd2_with_fallback(a2, b2);
return kv_half(res.x, res.y);
}
__device__ inline kv_half2 operator+(const kv_half2& a, const kv_half2& b) {
return kv_half2(__hadd2_with_fallback(a.key, b.key),
__hadd2_with_fallback(a.value, b.value));
}
// Helper Functions
template <typename T>
using kvp = cub::KeyValuePair<T, T>;
template <typename T, typename R, typename P, int TPB>
__device__ inline void layerNorm(const kvp<R>& threadData,
const int ld,
const int offset,
const P* beta,
const P* gamma,
T* output) {
// Assuming threadData is already divided by ld
using BlockReduce = cub::BlockReduce<kvp<R>, TPB>;
__shared__ typename BlockReduce::TempStorage temp_storage;
__shared__ R mu; // mean
__shared__ R rsigma; // 1 / std.dev.
const auto sumKV = BlockReduce(temp_storage).Reduce(threadData, cub::Sum());
if (threadIdx.x == 0) {
mu = sumKV.key;
rsigma = rsqrt(sumKV.value - mu * mu);
}
__syncthreads();
for (int i = threadIdx.x; i < ld; i += TPB) {
const int idx = offset + i;
const R val = output[idx];
const R g(gamma[i]);
const R b(beta[i]);
output[idx] = g * (val - mu) * rsigma + b;
}
}
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
// Helper Functions for multihead related plugins
template <typename T>
__global__ void transpose(T* src,
T* dst,
const int batch_size,
const int seq_len,
const int head_num,
const int size_per_head) {
int batch_id = blockIdx.x / (head_num * seq_len);
int seq_id = blockIdx.x % seq_len;
int head_id = (blockIdx.x % (head_num * seq_len)) / seq_len;
dst[batch_id * (head_num * seq_len * size_per_head) +
seq_id * head_num * size_per_head + head_id * size_per_head +
threadIdx.x] = src[blockIdx.x * size_per_head + threadIdx.x];
}
template <typename T>
__global__ void TransposeQkvKernel(const int H, const T* input, T* output) {
// Input: BxSx3xNxH
// Bias: 3xSxB
// Output: 3xBxNxSxH
int n = threadIdx.y;
int s = blockIdx.x;
int b = blockIdx.y;
int m = blockIdx.z;
const int N = blockDim.y;
const int S = gridDim.x;
const int B = gridDim.y;
const int NH = N * H;
const int NHS = NH * S;
const int in_offset = n * H + m * NH + s * 3 * NH + b * NHS * 3;
const int out_offset = s * H + n * S * H + b * NHS + m * NHS * B;
const int i = threadIdx.x;
output[out_offset + i] = input[in_offset + i];
}
inline void TransposeQKV(const int batch,
const int seq_len,
const int head_size,
const int head_num,
const float* input,
float* output,
cudaStream_t stream) {
int scratch_size = batch * head_num * seq_len * seq_len;
const dim3 grid(seq_len, batch, 3);
if (head_size % 4 == 0 && scratch_size % 4 == 0) {
const int h = head_size / 4;
const float4* input4 = reinterpret_cast<const float4*>(input);
float4* output4 = reinterpret_cast<float4*>(output);
const dim3 block(h, head_num, 1);
// limit h * head_num to max block size(1024).
PADDLE_ENFORCE_LE(h * head_num,
1024,
common::errors::InvalidArgument(
"head_num (%d) * head_size (%d) should <= %d",
head_num,
head_size,
1024 * 4));
TransposeQkvKernel<float4><<<grid, block, 0, stream>>>(h, input4, output4);
} else if (head_size % 2 == 0 && scratch_size % 2 == 0) {
const int h = head_size / 2;
const float2* input2 = reinterpret_cast<const float2*>(input);
float2* output2 = reinterpret_cast<float2*>(output);
const dim3 block(h, head_num, 1);
// limit h * head_num to max block size(1024).
PADDLE_ENFORCE_LE(h * head_num,
1024,
common::errors::InvalidArgument(
"head_num (%d) * head_size (%d) should <= %d",
head_num,
head_size,
1024 * 2));
TransposeQkvKernel<float2><<<grid, block, 0, stream>>>(h, input2, output2);
} else {
const dim3 block(head_size, head_num, 1);
// limit head_size * head_num to max block size(1024).
PADDLE_ENFORCE_LE(head_size * head_num,
1024,
common::errors::InvalidArgument(
"head_num (%d) * head_size (%d) should <= %d",
head_num,
head_size,
1024));
TransposeQkvKernel<float>
<<<grid, block, 0, stream>>>(head_size, input, output);
}
}
inline void TransposeQKV(const int batch,
const int seq_len,
const int head_size,
const int head_num,
const half* input,
half* output,
cudaStream_t stream) {
int scratch_size = batch * head_num * seq_len * seq_len;
const dim3 grid(seq_len, batch, 3);
if (head_size % 8 == 0 && scratch_size % 8 == 0) {
int h = head_size / 8;
const int4* input4 = reinterpret_cast<const int4*>(input);
int4* output4 = reinterpret_cast<int4*>(output);
dim3 block(h, head_num, 1);
// limit h * head_num to max block size(1024).
PADDLE_ENFORCE_LE(h * head_num,
1024,
common::errors::InvalidArgument(
"head_num (%d) * head_size (%d) should <= %d",
head_num,
head_size,
1024 * 8));
TransposeQkvKernel<int4><<<grid, block, 0, stream>>>(h, input4, output4);
} else if (head_size % 2 == 0 && scratch_size % 2 == 0) {
const int h = head_size / 2;
const half2* input2 = reinterpret_cast<const half2*>(input);
half2* output2 = reinterpret_cast<half2*>(output);
const dim3 block(h, head_num, 1);
// limit h * head_num to max block size(1024).
PADDLE_ENFORCE_LE(h * head_num,
1024,
common::errors::InvalidArgument(
"head_num (%d) * head_size (%d) should <= %d",
head_num,
head_size,
1024 * 2));
TransposeQkvKernel<half2><<<grid, block, 0, stream>>>(h, input2, output2);
} else {
const dim3 block(head_size, head_num, 1);
// limit head_size * head_num to max block size(1024).
PADDLE_ENFORCE_LE(head_size * head_num,
1024,
common::errors::InvalidArgument(
"head_num (%d) * head_size (%d) should <= %d",
head_num,
head_size,
1024));
TransposeQkvKernel<half>
<<<grid, block, 0, stream>>>(head_size, input, output);
}
}
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,62 @@
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
// SPDX-FileCopyrightText: Copyright (c) 1993-2022 NVIDIA CORPORATION &
// AFFILIATES. 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.
#pragma once
#include <cuda_runtime.h>
#include <cstring>
#include <iostream>
#include <memory>
#include <sstream>
#include <string>
#include "NvInfer.h"
#include "NvInferPlugin.h"
typedef enum {
STATUS_SUCCESS = 0,
STATUS_FAILURE = 1,
STATUS_BAD_PARAM = 2,
STATUS_NOT_SUPPORTED = 3,
STATUS_NOT_INITIALIZED = 4
} pluginStatus_t;
namespace nvinfer1 {
class BasePlugin : public IPluginV2 {
protected:
void setPluginNamespace(const char* libNamespace) noexcept override {
mNamespace = libNamespace;
}
const char* getPluginNamespace() const noexcept override {
return mNamespace.c_str();
}
std::string mNamespace;
};
class BaseCreator : public IPluginCreator {
public:
void setPluginNamespace(const char* libNamespace) noexcept override {
mNamespace = libNamespace;
}
const char* getPluginNamespace() const noexcept override {
return mNamespace.c_str();
}
protected:
std::string mNamespace;
};
} // namespace nvinfer1
@@ -0,0 +1,119 @@
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
// SPDX-FileCopyrightText: Copyright (c) 1993-2022 NVIDIA CORPORATION &
// AFFILIATES. 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.
#pragma once
#include <cassert>
#include <cstring>
#include <type_traits>
#include <vector>
#include <iostream>
using std::cerr;
using std::cout;
using std::endl;
template <typename T>
inline void serialize_value(void** buffer, T const& value);
template <typename T>
inline void deserialize_value(void const** buffer,
size_t* buffer_size,
T* value);
template <typename T, class Enable = void>
struct Serializer {};
template <typename T>
struct Serializer<T,
typename std::enable_if<std::is_arithmetic<T>::value ||
std::is_enum<T>::value ||
std::is_pod<T>::value>::type> {
static size_t serialized_size(T const&) { return sizeof(T); }
static void serialize(void** buffer, T const& value) {
::memcpy(*buffer, &value, sizeof(T));
reinterpret_cast<char*&>(*buffer) += sizeof(T);
}
static void deserialize(void const** buffer, size_t* buffer_size, T* value) {
assert(*buffer_size >= sizeof(T));
::memcpy(value, *buffer, sizeof(T));
reinterpret_cast<char const*&>(*buffer) += sizeof(T);
*buffer_size -= sizeof(T);
}
};
template <>
struct Serializer<const char*> {
static size_t serialized_size(const char* value) { return strlen(value) + 1; }
static void serialize(void** buffer, const char* value) {
::strcpy(static_cast<char*>(*buffer), value); // NOLINT
reinterpret_cast<char*&>(*buffer) += strlen(value) + 1;
}
static void deserialize(void const** buffer,
size_t* buffer_size,
const char** value) {
*value = static_cast<char const*>(*buffer);
size_t data_size = strnlen(*value, *buffer_size) + 1;
assert(*buffer_size >= data_size);
reinterpret_cast<char const*&>(*buffer) += data_size;
*buffer_size -= data_size;
}
};
template <typename T>
struct Serializer<std::vector<T>,
typename std::enable_if<std::is_arithmetic<T>::value ||
std::is_enum<T>::value ||
std::is_pod<T>::value>::type> {
static size_t serialized_size(std::vector<T> const& value) {
return sizeof(value.size()) + value.size() * sizeof(T);
}
static void serialize(void** buffer, std::vector<T> const& value) {
serialize_value(buffer, value.size());
size_t nbyte = value.size() * sizeof(T);
::memcpy(*buffer, value.data(), nbyte);
reinterpret_cast<char*&>(*buffer) += nbyte;
}
static void deserialize(void const** buffer,
size_t* buffer_size,
std::vector<T>* value) {
size_t size;
deserialize_value(buffer, buffer_size, &size);
value->resize(size);
size_t nbyte = value->size() * sizeof(T);
assert(*buffer_size >= nbyte);
::memcpy(value->data(), *buffer, nbyte);
reinterpret_cast<char const*&>(*buffer) += nbyte;
*buffer_size -= nbyte;
}
};
template <typename T>
inline size_t serialized_size(T const& value) {
return Serializer<T>::serialized_size(value);
}
template <typename T>
inline void serialize_value(void** buffer, T const& value) {
return Serializer<T>::serialize(buffer, value);
}
template <typename T>
inline void deserialize_value(void const** buffer,
size_t* buffer_size,
T* value) {
return Serializer<T>::deserialize(buffer, buffer_size, value);
}
@@ -0,0 +1,668 @@
// Copyright (c) 2023 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/plugin/custom_generic_plugin.h"
#include "paddle/common/enforce.h"
#include "paddle/fluid/framework/op_kernel_type.h"
#include "paddle/fluid/framework/phi_utils.h"
#include "paddle/fluid/inference/tensorrt/op_teller.h"
#include "paddle/phi/api/include/tensor.h"
#include "paddle/phi/backends/gpu/gpu_context.h"
#include "paddle/phi/common/data_type.h"
#include "paddle/phi/core/compat/op_utils.h"
#include "paddle/phi/core/framework/framework.pb.h"
#include "paddle/phi/core/kernel_context.h"
#include "paddle/phi/core/kernel_factory.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
void validate(const std::string& op_type,
const std::string& datatype,
const std::string& tensor_format) {
std::unordered_set<std::string> supports_dtypes = {
"float32", "float16", "int8", "int32"};
std::unordered_set<std::string> supports_tensor_formats = {
"LINEAR", "CHW32", "CHW2", "HWC8", "CHW4"};
supports_tensor_formats.insert("DHWC8");
supports_tensor_formats.insert("HWC16");
// refer to
// https://docs.nvidia.com/deeplearning/tensorrt/developer-guide/index.html#ipluginv2
PADDLE_ENFORCE_GE(supports_dtypes.count(datatype),
0,
common::errors::InvalidArgument(
"custom op [%s] has unsupported datatype: [%s], "
"now only support: [float32, float16, int8, int32].",
op_type,
datatype));
PADDLE_ENFORCE_GE(
supports_tensor_formats.count(tensor_format),
0,
common::errors::InvalidArgument(
"custom op [%s] has unsupported tensor format: [%s], "
"now only support: [LINEAR, CHW32, CHW2, HWC8, CHW4, DHWC8(TensorRT "
"7.2 and after), HWC16(TensorRT 8.0 and after)].",
op_type,
tensor_format));
if (datatype == "float32") {
std::unordered_set<std::string> supports_formats_tmp = {"LINEAR", "CHW32"};
PADDLE_ENFORCE_GE(
supports_formats_tmp.count(tensor_format),
0,
common::errors::InvalidArgument(
"custom op [%s]: float32 only supports [LINEAR, CHW32], "
"but got tensor format: [%s], ",
op_type,
tensor_format));
}
if (datatype == "float16") {
std::unordered_set<std::string> supports_formats_tmp = {
"LINEAR", "CHW2", "HWC8", "CHW4"};
supports_formats_tmp.insert("DHWC8");
supports_formats_tmp.insert("HWC16");
PADDLE_ENFORCE_GE(supports_formats_tmp.count(tensor_format),
0,
common::errors::InvalidArgument(
"custom op [%s]: float16 only supports [LINEAR, "
"CHW2, HWC8, CHW4, DHWC8(TensorRT 7.2 and after), "
"HWC16(TensorRT 8.0 and after)], "
"but got tensor format: [%s], ",
op_type,
tensor_format));
}
if (datatype == "int8") {
std::unordered_set<std::string> supports_formats_tmp = {
"LINEAR", "CHW32", "CHW4"};
PADDLE_ENFORCE_GE(
supports_formats_tmp.count(tensor_format),
0,
common::errors::InvalidArgument(
"custom op [%s]: int8 only supports [LINEAR, CHW32, CHW4], "
"but got tensor format: [%s], ",
op_type,
tensor_format));
}
if (datatype == "int32") {
std::unordered_set<std::string> supports_formats_tmp = {"LINEAR"};
PADDLE_ENFORCE_GE(supports_formats_tmp.count(tensor_format),
0,
common::errors::InvalidArgument(
"custom op [%s]: int32 only supports [LINEAR], "
"but got tensor format: [%s], ",
op_type,
tensor_format));
}
}
std::vector<std::pair<std::string, std::string>> parseConfig(
const std::string& op_type, const std::string& config) {
std::vector<std::pair<std::string, std::string>> res;
size_t start = 0;
size_t seg = config.find("+", start);
while (seg != std::string::npos) {
std::string dtype_format = config.substr(start, seg - start);
size_t split_pos = dtype_format.find(":");
std::string dtype = dtype_format.substr(0, split_pos);
std::string format;
if (split_pos == std::string::npos) {
format = "LINEAR";
} else {
format = dtype_format.substr(split_pos + 1);
}
transform(dtype.begin(), dtype.end(), dtype.begin(), ::tolower);
transform(format.begin(), format.end(), format.begin(), ::toupper);
validate(op_type, dtype, format);
res.emplace_back(dtype, format);
start = seg + 1;
seg = config.find("+", start);
}
std::string dtype_format = config.substr(start);
size_t split_pos = dtype_format.find(":");
std::string dtype = dtype_format.substr(0, split_pos);
std::string format;
if (split_pos == std::string::npos) {
format = "LINEAR";
} else {
format = dtype_format.substr(split_pos + 1);
}
transform(dtype.begin(), dtype.end(), dtype.begin(), ::tolower);
transform(format.begin(), format.end(), format.begin(), ::toupper);
validate(op_type, dtype, format);
res.emplace_back(dtype, format);
return res;
}
nvinfer1::DataType getTrtDtype(std::string dtype) {
if (dtype == "float32") {
return nvinfer1::DataType::kFLOAT;
} else if (dtype == "float16") {
return nvinfer1::DataType::kHALF;
} else if (dtype == "int8") {
return nvinfer1::DataType::kINT8;
} else if (dtype == "int32") {
return nvinfer1::DataType::kINT32;
} else {
PADDLE_THROW(
common::errors::Unimplemented("Unsupported data type [%s]", dtype));
}
}
nvinfer1::TensorFormat getTrtTensorFormat(std::string tensor_format) {
if (tensor_format == "LINEAR") {
return nvinfer1::TensorFormat::kLINEAR;
} else if (tensor_format == "CHW32") {
return nvinfer1::TensorFormat::kCHW32;
} else if (tensor_format == "CHW2") {
return nvinfer1::TensorFormat::kCHW2;
} else if (tensor_format == "HWC8") {
return nvinfer1::TensorFormat::kHWC8;
} else if (tensor_format == "CHW4") {
return nvinfer1::TensorFormat::kCHW4;
} else if (tensor_format == "DHWC8") {
return nvinfer1::TensorFormat::kDHWC8;
} else if (tensor_format == "HWC16") {
return nvinfer1::TensorFormat::kHWC16;
} else {
PADDLE_THROW(common::errors::Unimplemented("Unsupported tensor format [%s]",
tensor_format));
}
}
GenerateCustomGenericPluginDataType
ProtoTypeToGenerateCustomGenericPluginDataType(
framework::proto::VarType_Type proto_type) {
using framework::proto::VarType_Type;
switch (proto_type) {
case VarType_Type::VarType_Type_BOOL:
return GenerateCustomGenericPluginDataType::PLUGIN_BOOL;
case VarType_Type::VarType_Type_UINT8:
return GenerateCustomGenericPluginDataType::PLUGIN_UINT8;
case VarType_Type::VarType_Type_INT8:
return GenerateCustomGenericPluginDataType::PLUGIN_INT8;
case VarType_Type::VarType_Type_INT16:
return GenerateCustomGenericPluginDataType::PLUGIN_INT16;
case VarType_Type::VarType_Type_INT32:
return GenerateCustomGenericPluginDataType::PLUGIN_INT32;
case VarType_Type::VarType_Type_INT64:
return GenerateCustomGenericPluginDataType::PLUGIN_INT64;
case VarType_Type::VarType_Type_FP16:
return GenerateCustomGenericPluginDataType::PLUGIN_FP16;
case VarType_Type::VarType_Type_FP32:
return GenerateCustomGenericPluginDataType::PLUGIN_FP32;
case VarType_Type::VarType_Type_FP64:
return GenerateCustomGenericPluginDataType::PLUGIN_FP64;
case VarType_Type::VarType_Type_SIZE_T:
return GenerateCustomGenericPluginDataType::PLUGIN_SIZE_T;
case VarType_Type::VarType_Type_BF16:
return GenerateCustomGenericPluginDataType::PLUGIN_BF16;
case VarType_Type::VarType_Type_COMPLEX64:
return GenerateCustomGenericPluginDataType::PLUGIN_COMPLEX64;
case VarType_Type::VarType_Type_COMPLEX128:
return GenerateCustomGenericPluginDataType::PLUGIN_COMPLEX128;
default:
PADDLE_THROW(common::errors::Unimplemented(
"This data type is currently not supported"));
}
}
CustomGenericPlugin::CustomGenericPlugin(
const paddle::framework::proto::OpDesc& proto_op_desc,
const InputOutPutVarInfo& in_out_info,
bool with_fp16) {
proto_op_desc_ = proto_op_desc;
op_desc_ = framework::OpDesc(proto_op_desc_, nullptr);
proto_op_desc_.SerializeToString(&op_meta_data_);
inputs_data_type_ = in_out_info.inputs_data_type;
outputs_data_type_ = in_out_info.outputs_data_type;
with_fp16_ = with_fp16;
}
CustomGenericPlugin::CustomGenericPlugin(
const paddle::framework::proto::OpDesc& proto_op_desc,
const std::vector<GenerateCustomGenericPluginDataType>& inputs_data_type,
const std::vector<GenerateCustomGenericPluginDataType>& outputs_data_type,
bool with_fp16) {
proto_op_desc_ = proto_op_desc;
op_desc_ = framework::OpDesc(proto_op_desc_, nullptr);
proto_op_desc_.SerializeToString(&op_meta_data_);
inputs_data_type_ = inputs_data_type;
outputs_data_type_ = outputs_data_type;
with_fp16_ = with_fp16;
}
CustomGenericPlugin::CustomGenericPlugin(void const* serial_data,
size_t serial_length) {
DeserializeValue(&serial_data, &serial_length, &inputs_data_type_);
DeserializeValue(&serial_data, &serial_length, &outputs_data_type_);
DeserializeValue(&serial_data, &serial_length, &with_fp16_);
std::string op_meta_data((char*)(serial_data), serial_length); // NOLINT
op_meta_data_ = std::move(op_meta_data);
proto_op_desc_.ParseFromString(op_meta_data_);
op_desc_ = framework::OpDesc(proto_op_desc_, nullptr);
}
int CustomGenericPlugin::getNbOutputs() const TRT_NOEXCEPT {
int res = 0;
for (auto& i : op_desc_.Outputs()) {
if (!i.second.empty()) res += i.second.size();
}
return res;
}
int CustomGenericPlugin::getNbInputs() const TRT_NOEXCEPT {
int res = 0;
for (auto& i : op_desc_.Inputs()) {
if (!i.second.empty()) res += i.second.size();
}
return res;
}
nvinfer1::IPluginV2DynamicExt* CustomGenericPlugin::clone() const TRT_NOEXCEPT {
nvinfer1::IPluginV2DynamicExt* plugin = new CustomGenericPlugin(
proto_op_desc_, inputs_data_type_, outputs_data_type_, with_fp16_);
plugin->initialize();
return plugin;
}
void CustomGenericPlugin::serialize(void* buffer) const TRT_NOEXCEPT {
// inputs_data_type_
SerializeValue(&buffer, inputs_data_type_);
// outputs_data_type_
SerializeValue(&buffer, outputs_data_type_);
// use fp16
SerializeValue(&buffer, with_fp16_);
// serialize op_meta_data_
std::memcpy(buffer, op_meta_data_.c_str(), op_meta_data_.size());
reinterpret_cast<char*&>(buffer) += op_meta_data_.size();
}
bool CustomGenericPlugin::supportsFormatCombination(
int pos,
const nvinfer1::PluginTensorDesc* in_out,
int nb_inputs,
int nb_outputs) TRT_NOEXCEPT {
auto& op_meta_info_map = OpMetaInfoMap::Instance();
const auto& meta_info_map = op_meta_info_map.GetMap();
auto& op_info = meta_info_map.at(op_desc_.Type()).front();
auto& supports_format_config =
OpMetaInfoHelper::GetTrtSupportsFormatConfig(op_info);
PADDLE_ENFORCE_NE(supports_format_config.empty(),
true,
common::errors::InvalidArgument(
"The %s op has no tensorrt plugin "
"supportsFormatCombination config!"
"Please use SetTrtSupportsFormatConfig to set.",
op_desc_.Type().c_str()));
// generate support format combination function by config
size_t input_num = OpMetaInfoHelper::GetInputs(op_info).size();
size_t output_num = OpMetaInfoHelper::GetOutputs(op_info).size();
std::vector<std::vector<std::pair<std::string, std::string>>>
format_combinations;
for (auto& config : supports_format_config) {
auto format_combination = parseConfig(op_desc_.Type(), config);
PADDLE_ENFORCE_EQ(input_num + output_num,
format_combination.size(),
common::errors::InvalidArgument(
"Expected %d format_combination, but got %d.",
input_num + output_num,
format_combination.size()));
format_combinations.emplace_back(format_combination);
}
bool is_supported = false;
for (size_t i = 0; i < input_num + output_num; ++i) {
if (i < input_num) {
if (pos == i) {
for (auto& format_combination : format_combinations) {
is_supported |=
(in_out[pos].type == getTrtDtype(format_combination[i].first) &&
in_out[pos].format ==
getTrtTensorFormat(format_combination[i].second));
}
}
} else {
if (pos == i) {
for (auto& format_combination : format_combinations) {
bool is_supported_tmp = true;
for (size_t j = 0; j < input_num; ++j) {
is_supported_tmp &=
(in_out[j].type == getTrtDtype(format_combination[j].first) &&
in_out[j].format ==
getTrtTensorFormat(format_combination[j].second));
}
is_supported_tmp &=
(in_out[pos].type == getTrtDtype(format_combination[i].first) &&
in_out[pos].format ==
getTrtTensorFormat(format_combination[i].second));
is_supported |= is_supported_tmp;
}
}
}
}
return is_supported;
}
nvinfer1::DataType CustomGenericPlugin::getOutputDataType(
int index,
const nvinfer1::DataType* input_types,
int nb_inputs) const TRT_NOEXCEPT {
PADDLE_ENFORCE_NE(
input_types,
nullptr,
common::errors::Unavailable("Input type should not be nullptr."));
return input_types[0];
}
int CustomGenericPlugin::initialize() TRT_NOEXCEPT {
if (!tensor_inputs_)
tensor_inputs_ = new std::vector<paddle::Tensor>(getNbInputs());
if (!tensor_outputs_)
tensor_outputs_ = new std::vector<paddle::Tensor>(getNbOutputs());
return 0;
}
nvinfer1::DimsExprs CustomGenericPlugin::getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs* inputs,
int nb_inputs,
nvinfer1::IExprBuilder& expr_builder) TRT_NOEXCEPT {
PADDLE_ENFORCE_LT(
output_index,
getNbOutputs(),
common::errors::InvalidArgument(
"Output index (%d) must be less than the number of outputs (%d).",
output_index,
getNbOutputs()));
auto& op_meta_info_map = OpMetaInfoMap::Instance();
const auto& meta_info_map = op_meta_info_map.GetMap();
auto& op_info = meta_info_map.at(op_desc_.Type()).front();
auto& infer_shape_fn = OpMetaInfoHelper::GetTrtInferShapeFn(op_info);
PADDLE_ENFORCE_NE(infer_shape_fn,
nullptr,
common::errors::InvalidArgument(
"The %s op has no getOutputDimensions function!"
"Please use SetTrtInferShapeFn to set.",
op_desc_.Type().c_str()));
std::vector<paddle::any> custom_attrs;
auto& attrs = op_desc_.GetAttrMap();
auto& op_attrs_names = OpMetaInfoHelper::GetAttrs(op_info);
for (auto& op_attrs_name : op_attrs_names) {
auto attr_name_and_type = paddle::ParseAttrStr(op_attrs_name);
auto attr_name = attr_name_and_type[0];
auto attr_type_str = attr_name_and_type[1];
if (attr_type_str == "bool") {
custom_attrs.emplace_back(PADDLE_GET_CONST(bool, attrs.at(attr_name)));
} else if (attr_type_str == "int") {
custom_attrs.emplace_back(PADDLE_GET_CONST(int, attrs.at(attr_name)));
} else if (attr_type_str == "float") {
custom_attrs.emplace_back(PADDLE_GET_CONST(float, attrs.at(attr_name)));
} else if (attr_type_str == "int64_t") {
custom_attrs.emplace_back(PADDLE_GET_CONST(int64_t, attrs.at(attr_name)));
} else if (attr_type_str == "std::string") {
custom_attrs.emplace_back(
PADDLE_GET_CONST(std::string, attrs.at(attr_name)));
} else if (attr_type_str == "std::vector<int>") {
custom_attrs.emplace_back(
PADDLE_GET_CONST(std::vector<int>, attrs.at(attr_name)));
} else if (attr_type_str == "std::vector<float>") {
custom_attrs.emplace_back(
PADDLE_GET_CONST(std::vector<float>, attrs.at(attr_name)));
} else if (attr_type_str == "std::vector<int64_t>") {
custom_attrs.emplace_back(
PADDLE_GET_CONST(std::vector<int64_t>, attrs.at(attr_name)));
} else if (attr_type_str == "std::vector<std::string>") {
custom_attrs.emplace_back(
PADDLE_GET_CONST(std::vector<std::string>, attrs.at(attr_name)));
} else {
PADDLE_THROW(common::errors::Unimplemented(
"Unsupported `%s` type value as custom attribute now. "
"Supported data types include `bool`, `int`, `float`, "
"`int64_t`, `std::string`, `std::vector<int>`, "
"`std::vector<float>`, `std::vector<int64_t>`, "
"`std::vector<std::string>`, Please check whether "
"the attribute data type and data type string are matched.",
attr_type_str));
}
}
return infer_shape_fn(
{output_index, nb_inputs}, inputs, expr_builder, custom_attrs);
}
void CustomGenericPlugin::configurePlugin(
const nvinfer1::DynamicPluginTensorDesc* in,
int nb_inputs,
const nvinfer1::DynamicPluginTensorDesc* out,
int nb_outputs) TRT_NOEXCEPT {
PADDLE_ENFORCE_EQ(nb_inputs,
getNbInputs(),
common::errors::InvalidArgument(
"Number of inputs (%d) does not match the "
"expected number of inputs (%d).",
nb_inputs,
getNbInputs()));
PADDLE_ENFORCE_EQ(nb_outputs,
getNbOutputs(),
common::errors::InvalidArgument(
"Number of outputs (%d) does not match the "
"expected number of outputs (%d).",
nb_outputs,
getNbOutputs()));
}
// Shutdown the layer. This is called when the engine is destroyed
void CustomGenericPlugin::terminate() TRT_NOEXCEPT {
delete tensor_inputs_;
delete tensor_outputs_;
}
int CustomGenericPlugin::enqueue(const nvinfer1::PluginTensorDesc* input_desc,
const nvinfer1::PluginTensorDesc* output_desc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT {
GPUPlace place(platform::GetCurrentDeviceId());
// TODO(inference): custom generic plugin do not support INT8 precision now.
auto protoType2PhiType =
[&](GenerateCustomGenericPluginDataType proto_type,
nvinfer1::DataType nv_dtype) -> std::pair<phi::DataType, int> {
if (proto_type == GenerateCustomGenericPluginDataType::PLUGIN_FP16) {
return {phi::DataType::FLOAT16, sizeof(half)};
} else if (proto_type == GenerateCustomGenericPluginDataType::PLUGIN_FP32) {
if (isFp16Supported() && nv_dtype == nvinfer1::DataType::kHALF) {
return {phi::DataType::FLOAT16, sizeof(half)};
} else {
return {phi::DataType::FLOAT32, sizeof(float)};
}
} else if (proto_type ==
GenerateCustomGenericPluginDataType::PLUGIN_INT64) {
return {phi::DataType::INT64, sizeof(int64_t)};
} else if (proto_type ==
GenerateCustomGenericPluginDataType::PLUGIN_INT32) {
return {phi::DataType::INT32, sizeof(int32_t)};
} else if (proto_type == GenerateCustomGenericPluginDataType::PLUGIN_BOOL) {
return {phi::DataType::BOOL, sizeof(bool)};
} else {
PADDLE_ENFORCE_EQ(
false,
true,
common::errors::InvalidArgument("Precision is not supported."));
}
};
nvinfer1::DataType data_type = input_desc[0].type;
PADDLE_ENFORCE_EQ(
(data_type == nvinfer1::DataType::kFLOAT) ||
(data_type == nvinfer1::DataType::kHALF),
true,
common::errors::InvalidArgument("The data type must be either kFLOAT or "
"kHALF, but received data type %d.",
static_cast<int>(data_type)));
paddle::CustomOpKernelContext kernel_ctx;
// input
for (int i = 0; i < getNbInputs(); i++) {
if (inputs_data_type_[i] ==
GenerateCustomGenericPluginDataType::PLUGIN_OPTIONAL) {
(*tensor_inputs_)[i] = paddle::Tensor();
continue;
}
auto const& input_dims = input_desc[i].dims;
std::vector<int> input_shape;
for (int j = 0; j < input_dims.nbDims; j++)
input_shape.push_back(input_dims.d[j]);
int input_numel = 1;
for (int k : input_shape) input_numel *= k;
auto data_type_and_size =
protoType2PhiType(inputs_data_type_[i], data_type);
phi::DenseTensorMeta input_meta(data_type_and_size.first,
phi::make_ddim(input_shape));
std::shared_ptr<phi::Allocation> input_alloc(
new phi::Allocation((void*)(inputs[i]), // NOLINT
input_numel * data_type_and_size.second,
place));
(*tensor_inputs_)[i] = paddle::Tensor(
std::make_shared<phi::DenseTensor>(input_alloc, input_meta));
kernel_ctx.EmplaceBackInput(std::move((*tensor_inputs_)[i]));
}
// output
for (int i = 0; i < getNbOutputs(); i++) {
auto const& output_dims = output_desc[i].dims;
std::vector<int> output_shape;
for (int j = 0; j < output_dims.nbDims; j++)
output_shape.push_back(output_dims.d[j]);
int output_numel = 1;
for (int k : output_shape) output_numel *= k;
auto data_type_and_size =
protoType2PhiType(outputs_data_type_[i], data_type);
phi::DenseTensorMeta output_meta(data_type_and_size.first,
phi::make_ddim(output_shape));
std::shared_ptr<phi::Allocation> output_alloc(
new phi::Allocation(reinterpret_cast<void*>(outputs[i]),
output_numel * data_type_and_size.second,
place));
(*tensor_outputs_)[i] = paddle::Tensor(
std::make_shared<phi::DenseTensor>(output_alloc, output_meta));
kernel_ctx.EmplaceBackOutput(std::move((*tensor_outputs_)[i]));
}
auto& op_meta_info_map = OpMetaInfoMap::Instance();
const auto& meta_info_map = op_meta_info_map.GetMap();
auto& op_info = meta_info_map.at(op_desc_.Type()).front();
auto& op_attrs_names = OpMetaInfoHelper::GetAttrs(op_info);
auto& attrs = op_desc_.GetAttrMap();
for (auto& op_attrs_name : op_attrs_names) {
auto attr_name_and_type = paddle::ParseAttrStr(op_attrs_name);
auto attr_name = attr_name_and_type[0];
auto attr_type_str = attr_name_and_type[1];
if (attr_type_str == "bool") {
kernel_ctx.EmplaceBackAttr(PADDLE_GET_CONST(bool, attrs.at(attr_name)));
} else if (attr_type_str == "int") {
kernel_ctx.EmplaceBackAttr(PADDLE_GET_CONST(int, attrs.at(attr_name)));
} else if (attr_type_str == "float") {
kernel_ctx.EmplaceBackAttr(PADDLE_GET_CONST(float, attrs.at(attr_name)));
} else if (attr_type_str == "int64_t") {
kernel_ctx.EmplaceBackAttr(
PADDLE_GET_CONST(int64_t, attrs.at(attr_name)));
} else if (attr_type_str == "std::string") {
kernel_ctx.EmplaceBackAttr(
PADDLE_GET_CONST(std::string, attrs.at(attr_name)));
} else if (attr_type_str == "std::vector<int>") {
kernel_ctx.EmplaceBackAttr(
PADDLE_GET_CONST(std::vector<int>, attrs.at(attr_name)));
} else if (attr_type_str == "std::vector<float>") {
kernel_ctx.EmplaceBackAttr(
PADDLE_GET_CONST(std::vector<float>, attrs.at(attr_name)));
} else if (attr_type_str == "std::vector<int64_t>") {
kernel_ctx.EmplaceBackAttr(
PADDLE_GET_CONST(std::vector<int64_t>, attrs.at(attr_name)));
} else if (attr_type_str == "std::vector<std::string>") {
kernel_ctx.EmplaceBackAttr(
PADDLE_GET_CONST(std::vector<std::string>, attrs.at(attr_name)));
} else {
PADDLE_THROW(common::errors::Unimplemented(
"Unsupported `%s` type value as custom attribute now. "
"Supported data types include `bool`, `int`, `float`, "
"`int64_t`, `std::string`, `std::vector<int>`, "
"`std::vector<float>`, `std::vector<int64_t>`, "
"`std::vector<std::string>`, Please check whether "
"the attribute data type and data type string are matched.",
attr_type_str));
}
}
auto kernel_fn = OpMetaInfoHelper::GetKernelFn(op_info);
kernel_ctx.UpdatePlainOutputs(OpMetaInfoHelper::GetInputs(op_info),
OpMetaInfoHelper::GetOutputs(op_info),
OpMetaInfoHelper::GetInplaceMap(op_info));
kernel_fn(&kernel_ctx);
kernel_ctx.AssignInplaceOutputs();
// sync output tensor data into TensorRT output
auto* calc_outs = kernel_ctx.AllMutableOutput();
for (int i = 0; i < getNbOutputs(); i++) {
auto calc_out =
std::dynamic_pointer_cast<phi::DenseTensor>(calc_outs->at(i).impl());
if (reinterpret_cast<void*>(calc_out->data()) !=
reinterpret_cast<void*>(outputs[i])) {
LOG_FIRST_N(WARNING, 1)
<< "You created new Tensor(s) in custom operator(s) used as "
"output(s), "
"we will do cudaMemcpy to synchronize the output(s) "
"address needed by TensorRT plugin. "
"Inplace operation is highly recommended for better performance.";
auto const& output_dims = output_desc[i].dims;
std::vector<int> output_shape;
for (int j = 0; j < output_dims.nbDims; j++)
output_shape.push_back(output_dims.d[j]);
int output_numel = 1;
for (int k : output_shape) output_numel *= k;
auto data_type_and_size =
protoType2PhiType(outputs_data_type_[i], data_type);
phi::DenseTensorMeta output_meta(data_type_and_size.first,
phi::make_ddim(output_shape));
std::shared_ptr<phi::Allocation> output_alloc(
new phi::Allocation(reinterpret_cast<void*>(outputs[i]),
output_numel * data_type_and_size.second,
place));
phi::DenseTensor dense_output =
std::move(phi::DenseTensor(output_alloc, output_meta));
cudaMemcpy(static_cast<void*>(dense_output.data()),
static_cast<void*>(calc_out->data()),
output_numel * data_type_and_size.second,
cudaMemcpyDeviceToDevice);
}
}
return cudaGetLastError() != cudaSuccess;
}
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,186 @@
// Copyright (c) 2023 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.
#pragma once
#include <NvInfer.h>
#include <string>
#include <vector>
#include "paddle/fluid/framework/op_desc.h"
#include "paddle/fluid/framework/op_registry.h"
#include "paddle/fluid/framework/operator.h"
#include "paddle/fluid/framework/scope.h"
#include "paddle/fluid/framework/type_defs.h"
#include "paddle/fluid/inference/tensorrt/engine.h"
#include "paddle/fluid/inference/tensorrt/helper.h"
#include "paddle/fluid/inference/tensorrt/plugin/trt_plugin.h"
#include "paddle/fluid/inference/tensorrt/plugin/trt_plugin_utils.h"
#include "paddle/fluid/inference/tensorrt/plugin_arg_mapping_context.h"
#include "paddle/fluid/platform/enforce.h"
#include "paddle/phi/api/ext/op_meta_info.h"
#include "paddle/phi/backends/gpu/gpu_context.h"
#include "paddle/phi/core/kernel_context.h"
#include "paddle/phi/core/memory/allocation/cuda_allocator.h"
#include "paddle/phi/core/platform/device_context.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
enum class GenerateCustomGenericPluginDataType {
PLUGIN_BOOL,
PLUGIN_UINT8,
PLUGIN_INT8,
PLUGIN_INT16,
PLUGIN_INT32,
PLUGIN_INT64,
PLUGIN_FP16,
PLUGIN_FP32,
PLUGIN_FP64,
PLUGIN_BF16,
PLUGIN_SIZE_T,
PLUGIN_COMPLEX64,
PLUGIN_COMPLEX128,
PLUGIN_OPTIONAL,
};
GenerateCustomGenericPluginDataType
ProtoTypeToGenerateCustomGenericPluginDataType(
framework::proto::VarType_Type proto_type);
class CustomGenericPlugin : public DynamicPluginTensorRT {
public:
struct InputOutPutVarInfo {
std::vector<GenerateCustomGenericPluginDataType> inputs_data_type;
std::vector<GenerateCustomGenericPluginDataType> outputs_data_type;
};
public:
CustomGenericPlugin() = default;
CustomGenericPlugin(const paddle::framework::proto::OpDesc& proto_op_desc,
const InputOutPutVarInfo& in_out_info,
bool with_fp16_ = false);
CustomGenericPlugin(
const paddle::framework::proto::OpDesc& proto_op_desc,
const std::vector<GenerateCustomGenericPluginDataType>& inputs_data_type,
const std::vector<GenerateCustomGenericPluginDataType>& outputs_data_type,
bool with_fp16_ = false);
// It was used for tensorrt deserialization.
// It should not be called by users.
CustomGenericPlugin(void const* serialData, size_t serialLength);
// IPluginV2 method
const char* getPluginType() const TRT_NOEXCEPT override {
return "custom_generic_plugin";
}
int getNbOutputs() const TRT_NOEXCEPT override;
int getNbInputs() const TRT_NOEXCEPT;
// Initialize the layer for execution.
int initialize() TRT_NOEXCEPT override;
// Shutdown the layer. This is called when the engine is destroyed
void terminate() TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override{};
size_t getSerializationSize() const TRT_NOEXCEPT override {
size_t sum = 0;
sum += SerializedSize(inputs_data_type_);
sum += SerializedSize(outputs_data_type_);
sum += SerializedSize(with_fp16_);
sum += op_meta_data_.size();
return sum;
}
void serialize(void* buffer) const TRT_NOEXCEPT override;
// The Func in IPluginV2
nvinfer1::IPluginV2DynamicExt* clone() const TRT_NOEXCEPT override;
nvinfer1::DimsExprs getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs* inputs,
int nb_inputs,
nvinfer1::IExprBuilder& expr_builder) // NOLINT
TRT_NOEXCEPT override;
bool supportsFormatCombination(int pos,
const nvinfer1::PluginTensorDesc* in_out,
int nb_inputs,
int nb_outputs) TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::DynamicPluginTensorDesc* in,
int nb_inputs,
const nvinfer1::DynamicPluginTensorDesc* out,
int nb_outputs) TRT_NOEXCEPT override;
int enqueue(const nvinfer1::PluginTensorDesc* input_desc,
const nvinfer1::PluginTensorDesc* output_desc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* input_types,
int nb_inputs) const
TRT_NOEXCEPT override;
bool isFp16Supported() { return with_fp16_; }
private:
bool with_fp16_{false};
std::string op_meta_data_;
framework::proto::OpDesc proto_op_desc_;
framework::OpDesc op_desc_;
private:
std::vector<paddle::Tensor>* tensor_inputs_{nullptr};
std::vector<paddle::Tensor>* tensor_outputs_{nullptr};
private:
std::vector<GenerateCustomGenericPluginDataType> inputs_data_type_;
std::vector<GenerateCustomGenericPluginDataType> outputs_data_type_;
};
class CustomGenericPluginCreator : public TensorRTPluginCreator {
public:
const char* getPluginName() const TRT_NOEXCEPT override {
return "custom_generic_plugin";
}
const char* getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
nvinfer1::IPluginV2DynamicExt* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override {
return new CustomGenericPlugin(serial_data, serial_length);
}
};
REGISTER_TRT_PLUGIN_V2(CustomGenericPluginCreator);
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,418 @@
/* Copyright (c) 2021 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. */
#pragma once
#include <cstdio>
#include <string>
#include <vector>
#include "paddle/fluid/inference/tensorrt/engine.h"
#include "paddle/fluid/inference/tensorrt/plugin/trt_plugin.h"
#include "paddle/fluid/platform/enforce.h"
#include "paddle/phi/backends/dynload/cublas.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
class DeformableConvPlugin : public nvinfer1::IPluginV2Ext {
public:
explicit DeformableConvPlugin(const nvinfer1::DataType data_type,
const nvinfer1::Weights& weights,
const std::vector<int>& kernel_dims,
const std::vector<int>& strides,
const std::vector<int>& paddings,
const std::vector<int>& dilations,
const int groups,
const int deformable_groups,
const int im2col_step,
const bool with_fp16);
explicit DeformableConvPlugin(const nvinfer1::DataType data_type,
const nvinfer1::Weights& weights,
const std::vector<int>& kernel_dims,
const std::vector<int>& strides,
const std::vector<int>& paddings,
const std::vector<int>& dilations,
const int groups,
const int deformable_groups,
const int im2col_step,
const std::vector<int>& input_dim,
const std::vector<int>& offset_dim,
const std::vector<int>& mask_dim,
const std::vector<int>& output_dim,
const bool with_fp16);
DeformableConvPlugin(const void* data, size_t length);
~DeformableConvPlugin() override;
const char* getPluginType() const TRT_NOEXCEPT override;
const char* getPluginVersion() const TRT_NOEXCEPT override;
int getNbOutputs() const TRT_NOEXCEPT override;
nvinfer1::Dims getOutputDimensions(int index,
const nvinfer1::Dims* inputs,
int nb_input_dims) TRT_NOEXCEPT override;
bool supportsFormat(nvinfer1::DataType type, nvinfer1::TensorFormat format)
const TRT_NOEXCEPT override;
size_t getWorkspaceSize(int max_batch_size) const TRT_NOEXCEPT override;
int enqueue(int batch_size,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
int initialize() TRT_NOEXCEPT override;
void terminate() TRT_NOEXCEPT override;
size_t getSerializationSize() const TRT_NOEXCEPT override;
void serialize(void* buffer) const TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override;
void setPluginNamespace(const char* lib_namespace) TRT_NOEXCEPT override;
const char* getPluginNamespace() const TRT_NOEXCEPT override;
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* input_type,
int nb_inputs) const
TRT_NOEXCEPT override;
bool isOutputBroadcastAcrossBatch(int output_index,
const bool* input_is_broadcast,
int nb_inputs) const TRT_NOEXCEPT override;
bool canBroadcastInputAcrossBatch(int input_index) const
TRT_NOEXCEPT override;
void attachToContext(cudnnContext* cudnnContext,
cublasContext* cublasContext,
nvinfer1::IGpuAllocator* gpuAllocator)
TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::Dims* input_dims,
int nb_inputs,
const nvinfer1::Dims* output_dims,
int nb_outputs,
const nvinfer1::DataType* input_types,
const nvinfer1::DataType* output_types,
const bool* input_is_broadcast,
const bool* output_is_broadcast,
nvinfer1::PluginFormat float_format,
int max_batch_size) TRT_NOEXCEPT override;
nvinfer1::IPluginV2Ext* clone() const TRT_NOEXCEPT override;
private:
template <typename T>
int enqueue_impl(int batch_size,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream);
nvinfer1::Weights copyToDevice(const void* hostData, size_t count);
void serializeFromDevice(void** hostBuffer,
const nvinfer1::Weights& deviceWeights) const;
nvinfer1::Weights deserializeToDevice(const void** hostBuffer, size_t count);
bool with_fp16_;
nvinfer1::DataType data_type_;
nvinfer1::Weights weights_;
std::vector<int> kernel_dims_;
std::vector<int> strides_;
std::vector<int> paddings_;
std::vector<int> dilations_;
int groups_;
int deformable_groups_;
int im2col_step_;
std::string namespace_;
std::vector<int> input_dim_;
std::vector<int> offset_dim_;
std::vector<int> mask_dim_;
std::vector<int> output_dim_;
cublasHandle_t cublasHandle_;
};
class DeformableConvPluginCreator : public nvinfer1::IPluginCreator {
public:
DeformableConvPluginCreator() = default;
~DeformableConvPluginCreator() override = default;
void setPluginNamespace(const char* lib_namespace) TRT_NOEXCEPT override;
const char* getPluginNamespace() const TRT_NOEXCEPT override;
const char* getPluginName() const TRT_NOEXCEPT override;
const char* getPluginVersion() const TRT_NOEXCEPT override;
const nvinfer1::PluginFieldCollection* getFieldNames() TRT_NOEXCEPT override;
nvinfer1::IPluginV2Ext* createPlugin(
const char* name,
const nvinfer1::PluginFieldCollection* fc) TRT_NOEXCEPT override;
nvinfer1::IPluginV2Ext* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override;
private:
std::string namespace_;
nvinfer1::PluginFieldCollection field_collection_;
};
REGISTER_TRT_PLUGIN_V2(DeformableConvPluginCreator);
class DeformableConvPluginDynamic : public DynamicPluginTensorRT {
public:
explicit DeformableConvPluginDynamic(const nvinfer1::DataType data_type,
const nvinfer1::Weights& weights,
const std::vector<int>& kernel_dims,
const std::vector<int>& strides,
const std::vector<int>& paddings,
const std::vector<int>& dilations,
const int groups,
const int deformable_groups,
const int im2col_step,
const bool with_fp16);
DeformableConvPluginDynamic(const void* data, size_t length);
~DeformableConvPluginDynamic() override;
nvinfer1::IPluginV2DynamicExt* clone() const TRT_NOEXCEPT override {
return new DeformableConvPluginDynamic(data_type_,
weights_,
kernel_dims_,
strides_,
paddings_,
dilations_,
groups_,
deformable_groups_,
im2col_step_,
with_fp16_);
}
const char* getPluginType() const TRT_NOEXCEPT override {
return "deformable_conv_plugin_dynamic";
}
int getNbOutputs() const TRT_NOEXCEPT override { return 1; }
int initialize() TRT_NOEXCEPT override;
size_t getSerializationSize() const TRT_NOEXCEPT override;
void serialize(void* buffer) const TRT_NOEXCEPT override;
nvinfer1::DimsExprs getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs* inputs,
int nb_inputs,
nvinfer1::IExprBuilder& expr_builder) // NOLINT
TRT_NOEXCEPT override;
bool supportsFormatCombination(int pos,
const nvinfer1::PluginTensorDesc* inOut,
int nbInputs,
int nbOutputs) TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::DynamicPluginTensorDesc* in,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc* out,
int nbOutputs) TRT_NOEXCEPT override;
size_t getWorkspaceSize(const nvinfer1::PluginTensorDesc* inputs,
int nbInputs,
const nvinfer1::PluginTensorDesc* outputs,
int nbOutputs) const TRT_NOEXCEPT override;
int enqueue(const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override { delete this; }
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* inputTypes,
int nbInputs) const
TRT_NOEXCEPT override;
private:
nvinfer1::Weights copyToDevice(const void* hostData, size_t count);
void serializeFromDevice(void** hostBuffer,
const nvinfer1::Weights& deviceWeights) const;
nvinfer1::Weights deserializeToDevice(const void** hostBuffer, size_t count);
template <typename T>
int enqueue_impl(const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream);
bool with_fp16_;
nvinfer1::DataType data_type_;
nvinfer1::Weights weights_;
std::vector<int> kernel_dims_;
std::vector<int> strides_;
std::vector<int> paddings_;
std::vector<int> dilations_;
int groups_;
int deformable_groups_;
int im2col_step_;
std::string namespace_;
cublasHandle_t cublasHandle_;
};
class DeformableConvPluginDynamicCreator : public TensorRTPluginCreator {
public:
void setPluginNamespace(const char* lib_namespace) TRT_NOEXCEPT override {
namespace_ = lib_namespace;
}
const char* getPluginNamespace() const TRT_NOEXCEPT override {
return namespace_.c_str();
}
const char* getPluginName() const TRT_NOEXCEPT override {
return "deformable_conv_plugin_dynamic";
}
const char* getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
const nvinfer1::PluginFieldCollection* getFieldNames() TRT_NOEXCEPT override {
return &field_collection_;
}
nvinfer1::IPluginV2Ext* createPlugin(
const char* name,
const nvinfer1::PluginFieldCollection* fc) TRT_NOEXCEPT override;
nvinfer1::IPluginV2Ext* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override;
private:
std::string namespace_;
nvinfer1::PluginFieldCollection field_collection_;
};
class PIRDeformableConvPluginDynamic : public DynamicPluginTensorRT {
public:
explicit PIRDeformableConvPluginDynamic(const nvinfer1::DataType data_type,
const nvinfer1::Weights& weights,
const std::vector<int>& kernel_dims,
const std::vector<int>& strides,
const std::vector<int>& paddings,
const std::vector<int>& dilations,
const int groups,
const int deformable_groups,
const int im2col_step,
const bool with_fp16);
PIRDeformableConvPluginDynamic(const void* data, size_t length);
~PIRDeformableConvPluginDynamic() override;
nvinfer1::IPluginV2DynamicExt* clone() const TRT_NOEXCEPT override {
return new PIRDeformableConvPluginDynamic(data_type_,
weights_,
kernel_dims_,
strides_,
paddings_,
dilations_,
groups_,
deformable_groups_,
im2col_step_,
with_fp16_);
}
const char* getPluginType() const TRT_NOEXCEPT override {
return "deformable_conv_plugin_dynamic";
}
int getNbOutputs() const TRT_NOEXCEPT override { return 1; }
int initialize() TRT_NOEXCEPT override;
size_t getSerializationSize() const TRT_NOEXCEPT override;
void serialize(void* buffer) const TRT_NOEXCEPT override;
nvinfer1::DimsExprs getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs* inputs,
int nb_inputs,
nvinfer1::IExprBuilder& expr_builder) // NOLINT
TRT_NOEXCEPT override;
bool supportsFormatCombination(int pos,
const nvinfer1::PluginTensorDesc* inOut,
int nbInputs,
int nbOutputs) TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::DynamicPluginTensorDesc* in,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc* out,
int nbOutputs) TRT_NOEXCEPT override;
size_t getWorkspaceSize(const nvinfer1::PluginTensorDesc* inputs,
int nbInputs,
const nvinfer1::PluginTensorDesc* outputs,
int nbOutputs) const TRT_NOEXCEPT override;
int enqueue(const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override { delete this; }
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* inputTypes,
int nbInputs) const
TRT_NOEXCEPT override;
private:
nvinfer1::Weights copyToDevice(const void* hostData, size_t count);
void serializeFromDevice(void** hostBuffer,
const nvinfer1::Weights& deviceWeights) const;
nvinfer1::Weights deserializeToDevice(const void** hostBuffer, size_t count);
template <typename T>
int enqueue_impl(const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream);
bool with_fp16_;
nvinfer1::DataType data_type_;
nvinfer1::Weights weights_;
std::vector<int> kernel_dims_;
std::vector<int> strides_;
std::vector<int> paddings_;
std::vector<int> dilations_;
int groups_;
int deformable_groups_;
int im2col_step_;
std::string namespace_;
cublasHandle_t cublasHandle_;
};
class PIRDeformableConvPluginDynamicCreator : public nvinfer1::IPluginCreator {
public:
PIRDeformableConvPluginDynamicCreator() = default;
~PIRDeformableConvPluginDynamicCreator() override = default;
void setPluginNamespace(const char* lib_namespace) TRT_NOEXCEPT override;
const char* getPluginNamespace() const TRT_NOEXCEPT override;
const char* getPluginName() const TRT_NOEXCEPT override;
const char* getPluginVersion() const TRT_NOEXCEPT override;
const nvinfer1::PluginFieldCollection* getFieldNames() TRT_NOEXCEPT override;
nvinfer1::IPluginV2Ext* createPlugin(
const char* name,
const nvinfer1::PluginFieldCollection* fc) TRT_NOEXCEPT override;
nvinfer1::IPluginV2Ext* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override;
private:
std::string namespace_;
nvinfer1::PluginFieldCollection field_collection_;
};
REGISTER_TRT_PLUGIN_V2(PIRDeformableConvPluginDynamicCreator);
REGISTER_TRT_PLUGIN_V2(DeformableConvPluginDynamicCreator);
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,346 @@
/* Copyright (c) 2018 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 <glog/logging.h>
#include "paddle/fluid/inference/tensorrt/plugin/elementwise_op_plugin.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
namespace details {
template <typename T>
struct Add {
__device__ T operator()(const T &a, const T &b) const { return a + b; }
};
template <typename T>
struct Mul {
__device__ T operator()(const T &a, const T &b) const { return a * b; }
};
template <typename T>
struct Div {
__device__ T operator()(const T &a, const T &b) const { return a / b; }
};
template <typename T>
struct Sub {
__device__ T operator()(const T &a, const T &b) const { return a - b; }
};
template <typename T>
struct Pow {
__device__ T operator()(const T &a, const T &b) const {
return static_cast<T>(::powf(static_cast<float>(a), static_cast<float>(b)));
}
};
} // namespace details
template <typename T, typename Operator>
__global__ void elementwise_kernel(const size_t total,
const T *x_data,
const T *y_data,
T *out_data,
int pre,
int n,
int post,
Operator op) {
int tid = blockIdx.x * blockDim.x + threadIdx.x;
if (tid < total) {
int idx = tid / post % n;
#if __CUDA_ARCH__ >= 350
out_data[tid] = op(__ldg(x_data + tid), __ldg(y_data + idx));
#else
out_data[tid] = op(x_data[tid], y_data[idx]);
#endif
}
}
nvinfer1::Dims ElementWisePlugin::getOutputDimensions(
int index, const nvinfer1::Dims *input_dims, int num_inputs) TRT_NOEXCEPT {
PADDLE_ENFORCE_EQ(index,
0,
common::errors::InvalidArgument(
"There is only one output in TRT elementwise "
"op plugin, but got output index: %d.",
index));
PADDLE_ENFORCE_EQ(
num_inputs,
2,
common::errors::InvalidArgument("There are 2 inputs in TRT elementwise "
"op plugin, but got input number: %d.",
num_inputs));
PADDLE_ENFORCE_NOT_NULL(
input_dims,
common::errors::InvalidArgument(
"The input dims of TRT elementwise op plugin should not be null."));
return input_dims[0];
}
int ElementWisePlugin::initialize() TRT_NOEXCEPT {
axis_ = (axis_ == -1) ? dims_x_.nbDims - dims_y_.nbDims : axis_;
int trimmed_nb_dims = dims_y_.nbDims;
for (; trimmed_nb_dims > 0; --trimmed_nb_dims) {
if (dims_y_.d[trimmed_nb_dims - 1] != 1) {
break;
}
}
dims_y_.nbDims = trimmed_nb_dims;
PADDLE_ENFORCE_GE(dims_x_.nbDims,
dims_y_.nbDims + axis_,
common::errors::InvalidArgument(
"We expect [number of x dims] >= [number of y dims + "
"axis] in TRT elementwise op plugin, but got [number "
"of x dims] = %d, [number of y dims + axis] = %d.",
dims_x_.nbDims,
dims_y_.nbDims + axis_));
PADDLE_ENFORCE_LT(
axis_,
dims_x_.nbDims,
common::errors::InvalidArgument("We expect [axis] < [number of x dims] "
"in TRT elementwise op plugin, but got "
"[axis] = %d, [number of x dims] = %d.",
axis_,
dims_x_.nbDims));
prev_size_ = 1;
midd_size_ = 1;
post_size_ = 1;
for (int i = 0; i < axis_; ++i) {
prev_size_ *= dims_x_.d[i];
}
for (int i = 0; i < dims_y_.nbDims; ++i) {
PADDLE_ENFORCE_EQ(dims_x_.d[i + axis_],
dims_y_.d[i],
common::errors::InvalidArgument(
"Broadcast dimension mismatch. The dims of input Y "
"should be a subsequence of X."));
midd_size_ *= dims_y_.d[i];
}
for (int i = axis_ + dims_y_.nbDims; i < dims_x_.nbDims; ++i) {
post_size_ *= dims_x_.d[i];
}
return 0;
}
int ElementWisePlugin::enqueue(int batch_size,
const void *const *inputs,
void *const *outputs,
void *workspace,
cudaStream_t stream) TRT_NOEXCEPT {
const float *x = reinterpret_cast<const float *>(inputs[0]);
const float *y = reinterpret_cast<const float *>(inputs[1]);
float *out = reinterpret_cast<float *>(outputs[0]);
int num = batch_size * prev_size_ * midd_size_ * post_size_;
int thread = 256;
int block = (num + thread - 1) / thread;
if (type_ == "add") {
elementwise_kernel<<<block, thread, 0, stream>>>(num,
x,
y,
out,
prev_size_,
batch_size * midd_size_,
post_size_,
details::Add<float>());
} else if (type_ == "mul") {
elementwise_kernel<<<block, thread, 0, stream>>>(num,
x,
y,
out,
prev_size_,
batch_size * midd_size_,
post_size_,
details::Mul<float>());
} else if (type_ == "div") {
elementwise_kernel<<<block, thread, 0, stream>>>(num,
x,
y,
out,
prev_size_,
batch_size * midd_size_,
post_size_,
details::Div<float>());
} else if (type_ == "sub") {
elementwise_kernel<<<block, thread, 0, stream>>>(num,
x,
y,
out,
prev_size_,
batch_size * midd_size_,
post_size_,
details::Sub<float>());
} else if (type_ == "pow") {
elementwise_kernel<<<block, thread, 0, stream>>>(num,
x,
y,
out,
prev_size_,
batch_size * midd_size_,
post_size_,
details::Pow<float>());
} else {
PADDLE_THROW(common::errors::Fatal(
"The %s type elementwise is not implemented in trt plugin.", type_));
}
return cudaGetLastError() != cudaSuccess;
}
int ElementwisePluginDynamic::initialize() TRT_NOEXCEPT { return 0; }
size_t ElementwisePluginDynamic::getSerializationSize() const TRT_NOEXCEPT {
return SerializedSize(type_.c_str()) + SerializedSize(axis_);
}
void ElementwisePluginDynamic::serialize(void *buffer) const TRT_NOEXCEPT {
SerializeValue(&buffer, type_.c_str());
SerializeValue(&buffer, axis_);
}
nvinfer1::DimsExprs ElementwisePluginDynamic::getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs *inputs,
int nb_inputs,
nvinfer1::IExprBuilder &expr_builder) TRT_NOEXCEPT {
return inputs[0];
}
bool ElementwisePluginDynamic::supportsFormatCombination(
int pos,
const nvinfer1::PluginTensorDesc *in_out,
int nb_inputs,
int nb_outputs) TRT_NOEXCEPT {
PADDLE_ENFORCE_NOT_NULL(
in_out,
common::errors::InvalidArgument(
"The input of swish plugin should not be nullptr."));
PADDLE_ENFORCE_LT(
pos,
nb_inputs + nb_outputs,
common::errors::InvalidArgument("The pos(%d) should be less than the "
"num(%d) of the input and the output.",
pos,
nb_inputs + nb_outputs));
(in_out && pos < (nb_inputs + nb_outputs));
const nvinfer1::PluginTensorDesc &in = in_out[pos];
if (pos == 0) {
return (in.type == nvinfer1::DataType::kFLOAT) &&
(in.format == nvinfer1::TensorFormat::kLINEAR);
}
const nvinfer1::PluginTensorDesc &prev = in_out[pos - 1];
// output
return in.type == prev.type && in.format == prev.format;
}
nvinfer1::DataType ElementwisePluginDynamic::getOutputDataType(
int index,
const nvinfer1::DataType *input_types,
int nb_inputs) const TRT_NOEXCEPT {
PADDLE_ENFORCE_EQ(index,
0,
common::errors::InvalidArgument(
"The Elementwise Plugin only has one input, so the "
"index value should be 0, but get %d.",
index));
return input_types[0];
}
int ElementwisePluginDynamic::enqueue(
const nvinfer1::PluginTensorDesc *input_desc,
const nvinfer1::PluginTensorDesc *output_desc,
const void *const *inputs,
void *const *outputs,
void *workspace,
cudaStream_t stream) TRT_NOEXCEPT {
auto x_dims = input_desc[0].dims;
auto y_dims = input_desc[1].dims;
int axis = (axis_ == -1) ? x_dims.nbDims - y_dims.nbDims : axis_;
int batch_size = x_dims.d[0];
int prev_size = 1;
int midd_size = 1;
int post_size = 1;
for (int i = 0; i < axis; ++i) {
prev_size *= x_dims.d[i];
}
int trimmed_nb_dims = y_dims.nbDims;
for (; trimmed_nb_dims > 0; --trimmed_nb_dims) {
if (y_dims.d[trimmed_nb_dims - 1] != 1) {
break;
}
}
for (int i = 0; i < trimmed_nb_dims; ++i) {
PADDLE_ENFORCE_EQ(x_dims.d[i + axis],
y_dims.d[i],
common::errors::InvalidArgument(
"Broadcast dimension mismatch found in trt "
"elementwise plugin's x and y input."));
midd_size *= y_dims.d[i];
}
for (int i = axis + trimmed_nb_dims; i < x_dims.nbDims; ++i) {
post_size *= x_dims.d[i];
}
const float *x = static_cast<const float *>(inputs[0]);
const float *y = static_cast<const float *>(inputs[1]);
float *out = static_cast<float *>(outputs[0]);
int num = prev_size * midd_size * post_size;
int thread = 256;
int block = (num + thread - 1) / thread;
if (type_ == "add") {
elementwise_kernel<<<block, thread, 0, stream>>>(
num, x, y, out, prev_size, midd_size, post_size, details::Add<float>());
} else if (type_ == "mul") {
elementwise_kernel<<<block, thread, 0, stream>>>(
num, x, y, out, prev_size, midd_size, post_size, details::Mul<float>());
} else if (type_ == "div") {
elementwise_kernel<<<block, thread, 0, stream>>>(
num, x, y, out, prev_size, midd_size, post_size, details::Div<float>());
} else if (type_ == "sub") {
elementwise_kernel<<<block, thread, 0, stream>>>(
num, x, y, out, prev_size, midd_size, post_size, details::Sub<float>());
} else if (type_ == "pow") {
elementwise_kernel<<<block, thread, 0, stream>>>(
num, x, y, out, prev_size, midd_size, post_size, details::Pow<float>());
} else {
PADDLE_THROW(common::errors::Unimplemented(
"Paddle-TRT only support elementwise "
"operation: {add, mul, div, sub, pow} currently, "
"but got %s.",
type_));
}
return cudaGetLastError() != cudaSuccess;
}
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,231 @@
/* Copyright (c) 2018 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. */
#pragma once
#include <string>
#include <vector>
#include "paddle/fluid/inference/tensorrt/plugin/trt_plugin.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
class ElementWisePlugin : public PluginTensorRT {
public:
ElementWisePlugin(std::string type,
nvinfer1::Dims const& dims_x,
nvinfer1::Dims const& dims_y,
int axis)
: type_(type),
dims_x_(dims_x),
dims_y_(dims_y),
axis_(axis),
prev_size_(1),
midd_size_(1),
post_size_(1) {}
ElementWisePlugin(void const* serial_data, size_t serial_length) {
deserializeBase(serial_data, serial_length);
const char* elementwise_type;
DeserializeValue(&serial_data, &serial_length, &elementwise_type);
type_ = std::string(elementwise_type);
DeserializeValue(&serial_data, &serial_length, &dims_x_);
DeserializeValue(&serial_data, &serial_length, &dims_y_);
DeserializeValue(&serial_data, &serial_length, &axis_);
DeserializeValue(&serial_data, &serial_length, &prev_size_);
DeserializeValue(&serial_data, &serial_length, &midd_size_);
DeserializeValue(&serial_data, &serial_length, &post_size_);
}
ElementWisePlugin* clone() const TRT_NOEXCEPT override {
return new ElementWisePlugin(type_, dims_x_, dims_y_, axis_);
}
const char* getPluginType() const TRT_NOEXCEPT override {
return "elementwise_plugin";
}
nvinfer1::Dims getOutputDimensions(int index,
const nvinfer1::Dims* input_dims,
int num_inputs) TRT_NOEXCEPT override;
int initialize() TRT_NOEXCEPT override;
int enqueue(int batch_size,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT;
size_t getSerializationSize() const TRT_NOEXCEPT override {
return getBaseSerializationSize() + SerializedSize(type_.c_str()) +
SerializedSize(dims_x_) + SerializedSize(dims_y_) +
SerializedSize(axis_) + SerializedSize(prev_size_) +
SerializedSize(midd_size_) + SerializedSize(post_size_);
}
void serialize(void* buffer) const TRT_NOEXCEPT override {
serializeBase(buffer);
SerializeValue(&buffer, type_.c_str());
SerializeValue(&buffer, dims_x_);
SerializeValue(&buffer, dims_y_);
SerializeValue(&buffer, axis_);
SerializeValue(&buffer, prev_size_);
SerializeValue(&buffer, midd_size_);
SerializeValue(&buffer, post_size_);
}
protected:
std::string type_;
nvinfer1::Dims dims_x_;
nvinfer1::Dims dims_y_;
int axis_;
int prev_size_;
int midd_size_;
int post_size_;
};
class ElementWisePluginCreator : public TensorRTPluginCreator {
public:
const char* getPluginName() const TRT_NOEXCEPT override {
return "elementwise_plugin";
}
const char* getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
nvinfer1::IPluginV2* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override {
return new ElementWisePlugin(serial_data, serial_length);
}
};
REGISTER_TRT_PLUGIN_V2(ElementWisePluginCreator);
class ElementwisePluginDynamic : public DynamicPluginTensorRT {
public:
explicit ElementwisePluginDynamic(const std::string& type, int axis)
: type_(type), axis_(axis) {}
ElementwisePluginDynamic(void const* serialData, size_t serialLength) {
const char* elementwise_type;
DeserializeValue(&serialData, &serialLength, &elementwise_type);
type_ = std::string(elementwise_type);
DeserializeValue(&serialData, &serialLength, &axis_);
}
nvinfer1::IPluginV2DynamicExt* clone() const TRT_NOEXCEPT override {
return new ElementwisePluginDynamic(type_, axis_);
}
const char* getPluginType() const TRT_NOEXCEPT override {
return "elementwise_plugin_dynamic";
}
int getNbOutputs() const TRT_NOEXCEPT override { return 1; }
int initialize() TRT_NOEXCEPT override;
size_t getSerializationSize() const TRT_NOEXCEPT override;
void serialize(void* buffer) const TRT_NOEXCEPT override;
nvinfer1::DimsExprs getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs* inputs,
int nb_inputs,
nvinfer1::IExprBuilder& expr_builder) // NOLINT
TRT_NOEXCEPT override;
bool supportsFormatCombination(int pos,
const nvinfer1::PluginTensorDesc* inOut,
int nbInputs,
int nbOutputs) TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::DynamicPluginTensorDesc* in,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc* out,
int nbOutputs) TRT_NOEXCEPT override {}
size_t getWorkspaceSize(const nvinfer1::PluginTensorDesc* inputs,
int nbInputs,
const nvinfer1::PluginTensorDesc* outputs,
int nbOutputs) const TRT_NOEXCEPT override {
return 0;
}
int enqueue(const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* inputTypes,
int nbInputs) const
TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override { delete this; }
private:
std::string type_;
int axis_;
};
class ElementwisePluginDynamicCreator : public nvinfer1::IPluginCreator {
public:
ElementwisePluginDynamicCreator() {}
const char* getPluginName() const TRT_NOEXCEPT override {
return "elementwise_plugin_dynamic";
}
const char* getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
const nvinfer1::PluginFieldCollection* getFieldNames() TRT_NOEXCEPT override {
return &field_collection_;
}
nvinfer1::IPluginV2* createPlugin(const char* name,
const nvinfer1::PluginFieldCollection* fc)
TRT_NOEXCEPT override {
return nullptr;
}
nvinfer1::IPluginV2* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override {
auto plugin = new ElementwisePluginDynamic(serial_data, serial_length);
return plugin;
}
void setPluginNamespace(const char* lib_namespace) TRT_NOEXCEPT override {
plugin_namespace_ = lib_namespace;
}
const char* getPluginNamespace() const TRT_NOEXCEPT override {
return plugin_namespace_.c_str();
}
private:
std::string plugin_namespace_;
std::string plugin_name_;
nvinfer1::PluginFieldCollection field_collection_{0, nullptr};
std::vector<nvinfer1::PluginField> plugin_attributes_;
};
REGISTER_TRT_PLUGIN_V2(ElementwisePluginDynamicCreator);
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,260 @@
/* Copyright (c) 2023 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/plugin/elementwiseadd_transpose_op_plugin.h"
#include <glog/logging.h>
#include "paddle/fluid/framework/tensor.h"
#include "paddle/fluid/framework/tensor_util.h"
#include "paddle/phi/backends/gpu/gpu_context.h"
#include "paddle/phi/kernels/elementwise_add_kernel.h"
#include "paddle/phi/kernels/transpose_kernel.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
int ElementwiseAddTransposePluginDynamic::initialize() TRT_NOEXCEPT {
return 0;
}
size_t ElementwiseAddTransposePluginDynamic::getSerializationSize() const
TRT_NOEXCEPT {
return SerializedSize(axis_) + SerializedSize(output_shape_);
}
void ElementwiseAddTransposePluginDynamic::serialize(void *buffer) const
TRT_NOEXCEPT {
SerializeValue(&buffer, axis_);
SerializeValue(&buffer, output_shape_);
}
nvinfer1::DimsExprs ElementwiseAddTransposePluginDynamic::getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs *inputs,
int nb_inputs,
nvinfer1::IExprBuilder &expr_builder) TRT_NOEXCEPT {
nvinfer1::DimsExprs ret;
ret.nbDims = 4;
ret.d[0] = inputs[0].d[0];
ret.d[1] = inputs[0].d[2];
ret.d[2] = expr_builder.constant(output_shape_[1]);
ret.d[3] = expr_builder.constant(output_shape_[2]);
return ret;
}
bool ElementwiseAddTransposePluginDynamic::supportsFormatCombination(
int pos,
const nvinfer1::PluginTensorDesc *in_out,
int nb_inputs,
int nb_outputs) TRT_NOEXCEPT {
PADDLE_ENFORCE_NOT_NULL(
in_out,
common::errors::InvalidArgument("The input of elementwiseadd_transpose "
"plugin should not be nullptr."));
PADDLE_ENFORCE_LT(
pos,
nb_inputs + nb_outputs,
common::errors::InvalidArgument("The pos(%d) should be less than the "
"num(%d) of the input and the output.",
pos,
nb_inputs + nb_outputs));
// (in_out && pos < (nb_inputs + nb_outputs));
const nvinfer1::PluginTensorDesc &in = in_out[pos];
// input 0
if (pos == 0) {
return (in.type == nvinfer1::DataType::kHALF ||
in.type == nvinfer1::DataType::kFLOAT) &&
(in.format == nvinfer1::TensorFormat::kLINEAR);
}
// input 1
if (pos == 1) {
return (in.type == in_out[0].type) &&
(in.format == nvinfer1::TensorFormat::kLINEAR);
}
// output 0
if (pos == 2) {
bool support_format = in.format == nvinfer1::TensorFormat::kLINEAR ||
in.format == nvinfer1::TensorFormat::kHWC8;
return (in.type == in_out[0].type) && (support_format);
}
}
void ElementwiseAddTransposePluginDynamic::configurePlugin(
const nvinfer1::DynamicPluginTensorDesc *input_desc,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc *output_desc,
int nbOutputs) TRT_NOEXCEPT {
const auto &x_dims = input_desc[0].desc.dims;
const auto &y_dims = input_desc[1].desc.dims;
const auto &out_dims = output_desc[0].desc.dims;
const auto &x_type = input_desc[0].desc.type;
std::vector<int> x_shape;
int x_numel = 1;
for (int i = 0; i < x_dims.nbDims; i++) {
x_shape.push_back(x_dims.d[i]);
x_numel *= x_dims.d[i];
}
std::vector<int> y_shape;
int y_numel = 1;
for (int i = 0; i < y_dims.nbDims; i++) {
y_shape.push_back(y_dims.d[i]);
y_numel *= y_dims.d[i];
}
std::vector<int> out_shape;
int out_numel = 1;
for (int i = 0; i < out_dims.nbDims; i++) {
out_shape.push_back(out_dims.d[i]);
out_numel *= out_dims.d[i];
}
x_numel_ = x_numel;
y_numel_ = y_numel;
out_numel_ = out_numel;
if (x_numel <= 0) {
return;
}
ele_out_tensor_.Resize(common::make_ddim(x_shape));
phi::DeviceContextPool &pool = phi::DeviceContextPool::Instance();
GPUPlace place(platform::GetCurrentDeviceId());
auto *device_context = static_cast<phi::GPUContext *>(pool.Get(place));
const phi::GPUContext &dev_ctx = *device_context;
if (x_type == nvinfer1::DataType::kFLOAT) {
x_meta_ = phi::DenseTensorMeta(phi::DataType::FLOAT32,
common::make_ddim(x_shape));
y_meta_ = phi::DenseTensorMeta(phi::DataType::FLOAT32,
common::make_ddim(y_shape));
out_meta_ = phi::DenseTensorMeta(phi::DataType::FLOAT32,
common::make_ddim(out_shape));
dev_ctx.template Alloc<float>(&ele_out_tensor_, x_numel * sizeof(float));
} else if (x_type == nvinfer1::DataType::kHALF) {
x_meta_ = phi::DenseTensorMeta(phi::DataType::FLOAT16,
common::make_ddim(x_shape));
y_meta_ = phi::DenseTensorMeta(phi::DataType::FLOAT16,
common::make_ddim(y_shape));
out_meta_ = phi::DenseTensorMeta(phi::DataType::FLOAT16,
common::make_ddim(out_shape));
dev_ctx.template Alloc<phi::dtype::float16>(
&ele_out_tensor_, x_numel * sizeof(phi::dtype::float16));
}
}
nvinfer1::DataType ElementwiseAddTransposePluginDynamic::getOutputDataType(
int index,
const nvinfer1::DataType *input_types,
int nb_inputs) const TRT_NOEXCEPT {
PADDLE_ENFORCE_EQ(index,
0,
common::errors::InvalidArgument(
"The Elementwise Plugin only has one input, so the "
"index value should be 0, but get %d.",
index));
return input_types[0];
}
int ElementwiseAddTransposePluginDynamic::enqueue(
const nvinfer1::PluginTensorDesc *input_desc,
const nvinfer1::PluginTensorDesc *output_desc,
const void *const *inputs,
void *const *outputs,
void *workspace,
cudaStream_t stream) TRT_NOEXCEPT {
phi::DeviceContextPool &pool = phi::DeviceContextPool::Instance();
GPUPlace place(platform::GetCurrentDeviceId());
auto *device_context = static_cast<phi::GPUContext *>(pool.Get(place));
const phi::GPUContext &dev_ctx = *device_context;
auto input_type = input_desc[0].type;
auto output_format = output_desc[0].format;
if (input_type == nvinfer1::DataType::kFLOAT) {
VLOG(1) << "TRT Plugin DataType selected. elementwiseadd_transpose-->fp32";
const float *x = static_cast<const float *>(inputs[0]);
const float *y = static_cast<const float *>(inputs[1]);
float *out = static_cast<float *>(outputs[0]);
VLOG(1) << "TRT Plugin format selected. elementwiseadd_transpose-->kLINEAR";
std::shared_ptr<phi::Allocation> x_alloc(new phi::Allocation(
static_cast<void *>(const_cast<float *>(x)), // NOLINT
x_numel_ * sizeof(float),
place));
std::shared_ptr<phi::Allocation> y_alloc(new phi::Allocation(
static_cast<void *>(const_cast<float *>(y)), // NOLINT
y_numel_ * sizeof(float),
place));
std::shared_ptr<phi::Allocation> out_alloc(
new phi::Allocation(static_cast<void *>(out), // NOLINT
out_numel_ * sizeof(float),
place));
const phi::DenseTensor x_tensor = phi::DenseTensor(x_alloc, x_meta_);
const phi::DenseTensor y_tensor = phi::DenseTensor(y_alloc, y_meta_);
phi::DenseTensor out_tensor = phi::DenseTensor(out_alloc, out_meta_);
phi::AddKernel<float, phi::GPUContext>(
dev_ctx, x_tensor, y_tensor, &ele_out_tensor_);
phi::TransposeKernel<float, phi::GPUContext>(
dev_ctx, ele_out_tensor_, std::vector<int>{0, 2, 1}, &out_tensor);
} else if (input_type == nvinfer1::DataType::kHALF) {
VLOG(1) << "TRT Plugin DataType selected. elementwiseadd_transpose-->fp16";
const half *x = static_cast<const half *>(inputs[0]);
const half *y = static_cast<const half *>(inputs[1]);
half *out = static_cast<half *>(outputs[0]);
if (output_format == nvinfer1::PluginFormat::kLINEAR) {
VLOG(1)
<< "TRT Plugin format selected. elementwiseadd_transpose-->kLINEAR";
std::shared_ptr<phi::Allocation> x_alloc(new phi::Allocation(
static_cast<void *>(const_cast<half *>(x)), // NOLINT
x_numel_ * sizeof(half),
place));
std::shared_ptr<phi::Allocation> y_alloc(new phi::Allocation(
static_cast<void *>(const_cast<half *>(y)), // NOLINT
y_numel_ * sizeof(half),
place));
std::shared_ptr<phi::Allocation> out_alloc(
new phi::Allocation(static_cast<void *>(out), // NOLINT
out_numel_ * sizeof(half),
place));
const phi::DenseTensor x_tensor = phi::DenseTensor(x_alloc, x_meta_);
const phi::DenseTensor y_tensor = phi::DenseTensor(y_alloc, y_meta_);
phi::DenseTensor out_tensor = phi::DenseTensor(out_alloc, out_meta_);
phi::AddKernel<phi::dtype::float16, phi::GPUContext>(
dev_ctx, x_tensor, y_tensor, &ele_out_tensor_);
phi::TransposeKernel<phi::dtype::float16, phi::GPUContext>(
dev_ctx, ele_out_tensor_, std::vector<int>{0, 2, 1}, &out_tensor);
} else if (output_format == nvinfer1::PluginFormat::kHWC8) {
VLOG(1) << "TRT Plugin format selected. elementwiseadd_transpose-->kHWC8";
std::shared_ptr<phi::Allocation> x_alloc(new phi::Allocation(
static_cast<void *>(const_cast<half *>(x)), // NOLINT
x_numel_ * sizeof(half),
place));
std::shared_ptr<phi::Allocation> y_alloc(new phi::Allocation(
static_cast<void *>(const_cast<half *>(y)), // NOLINT
y_numel_ * sizeof(half),
place));
std::shared_ptr<phi::Allocation> out_alloc(
new phi::Allocation(static_cast<void *>(out), // NOLINT
out_numel_ * sizeof(half),
place));
const phi::DenseTensor x_tensor = phi::DenseTensor(x_alloc, x_meta_);
const phi::DenseTensor y_tensor = phi::DenseTensor(y_alloc, y_meta_);
phi::DenseTensor out_tensor = phi::DenseTensor(out_alloc, out_meta_);
phi::AddKernel<phi::dtype::float16, phi::GPUContext>(
dev_ctx, x_tensor, y_tensor, &out_tensor);
}
}
return cudaGetLastError() != cudaSuccess;
}
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,150 @@
/* Copyright (c) 2023 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. */
#pragma once
#include <string>
#include <vector>
#include "paddle/fluid/framework/tensor.h"
#include "paddle/fluid/framework/tensor_util.h"
#include "paddle/fluid/inference/tensorrt/plugin/trt_plugin.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
class ElementwiseAddTransposePluginDynamic : public DynamicPluginTensorRT {
public:
explicit ElementwiseAddTransposePluginDynamic(int axis,
std::vector<int> output_shape)
: axis_(axis), output_shape_(output_shape) {}
ElementwiseAddTransposePluginDynamic(void const* serialData,
size_t serialLength) {
DeserializeValue(&serialData, &serialLength, &axis_);
DeserializeValue(&serialData, &serialLength, &output_shape_);
}
nvinfer1::IPluginV2DynamicExt* clone() const TRT_NOEXCEPT override {
return new ElementwiseAddTransposePluginDynamic(axis_, output_shape_);
}
const char* getPluginType() const TRT_NOEXCEPT override {
return "elementwise_add_transpose_plugin_dynamic";
}
int getNbOutputs() const TRT_NOEXCEPT override { return 1; }
int initialize() TRT_NOEXCEPT override;
size_t getSerializationSize() const TRT_NOEXCEPT override;
void serialize(void* buffer) const TRT_NOEXCEPT override;
nvinfer1::DimsExprs getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs* inputs,
int nb_inputs,
nvinfer1::IExprBuilder& expr_builder) // NOLINT
TRT_NOEXCEPT override;
bool supportsFormatCombination(int pos,
const nvinfer1::PluginTensorDesc* inOut,
int nbInputs,
int nbOutputs) TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::DynamicPluginTensorDesc* input_desc,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc* output_desc,
int nbOutputs) TRT_NOEXCEPT override;
size_t getWorkspaceSize(const nvinfer1::PluginTensorDesc* inputs,
int nbInputs,
const nvinfer1::PluginTensorDesc* outputs,
int nbOutputs) const TRT_NOEXCEPT override {
return 0;
}
int enqueue(const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* inputTypes,
int nbInputs) const
TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override { delete this; }
private:
int axis_;
std::vector<int> output_shape_;
phi::DenseTensorMeta x_meta_;
phi::DenseTensorMeta y_meta_;
phi::DenseTensorMeta out_meta_;
phi::DenseTensor ele_out_tensor_;
int x_numel_ = -1;
int y_numel_ = -1;
int out_numel_ = -1;
};
class ElementwiseAddTransposePluginDynamicCreator
: public nvinfer1::IPluginCreator {
public:
ElementwiseAddTransposePluginDynamicCreator() {}
const char* getPluginName() const TRT_NOEXCEPT override {
return "elementwise_add_transpose_plugin_dynamic";
}
const char* getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
const nvinfer1::PluginFieldCollection* getFieldNames() TRT_NOEXCEPT override {
return &field_collection_;
}
nvinfer1::IPluginV2* createPlugin(const char* name,
const nvinfer1::PluginFieldCollection* fc)
TRT_NOEXCEPT override {
return nullptr;
}
nvinfer1::IPluginV2* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override {
auto plugin =
new ElementwiseAddTransposePluginDynamic(serial_data, serial_length);
return plugin;
}
void setPluginNamespace(const char* lib_namespace) TRT_NOEXCEPT override {
plugin_namespace_ = lib_namespace;
}
const char* getPluginNamespace() const TRT_NOEXCEPT override {
return plugin_namespace_.c_str();
}
private:
std::string plugin_namespace_;
std::string plugin_name_;
nvinfer1::PluginFieldCollection field_collection_{0, nullptr};
std::vector<nvinfer1::PluginField> plugin_attributes_;
};
REGISTER_TRT_PLUGIN_V2(ElementwiseAddTransposePluginDynamicCreator);
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,657 @@
// Copyright (c) 2022 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 <vector>
#include "cub/cub.cuh"
#include "paddle/phi/kernels/funcs/math_function.h"
#include "paddle/phi/common/memory_utils.h"
#include "paddle/phi/core/platform/device/gpu/gpu_info.h"
#include "paddle/fluid/framework/tensor.h"
#include "paddle/fluid/framework/tensor_util.h"
#include "paddle/phi/backends/gpu/gpu_primitives.h"
#include "paddle/phi/core/platform/device_context.h"
#include "paddle/fluid/inference/tensorrt/plugin/fused_token_prune_op_plugin.h"
#include "paddle/phi/kernels/funcs/fused_token_prune_utils.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
__global__ void compute_token_length(const int32_t* src,
int32_t* dst,
float scale) {
int32_t it = threadIdx.x;
dst[it] = max(static_cast<int>((src[it + 1] - src[it]) * scale), 1);
}
template <typename T>
__global__ void fill_index_padding_score(int32_t* token_index,
const T* scores,
int32_t sequence_length,
T* padding_scores) {
int padding_scores_it = threadIdx.x + blockIdx.x * blockDim.x;
int scores_it = threadIdx.x + blockIdx.x * sequence_length;
token_index[padding_scores_it] = threadIdx.x;
if (threadIdx.x < sequence_length) {
padding_scores[padding_scores_it] = scores[scores_it];
} else {
padding_scores[padding_scores_it] = 0;
}
}
template <typename T, int BLOCK_THREADS, int ITEMS_PER_THREAD>
__global__ void general_topk_pair_sort(T* in_keys, int32_t* in_out_values) {
typedef cub::BlockRadixSort<T, BLOCK_THREADS, ITEMS_PER_THREAD, int>
BlockRadixSort;
typedef cub::
BlockLoad<T, BLOCK_THREADS, ITEMS_PER_THREAD, cub::BLOCK_LOAD_TRANSPOSE>
BlockLoadKey;
typedef cub::
BlockLoad<int, BLOCK_THREADS, ITEMS_PER_THREAD, cub::BLOCK_LOAD_TRANSPOSE>
BlockLoadValue;
typedef cub::
BlockStore<T, BLOCK_THREADS, ITEMS_PER_THREAD, cub::BLOCK_STORE_TRANSPOSE>
BlockStoreKey;
typedef cub::BlockStore<int,
BLOCK_THREADS,
ITEMS_PER_THREAD,
cub::BLOCK_STORE_TRANSPOSE>
BlockStoreValue;
__shared__ union {
typename BlockRadixSort::TempStorage sort;
typename BlockLoadKey::TempStorage loadkey;
typename BlockLoadValue::TempStorage loadvalue;
typename BlockStoreKey::TempStorage storekey;
typename BlockStoreValue::TempStorage storevalue;
} temp_storage;
int block_offset = blockIdx.x * BLOCK_THREADS * ITEMS_PER_THREAD;
T thread_keys[ITEMS_PER_THREAD];
int thread_values[ITEMS_PER_THREAD];
BlockLoadKey(temp_storage.loadkey).Load(in_keys + block_offset, thread_keys);
BlockLoadValue(temp_storage.loadvalue)
.Load(in_out_values + block_offset, thread_values);
__syncthreads();
BlockRadixSort(temp_storage.sort).SortDescending(thread_keys, thread_values);
__syncthreads();
BlockStoreValue(temp_storage.storevalue)
.Store(in_out_values + block_offset, thread_values);
}
__global__ void varlen_prune_token_change_order(
const half* tokens,
const int32_t* token_pos,
const int32_t padding_token_length,
const int32_t* token_index,
half* output) {
int batch = blockIdx.x;
int token_it = batch * gridDim.y + blockIdx.y;
int pre_value_it =
token_it * gridDim.z * blockDim.x + blockIdx.z * blockDim.x + threadIdx.x;
int token_index_it = batch * padding_token_length + blockIdx.y;
if (token_index[token_index_it] < token_pos[batch + 1] - token_pos[batch]) {
output[(token_index[token_index_it] + token_pos[batch]) * gridDim.z *
blockDim.x +
blockIdx.z * blockDim.x + threadIdx.x] = tokens[pre_value_it];
}
}
template <typename T>
__global__ void prune_token_change_order(const T* tokens,
int32_t new_sequence_length,
const int32_t padding_token_length,
const int32_t* token_index,
T* output) {
int batch = blockIdx.x;
int token_it = batch * gridDim.y + blockIdx.y;
int pre_value_it =
token_it * gridDim.z * blockDim.x + blockIdx.z * blockDim.x + threadIdx.x;
int token_index_it = batch * padding_token_length + blockIdx.y;
if (token_index[token_index_it] < new_sequence_length) {
output[(batch * new_sequence_length + token_index[token_index_it]) *
gridDim.z * blockDim.x +
blockIdx.z * blockDim.x + threadIdx.x] = tokens[pre_value_it];
}
}
template <typename T>
__global__ void prune_token_keep_order(const T* tokens,
int32_t pre_sequence_length,
int32_t new_sequence_length,
const int32_t padding_token_length,
const int32_t* token_index,
T* output0,
int32_t* output1) {
int batch = blockIdx.x;
int index = 0;
for (int i = 0; i < pre_sequence_length; ++i) {
if (token_index[batch * padding_token_length + i] < new_sequence_length) {
output0[(batch * new_sequence_length + index) * gridDim.y * blockDim.x +
blockIdx.y * blockDim.x + threadIdx.x] =
tokens[(batch * pre_sequence_length + i) * gridDim.y * blockDim.x +
blockIdx.y * blockDim.x + threadIdx.x];
output1[batch * new_sequence_length + index] = i;
index++;
}
}
}
nvinfer1::DimsExprs FusedTokenPrunePluginDynamic::getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs* inputs,
int nb_inputs,
nvinfer1::IExprBuilder& expr_builder) TRT_NOEXCEPT {
auto x_dims = inputs[1], new_mask_dims = inputs[3];
if (flag_varseqlen_) {
// max sum of seqlen: ceil(sum / scale) + n -1 >= for(i=0;i<n;i++) {sum +=
// floor(num(i) / scale)} auto
// pruned_sum_length=std::ceil(inputs[4].d[0]*new_mask_dims.d[2]/inputs[6].d[1])+
// inputs[1].d[0] - 1;
auto pruned_sum_length = expr_builder.operation(
nvinfer1::DimensionOperation::kSUB,
*expr_builder.operation(
nvinfer1::DimensionOperation::kSUM,
*expr_builder.operation(
nvinfer1::DimensionOperation::kCEIL_DIV,
*expr_builder.operation(nvinfer1::DimensionOperation::kPROD,
*inputs[4].d[0],
*new_mask_dims.d[2]),
*inputs[6].d[1]),
*inputs[1].d[0]),
*expr_builder.constant(1));
if (output_index == 0) {
nvinfer1::DimsExprs ret;
ret.nbDims = 4;
ret.d[0] = pruned_sum_length;
ret.d[1] = x_dims.d[2];
ret.d[2] = expr_builder.constant(1);
ret.d[3] = expr_builder.constant(1);
return ret;
} else if (output_index == 1) {
nvinfer1::DimsExprs ret;
ret.nbDims = 2;
ret.d[0] = new_mask_dims.d[0];
ret.d[1] = new_mask_dims.d[2];
return ret;
} else if (output_index == 2) {
// word id
nvinfer1::DimsExprs ret;
ret.nbDims = 1;
ret.d[0] = pruned_sum_length;
return ret;
} else if (output_index == 3) {
// pos id
nvinfer1::DimsExprs ret = inputs[5];
return ret;
} else if (output_index == 4) {
// mask id
nvinfer1::DimsExprs ret;
ret.nbDims = 2;
ret.d[0] = inputs[6].d[0];
ret.d[1] = new_mask_dims.d[2];
return ret;
}
} else {
if (output_index == 0) {
nvinfer1::DimsExprs ret = x_dims;
ret.d[1] = new_mask_dims.d[2];
return ret;
} else {
nvinfer1::DimsExprs ret;
ret.nbDims = 2;
ret.d[0] = new_mask_dims.d[0];
ret.d[1] = new_mask_dims.d[2];
return ret;
}
}
}
bool FusedTokenPrunePluginDynamic::supportsFormatCombination(
int pos,
const nvinfer1::PluginTensorDesc* in_out,
int nb_inputs,
int nb_outputs) TRT_NOEXCEPT {
PADDLE_ENFORCE_NOT_NULL(
in_out,
common::errors::InvalidArgument(
"The input of swish plugin should not be nullptr."));
PADDLE_ENFORCE_LT(
pos,
nb_inputs + nb_outputs,
common::errors::InvalidArgument("The pos(%d) should be less than the "
"num(%d) of the input and the output.",
pos,
nb_inputs + nb_outputs));
const nvinfer1::PluginTensorDesc& in = in_out[pos];
if (flag_varseqlen_) {
if (pos <= 3 || pos == 7) {
if (with_fp16_) {
return (in.type == nvinfer1::DataType::kHALF) &&
(in.format == nvinfer1::TensorFormat::kLINEAR);
} else {
PADDLE_THROW(
common::errors::Fatal("The FusedTokenPrune TRT Plugin's input type "
"should be half for varseqlen."));
}
} else if (pos == 6 || pos == 11) { // mask_id, mask_id_out
return (in.type == nvinfer1::DataType::kHALF) &&
(in.format == nvinfer1::TensorFormat::kLINEAR);
} else {
return in.type == nvinfer1::DataType::kINT32 &&
in.format == nvinfer1::TensorFormat::kLINEAR;
}
} else {
if (pos == 0) {
if (with_fp16_) {
return (in.type == nvinfer1::DataType::kHALF) &&
(in.format == nvinfer1::TensorFormat::kLINEAR);
} else {
return (in.type == nvinfer1::DataType::kFLOAT) &&
(in.format == nvinfer1::TensorFormat::kLINEAR);
}
} else if (pos <= 4) {
const nvinfer1::PluginTensorDesc& prev = in_out[0];
return in.type == prev.type && in.format == prev.format;
} else {
return in.type == nvinfer1::DataType::kINT32 &&
in.format == nvinfer1::TensorFormat::kLINEAR;
}
}
}
nvinfer1::DataType FusedTokenPrunePluginDynamic::getOutputDataType(
int index,
const nvinfer1::DataType* input_types,
int nb_inputs) const TRT_NOEXCEPT {
if (flag_varseqlen_) {
if (index == 0) {
return nvinfer1::DataType::kHALF;
} else if (index == 4) { // mask id
return input_types[6];
} else {
// index = 1,2,3
return nvinfer1::DataType::kINT32;
}
} else {
if (index == 0) {
return input_types[1];
} else {
// index = 1
return nvinfer1::DataType::kINT32;
}
}
}
size_t FusedTokenPrunePluginDynamic::getWorkspaceSize(
const nvinfer1::PluginTensorDesc* inputs,
int nb_inputs,
const nvinfer1::PluginTensorDesc* outputs,
int nb_outputs) const TRT_NOEXCEPT {
auto attn_dims = inputs[0].dims;
auto x_dims = inputs[1].dims;
auto new_mask_dims = inputs[3].dims;
auto bsz = attn_dims.d[0], nb_head = attn_dims.d[1],
max_seq_len = attn_dims.d[2];
int slimmed_x_len = new_mask_dims.d[2];
int total = bsz * nb_head * max_seq_len * max_seq_len;
size_t size = total * sizeof(float);
size += bsz * max_seq_len * sizeof(float);
size += bsz * max_seq_len * sizeof(int32_t);
size += bsz * max_seq_len * sizeof(float);
size += bsz * max_seq_len * sizeof(int32_t);
size += (bsz + 1) * sizeof(int);
size += bsz * slimmed_x_len * sizeof(int32_t);
return size;
}
int FusedTokenPrunePluginDynamic::enqueue(
const nvinfer1::PluginTensorDesc* input_desc,
const nvinfer1::PluginTensorDesc* output_desc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT {
if (flag_varseqlen_) {
if (!(input_desc[0].type == nvinfer1::DataType::kHALF &&
input_desc[1].type == nvinfer1::DataType::kHALF)) {
PADDLE_THROW(common::errors::InvalidArgument(
"Token_prune'type must half for varseqlen"));
}
float scale =
static_cast<float>(input_desc[3].dims.d[2]) / input_desc[2].dims.d[2];
const int32_t* input5 =
static_cast<const int32_t*>(inputs[5]); // pre pos id
int32_t* output3 = static_cast<int32_t*>(outputs[3]); // new pos id
half* output0 = static_cast<half*>(outputs[0]);
const int32_t B = input_desc[1].dims.d[0]; // batches
const int32_t max_sequence_length =
input_desc[1].dims.d[1]; // max sequence length
const int32_t length = input_desc[1].dims.d[2]; // hidden size
const half* scores = static_cast<const half*>(inputs[0]); // reduce sum
const half* tokens = static_cast<const half*>(inputs[1]);
int32_t padding_token_length;
if (max_sequence_length <= 64) {
padding_token_length = 64;
} else if (max_sequence_length <= 128) {
padding_token_length = 128;
} else if (max_sequence_length <= 256) {
padding_token_length = 256;
} else if (max_sequence_length <= 384) {
padding_token_length = 384;
} else if (max_sequence_length <= 512) {
padding_token_length = 512;
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"Token_prune'token_length must <= 512"));
}
// 1. Compute the token length after pruning.
compute_token_length<<<1, B, 0, stream>>>(
input5, pruned_token_lengths_, scale);
// 2. Padding scores
fill_index_padding_score<half><<<B, padding_token_length, 0, stream>>>(
token_index_,
scores,
max_sequence_length,
static_cast<half*>(padding_scores_));
// 3. compute new pos id
// Determine temporary device storage requirements
size_t temp_storage_bytes = 0;
cub::DeviceScan::ExclusiveSum(
NULL, temp_storage_bytes, pruned_token_lengths_, output3, B + 1);
// Allocate temporary storage
GPUPlace place(platform::GetCurrentDeviceId());
auto d_temp_storage = phi::memory_utils::Alloc(place, temp_storage_bytes);
// Run exclusive prefix sum
cub::DeviceScan::ExclusiveSum(d_temp_storage->ptr(),
temp_storage_bytes,
pruned_token_lengths_,
output3,
B + 1);
// 4. sort scores
if (padding_token_length == 64) {
general_topk_pair_sort<half, 32, 2><<<B, 32, 0, stream>>>(
static_cast<half*>(padding_scores_), token_index_); // 64
} else if (padding_token_length == 128) {
general_topk_pair_sort<half, 32, 4><<<B, 32, 0, stream>>>(
static_cast<half*>(padding_scores_), token_index_); // 128
} else if (padding_token_length == 256) {
general_topk_pair_sort<half, 64, 4><<<B, 64, 0, stream>>>(
static_cast<half*>(padding_scores_), token_index_); // 256
} else if (padding_token_length == 384) {
general_topk_pair_sort<half, 96, 4><<<B, 96, 0, stream>>>(
static_cast<half*>(padding_scores_), token_index_); // 384
} else {
general_topk_pair_sort<half, 128, 4><<<B, 128, 0, stream>>>(
static_cast<half*>(padding_scores_), token_index_); // 512
}
// 5. compute output
int32_t num_threads;
if (length < 1024) {
num_threads = length;
} else {
if (length % 512 == 0) {
num_threads = 512;
} else if (length % 256 == 0) {
num_threads = 256;
} else if (length % 128 == 0) {
num_threads = 128;
} else if (length % 64 == 0) {
num_threads = 64;
} else if (length % 32 == 0) {
num_threads = 32;
} else if (length % 16 == 0) {
num_threads = 16;
} else if (length % 8 == 0) {
num_threads = 8;
} else if (length % 4 == 0) {
num_threads = 4;
} else if (length % 2 == 0) {
num_threads = 2;
} else {
num_threads = 1;
}
}
const dim3 num_blocks(
B,
max_sequence_length,
length / num_threads); // batches, max_sequence_length, vector_length
varlen_prune_token_change_order<<<num_blocks, num_threads, 0, stream>>>(
tokens, output3, padding_token_length, token_index_, output0);
} else {
auto input_type = input_desc[0].type;
const int32_t B = input_desc[1].dims.d[0]; // batches
const int32_t pre_sequence_length = input_desc[1].dims.d[1];
const int32_t new_sequence_length = input_desc[3].dims.d[2]; // new mask
const int32_t length = input_desc[1].dims.d[2]; // hidden size
if (input_type == nvinfer1::DataType::kFLOAT) {
VLOG(1) << "TRT Plugin DataType selected. FusedTokenPrune-->fp32";
const float* scores = static_cast<const float*>(inputs[0]); // reduce sum
const float* tokens = static_cast<const float*>(inputs[1]); // X
float* output0 = static_cast<float*>(outputs[0]);
int32_t* output1 = static_cast<int32_t*>(outputs[1]);
int32_t padding_token_length;
if (pre_sequence_length <= 64) {
padding_token_length = 64;
} else if (pre_sequence_length <= 128) {
padding_token_length = 128;
} else if (pre_sequence_length <= 256) {
padding_token_length = 256;
} else if (pre_sequence_length <= 384) {
padding_token_length = 384;
} else if (pre_sequence_length <= 512) {
padding_token_length = 512;
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"Token_prune'token_length must <= 512"));
}
// 1. Padding scores
fill_index_padding_score<float><<<B, padding_token_length, 0, stream>>>(
token_index_,
scores,
pre_sequence_length,
static_cast<float*>(padding_scores_));
// 2. sort scores
if (padding_token_length == 64) {
general_topk_pair_sort<float, 32, 2><<<B, 32, 0, stream>>>(
static_cast<float*>(padding_scores_), token_index_); // 64
} else if (padding_token_length == 128) {
general_topk_pair_sort<float, 32, 4><<<B, 32, 0, stream>>>(
static_cast<float*>(padding_scores_), token_index_); // 128
} else if (padding_token_length == 256) {
general_topk_pair_sort<float, 64, 4><<<B, 64, 0, stream>>>(
static_cast<float*>(padding_scores_), token_index_); // 256
} else if (padding_token_length == 384) {
general_topk_pair_sort<float, 96, 4><<<B, 96, 0, stream>>>(
static_cast<float*>(padding_scores_), token_index_); // 384
} else {
general_topk_pair_sort<float, 128, 4><<<B, 128, 0, stream>>>(
static_cast<float*>(padding_scores_), token_index_); // 512
}
// 3. compute output
int32_t num_threads;
if (length < 1024) {
num_threads = length;
} else {
if (length % 512 == 0) {
num_threads = 512;
} else if (length % 256 == 0) {
num_threads = 256;
} else if (length % 128 == 0) {
num_threads = 128;
} else if (length % 64 == 0) {
num_threads = 64;
} else if (length % 32 == 0) {
num_threads = 32;
} else if (length % 16 == 0) {
num_threads = 16;
} else if (length % 8 == 0) {
num_threads = 8;
} else if (length % 4 == 0) {
num_threads = 4;
} else if (length % 2 == 0) {
num_threads = 2;
} else {
num_threads = 1;
}
}
if (keep_order_) {
const dim3 num_blocks(B, length / num_threads);
prune_token_keep_order<float>
<<<num_blocks, num_threads, 0, stream>>>(tokens,
pre_sequence_length,
new_sequence_length,
padding_token_length,
token_index_,
output0,
output1);
} else {
const dim3 num_blocks(B, pre_sequence_length, length / num_threads);
prune_token_change_order<float>
<<<num_blocks, num_threads, 0, stream>>>(tokens,
new_sequence_length,
padding_token_length,
token_index_,
output0);
}
} else if (input_type == nvinfer1::DataType::kHALF) {
VLOG(1) << "TRT Plugin DataType selected. FusedTokenPrune-->fp16";
const half* scores = static_cast<const half*>(inputs[0]); // reduce sum
const half* tokens = static_cast<const half*>(inputs[1]); // X
half* output0 = static_cast<half*>(outputs[0]);
int32_t* output1 = static_cast<int32_t*>(outputs[1]);
int32_t padding_token_length;
if (pre_sequence_length <= 64) {
padding_token_length = 64;
} else if (pre_sequence_length <= 128) {
padding_token_length = 128;
} else if (pre_sequence_length <= 256) {
padding_token_length = 256;
} else if (pre_sequence_length <= 384) {
padding_token_length = 384;
} else if (pre_sequence_length <= 512) {
padding_token_length = 512;
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"Token_prune'token_length must <= 512"));
}
// 1. Padding scores
fill_index_padding_score<half><<<B, padding_token_length, 0, stream>>>(
token_index_,
scores,
pre_sequence_length,
static_cast<half*>(padding_scores_));
// 2. sort scores
if (padding_token_length == 64) {
general_topk_pair_sort<half, 32, 2><<<B, 32, 0, stream>>>(
static_cast<half*>(padding_scores_), token_index_); // 64
} else if (padding_token_length == 128) {
general_topk_pair_sort<half, 32, 4><<<B, 32, 0, stream>>>(
static_cast<half*>(padding_scores_), token_index_); // 128
} else if (padding_token_length == 256) {
general_topk_pair_sort<half, 64, 4><<<B, 64, 0, stream>>>(
static_cast<half*>(padding_scores_), token_index_); // 256
} else if (padding_token_length == 384) {
general_topk_pair_sort<half, 96, 4><<<B, 96, 0, stream>>>(
static_cast<half*>(padding_scores_), token_index_); // 384
} else {
general_topk_pair_sort<half, 128, 4><<<B, 128, 0, stream>>>(
static_cast<half*>(padding_scores_), token_index_); // 512
}
// 3. compute output
int32_t num_threads;
if (length < 1024) {
num_threads = length;
} else {
if (length % 512 == 0) {
num_threads = 512;
} else if (length % 256 == 0) {
num_threads = 256;
} else if (length % 128 == 0) {
num_threads = 128;
} else if (length % 64 == 0) {
num_threads = 64;
} else if (length % 32 == 0) {
num_threads = 32;
} else if (length % 16 == 0) {
num_threads = 16;
} else if (length % 8 == 0) {
num_threads = 8;
} else if (length % 4 == 0) {
num_threads = 4;
} else if (length % 2 == 0) {
num_threads = 2;
} else {
num_threads = 1;
}
}
if (keep_order_) {
const dim3 num_blocks(B, length / num_threads);
prune_token_keep_order<half>
<<<num_blocks, num_threads, 0, stream>>>(tokens,
pre_sequence_length,
new_sequence_length,
padding_token_length,
token_index_,
output0,
output1);
} else {
const dim3 num_blocks(B, pre_sequence_length, length / num_threads);
prune_token_change_order<half>
<<<num_blocks, num_threads, 0, stream>>>(tokens,
new_sequence_length,
padding_token_length,
token_index_,
output0);
}
} else {
PADDLE_THROW(
common::errors::Fatal("The FusedTokenPrune TRT Plugin's input type "
"should be float or half."));
}
}
return cudaGetLastError() != cudaSuccess;
}
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,206 @@
// Copyright (c) 2022 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.
#pragma once
#include "paddle/fluid/inference/tensorrt/engine.h"
#include "paddle/fluid/inference/tensorrt/plugin/trt_plugin.h"
#include "paddle/fluid/platform/enforce.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
class FusedTokenPrunePluginDynamic : public DynamicPluginTensorRT {
public:
explicit FusedTokenPrunePluginDynamic(bool with_fp16,
bool keep_first_token,
bool keep_order,
bool flag_varseqlen)
: with_fp16_(with_fp16),
keep_first_token_(keep_first_token),
keep_order_(keep_order),
flag_varseqlen_(flag_varseqlen) {}
FusedTokenPrunePluginDynamic(void const* serial_data, size_t serial_length) {
DeserializeValue(&serial_data, &serial_length, &with_fp16_);
DeserializeValue(&serial_data, &serial_length, &keep_first_token_);
DeserializeValue(&serial_data, &serial_length, &keep_order_);
DeserializeValue(&serial_data, &serial_length, &flag_varseqlen_);
}
nvinfer1::IPluginV2DynamicExt* clone() const TRT_NOEXCEPT override {
FusedTokenPrunePluginDynamic* ptr = new FusedTokenPrunePluginDynamic(
with_fp16_, keep_first_token_, keep_order_, flag_varseqlen_);
ptr->max_batches_ = max_batches_;
ptr->max_token_length_ = max_token_length_;
ptr->pruned_token_lengths_ = pruned_token_lengths_;
ptr->token_index_ = token_index_;
ptr->padding_scores_ = padding_scores_;
return ptr;
}
const char* getPluginType() const TRT_NOEXCEPT override {
return "fused_token_prune_plugin_dynamic";
}
int getNbOutputs() const TRT_NOEXCEPT override {
if (flag_varseqlen_) {
return 5;
} else {
return 2;
}
}
int initialize() TRT_NOEXCEPT override { return 0; }
size_t getSerializationSize() const TRT_NOEXCEPT override {
return SerializedSize(with_fp16_) + SerializedSize(keep_first_token_) +
SerializedSize(keep_order_) + SerializedSize(flag_varseqlen_);
}
void serialize(void* buffer) const TRT_NOEXCEPT override {
SerializeValue(&buffer, with_fp16_);
SerializeValue(&buffer, keep_first_token_);
SerializeValue(&buffer, keep_order_);
SerializeValue(&buffer, flag_varseqlen_);
}
nvinfer1::DimsExprs getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs* inputs,
int nb_inputs,
nvinfer1::IExprBuilder& expr_builder) // NOLINT
TRT_NOEXCEPT override;
bool supportsFormatCombination(int pos,
const nvinfer1::PluginTensorDesc* in_out,
int nb_inputs,
int nb_outputs) TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::DynamicPluginTensorDesc* in,
int nb_inputs,
const nvinfer1::DynamicPluginTensorDesc* out,
int nb_outputs) TRT_NOEXCEPT override {
max_batches_ = in[1].max.d[0];
max_token_length_ = in[1].max.d[1];
int32_t padding_token_length;
if (max_token_length_ <= 64) {
padding_token_length = 64;
} else if (max_token_length_ <= 128) {
padding_token_length = 128;
} else if (max_token_length_ <= 256) {
padding_token_length = 256;
} else if (max_token_length_ <= 384) {
padding_token_length = 384;
} else if (max_token_length_ <= 512) {
padding_token_length = 512;
} else {
try {
PADDLE_THROW(common::errors::InvalidArgument(
"Token_prune'token_length(max) must <= 512"));
} catch (std::exception& e) {
}
}
try {
PADDLE_ENFORCE_GPU_SUCCESS(cudaMalloc(
&pruned_token_lengths_, (max_batches_ + 1) * sizeof(int32_t)));
PADDLE_ENFORCE_GPU_SUCCESS(
cudaMalloc(&token_index_,
max_batches_ * padding_token_length * sizeof(int32_t)));
int32_t type_size = 4;
if (in[0].desc.type == nvinfer1::DataType::kHALF) {
type_size = 2;
} else {
type_size = 4;
}
PADDLE_ENFORCE_GPU_SUCCESS(cudaMalloc(
&padding_scores_, max_batches_ * padding_token_length * type_size));
} catch (std::exception& e) {
}
}
size_t getWorkspaceSize(const nvinfer1::PluginTensorDesc* inputs,
int nb_inputs,
const nvinfer1::PluginTensorDesc* outputs,
int nb_outputs) const TRT_NOEXCEPT override;
int enqueue(const nvinfer1::PluginTensorDesc* input_desc,
const nvinfer1::PluginTensorDesc* output_desc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* input_types,
int nb_inputs) const
TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override { delete this; }
private:
bool with_fp16_;
bool keep_first_token_;
bool keep_order_;
bool flag_varseqlen_;
int32_t* pruned_token_lengths_;
int32_t* token_index_;
int32_t max_batches_;
int32_t max_token_length_;
void* padding_scores_;
};
class FusedTokenPrunePluginDynamicCreator : public nvinfer1::IPluginCreator {
public:
FusedTokenPrunePluginDynamicCreator() {}
const char* getPluginName() const TRT_NOEXCEPT override {
return "fused_token_prune_plugin_dynamic";
}
const char* getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
const nvinfer1::PluginFieldCollection* getFieldNames() TRT_NOEXCEPT override {
return &field_collection_;
}
nvinfer1::IPluginV2* createPlugin(const char* name,
const nvinfer1::PluginFieldCollection* fc)
TRT_NOEXCEPT override {
return nullptr;
}
nvinfer1::IPluginV2* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override {
auto plugin = new FusedTokenPrunePluginDynamic(serial_data, serial_length);
return plugin;
}
void setPluginNamespace(const char* lib_namespace) TRT_NOEXCEPT override {
plugin_namespace_ = lib_namespace;
}
const char* getPluginNamespace() const TRT_NOEXCEPT override {
return plugin_namespace_.c_str();
}
private:
std::string plugin_namespace_;
std::string plugin_name_;
nvinfer1::PluginFieldCollection field_collection_;
std::vector<nvinfer1::PluginField> plugin_attributes_;
};
REGISTER_TRT_PLUGIN_V2(FusedTokenPrunePluginDynamicCreator);
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,262 @@
// Copyright (c) 2021 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 <cuda_fp16.h>
#include <algorithm>
#include <cstdint>
#include <functional>
#include <numeric>
#include <sstream>
#include "NvInferRuntimeCommon.h"
#include "paddle/fluid/inference/tensorrt/plugin/gather_nd_op_plugin.h"
#include "paddle/phi/backends/gpu/gpu_helper.h"
#include "paddle/phi/common/place.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
template <typename T, typename IndexT = int>
__global__ void GatherNdCUDAKernel(const T* input,
const int32_t* input_dims,
const IndexT* indices,
T* output,
int32_t remain_size,
int32_t slice_size,
int32_t end_size) {
CUDA_KERNEL_LOOP(i, remain_size * slice_size) {
int indices_i = i / slice_size;
int slice_i = i - indices_i * slice_size; // offset inside the slice
IndexT gather_i = 0;
int32_t temp = slice_size;
for (int32_t j = end_size - 1; j >= 0; --j) {
auto index_value = indices[indices_i * end_size + j];
PADDLE_ENFORCE(
index_value >= -input_dims[j] && index_value < input_dims[j],
"The index is out of bounds, "
"please check whether the dimensions of index and "
"input meet the requirements. It should "
"be less than [%d] and greater or equal to [%d], but received [%d]",
input_dims[j],
-input_dims[j],
index_value);
if (index_value < 0) {
index_value += input_dims[j];
}
gather_i += (index_value * temp);
temp *= input_dims[j];
}
IndexT input_i = gather_i + slice_i;
*(output + i) = *(input + input_i);
}
}
int GatherNdPluginDynamic::initialize() TRT_NOEXCEPT { return 0; }
size_t GatherNdPluginDynamic::getSerializationSize() const TRT_NOEXCEPT {
return SerializedSize(with_fp16_);
}
void GatherNdPluginDynamic::serialize(void* buffer) const TRT_NOEXCEPT {
SerializeValue(&buffer, with_fp16_);
}
nvinfer1::DimsExprs GatherNdPluginDynamic::getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs* inputs,
int nb_inputs,
nvinfer1::IExprBuilder& expr_builder) TRT_NOEXCEPT {
PADDLE_ENFORCE_EQ(
nb_inputs,
2,
common::errors::InvalidArgument(
"The gather_nd plugin should have 2 input, but got %d.", nb_inputs));
PADDLE_ENFORCE_EQ(
output_index,
0,
common::errors::InvalidArgument("When GetOutputDimensions in gather_nd "
"plugin, the output_index should be 0."));
nvinfer1::DimsExprs x_dims = inputs[0];
nvinfer1::DimsExprs index_dims = inputs[1];
int32_t x_dims_size = x_dims.nbDims;
int32_t index_dims_size = index_dims.nbDims;
// TODO(wilber): The result dims should be Index.shape[:-1] +
// X.shape[Index.shape[-1]:], but the trt DimsExprs is an expression we can't
// get the actual value. So we only support one scenario: input_dims.size ==
// index_dims.size.
nvinfer1::DimsExprs ret(x_dims);
for (int i = 0; i < index_dims_size - 1; ++i) {
ret.d[i] = index_dims.d[i];
}
return ret;
}
bool GatherNdPluginDynamic::supportsFormatCombination(
int pos,
const nvinfer1::PluginTensorDesc* in_out,
int nb_inputs,
int nb_outputs) TRT_NOEXCEPT {
PADDLE_ENFORCE_NOT_NULL(
in_out,
common::errors::InvalidArgument(
"The input of gather_nd plugin should not be nullptr."));
PADDLE_ENFORCE_LT(
pos,
nb_inputs + nb_outputs,
common::errors::InvalidArgument("The pos(%d) should be less than the "
"num(%d) of the input and the output.",
pos,
nb_inputs + nb_outputs));
(in_out && pos < (nb_inputs + nb_outputs));
const nvinfer1::PluginTensorDesc& in = in_out[pos];
if (pos == 0) {
if (with_fp16_) {
return (in.type == nvinfer1::DataType::kFLOAT ||
in.type == nvinfer1::DataType::kHALF) &&
(in.format == nvinfer1::TensorFormat::kLINEAR);
} else {
return (in.type == nvinfer1::DataType::kFLOAT) &&
(in.format == nvinfer1::TensorFormat::kLINEAR);
}
} else if (pos == 1) {
return in.type == nvinfer1::DataType::kINT32 &&
in.format == nvinfer1::TensorFormat::kLINEAR;
} else if (pos == 2) {
return in.type == in_out[0].type &&
in.format == nvinfer1::TensorFormat::kLINEAR;
}
return true;
}
nvinfer1::DataType GatherNdPluginDynamic::getOutputDataType(
int index,
const nvinfer1::DataType* input_types,
int nb_inputs) const TRT_NOEXCEPT {
return input_types[0];
}
int GatherNdPluginDynamic::enqueue(
const nvinfer1::PluginTensorDesc* input_desc,
const nvinfer1::PluginTensorDesc* output_desc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT {
auto input_dims = input_desc[0].dims;
auto index_dims = input_desc[1].dims;
auto input_dims_size = input_dims.nbDims;
auto index_dims_size = index_dims.nbDims;
std::vector<int32_t> input_shape, index_shape, out_shape;
for (int i = 0; i < input_dims.nbDims; i++)
input_shape.push_back(input_dims.d[i]);
for (int i = 0; i < index_dims.nbDims; i++)
index_shape.push_back(index_dims.d[i]);
// The out_shape is
// Index.shape[:-1] + X.shape[Index.shape[-1]:]
for (int i = 0; i < index_dims_size - 1; ++i) {
out_shape.emplace_back(index_shape[i]);
}
for (int i = index_shape[index_dims_size - 1]; i < input_dims_size; ++i) {
out_shape.emplace_back(input_shape[i]);
}
// final dim
int end_size = index_shape[index_dims_size - 1];
// remain dim
std::vector<int> remain_ddim(index_shape.begin(), index_shape.end() - 1);
int remain_numel = std::accumulate(
remain_ddim.begin(), remain_ddim.end(), 1, std::multiplies<int>());
// slice size
int slice_size = 1;
for (int i = end_size; i < input_dims_size; ++i) {
slice_size *= input_shape[i];
}
auto input_type = input_desc[0].type;
if (input_type == nvinfer1::DataType::kFLOAT) {
VLOG(1) << "TRT Plugin DataType selected. gather_nd-->fp32";
const float* p_input = static_cast<const float*>(inputs[0]);
const int32_t* p_index = static_cast<const int32_t*>(inputs[1]);
float* p_output = static_cast<float*>(outputs[0]);
if (input_dims_data_ == nullptr) {
cudaMalloc(&input_dims_data_, input_shape.size() * sizeof(int));
}
cudaMemcpyAsync(input_dims_data_,
input_shape.data(),
sizeof(int) * input_shape.size(),
cudaMemcpyHostToDevice,
stream);
int block = 512;
int n = slice_size * remain_numel;
int grid = (n + block - 1) / block;
GatherNdCUDAKernel<float, int32_t>
<<<grid, block, 0, stream>>>(p_input,
input_dims_data_,
p_index,
p_output,
remain_numel,
slice_size,
end_size);
} else if (input_type == nvinfer1::DataType::kHALF) {
VLOG(1) << "TRT Plugin DataType selected. gather_nd-->fp16";
const half* p_input = static_cast<const half*>(inputs[0]);
const int32_t* p_index = static_cast<const int32_t*>(inputs[1]);
half* p_output = static_cast<half*>(outputs[0]);
if (input_dims_data_ == nullptr) {
cudaMalloc(&input_dims_data_, input_shape.size() * sizeof(int));
}
cudaMemcpyAsync(input_dims_data_,
input_shape.data(),
sizeof(int) * input_shape.size(),
cudaMemcpyHostToDevice,
stream);
int block = 512;
int n = slice_size * remain_numel;
int grid = (n + block - 1) / block;
GatherNdCUDAKernel<half, int32_t>
<<<grid, block, 0, stream>>>(p_input,
input_dims_data_,
p_index,
p_output,
remain_numel,
slice_size,
end_size);
}
return cudaGetLastError() != cudaSuccess;
}
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,143 @@
// Copyright (c) 2021 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.
#pragma once
#include <string>
#include <utility>
#include <vector>
#include "paddle/fluid/framework/tensor.h"
#include "paddle/fluid/inference/tensorrt/plugin/trt_plugin.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
class GatherNdPluginDynamic : public DynamicPluginTensorRT {
public:
explicit GatherNdPluginDynamic(bool with_fp16) { with_fp16_ = with_fp16; }
GatherNdPluginDynamic(void const* serial_data, size_t serial_length) {
DeserializeValue(&serial_data, &serial_length, &with_fp16_);
}
nvinfer1::IPluginV2DynamicExt* clone() const TRT_NOEXCEPT override {
return new GatherNdPluginDynamic(with_fp16_);
}
const char* getPluginType() const TRT_NOEXCEPT override {
return "gather_nd_plugin";
}
int getNbOutputs() const TRT_NOEXCEPT override { return 1; }
int initialize() TRT_NOEXCEPT override;
size_t getSerializationSize() const TRT_NOEXCEPT override;
void serialize(void* buffer) const TRT_NOEXCEPT override;
nvinfer1::DimsExprs getOutputDimensions(
int outputIndex,
const nvinfer1::DimsExprs* inputs,
int nbInputs,
nvinfer1::IExprBuilder& exprBuilder) // NOLINT
TRT_NOEXCEPT override;
bool supportsFormatCombination(int pos,
const nvinfer1::PluginTensorDesc* inOut,
int nbInputs,
int nbOutputs) TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::DynamicPluginTensorDesc* in,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc* out,
int nbOutputs) TRT_NOEXCEPT override {}
size_t getWorkspaceSize(const nvinfer1::PluginTensorDesc* inputs,
int nbInputs,
const nvinfer1::PluginTensorDesc* outputs,
int nbOutputs) const TRT_NOEXCEPT override {
return 0;
}
int enqueue(const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* inputTypes,
int nbInputs) const
TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override {
if (input_dims_data_) {
cudaFree(input_dims_data_);
}
delete this;
}
private:
int32_t* input_dims_data_{nullptr};
};
class GatherNdPluginDynamicCreator : public nvinfer1::IPluginCreator {
public:
GatherNdPluginDynamicCreator() {}
const char* getPluginName() const TRT_NOEXCEPT override {
return "gather_nd_plugin";
}
const char* getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
const nvinfer1::PluginFieldCollection* getFieldNames() TRT_NOEXCEPT override {
return &field_collection_;
}
nvinfer1::IPluginV2* createPlugin(const char* name,
const nvinfer1::PluginFieldCollection* fc)
TRT_NOEXCEPT override {
return nullptr;
}
nvinfer1::IPluginV2* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override {
auto plugin = new GatherNdPluginDynamic(serial_data, serial_length);
return plugin;
}
void setPluginNamespace(const char* lib_namespace) TRT_NOEXCEPT override {
plugin_namespace_ = lib_namespace;
}
const char* getPluginNamespace() const TRT_NOEXCEPT override {
return plugin_namespace_.c_str();
}
private:
std::string plugin_namespace_;
std::string plugin_name_;
nvinfer1::PluginFieldCollection field_collection_{0, nullptr};
std::vector<nvinfer1::PluginField> plugin_attributes_;
};
REGISTER_TRT_PLUGIN_V2(GatherNdPluginDynamicCreator);
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,221 @@
// Copyright (c) 2018 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 <cassert>
#include <cstring>
#include <vector>
#include "paddle/fluid/inference/tensorrt/plugin/gelu_op_plugin.h"
#include "paddle/phi/common/float16.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
// constants for approximating the normal cdf
static const float kA = 1.41421356237309504; // sqrt(2)
static const float kAT = 0.5;
static const float kBT = 0.7978845608028654; // sqrt(2.0/M_PI)
static const float kCT = 0.035677408136300125; // 0.044715 * sqrt(2.0/M_PI)
bool GeluPlugin::supportsFormat(
nvinfer1::DataType type, nvinfer1::PluginFormat format) const TRT_NOEXCEPT {
if (with_fp16_) {
return ((type == nvinfer1::DataType::kFLOAT ||
type == nvinfer1::DataType::kHALF) &&
(format == nvinfer1::PluginFormat::kLINEAR));
} else {
return ((type == nvinfer1::DataType::kFLOAT) &&
(format == nvinfer1::PluginFormat::kLINEAR));
}
}
nvinfer1::Dims GeluPlugin::getOutputDimensions(int index,
const nvinfer1::Dims* in_dims,
int nb_inputs) TRT_NOEXCEPT {
assert(nb_inputs == 1);
assert(index < this->getNbOutputs());
nvinfer1::Dims const& input_dims = in_dims[0];
nvinfer1::Dims output_dims = input_dims;
return output_dims;
}
template <typename T, unsigned TPB>
__global__ void gelu_kernel(const T a, int n, const T* input, T* output) {
const int idx = blockIdx.x * TPB + threadIdx.x;
if (idx < n) {
const T in = input[idx];
const T cdf = 0.5f * (1.0f + erff(in * 0.5f * a));
output[idx] = in * cdf;
}
}
template <typename T>
__device__ T do_tanh(T a);
template <>
__device__ float do_tanh<float>(float a) {
return tanf(a);
}
template <>
__device__ half do_tanh<half>(half a) {
const float tmp = tanhf(__half2float(a));
return __float2half(tmp);
}
// the kernel below is not aligned with fluid fp32 forward ones, use it for
// fp16.
template <typename T, unsigned TPB>
__global__ void no_exact_gelu_kernel(
const T a, const T b, const T c, int n, const T* input, T* output) {
#if CUDA_ARCH_FP16_SUPPORTED(__CUDA_ARCH__)
const int idx = blockIdx.x * TPB + threadIdx.x;
if (idx < n) {
const T in = input[idx];
const T tmp = in * (c * in * in + b);
const T cdf = a + a * do_tanh<T>(tmp);
output[idx] = in * cdf;
}
#endif
}
int GeluPlugin::enqueue(int batch_size,
const void* const* inputs,
void* const* outputs,
void*,
cudaStream_t stream) TRT_NOEXCEPT {
const auto& input_dims = this->getInputDims(0);
int num = batch_size;
for (int i = 0; i < input_dims.nbDims; i++) {
num *= input_dims.d[i];
}
const int block_size = 256;
const int grid_size = (num + block_size - 1) / block_size;
auto type = getDataType();
if (type == nvinfer1::DataType::kFLOAT) {
VLOG(1) << "TRT Plugin DataType selected. Gelu-->fp32";
const float* input = static_cast<const float*>(inputs[0]);
float* output = static_cast<float*>(outputs[0]);
gelu_kernel<float, block_size>
<<<grid_size, block_size, 0, stream>>>(kA, num, input, output);
} else if (type == nvinfer1::DataType::kHALF) {
VLOG(1) << "TRT Plugin DataType selected. Gelu-->fp16";
const half* input = static_cast<const half*>(inputs[0]);
half* output = static_cast<half*>(outputs[0]);
no_exact_gelu_kernel<half, block_size>
<<<grid_size, block_size, 0, stream>>>(
kAT, kBT, kCT, num, input, output);
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"The Gelu TRT Plugin's input type should be float or half."));
}
return cudaGetLastError() != cudaSuccess;
}
nvinfer1::DimsExprs GeluPluginDynamic::getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs* inputs,
int nb_inputs,
nvinfer1::IExprBuilder& expr_builder) TRT_NOEXCEPT {
return inputs[0];
}
bool GeluPluginDynamic::supportsFormatCombination(
int pos,
const nvinfer1::PluginTensorDesc* in_out,
int nb_inputs,
int nb_outputs) TRT_NOEXCEPT {
PADDLE_ENFORCE_NOT_NULL(
in_out,
common::errors::InvalidArgument(
"The input of swish plugin should not be nullptr."));
PADDLE_ENFORCE_LT(
pos,
nb_inputs + nb_outputs,
common::errors::InvalidArgument("The pos(%d) should be less than the "
"num(%d) of the input and the output.",
pos,
nb_inputs + nb_outputs));
(in_out && pos < (nb_inputs + nb_outputs));
const nvinfer1::PluginTensorDesc& in = in_out[pos];
if (pos == 0) {
if (with_fp16_) {
return (in.type == nvinfer1::DataType::kFLOAT ||
in.type == nvinfer1::DataType::kHALF) &&
(in.format == nvinfer1::TensorFormat::kLINEAR);
} else {
return (in.type == nvinfer1::DataType::kFLOAT) &&
(in.format == nvinfer1::TensorFormat::kLINEAR);
}
}
const nvinfer1::PluginTensorDesc& prev = in_out[pos - 1];
// output
return in.type == prev.type && in.format == prev.format;
}
nvinfer1::DataType GeluPluginDynamic::getOutputDataType(
int index,
const nvinfer1::DataType* input_types,
int nb_inputs) const TRT_NOEXCEPT {
PADDLE_ENFORCE_EQ(index,
0,
common::errors::InvalidArgument(
"The Gelu Plugin only has one input, so the "
"index value should be 0, but get %d.",
index));
return input_types[0];
}
int GeluPluginDynamic::enqueue(const nvinfer1::PluginTensorDesc* input_desc,
const nvinfer1::PluginTensorDesc* output_desc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT {
auto input_dims = input_desc[0].dims;
size_t num = ProductDim(input_dims);
const int block_size = 256;
const int grid_size = (num + block_size - 1) / block_size;
auto input_type = input_desc[0].type;
if (input_type == nvinfer1::DataType::kFLOAT) {
VLOG(1) << "TRT Plugin DataType selected. Gelu-->fp32";
const float* input = static_cast<const float*>(inputs[0]);
float* output = static_cast<float*>(outputs[0]);
gelu_kernel<float, block_size>
<<<grid_size, block_size, 0, stream>>>(kA, num, input, output);
} else if (input_type == nvinfer1::DataType::kHALF) {
VLOG(1) << "TRT Plugin DataType selected. Gelu-->fp16";
const half* input = static_cast<const half*>(inputs[0]);
half* output = static_cast<half*>(outputs[0]);
no_exact_gelu_kernel<half, block_size>
<<<grid_size, block_size, 0, stream>>>(
kAT, kBT, kCT, num, input, output);
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"The Gelu TRT Plugin's input type should be float or half."));
}
return cudaGetLastError() != cudaSuccess;
}
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,172 @@
// 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.
#pragma once
#include <stdio.h>
#include <cassert>
#include <string>
#include <vector>
#include "paddle/fluid/inference/tensorrt/plugin/trt_plugin.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
class GeluPlugin : public PluginTensorRT {
public:
explicit GeluPlugin(const bool with_fp16) { with_fp16_ = with_fp16; }
// It was used for tensorrt deserialization.
// It should not be called by users.
GeluPlugin(void const* serial_data, size_t serial_length) {
deserializeBase(serial_data, serial_length);
}
~GeluPlugin() {}
GeluPlugin* clone() const TRT_NOEXCEPT override {
return new GeluPlugin(with_fp16_);
}
const char* getPluginType() const TRT_NOEXCEPT override {
return "gelu_plugin";
}
int getNbOutputs() const TRT_NOEXCEPT override { return 1; }
int initialize() TRT_NOEXCEPT override { return 0; }
bool supportsFormat(nvinfer1::DataType type, nvinfer1::PluginFormat format)
const TRT_NOEXCEPT override;
nvinfer1::Dims getOutputDimensions(int index,
const nvinfer1::Dims* inputs,
int nb_input_dims) TRT_NOEXCEPT override;
int enqueue(int batch_size,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
size_t getSerializationSize() const TRT_NOEXCEPT override {
return getBaseSerializationSize();
}
// TRT will call this func to serialize the configuration of TRT
// It should not be called by users.
void serialize(void* buffer) const TRT_NOEXCEPT override {
serializeBase(buffer);
}
};
class GeluPluginCreator : public TensorRTPluginCreator {
public:
const char* getPluginName() const TRT_NOEXCEPT override {
return "gelu_plugin";
}
const char* getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
nvinfer1::IPluginV2* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override {
return new GeluPlugin(serial_data, serial_length);
}
};
REGISTER_TRT_PLUGIN_V2(GeluPluginCreator);
class GeluPluginDynamic : public DynamicPluginTensorRT {
public:
explicit GeluPluginDynamic(const bool with_fp16) { with_fp16_ = with_fp16; }
GeluPluginDynamic(void const* serial_data, size_t serial_length) {
DeserializeValue(&serial_data, &serial_length, &with_fp16_);
}
~GeluPluginDynamic() {}
nvinfer1::IPluginV2DynamicExt* clone() const TRT_NOEXCEPT override {
return new GeluPluginDynamic(with_fp16_);
}
const char* getPluginType() const TRT_NOEXCEPT override {
return "gelu_plugin_dynamic";
}
int getNbOutputs() const TRT_NOEXCEPT override { return 1; }
int initialize() TRT_NOEXCEPT override { return 0; }
size_t getSerializationSize() const TRT_NOEXCEPT override {
return SerializedSize(with_fp16_);
}
void serialize(void* buffer) const TRT_NOEXCEPT override {
SerializeValue(&buffer, with_fp16_);
}
nvinfer1::DimsExprs getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs* inputs,
int nb_inputs,
nvinfer1::IExprBuilder& expr_builder) // NOLINT
TRT_NOEXCEPT override;
bool supportsFormatCombination(int pos,
const nvinfer1::PluginTensorDesc* in_out,
int nb_inputs,
int nb_outputs) TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::DynamicPluginTensorDesc* in,
int nb_inputs,
const nvinfer1::DynamicPluginTensorDesc* out,
int nb_outputs) TRT_NOEXCEPT override {}
size_t getWorkspaceSize(const nvinfer1::PluginTensorDesc* inputs,
int nb_inputs,
const nvinfer1::PluginTensorDesc* outputs,
int nb_outputs) const TRT_NOEXCEPT override {
return 0;
}
int enqueue(const nvinfer1::PluginTensorDesc* input_desc,
const nvinfer1::PluginTensorDesc* output_desc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* input_types,
int nb_inputs) const
TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override { delete this; }
};
class GeluPluginDynamicCreator : public TensorRTPluginCreator {
public:
const char* getPluginName() const TRT_NOEXCEPT override {
return "gelu_plugin_dynamic";
}
const char* getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
nvinfer1::IPluginV2* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override {
auto plugin = new GeluPluginDynamic(serial_data, serial_length);
return plugin;
}
};
REGISTER_TRT_PLUGIN_V2(GeluPluginDynamicCreator);
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,730 @@
// Copyright (c) 2022 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 <map>
#include "paddle/fluid/framework/op_kernel_type.h"
#include "paddle/fluid/framework/phi_utils.h"
#include "paddle/fluid/inference/tensorrt/dynamic_shape_infermeta_registry.h"
#include "paddle/fluid/inference/tensorrt/plugin/generic_plugin.h"
#include "paddle/phi/backends/gpu/gpu_context.h"
#include "paddle/phi/common/data_type.h"
#include "paddle/phi/core/compat/op_utils.h"
#include "paddle/phi/core/framework/framework.pb.h"
#include "paddle/phi/core/kernel_context.h"
#include "paddle/phi/core/kernel_factory.h"
#include "paddle/phi/kernels/funcs/data_type_transform.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
GeneratePluginDataType ProtoTypeToGeneratePluginDataType(
framework::proto::VarType_Type proto_type) {
using framework::proto::VarType_Type;
switch (proto_type) {
case VarType_Type::VarType_Type_BOOL:
return GeneratePluginDataType::PLUGIN_BOOL;
case VarType_Type::VarType_Type_UINT8:
return GeneratePluginDataType::PLUGIN_UINT8;
case VarType_Type::VarType_Type_INT8:
return GeneratePluginDataType::PLUGIN_INT8;
case VarType_Type::VarType_Type_INT16:
return GeneratePluginDataType::PLUGIN_INT16;
case VarType_Type::VarType_Type_INT32:
return GeneratePluginDataType::PLUGIN_INT32;
case VarType_Type::VarType_Type_INT64:
return GeneratePluginDataType::PLUGIN_INT64;
case VarType_Type::VarType_Type_FP16:
return GeneratePluginDataType::PLUGIN_FP16;
case VarType_Type::VarType_Type_FP32:
return GeneratePluginDataType::PLUGIN_FP32;
case VarType_Type::VarType_Type_FP64:
return GeneratePluginDataType::PLUGIN_FP64;
case VarType_Type::VarType_Type_SIZE_T:
return GeneratePluginDataType::PLUGIN_SIZE_T;
case VarType_Type::VarType_Type_BF16:
return GeneratePluginDataType::PLUGIN_BF16;
case VarType_Type::VarType_Type_COMPLEX64:
return GeneratePluginDataType::PLUGIN_COMPLEX64;
case VarType_Type::VarType_Type_COMPLEX128:
return GeneratePluginDataType::PLUGIN_COMPLEX128;
default:
PADDLE_THROW(common::errors::Unimplemented(
"This data type is currently not supported"));
}
}
void BuildPhiKernelContextAttr(const framework::OpDesc& op_desc,
phi::KernelContext* kernel_context,
const phi::KernelSignature& signature,
const phi::Kernel* phi_kernel) {
if (!phi_kernel->IsValid()) {
return;
}
const phi::KernelArgsDef& args_def = phi_kernel->args_def();
const auto& attr_names = signature.attr_names;
const auto& attr_defs = args_def.attribute_defs();
PADDLE_ENFORCE_EQ(
attr_names.size(),
attr_defs.size(),
common::errors::InvalidArgument(
"The attr_names.size() should be equal to attr_defs.size()."));
framework::AttrReader attr_reader(op_desc.GetAttrMap());
for (size_t k = 0; k < attr_names.size(); ++k) {
auto attr_name = attr_names[k];
auto* attr_ptr = attr_reader.GetAttr(attr_name);
if (attr_ptr) {
switch (attr_defs[k].type_index) {
case phi::AttributeType::SCALAR: {
auto& attr = *attr_ptr;
switch (AttrTypeID(attr)) {
case framework::proto::AttrType::FLOAT:
kernel_context->EmplaceBackAttr(
phi::Scalar(PADDLE_GET_CONST(float, attr)));
break;
case framework::proto::AttrType::FLOAT64:
kernel_context->EmplaceBackAttr(
phi::Scalar(PADDLE_GET_CONST(double, attr)));
break;
case framework::proto::AttrType::INT:
kernel_context->EmplaceBackAttr(
phi::Scalar(PADDLE_GET_CONST(int, attr)));
break;
case framework::proto::AttrType::LONG:
kernel_context->EmplaceBackAttr(
phi::Scalar(PADDLE_GET_CONST(int64_t, attr)));
break;
case framework::proto::AttrType::STRING:
kernel_context->EmplaceBackAttr(
phi::Scalar(PADDLE_GET_CONST(std::string, attr)));
break;
case framework::proto::AttrType::SCALAR:
kernel_context->EmplaceBackAttr(phi::Scalar(
PADDLE_GET_CONST(paddle::experimental::Scalar, attr)));
break;
default:
PADDLE_THROW(common::errors::Unimplemented(
"Unsupported cast op attribute `%s` to Scalar when "
"ProtoAttr2PhiAttr.",
attr_name));
}
} break;
case phi::AttributeType::INT_ARRAY: {
auto& attr = *attr_ptr;
switch (AttrTypeID(attr)) {
case framework::proto::AttrType::INTS:
kernel_context->EmplaceBackAttr(std::move(
phi::IntArray(PADDLE_GET_CONST(std::vector<int32_t>, attr))));
break;
case framework::proto::AttrType::LONGS:
kernel_context->EmplaceBackAttr(std::move(
phi::IntArray(PADDLE_GET_CONST(std::vector<int64_t>, attr))));
break;
case framework::proto::AttrType::INT:
kernel_context->EmplaceBackAttr(
phi::IntArray({PADDLE_GET_CONST(int, attr)}));
break;
default:
PADDLE_THROW(common::errors::Unimplemented(
"Unsupported cast op attribute `%s` to IntArray when "
"ProtoAttr2PhiAttr.",
attr_name));
}
} break;
case phi::AttributeType::SCALARS: {
auto& attr = *attr_ptr;
switch (AttrTypeID(attr)) {
case framework::proto::AttrType::INTS: {
const auto& vec = PADDLE_GET_CONST(std::vector<int32_t>, attr);
std::vector<phi::Scalar> scalar_list;
scalar_list.reserve(vec.size());
for (const auto& val : vec) {
scalar_list.emplace_back(val);
}
kernel_context->EmplaceBackAttr(std::move(scalar_list));
} break;
case framework::proto::AttrType::LONGS: {
const auto& vec = PADDLE_GET_CONST(std::vector<int64_t>, attr);
std::vector<phi::Scalar> scalar_list;
scalar_list.reserve(vec.size());
for (const auto& val : vec) {
scalar_list.emplace_back(val);
}
kernel_context->EmplaceBackAttr(std::move(scalar_list));
} break;
case framework::proto::AttrType::FLOATS: {
const auto& vec = PADDLE_GET_CONST(std::vector<float>, attr);
std::vector<phi::Scalar> scalar_list;
scalar_list.reserve(vec.size());
for (const auto& val : vec) {
scalar_list.emplace_back(val);
}
kernel_context->EmplaceBackAttr(std::move(scalar_list));
} break;
case framework::proto::AttrType::FLOAT64S: {
const auto& vec = PADDLE_GET_CONST(std::vector<double>, attr);
std::vector<phi::Scalar> scalar_list;
scalar_list.reserve(vec.size());
for (const auto& val : vec) {
scalar_list.emplace_back(val);
}
kernel_context->EmplaceBackAttr(std::move(scalar_list));
} break;
case framework::proto::AttrType::SCALARS: {
const auto& vec = PADDLE_GET_CONST(
std::vector<paddle::experimental::Scalar>, attr);
std::vector<phi::Scalar> scalar_list;
scalar_list.reserve(vec.size());
for (const auto& val : vec) {
scalar_list.emplace_back(val);
}
kernel_context->EmplaceBackAttr(std::move(scalar_list));
} break;
default:
PADDLE_THROW(common::errors::Unimplemented(
"Unsupported cast op attribute `%s` to vector<Scalar> when "
"ProtoAttr2PhiAttr.",
attr_name));
}
} break;
default: {
auto& attr = *attr_ptr;
switch (attr_defs[k].type_index) {
case phi::AttributeType::FLOAT32:
kernel_context->EmplaceBackAttr(PADDLE_GET_CONST(float, attr));
break;
case phi::AttributeType::FLOAT64:
kernel_context->EmplaceBackAttr(PADDLE_GET_CONST(double, attr));
break;
case phi::AttributeType::INT32:
kernel_context->EmplaceBackAttr(PADDLE_GET_CONST(int, attr));
break;
case phi::AttributeType::BOOL:
kernel_context->EmplaceBackAttr(PADDLE_GET_CONST(bool, attr));
break;
case phi::AttributeType::INT64:
kernel_context->EmplaceBackAttr(PADDLE_GET_CONST(int64_t, attr));
break;
case phi::AttributeType::INT32S:
kernel_context->EmplaceBackAttr(
PADDLE_GET_CONST(std::vector<int>, attr));
break;
case phi::AttributeType::DATA_TYPE: {
auto data_type = phi::TransToPhiDataType(
static_cast<framework::proto::VarType::Type>(
PADDLE_GET_CONST(int, attr)));
kernel_context->EmplaceBackAttr(data_type);
} break;
case phi::AttributeType::STRING:
kernel_context->EmplaceBackAttr(
PADDLE_GET_CONST(std::string, attr));
break;
case phi::AttributeType::INT64S:
switch (AttrTypeID(attr)) {
case framework::proto::AttrType::LONGS:
kernel_context->EmplaceBackAttr(
PADDLE_GET_CONST(std::vector<int64_t>, attr));
break;
case framework::proto::AttrType::INTS: {
const auto& vector_int_attr =
PADDLE_GET_CONST(std::vector<int>, attr);
const std::vector<int64_t> vector_int64_attr(
vector_int_attr.begin(), vector_int_attr.end());
kernel_context->EmplaceBackAttr(vector_int64_attr);
} break;
default:
PADDLE_THROW(common::errors::Unimplemented(
"Unsupported cast op attribute `%s` to vector<int64_t> "
"when ProtoAttr2PhiAttr.",
attr_name));
}
break;
case phi::AttributeType::FLOAT32S:
kernel_context->EmplaceBackAttr(
PADDLE_GET_CONST(std::vector<float>, attr));
break;
case phi::AttributeType::STRINGS:
kernel_context->EmplaceBackAttr(
PADDLE_GET_CONST(std::vector<std::string>, attr));
break;
case phi::AttributeType::BOOLS:
kernel_context->EmplaceBackAttr(
PADDLE_GET_CONST(std::vector<bool>, attr));
break;
case phi::AttributeType::FLOAT64S:
kernel_context->EmplaceBackAttr(
PADDLE_GET_CONST(std::vector<double>, attr));
break;
default:
PADDLE_THROW(common::errors::Unimplemented(
"Unsupported cast op attribute `%s` when construct "
"ProtoAttr2PhiAttr.",
attr_name));
}
}
}
}
}
PADDLE_ENFORCE_EQ(attr_names.size(),
kernel_context->AttrsSize(),
common::errors::InvalidArgument(
"The attr_names.size() should be equal to "
"kernel_context->AttrsSize()."
"Received attr_names.size() = % d,"
"kernel_context->AttrsSize() = %d.",
attr_names.size(),
kernel_context->AttrsSize()));
}
GenericPlugin::GenericPlugin(
const paddle::framework::proto::OpDesc& proto_op_desc,
const InputOutPutVarInfo& in_out_info,
bool with_fp16) {
proto_op_desc_ = proto_op_desc;
op_desc_ = std::move(framework::OpDesc(proto_op_desc_, nullptr));
proto_op_desc_.SerializeToString(&op_meta_data_);
inputs_data_type_ = in_out_info.inputs_data_type;
outputs_data_type_ = in_out_info.outputs_data_type;
with_fp16_ = with_fp16;
}
GenericPlugin::GenericPlugin(
const paddle::framework::proto::OpDesc& proto_op_desc,
const std::vector<GeneratePluginDataType>& inputs_data_type,
const std::vector<GeneratePluginDataType>& outputs_data_type,
bool with_fp16) {
proto_op_desc_ = proto_op_desc;
op_desc_ = std::move(framework::OpDesc(proto_op_desc_, nullptr));
proto_op_desc_.SerializeToString(&op_meta_data_);
inputs_data_type_ = inputs_data_type;
outputs_data_type_ = outputs_data_type;
with_fp16_ = with_fp16;
}
GenericPlugin::GenericPlugin(void const* serial_data, size_t serial_length) {
DeserializeValue(&serial_data, &serial_length, &inputs_data_type_);
DeserializeValue(&serial_data, &serial_length, &outputs_data_type_);
DeserializeValue(&serial_data, &serial_length, &with_fp16_);
std::string op_meta_data((char*)(serial_data), serial_length); // NOLINT
op_meta_data_ = std::move(op_meta_data);
proto_op_desc_.ParseFromString(op_meta_data_);
op_desc_ = std::move(framework::OpDesc(proto_op_desc_, nullptr));
}
int GenericPlugin::getNbOutputs() const TRT_NOEXCEPT {
int res = 0;
for (auto& i : op_desc_.Outputs()) {
if (!i.second.empty()) res += i.second.size();
}
return res;
}
int GenericPlugin::getNbInputs() const TRT_NOEXCEPT {
int res = 0;
for (auto& i : op_desc_.Inputs()) {
if (!i.second.empty()) res += i.second.size();
}
return res;
}
nvinfer1::IPluginV2DynamicExt* GenericPlugin::clone() const TRT_NOEXCEPT {
nvinfer1::IPluginV2DynamicExt* plugin = new GenericPlugin(
proto_op_desc_, inputs_data_type_, outputs_data_type_, with_fp16_);
plugin->initialize();
return plugin;
}
void GenericPlugin::serialize(void* buffer) const TRT_NOEXCEPT {
// inputs_data_type_
SerializeValue(&buffer, inputs_data_type_);
// outputs_data_type_
SerializeValue(&buffer, outputs_data_type_);
// use fp16
SerializeValue(&buffer, with_fp16_);
// serialize op_meta_data_
std::memcpy(buffer, op_meta_data_.c_str(), op_meta_data_.size());
reinterpret_cast<char*&>(buffer) += op_meta_data_.size();
}
bool GenericPlugin::supportsFormatCombination(
int pos,
const nvinfer1::PluginTensorDesc* in_out,
int nb_inputs,
int nb_outputs) TRT_NOEXCEPT {
if (op_desc_.Type() == "gather_nd" || op_desc_.Type() == "yolo_box") {
if (pos == 0)
return (in_out[pos].type == nvinfer1::DataType::kFLOAT ||
(isFp16Supported() &&
in_out[pos].type == nvinfer1::DataType::kHALF)) &&
(in_out[pos].format == nvinfer1::TensorFormat::kLINEAR);
if (pos == 1)
return (in_out[pos].type == nvinfer1::DataType::kINT32) &&
(in_out[pos].format == nvinfer1::TensorFormat::kLINEAR);
// output
if (pos == 2 || pos == 3)
return in_out[0].type == in_out[pos].type &&
in_out[0].format == in_out[pos].format;
} else if (op_desc_.Type() == "scatter_nd_add") {
// input X
if (pos == 0)
return (in_out[pos].type == nvinfer1::DataType::kFLOAT ||
(isFp16Supported() &&
in_out[pos].type == nvinfer1::DataType::kHALF)) &&
(in_out[pos].format == nvinfer1::TensorFormat::kLINEAR);
// input Index
if (pos == 1)
return (in_out[pos].type == nvinfer1::DataType::kINT32) &&
(in_out[pos].format == nvinfer1::TensorFormat::kLINEAR);
// input Updates and output
if (pos == 2 || pos == 3)
return in_out[0].type == in_out[pos].type &&
in_out[0].format == in_out[pos].format;
} else if (op_desc_.Type() == "lookup_table_v2") {
if (pos == 0)
return (in_out[pos].type == nvinfer1::DataType::kINT32 &&
(in_out[pos].format == nvinfer1::TensorFormat::kLINEAR));
if (pos == 1)
return (in_out[pos].type == nvinfer1::DataType::kFLOAT) ||
((isFp16Supported() &&
in_out[pos].type == nvinfer1::DataType::kHALF)) &&
(in_out[pos].format == nvinfer1::TensorFormat::kLINEAR);
// output
if (pos == 2)
return in_out[1].type == in_out[pos].type &&
in_out[1].format == in_out[pos].format;
} else if (op_desc_.Type() == "argsort") {
// input x
if (pos == 0) {
return ((in_out[pos].type == nvinfer1::DataType::kFLOAT ||
(isFp16Supported() &&
in_out[pos].type == nvinfer1::DataType::kHALF)) &&
in_out[pos].format == nvinfer1::TensorFormat::kLINEAR);
}
// output out
if (pos == 1) {
return (in_out[pos].type == in_out[0].type &&
in_out[pos].format == in_out[0].format);
}
// output indices
if (pos == 2) {
return (in_out[pos].type == nvinfer1::DataType::kINT32 &&
in_out[pos].format == in_out[0].format);
}
} else if (op_desc_.Type() == "scatter") {
// input X
if (pos == 0)
return (in_out[pos].type == nvinfer1::DataType::kFLOAT ||
(isFp16Supported() &&
in_out[pos].type == nvinfer1::DataType::kHALF)) &&
(in_out[pos].format == nvinfer1::TensorFormat::kLINEAR);
// Ids
if (pos == 1)
return (in_out[pos].type == nvinfer1::DataType::kINT32) &&
(in_out[pos].format == nvinfer1::TensorFormat::kLINEAR);
// 3:output 2:input Updates
if (pos == 3 || pos == 2)
return in_out[0].type == in_out[pos].type &&
in_out[0].format == in_out[pos].format;
} else if (op_desc_.Type() == "solve") {
// input X
if (pos == 0)
return in_out[pos].type == nvinfer1::DataType::kFLOAT &&
in_out[pos].format == nvinfer1::TensorFormat::kLINEAR;
// input Y
if (pos == 1)
return in_out[pos].type == nvinfer1::DataType::kFLOAT &&
in_out[pos].format == nvinfer1::TensorFormat::kLINEAR;
// output
if (pos == 2)
return in_out[0].type == in_out[pos].type &&
in_out[0].format == in_out[pos].format;
} else {
return (in_out[pos].type == nvinfer1::DataType::kFLOAT ||
(isFp16Supported() &&
in_out[pos].type == nvinfer1::DataType::kHALF)) &&
(in_out[pos].format == nvinfer1::TensorFormat::kLINEAR) &&
(in_out[0].type == in_out[pos].type);
}
}
nvinfer1::DataType GenericPlugin::getOutputDataType(
int index,
const nvinfer1::DataType* input_types,
int nb_inputs) const TRT_NOEXCEPT {
if (op_desc_.Type() == "lookup_table_v2") {
return input_types[1];
}
if (op_desc_.Type() == "argsort") {
if (index == 1) {
return nvinfer1::DataType::kINT32;
}
}
return input_types[0];
}
int GenericPlugin::initialize() TRT_NOEXCEPT {
std::string op_type = op_desc_.Type();
phi::KernelSignature phi_kernel_signature;
if (phi::OpUtilsMap::Instance().HasArgumentMappingFn(op_type)) {
const phi::ArgumentMappingFn* argument_mapping_func =
phi::OpUtilsMap::Instance().GetArgumentMappingFn(op_type);
PluginArgumentMappingContext argument_mapping_context(&op_desc_);
phi_kernel_signature = (*argument_mapping_func)(argument_mapping_context);
} else {
phi_kernel_signature =
phi::DefaultKernelSignatureMap::Instance().Get(op_type);
}
PADDLE_ENFORCE_EQ(
phi::KernelFactory::Instance().HasCompatiblePhiKernel(op_type),
true,
common::errors::Fatal("%s has no compatible phi kernel!",
op_type.c_str()));
phi::DeviceContextPool& pool = phi::DeviceContextPool::Instance();
GPUPlace place(platform::GetCurrentDeviceId());
auto* dev_ctx = static_cast<phi::GPUContext*>(pool.Get(place));
std::vector<phi::DataType> precision_types{phi::DataType::FLOAT32,
phi::DataType::FLOAT16};
for (auto& precision_type : precision_types) {
phi::KernelKey phi_kernel_key(
phi::Backend::GPU, phi::DataLayout::ANY, precision_type);
auto nv_dtype = PhiType2NvType(precision_type);
phi_kernels_[nv_dtype] = std::make_unique<phi::Kernel>(
phi::KernelFactory::Instance().SelectKernel(phi_kernel_signature.name,
phi_kernel_key));
if (phi_kernel_contexts_.find(nv_dtype) == phi_kernel_contexts_.end() ||
!phi_kernel_contexts_[nv_dtype]) {
phi_kernel_contexts_[nv_dtype] =
std::make_unique<phi::KernelContext>(dev_ctx);
BuildPhiKernelContextAttr(op_desc_,
phi_kernel_contexts_[nv_dtype].get(),
phi_kernel_signature,
phi_kernels_[nv_dtype].get());
}
}
PADDLE_ENFORCE_EQ(phi_kernels_[nvinfer1::DataType::kFLOAT]->IsValid() ||
phi_kernels_[nvinfer1::DataType::kHALF]->IsValid(),
true,
common::errors::Fatal("%s phi kernel is invalid!.",
phi_kernel_signature.name));
if (!dense_tensor_inputs_)
dense_tensor_inputs_ = new std::vector<phi::DenseTensor>(getNbInputs());
if (!dense_tensor_outputs_)
dense_tensor_outputs_ = new std::vector<phi::DenseTensor>(getNbOutputs());
return 0;
}
nvinfer1::DimsExprs GenericPlugin::getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs* inputs,
int nb_inputs,
nvinfer1::IExprBuilder& expr_builder) TRT_NOEXCEPT {
PADDLE_ENFORCE_EQ(
output_index < getNbOutputs(),
true,
common::errors::InvalidArgument(
"The output_index should be less than getNbOutputs()."));
auto& dynamic_infermeta_factory = tensorrt::DynamicMetaFnFactory::Instance();
PADDLE_ENFORCE_EQ(dynamic_infermeta_factory.Contains(op_desc_.Type()),
true,
common::errors::InvalidArgument(
"The %s op has no dynamic plugin infershape function!",
op_desc_.Type().c_str()));
auto* infershape_func = dynamic_infermeta_factory.Get(op_desc_.Type());
return infershape_func(
output_index, inputs, nb_inputs, expr_builder, op_desc_);
}
void GenericPlugin::configurePlugin(
const nvinfer1::DynamicPluginTensorDesc* in,
int nb_inputs,
const nvinfer1::DynamicPluginTensorDesc* out,
int nb_outputs) TRT_NOEXCEPT {
PADDLE_ENFORCE_EQ(phi_kernels_[nvinfer1::DataType::kFLOAT]->IsValid() ||
phi_kernels_[nvinfer1::DataType::kHALF]->IsValid(),
true,
common::errors::Fatal("Sorry, phi kernel is invalid!"));
PADDLE_ENFORCE_EQ(nb_inputs == getNbInputs(),
true,
common::errors::InvalidArgument(
"The nb_inputs should be equal to getNbInputs()."));
PADDLE_ENFORCE_EQ(nb_outputs == getNbOutputs(),
true,
common::errors::InvalidArgument(
"The nb_outputs should be equal to getNbOutputs()."));
}
// Shutdown the layer. This is called when the engine is destroyed
void GenericPlugin::terminate() TRT_NOEXCEPT {
delete dense_tensor_inputs_;
delete dense_tensor_outputs_;
}
int GenericPlugin::enqueue(const nvinfer1::PluginTensorDesc* input_desc,
const nvinfer1::PluginTensorDesc* output_desc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT {
GPUPlace place(platform::GetCurrentDeviceId());
phi::DeviceContextPool& pool = phi::DeviceContextPool::Instance();
// TODO(inference): generic plugin do not support INT8 precision now.
auto nvType2PhiType =
[&](nvinfer1::DataType nv_dtype) -> std::pair<phi::DataType, int> {
const std::map<nvinfer1::DataType, std::pair<phi::DataType, int>> _map{
{nvinfer1::DataType::kFLOAT, {phi::DataType::FLOAT32, sizeof(float)}},
{nvinfer1::DataType::kHALF, {phi::DataType::FLOAT16, sizeof(half)}},
{nvinfer1::DataType::kINT32, {phi::DataType::INT32, sizeof(int32_t)}},
{nvinfer1::DataType::kBOOL, {phi::DataType::BOOL, sizeof(bool)}},
};
PADDLE_ENFORCE_EQ(
_map.count(nv_dtype),
true,
common::errors::InvalidArgument("Sorry, dtype [ %d ] is not supported.",
static_cast<int>(nv_dtype)));
return _map.at(nv_dtype);
};
nvinfer1::DataType data_type;
// input
if (op_desc_.Type() == "lookup_table_v2") {
data_type = input_desc[1].type;
} else {
data_type = input_desc[0].type;
}
PADDLE_ENFORCE_EQ((data_type == nvinfer1::DataType::kFLOAT) ||
(data_type == nvinfer1::DataType::kHALF),
true,
common::errors::InvalidArgument(
"The data_type should be kFLOAT or kHALF."));
phi_kernel_contexts_[data_type]->ClearInputOutput();
auto* dev_ctx = static_cast<phi::GPUContext*>(pool.Get(place));
phi_kernel_contexts_[data_type]->SetDeviceContext(dev_ctx);
for (int i = 0; i < getNbInputs(); i++) {
if (inputs_data_type_[i] == GeneratePluginDataType::PLUGIN_OPTIONAL) {
phi_kernel_contexts_[data_type]->EmplaceBackInput(nullptr);
continue;
}
auto const& input_dims = input_desc[i].dims;
std::vector<int> input_shape;
for (int j = 0; j < input_dims.nbDims; j++)
input_shape.push_back(input_dims.d[j]);
int input_numel = 1;
for (int k = 0; k < input_shape.size(); k++) input_numel *= input_shape[k];
auto data_type_and_size = nvType2PhiType(input_desc[i].type);
phi::DenseTensorMeta input_meta(data_type_and_size.first,
common::make_ddim(input_shape));
std::shared_ptr<phi::Allocation> input_alloc(
new phi::Allocation((void*)(inputs[i]), // NOLINT
input_numel * data_type_and_size.second,
place));
(*dense_tensor_inputs_)[i] =
std::move(phi::DenseTensor(input_alloc, input_meta));
phi_kernel_contexts_[data_type]->EmplaceBackInput(
&((*dense_tensor_inputs_)[i]));
}
// output
for (int i = 0; i < getNbOutputs(); i++) {
auto const& output_dims = output_desc[i].dims;
std::vector<int> output_shape;
for (int j = 0; j < output_dims.nbDims; j++)
output_shape.push_back(output_dims.d[j]);
int output_numel = 1;
for (int k = 0; k < output_shape.size(); k++)
output_numel *= output_shape[k];
auto data_type_and_size = nvType2PhiType(output_desc[i].type);
phi::DenseTensorMeta output_meta(data_type_and_size.first,
common::make_ddim(output_shape));
std::shared_ptr<phi::Allocation> output_alloc(
new phi::Allocation(reinterpret_cast<void*>(outputs[i]),
output_numel * data_type_and_size.second,
place));
(*dense_tensor_outputs_)[i] =
std::move(phi::DenseTensor(output_alloc, output_meta));
phi_kernel_contexts_[data_type]->EmplaceBackOutput(
&((*dense_tensor_outputs_)[i]));
}
PADDLE_ENFORCE_EQ(
phi_kernel_contexts_[data_type]->InputsSize(),
getNbInputs(),
common::errors::InvalidArgument(
"The phi_kernel_contexts_[data_type]->InputsSize() "
"should be equal to getNbInputs()."
"Received phi_kernel_contexts_[data_type]->InputsSize() "
"= %d, getNbInputs() = %d.",
phi_kernel_contexts_[data_type]->InputsSize(),
getNbInputs()));
PADDLE_ENFORCE_EQ(phi_kernel_contexts_[data_type]->OutputsSize(),
getNbOutputs(),
common::errors::InvalidArgument(
"The phi_kernel_contexts_[data_type]->OutputsSize() "
"should be equal to getNbOutputs()."));
(*phi_kernels_[data_type])(phi_kernel_contexts_[data_type].get());
if (op_desc_.Type() == "argsort") {
for (int i = 0; i < getNbOutputs(); i++) {
phi::DenseTensor& output_tensor = (*dense_tensor_outputs_)[i];
phi::DataType dtype = output_tensor.dtype();
if (dtype == phi::DataType::INT64) {
auto& int32_tensor = output_tensor;
auto ctx = pool.Get(output_tensor.place());
int32_tensor = phi::funcs::TransDataType(
reinterpret_cast<const phi::GPUContext&>(*ctx),
output_tensor,
phi::DataType::INT32);
paddle::memory::Copy(output_tensor.place(),
outputs[i],
output_tensor.place(),
int32_tensor.data<int32_t>(),
int32_tensor.numel() * sizeof(int),
nullptr);
}
}
}
return cudaGetLastError() != cudaSuccess;
}
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,197 @@
// Copyright (c) 2024 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <NvInfer.h>
#include <string>
#include <vector>
#include "paddle/fluid/framework/op_desc.h"
#include "paddle/fluid/framework/op_registry.h"
#include "paddle/fluid/framework/operator.h"
#include "paddle/fluid/framework/scope.h"
#include "paddle/fluid/framework/type_defs.h"
#include "paddle/fluid/inference/tensorrt/engine.h"
#include "paddle/fluid/inference/tensorrt/helper.h"
#include "paddle/fluid/inference/tensorrt/plugin/trt_plugin.h"
#include "paddle/fluid/inference/tensorrt/plugin/trt_plugin_utils.h"
#include "paddle/fluid/inference/tensorrt/plugin_arg_mapping_context.h"
#include "paddle/fluid/platform/enforce.h"
#include "paddle/phi/backends/gpu/gpu_context.h"
#include "paddle/phi/core/kernel_context.h"
#include "paddle/phi/core/memory/allocation/cuda_allocator.h"
#include "paddle/phi/core/platform/device_context.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
enum class GeneratePluginDataType {
PLUGIN_BOOL,
PLUGIN_UINT8,
PLUGIN_INT8,
PLUGIN_INT16,
PLUGIN_INT32,
PLUGIN_INT64,
PLUGIN_FP16,
PLUGIN_FP32,
PLUGIN_FP64,
PLUGIN_BF16,
PLUGIN_SIZE_T,
PLUGIN_COMPLEX64,
PLUGIN_COMPLEX128,
PLUGIN_OPTIONAL,
};
GeneratePluginDataType ProtoTypeToGeneratePluginDataType(
framework::proto::VarType_Type proto_type);
void BuildPhiKernelContextAttr(const framework::OpDesc& op_desc,
phi::KernelContext* kernel_context,
const phi::KernelSignature& signature,
const phi::Kernel* phi_kernel);
class GenericPlugin : public DynamicPluginTensorRT {
public:
struct InputOutPutVarInfo {
std::vector<GeneratePluginDataType> inputs_data_type;
std::vector<GeneratePluginDataType> outputs_data_type;
};
public:
GenericPlugin() {}
GenericPlugin(const paddle::framework::proto::OpDesc& proto_op_desc,
const InputOutPutVarInfo& in_out_info,
bool with_fp16_ = false);
GenericPlugin(const paddle::framework::proto::OpDesc& proto_op_desc,
const std::vector<GeneratePluginDataType>& inputs_data_type,
const std::vector<GeneratePluginDataType>& outputs_data_type,
bool with_fp16_ = false);
// It was used for tensorrt deserialization.
// It should not be called by users.
GenericPlugin(void const* serialData, size_t serialLength);
// IPluginV2 method
const char* getPluginType() const TRT_NOEXCEPT override {
return "generic_plugin";
}
int getNbOutputs() const TRT_NOEXCEPT override;
int getNbInputs() const TRT_NOEXCEPT;
// Initialize the layer for execution.
int initialize() TRT_NOEXCEPT override;
// Shutdown the layer. This is called when the engine is destroyed
void terminate() TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override{};
size_t getSerializationSize() const TRT_NOEXCEPT override {
size_t sum = 0;
sum += SerializedSize(inputs_data_type_);
sum += SerializedSize(outputs_data_type_);
sum += SerializedSize(with_fp16_);
sum += op_meta_data_.size();
return sum;
}
void serialize(void* buffer) const TRT_NOEXCEPT override;
// The Func in IPluginV2
nvinfer1::IPluginV2DynamicExt* clone() const TRT_NOEXCEPT override;
nvinfer1::DimsExprs getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs* inputs,
int nb_inputs,
nvinfer1::IExprBuilder& expr_builder) // NOLINT
TRT_NOEXCEPT override;
bool supportsFormatCombination(int pos,
const nvinfer1::PluginTensorDesc* in_out,
int nb_inputs,
int nb_outputs) TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::DynamicPluginTensorDesc* in,
int nb_inputs,
const nvinfer1::DynamicPluginTensorDesc* out,
int nb_outputs) TRT_NOEXCEPT override;
int enqueue(const nvinfer1::PluginTensorDesc* input_desc,
const nvinfer1::PluginTensorDesc* output_desc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* input_types,
int nb_inputs) const
TRT_NOEXCEPT override;
bool isFp16Supported() {
auto half_dtype = nvinfer1::DataType::kHALF;
return with_fp16_ &&
!(phi_kernels_.find(half_dtype) == phi_kernels_.end()) &&
phi_kernels_[half_dtype]->IsValid();
}
private:
std::string op_meta_data_;
framework::proto::OpDesc proto_op_desc_;
framework::OpDesc op_desc_;
private:
std::unordered_map<nvinfer1::DataType, std::unique_ptr<phi::Kernel>>
phi_kernels_;
std::unordered_map<nvinfer1::DataType, std::unique_ptr<phi::KernelContext>>
phi_kernel_contexts_;
std::vector<phi::DenseTensor>* dense_tensor_inputs_{nullptr};
std::vector<phi::DenseTensor>* dense_tensor_outputs_{nullptr};
private:
std::vector<GeneratePluginDataType> inputs_data_type_;
std::vector<GeneratePluginDataType> outputs_data_type_;
};
class GenericPluginCreator : public TensorRTPluginCreator {
public:
const char* getPluginName() const TRT_NOEXCEPT override {
return "generic_plugin";
}
const char* getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
nvinfer1::IPluginV2DynamicExt* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override {
return new GenericPlugin(serial_data, serial_length);
}
};
REGISTER_TRT_PLUGIN_V2(GenericPluginCreator);
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,830 @@
/* Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
SPDX-FileCopyrightText: Copyright (c) 1993-2022 NVIDIA CORPORATION &
AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0
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/plugin/group_norm_op_plugin.h"
#include "paddle/phi/kernels/group_norm_kernel.h"
#include <cub/cub.cuh>
#include "paddle/common/layout.h"
#include "paddle/phi/backends/gpu/gpu_context.h"
#include "paddle/phi/kernels/funcs/math_function.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
using DataLayout = phi::DataLayout;
template <typename T>
static inline T divUp(T m, T n) {
return (m + n - 1) / n;
}
static inline __device__ __host__ float sigmoid(float x) {
return 1.F / (1.F + expf(-x));
}
struct GroupSums {
// Is it the 1st element of the group?
int32_t flag;
// The sum.
float sum;
// The sum of squares.
float sumSq;
};
struct GroupSumsOp {
inline __device__ GroupSums operator()(GroupSums const &a,
GroupSums const &b) {
GroupSums dst;
dst.sum = b.flag ? b.sum : (a.sum + b.sum);
dst.sumSq = b.flag ? b.sumSq : (a.sumSq + b.sumSq);
dst.flag = a.flag + b.flag;
return dst;
}
};
static int64_t findMaxDivisor(int64_t n, int64_t maxAllowedDivisor) {
int64_t maxDivisor = -1;
for (int64_t i = 1; i <= std::sqrt(n); i++) {
if (n % i == 0) {
int64_t divisor1 = n / i;
int64_t divisor2 = i;
if (divisor1 > maxDivisor && divisor1 < maxAllowedDivisor) {
maxDivisor = divisor1;
}
if (divisor2 > maxDivisor && divisor2 < maxAllowedDivisor) {
maxDivisor = divisor2;
}
}
}
return maxDivisor;
}
template <int tTHREADS_PER_BLOCK>
__global__ void groupNormNCHW32SumKernelQDQ(
const GroupNormNDHWCParams<__half> params) {
// The object in charge of doing the sums for the different blocks.
typedef cub::BlockScan<GroupSums, tTHREADS_PER_BLOCK> BlockScan;
// Allocate shared memory for BlockScan.
__shared__ typename BlockScan::TempStorage tempStorage;
// Allocate shared memory for the groups. We could reduce the amount of shared
// memory reserved.
__shared__ float2 smem[tTHREADS_PER_BLOCK];
// The instance in the batch.
int32_t ni = blockIdx.z;
// The channel loaded by that thread (2 channels per thread for int8x2).
int32_t ci = blockIdx.x * params.cPerBlock + threadIdx.x * 2;
// The first activation loaded by that block.
int64_t dhwBegin = static_cast<int64_t>(blockIdx.y) * params.dhwPerBlock;
// The last activation loaded by that block.
int64_t dhwEnd = min(dhwBegin + params.dhwPerBlock, params.dhw);
// The sums.
float sum = 0.F;
float sumSq = 0.F;
const int8_t *src_ptr = reinterpret_cast<const int8_t *>(params.srcX);
// nchw32 layout
// batch offset + channel offset
int64_t nc_offset = ni * params.dhwc + ci / 32 * params.dhw * 32 + ci % 32;
// Iterate over the activations to compute the sums.
for (int64_t dhwi = dhwBegin; dhwi < dhwEnd; ++dhwi) {
// The offset.
int64_t offset = nc_offset + static_cast<int64_t>(dhwi) * 32;
// Fetch two channels per thread.
__half2 h2(0, 0);
if (ci < params.c) {
int8_t tmp_in[2];
*reinterpret_cast<int16_t *>(tmp_in) =
*reinterpret_cast<int16_t const *>(&src_ptr[offset]);
h2.x = params.dqScaleIn * tmp_in[0];
h2.y = params.dqScaleIn * tmp_in[1];
}
// Extract the two half values.
float2 f2 = __half22float2(h2);
// Update the sum.
sum += f2.x + f2.y;
// Update the sum of squares.
sumSq += f2.x * f2.x + f2.y * f2.y;
}
// The group that thread works on and the channel in the group (modulus).
int32_t gi = threadIdx.x * 2 / params.cPerGroup;
int32_t cj = threadIdx.x * 2 - params.cPerGroup * gi;
// The data for the summations.
GroupSums inp{cj == 0 ? 1 : 0, sum, sumSq};
// Do the segmented scan.
GroupSums out;
BlockScan(tempStorage).InclusiveScan(inp, out, GroupSumsOp());
// Store the results for the groups in shared memory (to produce coalesced
// stores later).
// 2 channels per thread
if (cj == params.cPerGroup - 2) {
smem[gi] = make_float2(out.sum, out.sumSq);
}
// Make sure the data is in shared memory.
__syncthreads();
// The global group index.
int32_t gj = blockIdx.x * params.groupsPerBlock + threadIdx.x;
// Threads that have nothing left to do, exit.
if (threadIdx.x >= params.groupsPerBlock || gj >= params.groups) {
return;
}
// The first threads (those storing to global memory, load the values).
float2 sums = smem[threadIdx.x];
// Store to global memory.
atomicAdd(&params.redBuffer[(2 * ni + 0) * params.groups + gj], sums.x);
atomicAdd(&params.redBuffer[(2 * ni + 1) * params.groups + gj], sums.y);
}
void groupNormNCHW32SumQDQ(const GroupNormNDHWCParams<__half> &params,
cudaStream_t stream) {
dim3 grid;
// The number of blocks to compute all the channels.
grid.x = divUp(params.c, params.cPerBlock);
// The number of blocks to compute all the activations in a given instance.
grid.y = divUp(params.dhw, params.dhwPerBlock);
// The number of instances.
grid.z = params.n;
switch (params.cPerBlock) {
case 320:
groupNormNCHW32SumKernelQDQ<160><<<grid, 160, 0, stream>>>(params);
break;
case 480:
groupNormNCHW32SumKernelQDQ<256><<<grid, 256, 0, stream>>>(params);
break;
case 256:
groupNormNCHW32SumKernelQDQ<128><<<grid, 128, 0, stream>>>(params);
break;
case 128:
groupNormNCHW32SumKernelQDQ<64><<<grid, 64, 0, stream>>>(params);
break;
case 8:
groupNormNCHW32SumKernelQDQ<4><<<grid, 4, 0, stream>>>(params);
break;
}
}
template <int tTHREADS_PER_BLOCK>
__global__ void groupNormNCHW32ScaleKernelQDQ(
const GroupNormNDHWCParams<__half> params) {
// The instance in the batch.
int32_t ni = blockIdx.z;
// The channel loaded by that thread (2 channels per thread for F16x2).
int32_t ci = blockIdx.x * params.cPerBlock + threadIdx.x * 2;
// The group that thread works on and the channel in the group (modulus).
int32_t gi = ci / params.cPerGroup;
const int8_t *src_ptr = reinterpret_cast<const int8_t *>(params.srcX);
int8_t *dst_ptr = reinterpret_cast<int8_t *>(params.dst);
// Load the sum and sum of squares for the group.
float sum = 0.F, sumSq = 0.F;
if (gi < params.groups) {
sum = params.redBuffer[(2 * ni + 0) * params.groups + gi];
sumSq = params.redBuffer[(2 * ni + 1) * params.groups + gi];
}
// Load gamma/beta.
float2 gammaF2, betaF2;
if (ci < params.c) {
gammaF2 = __half22float2(*reinterpret_cast<half2 const *>(
reinterpret_cast<half const *>(params.gamma) + ci));
betaF2 = __half22float2(*reinterpret_cast<half2 const *>(
reinterpret_cast<half const *>(params.beta) + ci));
}
// Compute the mean.
float mean = sum * params.invDHWC;
// Compute the variance.
float var = sumSq * params.invDHWC - (mean * mean);
// Compute the inverse of the stddev.
float invStdDev = rsqrtf(var + params.eps);
// The first activation loaded by that block.
int64_t dhwBegin = static_cast<int64_t>(blockIdx.y) * params.dhwPerBlock;
// The last activation loaded by that block.
int64_t dhwEnd = min(dhwBegin + params.dhwPerBlock, params.dhw);
// nchw32 layout
int64_t c_offset = ci / 32 * params.dhw * 32 + ci % 32;
// Iterate over the activations to compute the sums.
for (int64_t dhwi = dhwBegin; dhwi < dhwEnd; ++dhwi) {
// The src/dst offset.
int64_t offset = static_cast<int64_t>(ni) * params.dhwc + c_offset +
static_cast<int64_t>(dhwi) * 32;
// Fetch two channels per thread.
__half2 h2(0, 0);
if (ci < params.c) {
int8_t tmp_in[2];
*reinterpret_cast<int16_t *>(tmp_in) =
*reinterpret_cast<int16_t const *>(&src_ptr[offset]);
h2.x = params.dqScaleIn * tmp_in[0];
h2.y = params.dqScaleIn * tmp_in[1];
}
// Extract the two half values.
float2 f2 = __half22float2(h2);
// Normalize the channels.
f2.x = (f2.x - mean) * invStdDev;
f2.y = (f2.y - mean) * invStdDev;
// Scale by gamma and add beta.
f2.x = gammaF2.x * f2.x + betaF2.x;
f2.y = gammaF2.y * f2.y + betaF2.y;
// Apply Silu if needed.
if (params.withSilu) {
f2.x = f2.x * sigmoid(f2.x);
f2.y = f2.y * sigmoid(f2.y);
}
// Store the scaled values.
if (ci < params.c) {
int8_t tmp_in[2];
int32_t tmpq0 = __float2int_rn(params.inv_qScale * f2.x);
int32_t tmpq1 = __float2int_rn(params.inv_qScale * f2.y);
tmpq0 = max(-128, tmpq0);
tmpq0 = min(127, tmpq0);
tmpq1 = max(-128, tmpq1);
tmpq1 = min(127, tmpq1);
tmp_in[0] = tmpq0;
tmp_in[1] = tmpq1;
*reinterpret_cast<int16_t *>(&dst_ptr[offset]) =
*reinterpret_cast<int16_t *>(tmp_in);
}
}
}
void groupNormNCHW32ScaleQDQ(const GroupNormNDHWCParams<__half> &params,
cudaStream_t stream) {
dim3 grid;
// The number of blocks to compute all the channels.
grid.x = divUp(params.c, params.cPerBlock);
// The number of blocks to compute all the activations in a given instance.
grid.y = divUp(params.dhw, params.dhwPerBlock);
// The number of instances.
grid.z = params.n;
switch (params.cPerBlock) {
case 320:
groupNormNCHW32ScaleKernelQDQ<160><<<grid, 160, 0, stream>>>(params);
break;
case 480:
groupNormNCHW32ScaleKernelQDQ<256><<<grid, 256, 0, stream>>>(params);
break;
case 256:
groupNormNCHW32ScaleKernelQDQ<128><<<grid, 128, 0, stream>>>(params);
break;
case 128:
groupNormNCHW32ScaleKernelQDQ<64><<<grid, 64, 0, stream>>>(params);
break;
case 8:
groupNormNCHW32ScaleKernelQDQ<4><<<grid, 4, 0, stream>>>(params);
break;
default:
PADDLE_THROW(
common::errors::Fatal("The function groupNormNCHW32ScaleQDQ of "
"GroupNorm TRT Plugin encounter error"));
}
}
int GroupNormPlugin::initialize() TRT_NOEXCEPT {
if (!with_fp16_) {
// if use fp32
cudaMalloc(&scale_gpu_, sizeof(float) * scale_.size());
cudaMalloc(&bias_gpu_, sizeof(float) * bias_.size());
cudaMemcpy(scale_gpu_,
scale_.data(),
scale_.size() * sizeof(float),
cudaMemcpyHostToDevice);
cudaMemcpy(bias_gpu_,
bias_.data(),
bias_.size() * sizeof(float),
cudaMemcpyHostToDevice);
} else {
// if use fp16
std::vector<half> scale_half(scale_.size());
std::vector<half> bias_half(bias_.size());
for (int i = 0; i < scale_.size(); ++i) {
scale_half[i] = static_cast<half>(scale_[i]);
}
for (int i = 0; i < bias_.size(); ++i) {
bias_half[i] = static_cast<half>(bias_[i]);
}
cudaMalloc(&scale_gpu_, sizeof(half) * scale_half.size());
cudaMalloc(&bias_gpu_, sizeof(half) * bias_half.size());
cudaMemcpy(scale_gpu_,
scale_half.data(),
scale_half.size() * sizeof(half),
cudaMemcpyHostToDevice);
cudaMemcpy(bias_gpu_,
bias_half.data(),
bias_half.size() * sizeof(half),
cudaMemcpyHostToDevice);
}
return 0;
}
bool GroupNormPlugin::supportsFormat(
nvinfer1::DataType type, nvinfer1::PluginFormat format) const TRT_NOEXCEPT {
if (with_fp16_) {
return ((type == nvinfer1::DataType::kHALF) &&
(format == nvinfer1::PluginFormat::kLINEAR));
} else {
return ((type == nvinfer1::DataType::kFLOAT) &&
(format == nvinfer1::PluginFormat::kLINEAR));
}
}
nvinfer1::Dims GroupNormPlugin::getOutputDimensions(
int index, const nvinfer1::Dims *inputDims, int nbInputs) TRT_NOEXCEPT {
return inputDims[0];
}
int GroupNormPlugin::enqueue(int batch_size,
const void *const *inputs,
void *const *outputs,
void *workspace,
cudaStream_t stream) TRT_NOEXCEPT {
const auto &input_dims = this->getInputDims(0);
int groups = groups_;
float eps = eps_;
std::vector<int> input_shape;
input_shape.push_back(batch_size);
for (int i = 0; i < input_dims.nbDims; i++) {
input_shape.push_back(input_dims.d[i]);
}
const auto input_ddim = common::make_ddim(input_shape);
int C = input_shape[1];
PADDLE_ENFORCE_EQ(
C,
scale_.size(),
common::errors::InvalidArgument(
"scale's size should be equal to the channel number in groupnorm,"
"but got channel number:%d, scale's size:%d.",
C,
scale_.size()));
PADDLE_ENFORCE_EQ(
C,
bias_.size(),
common::errors::InvalidArgument(
"bias's size should be equal to the channel number in groupnorm,"
"but got channel number:%d, bias's size:%d.",
C,
bias_.size()));
float *mean_d = static_cast<float *>(workspace);
float *variance_d = mean_d + input_shape[0] * groups_;
float *temp_variance_d = variance_d + input_shape[0] * groups_;
auto input_type = getDataType();
if (input_type == nvinfer1::DataType::kFLOAT) {
VLOG(1) << "TRT Plugin DataType selected. GroupNorm-->fp32";
const float *input = static_cast<const float *>(inputs[0]);
float *output = static_cast<float *>(outputs[0]);
phi::GroupNormDirectCUDAFunctor<float> group_norm;
group_norm(stream,
input,
input_shape,
reinterpret_cast<float *>(bias_gpu_),
reinterpret_cast<float *>(scale_gpu_),
temp_variance_d,
groups_,
eps_,
output,
mean_d,
variance_d,
DataLayout::kNCHW);
} else if (input_type == nvinfer1::DataType::kHALF) {
VLOG(1) << "TRT Plugin DataType selected. GroupNorm-->fp16";
const half *input = static_cast<const half *>(inputs[0]);
half *output = static_cast<half *>(outputs[0]);
phi::GroupNormDirectCUDAFunctor<half, float> group_norm;
group_norm(stream,
input,
input_shape,
reinterpret_cast<const half *>(bias_gpu_),
reinterpret_cast<const half *>(scale_gpu_),
temp_variance_d,
groups_,
eps_,
output,
mean_d,
variance_d,
DataLayout::kNCHW);
} else {
PADDLE_THROW(common::errors::Fatal(
"The GroupNorm TRT Plugin's input type should be float or half."));
}
return cudaGetLastError() != cudaSuccess;
}
nvinfer1::DimsExprs GroupNormPluginDynamic::getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs *inputDims,
int nb_inputs,
nvinfer1::IExprBuilder &expr_builder) TRT_NOEXCEPT {
return inputDims[0];
}
bool GroupNormPluginDynamic::supportsFormatCombination(
int pos,
const nvinfer1::PluginTensorDesc *in_out,
int nb_inputs,
int nb_outputs) TRT_NOEXCEPT {
PADDLE_ENFORCE_NOT_NULL(
in_out,
common::errors::InvalidArgument(
"The input of groupnorm plugin should not be nullptr."));
PADDLE_ENFORCE_LT(
pos,
nb_inputs + nb_outputs,
common::errors::InvalidArgument("The pos(%d) should be less than the "
"num(%d) of the input and the output.",
pos,
nb_inputs + nb_outputs));
const nvinfer1::PluginTensorDesc &in = in_out[pos];
bool int8_support = in.type == nvinfer1::DataType::kINT8 &&
in.format == nvinfer1::PluginFormat::kCHW32;
bool fp16_support =
(in.type == nvinfer1::DataType::kHALF) &&
((!with_silu_ && in.format == nvinfer1::PluginFormat::kLINEAR) ||
in.format == nvinfer1::PluginFormat::kHWC8);
if (pos == 0) {
if (with_int8_) {
return int8_support || fp16_support;
} else if (with_fp16_) {
return fp16_support;
} else {
return (in.type == nvinfer1::DataType::kFLOAT) &&
(in.format == nvinfer1::TensorFormat::kLINEAR);
}
}
const nvinfer1::PluginTensorDesc &prev = in_out[pos - 1];
// output
return in.type == prev.type && in.format == prev.format;
}
nvinfer1::DataType GroupNormPluginDynamic::getOutputDataType(
int index,
const nvinfer1::DataType *input_types,
int nb_inputs) const TRT_NOEXCEPT {
PADDLE_ENFORCE_EQ(index,
0,
common::errors::InvalidArgument(
"The groupnorm Plugin only has one input, so the "
"index value should be 0, but get %d.",
index));
PADDLE_ENFORCE_EQ((input_types[0] == nvinfer1::DataType::kFLOAT ||
input_types[0] == nvinfer1::DataType::kHALF),
true,
common::errors::InvalidArgument(
"The input type should be half or float"));
return input_types[0];
}
int GroupNormPluginDynamic::initialize() TRT_NOEXCEPT {
if (with_fp16_ == false) {
// if use fp32
cudaMalloc(&scale_gpu_, sizeof(float) * scale_.size());
cudaMalloc(&bias_gpu_, sizeof(float) * bias_.size());
cudaMemcpy(scale_gpu_,
scale_.data(),
scale_.size() * sizeof(float),
cudaMemcpyHostToDevice);
cudaMemcpy(bias_gpu_,
bias_.data(),
bias_.size() * sizeof(float),
cudaMemcpyHostToDevice);
} else {
// if use fp16
std::vector<half> scale_half(scale_.size());
std::vector<half> bias_half(bias_.size());
for (int i = 0; i < scale_.size(); ++i) {
scale_half[i] = static_cast<half>(scale_[i]);
}
for (int i = 0; i < bias_.size(); ++i) {
bias_half[i] = static_cast<half>(bias_[i]);
}
cudaMalloc(&scale_gpu_, sizeof(half) * scale_.size());
cudaMalloc(&bias_gpu_, sizeof(half) * bias_.size());
cudaMemcpy(scale_gpu_,
scale_half.data(),
scale_half.size() * sizeof(half),
cudaMemcpyHostToDevice);
cudaMemcpy(bias_gpu_,
bias_half.data(),
bias_half.size() * sizeof(half),
cudaMemcpyHostToDevice);
}
return 0;
}
int GroupNormPluginDynamic::enqueue(
const nvinfer1::PluginTensorDesc *input_desc,
const nvinfer1::PluginTensorDesc *output_desc,
const void *const *inputs,
void *const *outputs,
void *workspace,
cudaStream_t stream) TRT_NOEXCEPT {
const auto &input_dims = input_desc[0].dims;
int groups = groups_;
float eps = eps_;
std::vector<int> input_shape;
for (int i = 0; i < input_dims.nbDims; i++) {
input_shape.push_back(input_dims.d[i]);
}
const auto input_ddim = common::make_ddim(input_shape);
int C = input_shape[1];
int64_t image_size = input_shape[2] * input_shape[3];
int batchSize = input_shape[0];
PADDLE_ENFORCE_EQ(
C,
scale_.size(),
common::errors::InvalidArgument(
"scale's size should be equal to the channel number in groupnorm,"
"but got feature_size:%d, scale's size:%d.",
C,
scale_.size()));
PADDLE_ENFORCE_EQ(
C,
bias_.size(),
common::errors::InvalidArgument(
"bias's size should be equal to the channel number in groupnorm,"
"but got feature_size:%d, bias's size:%d.",
C,
bias_.size()));
float *mean_d = static_cast<float *>(workspace);
float *variance_d = mean_d + input_shape[0] * groups_;
float *temp_variance_d = variance_d + input_shape[0] * groups_;
auto input_type = input_desc[0].type;
if (input_type == nvinfer1::DataType::kFLOAT) {
VLOG(1) << "TRT Plugin DataType selected. GroupNorm-->fp32";
const float *input = reinterpret_cast<const float *>(inputs[0]);
float *output = static_cast<float *>(outputs[0]);
phi::GroupNormDirectCUDAFunctor<float, float> group_norm;
group_norm(stream,
input,
input_shape,
reinterpret_cast<float *>(bias_gpu_),
reinterpret_cast<float *>(scale_gpu_),
temp_variance_d,
groups,
eps,
output,
mean_d,
variance_d,
DataLayout::kNCHW);
} else if (input_type == nvinfer1::DataType::kHALF) {
VLOG(1) << "TRT Plugin DataType selected. GroupNorm-->fp16";
const half *input = reinterpret_cast<const half *>(inputs[0]);
half *output = static_cast<half *>(outputs[0]);
if (input_desc[0].format == nvinfer1::PluginFormat::kLINEAR) {
phi::GroupNormDirectCUDAFunctor<half, float> group_norm;
group_norm(stream,
input,
input_shape,
reinterpret_cast<half *>(bias_gpu_),
reinterpret_cast<half *>(scale_gpu_),
temp_variance_d,
groups,
eps,
output,
mean_d,
variance_d,
DataLayout::kNCHW);
} else if (input_desc[0].format == nvinfer1::PluginFormat::kHWC8) {
int32_t cPerBlock = 320;
int32_t maxBlocksPerDHW = 1024;
switch (input_desc[0].dims.d[1]) {
case 960:
case 1920:
cPerBlock = 480;
break;
case 512:
case 256:
cPerBlock = 256;
break;
case 128:
cPerBlock = 128;
break;
default:
cPerBlock = 320;
}
if (cPerBlock > input_desc[0].dims.d[1]) {
cPerBlock = 8;
}
auto d_dim = input_desc[0].dims.nbDims;
params_.n = input_desc[0].dims.d[0];
if (d_dim == 3) {
params_.c = input_desc[0].dims.d[1];
params_.d = 1;
params_.h = 1;
params_.w = input_desc[0].dims.d[2];
} else if (d_dim == 4) {
params_.c = input_desc[0].dims.d[1];
params_.d = 1;
params_.h = input_desc[0].dims.d[2];
params_.w = input_desc[0].dims.d[3];
} else {
// d_dim == 5
params_.c = input_desc[0].dims.d[1];
params_.d = input_desc[0].dims.d[2];
params_.h = input_desc[0].dims.d[3];
params_.w = input_desc[0].dims.d[4];
}
params_.withSilu = with_silu_;
params_.dst = static_cast<half *>(outputs[0]);
params_.srcX = static_cast<half const *>(inputs[0]);
params_.gamma = reinterpret_cast<half *>(scale_gpu_);
params_.beta = reinterpret_cast<half *>(bias_gpu_);
params_.redBuffer = static_cast<float *>(workspace);
params_.var_data = nullptr;
// params_.n = input_desc[0].dims.d[0];
// params_.h = input_desc[0].dims.d[2];
// params_.w = input_desc[0].dims.d[3];
// params_.c = input_desc[0].dims.d[1];
params_.groups = groups_;
params_.dhw = static_cast<int64_t>(params_.d) * params_.h * params_.w;
const int64_t blocksPerDHW =
findMaxDivisor(params_.dhw, static_cast<int64_t>(maxBlocksPerDHW));
params_.dhwPerBlock = divUp(params_.dhw, blocksPerDHW);
params_.cPerBlock = cPerBlock;
params_.cPerGroup = params_.c / params_.groups;
params_.dhwc = params_.dhw * params_.c;
params_.invDHWC =
1.F / static_cast<float>(params_.dhw * params_.cPerGroup);
params_.groupsPerBlock = cPerBlock / params_.cPerGroup;
params_.eps = eps_;
params_.var_data = nullptr;
cudaMemsetAsync(params_.redBuffer,
0,
2 * sizeof(float) * params_.n * groups_,
stream);
phi::groupNormNDHWCSum<half> ndhwc_sum;
ndhwc_sum(&params_, stream);
phi::groupNormNDHWCScale<half> ndhwc_scale;
ndhwc_scale(params_, stream);
} else {
PADDLE_THROW(common::errors::Fatal(
"The Groupnorm TRT Plugin's only support nchw or nhwc8 input"));
}
} else if (input_type == nvinfer1::DataType::kINT8) {
const int8_t *input = reinterpret_cast<const int8_t *>(inputs[0]);
int8_t *output = static_cast<int8_t *>(outputs[0]);
if (input_desc[0].format == nvinfer1::PluginFormat::kCHW32) {
int32_t cPerBlock = 320;
int32_t maxBlocksPerDHW = 1024;
switch (input_desc[0].dims.d[1]) {
case 960:
case 1920:
cPerBlock = 480;
break;
case 512:
case 256:
cPerBlock = 256;
break;
case 128:
cPerBlock = 128;
break;
default:
cPerBlock = 320;
}
if (cPerBlock > input_desc[0].dims.d[1]) {
cPerBlock = 8;
}
auto d_dim = input_desc[0].dims.nbDims;
params_.n = input_desc[0].dims.d[0];
if (d_dim == 3) {
params_.c = input_desc[0].dims.d[1];
params_.d = 1;
params_.h = 1;
params_.w = input_desc[0].dims.d[2];
} else if (d_dim == 4) {
params_.c = input_desc[0].dims.d[1];
params_.d = 1;
params_.h = input_desc[0].dims.d[2];
params_.w = input_desc[0].dims.d[3];
} else {
// d_dim == 5
params_.c = input_desc[0].dims.d[1];
params_.d = input_desc[0].dims.d[2];
params_.h = input_desc[0].dims.d[3];
params_.w = input_desc[0].dims.d[4];
}
params_.withSilu = with_silu_;
params_.dst = static_cast<half *>(outputs[0]);
params_.srcX = static_cast<half const *>(inputs[0]);
params_.gamma = scale_gpu_;
params_.beta = bias_gpu_;
params_.redBuffer = static_cast<float *>(workspace);
// params_.n = input_desc[0].dims.d[0];
// params_.h = input_desc[0].dims.d[2];
// params_.w = input_desc[0].dims.d[3];
// params_.c = input_desc[0].dims.d[1];
params_.groups = groups_;
params_.dhw = static_cast<int64_t>(params_.d) * params_.h * params_.w;
const int64_t blocksPerDHW =
findMaxDivisor(params_.dhw, static_cast<int64_t>(maxBlocksPerDHW));
params_.dhwPerBlock = divUp(params_.dhw, blocksPerDHW);
params_.cPerBlock = cPerBlock;
params_.cPerGroup = params_.c / params_.groups;
params_.dhwc = params_.dhw * params_.c;
params_.invDHWC =
1.F / static_cast<float>(params_.dhw * params_.cPerGroup);
params_.groupsPerBlock = cPerBlock / params_.cPerGroup;
PADDLE_ENFORCE_EQ(
cPerBlock % params_.cPerGroup,
0,
common::errors::InvalidArgument(
"cPerBlock should be multiple of params_.cPerGroup, "
"now cPerBlock is %d, params_.cPerGroup is %d",
cPerBlock,
params_.cPerGroup));
PADDLE_ENFORCE_EQ(
params_.cPerGroup % 2,
0,
common::errors::InvalidArgument(
"params_.cPerGroup should be a even number, but received %d",
params_.cPerGroup));
params_.eps = eps_;
params_.dqScaleIn = input_desc[0].scale;
params_.inv_qScale = 1.f / output_desc[0].scale;
// Just used for TensorRTDynamicShapeGNTes in test_dynamic_engine.cc
// Do not Edit it
// params_.dqScaleIn = 1.f;
// params_.inv_qScale = 1 / 0.05f;
cudaMemsetAsync(params_.redBuffer,
0,
2 * sizeof(float) * params_.n * groups_,
stream);
groupNormNCHW32SumQDQ(params_, stream);
groupNormNCHW32ScaleQDQ(params_, stream);
} else {
PADDLE_THROW(common::errors::Fatal(
"The Groupnorm TRT Plugin only support nchw32 input"));
}
} else {
// input not float
PADDLE_THROW(common::errors::Fatal(
"The Groupnorm TRT Plugin's only support fp32, fp16 or int8 input"));
}
return cudaGetLastError() != cudaSuccess;
}
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,308 @@
/* Copyright (c) 2022 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. */
#pragma once
#include <algorithm>
#include <string>
#include <vector>
#include "paddle/fluid/framework/tensor.h"
#include "paddle/fluid/framework/tensor_util.h"
#include "paddle/fluid/inference/tensorrt/engine.h"
#include "paddle/fluid/inference/tensorrt/plugin/trt_plugin.h"
#include "paddle/phi/kernels/group_norm_kernel.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
using phi::GroupNormNDHWCParams;
class GroupNormPlugin : public PluginTensorRT {
public:
size_t getSerializationSize() const TRT_NOEXCEPT override {
return getBaseSerializationSize() + SerializedSize(scale_) +
SerializedSize(bias_) + SerializedSize(eps_) +
SerializedSize(groups_) + SerializedSize(mean_shape_) +
SerializedSize(variance_shape_) + SerializedSize(with_fp16_);
}
void serialize(void* buffer) const TRT_NOEXCEPT override {
serializeBase(buffer);
SerializeValue(&buffer, scale_);
SerializeValue(&buffer, bias_);
SerializeValue(&buffer, eps_);
SerializeValue(&buffer, groups_);
SerializeValue(&buffer, mean_shape_);
SerializeValue(&buffer, variance_shape_);
SerializeValue(&buffer, with_fp16_);
}
GroupNormPlugin(const float* scale,
const int scale_num,
const float* bias,
const int bias_num,
float eps,
int groups,
std::vector<int64_t> mean_shape,
std::vector<int64_t> variance_shape,
bool with_fp16)
: groups_(groups),
eps_(eps),
mean_shape_(mean_shape),
variance_shape_(variance_shape),
with_fp16_(with_fp16) {
scale_.resize(scale_num);
bias_.resize(bias_num);
std::copy(scale, scale + scale_num, scale_.data());
std::copy(bias, bias + bias_num, bias_.data());
}
GroupNormPlugin(void const* serialData, size_t serialLength) {
deserializeBase(serialData, serialLength);
DeserializeValue(&serialData, &serialLength, &scale_);
DeserializeValue(&serialData, &serialLength, &bias_);
DeserializeValue(&serialData, &serialLength, &eps_);
DeserializeValue(&serialData, &serialLength, &groups_);
DeserializeValue(&serialData, &serialLength, &mean_shape_);
DeserializeValue(&serialData, &serialLength, &variance_shape_);
DeserializeValue(&serialData, &serialLength, &with_fp16_);
}
~GroupNormPlugin() {}
int initialize() TRT_NOEXCEPT override;
GroupNormPlugin* clone() const TRT_NOEXCEPT override {
auto* ptr = new GroupNormPlugin(scale_.data(),
scale_.size(),
bias_.data(),
bias_.size(),
eps_,
groups_,
mean_shape_,
variance_shape_,
with_fp16_);
ptr->scale_gpu_ = scale_gpu_;
ptr->bias_gpu_ = bias_gpu_;
return ptr;
}
const char* getPluginType() const TRT_NOEXCEPT override {
return "groupnorm_plugin";
}
size_t getWorkspaceSize(int max_batch_size) const TRT_NOEXCEPT {
return 3 * max_batch_size * groups_;
}
bool supportsFormat(nvinfer1::DataType type, nvinfer1::PluginFormat format)
const TRT_NOEXCEPT override;
int getNbOutputs() const TRT_NOEXCEPT override { return 1; }
nvinfer1::Dims getOutputDimensions(int index,
const nvinfer1::Dims* inputs,
int nbInputDims) TRT_NOEXCEPT override;
int enqueue(int batchSize,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
void terminate() TRT_NOEXCEPT override {
if (bias_gpu_) {
cudaFree(bias_gpu_);
bias_gpu_ = nullptr;
}
if (scale_gpu_) {
cudaFree(scale_gpu_);
scale_gpu_ = nullptr;
}
};
private:
std::vector<float> scale_;
std::vector<float> bias_;
void* scale_gpu_;
void* bias_gpu_;
int groups_;
float eps_;
std::vector<int64_t> mean_shape_;
std::vector<int64_t> variance_shape_;
bool with_fp16_;
};
class GroupNormPluginCreator : public TensorRTPluginCreator {
public:
const char* getPluginName() const TRT_NOEXCEPT override {
return "groupnorm_plugin";
}
const char* getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
nvinfer1::IPluginV2* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override {
return new GroupNormPlugin(serial_data, serial_length);
}
};
REGISTER_TRT_PLUGIN_V2(GroupNormPluginCreator);
class GroupNormPluginDynamic : public DynamicPluginTensorRT {
public:
GroupNormPluginDynamic(const float* scale,
const int scale_num,
const float* bias,
const int bias_num,
float eps,
int groups,
std::vector<int64_t> mean_shape,
std::vector<int64_t> variance_shape,
bool with_silu,
bool with_fp16,
bool with_int8)
: groups_(groups),
eps_(eps),
mean_shape_(mean_shape),
variance_shape_(variance_shape),
with_silu_(with_silu),
with_fp16_(with_fp16),
with_int8_(with_int8) {
scale_.resize(scale_num);
bias_.resize(bias_num);
std::copy(scale, scale + scale_num, scale_.data());
std::copy(bias, bias + bias_num, bias_.data());
}
GroupNormPluginDynamic(void const* serialData, size_t serialLength) {
DeserializeValue(&serialData, &serialLength, &scale_);
DeserializeValue(&serialData, &serialLength, &bias_);
DeserializeValue(&serialData, &serialLength, &eps_);
DeserializeValue(&serialData, &serialLength, &groups_);
DeserializeValue(&serialData, &serialLength, &mean_shape_);
DeserializeValue(&serialData, &serialLength, &variance_shape_);
DeserializeValue(&serialData, &serialLength, &with_silu_);
DeserializeValue(&serialData, &serialLength, &with_fp16_);
DeserializeValue(&serialData, &serialLength, &with_int8_);
}
nvinfer1::IPluginV2DynamicExt* clone() const TRT_NOEXCEPT override {
auto* ptr = new GroupNormPluginDynamic(scale_.data(),
scale_.size(),
bias_.data(),
bias_.size(),
eps_,
groups_,
mean_shape_,
variance_shape_,
with_silu_,
with_fp16_,
with_int8_);
ptr->scale_gpu_ = scale_gpu_;
ptr->bias_gpu_ = bias_gpu_;
return ptr;
}
const char* getPluginType() const TRT_NOEXCEPT override {
return "groupnorm_plugin_dynamic";
}
int getNbOutputs() const TRT_NOEXCEPT override { return 1; }
int initialize() TRT_NOEXCEPT override;
size_t getSerializationSize() const TRT_NOEXCEPT override {
return SerializedSize(scale_) + SerializedSize(bias_) +
SerializedSize(eps_) + SerializedSize(groups_) +
SerializedSize(mean_shape_) + SerializedSize(variance_shape_) +
SerializedSize(with_silu_) + SerializedSize(with_fp16_) +
+SerializedSize(with_int8_);
}
void serialize(void* buffer) const TRT_NOEXCEPT override {
SerializeValue(&buffer, scale_);
SerializeValue(&buffer, bias_);
SerializeValue(&buffer, eps_);
SerializeValue(&buffer, groups_);
SerializeValue(&buffer, mean_shape_);
SerializeValue(&buffer, variance_shape_);
SerializeValue(&buffer, with_silu_);
SerializeValue(&buffer, with_fp16_);
SerializeValue(&buffer, with_int8_);
}
nvinfer1::DimsExprs getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs* inputs,
int nb_inputs,
nvinfer1::IExprBuilder& expr_builder) // NOLINT
TRT_NOEXCEPT override;
bool supportsFormatCombination(int pos,
const nvinfer1::PluginTensorDesc* inOut,
int nbInputs,
int nbOutputs) TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::DynamicPluginTensorDesc* in,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc* out,
int nbOutputs) TRT_NOEXCEPT override {}
size_t getWorkspaceSize(const nvinfer1::PluginTensorDesc* inputs,
int nbInputs,
const nvinfer1::PluginTensorDesc* outputs,
int nbOutputs) const TRT_NOEXCEPT override {
return 3 * inputs[0].dims.d[0] * groups_ * sizeof(float);
}
int enqueue(const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* inputTypes,
int nbInputs) const
TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override { delete this; }
void terminate() TRT_NOEXCEPT override {
if (bias_gpu_) {
cudaFree(bias_gpu_);
bias_gpu_ = nullptr;
}
if (scale_gpu_) {
cudaFree(scale_gpu_);
scale_gpu_ = nullptr;
}
};
private:
std::vector<float> scale_;
std::vector<float> bias_;
void* scale_gpu_ = nullptr;
void* bias_gpu_ = nullptr;
int groups_;
float eps_;
std::vector<int64_t> mean_shape_;
std::vector<int64_t> variance_shape_;
GroupNormNDHWCParams<half> params_;
bool with_silu_;
bool with_fp16_;
bool with_int8_;
};
class GroupNormPluginDynamicCreator : public TensorRTPluginCreator {
public:
const char* getPluginName() const TRT_NOEXCEPT override {
return "groupnorm_plugin_dynamic";
}
const char* getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
nvinfer1::IPluginV2* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override {
return new GroupNormPluginDynamic(serial_data, serial_length);
}
};
REGISTER_TRT_PLUGIN_V2(GroupNormPluginDynamicCreator);
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,161 @@
// Copyright (c) 2020 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 <cassert>
#include <cstring>
#include "paddle/fluid/inference/tensorrt/plugin/hard_swish_op_plugin.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
nvinfer1::Dims HardSwishPlugin::getOutputDimensions(
int index, const nvinfer1::Dims *in_dims, int nb_inputs) TRT_NOEXCEPT {
assert(nb_inputs == 1);
assert(index < this->getNbOutputs());
nvinfer1::Dims const &input_dims = in_dims[0];
nvinfer1::Dims output_dims = input_dims;
return output_dims;
}
template <typename T>
__device__ T kMax(T a, T b) {
return a > b ? a : b;
}
template <typename T>
__device__ T kMin(T a, T b) {
return a < b ? a : b;
}
template <typename T, unsigned TPB>
__global__ void hard_swish_kernel(float threshold,
float scale,
float offset,
int n,
const T *input,
T *output) {
const int idx = blockIdx.x * TPB + threadIdx.x;
if (idx < n) {
const T in = input[idx];
output[idx] = in / scale * kMin<T>(kMax<T>(in + offset, 0), threshold);
}
}
int HardSwishPlugin::enqueue(int batch_size,
const void *const *inputs,
void *const *outputs,
void *,
cudaStream_t stream) TRT_NOEXCEPT {
const auto &input_dims = this->getInputDims(0);
int num = batch_size;
for (int i = 0; i < input_dims.nbDims; i++) {
num *= input_dims.d[i];
}
float threshold = threshold_;
float scale = scale_;
float offset = offset_;
const int block_size = 256;
const int grid_size = (num + block_size - 1) / block_size;
const float *input = static_cast<const float *>(inputs[0]);
float *output = static_cast<float *>(outputs[0]);
hard_swish_kernel<float, block_size><<<grid_size, block_size, 0, stream>>>(
threshold, scale, offset, num, input, output);
return cudaGetLastError() != cudaSuccess;
}
nvinfer1::DimsExprs HardSwishPluginDynamic::getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs *inputs,
int nb_inputs,
nvinfer1::IExprBuilder &expr_builder) TRT_NOEXCEPT {
return inputs[0];
}
int HardSwishPluginDynamic::enqueue(
const nvinfer1::PluginTensorDesc *input_desc,
const nvinfer1::PluginTensorDesc *output_desc,
const void *const *inputs,
void *const *outputs,
void *workspace,
cudaStream_t stream) TRT_NOEXCEPT {
auto input_dims = input_desc[0].dims;
int num = 1;
for (int i = 0; i < input_dims.nbDims; i++) {
num *= input_dims.d[i];
}
float threshold = threshold_;
float scale = scale_;
float offset = offset_;
const int block_size = 256;
const int grid_size = (num + block_size - 1) / block_size;
const float *input = static_cast<const float *>(inputs[0]);
float *output = static_cast<float *>(outputs[0]);
hard_swish_kernel<float, block_size><<<grid_size, block_size, 0, stream>>>(
threshold, scale, offset, num, input, output);
return cudaGetLastError() != cudaSuccess;
}
nvinfer1::DataType HardSwishPluginDynamic::getOutputDataType(
int index,
const nvinfer1::DataType *input_types,
int nb_inputs) const TRT_NOEXCEPT {
PADDLE_ENFORCE_EQ(index,
0,
common::errors::InvalidArgument(
"The Elementwise Plugin only has one input, so the "
"index value should be 0, but get %d.",
index));
return input_types[0];
}
bool HardSwishPluginDynamic::supportsFormatCombination(
int pos,
const nvinfer1::PluginTensorDesc *in_out,
int nb_inputs,
int nb_outputs) TRT_NOEXCEPT {
PADDLE_ENFORCE_NOT_NULL(
in_out,
common::errors::InvalidArgument(
"The input of swish plugin should not be nullptr."));
PADDLE_ENFORCE_LT(
pos,
nb_inputs + nb_outputs,
common::errors::InvalidArgument("The pos(%d) should be less than the "
"num(%d) of the input and the output.",
pos,
nb_inputs + nb_outputs));
(in_out && pos < (nb_inputs + nb_outputs));
const nvinfer1::PluginTensorDesc &in = in_out[pos];
if (pos == 0) {
return (in.type == nvinfer1::DataType::kFLOAT) &&
(in.format == nvinfer1::TensorFormat::kLINEAR);
}
const nvinfer1::PluginTensorDesc &prev = in_out[pos - 1];
// output
return in.type == prev.type && in.format == prev.format;
}
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,215 @@
// 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.
#pragma once
#include <stdio.h>
#include <cassert>
#include <string>
#include <vector>
#include "paddle/fluid/inference/tensorrt/engine.h"
#include "paddle/fluid/inference/tensorrt/plugin/trt_plugin.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
class HardSwishPlugin : public PluginTensorRT {
public:
HardSwishPlugin(const float threshold, const float scale, const float offset)
: threshold_(threshold), scale_(scale), offset_(offset) {}
// It was used for tensorrt deserialization.
// It should not be called by users.
HardSwishPlugin(void const* serialData, size_t serialLength) {
deserializeBase(serialData, serialLength);
DeserializeValue(&serialData, &serialLength, &threshold_);
DeserializeValue(&serialData, &serialLength, &scale_);
DeserializeValue(&serialData, &serialLength, &offset_);
}
~HardSwishPlugin() {}
HardSwishPlugin* clone() const TRT_NOEXCEPT override {
return new HardSwishPlugin(threshold_, scale_, offset_);
}
const char* getPluginType() const TRT_NOEXCEPT override {
return "hard_swish_plugin";
}
int getNbOutputs() const TRT_NOEXCEPT override { return 1; }
int initialize() TRT_NOEXCEPT override { return 0; }
nvinfer1::Dims getOutputDimensions(int index,
const nvinfer1::Dims* inputs,
int nbInputDims) TRT_NOEXCEPT override;
int enqueue(int batchSize,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
size_t getSerializationSize() const TRT_NOEXCEPT override {
return getBaseSerializationSize() + SerializedSize(threshold_) +
SerializedSize(scale_) + SerializedSize(offset_);
}
// TRT will call this func to serialize the configuration of TRT
// It should not be called by users.
void serialize(void* buffer) const TRT_NOEXCEPT override {
serializeBase(buffer);
SerializeValue(&buffer, threshold_);
SerializeValue(&buffer, scale_);
SerializeValue(&buffer, offset_);
}
protected:
float threshold_;
float scale_;
float offset_;
};
class HardSwishPluginCreator : public TensorRTPluginCreator {
public:
const char* getPluginName() const TRT_NOEXCEPT override {
return "hard_swish_plugin";
}
const char* getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
nvinfer1::IPluginV2* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override {
return new HardSwishPlugin(serial_data, serial_length);
}
};
REGISTER_TRT_PLUGIN_V2(HardSwishPluginCreator);
class HardSwishPluginDynamic : public DynamicPluginTensorRT {
public:
HardSwishPluginDynamic(const float threshold,
const float scale,
const float offset)
: threshold_(threshold), scale_(scale), offset_(offset) {}
// It was used for tensorrt deserialization.
// It should not be called by users.
HardSwishPluginDynamic(void const* serialData, size_t serialLength) {
DeserializeValue(&serialData, &serialLength, &threshold_);
DeserializeValue(&serialData, &serialLength, &scale_);
DeserializeValue(&serialData, &serialLength, &offset_);
}
~HardSwishPluginDynamic() {}
nvinfer1::IPluginV2DynamicExt* clone() const TRT_NOEXCEPT override {
return new HardSwishPluginDynamic(threshold_, scale_, offset_);
}
const char* getPluginType() const TRT_NOEXCEPT override {
return "hard_swish_plugin_dynamic";
}
int getNbOutputs() const TRT_NOEXCEPT override { return 1; }
int initialize() TRT_NOEXCEPT override { return 0; }
nvinfer1::DimsExprs getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs* inputs,
int nb_inputs,
nvinfer1::IExprBuilder& expr_builder) // NOLINT
TRT_NOEXCEPT override;
int enqueue(const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
size_t getSerializationSize() const TRT_NOEXCEPT override {
return SerializedSize(threshold_) + SerializedSize(scale_) +
SerializedSize(offset_);
}
// TRT will call this func to serialize the configuration of TRT
// It should not be called by users.
void serialize(void* buffer) const TRT_NOEXCEPT override {
SerializeValue(&buffer, threshold_);
SerializeValue(&buffer, scale_);
SerializeValue(&buffer, offset_);
}
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* inputTypes,
int nbInputs) const
TRT_NOEXCEPT override;
bool supportsFormatCombination(int pos,
const nvinfer1::PluginTensorDesc* inOut,
int nbInputs,
int nbOutputs) TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::DynamicPluginTensorDesc* in,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc* out,
int nbOutputs) TRT_NOEXCEPT override {}
void destroy() TRT_NOEXCEPT override { delete this; }
protected:
float threshold_;
float scale_;
float offset_;
};
class HardSwishPluginDynamicCreator : public nvinfer1::IPluginCreator {
public:
HardSwishPluginDynamicCreator() {}
const char* getPluginName() const TRT_NOEXCEPT override {
return "hard_swish_plugin_dynamic";
}
const char* getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
const nvinfer1::PluginFieldCollection* getFieldNames() TRT_NOEXCEPT override {
return &field_collection_;
}
nvinfer1::IPluginV2* createPlugin(const char* name,
const nvinfer1::PluginFieldCollection* fc)
TRT_NOEXCEPT override {
return nullptr;
}
nvinfer1::IPluginV2* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override {
auto plugin = new HardSwishPluginDynamic(serial_data, serial_length);
return plugin;
}
void setPluginNamespace(const char* lib_namespace) TRT_NOEXCEPT override {
plugin_namespace_ = lib_namespace;
}
const char* getPluginNamespace() const TRT_NOEXCEPT override {
return plugin_namespace_.c_str();
}
private:
std::string plugin_namespace_;
std::string plugin_name_;
nvinfer1::PluginFieldCollection field_collection_{0, nullptr};
std::vector<nvinfer1::PluginField> plugin_attributes_;
};
REGISTER_TRT_PLUGIN_V2(HardSwishPluginDynamicCreator);
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,347 @@
// Copyright (c) 2018 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 <stdio.h>
#include <cassert>
#include <vector>
#include "glog/logging.h"
#include "paddle/fluid/inference/tensorrt/plugin/instance_norm_op_plugin.h"
#include "paddle/phi/core/platform/device/gpu/gpu_dnn.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
cudnnStatus_t convert_trt2cudnn_dtype(nvinfer1::DataType trt_dtype,
cudnnDataType_t *cudnn_dtype) {
switch (trt_dtype) {
case nvinfer1::DataType::kFLOAT:
*cudnn_dtype = CUDNN_DATA_FLOAT;
break;
case nvinfer1::DataType::kHALF:
*cudnn_dtype = CUDNN_DATA_HALF;
break;
default:
return CUDNN_STATUS_BAD_PARAM;
}
return CUDNN_STATUS_SUCCESS;
}
int InstanceNormPlugin::initialize() TRT_NOEXCEPT { return 0; }
nvinfer1::Dims InstanceNormPlugin::getOutputDimensions(
int index, const nvinfer1::Dims *inputDims, int nbInputs) TRT_NOEXCEPT {
assert(nbInputs == 1);
assert(index < this->getNbOutputs());
nvinfer1::Dims const &input_dims = inputDims[0];
nvinfer1::Dims output_dims = input_dims;
return output_dims;
}
bool InstanceNormPlugin::supportsFormat(
nvinfer1::DataType type, nvinfer1::PluginFormat format) const TRT_NOEXCEPT {
return ((type == nvinfer1::DataType::kFLOAT ||
type == nvinfer1::DataType::kHALF) &&
(format == nvinfer1::PluginFormat::kLINEAR));
}
int InstanceNormPlugin::enqueue(int batch_size,
const void *const *inputs,
void *const *outputs,
void *workspace,
cudaStream_t stream) TRT_NOEXCEPT {
const auto &input_dims = this->getInputDims(0);
int n = batch_size;
int c = input_dims.d[0];
int h = input_dims.d[1];
int w = input_dims.d[2];
scale_t.Resize(common::make_ddim({batch_size, c}));
bias_t.Resize(common::make_ddim({batch_size, c}));
int device_id;
cudaGetDevice(&device_id);
float *scale_d = scale_t.mutable_data<float>(GPUPlace(device_id));
float *bias_d = bias_t.mutable_data<float>(GPUPlace(device_id));
for (int i = 0; i < batch_size; i++) {
cudaMemcpyAsync(scale_d + i * c,
scale_.data(),
sizeof(float) * c,
cudaMemcpyHostToDevice,
stream);
cudaMemcpyAsync(bias_d + i * c,
bias_.data(),
sizeof(float) * c,
cudaMemcpyHostToDevice,
stream);
}
phi::dynload::cudnnSetTensor4dDescriptor(
b_desc_, CUDNN_TENSOR_NCHW, CUDNN_DATA_FLOAT, 1, n * c, 1, 1);
cudnnDataType_t cudnn_dtype;
nvinfer1::DataType data_type = getDataType();
convert_trt2cudnn_dtype(data_type, &cudnn_dtype);
phi::dynload::cudnnSetTensor4dDescriptor(
x_desc_, CUDNN_TENSOR_NCHW, cudnn_dtype, 1, n * c, h, w);
phi::dynload::cudnnSetTensor4dDescriptor(
y_desc_, CUDNN_TENSOR_NCHW, cudnn_dtype, 1, n * c, h, w);
float alpha = 1;
float beta = 0;
phi::dynload::cudnnSetStream(handle_, stream);
void const *x_ptr = inputs[0];
void *y_ptr = outputs[0];
phi::dynload::cudnnBatchNormalizationForwardTraining(
handle_,
CUDNN_BATCHNORM_SPATIAL_PERSISTENT,
&alpha,
&beta,
x_desc_,
x_ptr,
y_desc_,
y_ptr,
b_desc_,
scale_d,
bias_d,
1.,
nullptr,
nullptr,
eps_,
nullptr,
nullptr);
return cudaGetLastError() != cudaSuccess;
}
int InstanceNormPluginEnqueue(const nvinfer1::PluginTensorDesc *inputDesc,
const nvinfer1::PluginTensorDesc *outputDesc,
const void *const *inputs,
void *const *outputs,
void *workspace,
const float *scale,
const float *bias,
float eps,
cudnnTensorDescriptor_t x_desc_,
cudnnTensorDescriptor_t y_desc_,
cudnnTensorDescriptor_t b_desc_,
cudnnHandle_t handle_,
cudaStream_t stream) {
nvinfer1::Dims input_dims = inputDesc[0].dims;
int n = input_dims.d[0];
int c = input_dims.d[1];
int h = input_dims.d[2];
int w = input_dims.d[3];
phi::DenseTensor scale_t;
phi::DenseTensor bias_t;
scale_t.Resize(common::make_ddim({n, c}));
bias_t.Resize(common::make_ddim({n, c}));
int device_id;
cudaGetDevice(&device_id);
float *scale_d = scale_t.mutable_data<float>(GPUPlace(device_id));
float *bias_d = bias_t.mutable_data<float>(GPUPlace(device_id));
for (int i = 0; i < n; i++) {
cudaMemcpyAsync(scale_d + i * c,
scale,
sizeof(float) * c,
cudaMemcpyHostToDevice,
stream);
cudaMemcpyAsync(bias_d + i * c,
bias,
sizeof(float) * c,
cudaMemcpyHostToDevice,
stream);
}
phi::dynload::cudnnSetTensor4dDescriptor(
b_desc_, CUDNN_TENSOR_NCHW, CUDNN_DATA_FLOAT, 1, n * c, 1, 1);
cudnnDataType_t cudnn_dtype;
auto data_type = inputDesc[0].type;
convert_trt2cudnn_dtype(data_type, &cudnn_dtype);
phi::dynload::cudnnSetTensor4dDescriptor(
x_desc_, CUDNN_TENSOR_NCHW, cudnn_dtype, 1, n * c, h, w);
phi::dynload::cudnnSetTensor4dDescriptor(
y_desc_, CUDNN_TENSOR_NCHW, cudnn_dtype, 1, n * c, h, w);
float alpha = 1;
float beta = 0;
phi::dynload::cudnnSetStream(handle_, stream);
void const *x_ptr = inputs[0];
void *y_ptr = outputs[0];
phi::dynload::cudnnBatchNormalizationForwardTraining(
handle_,
CUDNN_BATCHNORM_SPATIAL_PERSISTENT,
&alpha,
&beta,
x_desc_,
x_ptr,
y_desc_,
y_ptr,
b_desc_,
scale_d,
bias_d,
1.,
nullptr,
nullptr,
eps,
nullptr,
nullptr);
return cudaGetLastError() != cudaSuccess;
}
int InstanceNormPluginDynamic::initialize() TRT_NOEXCEPT { return 0; }
nvinfer1::DimsExprs InstanceNormPluginDynamic::getOutputDimensions(
int index,
const nvinfer1::DimsExprs *inputs,
int nbInputs,
nvinfer1::IExprBuilder &expr_builder) TRT_NOEXCEPT {
assert(nbInputs == 1);
assert(index < this->getNbOutputs());
nvinfer1::DimsExprs output(inputs[0]);
return output;
}
bool InstanceNormPluginDynamic::supportsFormatCombination(
int pos,
const nvinfer1::PluginTensorDesc *inOut,
int nbInputs,
int nbOutputs) TRT_NOEXCEPT {
assert(inOut && pos < (nbInputs + nbOutputs));
assert(pos == 0 || pos == 1);
return ((inOut[pos].type == nvinfer1::DataType::kFLOAT ||
inOut[pos].type == nvinfer1::DataType::kHALF) &&
(inOut[pos].format == nvinfer1::PluginFormat::kLINEAR) &&
inOut[pos].type == inOut[0].type);
}
int InstanceNormPluginDynamic::enqueue(
const nvinfer1::PluginTensorDesc *inputDesc,
const nvinfer1::PluginTensorDesc *outputDesc,
const void *const *inputs,
void *const *outputs,
void *workspace,
cudaStream_t stream) TRT_NOEXCEPT {
return InstanceNormPluginEnqueue(inputDesc,
outputDesc,
inputs,
outputs,
workspace,
scale_.data(),
bias_.data(),
eps_,
x_desc_,
y_desc_,
b_desc_,
handle_,
stream);
}
nvinfer1::DataType InstanceNormPluginDynamic::getOutputDataType(
int index,
const nvinfer1::DataType *inputTypes,
int nbInputs) const TRT_NOEXCEPT {
assert(inputTypes && nbInputs > 0 && index == 0);
return inputTypes[0];
}
void InstanceNormPluginDynamic::configurePlugin(
const nvinfer1::DynamicPluginTensorDesc *in,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc *out,
int nbOutputs) TRT_NOEXCEPT {}
int PIRInstanceNormPlugin::initialize() TRT_NOEXCEPT { return 0; }
nvinfer1::DimsExprs PIRInstanceNormPlugin::getOutputDimensions(
int index,
const nvinfer1::DimsExprs *inputs,
int nbInputs,
nvinfer1::IExprBuilder &expr_builder) TRT_NOEXCEPT {
assert(nbInputs == 1);
assert(index < this->getNbOutputs());
nvinfer1::DimsExprs output(inputs[0]);
return output;
}
bool PIRInstanceNormPlugin::supportsFormatCombination(
int pos,
const nvinfer1::PluginTensorDesc *inOut,
int nbInputs,
int nbOutputs) TRT_NOEXCEPT {
assert(inOut && pos < (nbInputs + nbOutputs));
assert(pos == 0 || pos == 1);
return ((inOut[pos].type == nvinfer1::DataType::kFLOAT ||
inOut[pos].type == nvinfer1::DataType::kHALF) &&
(inOut[pos].format == nvinfer1::PluginFormat::kLINEAR) &&
inOut[pos].type == inOut[0].type);
}
int PIRInstanceNormPlugin::enqueue(const nvinfer1::PluginTensorDesc *inputDesc,
const nvinfer1::PluginTensorDesc *outputDesc,
const void *const *inputs,
void *const *outputs,
void *workspace,
cudaStream_t stream) TRT_NOEXCEPT {
const float *scale_ = reinterpret_cast<const float *>(inputs[1]);
const float *bias_ = reinterpret_cast<const float *>(inputs[2]);
return InstanceNormPluginEnqueue(inputDesc,
outputDesc,
inputs,
outputs,
workspace,
scale_,
bias_,
eps_,
x_desc_,
y_desc_,
b_desc_,
handle_,
stream);
}
nvinfer1::DataType PIRInstanceNormPlugin::getOutputDataType(
int index,
const nvinfer1::DataType *inputTypes,
int nbInputs) const TRT_NOEXCEPT {
assert(inputTypes && nbInputs > 0 && index == 0);
return inputTypes[0];
}
void PIRInstanceNormPlugin::configurePlugin(
const nvinfer1::DynamicPluginTensorDesc *in,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc *out,
int nbOutputs) TRT_NOEXCEPT {}
nvinfer1::IPluginV2 *PIRInstanceNormPluginCreator::createPlugin(
const char *name, const nvinfer1::PluginFieldCollection *fc) TRT_NOEXCEPT {
float epsilon = 1e-8;
for (int i = 0; i < fc->nbFields; ++i) {
const std::string field_name(fc->fields[i].name);
if (field_name.compare("epsilon") == 0) {
epsilon = *static_cast<const float *>(fc->fields[i].data);
} else {
assert(false && "unknown plugin field name.");
}
}
return new PIRInstanceNormPlugin(epsilon);
}
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,380 @@
// Copyright (c) 2018 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.
#pragma once
#include <algorithm>
#include <string>
#include <vector>
#include "paddle/fluid/framework/tensor.h"
#include "paddle/fluid/inference/tensorrt/engine.h"
#include "paddle/fluid/inference/tensorrt/plugin/trt_plugin.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
class InstanceNormPlugin : public PluginTensorRT {
private:
float eps_;
std::vector<float> scale_;
std::vector<float> bias_;
phi::DenseTensor scale_t;
phi::DenseTensor bias_t;
cudnnHandle_t handle_;
cudnnTensorDescriptor_t x_desc_, y_desc_, b_desc_;
public:
size_t getSerializationSize() const TRT_NOEXCEPT override {
return getBaseSerializationSize() + SerializedSize(eps_) +
SerializedSize(scale_) + SerializedSize(bias_);
}
// TRT will call this func when we need to serialize the configuration of
// tensorrt.
// It should not be called by users.
void serialize(void *buffer) const TRT_NOEXCEPT override {
serializeBase(buffer);
SerializeValue(&buffer, eps_);
SerializeValue(&buffer, scale_);
SerializeValue(&buffer, bias_);
}
explicit InstanceNormPlugin(const float eps,
const std::vector<float> scale,
const std::vector<float> bias)
: eps_(eps), scale_(scale), bias_(bias) {
PADDLE_ENFORCE_EQ(scale.size(),
bias.size(),
common::errors::InvalidArgument(
"The instanceNorm's scale and bias should be the "
"same size. Got scale size = %d, but bias size = %d",
scale.size(),
bias.size()));
phi::dynload::cudnnCreate(&handle_);
phi::dynload::cudnnCreateTensorDescriptor(&x_desc_);
phi::dynload::cudnnCreateTensorDescriptor(&y_desc_);
phi::dynload::cudnnCreateTensorDescriptor(&b_desc_);
}
// It was used for tensorrt deserialization.
// It should not be called by users.
InstanceNormPlugin(void const *serialData, size_t serialLength) {
deserializeBase(serialData, serialLength);
DeserializeValue(&serialData, &serialLength, &eps_);
DeserializeValue(&serialData, &serialLength, &scale_);
DeserializeValue(&serialData, &serialLength, &bias_);
phi::dynload::cudnnCreate(&handle_);
phi::dynload::cudnnCreateTensorDescriptor(&x_desc_);
phi::dynload::cudnnCreateTensorDescriptor(&y_desc_);
phi::dynload::cudnnCreateTensorDescriptor(&b_desc_);
}
~InstanceNormPlugin() {
phi::dynload::cudnnDestroy(handle_);
phi::dynload::cudnnDestroyTensorDescriptor(x_desc_);
phi::dynload::cudnnDestroyTensorDescriptor(y_desc_);
phi::dynload::cudnnDestroyTensorDescriptor(b_desc_);
}
int initialize() TRT_NOEXCEPT override;
InstanceNormPlugin *clone() const TRT_NOEXCEPT override {
return new InstanceNormPlugin(eps_, scale_, bias_);
}
const char *getPluginType() const TRT_NOEXCEPT override {
return "instance_norm";
}
int getNbOutputs() const TRT_NOEXCEPT override { return 1; }
nvinfer1::Dims getOutputDimensions(int index,
const nvinfer1::Dims *inputs,
int nbInputDims) TRT_NOEXCEPT override;
int enqueue(int batchSize,
const void *const *inputs,
void *const *outputs,
void *workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
bool supportsFormat(nvinfer1::DataType type, nvinfer1::PluginFormat format)
const TRT_NOEXCEPT override;
};
class InstanceNormPluginCreator : public TensorRTPluginCreator {
public:
const char *getPluginName() const TRT_NOEXCEPT override {
return "instance_norm";
}
const char *getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
nvinfer1::IPluginV2 *deserializePlugin(const char *name,
const void *serial_data,
size_t serial_length)
TRT_NOEXCEPT override {
return new InstanceNormPlugin(serial_data, serial_length);
}
};
class InstanceNormPluginDynamic : public DynamicPluginTensorRT {
private:
float eps_;
std::vector<float> scale_;
std::vector<float> bias_;
cudnnHandle_t handle_;
cudnnTensorDescriptor_t x_desc_, y_desc_, b_desc_;
public:
size_t getSerializationSize() const TRT_NOEXCEPT override {
return SerializedSize(eps_) + SerializedSize(scale_) +
SerializedSize(bias_);
}
// TRT will call this func when we need to serialize the configuration of
// tensorrt.
// It should not be called by users.
void serialize(void *buffer) const TRT_NOEXCEPT override {
SerializeValue(&buffer, eps_);
SerializeValue(&buffer, scale_);
SerializeValue(&buffer, bias_);
}
explicit InstanceNormPluginDynamic(const float eps,
const std::vector<float> scale,
const std::vector<float> bias)
: eps_(eps), scale_(scale), bias_(bias) {
PADDLE_ENFORCE_EQ(scale.size(),
bias.size(),
common::errors::InvalidArgument(
"The instanceNorm's scale and bias should be the "
"same size. Got scale size = %d, but bias size = %d",
scale.size(),
bias.size()));
phi::dynload::cudnnCreate(&handle_);
phi::dynload::cudnnCreateTensorDescriptor(&x_desc_);
phi::dynload::cudnnCreateTensorDescriptor(&y_desc_);
phi::dynload::cudnnCreateTensorDescriptor(&b_desc_);
}
// It was used for tensorrt deserialization.
// It should not be called by users.
InstanceNormPluginDynamic(void const *serialData, size_t serialLength) {
DeserializeValue(&serialData, &serialLength, &eps_);
DeserializeValue(&serialData, &serialLength, &scale_);
DeserializeValue(&serialData, &serialLength, &bias_);
phi::dynload::cudnnCreate(&handle_);
phi::dynload::cudnnCreateTensorDescriptor(&x_desc_);
phi::dynload::cudnnCreateTensorDescriptor(&y_desc_);
phi::dynload::cudnnCreateTensorDescriptor(&b_desc_);
}
~InstanceNormPluginDynamic() {
phi::dynload::cudnnDestroy(handle_);
phi::dynload::cudnnDestroyTensorDescriptor(x_desc_);
phi::dynload::cudnnDestroyTensorDescriptor(y_desc_);
phi::dynload::cudnnDestroyTensorDescriptor(b_desc_);
}
int initialize() TRT_NOEXCEPT override;
nvinfer1::IPluginV2DynamicExt *clone() const TRT_NOEXCEPT override {
return new InstanceNormPluginDynamic(eps_, scale_, bias_);
}
const char *getPluginType() const TRT_NOEXCEPT override {
return "instance_norm_dynamic";
}
int getNbOutputs() const TRT_NOEXCEPT override { return 1; }
nvinfer1::DimsExprs getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs *inputs,
int nb_inputs,
nvinfer1::IExprBuilder &expr_builder) // NOLINT
TRT_NOEXCEPT override;
bool supportsFormatCombination(int pos,
const nvinfer1::PluginTensorDesc *inOut,
int nbInputs,
int nbOutputs) TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::DynamicPluginTensorDesc *in,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc *out,
int nbOutputs) TRT_NOEXCEPT override;
size_t getWorkspaceSize(const nvinfer1::PluginTensorDesc *inputs,
int nbInputs,
const nvinfer1::PluginTensorDesc *outputs,
int nbOutputs) const TRT_NOEXCEPT override {
return 0;
}
int enqueue(const nvinfer1::PluginTensorDesc *inputDesc,
const nvinfer1::PluginTensorDesc *outputDesc,
const void *const *inputs,
void *const *outputs,
void *workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType *inputTypes,
int nbInputs) const
TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override { delete this; }
};
class InstanceNormPluginDynamicCreator : public TensorRTPluginCreator {
public:
const char *getPluginName() const TRT_NOEXCEPT override {
return "instance_norm_dynamic";
}
const char *getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
nvinfer1::IPluginV2 *deserializePlugin(const char *name,
const void *serial_data,
size_t serial_length)
TRT_NOEXCEPT override {
return new InstanceNormPluginDynamic(serial_data, serial_length);
}
};
class PIRInstanceNormPlugin : public DynamicPluginTensorRT {
private:
float eps_;
cudnnHandle_t handle_;
cudnnTensorDescriptor_t x_desc_, y_desc_, b_desc_;
public:
size_t getSerializationSize() const TRT_NOEXCEPT override {
return SerializedSize(eps_);
}
// TRT will call this func when we need to serialize the configuration of
// tensorrt.
// It should not be called by users.
void serialize(void *buffer) const TRT_NOEXCEPT override {
SerializeValue(&buffer, eps_);
}
explicit PIRInstanceNormPlugin(const float eps) : eps_(eps) {
phi::dynload::cudnnCreate(&handle_);
phi::dynload::cudnnCreateTensorDescriptor(&x_desc_);
phi::dynload::cudnnCreateTensorDescriptor(&y_desc_);
phi::dynload::cudnnCreateTensorDescriptor(&b_desc_);
}
// It was used for tensorrt deserialization.
// It should not be called by users.
PIRInstanceNormPlugin(void const *serialData, size_t serialLength) {
DeserializeValue(&serialData, &serialLength, &eps_);
phi::dynload::cudnnCreate(&handle_);
phi::dynload::cudnnCreateTensorDescriptor(&x_desc_);
phi::dynload::cudnnCreateTensorDescriptor(&y_desc_);
phi::dynload::cudnnCreateTensorDescriptor(&b_desc_);
}
~PIRInstanceNormPlugin() {
phi::dynload::cudnnDestroy(handle_);
phi::dynload::cudnnDestroyTensorDescriptor(x_desc_);
phi::dynload::cudnnDestroyTensorDescriptor(y_desc_);
phi::dynload::cudnnDestroyTensorDescriptor(b_desc_);
}
int initialize() TRT_NOEXCEPT override;
nvinfer1::IPluginV2DynamicExt *clone() const TRT_NOEXCEPT override {
return new PIRInstanceNormPlugin(eps_);
}
const char *getPluginType() const TRT_NOEXCEPT override {
return "pir_instance_norm";
}
int getNbOutputs() const TRT_NOEXCEPT override { return 1; }
nvinfer1::DimsExprs getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs *inputs,
int nb_inputs,
nvinfer1::IExprBuilder &expr_builder) // NOLINT
TRT_NOEXCEPT override;
bool supportsFormatCombination(int pos,
const nvinfer1::PluginTensorDesc *inOut,
int nbInputs,
int nbOutputs) TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::DynamicPluginTensorDesc *in,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc *out,
int nbOutputs) TRT_NOEXCEPT override;
size_t getWorkspaceSize(const nvinfer1::PluginTensorDesc *inputs,
int nbInputs,
const nvinfer1::PluginTensorDesc *outputs,
int nbOutputs) const TRT_NOEXCEPT override {
return 0;
}
int enqueue(const nvinfer1::PluginTensorDesc *inputDesc,
const nvinfer1::PluginTensorDesc *outputDesc,
const void *const *inputs,
void *const *outputs,
void *workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType *inputTypes,
int nbInputs) const
TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override { delete this; }
};
class PIRInstanceNormPluginCreator : public TensorRTPluginCreator {
public:
const char *getPluginName() const TRT_NOEXCEPT override {
return "pir_instance_norm";
}
const char *getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
nvinfer1::IPluginV2 *createPlugin(const char *name,
const nvinfer1::PluginFieldCollection *fc)
TRT_NOEXCEPT override;
nvinfer1::IPluginV2 *deserializePlugin(const char *name,
const void *serial_data,
size_t serial_length)
TRT_NOEXCEPT override {
return new PIRInstanceNormPlugin(serial_data, serial_length);
}
};
REGISTER_TRT_PLUGIN_V2(InstanceNormPluginCreator);
REGISTER_TRT_PLUGIN_V2(InstanceNormPluginDynamicCreator);
REGISTER_TRT_PLUGIN_V2(PIRInstanceNormPluginCreator);
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,371 @@
// Copyright (c) 2018 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 <stdio.h>
#include <cassert>
#include <vector>
#include "glog/logging.h"
#include "paddle/fluid/inference/tensorrt/plugin/layer_norm_op_plugin.h"
#include "paddle/phi/kernels/layer_norm_kernel.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
int LayerNormPlugin::initialize() TRT_NOEXCEPT {
cudaMalloc(&bias_gpu_, sizeof(float) * bias_.size());
cudaMemcpy(bias_gpu_,
bias_.data(),
bias_.size() * sizeof(float),
cudaMemcpyHostToDevice);
cudaMalloc(&scale_gpu_, sizeof(float) * scale_.size());
cudaMemcpy(scale_gpu_,
scale_.data(),
scale_.size() * sizeof(float),
cudaMemcpyHostToDevice);
return 0;
}
void LayerNormPlugin::terminate() TRT_NOEXCEPT {
if (bias_gpu_) {
cudaFree(bias_gpu_);
bias_gpu_ = nullptr;
}
if (scale_gpu_) {
cudaFree(scale_gpu_);
scale_gpu_ = nullptr;
}
}
nvinfer1::Dims LayerNormPlugin::getOutputDimensions(
int index, const nvinfer1::Dims *inputDims, int nbInputs) TRT_NOEXCEPT {
assert(nbInputs == 1);
assert(index < this->getNbOutputs());
nvinfer1::Dims const &input_dims = inputDims[0];
nvinfer1::Dims output_dims = input_dims;
return output_dims;
}
bool LayerNormPlugin::supportsFormat(
nvinfer1::DataType type, nvinfer1::PluginFormat format) const TRT_NOEXCEPT {
if (with_fp16_) {
return ((type == nvinfer1::DataType::kFLOAT ||
type == nvinfer1::DataType::kHALF) &&
(format == nvinfer1::PluginFormat::kLINEAR));
} else {
return ((type == nvinfer1::DataType::kFLOAT) &&
(format == nvinfer1::PluginFormat::kLINEAR));
}
}
int LayerNormPlugin::enqueue(int batch_size,
const void *const *inputs,
void *const *outputs,
void *workspace,
cudaStream_t stream) TRT_NOEXCEPT {
const auto &input_dims = this->getInputDims(0);
int begin_norm_axis = begin_norm_axis_;
float eps = eps_;
PADDLE_ENFORCE_EQ(1,
mean_shape_.size(),
common::errors::InvalidArgument(
"Size of mean_shape vector should be equal to 1,"
"but got Size of mean_shape vector:%d",
mean_shape_.size()));
PADDLE_ENFORCE_EQ(1,
variance_shape_.size(),
common::errors::InvalidArgument(
"Size of variance_shape vector should be equal to 1,"
"but got Size of mean_shape vector:%d",
mean_shape_.size()));
int64_t batched_mean_shape = mean_shape_[0] * input_dims.d[0];
int64_t batched_variance_shape = variance_shape_[0] * input_dims.d[0];
std::vector<int64_t> input_shape;
input_shape.push_back(batch_size);
for (int i = 0; i < input_dims.nbDims; i++) {
input_shape.push_back(input_dims.d[i]);
}
const auto input_ddim = common::make_ddim(input_shape);
auto matrix_dim = common::flatten_to_2d(input_ddim, begin_norm_axis);
int feature_size = static_cast<int>(matrix_dim[1]);
PADDLE_ENFORCE_EQ(feature_size,
scale_.size(),
common::errors::InvalidArgument(
"scale's size should be equal to the feature_size,"
"but got feature_size:%d, scale's size:%d.",
feature_size,
scale_.size()));
PADDLE_ENFORCE_EQ(feature_size,
bias_.size(),
common::errors::InvalidArgument(
"bias's size should be equal to the feature_size,"
"but got feature_size:%d, bias's size:%d.",
feature_size,
bias_.size()));
int device_id;
cudaGetDevice(&device_id);
mean_t.Resize(common::make_ddim({batched_mean_shape}));
variance_t.Resize(common::make_ddim({batched_variance_shape}));
float *mean_d = mean_t.mutable_data<float>(GPUPlace(device_id));
float *variance_d = variance_t.mutable_data<float>(GPUPlace(device_id));
auto input_type = getDataType();
if (input_type == nvinfer1::DataType::kFLOAT) {
VLOG(1) << "TRT Plugin DataType selected. LayerNorm-->fp32";
const float *input = reinterpret_cast<const float *>(inputs[0]);
float *output = static_cast<float *>(outputs[0]);
phi::LayerNormDirectCUDAFunctor<float, float> layer_norm;
layer_norm(stream,
input,
input_shape,
bias_gpu_,
scale_gpu_,
output,
mean_d,
variance_d,
begin_norm_axis,
eps);
} else if (input_type == nvinfer1::DataType::kHALF) {
VLOG(1) << "TRT Plugin DataType selected. LayerNorm-->fp16";
const half *input = reinterpret_cast<const half *>(inputs[0]);
half *output = static_cast<half *>(outputs[0]);
phi::LayerNormDirectCUDAFunctor<half, float> layer_norm;
layer_norm(stream,
input,
input_shape,
bias_gpu_,
scale_gpu_,
output,
mean_d,
variance_d,
begin_norm_axis,
eps);
} else {
PADDLE_THROW(common::errors::Fatal(
"The LayerNorm TRT Plugin's input type should be float or half."));
}
return cudaGetLastError() != cudaSuccess;
}
int LayerNormPluginDynamic::initialize() TRT_NOEXCEPT {
cudaMalloc(&bias_gpu_, sizeof(float) * bias_.size());
cudaMemcpy(bias_gpu_,
bias_.data(),
bias_.size() * sizeof(float),
cudaMemcpyHostToDevice);
cudaMalloc(&scale_gpu_, sizeof(float) * scale_.size());
cudaMemcpy(scale_gpu_,
scale_.data(),
scale_.size() * sizeof(float),
cudaMemcpyHostToDevice);
return 0;
}
void LayerNormPluginDynamic::terminate() TRT_NOEXCEPT {
if (bias_gpu_) {
cudaFree(bias_gpu_);
bias_gpu_ = nullptr;
}
if (scale_gpu_) {
cudaFree(scale_gpu_);
scale_gpu_ = nullptr;
}
}
nvinfer1::DimsExprs LayerNormPluginDynamic::getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs *inputDims,
int nb_inputs,
nvinfer1::IExprBuilder &expr_builder) TRT_NOEXCEPT {
return inputDims[0];
}
bool LayerNormPluginDynamic::supportsFormatCombination(
int pos,
const nvinfer1::PluginTensorDesc *in_out,
int nb_inputs,
int nb_outputs) TRT_NOEXCEPT {
PADDLE_ENFORCE_NOT_NULL(
in_out,
common::errors::InvalidArgument(
"The input of layernorm plugin should not be nullptr."));
PADDLE_ENFORCE_LT(
pos,
nb_inputs + nb_outputs,
common::errors::InvalidArgument("The pos(%d) should be less than the "
"num(%d) of the input and the output.",
pos,
nb_inputs + nb_outputs));
const nvinfer1::PluginTensorDesc &in = in_out[pos];
if (pos == 0) {
if (with_fp16_) {
return ((in.type == nvinfer1::DataType::kFLOAT ||
in.type == nvinfer1::DataType::kHALF) &&
(in.format == nvinfer1::PluginFormat::kLINEAR));
} else {
return (in.type == nvinfer1::DataType::kFLOAT) &&
(in.format == nvinfer1::TensorFormat::kLINEAR);
}
}
const nvinfer1::PluginTensorDesc &prev = in_out[pos - 1];
// output
return in.type == prev.type && in.format == prev.format;
}
void LayerNormPluginDynamic::configurePlugin(
const nvinfer1::DynamicPluginTensorDesc *in,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc *out,
int nbOutputs) TRT_NOEXCEPT {
const auto &input_dims = in[0].desc.dims;
int statis_num = 1;
for (int i = 0; i < begin_norm_axis_; i++) {
statis_num *= input_dims.d[i];
}
mean_shape_[0] = statis_num;
variance_shape_[0] = statis_num;
}
nvinfer1::DataType LayerNormPluginDynamic::getOutputDataType(
int index,
const nvinfer1::DataType *input_types,
int nb_inputs) const TRT_NOEXCEPT {
PADDLE_ENFORCE_EQ(index,
0,
common::errors::InvalidArgument(
"The LayerNormPlugin only has one input, so the "
"index value should be 0, but get %d.",
index));
PADDLE_ENFORCE_EQ((input_types[0] == nvinfer1::DataType::kFLOAT ||
input_types[0] == nvinfer1::DataType::kHALF),
true,
common::errors::InvalidArgument(
"The input type should be half or float"));
return input_types[0];
}
int LayerNormPluginDynamic::enqueue(
const nvinfer1::PluginTensorDesc *input_desc,
const nvinfer1::PluginTensorDesc *output_desc,
const void *const *inputs,
void *const *outputs,
void *workspace,
cudaStream_t stream) TRT_NOEXCEPT {
const auto &input_dims = input_desc[0].dims;
int begin_norm_axis = begin_norm_axis_;
float eps = eps_;
std::vector<int64_t> input_shape;
for (int i = 0; i < input_dims.nbDims; i++) {
input_shape.push_back(input_dims.d[i]);
}
// in dynamic shape
// the batch num should be involved in mean/variance shape
PADDLE_ENFORCE_EQ(1,
mean_shape_.size(),
common::errors::InvalidArgument(
"Size of mean_shape vector should be equal to 1,"
"but got Size of mean_shape vector:%d",
mean_shape_.size()));
PADDLE_ENFORCE_EQ(1,
variance_shape_.size(),
common::errors::InvalidArgument(
"Size of variance_shape vector should be equal to 1,"
"but got Size of mean_shape vector:%d",
mean_shape_.size()));
PADDLE_ENFORCE_GE(mean_shape_[0],
0,
common::errors::InvalidArgument(
"The size of mean vector should be positive,"
"but got:%d",
mean_shape_[0]));
PADDLE_ENFORCE_GE(variance_shape_[0],
0,
common::errors::InvalidArgument(
"The size of mean vector should be positive,"
"but got:%d",
variance_shape_[0]));
const auto input_ddim = common::make_ddim(input_shape);
auto matrix_dim = common::flatten_to_2d(input_ddim, begin_norm_axis);
int feature_size = static_cast<int>(matrix_dim[1]);
PADDLE_ENFORCE_EQ(feature_size,
scale_.size(),
common::errors::InvalidArgument(
"scale's size should be equal to the feature_size,"
"but got feature_size:%d, scale's size:%d.",
feature_size,
scale_.size()));
PADDLE_ENFORCE_EQ(feature_size,
bias_.size(),
common::errors::InvalidArgument(
"bias's size should be equal to the feature_size,"
"but got feature_size:%d, bias's size:%d.",
feature_size,
bias_.size()));
int device_id;
cudaGetDevice(&device_id);
mean_t.Resize(common::make_ddim(mean_shape_));
variance_t.Resize(common::make_ddim(variance_shape_));
float *mean_d = mean_t.mutable_data<float>(GPUPlace(device_id));
float *variance_d = variance_t.mutable_data<float>(GPUPlace(device_id));
auto input_type = input_desc[0].type;
if (input_type == nvinfer1::DataType::kFLOAT) {
VLOG(1) << "TRT Plugin DataType selected. LayerNorm-->fp32";
const float *input = reinterpret_cast<const float *>(inputs[0]);
float *output = static_cast<float *>(outputs[0]);
phi::LayerNormDirectCUDAFunctor<float, float> layer_norm;
layer_norm(stream,
input,
input_shape,
bias_gpu_,
scale_gpu_,
output,
mean_d,
variance_d,
begin_norm_axis,
eps);
} else if (input_type == nvinfer1::DataType::kHALF) {
VLOG(1) << "TRT Plugin DataType selected. LayerNorm-->fp16";
const half *input = reinterpret_cast<const half *>(inputs[0]);
half *output = static_cast<half *>(outputs[0]);
phi::LayerNormDirectCUDAFunctor<half, float> layer_norm;
layer_norm(stream,
input,
input_shape,
bias_gpu_,
scale_gpu_,
output,
mean_d,
variance_d,
begin_norm_axis,
eps);
} else {
PADDLE_THROW(common::errors::Fatal(
"The LayerNorm TRT Plugin's input type should be float or half."));
}
return cudaGetLastError() != cudaSuccess;
}
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,294 @@
// Copyright (c) 2018 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.
#pragma once
#include <algorithm>
#include <string>
#include <vector>
#include "paddle/fluid/framework/tensor.h"
#include "paddle/fluid/framework/tensor_util.h"
#include "paddle/fluid/inference/tensorrt/engine.h"
#include "paddle/fluid/inference/tensorrt/plugin/trt_plugin.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
class LayerNormPlugin : public PluginTensorRT {
std::vector<float> bias_;
std::vector<float> scale_;
phi::DenseTensor mean_t;
phi::DenseTensor variance_t;
int begin_norm_axis_;
float eps_;
std::vector<int64_t> mean_shape_;
std::vector<int64_t> variance_shape_;
// data on devices
float* bias_gpu_{nullptr};
float* scale_gpu_{nullptr};
public:
size_t getSerializationSize() const TRT_NOEXCEPT override {
return getBaseSerializationSize() + SerializedSize(bias_) +
SerializedSize(scale_) + SerializedSize(begin_norm_axis_) +
SerializedSize(eps_) + SerializedSize(mean_shape_) +
SerializedSize(variance_shape_) + SerializedSize(with_fp16_);
}
// TRT will call this func when we need to serialize the configuration of
// tensorrt.
// It should not be called by users.
void serialize(void* buffer) const TRT_NOEXCEPT override {
serializeBase(buffer);
SerializeValue(&buffer, bias_);
SerializeValue(&buffer, scale_);
SerializeValue(&buffer, begin_norm_axis_);
SerializeValue(&buffer, eps_);
SerializeValue(&buffer, mean_shape_);
SerializeValue(&buffer, variance_shape_);
SerializeValue(&buffer, with_fp16_);
}
LayerNormPlugin(const float* bias,
const int bias_num,
const float* scale,
const int scale_num,
int begin_norm_axis,
float eps,
std::vector<int64_t> mean_shape,
std::vector<int64_t> variance_shape,
bool with_fp16)
: begin_norm_axis_(begin_norm_axis),
eps_(eps),
mean_shape_(mean_shape),
variance_shape_(variance_shape) {
with_fp16_ = with_fp16;
bias_.resize(bias_num);
scale_.resize(scale_num);
std::copy(bias, bias + bias_num, bias_.data());
std::copy(scale, scale + scale_num, scale_.data());
}
// It was used for tensorrt deserialization.
// It should not be called by users.
LayerNormPlugin(void const* serialData, size_t serialLength) {
deserializeBase(serialData, serialLength);
DeserializeValue(&serialData, &serialLength, &bias_);
DeserializeValue(&serialData, &serialLength, &scale_);
DeserializeValue(&serialData, &serialLength, &begin_norm_axis_);
DeserializeValue(&serialData, &serialLength, &eps_);
DeserializeValue(&serialData, &serialLength, &mean_shape_);
DeserializeValue(&serialData, &serialLength, &variance_shape_);
DeserializeValue(&serialData, &serialLength, &with_fp16_);
}
~LayerNormPlugin() {}
int initialize() TRT_NOEXCEPT override;
void terminate() TRT_NOEXCEPT override;
LayerNormPlugin* clone() const TRT_NOEXCEPT override {
auto ptr = new LayerNormPlugin(bias_.data(),
bias_.size(),
scale_.data(),
scale_.size(),
begin_norm_axis_,
eps_,
mean_shape_,
variance_shape_,
with_fp16_);
ptr->bias_gpu_ = bias_gpu_;
ptr->scale_gpu_ = scale_gpu_;
return ptr;
}
const char* getPluginType() const TRT_NOEXCEPT override {
return "layernorm_plugin";
}
bool supportsFormat(nvinfer1::DataType type, nvinfer1::PluginFormat format)
const TRT_NOEXCEPT override;
int getNbOutputs() const TRT_NOEXCEPT override { return 1; }
nvinfer1::Dims getOutputDimensions(int index,
const nvinfer1::Dims* inputs,
int nbInputDims) TRT_NOEXCEPT override;
int enqueue(int batchSize,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
};
class LayerNormPluginCreator : public TensorRTPluginCreator {
public:
const char* getPluginName() const TRT_NOEXCEPT override {
return "layernorm_plugin";
}
const char* getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
nvinfer1::IPluginV2* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override {
return new LayerNormPlugin(serial_data, serial_length);
}
};
REGISTER_TRT_PLUGIN_V2(LayerNormPluginCreator);
class LayerNormPluginDynamic : public DynamicPluginTensorRT {
public:
LayerNormPluginDynamic(const float* bias,
const int bias_num,
const float* scale,
const int scale_num,
int begin_norm_axis,
float eps,
std::vector<int64_t> mean_shape,
std::vector<int64_t> variance_shape,
bool with_fp16)
: begin_norm_axis_(begin_norm_axis),
eps_(eps),
mean_shape_(mean_shape),
variance_shape_(variance_shape) {
with_fp16_ = with_fp16;
bias_.resize(bias_num);
scale_.resize(scale_num);
std::copy(bias, bias + bias_num, bias_.data());
std::copy(scale, scale + scale_num, scale_.data());
}
LayerNormPluginDynamic(void const* serialData, size_t serialLength) {
DeserializeValue(&serialData, &serialLength, &bias_);
DeserializeValue(&serialData, &serialLength, &scale_);
DeserializeValue(&serialData, &serialLength, &begin_norm_axis_);
DeserializeValue(&serialData, &serialLength, &eps_);
DeserializeValue(&serialData, &serialLength, &mean_shape_);
DeserializeValue(&serialData, &serialLength, &variance_shape_);
DeserializeValue(&serialData, &serialLength, &with_fp16_);
}
nvinfer1::IPluginV2DynamicExt* clone() const TRT_NOEXCEPT override {
auto ptr = new LayerNormPluginDynamic(bias_.data(),
bias_.size(),
scale_.data(),
scale_.size(),
begin_norm_axis_,
eps_,
mean_shape_,
variance_shape_,
with_fp16_);
ptr->bias_gpu_ = bias_gpu_;
ptr->scale_gpu_ = scale_gpu_;
return ptr;
}
const char* getPluginType() const TRT_NOEXCEPT override {
return "layernorm_plugin_dynamic";
}
int getNbOutputs() const TRT_NOEXCEPT override { return 1; }
int initialize() TRT_NOEXCEPT override;
void terminate() TRT_NOEXCEPT override;
size_t getSerializationSize() const TRT_NOEXCEPT override {
return SerializedSize(bias_) + SerializedSize(scale_) +
SerializedSize(begin_norm_axis_) + SerializedSize(eps_) +
SerializedSize(mean_shape_) + SerializedSize(variance_shape_) +
SerializedSize(with_fp16_);
}
void serialize(void* buffer) const TRT_NOEXCEPT override {
SerializeValue(&buffer, bias_);
SerializeValue(&buffer, scale_);
SerializeValue(&buffer, begin_norm_axis_);
SerializeValue(&buffer, eps_);
SerializeValue(&buffer, mean_shape_);
SerializeValue(&buffer, variance_shape_);
SerializeValue(&buffer, with_fp16_);
}
nvinfer1::DimsExprs getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs* inputs,
int nb_inputs,
nvinfer1::IExprBuilder& expr_builder) // NOLINT
TRT_NOEXCEPT override;
bool supportsFormatCombination(int pos,
const nvinfer1::PluginTensorDesc* inOut,
int nbInputs,
int nbOutputs) TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::DynamicPluginTensorDesc* in,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc* out,
int nbOutputs) TRT_NOEXCEPT override;
size_t getWorkspaceSize(const nvinfer1::PluginTensorDesc* inputs,
int nbInputs,
const nvinfer1::PluginTensorDesc* outputs,
int nbOutputs) const TRT_NOEXCEPT override {
return 0;
}
int enqueue(const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* inputTypes,
int nbInputs) const
TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override { delete this; }
private:
std::vector<float> bias_;
std::vector<float> scale_;
phi::DenseTensor mean_t;
phi::DenseTensor variance_t;
int begin_norm_axis_;
float eps_;
std::vector<int64_t> mean_shape_;
std::vector<int64_t> variance_shape_;
// data on devices
float* bias_gpu_{nullptr};
float* scale_gpu_{nullptr};
};
class LayerNormPluginDynamicCreator : public TensorRTPluginCreator {
public:
const char* getPluginName() const TRT_NOEXCEPT override {
return "layernorm_plugin_dynamic";
}
const char* getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
nvinfer1::IPluginV2* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override {
return new LayerNormPluginDynamic(serial_data, serial_length);
}
};
REGISTER_TRT_PLUGIN_V2(LayerNormPluginDynamicCreator);
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,685 @@
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
// Copyright (c) 2019-2022, NVIDIA CORPORATION. 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 <stdio.h>
#include <cassert>
#include <vector>
#include "glog/logging.h"
#include "paddle/fluid/inference/tensorrt/plugin/layernorm_shift_partition_op.h"
#include "paddle/phi/kernels/layer_norm_kernel.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
#define FINAL_MASK 0xffffffff
template <typename T>
__inline__ __device__ T warpReduceSum(T val) {
#pragma unroll
for (int mask = 16; mask > 0; mask >>= 1)
val += __shfl_xor_sync(FINAL_MASK, val, mask, 32);
return val;
}
/* Calculate the sum of all elements in a block */
template <typename T>
__inline__ __device__ T blockReduceSum(T val) {
static __shared__ T shared[32];
int lane = threadIdx.x & 0x1f;
int wid = threadIdx.x >> 5;
val = warpReduceSum<T>(val);
if (lane == 0) shared[wid] = val;
__syncthreads();
// Modify from blockDim.x << 5 to blockDim.x / 32. to prevent
// blockDim.x is not divided by 32
val = (threadIdx.x < (blockDim.x / 32.f)) ? shared[lane] : (T)(0.0f);
val = warpReduceSum<T>(val);
return val;
}
template <typename T>
__global__ void layernorm_shift_partition(T *out,
const T *input,
const T *gamma,
const T *beta,
int batch,
int H,
int W,
int n,
int shift_size,
int window_size,
const float eps) {
int tid = threadIdx.x;
const int batch_offset = blockIdx.z * gridDim.y * gridDim.x;
const int bid = batch_offset + blockIdx.y * gridDim.x + blockIdx.x;
const int shifted_H_idx =
(shift_size != 0) ? ((blockIdx.y - shift_size + gridDim.y) % gridDim.y)
: blockIdx.y;
const int shifted_W_idx =
(shift_size != 0) ? ((blockIdx.x - shift_size + gridDim.x) % gridDim.x)
: blockIdx.x;
const int window_H_idx = shifted_H_idx / window_size;
const int window_W_idx = shifted_W_idx / window_size;
const int stride_of_window_H = W / window_size;
const int window_idx = window_H_idx * stride_of_window_H + window_W_idx;
const int idx_in_window = (shifted_H_idx % window_size) * window_size +
(shifted_W_idx % window_size);
const int output_bid =
batch_offset + window_idx * window_size * window_size + idx_in_window;
__shared__ float s_mean;
__shared__ float s_variance;
float mean = 0.0f;
float variance = 0.0f;
#if CUDA_ARCH_FP16_SUPPORTED(__CUDA_ARCH__)
float local_out =
(tid < n) ? static_cast<float>(__ldg(input + bid * n + tid)) : 0.0f;
#else
float local_out = (tid < n) ? static_cast<float>(input[bid * n + tid]) : 0.0f;
#endif
mean = blockReduceSum<float>(local_out);
if (threadIdx.x == 0) {
s_mean = mean / n;
}
__syncthreads();
float diff = (tid < n) ? (local_out - s_mean) : 0.0f;
variance = blockReduceSum<float>(diff * diff);
if (threadIdx.x == 0) {
s_variance = variance / n + eps;
}
__syncthreads();
if (tid < n) {
#if CUDA_ARCH_FP16_SUPPORTED(__CUDA_ARCH__)
out[output_bid * n + tid] =
(T)(((local_out - s_mean) * rsqrtf(s_variance)) *
static_cast<float>(__ldg(&gamma[tid])) +
static_cast<float>(__ldg(&beta[tid])));
#else
out[output_bid * n + tid] =
(T)(((local_out - s_mean) * rsqrtf(s_variance)) *
static_cast<float>(gamma[tid]) +
static_cast<float>(beta[tid]));
#endif
}
}
template <>
__global__ void layernorm_shift_partition(half2 *out_ptr,
const half2 *input_ptr,
const half2 *gamma_ptr,
const half2 *beta_ptr,
int batch,
int H,
int W,
int n,
int shift_size,
int window_size,
const float eps) {
#if CUDA_ARCH_FP16_SUPPORTED(__CUDA_ARCH__)
const int batch_offset = blockIdx.z * gridDim.y * gridDim.x;
const int bid = batch_offset + blockIdx.y * gridDim.x + blockIdx.x;
const int shifted_H_idx =
(shift_size != 0) ? ((blockIdx.y - shift_size + gridDim.y) % gridDim.y)
: blockIdx.y;
const int shifted_W_idx =
(shift_size != 0) ? ((blockIdx.x - shift_size + gridDim.x) % gridDim.x)
: blockIdx.x;
const int window_H_idx = shifted_H_idx / window_size;
const int window_W_idx = shifted_W_idx / window_size;
const int stride_of_window_H = W / window_size;
const int window_idx = window_H_idx * stride_of_window_H + window_W_idx;
const int idx_in_window = (shifted_H_idx % window_size) * window_size +
(shifted_W_idx % window_size);
const int output_bid =
batch_offset + window_idx * window_size * window_size + idx_in_window;
int tid = threadIdx.x;
__shared__ float s_mean;
__shared__ float s_variance;
float mean = 0.0f;
float variance = 0.0f;
float2 local_out_fp2;
float local_out = 0.0f;
int id = bid * n + tid;
if (tid < n) {
local_out_fp2 = __half22float2(__ldg(input_ptr + id));
local_out += local_out_fp2.x;
local_out += local_out_fp2.y;
}
mean = blockReduceSum<float>(local_out);
if (threadIdx.x == 0) {
s_mean = mean / (n * 2);
}
__syncthreads();
if (tid < n) {
variance = (local_out_fp2.x - s_mean) * (local_out_fp2.x - s_mean);
variance += (local_out_fp2.y - s_mean) * (local_out_fp2.y - s_mean);
}
variance = blockReduceSum<float>(variance);
if (threadIdx.x == 0) {
s_variance = rsqrtf(variance / (n * 2) + eps);
}
__syncthreads();
if (tid < n) {
float2 gamma_val = __half22float2(__ldg(&gamma_ptr[tid]));
float2 beta_val = __half22float2(__ldg(&beta_ptr[tid]));
local_out_fp2.x =
(local_out_fp2.x - s_mean) * s_variance * gamma_val.x + beta_val.x;
local_out_fp2.y =
(local_out_fp2.y - s_mean) * s_variance * gamma_val.y + beta_val.y;
out_ptr[output_bid * n + tid] = __float22half2_rn(local_out_fp2);
}
#endif
}
#define kITE 4
template <typename T>
__global__ void layernorm_shift_partition_v2(T *out,
const T *__restrict input,
const T *__restrict gamma,
const T *__restrict beta,
int batch,
int H,
int W,
int n,
int shift_size,
int window_size,
const float eps) {
// constexpr int kITE = 4;
const int tid = threadIdx.x;
const int batch_offset = blockIdx.z * gridDim.y * gridDim.x;
const int bid = batch_offset + blockIdx.y * gridDim.x + blockIdx.x;
const int shifted_H_idx =
(shift_size != 0) ? ((blockIdx.y - shift_size + gridDim.y) % gridDim.y)
: blockIdx.y;
const int shifted_W_idx =
(shift_size != 0) ? ((blockIdx.x - shift_size + gridDim.x) % gridDim.x)
: blockIdx.x;
const int window_H_idx = shifted_H_idx / window_size;
const int window_W_idx = shifted_W_idx / window_size;
const int stride_of_window_H = W / window_size;
const int window_idx = window_H_idx * stride_of_window_H + window_W_idx;
const int idx_in_window = (shifted_H_idx % window_size) * window_size +
(shifted_W_idx % window_size);
const int output_bid =
batch_offset + window_idx * window_size * window_size + idx_in_window;
const int offset = bid * n;
const int output_offset = output_bid * n;
__shared__ float s_mean;
__shared__ float s_variance;
float mean = 0.0f;
float variance = 0.0f;
float local_out[kITE];
float sum = 0.0f;
#pragma unroll
for (int i = 0; i < kITE; i++) {
int col_id = i * blockDim.x + tid;
if (col_id < n) {
#if CUDA_ARCH_FP16_SUPPORTED(__CUDA_ARCH__)
local_out[i] = static_cast<float>(__ldg(input + offset + col_id));
#else
local_out[i] = static_cast<float>(input[offset + col_id]);
#endif
sum += local_out[i];
}
}
mean = blockReduceSum<float>(sum);
if (tid == 0) {
s_mean = mean / n;
}
__syncthreads();
float var = 0.0f;
#pragma unroll
for (int i = 0; i < kITE; i++) {
int col_id = i * blockDim.x + tid;
if (col_id < n) {
float diff = local_out[i] - s_mean;
local_out[i] = diff;
var += diff * diff;
}
}
variance = blockReduceSum<float>(var);
if (tid == 0) {
s_variance = rsqrtf(variance / n + eps);
}
__syncthreads();
#pragma unroll
for (int i = 0; i < kITE; i++) {
int col_id = i * blockDim.x + tid;
if (col_id < n) {
#if CUDA_ARCH_FP16_SUPPORTED(__CUDA_ARCH__)
out[output_offset + col_id] =
(T)(local_out[i] * s_variance *
static_cast<float>(__ldg(&gamma[col_id])) +
static_cast<float>(__ldg(&beta[col_id])));
#else
out[output_offset + col_id] =
(T)(local_out[i] * s_variance * static_cast<float>(gamma[col_id]) +
static_cast<float>(beta[col_id]));
#endif
}
}
}
template <>
__global__ void layernorm_shift_partition_v2(half2 *out_ptr,
const half2 *__restrict input_ptr,
const half2 *__restrict gamma_ptr,
const half2 *__restrict beta_ptr,
int batch,
int H,
int W,
int n,
int shift_size,
int window_size,
const float eps) {
#if CUDA_ARCH_FP16_SUPPORTED(__CUDA_ARCH__)
// constexpr int ite = 4;
const int tid = threadIdx.x;
const int batch_offset = blockIdx.z * gridDim.y * gridDim.x;
const int bid = batch_offset + blockIdx.y * gridDim.x + blockIdx.x;
const int shifted_H_idx =
(shift_size != 0) ? ((blockIdx.y - shift_size + gridDim.y) % gridDim.y)
: blockIdx.y;
const int shifted_W_idx =
(shift_size != 0) ? ((blockIdx.x - shift_size + gridDim.x) % gridDim.x)
: blockIdx.x;
const int window_H_idx = shifted_H_idx / window_size;
const int window_W_idx = shifted_W_idx / window_size;
const int stride_of_window_H = W / window_size;
const int window_idx = window_H_idx * stride_of_window_H + window_W_idx;
const int idx_in_window = (shifted_H_idx % window_size) * window_size +
(shifted_W_idx % window_size);
const int output_bid =
batch_offset + window_idx * window_size * window_size + idx_in_window;
const int offset = bid * n;
const int output_offset = output_bid * n;
__shared__ float s_mean;
__shared__ float s_variance;
float mean = 0.0f;
float variance = 0.0f;
half2 local_out_half2[kITE];
const half2 zero = {static_cast<half>(0.0f), static_cast<half>(0.0f)};
// float sum = 0.0f;
half2 sum = __float2half2_rn(0.0f);
#pragma unroll
for (int i = 0; i < kITE; i++) {
int col_id = i * blockDim.x + tid;
if (col_id < n) {
local_out_half2[i] = __ldg(input_ptr + offset + col_id);
sum += local_out_half2[i];
}
}
mean = blockReduceSum<float>(static_cast<float>(sum.x + sum.y));
if (threadIdx.x == 0) {
s_mean = mean / (n * 2);
}
__syncthreads();
float var = 0.0f;
half2 s_mean_2 = __float2half2_rn(s_mean);
#pragma unroll
for (int i = 0; i < kITE; i++) {
int col_id = i * blockDim.x + tid;
if (col_id < n) {
local_out_half2[i] = local_out_half2[i] - s_mean_2;
float v1 = static_cast<float>(local_out_half2[i].x);
float v2 = static_cast<float>(local_out_half2[i].y);
var += v1 * v1 + v2 * v2;
}
}
variance = blockReduceSum<float>(var);
if (threadIdx.x == 0) {
s_variance = rsqrtf(variance / (n * 2) + eps);
}
__syncthreads();
half2 s_var_2 = __float2half2_rn(s_variance);
#pragma unroll
for (int i = 0; i < kITE; i++) {
int col_id = i * blockDim.x + tid;
if (col_id < n) {
out_ptr[output_offset + col_id] =
local_out_half2[i] * s_var_2 * __ldg(&gamma_ptr[col_id]) +
__ldg(&beta_ptr[col_id]);
}
}
#endif
}
template <typename T>
void invokeLayernormShiftPartition(T *out,
const T *input,
const T *gamma,
const T *beta,
int batch,
int H,
int W,
int n,
int shift_size,
int window_size,
const float eps,
cudaStream_t stream) {
dim3 grid(W, H, batch);
int blockSize = (n + 31) / 32 * 32;
if (blockSize >= 768) {
blockSize = ((blockSize / 4) + 31) / 32 * 32;
layernorm_shift_partition_v2<T><<<grid, blockSize, 0, stream>>>(
out, input, gamma, beta, batch, H, W, n, shift_size, window_size, eps);
} else {
layernorm_shift_partition<T><<<grid, blockSize, 0, stream>>>(
out, input, gamma, beta, batch, H, W, n, shift_size, window_size, eps);
}
}
template <>
void invokeLayernormShiftPartition(half *out,
const half *input,
const half *gamma,
const half *beta,
int batch,
int H,
int W,
int n,
int shift_size,
int window_size,
const float eps,
cudaStream_t stream) {
dim3 grid(W, H, batch);
int blockSize = n / 2;
blockSize = (blockSize + 31) / 32 * 32;
if ((batch * H * W >= 512 && blockSize >= 768) || blockSize > 1024) {
blockSize = ((blockSize / 4) + 31) / 32 * 32;
layernorm_shift_partition_v2<<<grid, blockSize, 0, stream>>>(
reinterpret_cast<half2 *>(out),
(const half2 *)input,
(const half2 *)gamma,
(const half2 *)beta,
batch,
H,
W,
n / 2,
shift_size,
window_size,
eps);
} else {
layernorm_shift_partition<<<grid, blockSize, 0, stream>>>(
reinterpret_cast<half2 *>(out),
(const half2 *)input,
(const half2 *)gamma,
(const half2 *)beta,
batch,
H,
W,
n / 2,
shift_size,
window_size,
eps);
}
}
template <typename T>
static void convertAndCopy(const std::vector<float> &host, T *dev) {
T *host_ptr = new T[host.size()];
std::transform(host.begin(), host.end(), host_ptr, [](float x) {
return static_cast<T>(x);
});
cudaMemcpy(dev, host_ptr, sizeof(T) * host.size(), cudaMemcpyHostToDevice);
delete host_ptr;
}
void LayernormShiftPartitionPluginDynamic::configurePlugin(
const nvinfer1::DynamicPluginTensorDesc *in,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc *out,
int nbOutputs) TRT_NOEXCEPT {}
LayernormShiftPartitionPluginDynamic::LayernormShiftPartitionPluginDynamic(
const float *gamma,
const float *beta,
const int param_num,
int shift_size,
int window_size,
int input_resolution,
float eps,
bool with_fp16,
std::shared_ptr<void> gamma_dev,
std::shared_ptr<void> beta_dev)
: with_fp16_(with_fp16),
window_size_(window_size),
shift_size_(shift_size),
input_resolution_(input_resolution),
eps_(eps),
param_num_(param_num),
gamma_dev_(gamma_dev),
beta_dev_(beta_dev) {
beta_.resize(param_num);
gamma_.resize(param_num);
std::copy(gamma, gamma + param_num, gamma_.data());
std::copy(beta, beta + param_num, beta_.data());
int type_size = with_fp16 ? sizeof(half) : sizeof(float);
if (gamma_dev_ == nullptr) {
void *p;
cudaMalloc(reinterpret_cast<void **>(&p), param_num_ * type_size);
gamma_dev_.reset(p, [](void *ptr) { cudaFree(ptr); });
if (with_fp16)
convertAndCopy(gamma_, reinterpret_cast<half *>(p));
else
convertAndCopy(gamma_, reinterpret_cast<float *>(p));
}
if (beta_dev_ == nullptr) {
void *p;
cudaMalloc(reinterpret_cast<void **>(&p), param_num_ * type_size);
beta_dev_.reset(p, [](void *ptr) { cudaFree(ptr); });
if (with_fp16)
convertAndCopy(beta_, reinterpret_cast<half *>(p));
else
convertAndCopy(beta_, reinterpret_cast<float *>(p));
}
}
LayernormShiftPartitionPluginDynamic::LayernormShiftPartitionPluginDynamic(
void const *serialData, size_t serialLength) {
DeserializeValue(&serialData, &serialLength, &beta_);
DeserializeValue(&serialData, &serialLength, &gamma_);
DeserializeValue(&serialData, &serialLength, &param_num_);
DeserializeValue(&serialData, &serialLength, &with_fp16_);
DeserializeValue(&serialData, &serialLength, &shift_size_);
DeserializeValue(&serialData, &serialLength, &window_size_);
DeserializeValue(&serialData, &serialLength, &input_resolution_);
DeserializeValue(&serialData, &serialLength, &eps_);
int type_size = with_fp16_ ? sizeof(half) : sizeof(float);
{
void *p;
cudaMalloc(reinterpret_cast<void **>(&p), param_num_ * type_size);
gamma_dev_.reset(p, [](void *ptr) { cudaFree(ptr); });
if (with_fp16_)
convertAndCopy(gamma_, reinterpret_cast<half *>(p));
else
convertAndCopy(gamma_, reinterpret_cast<float *>(p));
}
{
void *p;
cudaMalloc(reinterpret_cast<void **>(&p), param_num_ * type_size);
beta_dev_.reset(p, [](void *ptr) { cudaFree(ptr); });
if (with_fp16_)
convertAndCopy(beta_, reinterpret_cast<half *>(p));
else
convertAndCopy(beta_, reinterpret_cast<float *>(p));
}
}
bool LayernormShiftPartitionPluginDynamic::supportsFormatCombination(
int pos,
const nvinfer1::PluginTensorDesc *in_out,
int nb_inputs,
int nb_outputs) TRT_NOEXCEPT {
PADDLE_ENFORCE_NOT_NULL(
in_out,
common::errors::InvalidArgument("The input of LayernormShiftPartition "
"plugin should not be nullptr."));
PADDLE_ENFORCE_LT(
pos,
nb_inputs + nb_outputs,
common::errors::InvalidArgument("The pos(%d) should be less than the "
"num(%d) of the input and the output.",
pos,
nb_inputs + nb_outputs));
const nvinfer1::PluginTensorDesc &in = in_out[pos];
if (pos == 0) {
if (with_fp16_) {
return in.type == nvinfer1::DataType::kHALF &&
in.format == nvinfer1::TensorFormat::kLINEAR;
} else {
return in.type == nvinfer1::DataType::kFLOAT &&
in.format == nvinfer1::TensorFormat::kLINEAR;
}
}
const nvinfer1::PluginTensorDesc &prev = in_out[pos - 1];
// output
return in.type == prev.type && in.format == prev.format;
}
nvinfer1::DataType LayernormShiftPartitionPluginDynamic::getOutputDataType(
int index,
const nvinfer1::DataType *input_types,
int nb_inputs) const TRT_NOEXCEPT {
PADDLE_ENFORCE_EQ(
index,
0,
common::errors::InvalidArgument(
"The LayernormShiftPartition only has one input, so the "
"index value should be 0, but get %d.",
index));
return input_types[0];
}
nvinfer1::DimsExprs LayernormShiftPartitionPluginDynamic::getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs *inputs,
int nb_inputs,
nvinfer1::IExprBuilder &expr_builder) TRT_NOEXCEPT {
PADDLE_ENFORCE_EQ(
output_index,
0,
common::errors::InvalidArgument(
"There is only one output of the LayernormShiftPartition, "
"so the index should be zero,"
"but it's (%d)",
output_index));
PADDLE_ENFORCE_EQ(
nb_inputs,
1,
common::errors::InvalidArgument(
"The Input of the LayernormShiftPartition should be 1, but we found "
"it has (%d) inputs",
nb_inputs));
nvinfer1::DimsExprs ret;
ret.nbDims = 3;
ret.d[0] = expr_builder.operation(
nvinfer1::DimensionOperation::kFLOOR_DIV,
*expr_builder.operation(nvinfer1::DimensionOperation::kPROD,
*inputs[0].d[0],
*inputs[0].d[1]),
*expr_builder.constant(window_size_ * window_size_));
ret.d[1] = expr_builder.constant(window_size_ * window_size_);
ret.d[2] = inputs[0].d[2];
return ret;
}
int LayernormShiftPartitionPluginDynamic::enqueue(
const nvinfer1::PluginTensorDesc *input_desc,
const nvinfer1::PluginTensorDesc *output_desc,
const void *const *inputs,
void *const *outputs,
void *workspace,
cudaStream_t stream) TRT_NOEXCEPT {
const auto &input_dims = input_desc[0].dims;
auto input_type = input_desc[0].type;
int batch = input_dims.d[0];
int emb_dim = input_dims.d[2];
PADDLE_ENFORCE_EQ(
input_resolution_ * input_resolution_,
input_dims.d[1],
common::errors::InvalidArgument(
"The LayernormShiftPartition's input_resolution is wrong (%d)",
input_dims.d[1]));
if (input_type == nvinfer1::DataType::kFLOAT) {
VLOG(3) << "TRT Plugin DataType selected. LayernormShiftPartition-->fp32";
invokeLayernormShiftPartition(
reinterpret_cast<float *>(outputs[0]),
reinterpret_cast<const float *>(inputs[0]),
reinterpret_cast<const float *>(gamma_dev_.get()),
reinterpret_cast<const float *>(beta_dev_.get()),
batch,
input_resolution_,
input_resolution_,
emb_dim,
shift_size_,
window_size_,
eps_,
stream);
} else if (input_type == nvinfer1::DataType::kHALF) {
VLOG(3) << "TRT Plugin DataType selected. LayernormShiftPartition-->half";
invokeLayernormShiftPartition(
reinterpret_cast<half *>(outputs[0]),
reinterpret_cast<const half *>(inputs[0]),
reinterpret_cast<const half *>(gamma_dev_.get()),
reinterpret_cast<const half *>(beta_dev_.get()),
batch,
input_resolution_,
input_resolution_,
emb_dim,
shift_size_,
window_size_,
eps_,
stream);
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"The LayerNorm TRT Plugin's input type should be float or half."));
}
return cudaGetLastError() != cudaSuccess;
}
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,157 @@
// Copyright (c) 2022 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.
#pragma once
#include <algorithm>
#include <string>
#include <vector>
#include "paddle/fluid/framework/tensor.h"
#include "paddle/fluid/framework/tensor_util.h"
#include "paddle/fluid/inference/tensorrt/engine.h"
#include "paddle/fluid/inference/tensorrt/plugin/trt_plugin.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
class LayernormShiftPartitionPluginDynamic : public DynamicPluginTensorRT {
public:
LayernormShiftPartitionPluginDynamic(
const float* gamma,
const float* beta,
const int param_num,
int shift_size,
int window_size,
int input_resolution,
float eps,
bool with_fp16,
std::shared_ptr<void> gamma_dev = nullptr,
std::shared_ptr<void> beta_dev = nullptr);
LayernormShiftPartitionPluginDynamic(void const* serialData,
size_t serialLength);
nvinfer1::IPluginV2DynamicExt* clone() const TRT_NOEXCEPT override {
return new LayernormShiftPartitionPluginDynamic(gamma_.data(),
beta_.data(),
beta_.size(),
shift_size_,
window_size_,
input_resolution_,
eps_,
with_fp16_,
gamma_dev_,
beta_dev_);
}
const char* getPluginType() const TRT_NOEXCEPT override {
return "layernorm_shift_partition_dynamic";
}
int getNbOutputs() const TRT_NOEXCEPT override { return 1; }
int initialize() TRT_NOEXCEPT override { return 0; }
size_t getSerializationSize() const TRT_NOEXCEPT override {
return SerializedSize(beta_) + SerializedSize(gamma_) +
SerializedSize(param_num_) + SerializedSize(with_fp16_) +
SerializedSize(shift_size_) + SerializedSize(window_size_) +
SerializedSize(input_resolution_) + SerializedSize(eps_);
}
void serialize(void* buffer) const TRT_NOEXCEPT override {
SerializeValue(&buffer, beta_);
SerializeValue(&buffer, gamma_);
SerializeValue(&buffer, param_num_);
SerializeValue(&buffer, with_fp16_);
SerializeValue(&buffer, shift_size_);
SerializeValue(&buffer, window_size_);
SerializeValue(&buffer, input_resolution_);
SerializeValue(&buffer, eps_);
}
nvinfer1::DimsExprs getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs* inputs,
int nb_inputs,
nvinfer1::IExprBuilder& expr_builder) // NOLINT
TRT_NOEXCEPT override;
bool supportsFormatCombination(int pos,
const nvinfer1::PluginTensorDesc* inOut,
int nbInputs,
int nbOutputs) TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::DynamicPluginTensorDesc* in,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc* out,
int nbOutputs) TRT_NOEXCEPT override;
size_t getWorkspaceSize(const nvinfer1::PluginTensorDesc* inputs,
int nbInputs,
const nvinfer1::PluginTensorDesc* outputs,
int nbOutputs) const TRT_NOEXCEPT override {
return 0;
}
int enqueue(const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* inputTypes,
int nbInputs) const
TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override { delete this; }
private:
bool with_fp16_;
std::vector<float> gamma_;
std::vector<float> beta_;
int window_size_;
int shift_size_;
int input_resolution_;
int param_num_;
float eps_;
std::shared_ptr<void> gamma_dev_;
std::shared_ptr<void> beta_dev_;
};
class LayernormShiftPartitionPluginDynamicCreator
: public TensorRTPluginCreator {
public:
const char* getPluginName() const TRT_NOEXCEPT override {
return "layernorm_shift_partition_dynamic";
}
const char* getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
nvinfer1::IPluginV2* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override {
return new LayernormShiftPartitionPluginDynamic(serial_data, serial_length);
}
};
REGISTER_TRT_PLUGIN_V2(LayernormShiftPartitionPluginDynamicCreator);
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,475 @@
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
// SPDX-FileCopyrightText: Copyright (c) 1993-2022 NVIDIA CORPORATION &
// AFFILIATES. 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 <cuda.h>
#include <cassert>
#include <cstring>
#include <iostream>
#include <vector>
#include "NvInfer.h"
#include "paddle/fluid/inference/tensorrt/plugin/common/common.cuh"
#include "paddle/fluid/inference/tensorrt/plugin/many_emb_layernorm_plugin.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
template <typename T, unsigned TPB>
__global__ void embLayerNormKernel_2(int32_t ld,
int32_t const* inputIds0,
int32_t const* inputIds1,
float const* beta,
float const* gamma,
T const* mIdsEmbDev0,
T const* mIdsEmbDev1,
int32_t IdsSize0,
int32_t IdsSize1,
T* output) {
T const rld = T(1.f) / T(ld);
cub::Sum pairSum;
int32_t const seqPos = blockIdx.y * gridDim.x + blockIdx.x;
extern __shared__ int32_t word_id[];
if (threadIdx.x == 0) {
if (static_cast<int32_t const*>(inputIds0)[seqPos] < 0 ||
static_cast<int32_t const*>(inputIds0)[seqPos] >= IdsSize0) {
printf(
"Error!!!!!!(embLayerNormVarPlugin): ID cannot be lookup "
"table: ID < 0 or ID > max ");
return;
} else {
word_id[0] = static_cast<int32_t const*>(inputIds0)[seqPos];
}
if (static_cast<int32_t const*>(inputIds1)[seqPos] < 0 ||
static_cast<int32_t const*>(inputIds1)[seqPos] >= IdsSize1) {
printf(
"Error!!!!!!(embLayerNormVarPlugin): ID cannot be lookup "
"table: ID < 0 or ID > max ");
return;
} else {
word_id[1] = static_cast<int32_t const*>(inputIds1)[seqPos];
}
}
__syncthreads();
// offset into embeddings is given by wordId * hidden_size
int32_t const outOffset = seqPos * ld;
// the output offset is given by b * (S*hidden_size) + s * hidden_size
kvp<T> threadData(0, 0);
for (int32_t it = threadIdx.x; it < ld; it += TPB) {
int32_t const offset0 = word_id[0] * ld;
T val = mIdsEmbDev0[offset0 + it];
int32_t const offset1 = word_id[1] * ld;
val += mIdsEmbDev1[offset1 + it];
output[outOffset + it] = val;
T const rldval = rld * val;
threadData = pairSum(threadData, kvp<T>(rldval, rldval * val));
}
// layer norm on the sum
layerNorm<T, T, float, TPB>(threadData, ld, outOffset, beta, gamma, output);
}
template <typename T, unsigned TPB>
__global__ void embLayerNormKernel_3(int32_t ld,
int32_t const* inputIds0,
int32_t const* inputIds1,
int32_t const* inputIds2,
float const* beta,
float const* gamma,
T const* mIdsEmbDev0,
T const* mIdsEmbDev1,
T const* mIdsEmbDev2,
int32_t IdsSize0,
int32_t IdsSize1,
int32_t IdsSize2,
T* output) {
T const rld = T(1.f) / T(ld);
cub::Sum pairSum;
int32_t const seqPos = blockIdx.y * gridDim.x + blockIdx.x;
extern __shared__ int32_t word_id[];
if (threadIdx.x == 0) {
if (static_cast<int32_t const*>(inputIds0)[seqPos] < 0 ||
static_cast<int32_t const*>(inputIds0)[seqPos] >= IdsSize0) {
printf(
"Error!!!!!!(embLayerNormVarPlugin): ID cannot be lookup "
"table: ID < 0 or ID > max ");
return;
} else {
word_id[0] = static_cast<int32_t const*>(inputIds0)[seqPos];
}
if (static_cast<int32_t const*>(inputIds1)[seqPos] < 0 ||
static_cast<int32_t const*>(inputIds1)[seqPos] >= IdsSize1) {
printf(
"Error!!!!!!(embLayerNormVarPlugin): ID cannot be lookup "
"table: ID < 0 or ID > max ");
return;
} else {
word_id[1] = static_cast<int32_t const*>(inputIds1)[seqPos];
}
if (static_cast<int32_t const*>(inputIds2)[seqPos] < 0 ||
static_cast<int32_t const*>(inputIds2)[seqPos] >= IdsSize2) {
printf(
"Error!!!!!!(embLayerNormVarPlugin): ID cannot be lookup "
"table: ID < 0 or ID > max ");
return;
} else {
word_id[2] = static_cast<int32_t const*>(inputIds2)[seqPos];
}
}
__syncthreads();
// offset into embeddings is given by wordId * hidden_size
int32_t const outOffset = seqPos * ld;
// the output offset is given by b * (S*hidden_size) + s * hidden_size
kvp<T> threadData(0, 0);
for (int32_t it = threadIdx.x; it < ld; it += TPB) {
int32_t const offset0 = word_id[0] * ld;
T val = mIdsEmbDev0[offset0 + it];
int32_t const offset1 = word_id[1] * ld;
val += mIdsEmbDev1[offset1 + it];
int32_t const offset2 = word_id[2] * ld;
val += mIdsEmbDev2[offset2 + it];
output[outOffset + it] = val;
T const rldval = rld * val;
threadData = pairSum(threadData, kvp<T>(rldval, rldval * val));
}
// layer norm on the sum
layerNorm<T, T, float, TPB>(threadData, ld, outOffset, beta, gamma, output);
}
template <typename T, unsigned TPB>
__global__ void embLayerNormKernel_4(int32_t ld,
int32_t const* inputIds0,
int32_t const* inputIds1,
int32_t const* inputIds2,
int32_t const* inputIds3,
float const* beta,
float const* gamma,
T const* mIdsEmbDev0,
T const* mIdsEmbDev1,
T const* mIdsEmbDev2,
T const* mIdsEmbDev3,
int32_t IdsSize0,
int32_t IdsSize1,
int32_t IdsSize2,
int32_t IdsSize3,
T* output) {
T const rld = T(1.f) / T(ld);
cub::Sum pairSum;
int32_t const seqPos = blockIdx.y * gridDim.x + blockIdx.x;
extern __shared__ int32_t word_id[];
if (threadIdx.x == 0) {
if (static_cast<int32_t const*>(inputIds0)[seqPos] < 0 ||
static_cast<int32_t const*>(inputIds0)[seqPos] >= IdsSize0) {
printf(
"Error!!!!!!(embLayerNormVarPlugin): ID cannot be lookup "
"table: ID < 0 or ID > max ");
return;
} else {
word_id[0] = static_cast<int32_t const*>(inputIds0)[seqPos];
}
if (static_cast<int32_t const*>(inputIds1)[seqPos] < 0 ||
static_cast<int32_t const*>(inputIds1)[seqPos] >= IdsSize1) {
printf(
"Error!!!!!!(embLayerNormVarPlugin): ID cannot be lookup "
"table: ID < 0 or ID > max ");
return;
} else {
word_id[1] = static_cast<int32_t const*>(inputIds1)[seqPos];
}
if (static_cast<int32_t const*>(inputIds2)[seqPos] < 0 ||
static_cast<int32_t const*>(inputIds2)[seqPos] >= IdsSize2) {
printf(
"Error!!!!!!(embLayerNormVarPlugin): ID cannot be lookup "
"table: ID < 0 or ID > max ");
return;
} else {
word_id[2] = static_cast<int32_t const*>(inputIds2)[seqPos];
}
if (static_cast<int32_t const*>(inputIds3)[seqPos] < 0 ||
static_cast<int32_t const*>(inputIds3)[seqPos] >= IdsSize3) {
printf(
"Error!!!!!!(embLayerNormVarPlugin): ID cannot be lookup "
"table: ID < 0 or ID > max ");
return;
} else {
word_id[3] = static_cast<int32_t const*>(inputIds3)[seqPos];
}
}
__syncthreads();
// offset into embeddings is given by wordId * hidden_size
int32_t const outOffset = seqPos * ld;
// the output offset is given by b * (S*hidden_size) + s * hidden_size
kvp<T> threadData(0, 0);
for (int32_t it = threadIdx.x; it < ld; it += TPB) {
int32_t const offset0 = word_id[0] * ld;
T val = mIdsEmbDev0[offset0 + it];
int32_t const offset1 = word_id[1] * ld;
val += mIdsEmbDev1[offset1 + it];
int32_t const offset2 = word_id[2] * ld;
val += mIdsEmbDev2[offset2 + it];
int32_t const offset3 = word_id[3] * ld;
val += mIdsEmbDev3[offset3 + it];
output[outOffset + it] = val;
T const rldval = rld * val;
threadData = pairSum(threadData, kvp<T>(rldval, rldval * val));
}
// layer norm on the sum
layerNorm<T, T, float, TPB>(threadData, ld, outOffset, beta, gamma, output);
}
template <typename T>
int32_t embSkipLayerNorm_2(cudaStream_t stream,
int32_t ld,
int32_t B,
int32_t S,
int const* inputIds0,
int const* inputIds1,
int32_t nbLookupTables,
float const* beta,
float const* gamma,
T const* mIdsEmbDev0,
T const* mIdsEmbDev1,
int32_t IdsSize0,
int32_t IdsSize1,
T* output) {
constexpr int32_t tpb = 256;
dim3 const grid(S, B, 1);
dim3 const block(tpb, 1, 1);
size_t cache_size = sizeof(int32_t) * nbLookupTables;
embLayerNormKernel_2<T, tpb><<<grid, block, cache_size, stream>>>(ld,
inputIds0,
inputIds1,
beta,
gamma,
mIdsEmbDev0,
mIdsEmbDev1,
IdsSize0,
IdsSize1,
output);
return cudaPeekAtLastError();
}
template <typename T>
int32_t embSkipLayerNorm_3(cudaStream_t stream,
int32_t ld,
int32_t B,
int32_t S,
int const* inputIds0,
int const* inputIds1,
int const* inputIds2,
int32_t nbLookupTables,
float const* beta,
float const* gamma,
T const* mIdsEmbDev0,
T const* mIdsEmbDev1,
T const* mIdsEmbDev2,
int32_t IdsSize0,
int32_t IdsSize1,
int32_t IdsSize2,
T* output) {
constexpr int32_t tpb = 256;
dim3 const grid(S, B, 1);
dim3 const block(tpb, 1, 1);
size_t cache_size = sizeof(int32_t) * nbLookupTables;
embLayerNormKernel_3<T, tpb><<<grid, block, cache_size, stream>>>(ld,
inputIds0,
inputIds1,
inputIds2,
beta,
gamma,
mIdsEmbDev0,
mIdsEmbDev1,
mIdsEmbDev2,
IdsSize0,
IdsSize1,
IdsSize2,
output);
return cudaPeekAtLastError();
}
template <typename T>
int32_t embSkipLayerNorm_4(cudaStream_t stream,
int32_t ld,
int32_t B,
int32_t S,
int const* inputIds0,
int const* inputIds1,
int const* inputIds2,
int const* inputIds3,
int32_t nbLookupTables,
float const* beta,
float const* gamma,
T const* mIdsEmbDev0,
T const* mIdsEmbDev1,
T const* mIdsEmbDev2,
T const* mIdsEmbDev3,
int32_t IdsSize0,
int32_t IdsSize1,
int32_t IdsSize2,
int32_t IdsSize3,
T* output) {
constexpr int32_t tpb = 256;
dim3 const grid(S, B, 1);
dim3 const block(tpb, 1, 1);
size_t cache_size = sizeof(int32_t) * nbLookupTables;
embLayerNormKernel_4<T, tpb><<<grid, block, cache_size, stream>>>(ld,
inputIds0,
inputIds1,
inputIds2,
inputIds3,
beta,
gamma,
mIdsEmbDev0,
mIdsEmbDev1,
mIdsEmbDev2,
mIdsEmbDev3,
IdsSize0,
IdsSize1,
IdsSize2,
IdsSize3,
output);
return cudaPeekAtLastError();
}
template int32_t embSkipLayerNorm_2<float>(cudaStream_t,
int32_t,
int32_t,
int32_t,
int32_t const*,
int32_t const*,
int32_t,
float const*,
float const*,
float const*,
float const*,
int32_t,
int32_t,
float*);
template int32_t embSkipLayerNorm_3<float>(cudaStream_t,
int32_t,
int32_t,
int32_t,
int32_t const*,
int32_t const*,
int32_t const*,
int32_t,
float const*,
float const*,
float const*,
float const*,
float const*,
int32_t,
int32_t,
int32_t,
float*);
template int32_t embSkipLayerNorm_4<float>(cudaStream_t,
int32_t,
int32_t,
int32_t,
int32_t const*,
int32_t const*,
int32_t const*,
int32_t const*,
int32_t,
float const*,
float const*,
float const*,
float const*,
float const*,
float const*,
int32_t,
int32_t,
int32_t,
int32_t,
float*);
template int32_t embSkipLayerNorm_2<half>(cudaStream_t,
int32_t,
int32_t,
int32_t,
int32_t const*,
int32_t const*,
int32_t,
float const*,
float const*,
half const*,
half const*,
int32_t,
int32_t,
half*);
template int32_t embSkipLayerNorm_3<half>(cudaStream_t,
int32_t,
int32_t,
int32_t,
int32_t const*,
int32_t const*,
int32_t const*,
int32_t,
float const*,
float const*,
half const*,
half const*,
half const*,
int32_t,
int32_t,
int32_t,
half*);
template int32_t embSkipLayerNorm_4<half>(cudaStream_t,
int32_t,
int32_t,
int32_t,
int32_t const*,
int32_t const*,
int32_t const*,
int32_t const*,
int32_t,
float const*,
float const*,
half const*,
half const*,
half const*,
half const*,
int32_t,
int32_t,
int32_t,
int32_t,
half*);
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,497 @@
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
// SPDX-FileCopyrightText: Copyright (c) 1993-2022 NVIDIA CORPORATION &
// AFFILIATES. 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/plugin/many_emb_layernorm_plugin.h"
#include <cuda.h>
#include <cstring>
#include <vector>
#include "NvInfer.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
constexpr size_t threadsPerCta128 = 2 * 2 * 32;
constexpr size_t threadsPerCta256 = 1 * 4 * 32;
constexpr size_t threadsPerCta384 = 1 * 8 * 32;
// The number of xmmas in the M dimension. We use one uint32_t per XMMA in the M
// dimension: (s + 16*warps_m - 1) / (16*warps_m);
constexpr size_t xmmasM128 = 4;
constexpr size_t xmmasM256 = 16;
constexpr size_t xmmasM384 = 24;
// Packed mask size per batch. Layout is XMMAS_M * THREADS_PER_CTA.
constexpr size_t packedMaskSize128 = xmmasM128 * threadsPerCta128;
constexpr size_t packedMaskSize256 = xmmasM256 * threadsPerCta256;
constexpr size_t packedMaskSize384 = xmmasM384 * threadsPerCta384;
char const* EMB_LAYER_NORM_VERSION{"1"};
char const* EMB_LAYER_NORM_NAME{"ManyEmbLayerNormPluginDynamic"};
// Static class fields initialization
nvinfer1::PluginFieldCollection EmbLayerNormPluginCreator::mFC{};
std::vector<nvinfer1::PluginField> EmbLayerNormPluginCreator::mPluginAttributes;
EmbLayerNormPlugin::EmbLayerNormPlugin(
std::string const& name,
nvinfer1::DataType const type,
nvinfer1::Weights const& beta,
nvinfer1::Weights const& gamma,
const std::vector<nvinfer1::Weights>& IdsEmb)
: mLayerName(name),
mLd(beta.count),
mType(type),
mIdsEmb_(IdsEmb),
nbLookupTables_(static_cast<int>(IdsEmb.size())) {
// Assuming Weights.count is the number of elements and not bytes
assert(beta.count == gamma.count);
mBeta.convertAndCopy(beta, nvinfer1::DataType::kFLOAT);
mGamma.convertAndCopy(gamma, nvinfer1::DataType::kFLOAT);
copyToDevice(&mGamma, sizeof(float) * mGamma.count, &mGammaDev);
copyToDevice(&mBeta, sizeof(float) * mBeta.count, &mBetaDev);
for (size_t i = 0; i < mIdsEmb_.size(); ++i) {
assert(mIdsEmb_[i].count % mLd == 0);
mIdsVocabSize.push_back(int32_t(mIdsEmb_[i].count / mLd));
WeightsWithOwnership tem_weight;
tem_weight.convertAndCopy(mIdsEmb_[i], mType);
void* cudaMem{nullptr};
PADDLE_ENFORCE_GPU_SUCCESS(
cudaMalloc(&cudaMem, getWeightsSize(tem_weight, mType)));
PADDLE_ENFORCE_GPU_SUCCESS(cudaMemcpy(cudaMem,
tem_weight.values,
getWeightsSize(tem_weight, mType),
cudaMemcpyHostToDevice));
mIdsEmbPtrs.push_back(cudaMem);
}
}
EmbLayerNormPlugin::EmbLayerNormPlugin(std::string const& name,
void const* data,
size_t length)
: mLayerName(name),
mGammaDev(nullptr),
mBetaDev(nullptr),
mIdsEmbPtrs{},
mIdsEmb_{} {
// Deserialize in the same order as serialization
deserialize_value(&data, &length, &mType);
deserialize_value(&data, &length, &mLd);
deserialize_value(&data, &length, &nbLookupTables_);
for (int32_t i = 0; i < nbLookupTables_; ++i) {
int32_t tem;
deserialize_value(&data, &length, &tem);
mIdsVocabSize.push_back(tem);
}
char const* d = static_cast<char const*>(data);
mBeta.convertAndCopy(&d, mLd, nvinfer1::DataType::kFLOAT);
mGamma.convertAndCopy(&d, mLd, nvinfer1::DataType::kFLOAT);
for (int32_t i = 0; i < nbLookupTables_; ++i) {
nvinfer1::Weights pre_tem_weight;
pre_tem_weight.type = mType;
pre_tem_weight.count = mLd * size_t(mIdsVocabSize[i]);
const auto nbBytes = mLd * size_t(mIdsVocabSize[i]) * getElementSize(mType);
auto destBuf = new char[nbBytes];
pre_tem_weight.values = destBuf;
std::copy_n(d, nbBytes, destBuf);
d += nbBytes;
mIdsEmb_.push_back(pre_tem_weight);
}
}
// IPluginV2DynamicExt Methods
nvinfer1::IPluginV2DynamicExt* EmbLayerNormPlugin::clone() const noexcept {
TRANSFORMER_DEBUG_MSG("EmbLayerNormPlugin clone");
auto p = new EmbLayerNormPlugin(mLayerName, mType, mBeta, mGamma, mIdsEmb_);
p->setPluginNamespace(mNamespace.c_str());
return p;
}
nvinfer1::DimsExprs EmbLayerNormPlugin::getOutputDimensions(
int32_t outputIndex,
nvinfer1::DimsExprs const* inputs,
int32_t nbInputs,
nvinfer1::IExprBuilder& exprBuilder) noexcept {
assert(outputIndex == 0);
nvinfer1::DimsExprs ret;
ret.nbDims = 3;
ret.d[0] = inputs[0].d[0];
ret.d[1] = inputs[0].d[1];
ret.d[2] = exprBuilder.constant(mLd);
return ret;
}
bool EmbLayerNormPlugin::supportsFormatCombination(
int32_t pos,
nvinfer1::PluginTensorDesc const* inOut,
int32_t nbInputs,
int32_t nbOutputs) noexcept {
assert(nbOutputs == 1);
nvinfer1::PluginTensorDesc const& prev = inOut[0];
nvinfer1::PluginTensorDesc const& desc = inOut[pos];
if (desc.format != nvinfer1::TensorFormat::kLINEAR) {
return false;
}
if (pos == 0) {
return desc.type == nvinfer1::DataType::kINT32;
}
if (0 < pos && pos < nbInputs) {
assert(desc.dims.nbDims == prev.dims.nbDims);
for (int i = 0; i < prev.dims.nbDims; ++i) {
assert(desc.dims.d[i] == prev.dims.d[i]);
}
return desc.type == prev.type;
}
if (pos == nbInputs) { // output
return desc.type == mType && desc.dims.nbDims == 3 &&
desc.dims.d[0] == prev.dims.d[0] && desc.dims.d[1] == prev.dims.d[1];
}
}
void EmbLayerNormPlugin::configurePlugin(
nvinfer1::DynamicPluginTensorDesc const* inputs,
int32_t nbInputs,
nvinfer1::DynamicPluginTensorDesc const* outputs,
int32_t nbOutputs) noexcept {
TRANSFORMER_DEBUG_MSG("EmbLayerNormPlugin configurePlugin");
assert(static_cast<size_t>(outputs[0].desc.dims.d[2]) ==
static_cast<size_t>(mLd));
int32_t const B = inputs[0].desc.dims.d[0];
if (B > 0) {
assert(outputs[0].desc.dims.d[0] == B);
}
assert(outputs[0].desc.type == mType);
}
size_t EmbLayerNormPlugin::getWorkspaceSize(
nvinfer1::PluginTensorDesc const* inputs,
int32_t nbInputs,
nvinfer1::PluginTensorDesc const* outputs,
int32_t nbOutputs) const noexcept {
return 0;
}
int32_t EmbLayerNormPlugin::enqueue(
nvinfer1::PluginTensorDesc const* inputDesc,
nvinfer1::PluginTensorDesc const* outputDesc,
void const* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) noexcept {
int32_t batchSize = inputDesc[0].dims.d[0];
int32_t const maxSeqlen = inputDesc[0].dims.d[1];
if (maxSeqlen > 512) {
PADDLE_THROW(common::errors::InvalidArgument(
"EmbLayerNormPlugin support maxSeqlen is 512"));
}
const float* beta = mBetaDev.get();
const float* gamma = mGammaDev.get();
if (mType == nvinfer1::DataType::kFLOAT) {
auto output = static_cast<float*>(outputs[0]);
if (nbLookupTables_ == 2) {
return embSkipLayerNorm_2<float>(
stream,
static_cast<int32_t>(mLd),
batchSize,
maxSeqlen,
static_cast<int32_t const*>(inputs[0]),
static_cast<int32_t const*>(inputs[1]),
nbLookupTables_,
beta,
gamma,
static_cast<float const*>(mIdsEmbPtrs[0]),
static_cast<float const*>(mIdsEmbPtrs[1]),
mIdsVocabSize[0],
mIdsVocabSize[1],
output);
} else if (nbLookupTables_ == 3) {
return embSkipLayerNorm_3<float>(
stream,
static_cast<int32_t>(mLd),
batchSize,
maxSeqlen,
static_cast<int32_t const*>(inputs[0]),
static_cast<int32_t const*>(inputs[1]),
static_cast<int32_t const*>(inputs[2]),
nbLookupTables_,
beta,
gamma,
static_cast<float const*>(mIdsEmbPtrs[0]),
static_cast<float const*>(mIdsEmbPtrs[1]),
static_cast<float const*>(mIdsEmbPtrs[2]),
mIdsVocabSize[0],
mIdsVocabSize[1],
mIdsVocabSize[2],
output);
} else if (nbLookupTables_ == 4) {
return embSkipLayerNorm_4<float>(
stream,
static_cast<int32_t>(mLd),
batchSize,
maxSeqlen,
static_cast<int32_t const*>(inputs[0]),
static_cast<int32_t const*>(inputs[1]),
static_cast<int32_t const*>(inputs[2]),
static_cast<int32_t const*>(inputs[3]),
nbLookupTables_,
beta,
gamma,
static_cast<float const*>(mIdsEmbPtrs[0]),
static_cast<float const*>(mIdsEmbPtrs[1]),
static_cast<float const*>(mIdsEmbPtrs[2]),
static_cast<float const*>(mIdsEmbPtrs[3]),
mIdsVocabSize[0],
mIdsVocabSize[1],
mIdsVocabSize[2],
mIdsVocabSize[3],
output);
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"Only support 2,3,4 lookup_tables fused "));
}
} else if (mType == nvinfer1::DataType::kHALF) {
auto output = static_cast<half*>(outputs[0]);
if (nbLookupTables_ == 2) {
return embSkipLayerNorm_2<half>(stream,
static_cast<int32_t>(mLd),
batchSize,
maxSeqlen,
static_cast<int32_t const*>(inputs[0]),
static_cast<int32_t const*>(inputs[1]),
nbLookupTables_,
beta,
gamma,
static_cast<half const*>(mIdsEmbPtrs[0]),
static_cast<half const*>(mIdsEmbPtrs[1]),
mIdsVocabSize[0],
mIdsVocabSize[1],
output);
} else if (nbLookupTables_ == 3) {
return embSkipLayerNorm_3<half>(stream,
static_cast<int32_t>(mLd),
batchSize,
maxSeqlen,
static_cast<int32_t const*>(inputs[0]),
static_cast<int32_t const*>(inputs[1]),
static_cast<int32_t const*>(inputs[2]),
nbLookupTables_,
beta,
gamma,
static_cast<half const*>(mIdsEmbPtrs[0]),
static_cast<half const*>(mIdsEmbPtrs[1]),
static_cast<half const*>(mIdsEmbPtrs[2]),
mIdsVocabSize[0],
mIdsVocabSize[1],
mIdsVocabSize[2],
output);
} else if (nbLookupTables_ == 4) {
return embSkipLayerNorm_4<half>(stream,
static_cast<int32_t>(mLd),
batchSize,
maxSeqlen,
static_cast<int32_t const*>(inputs[0]),
static_cast<int32_t const*>(inputs[1]),
static_cast<int32_t const*>(inputs[2]),
static_cast<int32_t const*>(inputs[3]),
nbLookupTables_,
beta,
gamma,
static_cast<half const*>(mIdsEmbPtrs[0]),
static_cast<half const*>(mIdsEmbPtrs[1]),
static_cast<half const*>(mIdsEmbPtrs[2]),
static_cast<half const*>(mIdsEmbPtrs[3]),
mIdsVocabSize[0],
mIdsVocabSize[1],
mIdsVocabSize[2],
mIdsVocabSize[3],
output);
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"Only support 2,3,4 lookup_tables fused "));
}
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"Unsupported type error, expected [kHALF,kFLOAT]"));
}
return STATUS_SUCCESS;
}
// IPluginV2Ext Methods
nvinfer1::DataType EmbLayerNormPlugin::getOutputDataType(
int32_t index,
nvinfer1::DataType const* inputTypes,
int32_t nbInputs) const noexcept {
assert(index == 0);
assert(mType == nvinfer1::DataType::kHALF ||
mType == nvinfer1::DataType::kFLOAT);
return mType;
}
// IPluginV2 Methods
char const* EmbLayerNormPlugin::getPluginType() const noexcept {
return EMB_LAYER_NORM_NAME;
}
char const* EmbLayerNormPlugin::getPluginVersion() const noexcept {
return EMB_LAYER_NORM_VERSION;
}
int32_t EmbLayerNormPlugin::getNbOutputs() const noexcept { return 1; }
int32_t EmbLayerNormPlugin::initialize() noexcept {
TRANSFORMER_DEBUG_MSG("EmbLayerNormPlugin initialize");
return 0;
}
void EmbLayerNormPlugin::terminate() noexcept {
TRANSFORMER_DEBUG_MSG("EmbLayerNormPlugin terminate");
}
size_t EmbLayerNormPlugin::getSerializationSize() const noexcept {
size_t const wordSize = getElementSize(mType);
return 2 * sizeof(float) * mLd // beta + gamma
+ sizeof(mType) //
+ sizeof(mLd) //
+ mIdsVocabSize.size() * sizeof(mIdsVocabSize[0]) //
+ wordSize * mLd *
accumulate(
mIdsVocabSize.begin(), mIdsVocabSize.end(), 0) // ids emb
+ sizeof(nbLookupTables_); // numbers of lookup_table
}
void EmbLayerNormPlugin::serialize(void* buffer) const noexcept {
serialize_value(&buffer, mType);
serialize_value(&buffer, mLd);
serialize_value(&buffer, nbLookupTables_);
for (size_t i = 0; i < mIdsVocabSize.size(); ++i) {
serialize_value(&buffer, mIdsVocabSize[i]);
}
char* d = static_cast<char*>(buffer);
size_t const wordSize = getElementSize(mType);
serFromDev(&d, mBetaDev.get(), mLd);
serFromDev(&d, mGammaDev.get(), mLd);
for (size_t i = 0; i < mIdsEmbPtrs.size(); ++i) {
serFromDev(&d,
static_cast<char*>(mIdsEmbPtrs[i]),
mLd * mIdsVocabSize[i] * wordSize);
}
}
void EmbLayerNormPlugin::destroy() noexcept {
// This gets called when the network containing plugin is destroyed
mBetaDev.reset(nullptr);
mGammaDev.reset(nullptr);
for (size_t i = 0; i < mIdsEmbPtrs.size(); ++i) {
cudaFree(mIdsEmbPtrs[i]);
}
delete this;
}
void EmbLayerNormPlugin::setPluginNamespace(char const* libNamespace) noexcept {
mNamespace = libNamespace;
}
char const* EmbLayerNormPlugin::getPluginNamespace() const noexcept {
return mNamespace.c_str();
}
EmbLayerNormPluginCreator::EmbLayerNormPluginCreator() = default;
char const* EmbLayerNormPluginCreator::getPluginName() const noexcept {
return EMB_LAYER_NORM_NAME;
}
char const* EmbLayerNormPluginCreator::getPluginVersion() const noexcept {
return EMB_LAYER_NORM_VERSION;
}
nvinfer1::PluginFieldCollection const*
EmbLayerNormPluginCreator::getFieldNames() noexcept {
return &mFC;
}
bool initialize_fields(nvinfer1::PluginFieldCollection const* fc,
nvinfer1::Weights* beta,
nvinfer1::Weights* gamma,
std::vector<nvinfer1::Weights>* IdsEmb) {
bool output_fp16 = false;
for (int32_t i = 0; i < fc->nbFields; i++) {
std::string field_name(fc->fields[i].name);
if (field_name.compare("bert_embeddings_layernorm_beta") == 0) {
TRANSFORMER_DEBUG_MSG("Building bert_embeddings_layernorm_beta...");
beta->values = fc->fields[i].data;
beta->count = fc->fields[i].length;
beta->type = fieldTypeToDataType(fc->fields[i].type);
}
if (field_name.compare("bert_embeddings_layernorm_gamma") == 0) {
TRANSFORMER_DEBUG_MSG("Building bert_embeddings_layernorm_gamma...");
gamma->values = fc->fields[i].data;
gamma->count = fc->fields[i].length;
gamma->type = fieldTypeToDataType(fc->fields[i].type);
}
if (field_name.compare("output_fp16") == 0) {
TRANSFORMER_DEBUG_MSG("Building output_fp16...");
assert(fc->fields[i].type == nvinfer1::PluginFieldType::kINT32);
output_fp16 = static_cast<int32_t const*>(fc->fields[i].data)[0] != 0;
}
if (field_name.compare("bert_embeddings_word_embeddings_" +
std::to_string(i - 3)) == 0) {
TRANSFORMER_DEBUG_MSG(
("bert_embeddings_word_embeddings_" + std::to_string(i - 3)).c_str());
nvinfer1::Weights tem;
tem.values = fc->fields[i].data;
tem.count = fc->fields[i].length;
tem.type = fieldTypeToDataType(fc->fields[i].type);
IdsEmb->push_back(tem);
}
}
return output_fp16;
}
nvinfer1::IPluginV2* EmbLayerNormPluginCreator::createPlugin(
char const* name, nvinfer1::PluginFieldCollection const* fc) noexcept {
TRANSFORMER_DEBUG_MSG("EmbLayerNormVar createPlugin");
nvinfer1::Weights beta;
nvinfer1::Weights gamma;
std::vector<nvinfer1::Weights> IdsEmb;
bool output_fp16 = initialize_fields(fc, &beta, &gamma, &IdsEmb);
TRANSFORMER_DEBUG_MSG("Building the Plugin...");
EmbLayerNormPlugin* p = new EmbLayerNormPlugin(
name,
output_fp16 ? nvinfer1::DataType::kHALF : nvinfer1::DataType::kFLOAT,
beta,
gamma,
IdsEmb);
return p;
}
nvinfer1::IPluginV2* EmbLayerNormPluginCreator::deserializePlugin(
char const* name, void const* serialData, size_t serialLength) noexcept {
return new EmbLayerNormPlugin(name, serialData, serialLength);
}
void EmbLayerNormPluginCreator::setPluginNamespace(
char const* libNamespace) noexcept {
mNamespace = libNamespace;
}
char const* EmbLayerNormPluginCreator::getPluginNamespace() const noexcept {
return mNamespace.c_str();
}
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,203 @@
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
// SPDX-FileCopyrightText: Copyright (c) 1993-2022 NVIDIA CORPORATION &
// AFFILIATES. 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.
#pragma once
#include <cuda.h>
#include "NvInferPlugin.h"
#include "NvInferRuntime.h"
#include "paddle/fluid/inference/tensorrt/plugin/common/bertCommon.h"
#include "paddle/fluid/inference/tensorrt/plugin/common/plugin.h"
#include "paddle/fluid/inference/tensorrt/plugin/common/serialize.h"
#include "paddle/fluid/inference/tensorrt/plugin/trt_plugin.h"
#include "paddle/fluid/platform/enforce.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
template <typename T>
int32_t embSkipLayerNorm_2(cudaStream_t,
int32_t,
int32_t,
int32_t,
int32_t const*,
int32_t const*,
int32_t,
float const*,
float const*,
T const*,
T const*,
int32_t,
int32_t,
T*);
template <typename T>
int32_t embSkipLayerNorm_3(cudaStream_t,
int32_t,
int32_t,
int32_t,
int32_t const*,
int32_t const*,
int32_t const*,
int32_t,
float const*,
float const*,
T const*,
T const*,
T const*,
int32_t,
int32_t,
int32_t,
T*);
template <typename T>
int32_t embSkipLayerNorm_4(cudaStream_t,
int32_t,
int32_t,
int32_t,
int32_t const*,
int32_t const*,
int32_t const*,
int32_t const*,
int32_t,
float const*,
float const*,
T const*,
T const*,
T const*,
T const*,
int32_t,
int32_t,
int32_t,
int32_t,
T*);
class EmbLayerNormPlugin : public nvinfer1::IPluginV2DynamicExt {
public:
EmbLayerNormPlugin(std::string const& name,
nvinfer1::DataType const type,
nvinfer1::Weights const& beta,
nvinfer1::Weights const& gamma,
const std::vector<nvinfer1::Weights>& ids_emb);
EmbLayerNormPlugin(std::string const& name, void const* data, size_t length);
EmbLayerNormPlugin() = delete;
nvinfer1::IPluginV2DynamicExt* clone() const noexcept override;
nvinfer1::DimsExprs getOutputDimensions(
int32_t outputIndex,
const nvinfer1::DimsExprs* inputs,
int32_t nbInputs,
nvinfer1::IExprBuilder& exprBuilder) noexcept override;
void configurePlugin(nvinfer1::DynamicPluginTensorDesc const* in,
int32_t nbInputs,
nvinfer1::DynamicPluginTensorDesc const* out,
int32_t nbOutputs) noexcept override;
int32_t enqueue(nvinfer1::PluginTensorDesc const* inputDesc,
nvinfer1::PluginTensorDesc const* outputDesc,
void const* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) noexcept override;
int32_t initialize() noexcept override;
void terminate() noexcept override;
char const* getPluginVersion() const noexcept override;
bool supportsFormatCombination(int32_t pos,
nvinfer1::PluginTensorDesc const* inOut,
int32_t nbInputs,
int32_t nbOutputs) noexcept override;
size_t getWorkspaceSize(nvinfer1::PluginTensorDesc const* inputs,
int32_t nbInputs,
nvinfer1::PluginTensorDesc const* outputs,
int32_t nbOutputs) const noexcept override;
nvinfer1::DataType getOutputDataType(
int32_t index,
nvinfer1::DataType const* inputTypes,
int32_t nbInputs) const noexcept override;
char const* getPluginType() const noexcept override;
int32_t getNbOutputs() const noexcept override;
size_t getSerializationSize() const noexcept override;
void serialize(void* buffer) const noexcept override;
void destroy() noexcept override;
char const* getPluginNamespace() const noexcept override;
void setPluginNamespace(char const* pluginNamespace) noexcept override;
protected:
std::string const mLayerName;
std::string mNamespace;
cuda_unique_ptr<float> mGammaDev;
cuda_unique_ptr<float> mBetaDev;
std::vector<void*> mIdsEmbPtrs;
size_t mLd; // leading dim = hidden size
std::vector<int32_t> mIdsVocabSize;
WeightsWithOwnership mBeta;
WeightsWithOwnership mGamma;
nvinfer1::DataType mType;
std::vector<nvinfer1::Weights> mIdsEmb_;
int32_t nbLookupTables_ = 0;
};
class EmbLayerNormPluginCreator : public nvinfer1::IPluginCreator {
public:
EmbLayerNormPluginCreator();
char const* getPluginName() const noexcept override;
const nvinfer1::PluginFieldCollection* getFieldNames() noexcept override;
void setPluginNamespace(char const* pluginNamespace) noexcept override;
char const* getPluginNamespace() const noexcept override;
nvinfer1::IPluginV2* createPlugin(
char const* name,
const nvinfer1::PluginFieldCollection* fc) noexcept override;
char const* getPluginVersion() const noexcept override;
nvinfer1::IPluginV2* deserializePlugin(char const* name,
void const* serialData,
size_t serialLength) noexcept override;
protected:
static nvinfer1::PluginFieldCollection mFC;
static std::vector<nvinfer1::PluginField> mPluginAttributes;
std::string mNamespace;
};
REGISTER_TRT_PLUGIN_V2(EmbLayerNormPluginCreator);
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,477 @@
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
// SPDX-FileCopyrightText: Copyright (c) 1993-2022 NVIDIA CORPORATION &
// AFFILIATES. 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 <cuda.h>
#include <cassert>
#include <cstring>
#include <iostream>
#include <vector>
#include "NvInfer.h"
#include "paddle/fluid/inference/tensorrt/plugin/common/common.cuh"
#include "paddle/fluid/inference/tensorrt/plugin/many_emb_layernorm_varseqlen_plugin.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
template <typename T, unsigned TPB>
__global__ void embLayerNormKernelHFace_2(int32_t ld,
int32_t const* inputIds0,
int32_t const* inputIds1,
float const* beta,
float const* gamma,
T const* mIdsEmbDev0,
T const* mIdsEmbDev1,
int32_t IdsSize0,
int32_t IdsSize1,
T* output) {
cub::Sum pairSum;
int32_t const s = blockIdx.x;
int32_t const b = blockIdx.y;
int32_t const sumS = inputIds0[b];
int32_t const s_b = inputIds0[b + 1] - sumS;
if (s >= s_b) {
return; // This CTA has nothing to do
}
T const rld = T(1.f) / T(ld);
int32_t const seqPos = sumS + s;
extern __shared__ int32_t word_id[];
if (threadIdx.x == 0) {
if (static_cast<int32_t const*>(inputIds1)[seqPos] < 0 ||
static_cast<int32_t const*>(inputIds1)[seqPos] >= IdsSize1) {
printf(
"Error!!!!!!(embLayerNormVarSeqlenPlugin): ID cannot be lookup "
"table: ID < 0 or ID > max ");
return;
} else {
word_id[0] = static_cast<int32_t const*>(inputIds1)[seqPos];
}
}
__syncthreads();
// 2. load pos/tok/word embeddings and add them together
// offset into embeddings is given by wordId * hidden_size
int32_t const poffset = blockIdx.x * ld;
int32_t const outOffset = seqPos * ld;
// the output offset is given by b * (S*hidden_size) + s * hidden_size
kvp<T> threadData(0, 0);
for (int32_t it = threadIdx.x; it < ld; it += TPB) {
T p(mIdsEmbDev0[poffset + it]); // pos id
T val = p;
int32_t const offset = word_id[0] * ld;
val += mIdsEmbDev1[offset + it];
output[outOffset + it] = val;
T const rldval = rld * val;
threadData = pairSum(threadData, kvp<T>(rldval, rldval * val));
}
// 3. layer norm on the sum
layerNorm<T, T, float, TPB>(threadData, ld, outOffset, beta, gamma, output);
}
template <typename T, unsigned TPB>
__global__ void embLayerNormKernelHFace_3(int32_t ld,
int32_t const* inputIds0,
int32_t const* inputIds1,
int32_t const* inputIds2,
float const* beta,
float const* gamma,
T const* mIdsEmbDev0,
T const* mIdsEmbDev1,
T const* mIdsEmbDev2,
int32_t IdsSize0,
int32_t IdsSize1,
int32_t IdsSize2,
T* output) {
cub::Sum pairSum;
int32_t const s = blockIdx.x;
int32_t const b = blockIdx.y;
int32_t const sumS = inputIds0[b];
int32_t const s_b = inputIds0[b + 1] - sumS;
if (s >= s_b) {
return; // This CTA has nothing to do
}
T const rld = T(1.f) / T(ld);
int32_t const seqPos = sumS + s;
extern __shared__ int32_t word_id[];
if (threadIdx.x == 0) {
if (static_cast<int32_t const*>(inputIds1)[seqPos] < 0 ||
static_cast<int32_t const*>(inputIds1)[seqPos] >= IdsSize1) {
printf(
"Error!!!!!!(embLayerNormVarSeqlenPlugin): ID cannot be lookup "
"table: ID < 0 or ID > max ");
return;
} else {
word_id[0] = static_cast<int32_t const*>(inputIds1)[seqPos];
}
if (static_cast<int32_t const*>(inputIds2)[seqPos] < 0 ||
static_cast<int32_t const*>(inputIds2)[seqPos] >= IdsSize2) {
printf(
"Error!!!!!!(embLayerNormVarSeqlenPlugin): ID cannot be lookup "
"table: ID < 0 or ID > max ");
return;
} else {
word_id[1] = static_cast<int32_t const*>(inputIds2)[seqPos];
}
}
__syncthreads();
// 2. load pos/tok/word embeddings and add them together
// offset into embeddings is given by wordId * hidden_size
int32_t const poffset = blockIdx.x * ld;
int32_t const outOffset = seqPos * ld;
// the output offset is given by b * (S*hidden_size) + s * hidden_size
kvp<T> threadData(0, 0);
for (int32_t it = threadIdx.x; it < ld; it += TPB) {
T p(mIdsEmbDev0[poffset + it]); // pos id
T val = p;
int32_t const offset0 = word_id[0] * ld;
val += mIdsEmbDev1[offset0 + it];
int32_t const offset1 = word_id[1] * ld;
val += mIdsEmbDev2[offset1 + it];
output[outOffset + it] = val;
T const rldval = rld * val;
threadData = pairSum(threadData, kvp<T>(rldval, rldval * val));
}
// 3. layer norm on the sum
layerNorm<T, T, float, TPB>(threadData, ld, outOffset, beta, gamma, output);
}
template <typename T, unsigned TPB>
__global__ void embLayerNormKernelHFace_4(int32_t ld,
int32_t const* inputIds0,
int32_t const* inputIds1,
int32_t const* inputIds2,
int32_t const* inputIds3,
float const* beta,
float const* gamma,
T const* mIdsEmbDev0,
T const* mIdsEmbDev1,
T const* mIdsEmbDev2,
T const* mIdsEmbDev3,
int32_t IdsSize0,
int32_t IdsSize1,
int32_t IdsSize2,
int32_t IdsSize3,
T* output) {
cub::Sum pairSum;
int32_t const s = blockIdx.x;
int32_t const b = blockIdx.y;
int32_t const sumS = inputIds0[b];
int32_t const s_b = inputIds0[b + 1] - sumS;
if (s >= s_b) {
return; // This CTA has nothing to do
}
T const rld = T(1.f) / T(ld);
int32_t const seqPos = sumS + s;
extern __shared__ int32_t word_id[];
if (threadIdx.x == 0) {
if (static_cast<int32_t const*>(inputIds1)[seqPos] < 0 ||
static_cast<int32_t const*>(inputIds1)[seqPos] >= IdsSize1) {
printf(
"Error!!!!!!(embLayerNormVarSeqlenPlugin): ID cannot be lookup "
"table: ID < 0 or ID > max ");
return;
} else {
word_id[0] = static_cast<int32_t const*>(inputIds1)[seqPos];
}
if (static_cast<int32_t const*>(inputIds2)[seqPos] < 0 ||
static_cast<int32_t const*>(inputIds2)[seqPos] >= IdsSize2) {
printf(
"Error!!!!!!(embLayerNormVarSeqlenPlugin): ID cannot be lookup "
"table: ID < 0 or ID > max ");
return;
} else {
word_id[1] = static_cast<int32_t const*>(inputIds2)[seqPos];
}
if (static_cast<int32_t const*>(inputIds3)[seqPos] < 0 ||
static_cast<int32_t const*>(inputIds3)[seqPos] >= IdsSize3) {
printf(
"Error!!!!!!(embLayerNormVarSeqlenPlugin): ID cannot be lookup "
"table: ID < 0 or ID > max ");
return;
} else {
word_id[2] = static_cast<int32_t const*>(inputIds3)[seqPos];
}
}
__syncthreads();
// 2. load pos/tok/word embeddings and add them together
// offset into embeddings is given by wordId * hidden_size
int32_t const poffset = blockIdx.x * ld;
int32_t const outOffset = seqPos * ld;
// the output offset is given by b * (S*hidden_size) + s * hidden_size
kvp<T> threadData(0, 0);
for (int32_t it = threadIdx.x; it < ld; it += TPB) {
T p(mIdsEmbDev0[poffset + it]); // pos id
T val = p;
int32_t const offset0 = word_id[0] * ld;
val += mIdsEmbDev1[offset0 + it];
int32_t const offset1 = word_id[1] * ld;
val += mIdsEmbDev2[offset1 + it];
int32_t const offset2 = word_id[2] * ld;
val += mIdsEmbDev3[offset2 + it];
output[outOffset + it] = val;
T const rldval = rld * val;
threadData = pairSum(threadData, kvp<T>(rldval, rldval * val));
}
// 3. layer norm on the sum
layerNorm<T, T, float, TPB>(threadData, ld, outOffset, beta, gamma, output);
}
template <typename T>
int32_t embSkipLayerNormHFace_2(cudaStream_t stream,
int32_t ld,
int32_t B,
int32_t S,
int const* inputIds0,
int const* inputIds1,
int32_t nbLookupTables,
float const* beta,
float const* gamma,
T const* mIdsEmbDev0,
T const* mIdsEmbDev1,
int32_t IdsSize0,
int32_t IdsSize1,
T* output) {
constexpr int32_t tpb = 256;
dim3 const grid(S, B, 1);
dim3 const block(tpb, 1, 1);
size_t cache_size = sizeof(int32_t) * (nbLookupTables - 1);
embLayerNormKernelHFace_2<T, tpb>
<<<grid, block, cache_size, stream>>>(ld,
inputIds0,
inputIds1,
beta,
gamma,
mIdsEmbDev0,
mIdsEmbDev1,
IdsSize0,
IdsSize1,
output);
return cudaPeekAtLastError();
}
template <typename T>
int32_t embSkipLayerNormHFace_3(cudaStream_t stream,
int32_t ld,
int32_t B,
int32_t S,
int const* inputIds0,
int const* inputIds1,
int const* inputIds2,
int32_t nbLookupTables,
float const* beta,
float const* gamma,
T const* mIdsEmbDev0,
T const* mIdsEmbDev1,
T const* mIdsEmbDev2,
int32_t IdsSize0,
int32_t IdsSize1,
int32_t IdsSize2,
T* output) {
constexpr int32_t tpb = 256;
dim3 const grid(S, B, 1);
dim3 const block(tpb, 1, 1);
size_t cache_size = sizeof(int32_t) * (nbLookupTables - 1);
embLayerNormKernelHFace_3<T, tpb>
<<<grid, block, cache_size, stream>>>(ld,
inputIds0,
inputIds1,
inputIds2,
beta,
gamma,
mIdsEmbDev0,
mIdsEmbDev1,
mIdsEmbDev2,
IdsSize0,
IdsSize1,
IdsSize2,
output);
return cudaPeekAtLastError();
}
template <typename T>
int32_t embSkipLayerNormHFace_4(cudaStream_t stream,
int32_t ld,
int32_t B,
int32_t S,
int const* inputIds0,
int const* inputIds1,
int const* inputIds2,
int const* inputIds3,
int32_t nbLookupTables,
float const* beta,
float const* gamma,
T const* mIdsEmbDev0,
T const* mIdsEmbDev1,
T const* mIdsEmbDev2,
T const* mIdsEmbDev3,
int32_t IdsSize0,
int32_t IdsSize1,
int32_t IdsSize2,
int32_t IdsSize3,
T* output) {
constexpr int32_t tpb = 256;
dim3 const grid(S, B, 1);
dim3 const block(tpb, 1, 1);
size_t cache_size = sizeof(int32_t) * (nbLookupTables - 1);
embLayerNormKernelHFace_4<T, tpb>
<<<grid, block, cache_size, stream>>>(ld,
inputIds0,
inputIds1,
inputIds2,
inputIds3,
beta,
gamma,
mIdsEmbDev0,
mIdsEmbDev1,
mIdsEmbDev2,
mIdsEmbDev3,
IdsSize0,
IdsSize1,
IdsSize2,
IdsSize3,
output);
return cudaPeekAtLastError();
}
template int32_t embSkipLayerNormHFace_2<float>(cudaStream_t,
int32_t,
int32_t,
int32_t,
int32_t const*,
int32_t const*,
int32_t,
float const*,
float const*,
float const*,
float const*,
int32_t,
int32_t,
float*);
template int32_t embSkipLayerNormHFace_3<float>(cudaStream_t,
int32_t,
int32_t,
int32_t,
int32_t const*,
int32_t const*,
int32_t const*,
int32_t,
float const*,
float const*,
float const*,
float const*,
float const*,
int32_t,
int32_t,
int32_t,
float*);
template int32_t embSkipLayerNormHFace_4<float>(cudaStream_t,
int32_t,
int32_t,
int32_t,
int32_t const*,
int32_t const*,
int32_t const*,
int32_t const*,
int32_t,
float const*,
float const*,
float const*,
float const*,
float const*,
float const*,
int32_t,
int32_t,
int32_t,
int32_t,
float*);
template int32_t embSkipLayerNormHFace_2<half>(cudaStream_t,
int32_t,
int32_t,
int32_t,
int32_t const*,
int32_t const*,
int32_t,
float const*,
float const*,
half const*,
half const*,
int32_t,
int32_t,
half*);
template int32_t embSkipLayerNormHFace_3<half>(cudaStream_t,
int32_t,
int32_t,
int32_t,
int32_t const*,
int32_t const*,
int32_t const*,
int32_t,
float const*,
float const*,
half const*,
half const*,
half const*,
int32_t,
int32_t,
int32_t,
half*);
template int32_t embSkipLayerNormHFace_4<half>(cudaStream_t,
int32_t,
int32_t,
int32_t,
int32_t const*,
int32_t const*,
int32_t const*,
int32_t const*,
int32_t,
float const*,
float const*,
half const*,
half const*,
half const*,
half const*,
int32_t,
int32_t,
int32_t,
int32_t,
half*);
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,496 @@
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
// SPDX-FileCopyrightText: Copyright (c) 1993-2022 NVIDIA CORPORATION &
// AFFILIATES. 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 <cuda.h>
#include <cassert>
#include <cstring>
#include <iostream>
#include <vector>
#include "NvInfer.h"
#include "paddle/fluid/inference/tensorrt/plugin/common/common.cuh"
#include "paddle/fluid/inference/tensorrt/plugin/many_emb_layernorm_varseqlen_plugin.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
template <typename T, unsigned TPB>
__global__ void embLayerNormKernelMTron_2(int32_t ld,
int32_t const* inputIds0,
int32_t const* inputIds1,
float const* beta,
float const* gamma,
T const* mIdsEmbDev0,
T const* mIdsEmbDev1,
int32_t IdsSize0,
int32_t IdsSize1,
T* output,
T* skip) {
cub::Sum pairSum;
int32_t const s = blockIdx.x;
int32_t const b = blockIdx.y;
int32_t const sumS = inputIds0[b];
int32_t const s_b = inputIds0[b + 1] - sumS;
if (s >= s_b) {
return; // This CTA has nothing to do
}
T const rld = T(1.f) / T(ld);
const int32_t seqPos = sumS + s;
extern __shared__ int32_t word_id[];
if (threadIdx.x == 0) {
if (static_cast<int32_t const*>(inputIds1)[seqPos] < 0 ||
static_cast<int32_t const*>(inputIds1)[seqPos] >= IdsSize1) {
printf(
"Error!!!!!!(embLayerNormVarSeqlenPlugin): ID cannot be lookup "
"table: ID < 0 or ID > max ");
return;
} else {
word_id[0] = static_cast<int32_t const*>(inputIds1)[seqPos];
}
}
__syncthreads();
// 2. load pos/tok/word embeddings and add them together
// offset into embeddings is given by wordId * hidden_size
const int32_t poffset = blockIdx.x * ld;
const int32_t outOffset = seqPos * ld;
// the output offset is given by b * (S*hidden_size) + s * hidden_size
kvp<T> threadData(0, 0);
for (int32_t it = threadIdx.x; it < ld; it += TPB) {
T p(mIdsEmbDev0[poffset + it]); // pos id
T val = p;
const int32_t offset = word_id[0] * ld;
val += mIdsEmbDev1[offset + it];
output[outOffset + it] = val;
skip[outOffset + it] = val;
const T rldval = rld * val;
threadData = pairSum(threadData, kvp<T>(rldval, rldval * val));
}
// 3. layer norm on the sum
layerNorm<T, T, float, TPB>(threadData, ld, outOffset, beta, gamma, output);
}
template <typename T, unsigned TPB>
__global__ void embLayerNormKernelMTron_3(int32_t ld,
int32_t const* inputIds0,
int32_t const* inputIds1,
int32_t const* inputIds2,
float const* beta,
float const* gamma,
T const* mIdsEmbDev0,
T const* mIdsEmbDev1,
T const* mIdsEmbDev2,
int32_t IdsSize0,
int32_t IdsSize1,
int32_t IdsSize2,
T* output,
T* skip) {
cub::Sum pairSum;
const int32_t s = blockIdx.x;
const int32_t b = blockIdx.y;
const int32_t sumS = inputIds0[b];
const int32_t s_b = inputIds0[b + 1] - sumS;
if (s >= s_b) {
return; // This CTA has nothing to do
}
const T rld = T(1.f) / T(ld);
const int32_t seqPos = sumS + s;
extern __shared__ int32_t word_id[];
if (threadIdx.x == 0) {
if (static_cast<int32_t const*>(inputIds1)[seqPos] < 0 ||
static_cast<int32_t const*>(inputIds1)[seqPos] >= IdsSize1) {
printf(
"Error!!!!!!(embLayerNormVarSeqlenPlugin): ID cannot be lookup "
"table: ID < 0 or ID > max ");
return;
} else {
word_id[0] = static_cast<int32_t const*>(inputIds1)[seqPos];
}
if (static_cast<int32_t const*>(inputIds2)[seqPos] < 0 ||
static_cast<int32_t const*>(inputIds2)[seqPos] >= IdsSize2) {
printf(
"Error!!!!!!(embLayerNormVarSeqlenPlugin): ID cannot be lookup "
"table: ID < 0 or ID > max ");
return;
} else {
word_id[1] = static_cast<int32_t const*>(inputIds2)[seqPos];
}
}
__syncthreads();
// 2. load pos/tok/word embeddings and add them together
// offset into embeddings is given by wordId * hidden_size
const int32_t poffset = blockIdx.x * ld;
const int32_t outOffset = seqPos * ld;
// the output offset is given by b * (S*hidden_size) + s * hidden_size
kvp<T> threadData(0, 0);
for (int32_t it = threadIdx.x; it < ld; it += TPB) {
T p(mIdsEmbDev0[poffset + it]); // pos id
T val = p;
const int32_t offset0 = word_id[0] * ld;
val += mIdsEmbDev1[offset0 + it];
const int32_t offset1 = word_id[1] * ld;
val += mIdsEmbDev2[offset1 + it];
output[outOffset + it] = val;
skip[outOffset + it] = val;
const T rldval = rld * val;
threadData = pairSum(threadData, kvp<T>(rldval, rldval * val));
}
// 3. layer norm on the sum
layerNorm<T, T, float, TPB>(threadData, ld, outOffset, beta, gamma, output);
}
template <typename T, unsigned TPB>
__global__ void embLayerNormKernelMTron_4(int32_t ld,
int32_t const* inputIds0,
int32_t const* inputIds1,
int32_t const* inputIds2,
int32_t const* inputIds3,
float const* beta,
float const* gamma,
T const* mIdsEmbDev0,
T const* mIdsEmbDev1,
T const* mIdsEmbDev2,
T const* mIdsEmbDev3,
int32_t IdsSize0,
int32_t IdsSize1,
int32_t IdsSize2,
int32_t IdsSize3,
T* output,
T* skip) {
cub::Sum pairSum;
const int32_t s = blockIdx.x;
const int32_t b = blockIdx.y;
const int32_t sumS = inputIds0[b];
const int32_t s_b = inputIds0[b + 1] - sumS;
if (s >= s_b) {
return; // This CTA has nothing to do
}
const T rld = T(1.f) / T(ld);
const int32_t seqPos = sumS + s;
extern __shared__ int32_t word_id[];
if (threadIdx.x == 0) {
if (static_cast<int32_t const*>(inputIds1)[seqPos] < 0 ||
static_cast<int32_t const*>(inputIds1)[seqPos] >= IdsSize1) {
printf(
"Error!!!!!!(embLayerNormVarSeqlenPlugin): ID cannot be lookup "
"table: ID < 0 or ID > max ");
return;
} else {
word_id[0] = static_cast<int32_t const*>(inputIds1)[seqPos];
}
if (static_cast<int32_t const*>(inputIds2)[seqPos] < 0 ||
static_cast<int32_t const*>(inputIds2)[seqPos] >= IdsSize2) {
printf(
"Error!!!!!!(embLayerNormVarSeqlenPlugin): ID cannot be lookup "
"table: ID < 0 or ID > max ");
return;
} else {
word_id[1] = static_cast<int32_t const*>(inputIds2)[seqPos];
}
if (static_cast<int32_t const*>(inputIds3)[seqPos] < 0 ||
static_cast<int32_t const*>(inputIds3)[seqPos] >= IdsSize3) {
printf(
"Error!!!!!!(embLayerNormVarSeqlenPlugin): ID cannot be lookup "
"table: ID < 0 or ID > max ");
return;
} else {
word_id[2] = static_cast<int32_t const*>(inputIds3)[seqPos];
}
}
__syncthreads();
// 2. load pos/tok/word embeddings and add them together
// offset into embeddings is given by wordId * hidden_size
const int32_t poffset = blockIdx.x * ld;
const int32_t outOffset = seqPos * ld;
// the output offset is given by b * (S*hidden_size) + s * hidden_size
kvp<T> threadData(0, 0);
for (int32_t it = threadIdx.x; it < ld; it += TPB) {
T p(mIdsEmbDev0[poffset + it]); // pos id
T val = p;
const int32_t offset0 = word_id[0] * ld;
val += mIdsEmbDev1[offset0 + it];
const int32_t offset1 = word_id[1] * ld;
val += mIdsEmbDev2[offset1 + it];
const int32_t offset2 = word_id[2] * ld;
val += mIdsEmbDev3[offset2 + it];
output[outOffset + it] = val;
skip[outOffset + it] = val;
const T rldval = rld * val;
threadData = pairSum(threadData, kvp<T>(rldval, rldval * val));
}
// 3. layer norm on the sum
layerNorm<T, T, float, TPB>(threadData, ld, outOffset, beta, gamma, output);
}
template <typename T>
int32_t embSkipLayerNormMTron_2(cudaStream_t stream,
int32_t ld,
int32_t B,
int32_t S,
int32_t const* inputIds0,
int32_t const* inputIds1,
int32_t nbLookupTables,
float const* beta,
float const* gamma,
T const* mIdsEmbDev0,
T const* mIdsEmbDev1,
int32_t IdsSize0,
int32_t IdsSize1,
T* output,
T* skip) {
constexpr int32_t tpb = 256;
dim3 const grid(S, B, 1);
dim3 const block(tpb, 1, 1);
size_t cache_size = sizeof(int32_t) * (nbLookupTables - 1);
embLayerNormKernelMTron_2<T, tpb>
<<<grid, block, cache_size, stream>>>(ld,
inputIds0,
inputIds1,
beta,
gamma,
mIdsEmbDev0,
mIdsEmbDev1,
IdsSize0,
IdsSize1,
output,
skip);
return cudaPeekAtLastError();
}
template <typename T>
int32_t embSkipLayerNormMTron_3(cudaStream_t stream,
int32_t ld,
int32_t B,
int32_t S,
int32_t const* inputIds0,
int32_t const* inputIds1,
int32_t const* inputIds2,
int32_t nbLookupTables,
float const* beta,
float const* gamma,
T const* mIdsEmbDev0,
T const* mIdsEmbDev1,
T const* mIdsEmbDev2,
int32_t IdsSize0,
int32_t IdsSize1,
int32_t IdsSize2,
T* output,
T* skip) {
constexpr int32_t tpb = 256;
dim3 const grid(S, B, 1);
dim3 const block(tpb, 1, 1);
size_t cache_size = sizeof(int32_t) * (nbLookupTables - 1);
embLayerNormKernelMTron_3<T, tpb>
<<<grid, block, cache_size, stream>>>(ld,
inputIds0,
inputIds1,
inputIds2,
beta,
gamma,
mIdsEmbDev0,
mIdsEmbDev1,
mIdsEmbDev2,
IdsSize0,
IdsSize1,
IdsSize2,
output,
skip);
return cudaPeekAtLastError();
}
template <typename T>
int32_t embSkipLayerNormMTron_4(cudaStream_t stream,
int32_t ld,
int32_t B,
int32_t S,
int32_t const* inputIds0,
int32_t const* inputIds1,
int32_t const* inputIds2,
int32_t const* inputIds3,
int32_t nbLookupTables,
float const* beta,
float const* gamma,
T const* mIdsEmbDev0,
T const* mIdsEmbDev1,
T const* mIdsEmbDev2,
T const* mIdsEmbDev3,
int32_t IdsSize0,
int32_t IdsSize1,
int32_t IdsSize2,
int32_t IdsSize3,
T* output,
T* skip) {
constexpr int32_t tpb = 256;
dim3 const grid(S, B, 1);
dim3 const block(tpb, 1, 1);
size_t cache_size = sizeof(int32_t) * (nbLookupTables - 1);
embLayerNormKernelMTron_4<T, tpb>
<<<grid, block, cache_size, stream>>>(ld,
inputIds0,
inputIds1,
inputIds2,
inputIds3,
beta,
gamma,
mIdsEmbDev0,
mIdsEmbDev1,
mIdsEmbDev2,
mIdsEmbDev3,
IdsSize0,
IdsSize1,
IdsSize2,
IdsSize3,
output,
skip);
return cudaPeekAtLastError();
}
template int32_t embSkipLayerNormMTron_2<float>(cudaStream_t,
int32_t,
int32_t,
int32_t,
int32_t const*,
int32_t const*,
int32_t,
float const*,
float const*,
float const*,
float const*,
int32_t,
int32_t,
float*,
float*);
template int32_t embSkipLayerNormMTron_3<float>(cudaStream_t,
int32_t,
int32_t,
int32_t,
int32_t const*,
int32_t const*,
int32_t const*,
int32_t,
float const*,
float const*,
float const*,
float const*,
float const*,
int32_t,
int32_t,
int32_t,
float*,
float*);
template int32_t embSkipLayerNormMTron_4<float>(cudaStream_t,
int32_t,
int32_t,
int32_t,
int32_t const*,
int32_t const*,
int32_t const*,
int32_t const*,
int32_t,
float const*,
float const*,
float const*,
float const*,
float const*,
float const*,
int32_t,
int32_t,
int32_t,
int32_t,
float*,
float*);
template int32_t embSkipLayerNormMTron_2<half>(cudaStream_t,
int32_t,
int32_t,
int32_t,
int32_t const*,
int32_t const*,
int32_t,
float const*,
float const*,
half const*,
half const*,
int32_t,
int32_t,
half*,
half*);
template int32_t embSkipLayerNormMTron_3<half>(cudaStream_t,
int32_t,
int32_t,
int32_t,
int32_t const*,
int32_t const*,
int32_t const*,
int32_t,
float const*,
float const*,
half const*,
half const*,
half const*,
int32_t,
int32_t,
int32_t,
half*,
half*);
template int32_t embSkipLayerNormMTron_4<half>(cudaStream_t,
int32_t,
int32_t,
int32_t,
int32_t const*,
int32_t const*,
int32_t const*,
int32_t const*,
int32_t,
float const*,
float const*,
half const*,
half const*,
half const*,
half const*,
int32_t,
int32_t,
int32_t,
int32_t,
half*,
half*);
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,909 @@
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
// SPDX-FileCopyrightText: Copyright (c) 1993-2022 NVIDIA CORPORATION &
// AFFILIATES. 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/plugin/many_emb_layernorm_varseqlen_plugin.h"
#include <cuda.h>
#include <cstring>
#include <vector>
#include "NvInfer.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
constexpr size_t threadsPerCta128 = 2 * 2 * 32;
constexpr size_t threadsPerCta256 = 1 * 4 * 32;
constexpr size_t threadsPerCta384 = 1 * 8 * 32;
// The number of xmmas in the M dimension. We use one uint32_t per XMMA in the M
// dimension: (s + 16*warps_m - 1) / (16*warps_m);
constexpr size_t xmmasM128 = 4;
constexpr size_t xmmasM256 = 16;
constexpr size_t xmmasM384 = 24;
// Packed mask size per batch. Layout is XMMAS_M * THREADS_PER_CTA.
constexpr size_t packedMaskSize128 = xmmasM128 * threadsPerCta128;
constexpr size_t packedMaskSize256 = xmmasM256 * threadsPerCta256;
constexpr size_t packedMaskSize384 = xmmasM384 * threadsPerCta384;
char const* EMB_LAYER_NORM_VAR_SEQLEN_VERSION_HFACE{"1"};
char const* EMB_LAYER_NORM_VAR_SEQLEN_VERSION_MTRON{"2"};
char const* EMB_LAYER_NORM_VAR_SEQLEN_NAME{
"ManyEmbLayerNormVarlenPluginDynamic"};
// Static class fields initialization
nvinfer1::PluginFieldCollection EmbLayerNormVarSeqlenPluginBaseCreator::mFC{};
std::vector<nvinfer1::PluginField>
EmbLayerNormVarSeqlenPluginBaseCreator::mPluginAttributes;
EmbLayerNormVarSeqlenPluginBase::EmbLayerNormVarSeqlenPluginBase(
std::string const& name,
nvinfer1::DataType const type,
nvinfer1::Weights const& beta,
nvinfer1::Weights const& gamma,
const std::vector<nvinfer1::Weights>& IdsEmb)
: mLayerName(name),
mLd(beta.count),
mType(type),
mIdsEmb_(IdsEmb),
nbLookupTables_(static_cast<int>(IdsEmb.size())) {
// Assuming Weights.count is the number of elements and not bytes
assert(beta.count == gamma.count);
mBeta.convertAndCopy(beta, nvinfer1::DataType::kFLOAT);
mGamma.convertAndCopy(gamma, nvinfer1::DataType::kFLOAT);
copyToDevice(&mGamma, sizeof(float) * mGamma.count, &mGammaDev);
copyToDevice(&mBeta, sizeof(float) * mBeta.count, &mBetaDev);
for (size_t i = 0; i < mIdsEmb_.size(); ++i) {
assert(mIdsEmb_[i].count % mLd == 0);
mIdsVocabSize.push_back(int32_t(mIdsEmb_[i].count / mLd));
WeightsWithOwnership tem_weight;
tem_weight.convertAndCopy(mIdsEmb_[i], mType);
void* cudaMem{nullptr};
PADDLE_ENFORCE_GPU_SUCCESS(
cudaMalloc(&cudaMem, getWeightsSize(tem_weight, mType)));
PADDLE_ENFORCE_GPU_SUCCESS(cudaMemcpy(cudaMem,
tem_weight.values,
getWeightsSize(tem_weight, mType),
cudaMemcpyHostToDevice));
mIdsEmbPtrs.push_back(cudaMem);
}
}
EmbLayerNormVarSeqlenPluginBase::EmbLayerNormVarSeqlenPluginBase(
std::string const& name, void const* data, size_t length)
: mLayerName(name),
mGammaDev(nullptr),
mBetaDev(nullptr),
mIdsEmbPtrs{},
mIdsEmb_{} {
// Deserialize in the same order as serialization
deserialize_value(&data, &length, &mType);
deserialize_value(&data, &length, &mLd);
deserialize_value(&data, &length, &nbLookupTables_);
for (int32_t i = 0; i < nbLookupTables_; ++i) {
int32_t tem;
deserialize_value(&data, &length, &tem);
mIdsVocabSize.push_back(tem);
}
char const* d = static_cast<char const*>(data);
mBeta.convertAndCopy(&d, mLd, nvinfer1::DataType::kFLOAT);
mGamma.convertAndCopy(&d, mLd, nvinfer1::DataType::kFLOAT);
for (int32_t i = 0; i < nbLookupTables_; ++i) {
nvinfer1::Weights pre_tem_weight;
pre_tem_weight.type = mType;
pre_tem_weight.count = mLd * size_t(mIdsVocabSize[i]);
const auto nbBytes = mLd * size_t(mIdsVocabSize[i]) * getElementSize(mType);
auto destBuf = new char[nbBytes];
pre_tem_weight.values = destBuf;
std::copy_n(d, nbBytes, destBuf);
d += nbBytes;
mIdsEmb_.push_back(pre_tem_weight);
}
}
EmbLayerNormVarSeqlenPluginHFace::EmbLayerNormVarSeqlenPluginHFace(
std::string const& name,
nvinfer1::DataType const type,
nvinfer1::Weights const& beta,
nvinfer1::Weights const& gamma,
const std::vector<nvinfer1::Weights>& IdsEmb)
: EmbLayerNormVarSeqlenPluginBase(name, type, beta, gamma, IdsEmb) {}
EmbLayerNormVarSeqlenPluginHFace::EmbLayerNormVarSeqlenPluginHFace(
std::string const& name, void const* data, size_t length)
: EmbLayerNormVarSeqlenPluginBase(name, data, length) {
TRANSFORMER_DEBUG_MSG("EmbLayerNormVarSeqlenPluginHFace deserialize");
}
EmbLayerNormVarSeqlenPluginMTron::EmbLayerNormVarSeqlenPluginMTron(
std::string const& name,
nvinfer1::DataType const type,
nvinfer1::Weights const& beta,
nvinfer1::Weights const& gamma,
const std::vector<nvinfer1::Weights>& IdsEmb)
: EmbLayerNormVarSeqlenPluginBase(name, type, beta, gamma, IdsEmb) {}
EmbLayerNormVarSeqlenPluginMTron::EmbLayerNormVarSeqlenPluginMTron(
std::string const& name, void const* data, size_t length)
: EmbLayerNormVarSeqlenPluginBase(name, data, length) {
TRANSFORMER_DEBUG_MSG("EmbLayerNormVarSeqlenPluginMTron deserialize");
}
// IPluginV2DynamicExt Methods
nvinfer1::IPluginV2DynamicExt* EmbLayerNormVarSeqlenPluginHFace::clone()
const noexcept {
TRANSFORMER_DEBUG_MSG("EmbLayerNormVarSeqlenPluginHFace clone");
auto p = new EmbLayerNormVarSeqlenPluginHFace(
mLayerName, mType, mBeta, mGamma, mIdsEmb_);
p->setPluginNamespace(mNamespace.c_str());
return p;
}
nvinfer1::IPluginV2DynamicExt* EmbLayerNormVarSeqlenPluginMTron::clone()
const noexcept {
TRANSFORMER_DEBUG_MSG("EmbLayerNormVarSeqlenPluginMTron clone");
auto p = new EmbLayerNormVarSeqlenPluginMTron(
mLayerName, mType, mBeta, mGamma, mIdsEmb_);
p->setPluginNamespace(mNamespace.c_str());
return p;
}
nvinfer1::DimsExprs EmbLayerNormVarSeqlenPluginHFace::getOutputDimensions(
int32_t outputIndex,
nvinfer1::DimsExprs const* inputs,
int32_t nbInputs,
nvinfer1::IExprBuilder& exprBuilder) noexcept {
for (int i = 1; i < nbInputs - 1; ++i) {
assert(inputs[i].nbDims == 1); // seq length
assert(inputs[i].nbDims == inputs[1].nbDims); // same shape
}
assert(inputs[0].nbDims == 1); // pos_id: B+1
if (outputIndex == 0) {
nvinfer1::DimsExprs ret;
ret.nbDims = 4;
ret.d[0] = inputs[1].d[0]; // sum of seq length
ret.d[1] = exprBuilder.constant(mLd);
ret.d[2] = exprBuilder.constant(1);
ret.d[3] = exprBuilder.constant(1);
return ret;
} else if (outputIndex == 1) {
// This is a hack: we just report some mask size and rely the plugins to
// play nicely together.
// At runtime, depending on the actual maxSeqlen, the size might be
// different.
int32_t maskSize_ = packedMaskSize384;
auto maskSize = exprBuilder.constant(maskSize_);
auto fp16maskSize =
exprBuilder.operation(nvinfer1::DimensionOperation::kPROD,
*maskSize,
*exprBuilder.constant(2));
auto Bplus1 = inputs[0].d[0]; // pos_id
auto one = exprBuilder.constant(1);
auto B = exprBuilder.operation(
nvinfer1::DimensionOperation::kSUB, *Bplus1, *one);
nvinfer1::DimsExprs ret;
ret.nbDims = 2;
ret.d[0] = B;
ret.d[1] = fp16maskSize;
return ret;
} else {
nvinfer1::DimsExprs ret;
ret.nbDims = 1;
ret.d[0] = inputs[nbInputs - 1].d[1]; // mask id: max seqlen
return ret;
}
}
nvinfer1::DimsExprs EmbLayerNormVarSeqlenPluginMTron::getOutputDimensions(
int32_t outputIndex,
nvinfer1::DimsExprs const* inputs,
int32_t nbInputs,
nvinfer1::IExprBuilder& exprBuilder) noexcept {
// Input should be input ids and token ids and cumulative seqlens
// Output should be the embeddings tensor and mask indices
for (int i = 1; i < nbInputs - 1; ++i) {
assert(inputs[i].nbDims == 1); // seq length
assert(inputs[i].nbDims == inputs[1].nbDims); // same shape
}
assert(inputs[0].nbDims == 1); // pos_id: B+1
if (outputIndex == 0 || outputIndex == 1) {
nvinfer1::DimsExprs ret;
ret.nbDims = 4;
ret.d[0] = inputs[1].d[0]; // sum of seq length
ret.d[1] = exprBuilder.constant(mLd);
ret.d[2] = exprBuilder.constant(1);
ret.d[3] = exprBuilder.constant(1);
return ret;
} else {
nvinfer1::DimsExprs ret;
ret.nbDims = 1;
ret.d[0] = inputs[nbInputs - 1].d[1]; // mask id: max seqlen
return ret;
}
}
bool EmbLayerNormVarSeqlenPluginBase::supportsFormatCombination(
int32_t pos,
nvinfer1::PluginTensorDesc const* inOut,
int32_t nbInputs,
int32_t nbOutputs) noexcept {
assert(nbOutputs == 3);
nvinfer1::PluginTensorDesc const& desc = inOut[pos];
if (desc.format != nvinfer1::TensorFormat::kLINEAR) {
return false;
}
if (pos == 0) { // pos_id
return desc.dims.nbDims == 1 && desc.type == nvinfer1::DataType::kINT32;
}
if (pos == 1) { // input_id
return desc.dims.nbDims == 1 && desc.type == nvinfer1::DataType::kINT32;
}
nvinfer1::PluginTensorDesc const& prev = inOut[1]; // input_ids
if (1 < pos &&
pos < (nbInputs - 1)) { // other ids: check it's the same as input_ids
return desc.type == prev.type && desc.dims.nbDims == 1 &&
desc.dims.d[0] == prev.dims.d[0];
}
if (pos == nbInputs - 1) { // mask id
return desc.type == mType;
}
// embedded sequence
if (pos == nbInputs) {
return desc.type == mType && desc.dims.nbDims == 4 &&
desc.dims.d[0] == inOut[1].dims.d[0] && desc.dims.d[2] == 1 &&
desc.dims.d[3] == 1;
}
// mask(HFace) or pre_layernorm_bias(MTron)
if (pos == nbInputs + 1) {
return desc.type == mType;
}
// max seqlen
if (pos == nbInputs + 2) {
return desc.type == mType;
}
}
void checkConfigurationInputs(nvinfer1::DynamicPluginTensorDesc const* inputs,
int32_t nbInputs,
nvinfer1::DynamicPluginTensorDesc const* outputs,
int32_t nbOutputs) noexcept {
// Validate input arguments
assert(nbOutputs == 3);
assert(inputs[0].desc.dims.nbDims == 1);
assert(inputs[0].desc.type == nvinfer1::DataType::kINT32);
for (int i = 1; i < nbInputs - 1; ++i) {
assert(inputs[i].desc.dims.nbDims == 1);
assert(inputs[i].desc.dims.d[0] == inputs[1].desc.dims.d[0]);
assert(inputs[i].desc.type == nvinfer1::DataType::kINT32);
}
assert(outputs[0].desc.dims.nbDims == 4);
assert(static_cast<size_t>(outputs[0].desc.dims.d[0]) ==
static_cast<size_t>(inputs[1].desc.dims.d[0]));
assert(outputs[0].desc.dims.d[2] == 1);
assert(outputs[0].desc.dims.d[3] == 1);
}
void EmbLayerNormVarSeqlenPluginHFace::configurePlugin(
nvinfer1::DynamicPluginTensorDesc const* inputs,
int32_t nbInputs,
nvinfer1::DynamicPluginTensorDesc const* outputs,
int32_t nbOutputs) noexcept {
TRANSFORMER_DEBUG_MSG("EmbLayerNormVarSeqlenPluginHFace configurePlugin");
checkConfigurationInputs(inputs, nbInputs, outputs, nbOutputs);
assert(static_cast<size_t>(outputs[0].desc.dims.d[1]) ==
static_cast<size_t>(mLd));
int32_t const B = inputs[0].desc.dims.d[0] - 1;
// check mask
assert(outputs[1].desc.dims.nbDims == 2);
if (B > 0) {
assert(outputs[1].desc.dims.d[0] == B);
}
assert((outputs[1].desc.dims.d[1] == 2 * packedMaskSize384) ||
(outputs[1].desc.dims.d[1] == 2 * packedMaskSize128) ||
(outputs[1].desc.dims.d[1] == 2 * packedMaskSize256));
assert(outputs[0].desc.type == mType);
assert(outputs[1].desc.type == nvinfer1::DataType::kHALF);
}
void EmbLayerNormVarSeqlenPluginMTron::configurePlugin(
nvinfer1::DynamicPluginTensorDesc const* inputs,
int32_t nbInputs,
nvinfer1::DynamicPluginTensorDesc const* outputs,
int32_t nbOutputs) noexcept {
TRANSFORMER_DEBUG_MSG("EmbLayerNormVarSeqlenPluginMTron configurePlugin");
checkConfigurationInputs(inputs, nbInputs, outputs, nbOutputs);
assert(static_cast<size_t>(outputs[0].desc.dims.d[1]) ==
static_cast<size_t>(mLd));
assert(outputs[1].desc.dims.nbDims == 4);
assert(static_cast<size_t>(outputs[1].desc.dims.d[0]) ==
static_cast<size_t>(inputs[1].desc.dims.d[0]));
assert(static_cast<size_t>(outputs[1].desc.dims.d[1]) ==
static_cast<size_t>(mLd));
assert(outputs[1].desc.dims.d[2] == 1);
assert(outputs[1].desc.dims.d[3] == 1);
assert(outputs[0].desc.type == mType);
assert(outputs[1].desc.type == mType);
}
size_t EmbLayerNormVarSeqlenPluginBase::getWorkspaceSize(
nvinfer1::PluginTensorDesc const* inputs,
int32_t nbInputs,
nvinfer1::PluginTensorDesc const* outputs,
int32_t nbOutputs) const noexcept {
return 0;
}
int32_t EmbLayerNormVarSeqlenPluginHFace::enqueue(
nvinfer1::PluginTensorDesc const* inputDesc,
nvinfer1::PluginTensorDesc const* outputDesc,
void const* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) noexcept {
int32_t batchSize = inputDesc[0].dims.d[0] - 1;
// read out the maximum sequence length from the dummy input
int32_t const maxSeqlen = inputDesc[nbLookupTables_].dims.d[1];
int32_t S = 512;
if (maxSeqlen <= 128) {
S = 128;
} else if (maxSeqlen <= 192) {
S = 192;
} else if (maxSeqlen <= 256) {
S = 256;
} else if (maxSeqlen <= 384) {
S = 384;
} else if (maxSeqlen <= 512) {
S = 512;
} else {
std::cerr << "fused_embedding_eltwise_layernorm'max sequence lengths is "
"512 for VarSeqlen"
<< std::endl;
}
const float* beta = mBetaDev.get();
const float* gamma = mGammaDev.get();
if (mType == nvinfer1::DataType::kFLOAT) {
auto output = static_cast<float*>(outputs[0]);
if (nbLookupTables_ == 2) {
return embSkipLayerNormHFace_2<float>(
stream,
static_cast<int32_t>(mLd),
batchSize,
S,
static_cast<int32_t const*>(inputs[0]),
static_cast<int32_t const*>(inputs[1]),
nbLookupTables_,
beta,
gamma,
static_cast<float const*>(mIdsEmbPtrs[0]),
static_cast<float const*>(mIdsEmbPtrs[1]),
mIdsVocabSize[0],
mIdsVocabSize[1],
output);
} else if (nbLookupTables_ == 3) {
return embSkipLayerNormHFace_3<float>(
stream,
static_cast<int32_t>(mLd),
batchSize,
S,
static_cast<int32_t const*>(inputs[0]),
static_cast<int32_t const*>(inputs[1]),
static_cast<int32_t const*>(inputs[2]),
nbLookupTables_,
beta,
gamma,
static_cast<float const*>(mIdsEmbPtrs[0]),
static_cast<float const*>(mIdsEmbPtrs[1]),
static_cast<float const*>(mIdsEmbPtrs[2]),
mIdsVocabSize[0],
mIdsVocabSize[1],
mIdsVocabSize[2],
output);
} else if (nbLookupTables_ == 4) {
return embSkipLayerNormHFace_4<float>(
stream,
static_cast<int32_t>(mLd),
batchSize,
S,
static_cast<int32_t const*>(inputs[0]),
static_cast<int32_t const*>(inputs[1]),
static_cast<int32_t const*>(inputs[2]),
static_cast<int32_t const*>(inputs[3]),
nbLookupTables_,
beta,
gamma,
static_cast<float const*>(mIdsEmbPtrs[0]),
static_cast<float const*>(mIdsEmbPtrs[1]),
static_cast<float const*>(mIdsEmbPtrs[2]),
static_cast<float const*>(mIdsEmbPtrs[3]),
mIdsVocabSize[0],
mIdsVocabSize[1],
mIdsVocabSize[2],
mIdsVocabSize[3],
output);
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"Only support 2,3,4 lookup_tables fused "));
}
} else if (mType == nvinfer1::DataType::kHALF) {
auto output = static_cast<half*>(outputs[0]);
if (nbLookupTables_ == 2) {
return embSkipLayerNormHFace_2<half>(
stream,
static_cast<int32_t>(mLd),
batchSize,
S,
static_cast<int32_t const*>(inputs[0]),
static_cast<int32_t const*>(inputs[1]),
nbLookupTables_,
beta,
gamma,
static_cast<half const*>(mIdsEmbPtrs[0]),
static_cast<half const*>(mIdsEmbPtrs[1]),
mIdsVocabSize[0],
mIdsVocabSize[1],
output);
} else if (nbLookupTables_ == 3) {
return embSkipLayerNormHFace_3<half>(
stream,
static_cast<int32_t>(mLd),
batchSize,
S,
static_cast<int32_t const*>(inputs[0]),
static_cast<int32_t const*>(inputs[1]),
static_cast<int32_t const*>(inputs[2]),
nbLookupTables_,
beta,
gamma,
static_cast<half const*>(mIdsEmbPtrs[0]),
static_cast<half const*>(mIdsEmbPtrs[1]),
static_cast<half const*>(mIdsEmbPtrs[2]),
mIdsVocabSize[0],
mIdsVocabSize[1],
mIdsVocabSize[2],
output);
} else if (nbLookupTables_ == 4) {
return embSkipLayerNormHFace_4<half>(
stream,
static_cast<int32_t>(mLd),
batchSize,
S,
static_cast<int32_t const*>(inputs[0]),
static_cast<int32_t const*>(inputs[1]),
static_cast<int32_t const*>(inputs[2]),
static_cast<int32_t const*>(inputs[3]),
nbLookupTables_,
beta,
gamma,
static_cast<half const*>(mIdsEmbPtrs[0]),
static_cast<half const*>(mIdsEmbPtrs[1]),
static_cast<half const*>(mIdsEmbPtrs[2]),
static_cast<half const*>(mIdsEmbPtrs[3]),
mIdsVocabSize[0],
mIdsVocabSize[1],
mIdsVocabSize[2],
mIdsVocabSize[3],
output);
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"Only support 2,3,4 lookup_tables fused "));
}
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"Unsupported type error, expected [kHALF,kFLOAT]"));
}
return STATUS_SUCCESS;
}
int32_t EmbLayerNormVarSeqlenPluginMTron::enqueue(
nvinfer1::PluginTensorDesc const* inputDesc,
nvinfer1::PluginTensorDesc const* outputDesc,
void const* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) noexcept {
int32_t batchSize = inputDesc[0].dims.d[0] - 1;
// read out the maximum sequence length from the dummy input
int32_t const maxSeqlen = inputDesc[nbLookupTables_].dims.d[1];
int32_t S = 512;
if (maxSeqlen <= 128) {
S = 128;
} else if (maxSeqlen <= 192) {
S = 192;
} else if (maxSeqlen <= 256) {
S = 256;
} else if (maxSeqlen <= 384) {
S = 384;
} else if (maxSeqlen <= 512) {
S = 512;
} else {
std::cerr << "fused_embedding_eltwise_layernorm'max sequence lengths is "
"512 for VarSeqlen"
<< std::endl;
}
const float* beta = mBetaDev.get();
const float* gamma = mGammaDev.get();
if (mType == nvinfer1::DataType::kFLOAT) {
auto output = static_cast<float*>(outputs[0]);
auto skip = static_cast<float*>(outputs[1]);
if (nbLookupTables_ == 2) {
return embSkipLayerNormMTron_2<float>(
stream,
static_cast<int32_t>(mLd),
batchSize,
S,
static_cast<int32_t const*>(inputs[0]),
static_cast<int32_t const*>(inputs[1]),
nbLookupTables_,
beta,
gamma,
static_cast<float const*>(mIdsEmbPtrs[0]),
static_cast<float const*>(mIdsEmbPtrs[1]),
mIdsVocabSize[0],
mIdsVocabSize[1],
output,
skip);
} else if (nbLookupTables_ == 3) {
return embSkipLayerNormMTron_3<float>(
stream,
static_cast<int32_t>(mLd),
batchSize,
S,
static_cast<int32_t const*>(inputs[0]),
static_cast<int32_t const*>(inputs[1]),
static_cast<int32_t const*>(inputs[2]),
nbLookupTables_,
beta,
gamma,
static_cast<float const*>(mIdsEmbPtrs[0]),
static_cast<float const*>(mIdsEmbPtrs[1]),
static_cast<float const*>(mIdsEmbPtrs[2]),
mIdsVocabSize[0],
mIdsVocabSize[1],
mIdsVocabSize[2],
output,
skip);
} else if (nbLookupTables_ == 4) {
return embSkipLayerNormMTron_4<float>(
stream,
static_cast<int32_t>(mLd),
batchSize,
S,
static_cast<int32_t const*>(inputs[0]),
static_cast<int32_t const*>(inputs[1]),
static_cast<int32_t const*>(inputs[2]),
static_cast<int32_t const*>(inputs[3]),
nbLookupTables_,
beta,
gamma,
static_cast<float const*>(mIdsEmbPtrs[0]),
static_cast<float const*>(mIdsEmbPtrs[1]),
static_cast<float const*>(mIdsEmbPtrs[2]),
static_cast<float const*>(mIdsEmbPtrs[3]),
mIdsVocabSize[0],
mIdsVocabSize[1],
mIdsVocabSize[2],
mIdsVocabSize[3],
output,
skip);
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"Only support 2,3,4 lookup_tables fused "));
}
} else if (mType == nvinfer1::DataType::kHALF) {
auto output = static_cast<half*>(outputs[0]);
auto skip = static_cast<half*>(outputs[1]);
if (nbLookupTables_ == 2) {
return embSkipLayerNormMTron_2<half>(
stream,
static_cast<int32_t>(mLd),
batchSize,
S,
static_cast<int32_t const*>(inputs[0]),
static_cast<int32_t const*>(inputs[1]),
nbLookupTables_,
beta,
gamma,
static_cast<half const*>(mIdsEmbPtrs[0]),
static_cast<half const*>(mIdsEmbPtrs[1]),
mIdsVocabSize[0],
mIdsVocabSize[1],
output,
skip);
} else if (nbLookupTables_ == 3) {
return embSkipLayerNormMTron_3<half>(
stream,
static_cast<int32_t>(mLd),
batchSize,
S,
static_cast<int32_t const*>(inputs[0]),
static_cast<int32_t const*>(inputs[1]),
static_cast<int32_t const*>(inputs[2]),
nbLookupTables_,
beta,
gamma,
static_cast<half const*>(mIdsEmbPtrs[0]),
static_cast<half const*>(mIdsEmbPtrs[1]),
static_cast<half const*>(mIdsEmbPtrs[2]),
mIdsVocabSize[0],
mIdsVocabSize[1],
mIdsVocabSize[2],
output,
skip);
} else if (nbLookupTables_ == 4) {
return embSkipLayerNormMTron_4<half>(
stream,
static_cast<int32_t>(mLd),
batchSize,
S,
static_cast<int32_t const*>(inputs[0]),
static_cast<int32_t const*>(inputs[1]),
static_cast<int32_t const*>(inputs[2]),
static_cast<int32_t const*>(inputs[3]),
nbLookupTables_,
beta,
gamma,
static_cast<half const*>(mIdsEmbPtrs[0]),
static_cast<half const*>(mIdsEmbPtrs[1]),
static_cast<half const*>(mIdsEmbPtrs[2]),
static_cast<half const*>(mIdsEmbPtrs[3]),
mIdsVocabSize[0],
mIdsVocabSize[1],
mIdsVocabSize[2],
mIdsVocabSize[3],
output,
skip);
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"Only support 2,3,4 lookup_tables fused "));
}
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"Unsupported type error, expected [kHALF,kFLOAT]"));
}
return STATUS_SUCCESS;
}
// IPluginV2Ext Methods
nvinfer1::DataType EmbLayerNormVarSeqlenPluginBase::getOutputDataType(
int32_t index,
nvinfer1::DataType const* inputTypes,
int32_t nbInputs) const noexcept {
assert(index == 0 || index == 1);
if (index == 0) {
assert(mType == nvinfer1::DataType::kHALF ||
mType == nvinfer1::DataType::kFLOAT);
return mType;
}
return nvinfer1::DataType::kHALF;
}
// IPluginV2 Methods
char const* EmbLayerNormVarSeqlenPluginBase::getPluginType() const noexcept {
return EMB_LAYER_NORM_VAR_SEQLEN_NAME;
}
char const* EmbLayerNormVarSeqlenPluginHFace::getPluginVersion()
const noexcept {
return EMB_LAYER_NORM_VAR_SEQLEN_VERSION_HFACE;
}
char const* EmbLayerNormVarSeqlenPluginMTron::getPluginVersion()
const noexcept {
return EMB_LAYER_NORM_VAR_SEQLEN_VERSION_MTRON;
}
int32_t EmbLayerNormVarSeqlenPluginBase::getNbOutputs() const noexcept {
return 3;
}
int32_t EmbLayerNormVarSeqlenPluginHFace::initialize() noexcept {
TRANSFORMER_DEBUG_MSG("EmbLayerNormVarSeqlenPluginHFace initialize");
return 0;
}
int32_t EmbLayerNormVarSeqlenPluginMTron::initialize() noexcept {
TRANSFORMER_DEBUG_MSG("EmbLayerNormVarSeqlenPluginMTron initialize");
return 0;
}
void EmbLayerNormVarSeqlenPluginHFace::terminate() noexcept {
TRANSFORMER_DEBUG_MSG("EmbLayerNormVarSeqlenPluginHFace terminate");
}
void EmbLayerNormVarSeqlenPluginMTron::terminate() noexcept {
TRANSFORMER_DEBUG_MSG("EmbLayerNormVarSeqlenPluginMTron terminate");
}
size_t EmbLayerNormVarSeqlenPluginBase::getSerializationSize() const noexcept {
size_t const wordSize = getElementSize(mType);
return 2 * sizeof(float) * mLd // beta + gamma
+ sizeof(mType) //
+ sizeof(mLd) //
+ mIdsVocabSize.size() * sizeof(mIdsVocabSize[0]) //
+ wordSize * mLd *
accumulate(
mIdsVocabSize.begin(), mIdsVocabSize.end(), 0) // ids emb
+ sizeof(nbLookupTables_); // numbers of lookup_table
}
void EmbLayerNormVarSeqlenPluginBase::serialize(void* buffer) const noexcept {
serialize_value(&buffer, mType);
serialize_value(&buffer, mLd);
serialize_value(&buffer, nbLookupTables_);
for (size_t i = 0; i < mIdsVocabSize.size(); ++i) {
serialize_value(&buffer, mIdsVocabSize[i]);
}
char* d = static_cast<char*>(buffer);
size_t const wordSize = getElementSize(mType);
serFromDev(&d, mBetaDev.get(), mLd);
serFromDev(&d, mGammaDev.get(), mLd);
for (size_t i = 0; i < mIdsEmbPtrs.size(); ++i) {
serFromDev(&d,
static_cast<char*>(mIdsEmbPtrs[i]),
mLd * mIdsVocabSize[i] * wordSize);
}
}
void EmbLayerNormVarSeqlenPluginBase::destroy() noexcept {
// This gets called when the network containing plugin is destroyed
mBetaDev.reset(nullptr);
mGammaDev.reset(nullptr);
for (size_t i = 0; i < mIdsEmbPtrs.size(); ++i) {
cudaFree(mIdsEmbPtrs[i]);
}
delete this;
}
void EmbLayerNormVarSeqlenPluginHFace::destroy() noexcept {
TRANSFORMER_DEBUG_MSG("EmbLayerNormVarSeqlenPluginHFace destroy");
EmbLayerNormVarSeqlenPluginBase::destroy();
}
void EmbLayerNormVarSeqlenPluginMTron::destroy() noexcept {
TRANSFORMER_DEBUG_MSG("EmbLayerNormVarSeqlenPluginMTron destroy");
EmbLayerNormVarSeqlenPluginBase::destroy();
}
void EmbLayerNormVarSeqlenPluginBase::setPluginNamespace(
char const* libNamespace) noexcept {
mNamespace = libNamespace;
}
char const* EmbLayerNormVarSeqlenPluginBase::getPluginNamespace()
const noexcept {
return mNamespace.c_str();
}
EmbLayerNormVarSeqlenPluginBaseCreator::
EmbLayerNormVarSeqlenPluginBaseCreator() = default;
char const* EmbLayerNormVarSeqlenPluginBaseCreator::getPluginName()
const noexcept {
return EMB_LAYER_NORM_VAR_SEQLEN_NAME;
}
char const* EmbLayerNormVarSeqlenPluginHFaceCreator::getPluginVersion()
const noexcept {
return EMB_LAYER_NORM_VAR_SEQLEN_VERSION_HFACE;
}
char const* EmbLayerNormVarSeqlenPluginMTronCreator::getPluginVersion()
const noexcept {
return EMB_LAYER_NORM_VAR_SEQLEN_VERSION_MTRON;
}
nvinfer1::PluginFieldCollection const*
EmbLayerNormVarSeqlenPluginBaseCreator::getFieldNames() noexcept {
return &mFC;
}
bool initializeFields(nvinfer1::PluginFieldCollection const* fc,
nvinfer1::Weights* beta,
nvinfer1::Weights* gamma,
std::vector<nvinfer1::Weights>* IdsEmb) {
bool output_fp16 = false;
for (int32_t i = 0; i < fc->nbFields; i++) {
std::string field_name(fc->fields[i].name);
if (field_name.compare("bert_embeddings_layernorm_beta") == 0) {
TRANSFORMER_DEBUG_MSG("Building bert_embeddings_layernorm_beta...");
beta->values = fc->fields[i].data;
beta->count = fc->fields[i].length;
beta->type = fieldTypeToDataType(fc->fields[i].type);
}
if (field_name.compare("bert_embeddings_layernorm_gamma") == 0) {
TRANSFORMER_DEBUG_MSG("Building bert_embeddings_layernorm_gamma...");
gamma->values = fc->fields[i].data;
gamma->count = fc->fields[i].length;
gamma->type = fieldTypeToDataType(fc->fields[i].type);
}
if (field_name.compare("output_fp16") == 0) {
TRANSFORMER_DEBUG_MSG("Building output_fp16...");
assert(fc->fields[i].type == nvinfer1::PluginFieldType::kINT32);
output_fp16 = static_cast<int32_t const*>(fc->fields[i].data)[0] != 0;
}
if (field_name.compare("bert_embeddings_word_embeddings_" +
std::to_string(i - 3)) == 0) {
TRANSFORMER_DEBUG_MSG(
("bert_embeddings_word_embeddings_" + std::to_string(i - 3)).c_str());
nvinfer1::Weights tem;
tem.values = fc->fields[i].data;
tem.count = fc->fields[i].length;
tem.type = fieldTypeToDataType(fc->fields[i].type);
IdsEmb->push_back(tem);
}
}
return output_fp16;
}
nvinfer1::IPluginV2* EmbLayerNormVarSeqlenPluginHFaceCreator::createPlugin(
char const* name, nvinfer1::PluginFieldCollection const* fc) noexcept {
TRANSFORMER_DEBUG_MSG("EmbLayerNormVarSeqlenHFace createPlugin");
nvinfer1::Weights beta;
nvinfer1::Weights gamma;
std::vector<nvinfer1::Weights> IdsEmb;
bool output_fp16 = initializeFields(fc, &beta, &gamma, &IdsEmb);
TRANSFORMER_DEBUG_MSG("Building the Plugin...");
EmbLayerNormVarSeqlenPluginHFace* p = new EmbLayerNormVarSeqlenPluginHFace(
name,
output_fp16 ? nvinfer1::DataType::kHALF : nvinfer1::DataType::kFLOAT,
beta,
gamma,
IdsEmb);
return p;
}
nvinfer1::IPluginV2* EmbLayerNormVarSeqlenPluginMTronCreator::createPlugin(
char const* name, nvinfer1::PluginFieldCollection const* fc) noexcept {
TRANSFORMER_DEBUG_MSG("EmbLayerNormVarSeqlenMTron createPlugin");
nvinfer1::Weights beta;
nvinfer1::Weights gamma;
std::vector<nvinfer1::Weights> IdsEmb;
bool output_fp16 = initializeFields(fc, &beta, &gamma, &IdsEmb);
TRANSFORMER_DEBUG_MSG("Building the Plugin...");
EmbLayerNormVarSeqlenPluginMTron* p = new EmbLayerNormVarSeqlenPluginMTron(
name,
output_fp16 ? nvinfer1::DataType::kHALF : nvinfer1::DataType::kFLOAT,
beta,
gamma,
IdsEmb);
return p;
}
nvinfer1::IPluginV2* EmbLayerNormVarSeqlenPluginHFaceCreator::deserializePlugin(
char const* name, void const* serialData, size_t serialLength) noexcept {
return new EmbLayerNormVarSeqlenPluginHFace(name, serialData, serialLength);
}
nvinfer1::IPluginV2* EmbLayerNormVarSeqlenPluginMTronCreator::deserializePlugin(
char const* name, void const* serialData, size_t serialLength) noexcept {
return new EmbLayerNormVarSeqlenPluginMTron(name, serialData, serialLength);
}
void EmbLayerNormVarSeqlenPluginBaseCreator::setPluginNamespace(
char const* libNamespace) noexcept {
mNamespace = libNamespace;
}
char const* EmbLayerNormVarSeqlenPluginBaseCreator::getPluginNamespace()
const noexcept {
return mNamespace.c_str();
}
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,338 @@
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
// SPDX-FileCopyrightText: Copyright (c) 1993-2022 NVIDIA CORPORATION &
// AFFILIATES. 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.
#pragma once
#include <cuda.h>
#include "NvInferPlugin.h"
#include "NvInferRuntime.h"
#include "paddle/fluid/inference/tensorrt/plugin/common/bertCommon.h"
#include "paddle/fluid/inference/tensorrt/plugin/common/plugin.h"
#include "paddle/fluid/inference/tensorrt/plugin/common/serialize.h"
#include "paddle/fluid/inference/tensorrt/plugin/trt_plugin.h"
#include "paddle/fluid/platform/enforce.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
template <typename T>
int32_t embSkipLayerNormHFace_2(cudaStream_t,
int32_t,
int32_t,
int32_t,
int32_t const*,
int32_t const*,
int32_t,
float const*,
float const*,
T const*,
T const*,
int32_t,
int32_t,
T*);
template <typename T>
int32_t embSkipLayerNormHFace_3(cudaStream_t,
int32_t,
int32_t,
int32_t,
int32_t const*,
int32_t const*,
int32_t const*,
int32_t,
float const*,
float const*,
T const*,
T const*,
T const*,
int32_t,
int32_t,
int32_t,
T*);
template <typename T>
int32_t embSkipLayerNormHFace_4(cudaStream_t,
int32_t,
int32_t,
int32_t,
int32_t const*,
int32_t const*,
int32_t const*,
int32_t const*,
int32_t,
float const*,
float const*,
T const*,
T const*,
T const*,
T const*,
int32_t,
int32_t,
int32_t,
int32_t,
T*);
template <typename T>
int32_t embSkipLayerNormMTron_2(cudaStream_t,
int32_t,
int32_t,
int32_t,
int32_t const*,
int32_t const*,
int32_t,
float const*,
float const*,
T const*,
T const*,
int32_t,
int32_t,
T*,
T*);
template <typename T>
int32_t embSkipLayerNormMTron_3(cudaStream_t,
int32_t,
int32_t,
int32_t,
int32_t const*,
int32_t const*,
int32_t const*,
int32_t,
float const*,
float const*,
T const*,
T const*,
T const*,
int32_t,
int32_t,
int32_t,
T*,
T*);
template <typename T>
int32_t embSkipLayerNormMTron_4(cudaStream_t,
int32_t,
int32_t,
int32_t,
int32_t const*,
int32_t const*,
int32_t const*,
int32_t const*,
int32_t,
float const*,
float const*,
T const*,
T const*,
T const*,
T const*,
int32_t,
int32_t,
int32_t,
int32_t,
T*,
T*);
class EmbLayerNormVarSeqlenPluginBase : public nvinfer1::IPluginV2DynamicExt {
public:
EmbLayerNormVarSeqlenPluginBase(
std::string const& name,
nvinfer1::DataType const type,
nvinfer1::Weights const& beta,
nvinfer1::Weights const& gamma,
const std::vector<nvinfer1::Weights>& ids_emb);
EmbLayerNormVarSeqlenPluginBase(std::string const& name,
void const* data,
size_t length);
// It doesn't make sense to make EmbLayerNormVarSeqlenPlugin without
// arguments, so we delete default constructor.
EmbLayerNormVarSeqlenPluginBase() = delete;
// IPluginV2DynamicExt Methods
bool supportsFormatCombination(int32_t pos,
nvinfer1::PluginTensorDesc const* inOut,
int32_t nbInputs,
int32_t nbOutputs) noexcept override;
size_t getWorkspaceSize(nvinfer1::PluginTensorDesc const* inputs,
int32_t nbInputs,
nvinfer1::PluginTensorDesc const* outputs,
int32_t nbOutputs) const noexcept override;
// IPluginV2Ext Methods
nvinfer1::DataType getOutputDataType(
int32_t index,
nvinfer1::DataType const* inputTypes,
int32_t nbInputs) const noexcept override;
// IPluginV2 Methods
char const* getPluginType() const noexcept override;
int32_t getNbOutputs() const noexcept override;
size_t getSerializationSize() const noexcept override;
void serialize(void* buffer) const noexcept override;
void destroy() noexcept override;
char const* getPluginNamespace() const noexcept override;
void setPluginNamespace(char const* pluginNamespace) noexcept override;
protected:
std::string const mLayerName;
std::string mNamespace;
cuda_unique_ptr<float> mGammaDev;
cuda_unique_ptr<float> mBetaDev;
std::vector<void*> mIdsEmbPtrs;
size_t mLd; // leading dim = hidden size
std::vector<int32_t> mIdsVocabSize;
WeightsWithOwnership mBeta;
WeightsWithOwnership mGamma;
nvinfer1::DataType mType;
std::vector<nvinfer1::Weights> mIdsEmb_;
int32_t nbLookupTables_ = 0;
};
class EmbLayerNormVarSeqlenPluginHFace
: public EmbLayerNormVarSeqlenPluginBase {
public:
EmbLayerNormVarSeqlenPluginHFace(
std::string const& name,
nvinfer1::DataType const type,
nvinfer1::Weights const& beta,
nvinfer1::Weights const& gamma,
const std::vector<nvinfer1::Weights>& ids_emb);
EmbLayerNormVarSeqlenPluginHFace(std::string const& name,
void const* data,
size_t length);
// It doesn't make sense to make EmbLayerNormVarSeqlenPlugin without
// arguments, so we delete default constructor.
EmbLayerNormVarSeqlenPluginHFace() = delete;
// IPluginV2DynamicExt Methods
nvinfer1::IPluginV2DynamicExt* clone() const noexcept override;
nvinfer1::DimsExprs getOutputDimensions(
int32_t outputIndex,
const nvinfer1::DimsExprs* inputs,
int32_t nbInputs,
nvinfer1::IExprBuilder& exprBuilder) noexcept override;
void configurePlugin(nvinfer1::DynamicPluginTensorDesc const* in,
int32_t nbInputs,
nvinfer1::DynamicPluginTensorDesc const* out,
int32_t nbOutputs) noexcept override;
int32_t enqueue(nvinfer1::PluginTensorDesc const* inputDesc,
nvinfer1::PluginTensorDesc const* outputDesc,
void const* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) noexcept override;
// IPluginV2 Methods
int32_t initialize() noexcept override;
void terminate() noexcept override;
void destroy() noexcept override;
char const* getPluginVersion() const noexcept override;
};
class EmbLayerNormVarSeqlenPluginMTron
: public EmbLayerNormVarSeqlenPluginBase {
public:
EmbLayerNormVarSeqlenPluginMTron(
std::string const& name,
nvinfer1::DataType const type,
nvinfer1::Weights const& beta,
nvinfer1::Weights const& gamma,
const std::vector<nvinfer1::Weights>& ids_emb);
EmbLayerNormVarSeqlenPluginMTron(std::string const& name,
void const* data,
size_t length);
// It doesn't make sense to make EmbLayerNormVarSeqlenPlugin without
// arguments, so we delete default constructor.
EmbLayerNormVarSeqlenPluginMTron() = delete;
// IPluginV2DynamicExt Methods
nvinfer1::IPluginV2DynamicExt* clone() const noexcept override;
nvinfer1::DimsExprs getOutputDimensions(
int32_t outputIndex,
const nvinfer1::DimsExprs* inputs,
int32_t nbInputs,
nvinfer1::IExprBuilder& exprBuilder) noexcept override;
void configurePlugin(nvinfer1::DynamicPluginTensorDesc const* in,
int32_t nbInputs,
nvinfer1::DynamicPluginTensorDesc const* out,
int32_t nbOutputs) noexcept override;
int32_t enqueue(nvinfer1::PluginTensorDesc const* inputDesc,
nvinfer1::PluginTensorDesc const* outputDesc,
void const* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) noexcept override;
// IPluginV2 Methods
int32_t initialize() noexcept override;
void terminate() noexcept override;
void destroy() noexcept override;
char const* getPluginVersion() const noexcept override;
};
class EmbLayerNormVarSeqlenPluginBaseCreator : public nvinfer1::IPluginCreator {
public:
EmbLayerNormVarSeqlenPluginBaseCreator();
char const* getPluginName() const noexcept override;
const nvinfer1::PluginFieldCollection* getFieldNames() noexcept override;
void setPluginNamespace(char const* pluginNamespace) noexcept override;
char const* getPluginNamespace() const noexcept override;
protected:
static nvinfer1::PluginFieldCollection mFC;
static std::vector<nvinfer1::PluginField> mPluginAttributes;
std::string mNamespace;
};
class EmbLayerNormVarSeqlenPluginHFaceCreator
: public EmbLayerNormVarSeqlenPluginBaseCreator {
public:
nvinfer1::IPluginV2* createPlugin(
char const* name,
const nvinfer1::PluginFieldCollection* fc) noexcept override;
char const* getPluginVersion() const noexcept override;
nvinfer1::IPluginV2* deserializePlugin(char const* name,
void const* serialData,
size_t serialLength) noexcept override;
};
class EmbLayerNormVarSeqlenPluginMTronCreator
: public EmbLayerNormVarSeqlenPluginBaseCreator {
public:
nvinfer1::IPluginV2* createPlugin(
char const* name,
const nvinfer1::PluginFieldCollection* fc) noexcept override;
char const* getPluginVersion() const noexcept override;
nvinfer1::IPluginV2* deserializePlugin(char const* name,
void const* serialData,
size_t serialLength) noexcept override;
};
REGISTER_TRT_PLUGIN_V2(EmbLayerNormVarSeqlenPluginHFaceCreator);
REGISTER_TRT_PLUGIN_V2(EmbLayerNormVarSeqlenPluginMTronCreator);
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,445 @@
/* Copyright (c) 2021 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. */
#pragma once
#include <cassert>
#include <string>
#include <vector>
#include "paddle/fluid/inference/tensorrt/plugin/trt_plugin.h"
#include "paddle/fluid/platform/enforce.h"
#include "paddle/phi/backends/dynload/cublasLt.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
class MatmulPlugin : public nvinfer1::IPluginV2IOExt {
public:
MatmulPlugin(nvinfer1::Dims const& dims_x,
nvinfer1::Dims const& dims_y,
bool transA,
bool transB,
float alpha)
: dims_x_(dims_x),
dims_y_(dims_y),
transB_(transA),
transA_(transB),
alpha_(alpha) {}
MatmulPlugin(void const* serial_data, size_t serial_length) {
DeserializeValue(&serial_data, &serial_length, &dims_x_);
DeserializeValue(&serial_data, &serial_length, &dims_y_);
DeserializeValue(&serial_data, &serial_length, &transB_);
DeserializeValue(&serial_data, &serial_length, &transA_);
DeserializeValue(&serial_data, &serial_length, &alpha_);
DeserializeValue(&serial_data, &serial_length, &alpha_scale_);
DeserializeValue(&serial_data, &serial_length, &alpha_one_);
DeserializeValue(&serial_data, &serial_length, &alpha_zero_);
DeserializeValue(&serial_data, &serial_length, &batch_);
DeserializeValue(&serial_data, &serial_length, &k_);
DeserializeValue(&serial_data, &serial_length, &m_);
DeserializeValue(&serial_data, &serial_length, &n_);
DeserializeValue(&serial_data, &serial_length, &cublas_);
DeserializeValue(&serial_data, &serial_length, &type_);
DeserializeValue(&serial_data, &serial_length, &Adesc_);
DeserializeValue(&serial_data, &serial_length, &Bdesc_);
DeserializeValue(&serial_data, &serial_length, &Cdesc_);
DeserializeValue(&serial_data, &serial_length, &AtransformDesc_);
DeserializeValue(&serial_data, &serial_length, &BtransformDesc_);
DeserializeValue(&serial_data, &serial_length, &CtransformDesc_);
DeserializeValue(&serial_data, &serial_length, &Atransform_);
DeserializeValue(&serial_data, &serial_length, &Btransform_);
DeserializeValue(&serial_data, &serial_length, &Ctransform_);
DeserializeValue(&serial_data, &serial_length, &transformDescT_);
DeserializeValue(&serial_data, &serial_length, &transformDescN_);
DeserializeValue(&serial_data, &serial_length, &matmulDesc_);
}
virtual bool isOutputBroadcastAcrossBatch(int32_t output_index,
const bool* input_is_broadcasted,
int32_t nb_inputs) const
TRT_NOEXCEPT {
return false;
}
virtual bool canBroadcastInputAcrossBatch(int32_t input_index) const
TRT_NOEXCEPT {
return false;
}
const char* getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
size_t getWorkspaceSize(int) const TRT_NOEXCEPT override { return 0; }
void setPluginNamespace(const char* plugin_namespace) TRT_NOEXCEPT override {
name_space_ = plugin_namespace;
}
nvinfer1::IPluginV2IOExt* clone() const TRT_NOEXCEPT override {
MatmulPlugin* ptr =
new MatmulPlugin(dims_x_, dims_y_, transB_, transA_, alpha_);
ptr->setPluginNamespace(this->getPluginNamespace());
ptr->batch_ = batch_;
ptr->k_ = k_;
ptr->m_ = m_;
ptr->n_ = n_;
ptr->alpha_scale_ = alpha_scale_;
ptr->alpha_one_ = alpha_one_;
ptr->alpha_zero_ = alpha_zero_;
ptr->cublas_ = cublas_;
ptr->type_ = type_;
ptr->Adesc_ = Adesc_;
ptr->Bdesc_ = Bdesc_;
ptr->Cdesc_ = Cdesc_;
ptr->AtransformDesc_ = AtransformDesc_;
ptr->BtransformDesc_ = BtransformDesc_;
ptr->CtransformDesc_ = CtransformDesc_;
ptr->Atransform_ = Atransform_;
ptr->Btransform_ = Btransform_;
ptr->Ctransform_ = Ctransform_;
ptr->transformDescT_ = transformDescT_;
ptr->transformDescN_ = transformDescN_;
ptr->matmulDesc_ = matmulDesc_;
return ptr;
}
const char* getPluginNamespace() const TRT_NOEXCEPT override {
return name_space_.c_str();
}
const char* getPluginType() const TRT_NOEXCEPT override {
return "matmul_int8_plugin";
}
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* input_types,
int nb_inputs) const
TRT_NOEXCEPT override;
int getNbOutputs() const TRT_NOEXCEPT override { return 1; }
nvinfer1::Dims getOutputDimensions(int index,
const nvinfer1::Dims* input_dims,
int num_inputs) TRT_NOEXCEPT override;
bool supportsFormatCombination(int32_t pos,
nvinfer1::PluginTensorDesc const* inOut,
int32_t nbInputs,
int32_t nbOutputs) const TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::PluginTensorDesc* in,
int32_t nbInputs,
const nvinfer1::PluginTensorDesc* out,
int32_t nbOutputs) TRT_NOEXCEPT override;
/*
bool supportsFormat(nvinfer1::DataType type, nvinfer1::PluginFormat format)
const TRT_NOEXCEPT override;
*/
int initialize() TRT_NOEXCEPT { return 0; }
void terminate() TRT_NOEXCEPT;
int enqueue(int batch_size,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override { delete this; }
void attachToContext(cudnnContext* cudnnContext,
cublasContext* cublasContext,
nvinfer1::IGpuAllocator* gpuAllocator)
TRT_NOEXCEPT override;
void detachFromContext() TRT_NOEXCEPT override;
protected:
nvinfer1::Dims dims_x_;
nvinfer1::Dims dims_y_;
bool transB_;
bool transA_;
float alpha_;
void *alpha_scale_{nullptr}, *alpha_one_{nullptr}, *alpha_zero_{nullptr};
int batch_;
uint64_t k_;
uint64_t m_;
uint64_t n_;
cublasLtHandle_t cublas_{nullptr};
nvinfer1::DataType type_;
cublasLtMatrixLayout_t Adesc_{nullptr}, Bdesc_{nullptr}, Cdesc_{nullptr};
cublasLtMatrixLayout_t AtransformDesc_{nullptr}, BtransformDesc_{nullptr},
CtransformDesc_{nullptr};
int8_t *Atransform_{nullptr}, *Btransform_{nullptr}, *Ctransform_{nullptr};
cublasLtMatrixTransformDesc_t transformDescT_{nullptr},
transformDescN_{nullptr};
cublasLtMatmulDesc_t matmulDesc_{nullptr};
std::string name_space_;
size_t getSerializationSize() const TRT_NOEXCEPT override {
return SerializedSize(dims_x_) + SerializedSize(dims_y_) +
SerializedSize(transB_) + SerializedSize(transA_) +
SerializedSize(alpha_) + SerializedSize(alpha_scale_) +
SerializedSize(alpha_one_) + SerializedSize(alpha_zero_) +
SerializedSize(batch_) + SerializedSize(k_) + SerializedSize(m_) +
SerializedSize(n_) + SerializedSize(cublas_) +
SerializedSize(type_) + SerializedSize(Adesc_) +
SerializedSize(Bdesc_) + SerializedSize(Cdesc_) +
SerializedSize(AtransformDesc_) + SerializedSize(BtransformDesc_) +
SerializedSize(CtransformDesc_) + SerializedSize(Atransform_) +
SerializedSize(Btransform_) + SerializedSize(Ctransform_) +
SerializedSize(transformDescT_) + SerializedSize(transformDescN_) +
SerializedSize(matmulDesc_);
}
void serialize(void* buffer) const TRT_NOEXCEPT override {
SerializeValue(&buffer, dims_x_);
SerializeValue(&buffer, dims_y_);
SerializeValue(&buffer, transB_);
SerializeValue(&buffer, transA_);
SerializeValue(&buffer, alpha_);
SerializeValue(&buffer, alpha_scale_);
SerializeValue(&buffer, alpha_one_);
SerializeValue(&buffer, alpha_zero_);
SerializeValue(&buffer, batch_);
SerializeValue(&buffer, k_);
SerializeValue(&buffer, m_);
SerializeValue(&buffer, n_);
SerializeValue(&buffer, cublas_);
SerializeValue(&buffer, type_);
SerializeValue(&buffer, Adesc_);
SerializeValue(&buffer, Bdesc_);
SerializeValue(&buffer, Cdesc_);
SerializeValue(&buffer, AtransformDesc_);
SerializeValue(&buffer, BtransformDesc_);
SerializeValue(&buffer, CtransformDesc_);
SerializeValue(&buffer, Atransform_);
SerializeValue(&buffer, Btransform_);
SerializeValue(&buffer, Ctransform_);
SerializeValue(&buffer, transformDescT_);
SerializeValue(&buffer, transformDescN_);
SerializeValue(&buffer, matmulDesc_);
}
};
class MatmulPluginCreator : public nvinfer1::IPluginCreator {
public:
MatmulPluginCreator() {}
const char* getPluginName() const TRT_NOEXCEPT override {
return "matmul_int8_plugin";
}
const char* getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
const nvinfer1::PluginFieldCollection* getFieldNames() TRT_NOEXCEPT override {
return &field_collection_;
}
nvinfer1::IPluginV2IOExt* createPlugin(
const char* name,
const nvinfer1::PluginFieldCollection* fc) TRT_NOEXCEPT override {
return nullptr;
}
nvinfer1::IPluginV2IOExt* deserializePlugin(const char* name,
void const* serial_data,
size_t serial_length)
TRT_NOEXCEPT override {
MatmulPlugin* obj = new MatmulPlugin(serial_data, serial_length);
obj->setPluginNamespace(name);
return obj;
}
void setPluginNamespace(const char* lib_namespace) TRT_NOEXCEPT override {
plugin_namespace_ = lib_namespace;
}
const char* getPluginNamespace() const TRT_NOEXCEPT override {
return plugin_namespace_.c_str();
}
private:
std::string plugin_namespace_;
std::string plugin_name_;
nvinfer1::PluginFieldCollection field_collection_{0, nullptr};
std::vector<nvinfer1::PluginField> plugin_attributes_;
};
REGISTER_TRT_PLUGIN_V2(MatmulPluginCreator);
class MatmulPluginDynamic : public DynamicPluginTensorRT {
public:
MatmulPluginDynamic(bool transA, bool transB, float alpha)
: transB_(transA), transA_(transB), alpha_(alpha) {}
MatmulPluginDynamic(void const* serial_data, size_t serial_length) {
DeserializeValue(&serial_data, &serial_length, &transB_);
DeserializeValue(&serial_data, &serial_length, &transA_);
DeserializeValue(&serial_data, &serial_length, &alpha_);
DeserializeValue(&serial_data, &serial_length, &alpha_scale_);
DeserializeValue(&serial_data, &serial_length, &alpha_one_);
DeserializeValue(&serial_data, &serial_length, &alpha_zero_);
DeserializeValue(&serial_data, &serial_length, &cublas_);
DeserializeValue(&serial_data, &serial_length, &Atransform_);
DeserializeValue(&serial_data, &serial_length, &Btransform_);
DeserializeValue(&serial_data, &serial_length, &Ctransform_);
DeserializeValue(&serial_data, &serial_length, &type_);
}
nvinfer1::IPluginV2DynamicExt* clone() const TRT_NOEXCEPT override {
MatmulPluginDynamic* ptr =
new MatmulPluginDynamic(transB_, transA_, alpha_);
ptr->setPluginNamespace(this->getPluginNamespace());
ptr->alpha_scale_ = alpha_scale_;
ptr->alpha_one_ = alpha_one_;
ptr->alpha_zero_ = alpha_zero_;
ptr->cublas_ = cublas_;
ptr->Atransform_ = Atransform_;
ptr->Btransform_ = Btransform_;
ptr->Ctransform_ = Ctransform_;
ptr->type_ = type_;
return ptr;
}
const char* getPluginType() const TRT_NOEXCEPT override {
return "matmul_int8_dynamic_plugin";
}
int getNbOutputs() const TRT_NOEXCEPT override { return 1; }
int initialize() TRT_NOEXCEPT { return 0; }
void terminate() TRT_NOEXCEPT;
nvinfer1::DimsExprs getOutputDimensions(
int outputIndex,
const nvinfer1::DimsExprs* inputs,
int nbInputs,
nvinfer1::IExprBuilder& exprBuilder) // NOLINT
TRT_NOEXCEPT override;
bool supportsFormatCombination(int pos,
const nvinfer1::PluginTensorDesc* inOut,
int nbInputs,
int nbOutputs) TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::DynamicPluginTensorDesc* inputs,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc* outputs,
int nbOutputs) TRT_NOEXCEPT override;
size_t getWorkspaceSize(const nvinfer1::PluginTensorDesc* inputs,
int nbInputs,
const nvinfer1::PluginTensorDesc* outputs,
int nbOutputs) const TRT_NOEXCEPT override {
return 0;
}
void attachToContext(cudnnContext* cudnnContext,
cublasContext* cublasContext,
nvinfer1::IGpuAllocator* gpuAllocator)
TRT_NOEXCEPT override;
void detachFromContext() TRT_NOEXCEPT override;
int enqueue(const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* inputTypes,
int nbInputs) const
TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override { delete this; }
protected:
bool transB_;
bool transA_;
float alpha_;
void *alpha_scale_{nullptr}, *alpha_one_{nullptr}, *alpha_zero_{nullptr};
cublasLtHandle_t cublas_{nullptr};
nvinfer1::DataType type_;
int8_t *Atransform_{nullptr}, *Btransform_{nullptr}, *Ctransform_{nullptr};
std::string name_space_;
size_t getSerializationSize() const TRT_NOEXCEPT override {
return SerializedSize(transB_) + SerializedSize(transA_) +
SerializedSize(alpha_) + SerializedSize(alpha_scale_) +
SerializedSize(alpha_one_) + SerializedSize(alpha_zero_) +
SerializedSize(Atransform_) + SerializedSize(Btransform_) +
SerializedSize(Ctransform_) + SerializedSize(cublas_) +
SerializedSize(type_);
}
void serialize(void* buffer) const TRT_NOEXCEPT override {
SerializeValue(&buffer, transB_);
SerializeValue(&buffer, transA_);
SerializeValue(&buffer, alpha_);
SerializeValue(&buffer, alpha_scale_);
SerializeValue(&buffer, alpha_one_);
SerializeValue(&buffer, alpha_zero_);
SerializeValue(&buffer, Atransform_);
SerializeValue(&buffer, Btransform_);
SerializeValue(&buffer, Ctransform_);
SerializeValue(&buffer, cublas_);
SerializeValue(&buffer, type_);
}
};
class MatmulPluginDynamicCreator : public nvinfer1::IPluginCreator {
public:
MatmulPluginDynamicCreator() {}
const char* getPluginName() const TRT_NOEXCEPT override {
return "matmul_int8_dynamic_plugin";
}
const char* getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
const nvinfer1::PluginFieldCollection* getFieldNames() TRT_NOEXCEPT override {
return &field_collection_;
}
nvinfer1::IPluginV2* createPlugin(const char* name,
const nvinfer1::PluginFieldCollection* fc)
TRT_NOEXCEPT override {
return nullptr;
}
nvinfer1::IPluginV2* deserializePlugin(const char* name,
void const* serial_data,
size_t serial_length)
TRT_NOEXCEPT override {
MatmulPluginDynamic* obj =
new MatmulPluginDynamic(serial_data, serial_length);
obj->setPluginNamespace(name);
return obj;
}
void setPluginNamespace(const char* lib_namespace) TRT_NOEXCEPT override {
plugin_namespace_ = lib_namespace;
}
const char* getPluginNamespace() const TRT_NOEXCEPT override {
return plugin_namespace_.c_str();
}
private:
std::string plugin_namespace_;
std::string plugin_name_;
nvinfer1::PluginFieldCollection field_collection_{0, nullptr};
std::vector<nvinfer1::PluginField> plugin_attributes_;
};
REGISTER_TRT_PLUGIN_V2(MatmulPluginDynamicCreator);
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,325 @@
/* Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
Copyright (c) 2019-2022, NVIDIA CORPORATION. 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 <algorithm>
#include "paddle/fluid/inference/tensorrt/plugin/merge_layernorm_op_plugin.h"
#include "paddle/phi/kernels/funcs/math_cuda_utils.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
#define FINAL_MASK 0xffffffff
template <typename T>
__global__ void merge_layernorm_v2(T *out,
const T *__restrict input,
const T *__restrict gamma,
const T *__restrict beta,
const float layernorm_eps,
int batch,
int H,
int W,
int n) {
// input is [batch, 2*H, 2*W, n/4]
// output is [batch, H, W, n]
// grid (W, H, batch)
// block (n)
const int kIte = 4;
const int tid = threadIdx.x;
const int W_idx = blockIdx.x;
const int H_idx = blockIdx.y;
const size_t batch_offset = blockIdx.z * H * W * n;
const int input_H_stride = W * n / 2;
const int output_H_stride = W * n;
const int n_4 = n >> 2;
__shared__ float s_mean;
__shared__ float s_variance;
float mean = 0.0f;
float variance = 0.0f;
float local_out[kIte];
float sum = 0.0f;
#pragma unroll
for (int i = 0; i < kIte; i++) {
int col_id = i * blockDim.x + tid;
if (col_id < n) {
int part_id = col_id / n_4;
int offset_in_W = part_id / 2;
int offset_in_H = part_id % 2;
size_t input_id = batch_offset +
(2 * H_idx + offset_in_H) * input_H_stride +
(2 * W_idx + offset_in_W) * n_4 + (col_id % n_4);
local_out[i] = static_cast<float>(__ldg(input + input_id));
sum += local_out[i];
}
}
mean = phi::funcs::BlockReduceSum<float>(sum, FINAL_MASK);
if (tid == 0) {
s_mean = mean / n;
}
__syncthreads();
float var = 0.0f;
#pragma unroll
for (int i = 0; i < kIte; i++) {
int col_id = i * blockDim.x + tid;
if (col_id < n) {
local_out[i] = local_out[i] - s_mean;
var += local_out[i] * local_out[i];
}
}
variance = phi::funcs::BlockReduceSum<float>(var, FINAL_MASK);
if (tid == 0) {
s_variance = rsqrtf(variance / n + layernorm_eps);
}
__syncthreads();
#pragma unroll
for (int i = 0; i < kIte; i++) {
int col_id = i * blockDim.x + tid;
if (col_id < n) {
size_t output_idx =
batch_offset + H_idx * output_H_stride + W_idx * n + col_id;
out[output_idx] =
static_cast<T>(local_out[i] * s_variance *
static_cast<float>(__ldg(&gamma[col_id])) +
static_cast<float>(__ldg(&beta[col_id])));
}
}
}
template <typename T>
void invokeMergeLayernorm(T *output,
const T *input,
const T *gamma,
const T *beta,
float layernorm_eps,
int batch,
int H,
int W,
int n,
cudaStream_t stream) {
if ((W % 2 != 0) || (H % 2 != 0)) {
PADDLE_THROW(common::errors::InvalidArgument(
"H(W) of merge layernorm should be a multiple of 2."));
}
dim3 grid(W / 2, H / 2, batch);
int blockSize = (n + 31) / 32 * 32;
merge_layernorm_v2<T><<<grid, blockSize, 0, stream>>>(
output, input, gamma, beta, layernorm_eps, batch, H / 2, W / 2, n * 4);
}
template void invokeMergeLayernorm<float>(float *output,
const float *input,
const float *gamma,
const float *beta,
float layernorm_eps,
int batch,
int H,
int W,
int n,
cudaStream_t stream);
template void invokeMergeLayernorm<half>(half *output,
const half *input,
const half *gamma,
const half *beta,
float layernorm_eps,
int batch,
int H,
int W,
int n,
cudaStream_t stream);
template <typename T>
static void convertAndCopy(const std::vector<float> &host, T *dev) {
T *host_ptr = new T[host.size()];
std::transform(host.begin(), host.end(), host_ptr, [](float x) {
return static_cast<T>(x);
});
cudaMemcpy(dev, host_ptr, sizeof(T) * host.size(), cudaMemcpyHostToDevice);
delete host_ptr;
}
void MergeLayernormPluginDynamic::configurePlugin(
const nvinfer1::DynamicPluginTensorDesc *in,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc *out,
int nbOutputs) TRT_NOEXCEPT {}
MergeLayernormPluginDynamic::MergeLayernormPluginDynamic(
const float *bias_d,
const size_t bias_num,
const float *scale_d,
const size_t scale_num,
const float eps,
const int begin_norm_axis,
const bool with_fp16,
std::shared_ptr<void> bias_device,
std::shared_ptr<void> scale_device)
: eps_(eps),
begin_norm_axis_(begin_norm_axis),
with_fp16_(with_fp16),
bias_device_(bias_device),
scale_device_(scale_device) {
bias_.resize(bias_num);
scale_.resize(scale_num);
std::copy(bias_d, bias_d + bias_num, bias_.data());
std::copy(scale_d, scale_d + scale_num, scale_.data());
int type_size = with_fp16_ ? sizeof(half) : sizeof(float);
if (bias_device_ == nullptr) {
void *p;
cudaMalloc(&p, bias_num * type_size);
bias_device_.reset(p, [](void *ptr) { cudaFree(ptr); });
if (with_fp16) {
convertAndCopy<half>(bias_, reinterpret_cast<half *>(p));
} else {
convertAndCopy<float>(bias_, reinterpret_cast<float *>(p));
}
}
if (scale_device_ == nullptr) {
void *p;
cudaMalloc(&p, scale_num * type_size);
scale_device_.reset(p, [](void *ptr) { cudaFree(ptr); });
if (with_fp16) {
convertAndCopy<half>(scale_, reinterpret_cast<half *>(p));
} else {
convertAndCopy<float>(scale_, reinterpret_cast<float *>(p));
}
}
}
bool MergeLayernormPluginDynamic::supportsFormatCombination(
int pos,
const nvinfer1::PluginTensorDesc *in_out,
int nb_inputs,
int nb_outputs) TRT_NOEXCEPT {
PADDLE_ENFORCE_NOT_NULL(
in_out,
common::errors::InvalidArgument("The input of MergeLayernorm "
"plugin should not be nullptr."));
PADDLE_ENFORCE_LT(
pos,
nb_inputs + nb_outputs,
common::errors::InvalidArgument("The pos(%d) should be less than the "
"num(%d) of the input and the output.",
pos,
nb_inputs + nb_outputs));
const nvinfer1::PluginTensorDesc &in = in_out[pos];
if (pos == 0) {
if (with_fp16_) {
return in.type == nvinfer1::DataType::kHALF &&
in.format == nvinfer1::TensorFormat::kLINEAR;
} else {
return in.type == nvinfer1::DataType::kFLOAT &&
in.format == nvinfer1::TensorFormat::kLINEAR;
}
}
const nvinfer1::PluginTensorDesc &prev = in_out[pos - 1];
// output
return in.type == prev.type && in.format == prev.format;
}
nvinfer1::DataType MergeLayernormPluginDynamic::getOutputDataType(
int index,
const nvinfer1::DataType *input_types,
int nb_inputs) const TRT_NOEXCEPT {
PADDLE_ENFORCE_EQ(index,
0,
common::errors::InvalidArgument(
"The MergeLayernorm only has one input, so the "
"index value should be 0, but get %d.",
index));
return input_types[0];
}
nvinfer1::DimsExprs MergeLayernormPluginDynamic::getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs *inputs,
int nb_inputs,
nvinfer1::IExprBuilder &expr_builder) TRT_NOEXCEPT {
nvinfer1::DimsExprs ret;
ret.nbDims = 3;
ret.d[0] = inputs[0].d[0];
ret.d[1] = expr_builder.operation(nvinfer1::DimensionOperation::kFLOOR_DIV,
*inputs[0].d[1],
*expr_builder.constant(4));
ret.d[2] = expr_builder.operation(nvinfer1::DimensionOperation::kPROD,
*inputs[0].d[2],
*expr_builder.constant(4));
return ret;
}
int MergeLayernormPluginDynamic::enqueue(
const nvinfer1::PluginTensorDesc *input_desc,
const nvinfer1::PluginTensorDesc *output_desc,
const void *const *inputs,
void *const *outputs,
void *workspace,
cudaStream_t stream) TRT_NOEXCEPT {
const auto &input_dims = input_desc[0].dims;
auto input_type = input_desc[0].type;
int batch = input_dims.d[0];
int input_resolution = static_cast<int>(std::sqrt(input_dims.d[1]));
int dim = static_cast<int>(input_dims.d[2]);
PADDLE_ENFORCE_EQ(
input_resolution * input_resolution,
input_dims.d[1],
common::errors::InvalidArgument(
"The MergeLayernorm TRT Plugin get invalid input_resolution %d",
input_resolution));
if (input_type == nvinfer1::DataType::kFLOAT) {
VLOG(3) << "TRT Plugin DataType selected. MergeLayernorm-->fp32";
invokeMergeLayernorm<float>(
reinterpret_cast<float *>(outputs[0]),
reinterpret_cast<const float *>(inputs[0]),
reinterpret_cast<const float *>(scale_device_.get()),
reinterpret_cast<const float *>(bias_device_.get()),
eps_,
batch,
input_resolution,
input_resolution,
dim,
stream);
} else if (input_type == nvinfer1::DataType::kHALF) {
VLOG(3) << "TRT Plugin DataType selected. MergeLayernorm-->fp16";
invokeMergeLayernorm<half>(
reinterpret_cast<half *>(outputs[0]),
reinterpret_cast<const half *>(inputs[0]),
reinterpret_cast<const half *>(scale_device_.get()),
reinterpret_cast<const half *>(bias_device_.get()),
eps_,
batch,
input_resolution,
input_resolution,
dim,
stream);
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"The MergeLayernorm TRT Plugin's input type should be float or half."));
}
return cudaGetLastError() != cudaSuccess;
}
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,141 @@
/* Copyright (c) 2022 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. */
#pragma once
#include <memory>
#include <vector>
#include "paddle/fluid/framework/tensor.h"
#include "paddle/fluid/framework/tensor_util.h"
#include "paddle/fluid/inference/tensorrt/engine.h"
#include "paddle/fluid/inference/tensorrt/plugin/trt_plugin.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
class MergeLayernormPluginDynamic : public DynamicPluginTensorRT {
public:
MergeLayernormPluginDynamic(const float* bias_d,
const size_t bias_num,
const float* scale_d,
const size_t scale_num,
const float eps,
const int begin_norm_axis,
const bool with_fp16,
std::shared_ptr<void> bias_device = nullptr,
std::shared_ptr<void> scale_device = nullptr);
MergeLayernormPluginDynamic(void const* serialData, size_t serialLength) {
DeserializeValue(&serialData, &serialLength, &bias_);
DeserializeValue(&serialData, &serialLength, &scale_);
DeserializeValue(&serialData, &serialLength, &eps_);
DeserializeValue(&serialData, &serialLength, &begin_norm_axis_);
DeserializeValue(&serialData, &serialLength, &with_fp16_);
}
nvinfer1::IPluginV2DynamicExt* clone() const TRT_NOEXCEPT override {
return new MergeLayernormPluginDynamic(bias_.data(),
bias_.size(),
scale_.data(),
scale_.size(),
eps_,
begin_norm_axis_,
with_fp16_,
bias_device_,
scale_device_);
}
const char* getPluginType() const TRT_NOEXCEPT override {
return "merge_layernorm_plugin_dynamic";
}
int getNbOutputs() const TRT_NOEXCEPT override { return 1; }
int initialize() TRT_NOEXCEPT override { return 0; }
size_t getSerializationSize() const TRT_NOEXCEPT override {
return SerializedSize(bias_) + SerializedSize(scale_) +
SerializedSize(eps_) + SerializedSize(begin_norm_axis_) +
SerializedSize(with_fp16_);
}
void serialize(void* buffer) const TRT_NOEXCEPT override {
SerializeValue(&buffer, bias_);
SerializeValue(&buffer, scale_);
SerializeValue(&buffer, eps_);
SerializeValue(&buffer, begin_norm_axis_);
SerializeValue(&buffer, with_fp16_);
}
nvinfer1::DimsExprs getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs* inputs,
int nb_inputs,
nvinfer1::IExprBuilder& expr_builder) // NOLINT
TRT_NOEXCEPT override;
bool supportsFormatCombination(int pos,
const nvinfer1::PluginTensorDesc* inOut,
int nbInputs,
int nbOutputs) TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::DynamicPluginTensorDesc* in,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc* out,
int nbOutputs) TRT_NOEXCEPT override;
size_t getWorkspaceSize(const nvinfer1::PluginTensorDesc* inputs,
int nbInputs,
const nvinfer1::PluginTensorDesc* outputs,
int nbOutputs) const TRT_NOEXCEPT override {
return 0;
}
int enqueue(const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* inputTypes,
int nbInputs) const
TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override { delete this; }
private:
std::vector<float> bias_;
std::vector<float> scale_;
float eps_;
int begin_norm_axis_;
bool with_fp16_;
std::shared_ptr<void> bias_device_ = nullptr;
std::shared_ptr<void> scale_device_ = nullptr;
};
class MergeLayernormPluginDynamicCreator : public TensorRTPluginCreator {
public:
const char* getPluginName() const TRT_NOEXCEPT override {
return "merge_layernorm_plugin_dynamic";
}
const char* getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
nvinfer1::IPluginV2* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override {
return new MergeLayernormPluginDynamic(serial_data, serial_length);
}
};
REGISTER_TRT_PLUGIN_V2(MergeLayernormPluginDynamicCreator);
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,250 @@
// Copyright (c) 2021 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 <cstring>
#include "glog/logging.h"
#include "paddle/fluid/inference/tensorrt/plugin/mish_op_plugin.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
int MishPlugin::initialize() TRT_NOEXCEPT { return 0; }
bool MishPlugin::supportsFormat(
nvinfer1::DataType type, nvinfer1::PluginFormat format) const TRT_NOEXCEPT {
if (with_fp16_) {
return ((type == nvinfer1::DataType::kFLOAT ||
type == nvinfer1::DataType::kHALF) &&
(format == nvinfer1::PluginFormat::kLINEAR));
} else {
return ((type == nvinfer1::DataType::kFLOAT) &&
(format == nvinfer1::PluginFormat::kLINEAR));
}
}
nvinfer1::Dims MishPlugin::getOutputDimensions(int index,
const nvinfer1::Dims* in_dims,
int nb_inputs) TRT_NOEXCEPT {
PADDLE_ENFORCE_EQ(
nb_inputs,
1,
common::errors::InvalidArgument("We expect [number of inputs] == 1"
"in TRT Mish op plugin, but got "
"[number of inputs] = %d.",
nb_inputs));
PADDLE_ENFORCE_LT(
index,
this->getNbOutputs(),
common::errors::InvalidArgument("We expect [index] < [number of outputs]"
"in TRT Mish op plugin, but got "
"[index] = %d, [number of outputs] = %d.",
index,
this->getNbOutputs()));
nvinfer1::Dims const& input_dims = in_dims[0];
nvinfer1::Dims output_dims = input_dims;
return output_dims;
}
template <typename T>
__device__ T kTanh(T x) {
return tanh(x);
}
template <>
__device__ half kTanh<half>(half x) {
#if CUDA_ARCH_FP16_SUPPORTED(__CUDA_ARCH__)
const float tmp = tanhf(__half2float(x));
return __float2half(tmp);
#endif
}
template <typename T>
__device__ T kSoftplus(T x, T threshold) {
return x > threshold ? x : log(exp(x) + static_cast<T>(1.0f));
}
template <>
__device__ half kSoftplus<half>(half x, half threshold) {
#if CUDA_ARCH_FP16_SUPPORTED(__CUDA_ARCH__)
return x > threshold ? x : hlog(hexp(x) + static_cast<half>(1.0f));
#endif
}
template <typename T>
__global__ void mish_kernel(float threshold, int n, const T* input, T* output) {
const int idx = blockIdx.x * blockDim.x + threadIdx.x;
if (idx < n) {
const T in = input[idx];
output[idx] = in * kTanh<T>(kSoftplus<T>(in, static_cast<T>(threshold)));
}
}
template <>
__global__ void mish_kernel<half>(float threshold,
int n,
const half* input,
half* output) {
#if CUDA_ARCH_FP16_SUPPORTED(__CUDA_ARCH__)
const int idx = blockIdx.x * blockDim.x + threadIdx.x;
if (idx < n) {
const half in = input[idx];
output[idx] =
in * kTanh<half>(kSoftplus<half>(in, static_cast<half>(threshold)));
}
#endif
}
int MishPlugin::enqueue(int batchSize,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT {
const auto& input_dims = this->getInputDims(0);
int num = batchSize;
for (int i = 0; i < input_dims.nbDims; i++) {
num *= input_dims.d[i];
}
const int block_size = 256;
const int grid_size = (num + block_size - 1) / block_size;
auto type = getDataType();
if (type == nvinfer1::DataType::kFLOAT) {
VLOG(1) << "TRT Plugin DataType selected. Mish-->fp32";
const float* input = static_cast<const float*>(inputs[0]);
float* output = static_cast<float*>(outputs[0]);
mish_kernel<float>
<<<grid_size, block_size, 0, stream>>>(threshold_, num, input, output);
} else if (type == nvinfer1::DataType::kHALF) {
VLOG(1) << "TRT Plugin DataType selected. Mish-->fp16";
const half* input = static_cast<const half*>(inputs[0]);
half* output = static_cast<half*>(outputs[0]);
mish_kernel<half>
<<<grid_size, block_size, 0, stream>>>(threshold_, num, input, output);
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"The Mish TRT Plugin's input type should be float or half."));
}
return cudaGetLastError() != cudaSuccess;
}
// Dynamic Plugin below.
int MishPluginDynamic::initialize() TRT_NOEXCEPT {
getPluginNamespace();
return 0;
}
size_t MishPluginDynamic::getSerializationSize() const TRT_NOEXCEPT {
return SerializedSize(threshold_) + SerializedSize(with_fp16_);
}
void MishPluginDynamic::serialize(void* buffer) const TRT_NOEXCEPT {
SerializeValue(&buffer, threshold_);
SerializeValue(&buffer, with_fp16_);
}
nvinfer1::DimsExprs MishPluginDynamic::getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs* inputs,
int nb_inputs,
nvinfer1::IExprBuilder& expr_builder) TRT_NOEXCEPT {
return inputs[0];
}
bool MishPluginDynamic::supportsFormatCombination(
int pos,
const nvinfer1::PluginTensorDesc* in_out,
int nb_inputs,
int nb_outputs) TRT_NOEXCEPT {
PADDLE_ENFORCE_NOT_NULL(
in_out,
common::errors::InvalidArgument(
"The input of mish plugin should not be nullptr."));
PADDLE_ENFORCE_LT(
pos,
nb_inputs + nb_outputs,
common::errors::InvalidArgument("The pos(%d) should be less than the "
"num(%d) of the input and the output.",
pos,
nb_inputs + nb_outputs));
const nvinfer1::PluginTensorDesc& in = in_out[pos];
if (pos == 0) {
if (with_fp16_) {
return (in.type == nvinfer1::DataType::kFLOAT ||
in.type == nvinfer1::DataType::kHALF) &&
(in.format == nvinfer1::TensorFormat::kLINEAR);
} else {
return (in.type == nvinfer1::DataType::kFLOAT) &&
(in.format == nvinfer1::TensorFormat::kLINEAR);
}
}
const nvinfer1::PluginTensorDesc& prev = in_out[pos - 1];
// output
return in.type == prev.type && in.format == prev.format;
}
nvinfer1::DataType MishPluginDynamic::getOutputDataType(
int index,
const nvinfer1::DataType* input_types,
int nb_inputs) const TRT_NOEXCEPT {
PADDLE_ENFORCE_EQ(index,
0,
common::errors::InvalidArgument(
"The Mish Plugin only has one input, so the "
"index value should be 0, but get %d.",
index));
return input_types[0];
}
int MishPluginDynamic::enqueue(const nvinfer1::PluginTensorDesc* input_desc,
const nvinfer1::PluginTensorDesc* output_desc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT {
auto input_dims = input_desc[0].dims;
size_t num = ProductDim(input_dims);
const int block_size = 256;
const int grid_size = (num + block_size - 1) / block_size;
auto input_type = input_desc[0].type;
if (input_type == nvinfer1::DataType::kFLOAT) {
VLOG(1) << "TRT Plugin DataType selected. Mish-->fp32";
const float* input = static_cast<const float*>(inputs[0]);
float* output = static_cast<float*>(outputs[0]);
mish_kernel<float>
<<<grid_size, block_size, 0, stream>>>(threshold_, num, input, output);
} else if (input_type == nvinfer1::DataType::kHALF) {
VLOG(1) << "TRT Plugin DataType selected. Mish-->fp16";
const half* input = static_cast<const half*>(inputs[0]);
half* output = static_cast<half*>(outputs[0]);
mish_kernel<half>
<<<grid_size, block_size, 0, stream>>>(threshold_, num, input, output);
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"The Mish TRT Plugin's input type should be float or half."));
}
return cudaGetLastError() != cudaSuccess;
}
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,185 @@
// Copyright (c) 2021 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.
#pragma once
#include <stdio.h>
#include <string>
#include <vector>
#include "paddle/fluid/inference/tensorrt/engine.h"
#include "paddle/fluid/inference/tensorrt/plugin/trt_plugin.h"
#include "paddle/fluid/platform/enforce.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
class MishPlugin : public PluginTensorRT {
private:
float threshold_;
protected:
size_t getSerializationSize() const TRT_NOEXCEPT override {
return getBaseSerializationSize() + SerializedSize(threshold_);
}
// TRT will call this func to serialize the configuration of TRT
// It should not be called by users.
void serialize(void* buffer) const TRT_NOEXCEPT override {
serializeBase(buffer);
SerializeValue(&buffer, threshold_);
}
public:
explicit MishPlugin(const float threshold, const bool with_fp16)
: threshold_(threshold) {
with_fp16_ = with_fp16;
}
// It was used for tensorrt deserialization.
// It should not be called by users.
MishPlugin(void const* serialData, size_t serialLength) {
deserializeBase(serialData, serialLength);
DeserializeValue(&serialData, &serialLength, &threshold_);
}
~MishPlugin() {}
MishPlugin* clone() const TRT_NOEXCEPT override {
return new MishPlugin(threshold_, with_fp16_);
}
const char* getPluginType() const TRT_NOEXCEPT override {
return "mish_plugin";
}
int getNbOutputs() const TRT_NOEXCEPT override { return 1; }
int initialize() TRT_NOEXCEPT override;
bool supportsFormat(nvinfer1::DataType type, nvinfer1::PluginFormat format)
const TRT_NOEXCEPT override;
nvinfer1::Dims getOutputDimensions(int index,
const nvinfer1::Dims* inputs,
int nbInputDims) TRT_NOEXCEPT override;
int enqueue(int batchSize,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
};
class MishPluginCreator : public TensorRTPluginCreator {
public:
const char* getPluginName() const TRT_NOEXCEPT override {
return "mish_plugin";
}
const char* getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
nvinfer1::IPluginV2* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override {
return new MishPlugin(serial_data, serial_length);
}
};
REGISTER_TRT_PLUGIN_V2(MishPluginCreator);
class MishPluginDynamic : public DynamicPluginTensorRT {
public:
explicit MishPluginDynamic(const float threshold, const bool with_fp16)
: threshold_(threshold) {
with_fp16_ = with_fp16;
}
MishPluginDynamic(void const* serialData, size_t serialLength) {
DeserializeValue(&serialData, &serialLength, &threshold_);
DeserializeValue(&serialData, &serialLength, &with_fp16_);
}
nvinfer1::IPluginV2DynamicExt* clone() const TRT_NOEXCEPT override {
return new MishPluginDynamic(threshold_, with_fp16_);
}
const char* getPluginType() const TRT_NOEXCEPT override {
return "mish_plugin_dynamic";
}
int getNbOutputs() const TRT_NOEXCEPT override { return 1; }
int initialize() TRT_NOEXCEPT override;
size_t getSerializationSize() const TRT_NOEXCEPT override;
void serialize(void* buffer) const TRT_NOEXCEPT override;
nvinfer1::DimsExprs getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs* inputs,
int nb_inputs,
nvinfer1::IExprBuilder& expr_builder) // NOLINT
TRT_NOEXCEPT override;
bool supportsFormatCombination(int pos,
const nvinfer1::PluginTensorDesc* inOut,
int nbInputs,
int nbOutputs) TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::DynamicPluginTensorDesc* in,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc* out,
int nbOutputs) TRT_NOEXCEPT override {}
size_t getWorkspaceSize(const nvinfer1::PluginTensorDesc* inputs,
int nbInputs,
const nvinfer1::PluginTensorDesc* outputs,
int nbOutputs) const TRT_NOEXCEPT override {
return 0;
}
int enqueue(const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* inputTypes,
int nbInputs) const
TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override { delete this; }
private:
float threshold_;
};
class MishPluginDynamicCreator : public TensorRTPluginCreator {
public:
const char* getPluginName() const TRT_NOEXCEPT override {
return "mish_plugin_dynamic";
}
const char* getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
nvinfer1::IPluginV2* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override {
auto plugin = new MishPluginDynamic(serial_data, serial_length);
return plugin;
}
};
REGISTER_TRT_PLUGIN_V2(MishPluginDynamicCreator);
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,360 @@
// Copyright (c) 2022 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/plugin/multihead_matmul_roformer_plugin.h"
#include <stdio.h>
#include <cassert>
#include <cub/cub.cuh> // NOLINT
#include <vector>
#include "glog/logging.h"
#include "paddle/fluid/framework/tensor.h"
#include "paddle/fluid/framework/tensor_util.h"
#include "paddle/fluid/inference/tensorrt/plugin/common/common.cuh"
#include "paddle/fluid/inference/tensorrt/plugin/trt_plugin_utils.h"
#include "paddle/phi/core/platform/device_context.h"
#include "paddle/phi/kernels/funcs/blas/blas.h"
#include "paddle/phi/kernels/funcs/multihead_matmul_functor.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
int MultiheadMatmulRoformerPlugin::initialize() TRT_NOEXCEPT { return 0; }
nvinfer1::DimsExprs MultiheadMatmulRoformerPlugin::getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs *inputs,
int nb_inputs,
nvinfer1::IExprBuilder &expr_builder) TRT_NOEXCEPT {
// input[0], (B, S, 3 * N * H, 1, 1)
// input[1], (B, head_num, seq_len, seq_len)
// output, (B, seq_len, hidden)
PADDLE_ENFORCE_EQ(output_index,
0,
common::errors::InvalidArgument(
"There is only one output of the EmbEltwiseLayernorm, "
"so the index should be zero,"
"but it's (%d)",
output_index));
PADDLE_ENFORCE_EQ(
nb_inputs,
4,
common::errors::InvalidArgument(
"The Input of the EmbEltwiseLayernorm should be 3, but we found "
"it has (%d) inputs",
nb_inputs));
nvinfer1::DimsExprs ret;
ret.nbDims = 3;
ret.d[0] = inputs[0].d[0];
ret.d[1] = inputs[0].d[1];
ret.d[2] = expr_builder.constant(head_size_ * head_number_);
return ret;
}
bool MultiheadMatmulRoformerPlugin::supportsFormatCombination(
int pos,
const nvinfer1::PluginTensorDesc *in_out,
int nb_inputs,
int nb_outputs) TRT_NOEXCEPT {
PADDLE_ENFORCE_NOT_NULL(
in_out,
common::errors::InvalidArgument(
"The input of swish plugin should not be nullptr."));
PADDLE_ENFORCE_LT(
pos,
nb_inputs + nb_outputs,
common::errors::InvalidArgument("The pos(%d) should be less than the "
"num(%d) of the input and the output.",
pos,
nb_inputs + nb_outputs));
const nvinfer1::PluginTensorDesc &in = in_out[pos];
if (pos == 0) {
if (with_fp16_) {
return (in.type == nvinfer1::DataType::kFLOAT ||
in.type == nvinfer1::DataType::kHALF) &&
(in.format == nvinfer1::TensorFormat::kLINEAR);
} else {
return (in.type == nvinfer1::DataType::kFLOAT) &&
(in.format == nvinfer1::TensorFormat::kLINEAR);
}
}
const nvinfer1::PluginTensorDesc &prev = in_out[pos - 1];
if (pos == 1) {
return in.type == prev.type && in.format == prev.format;
}
// output
return in.type == prev.type && in.format == prev.format;
}
nvinfer1::DataType MultiheadMatmulRoformerPlugin::getOutputDataType(
int index,
const nvinfer1::DataType *input_types,
int nb_inputs) const TRT_NOEXCEPT {
PADDLE_ENFORCE_EQ(
index,
0,
common::errors::InvalidArgument(
"The EmbEltwiseLayernorm Plugin only has one input, so the "
"index value should be 0, but get %d.",
index));
return input_types[0];
}
template <typename T>
__global__ void apply_scale(T *data, T scale, int n) {
#if CUDA_ARCH_FP16_SUPPORTED(__CUDA_ARCH__)
int tid = blockIdx.x * blockDim.x + threadIdx.x;
if (tid < n) {
data[tid] = data[tid] * scale;
}
#endif
}
template <typename T>
__global__ void RotrayKernel(const T *inputact,
const T *input1,
const T *input2,
T *output,
const int nElement,
const int lastdim) {
const int index = blockIdx.x * blockDim.x + threadIdx.x;
if (index >= nElement) return;
T left_elemul_out = input1[index] * inputact[index];
int col = index % lastdim;
int half_lastdim = lastdim / 2;
const int right_index = index - col + (col + half_lastdim) % lastdim;
output[index] = left_elemul_out + input2[index] * inputact[right_index];
}
inline int round_up(int seq_len, int multiple = 32) {
PADDLE_ENFORCE_GT(
multiple,
0,
common::errors::InvalidArgument(
"multiple should be a positive number, but it's (%d)", multiple));
return ((seq_len + multiple - 1) / multiple) * multiple;
}
template <typename T>
__global__ void broadcast(const T *src,
T *dst,
const int seq_len,
const int head_num) {
int batch_id = blockIdx.x / (head_num * seq_len);
int dst_offset = blockIdx.x * seq_len;
if (threadIdx.x < seq_len) {
dst[threadIdx.x + dst_offset] = src[threadIdx.x + batch_id * seq_len];
}
}
int MultiheadMatmulRoformerPlugin::enqueue(
const nvinfer1::PluginTensorDesc *input_desc,
const nvinfer1::PluginTensorDesc *output_desc,
const void *const *inputs,
void *const *outputs,
void *workspace,
cudaStream_t stream) TRT_NOEXCEPT {
auto input_dims = input_desc[0].dims;
int input_num = ProductDim(input_dims);
// input[0], (B, S, 3 * N * H, 1, 1)
int batch = input_dims.d[0];
int seq_len = input_dims.d[1];
phi::DenseTensor multihead_temp_tensor;
// masks
int scratch_size = batch * head_number_ * seq_len * seq_len * 1;
int device_id;
cudaGetDevice(&device_id);
multihead_temp_tensor.Resize({scratch_size + input_num});
// for roformer
phi::DenseTensor temp_roformer_tensor;
temp_roformer_tensor.Resize({input_num});
auto input_type = input_desc[0].type;
if (input_type == nvinfer1::DataType::kFLOAT) {
VLOG(1) << "TRT Plugin DataType selected. RoformerQkvToContext-->fp32";
auto *multihead_temp_data =
multihead_temp_tensor.mutable_data<float>(GPUPlace(device_id));
auto *temp_roformer_data =
temp_roformer_tensor.mutable_data<float>( // NOLINT
GPUPlace(device_id));
auto *tmp_roformer_ptr = reinterpret_cast<float *>(temp_roformer_data);
auto *qkptr = multihead_temp_data;
auto *tptr = multihead_temp_data + scratch_size;
const float *input0_data = static_cast<const float *>(inputs[0]);
// fit to [batch, head_num, length, length] + [batch, 1, 1, length]
phi::DenseTensor temp_qk_bias_tensor;
float *qk_bias = const_cast<float *>(static_cast<const float *>(inputs[3]));
if (ProductDim(input_desc[3].dims) == (batch * seq_len)) {
temp_qk_bias_tensor.Resize({batch, head_number_, seq_len, seq_len});
auto *temp_qk_bias =
temp_qk_bias_tensor.mutable_data<float>(GPUPlace(device_id));
int grid = batch * head_number_ * seq_len;
int block = round_up(seq_len);
broadcast<<<grid, block, 0, stream>>>(
static_cast<const float *>(inputs[3]),
temp_qk_bias,
seq_len,
head_number_);
qk_bias = temp_qk_bias;
}
const float *input3_data = static_cast<const float *>(qk_bias);
// BxSx3xNxH => tptr: 3xBxNxSxH.
TransposeQKV(
batch, seq_len, head_size_, head_number_, input0_data, tptr, stream);
cudaMemcpy(tmp_roformer_ptr, // dst
tptr, // src
input_num * sizeof(float),
cudaMemcpyDeviceToDevice);
int n_q = seq_len * head_number_ * head_size_ * batch;
constexpr int threads = 128;
int blocks = (n_q + threads - 1) / threads;
const float *input_cos_data = static_cast<const float *>(inputs[1]);
const float *input_sin_data = static_cast<const float *>(inputs[2]);
RotrayKernel<<<blocks, threads, 0, stream>>>(tmp_roformer_ptr,
input_cos_data,
input_sin_data,
tptr,
n_q,
head_size_); // q
RotrayKernel<<<blocks, threads, 0, stream>>>(tmp_roformer_ptr + n_q,
input_cos_data,
input_sin_data,
tptr + n_q,
n_q,
head_size_); // k
auto *device_ctx = static_cast<phi::GPUContext *>(
phi::DeviceContextPool::Instance().Get(GPUPlace(device_id)));
const phi::GPUContext &dev_ctx = *device_ctx;
phi::funcs::MultiheadGPUComputeFunctor<float> multihead_compute_func;
multihead_compute_func(dev_ctx,
batch,
seq_len,
head_number_,
head_size_,
qkptr,
input3_data,
false,
tptr,
scale_,
static_cast<float>(0.0));
int grid = batch * head_number_ * seq_len;
int block = head_size_;
float *output = static_cast<float *>(outputs[0]);
transpose<float><<<grid, block, 0, stream>>>(
tptr, output, batch, seq_len, head_number_, head_size_);
} else if (input_type == nvinfer1::DataType::kHALF) {
VLOG(1) << "TRT Plugin DataType selected. QkvToContext-->fp16";
auto *multihead_temp_data =
multihead_temp_tensor.mutable_data<int16_t>( // NOLINT
GPUPlace(device_id));
auto *temp_roformer_data =
temp_roformer_tensor.mutable_data<int16_t>( // NOLINT
GPUPlace(device_id));
half *tmp_roformer_ptr = reinterpret_cast<half *>(temp_roformer_data);
half *qkptr = reinterpret_cast<half *>(multihead_temp_data);
half *tptr = qkptr + scratch_size;
const half *input0_data = static_cast<const half *>(inputs[0]);
// fit to [batch, head_num, length, length] + [batch, 1, 1, length]
phi::DenseTensor temp_qk_bias_tensor;
half *qk_bias = const_cast<half *>(static_cast<const half *>(inputs[3]));
if (ProductDim(input_desc[3].dims) == (batch * seq_len)) {
temp_qk_bias_tensor.Resize({batch, head_number_, seq_len, seq_len});
auto *temp_qk_bias = reinterpret_cast<half *>(
temp_qk_bias_tensor.mutable_data<int16_t>(GPUPlace(device_id)));
int grid = batch * head_number_ * seq_len;
int block = round_up(seq_len);
broadcast<<<grid, block, 0, stream>>>(
static_cast<const half *>(inputs[3]),
temp_qk_bias,
seq_len,
head_number_);
qk_bias = temp_qk_bias;
}
const half *input3_data = static_cast<const half *>(qk_bias);
// BxSx3xNxH => tptr: 3xBxNxSxH.
TransposeQKV(
batch, seq_len, head_size_, head_number_, input0_data, tptr, stream);
cudaMemcpy(tmp_roformer_ptr,
tptr,
input_num * sizeof(half),
cudaMemcpyDeviceToDevice);
auto *device_ctx = static_cast<phi::GPUContext *>(
phi::DeviceContextPool::Instance().Get(GPUPlace(device_id)));
int n_q = seq_len * head_number_ * head_size_ * batch;
constexpr int threads = 128;
int blocks = (n_q + threads - 1) / threads;
const half *input_cos_data = static_cast<const half *>(inputs[1]);
const half *input_sin_data = static_cast<const half *>(inputs[2]);
RotrayKernel<<<blocks, threads, 0, stream>>>(tmp_roformer_ptr,
input_cos_data,
input_sin_data,
tptr,
n_q,
head_size_); // q
RotrayKernel<<<blocks, threads, 0, stream>>>(tmp_roformer_ptr + n_q,
input_cos_data,
input_sin_data,
tptr + n_q,
n_q,
head_size_); // k
apply_scale<<<blocks, threads, 0, stream>>>(
tptr, static_cast<half>(scale_), n_q);
const phi::GPUContext &dev_ctx = *device_ctx;
phi::funcs::MultiheadGPUComputeFunctor<half> multihead_compute_func;
multihead_compute_func(dev_ctx,
batch,
seq_len,
head_number_,
head_size_,
qkptr,
input3_data,
false,
tptr,
half(1.),
half(0.0));
int grid = batch * head_number_ * seq_len;
int block = head_size_;
half *output = static_cast<half *>(outputs[0]);
transpose<half><<<grid, block, 0, stream>>>(
tptr, output, batch, seq_len, head_number_, head_size_);
} else {
PADDLE_THROW(common::errors::Fatal(
"The QKV TRT Plugin's input type should be float or half."));
}
return cudaGetLastError() != cudaSuccess;
}
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,161 @@
// Copyright (c) 2022 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.
#pragma once
#include <algorithm>
#include <string>
#include <vector>
#include "paddle/fluid/inference/tensorrt/engine.h"
#include "paddle/fluid/inference/tensorrt/plugin/trt_plugin.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
class MultiheadMatmulRoformerPlugin : public DynamicPluginTensorRT {
public:
explicit MultiheadMatmulRoformerPlugin(
int hidden, int head_number, int head_size, float scale, bool with_fp16)
: hidden_(hidden),
head_number_(head_number),
head_size_(head_size),
scale_(scale) {
with_fp16_ = with_fp16;
}
MultiheadMatmulRoformerPlugin(void const* serial_data, size_t serial_length) {
DeserializeValue(&serial_data, &serial_length, &hidden_);
DeserializeValue(&serial_data, &serial_length, &head_number_);
DeserializeValue(&serial_data, &serial_length, &head_size_);
DeserializeValue(&serial_data, &serial_length, &scale_);
DeserializeValue(&serial_data, &serial_length, &with_fp16_);
}
nvinfer1::IPluginV2DynamicExt* clone() const TRT_NOEXCEPT override {
return new MultiheadMatmulRoformerPlugin(
hidden_, head_number_, head_size_, scale_, with_fp16_);
}
const char* getPluginType() const TRT_NOEXCEPT override {
return "multihead_matmul_roformer_plugin";
}
int getNbOutputs() const TRT_NOEXCEPT override { return 1; }
int initialize() TRT_NOEXCEPT override;
size_t getSerializationSize() const TRT_NOEXCEPT override {
return SerializedSize(hidden_) + SerializedSize(head_number_) +
SerializedSize(head_size_) + SerializedSize(scale_) +
SerializedSize(with_fp16_);
}
void serialize(void* buffer) const TRT_NOEXCEPT override {
SerializeValue(&buffer, hidden_);
SerializeValue(&buffer, head_number_);
SerializeValue(&buffer, head_size_);
SerializeValue(&buffer, scale_);
SerializeValue(&buffer, with_fp16_);
}
nvinfer1::DimsExprs getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs* inputs,
int nb_inputs,
nvinfer1::IExprBuilder& expr_builder) // NOLINT
TRT_NOEXCEPT override;
bool supportsFormatCombination(int pos,
const nvinfer1::PluginTensorDesc* in_out,
int nb_inputs,
int nb_outputs) TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::DynamicPluginTensorDesc* in,
int nb_inputs,
const nvinfer1::DynamicPluginTensorDesc* out,
int nb_outputs) TRT_NOEXCEPT override {}
size_t getWorkspaceSize(const nvinfer1::PluginTensorDesc* inputs,
int nb_inputs,
const nvinfer1::PluginTensorDesc* outputs,
int nb_outputs) const TRT_NOEXCEPT override {
return 0;
}
int enqueue(const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* input_types,
int nb_inputs) const
TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override { delete this; }
private:
int hidden_;
int head_number_;
int head_size_;
float scale_;
};
class MultiheadMatmulRoformerPluginCreator : public nvinfer1::IPluginCreator {
public:
MultiheadMatmulRoformerPluginCreator() {}
const char* getPluginName() const TRT_NOEXCEPT override {
return "multihead_matmul_roformer_plugin";
}
const char* getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
const nvinfer1::PluginFieldCollection* getFieldNames() TRT_NOEXCEPT override {
return &field_collection_;
}
nvinfer1::IPluginV2* createPlugin(const char* name,
const nvinfer1::PluginFieldCollection* fc)
TRT_NOEXCEPT override {
return nullptr;
}
nvinfer1::IPluginV2* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override {
auto plugin = new MultiheadMatmulRoformerPlugin(serial_data, serial_length);
return plugin;
}
void setPluginNamespace(const char* lib_namespace) TRT_NOEXCEPT override {
plugin_namespace_ = lib_namespace;
}
const char* getPluginNamespace() const TRT_NOEXCEPT override {
return plugin_namespace_.c_str();
}
private:
std::string plugin_namespace_;
std::string plugin_name_;
nvinfer1::PluginFieldCollection field_collection_;
std::vector<nvinfer1::PluginField> plugin_attributes_;
};
REGISTER_TRT_PLUGIN_V2(MultiheadMatmulRoformerPluginCreator);
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,719 @@
// Copyright (c) 2021 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, softwarepool
// 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/plugin/pool3d_op_plugin.h"
#include "paddle/phi/kernels/funcs/pooling.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
size_t Pool3DPlugin::getSerializationSize() const TRT_NOEXCEPT {
return getBaseSerializationSize() + SerializedSize(ceil_mode_) +
SerializedSize(pool3d_type_) + SerializedSize(adaptive_) +
SerializedSize(ksize_) + SerializedSize(strides_) +
SerializedSize(paddings_) + SerializedSize(input_shape_) +
SerializedSize(output_shape_);
}
// TRT will call this func when we need to serialize the configuration of
// tensorrt.
void Pool3DPlugin::serialize(void *buffer) const TRT_NOEXCEPT {
serializeBase(buffer);
SerializeValue(&buffer, ceil_mode_);
SerializeValue(&buffer, pool3d_type_);
SerializeValue(&buffer, adaptive_);
SerializeValue(&buffer, ksize_);
SerializeValue(&buffer, strides_);
SerializeValue(&buffer, paddings_);
SerializeValue(&buffer, input_shape_);
SerializeValue(&buffer, output_shape_);
}
Pool3DPlugin *Pool3DPlugin::clone() const TRT_NOEXCEPT {
return new Pool3DPlugin(ceil_mode_,
pool3d_type_,
adaptive_,
ksize_,
strides_,
paddings_,
input_shape_);
}
const char *Pool3DPlugin::getPluginType() const TRT_NOEXCEPT {
return "pool3d_plugin";
}
int Pool3DPlugin::getNbOutputs() const TRT_NOEXCEPT { return 1; }
int Pool3DPlugin::initialize() TRT_NOEXCEPT { return 0; }
nvinfer1::DataType Pool3DPlugin::getOutputDataType(
int index,
const nvinfer1::DataType *input_types,
int nb_inputs) const TRT_NOEXCEPT {
return input_types[0];
}
void Pool3DPlugin::destroy() TRT_NOEXCEPT { delete this; }
nvinfer1::Dims Pool3DPlugin::getOutputDimensions(
int index, const nvinfer1::Dims *inputDims, int nbInputs) TRT_NOEXCEPT {
PADDLE_ENFORCE_EQ(nbInputs,
1,
common::errors::InvalidArgument(
"The Pool3D Plugin only has one input, so the nbInputs "
"value should be 1, but get %d.",
nbInputs));
PADDLE_ENFORCE_EQ(index,
0,
common::errors::InvalidArgument(
"The Pool3D Plugin only has one input, so "
"the index value should be 0, but get %d.",
index));
PADDLE_ENFORCE_EQ(inputDims[0].nbDims,
4,
common::errors::InvalidArgument(
"The Pool3D Plugin only has four Dimensions, so the "
"nbDims value should be 4, but get %d.",
inputDims[0].nbDims));
nvinfer1::Dims const &input_dims = inputDims[0];
nvinfer1::Dims output_dims = input_dims;
output_dims.d[1] = output_shape_[1];
output_dims.d[2] = output_shape_[2];
output_dims.d[3] = output_shape_[3];
return output_dims;
}
int Pool3DPlugin::enqueue(int batchSize,
const void *const *inputs,
void *const *outputs,
void *workspace,
cudaStream_t stream) TRT_NOEXCEPT {
int input_size = 0;
float const *idata = reinterpret_cast<float const *>(inputs[0]);
float *const *odatas = reinterpret_cast<float *const *>(outputs);
std::vector<int> input_shape = input_shape_;
std::vector<int> output_shape = output_shape_;
input_shape.insert(input_shape.begin(), batchSize);
output_shape.insert(output_shape.begin(), batchSize);
if (pool3d_type_ == Pool3DType::max) {
phi::funcs::MaxPool<float> pool_process;
phi::funcs::Pool3dDirectCUDAFunctor<phi::funcs::MaxPool<float>, float>
pool3d_forward;
pool3d_forward(idata,
input_shape,
output_shape,
ksize_,
strides_,
paddings_,
true,
adaptive_,
odatas[0],
stream,
pool_process);
} else if (pool3d_type_ == Pool3DType::avg) {
phi::funcs::AvgPool<float> pool_process;
phi::funcs::Pool3dDirectCUDAFunctor<phi::funcs::AvgPool<float>, float>
pool3d_forward;
pool3d_forward(idata,
input_shape,
output_shape,
ksize_,
strides_,
paddings_,
true,
adaptive_,
odatas[0],
stream,
pool_process);
}
return cudaGetLastError() != cudaSuccess;
}
// Dynamic Plugin below.
Pool3DPluginDynamic::Pool3DPluginDynamic(void const *serialData,
size_t serialLength) {
DeserializeValue(&serialData, &serialLength, &ceil_mode_);
const char *pool3d_type;
DeserializeValue(&serialData, &serialLength, &pool3d_type);
pool3d_type_ = std::string(pool3d_type);
DeserializeValue(&serialData, &serialLength, &adaptive_);
DeserializeValue(&serialData, &serialLength, &ksize_);
DeserializeValue(&serialData, &serialLength, &strides_);
DeserializeValue(&serialData, &serialLength, &paddings_);
DeserializeValue(&serialData, &serialLength, &is_global_);
}
nvinfer1::IPluginV2DynamicExt *Pool3DPluginDynamic::clone() const TRT_NOEXCEPT {
return new Pool3DPluginDynamic(ceil_mode_,
pool3d_type_,
adaptive_,
ksize_,
strides_,
paddings_,
is_global_);
}
const char *Pool3DPluginDynamic::getPluginType() const TRT_NOEXCEPT {
return "pool3d_plugin_dynamic";
}
int Pool3DPluginDynamic::getNbOutputs() const TRT_NOEXCEPT { return 1; }
int Pool3DPluginDynamic::initialize() TRT_NOEXCEPT { return 0; }
void Pool3DPluginDynamic::configurePlugin(
const nvinfer1::DynamicPluginTensorDesc *in,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc *out,
int nbOutputs) TRT_NOEXCEPT {}
size_t Pool3DPluginDynamic::getWorkspaceSize(
const nvinfer1::PluginTensorDesc *inputs,
int nbInputs,
const nvinfer1::PluginTensorDesc *outputs,
int nbOutputs) const TRT_NOEXCEPT {
return 0;
}
size_t Pool3DPluginDynamic::getSerializationSize() const TRT_NOEXCEPT {
return SerializedSize(ceil_mode_) + SerializedSize(pool3d_type_.c_str()) +
SerializedSize(adaptive_) + SerializedSize(ksize_) +
SerializedSize(strides_) + SerializedSize(paddings_) +
SerializedSize(is_global_);
}
void Pool3DPluginDynamic::serialize(void *buffer) const TRT_NOEXCEPT {
SerializeValue(&buffer, ceil_mode_);
SerializeValue(&buffer, pool3d_type_.c_str());
SerializeValue(&buffer, adaptive_);
SerializeValue(&buffer, ksize_);
SerializeValue(&buffer, strides_);
SerializeValue(&buffer, paddings_);
SerializeValue(&buffer, is_global_);
}
nvinfer1::DimsExprs Pool3DPluginDynamic::getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs *inputs,
int nb_inputs,
nvinfer1::IExprBuilder &expr_builder) TRT_NOEXCEPT {
PADDLE_ENFORCE_EQ(nb_inputs,
1,
common::errors::InvalidArgument(
"The Split plugin should be only one input."));
PADDLE_ENFORCE_EQ(
inputs[0].d[1]->isConstant(),
true,
common::errors::InvalidArgument("The channel dimension should be "
"static, but we found it's dynamic."));
nvinfer1::DimsExprs output(inputs[0]);
if (is_global_) {
output.d[2] = expr_builder.constant(1);
output.d[3] = expr_builder.constant(1);
output.d[4] = expr_builder.constant(1);
return output;
}
if (adaptive_) {
output.d[2] = expr_builder.constant(ksize_[0]);
output.d[3] = expr_builder.constant(ksize_[1]);
output.d[4] = expr_builder.constant(ksize_[2]);
return output;
}
auto stri_0 = expr_builder.constant(strides_[0]);
auto stri_1 = expr_builder.constant(strides_[1]);
auto stri_2 = expr_builder.constant(strides_[2]);
auto one_value = expr_builder.constant(1);
auto v0_tmp = expr_builder.constant(-ksize_[0] + 2 * paddings_[0]);
auto v1_tmp = expr_builder.constant(-ksize_[1] + 2 * paddings_[1]);
auto v2_tmp = expr_builder.constant(-ksize_[2] + 2 * paddings_[2]);
auto ceil_tmp =
expr_builder.constant(-ksize_[0] + 2 * paddings_[0] + strides_[0] - 1);
auto ceil1_tmp =
expr_builder.constant(-ksize_[1] + 2 * paddings_[1] + strides_[1] - 1);
auto ceil2_tmp =
expr_builder.constant(-ksize_[2] + 2 * paddings_[2] + strides_[2] - 1);
if (!ceil_mode_) {
output.d[2] = expr_builder.operation(
nvinfer1::DimensionOperation::kSUM,
*expr_builder.operation(
nvinfer1::DimensionOperation::kFLOOR_DIV,
*expr_builder.operation(
nvinfer1::DimensionOperation::kSUM, *inputs[0].d[2], *v0_tmp),
*stri_0),
*one_value);
output.d[3] = expr_builder.operation(
nvinfer1::DimensionOperation::kSUM,
*expr_builder.operation(
nvinfer1::DimensionOperation::kFLOOR_DIV,
*expr_builder.operation(
nvinfer1::DimensionOperation::kSUM, *inputs[0].d[3], *v1_tmp),
*stri_1),
*one_value);
output.d[4] = expr_builder.operation(
nvinfer1::DimensionOperation::kSUM,
*expr_builder.operation(
nvinfer1::DimensionOperation::kFLOOR_DIV,
*expr_builder.operation(
nvinfer1::DimensionOperation::kSUM, *inputs[0].d[4], *v2_tmp),
*stri_2),
*one_value);
} else {
output.d[2] = expr_builder.operation(
nvinfer1::DimensionOperation::kSUM,
*expr_builder.operation(
nvinfer1::DimensionOperation::kFLOOR_DIV,
*expr_builder.operation(
nvinfer1::DimensionOperation::kSUM, *inputs[0].d[2], *ceil_tmp),
*stri_0),
*one_value);
output.d[3] = expr_builder.operation(
nvinfer1::DimensionOperation::kSUM,
*expr_builder.operation(
nvinfer1::DimensionOperation::kFLOOR_DIV,
*expr_builder.operation(nvinfer1::DimensionOperation::kSUM,
*inputs[0].d[3],
*ceil1_tmp),
*stri_1),
*one_value);
output.d[4] = expr_builder.operation(
nvinfer1::DimensionOperation::kSUM,
*expr_builder.operation(
nvinfer1::DimensionOperation::kFLOOR_DIV,
*expr_builder.operation(nvinfer1::DimensionOperation::kSUM,
*inputs[0].d[4],
*ceil2_tmp),
*stri_2),
*one_value);
}
return output;
}
bool Pool3DPluginDynamic::supportsFormatCombination(
int pos,
const nvinfer1::PluginTensorDesc *in_out,
int nb_inputs,
int nb_outputs) TRT_NOEXCEPT {
PADDLE_ENFORCE_NOT_NULL(
in_out,
common::errors::InvalidArgument(
"The input of swish plugin should not be nullptr."));
PADDLE_ENFORCE_LT(
pos,
nb_inputs + nb_outputs,
common::errors::InvalidArgument("The pos(%d) should be less than the "
"num(%d) of the input and the output.",
pos,
nb_inputs + nb_outputs));
(in_out && pos < (nb_inputs + nb_outputs));
return ((in_out[pos].type == nvinfer1::DataType::kFLOAT) &&
in_out[pos].format == nvinfer1::PluginFormat::kLINEAR);
}
nvinfer1::DataType Pool3DPluginDynamic::getOutputDataType(
int index,
const nvinfer1::DataType *input_types,
int nb_inputs) const TRT_NOEXCEPT {
PADDLE_ENFORCE_EQ(index,
0,
common::errors::InvalidArgument(
"The Pool3D Plugin only has one input, so the "
"index value should be 0, but get %d.",
index));
PADDLE_ENFORCE_EQ(
(input_types[0] == nvinfer1::DataType::kFLOAT),
true,
common::errors::InvalidArgument("The input type should be float"));
return input_types[0];
}
int Pool3DPluginDynamic::enqueue(const nvinfer1::PluginTensorDesc *input_desc,
const nvinfer1::PluginTensorDesc *output_desc,
const void *const *inputs,
void *const *outputs,
void *workspace,
cudaStream_t stream) TRT_NOEXCEPT {
auto input_dims = input_desc[0].dims;
int n = input_dims.d[0];
int c = input_dims.d[1];
int d = input_dims.d[2];
int h = input_dims.d[3];
int w = input_dims.d[4];
const float *input = static_cast<const float *>(inputs[0]);
float *output = static_cast<float *>(outputs[0]);
std::vector<int> input_shape, output_shape;
for (int i = 0; i < input_dims.nbDims; i++)
input_shape.push_back(input_dims.d[i]);
output_shape = input_shape;
std::vector<int> ksize = ksize_;
std::vector<int> paddings = paddings_;
if (is_global_) {
ksize[0] = d;
ksize[1] = h;
ksize[2] = w;
paddings[0] = 0;
paddings[1] = 0;
paddings[2] = 0;
output_shape[2] = 1;
output_shape[3] = 1;
output_shape[4] = 1;
} else {
auto data_dim = CalcOutputSize(
{d, h, w}, ceil_mode_, adaptive_, ksize_, strides_, paddings_);
output_shape[2] = data_dim[0];
output_shape[3] = data_dim[1];
output_shape[4] = data_dim[2];
}
if (pool3d_type_ == "max") {
phi::funcs::MaxPool<float> pool_process;
phi::funcs::Pool3dDirectCUDAFunctor<phi::funcs::MaxPool<float>, float>
pool3d_forward;
pool3d_forward(input,
input_shape,
output_shape,
ksize,
strides_,
paddings,
true,
adaptive_,
output,
stream,
pool_process);
} else if (pool3d_type_ == "avg") {
phi::funcs::AvgPool<float> pool_process;
phi::funcs::Pool3dDirectCUDAFunctor<phi::funcs::AvgPool<float>, float>
pool3d_forward;
pool3d_forward(input,
input_shape,
output_shape,
ksize,
strides_,
paddings,
true,
adaptive_,
output,
stream,
pool_process);
}
return cudaGetLastError() != cudaSuccess;
}
PIRPool3DPluginDynamic::PIRPool3DPluginDynamic(void const *serialData,
size_t serialLength) {
DeserializeValue(&serialData, &serialLength, &ceil_mode_);
const char *pool3d_type;
DeserializeValue(&serialData, &serialLength, &pool3d_type);
pool3d_type_ = std::string(pool3d_type);
DeserializeValue(&serialData, &serialLength, &adaptive_);
DeserializeValue(&serialData, &serialLength, &ksize_);
DeserializeValue(&serialData, &serialLength, &strides_);
DeserializeValue(&serialData, &serialLength, &paddings_);
DeserializeValue(&serialData, &serialLength, &is_global_);
}
nvinfer1::IPluginV2DynamicExt *PIRPool3DPluginDynamic::clone() const
TRT_NOEXCEPT {
return new PIRPool3DPluginDynamic(ceil_mode_,
pool3d_type_,
adaptive_,
ksize_,
strides_,
paddings_,
is_global_);
}
const char *PIRPool3DPluginDynamic::getPluginType() const TRT_NOEXCEPT {
return "pir_pool3d_plugin_dynamic";
}
int PIRPool3DPluginDynamic::getNbOutputs() const TRT_NOEXCEPT { return 1; }
int PIRPool3DPluginDynamic::initialize() TRT_NOEXCEPT { return 0; }
void PIRPool3DPluginDynamic::configurePlugin(
const nvinfer1::DynamicPluginTensorDesc *in,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc *out,
int nbOutputs) TRT_NOEXCEPT {}
size_t PIRPool3DPluginDynamic::getWorkspaceSize(
const nvinfer1::PluginTensorDesc *inputs,
int nbInputs,
const nvinfer1::PluginTensorDesc *outputs,
int nbOutputs) const TRT_NOEXCEPT {
return 0;
}
size_t PIRPool3DPluginDynamic::getSerializationSize() const TRT_NOEXCEPT {
return SerializedSize(ceil_mode_) + SerializedSize(pool3d_type_.c_str()) +
SerializedSize(adaptive_) + SerializedSize(ksize_) +
SerializedSize(strides_) + SerializedSize(paddings_) +
SerializedSize(is_global_);
}
void PIRPool3DPluginDynamic::serialize(void *buffer) const TRT_NOEXCEPT {
SerializeValue(&buffer, ceil_mode_);
SerializeValue(&buffer, pool3d_type_.c_str());
SerializeValue(&buffer, adaptive_);
SerializeValue(&buffer, ksize_);
SerializeValue(&buffer, strides_);
SerializeValue(&buffer, paddings_);
SerializeValue(&buffer, is_global_);
}
nvinfer1::DimsExprs PIRPool3DPluginDynamic::getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs *inputs,
int nb_inputs,
nvinfer1::IExprBuilder &expr_builder) TRT_NOEXCEPT {
PADDLE_ENFORCE_EQ(nb_inputs,
1,
common::errors::InvalidArgument(
"The Split plugin should be only one input."));
PADDLE_ENFORCE_EQ(
inputs[0].d[1]->isConstant(),
true,
common::errors::InvalidArgument("The channel dimension should be "
"static, but we found it's dynamic."));
nvinfer1::DimsExprs output(inputs[0]);
if (is_global_) {
output.d[2] = expr_builder.constant(1);
output.d[3] = expr_builder.constant(1);
output.d[4] = expr_builder.constant(1);
return output;
}
if (adaptive_) {
output.d[2] = expr_builder.constant(ksize_[0]);
output.d[3] = expr_builder.constant(ksize_[1]);
output.d[4] = expr_builder.constant(ksize_[2]);
return output;
}
auto stri_0 = expr_builder.constant(strides_[0]);
auto stri_1 = expr_builder.constant(strides_[1]);
auto stri_2 = expr_builder.constant(strides_[2]);
auto one_value = expr_builder.constant(1);
auto v0_tmp = expr_builder.constant(-ksize_[0] + 2 * paddings_[0]);
auto v1_tmp = expr_builder.constant(-ksize_[1] + 2 * paddings_[1]);
auto v2_tmp = expr_builder.constant(-ksize_[2] + 2 * paddings_[2]);
auto ceil_tmp =
expr_builder.constant(-ksize_[0] + 2 * paddings_[0] + strides_[0] - 1);
auto ceil1_tmp =
expr_builder.constant(-ksize_[1] + 2 * paddings_[1] + strides_[1] - 1);
auto ceil2_tmp =
expr_builder.constant(-ksize_[2] + 2 * paddings_[2] + strides_[2] - 1);
if (!ceil_mode_) {
output.d[2] = expr_builder.operation(
nvinfer1::DimensionOperation::kSUM,
*expr_builder.operation(
nvinfer1::DimensionOperation::kFLOOR_DIV,
*expr_builder.operation(
nvinfer1::DimensionOperation::kSUM, *inputs[0].d[2], *v0_tmp),
*stri_0),
*one_value);
output.d[3] = expr_builder.operation(
nvinfer1::DimensionOperation::kSUM,
*expr_builder.operation(
nvinfer1::DimensionOperation::kFLOOR_DIV,
*expr_builder.operation(
nvinfer1::DimensionOperation::kSUM, *inputs[0].d[3], *v1_tmp),
*stri_1),
*one_value);
output.d[4] = expr_builder.operation(
nvinfer1::DimensionOperation::kSUM,
*expr_builder.operation(
nvinfer1::DimensionOperation::kFLOOR_DIV,
*expr_builder.operation(
nvinfer1::DimensionOperation::kSUM, *inputs[0].d[4], *v2_tmp),
*stri_2),
*one_value);
} else {
output.d[2] = expr_builder.operation(
nvinfer1::DimensionOperation::kSUM,
*expr_builder.operation(
nvinfer1::DimensionOperation::kFLOOR_DIV,
*expr_builder.operation(
nvinfer1::DimensionOperation::kSUM, *inputs[0].d[2], *ceil_tmp),
*stri_0),
*one_value);
output.d[3] = expr_builder.operation(
nvinfer1::DimensionOperation::kSUM,
*expr_builder.operation(
nvinfer1::DimensionOperation::kFLOOR_DIV,
*expr_builder.operation(nvinfer1::DimensionOperation::kSUM,
*inputs[0].d[3],
*ceil1_tmp),
*stri_1),
*one_value);
output.d[4] = expr_builder.operation(
nvinfer1::DimensionOperation::kSUM,
*expr_builder.operation(
nvinfer1::DimensionOperation::kFLOOR_DIV,
*expr_builder.operation(nvinfer1::DimensionOperation::kSUM,
*inputs[0].d[4],
*ceil2_tmp),
*stri_2),
*one_value);
}
return output;
}
bool PIRPool3DPluginDynamic::supportsFormatCombination(
int pos,
const nvinfer1::PluginTensorDesc *in_out,
int nb_inputs,
int nb_outputs) TRT_NOEXCEPT {
PADDLE_ENFORCE_NOT_NULL(
in_out,
common::errors::InvalidArgument(
"The input of swish plugin should not be nullptr."));
PADDLE_ENFORCE_LT(
pos,
nb_inputs + nb_outputs,
common::errors::InvalidArgument("The pos(%d) should be less than the "
"num(%d) of the input and the output.",
pos,
nb_inputs + nb_outputs));
(in_out && pos < (nb_inputs + nb_outputs));
return ((in_out[pos].type == nvinfer1::DataType::kFLOAT) &&
in_out[pos].format == nvinfer1::PluginFormat::kLINEAR);
}
nvinfer1::DataType PIRPool3DPluginDynamic::getOutputDataType(
int index,
const nvinfer1::DataType *input_types,
int nb_inputs) const TRT_NOEXCEPT {
PADDLE_ENFORCE_EQ(index,
0,
common::errors::InvalidArgument(
"The Pool3D Plugin only has one input, so the "
"index value should be 0, but get %d.",
index));
PADDLE_ENFORCE_EQ(
(input_types[0] == nvinfer1::DataType::kFLOAT),
true,
common::errors::InvalidArgument("The input type should be float"));
return input_types[0];
}
int PIRPool3DPluginDynamic::enqueue(
const nvinfer1::PluginTensorDesc *input_desc,
const nvinfer1::PluginTensorDesc *output_desc,
const void *const *inputs,
void *const *outputs,
void *workspace,
cudaStream_t stream) TRT_NOEXCEPT {
auto input_dims = input_desc[0].dims;
int n = input_dims.d[0];
int c = input_dims.d[1];
int d = input_dims.d[2];
int h = input_dims.d[3];
int w = input_dims.d[4];
const float *input = static_cast<const float *>(inputs[0]);
float *output = static_cast<float *>(outputs[0]);
std::vector<int> input_shape, output_shape;
for (int i = 0; i < input_dims.nbDims; i++)
input_shape.push_back(input_dims.d[i]);
output_shape = input_shape;
std::vector<int> ksize = ksize_;
std::vector<int> paddings = paddings_;
if (is_global_) {
ksize[0] = d;
ksize[1] = h;
ksize[2] = w;
paddings[0] = 0;
paddings[1] = 0;
paddings[2] = 0;
output_shape[2] = 1;
output_shape[3] = 1;
output_shape[4] = 1;
} else {
auto data_dim = CalcOutputSize(
{d, h, w}, ceil_mode_, adaptive_, ksize_, strides_, paddings_);
output_shape[2] = data_dim[0];
output_shape[3] = data_dim[1];
output_shape[4] = data_dim[2];
}
if (pool3d_type_ == "max") {
phi::funcs::MaxPool<float> pool_process;
phi::funcs::Pool3dDirectCUDAFunctor<phi::funcs::MaxPool<float>, float>
pool3d_forward;
pool3d_forward(input,
input_shape,
output_shape,
ksize,
strides_,
paddings,
true,
adaptive_,
output,
stream,
pool_process);
} else if (pool3d_type_ == "avg") {
phi::funcs::AvgPool<float> pool_process;
phi::funcs::Pool3dDirectCUDAFunctor<phi::funcs::AvgPool<float>, float>
pool3d_forward;
pool3d_forward(input,
input_shape,
output_shape,
ksize,
strides_,
paddings,
true,
adaptive_,
output,
stream,
pool_process);
}
return cudaGetLastError() != cudaSuccess;
}
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,397 @@
// Copyright (c) 2021 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.
#pragma once
#include <stdio.h>
#include <cassert>
#include <string>
#include <vector>
#include "paddle/fluid/inference/tensorrt/plugin/trt_plugin.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
static std::vector<int> CalcOutputSize(const std::vector<int>& input_shape,
const bool& ceil_mode,
const bool& adaptive,
const std::vector<int>& ksize,
const std::vector<int>& strides,
const std::vector<int>& paddings) {
std::vector<int> output_shape = input_shape;
if (adaptive) {
output_shape[0] = ksize[0];
output_shape[1] = ksize[1];
output_shape[2] = ksize[2];
} else {
int output_d =
(input_shape[0] - ksize[0] + 2 * paddings[0]) / strides[0] + 1;
int output_h =
(input_shape[1] - ksize[1] + 2 * paddings[1]) / strides[1] + 1;
int output_w =
(input_shape[2] - ksize[2] + 2 * paddings[2]) / strides[2] + 1;
if (ceil_mode) {
output_d =
(input_shape[0] - ksize[0] + 2 * paddings[0] + strides[0] - 1) /
strides[0] +
1;
output_h =
(input_shape[1] - ksize[1] + 2 * paddings[1] + strides[1] - 1) /
strides[1] +
1;
output_w =
(input_shape[2] - ksize[2] + 2 * paddings[2] + strides[2] - 1) /
strides[2] +
1;
}
output_shape[0] = output_d;
output_shape[1] = output_h;
output_shape[2] = output_w;
}
return output_shape;
}
class Pool3DPlugin : public PluginTensorRTV2Ext {
public:
size_t getSerializationSize() const TRT_NOEXCEPT override;
// TRT will call this func when we need to serialize the configuration of
// tensorrt.
void serialize(void* buffer) const TRT_NOEXCEPT override;
enum class Pool3DType {
max = 0,
avg,
};
Pool3DPlugin() {}
Pool3DPlugin(bool ceil_mode,
Pool3DType pool3d_type,
bool adaptive,
std::vector<int> ksize,
std::vector<int> strides,
std::vector<int> paddings,
std::vector<int> input_shape)
: ceil_mode_(ceil_mode),
pool3d_type_(pool3d_type),
adaptive_(adaptive),
ksize_(ksize),
strides_(strides),
paddings_(paddings),
input_shape_(input_shape) {
output_shape_ = input_shape_;
std::vector<int> output_shape =
CalcOutputSize({input_shape_[1], input_shape_[2], input_shape_[3]},
ceil_mode_,
adaptive_,
ksize_,
strides_,
paddings_);
output_shape_[1] = output_shape[0];
output_shape_[2] = output_shape[1];
output_shape_[3] = output_shape[2];
}
// It was used for tensorrt deserialization.
// It should not be called by users.
Pool3DPlugin(void const* serialData, size_t serialLength) {
deserializeBase(serialData, serialLength);
DeserializeValue(&serialData, &serialLength, &ceil_mode_);
DeserializeValue(&serialData, &serialLength, &pool3d_type_);
DeserializeValue(&serialData, &serialLength, &adaptive_);
DeserializeValue(&serialData, &serialLength, &ksize_);
DeserializeValue(&serialData, &serialLength, &strides_);
DeserializeValue(&serialData, &serialLength, &paddings_);
DeserializeValue(&serialData, &serialLength, &input_shape_);
DeserializeValue(&serialData, &serialLength, &output_shape_);
}
Pool3DPlugin* clone() const TRT_NOEXCEPT override;
const char* getPluginType() const TRT_NOEXCEPT override;
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* input_types,
int nb_inputs) const
TRT_NOEXCEPT override;
int getNbOutputs() const TRT_NOEXCEPT override;
nvinfer1::Dims getOutputDimensions(int index,
const nvinfer1::Dims* inputs,
int nbInputDims) TRT_NOEXCEPT override;
int initialize() TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override;
int enqueue(int batchSize,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
private:
bool ceil_mode_;
Pool3DType pool3d_type_;
bool adaptive_;
std::vector<int> ksize_;
std::vector<int> strides_;
std::vector<int> paddings_;
std::vector<int> input_shape_;
std::vector<int> output_shape_;
};
class Pool3DPluginCreator : public TensorRTPluginCreator {
public:
const char* getPluginName() const TRT_NOEXCEPT override {
return "pool3d_plugin";
}
const char* getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
nvinfer1::IPluginV2* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override {
return new Pool3DPlugin(serial_data, serial_length);
}
};
REGISTER_TRT_PLUGIN_V2(Pool3DPluginCreator);
class Pool3DPluginDynamic : public DynamicPluginTensorRT {
public:
Pool3DPluginDynamic() {}
Pool3DPluginDynamic(const bool& ceil_mode,
const std::string& pool3d_type,
const bool& adaptive,
const std::vector<int>& ksize,
const std::vector<int>& strides,
const std::vector<int>& paddings,
const bool& is_global)
: ceil_mode_(ceil_mode),
pool3d_type_(pool3d_type),
adaptive_(adaptive),
ksize_(ksize),
strides_(strides),
paddings_(paddings),
is_global_(is_global) {}
Pool3DPluginDynamic(void const* serialData, size_t serialLength);
~Pool3DPluginDynamic() {}
nvinfer1::IPluginV2DynamicExt* clone() const TRT_NOEXCEPT override;
const char* getPluginType() const TRT_NOEXCEPT override;
int getNbOutputs() const TRT_NOEXCEPT override;
int initialize() TRT_NOEXCEPT override;
size_t getSerializationSize() const TRT_NOEXCEPT override;
void serialize(void* buffer) const TRT_NOEXCEPT override;
nvinfer1::DimsExprs getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs* inputs,
int nb_inputs,
nvinfer1::IExprBuilder& expr_builder) // NOLINT
TRT_NOEXCEPT override;
bool supportsFormatCombination(int pos,
const nvinfer1::PluginTensorDesc* inOut,
int nbInputs,
int nbOutputs) TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::DynamicPluginTensorDesc* in,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc* out,
int nbOutputs) TRT_NOEXCEPT override;
size_t getWorkspaceSize(const nvinfer1::PluginTensorDesc* inputs,
int nbInputs,
const nvinfer1::PluginTensorDesc* outputs,
int nbOutputs) const TRT_NOEXCEPT override;
int enqueue(const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* inputTypes,
int nbInputs) const
TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override { delete this; }
private:
bool ceil_mode_;
std::string pool3d_type_;
bool adaptive_;
std::vector<int> ksize_;
std::vector<int> strides_;
std::vector<int> paddings_;
bool is_global_;
};
class Pool3DPluginDynamicCreator : public TensorRTPluginCreator {
public:
const char* getPluginName() const TRT_NOEXCEPT override {
return "pool3d_plugin_dynamic";
}
const char* getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
nvinfer1::IPluginV2* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override {
return new Pool3DPluginDynamic(serial_data, serial_length);
}
};
class PIRPool3DPluginDynamic : public DynamicPluginTensorRT {
public:
PIRPool3DPluginDynamic() {}
PIRPool3DPluginDynamic(const bool& ceil_mode,
const std::string& pool3d_type,
const bool& adaptive,
const std::vector<int>& ksize,
const std::vector<int>& strides,
const std::vector<int>& paddings,
const bool& is_global)
: ceil_mode_(ceil_mode),
pool3d_type_(pool3d_type),
adaptive_(adaptive),
ksize_(ksize),
strides_(strides),
paddings_(paddings),
is_global_(is_global) {}
PIRPool3DPluginDynamic(void const* serialData, size_t serialLength);
~PIRPool3DPluginDynamic() {}
nvinfer1::IPluginV2DynamicExt* clone() const TRT_NOEXCEPT override;
const char* getPluginType() const TRT_NOEXCEPT override;
int getNbOutputs() const TRT_NOEXCEPT override;
int initialize() TRT_NOEXCEPT override;
size_t getSerializationSize() const TRT_NOEXCEPT override;
void serialize(void* buffer) const TRT_NOEXCEPT override;
nvinfer1::DimsExprs getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs* inputs,
int nb_inputs,
nvinfer1::IExprBuilder& expr_builder) // NOLINT
TRT_NOEXCEPT override;
bool supportsFormatCombination(int pos,
const nvinfer1::PluginTensorDesc* inOut,
int nbInputs,
int nbOutputs) TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::DynamicPluginTensorDesc* in,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc* out,
int nbOutputs) TRT_NOEXCEPT override;
size_t getWorkspaceSize(const nvinfer1::PluginTensorDesc* inputs,
int nbInputs,
const nvinfer1::PluginTensorDesc* outputs,
int nbOutputs) const TRT_NOEXCEPT override;
int enqueue(const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* inputTypes,
int nbInputs) const
TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override { delete this; }
private:
bool ceil_mode_;
std::string pool3d_type_;
bool adaptive_;
std::vector<int> ksize_;
std::vector<int> strides_;
std::vector<int> paddings_;
bool is_global_;
};
class PIRPool3DPluginDynamicCreator : public TensorRTPluginCreator {
public:
const char* getPluginName() const TRT_NOEXCEPT override {
return "pir_pool3d_plugin_dynamic";
}
const char* getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
nvinfer1::IPluginV2* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override {
return new PIRPool3DPluginDynamic(serial_data, serial_length);
}
nvinfer1::IPluginV2* createPlugin(const char* name,
const nvinfer1::PluginFieldCollection* fc)
TRT_NOEXCEPT override {
bool ceil_mode = false;
std::string pool3d_type;
bool adaptive = false;
std::vector<int> ksize;
std::vector<int> strides;
std::vector<int> paddings;
bool is_global = false;
for (int i = 0; i < fc->nbFields; ++i) {
const nvinfer1::PluginField& field = fc->fields[i];
const std::string field_name(field.name);
if (field_name.compare("ceil_mode") == 0) {
ceil_mode = *static_cast<const bool*>(field.data);
} else if (field_name.compare("pool3d_type") == 0) {
pool3d_type = std::string(static_cast<const char*>(fc->fields[i].data),
fc->fields[i].length);
} else if (field_name.compare("adaptive") == 0) {
adaptive = *static_cast<const bool*>(field.data);
} else if (field_name.compare("ksize") == 0) {
const int length = fc->fields[i].length;
const int* data = static_cast<const int*>(fc->fields[i].data);
ksize.insert(ksize.end(), data, data + length);
} else if (field_name.compare("strides") == 0) {
const int length = fc->fields[i].length;
const int* data = static_cast<const int*>(fc->fields[i].data);
strides.insert(strides.end(), data, data + length);
} else if (field_name.compare("paddings") == 0) {
const int length = fc->fields[i].length;
const int* data = static_cast<const int*>(fc->fields[i].data);
paddings.insert(paddings.end(), data, data + length);
} else if (field_name.compare("is_global") == 0) {
is_global = *static_cast<const bool*>(field.data);
} else {
assert(false && "Unknown plugin field name.");
}
}
return new PIRPool3DPluginDynamic(
ceil_mode, pool3d_type, adaptive, ksize, strides, paddings, is_global);
}
};
REGISTER_TRT_PLUGIN_V2(Pool3DPluginDynamicCreator);
REGISTER_TRT_PLUGIN_V2(PIRPool3DPluginDynamicCreator);
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,364 @@
// Copyright (c) 2018 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/plugin/pool_op_plugin.h"
#include "paddle/phi/kernels/funcs/pooling.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
nvinfer1::Dims PoolPlugin::getOutputDimensions(int index,
const nvinfer1::Dims *inputDims,
int nbInputs) TRT_NOEXCEPT {
assert(nbInputs == 1);
assert(index == 0);
assert(inputDims[0].nbDims == 3);
nvinfer1::Dims const &input_dims = inputDims[0];
nvinfer1::Dims output_dims = input_dims;
output_dims.d[1] = output_shape_[1];
output_dims.d[2] = output_shape_[2];
return output_dims;
}
size_t PoolPlugin::getSerializationSize() const TRT_NOEXCEPT {
return getBaseSerializationSize() + SerializedSize(ceil_mode_) +
SerializedSize(pool_type_) + SerializedSize(adaptive_) +
SerializedSize(exclusive_) + SerializedSize(ksize_) +
SerializedSize(strides_) + SerializedSize(paddings_) +
SerializedSize(real_paddings_) + SerializedSize(input_shape_) +
SerializedSize(output_shape_);
}
// TRT will call this func when we need to serialize the configuration of
// tensorrt.
void PoolPlugin::serialize(void *buffer) const TRT_NOEXCEPT {
serializeBase(buffer);
SerializeValue(&buffer, ceil_mode_);
SerializeValue(&buffer, pool_type_);
SerializeValue(&buffer, adaptive_);
SerializeValue(&buffer, exclusive_);
SerializeValue(&buffer, ksize_);
SerializeValue(&buffer, strides_);
SerializeValue(&buffer, paddings_);
SerializeValue(&buffer, real_paddings_);
SerializeValue(&buffer, input_shape_);
SerializeValue(&buffer, output_shape_);
}
PoolPlugin *PoolPlugin::clone() const TRT_NOEXCEPT {
return new PoolPlugin(ceil_mode_,
pool_type_,
adaptive_,
exclusive_,
ksize_,
strides_,
paddings_,
input_shape_,
real_paddings_);
}
int PoolPlugin::enqueue(int batchSize,
const void *const *inputs,
void *const *outputs,
void *workspace,
cudaStream_t stream) TRT_NOEXCEPT {
auto const &input_dims = this->getInputDims(0);
int input_size = 0;
float const *idata = reinterpret_cast<float const *>(inputs[0]);
float *const *odatas = reinterpret_cast<float *const *>(outputs);
std::vector<int> input_shape = input_shape_;
std::vector<int> output_shape = output_shape_;
input_shape.insert(input_shape.begin(), batchSize);
output_shape.insert(output_shape.begin(), batchSize);
if (pool_type_ == PoolType::max) {
phi::funcs::MaxPool<float> pool_process;
phi::funcs::Pool2dDirectCUDAFunctor<phi::funcs::MaxPool<float>, float>
pool2d_forward;
pool2d_forward(idata,
input_shape,
output_shape,
ksize_,
strides_,
paddings_,
true,
false,
odatas[0],
stream,
pool_process);
} else if (pool_type_ == PoolType::avg) {
phi::funcs::AvgPool<float> pool_process;
phi::funcs::Pool2dDirectCUDAFunctor<phi::funcs::AvgPool<float>, float>
pool2d_forward;
pool2d_forward(idata,
input_shape,
output_shape,
ksize_,
strides_,
paddings_,
exclusive_,
adaptive_,
odatas[0],
stream,
pool_process);
}
return cudaGetLastError() != cudaSuccess;
}
PoolPluginDynamic::PoolPluginDynamic(void const *serialData,
size_t serialLength) {
DeserializeValue(&serialData, &serialLength, &ceil_mode_);
const char *pool_type;
DeserializeValue(&serialData, &serialLength, &pool_type);
pool_type_ = std::string(pool_type);
DeserializeValue(&serialData, &serialLength, &adaptive_);
DeserializeValue(&serialData, &serialLength, &exclusive_);
DeserializeValue(&serialData, &serialLength, &ksize_);
DeserializeValue(&serialData, &serialLength, &strides_);
DeserializeValue(&serialData, &serialLength, &paddings_);
DeserializeValue(&serialData, &serialLength, &is_global_);
}
size_t PoolPluginDynamic::getSerializationSize() const TRT_NOEXCEPT {
return SerializedSize(ceil_mode_) + SerializedSize(pool_type_.c_str()) +
SerializedSize(adaptive_) + SerializedSize(exclusive_) +
SerializedSize(ksize_) + SerializedSize(strides_) +
SerializedSize(paddings_) + SerializedSize(is_global_);
}
void PoolPluginDynamic::serialize(void *buffer) const TRT_NOEXCEPT {
SerializeValue(&buffer, ceil_mode_);
SerializeValue(&buffer, pool_type_.c_str());
SerializeValue(&buffer, adaptive_);
SerializeValue(&buffer, exclusive_);
SerializeValue(&buffer, ksize_);
SerializeValue(&buffer, strides_);
SerializeValue(&buffer, paddings_);
SerializeValue(&buffer, is_global_);
}
nvinfer1::IPluginV2DynamicExt *PoolPluginDynamic::clone() const TRT_NOEXCEPT {
return new PoolPluginDynamic(ceil_mode_,
pool_type_,
adaptive_,
exclusive_,
ksize_,
strides_,
paddings_,
is_global_);
}
nvinfer1::DimsExprs PoolPluginDynamic::getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs *inputs,
int nb_inputs,
nvinfer1::IExprBuilder &expr_builder) TRT_NOEXCEPT {
PADDLE_ENFORCE_EQ(nb_inputs,
1,
common::errors::InvalidArgument(
"The Split plugin should be only one input."));
nvinfer1::DimsExprs output(inputs[0]);
if (is_global_ && !adaptive_) {
output.d[2] = expr_builder.constant(1);
output.d[3] = expr_builder.constant(1);
return output;
}
if (is_global_ && adaptive_) {
return inputs[0];
}
if (adaptive_) {
output.d[2] = expr_builder.constant(ksize_[0]);
output.d[3] = expr_builder.constant(ksize_[1]);
return output;
}
auto stri_0 = expr_builder.constant(strides_[0]);
auto stri_1 = expr_builder.constant(strides_[1]);
auto one_value = expr_builder.constant(1);
auto v0_tmp = expr_builder.constant(-ksize_[0] + 2 * paddings_[0]);
auto v1_tmp = expr_builder.constant(-ksize_[1] + 2 * paddings_[1]);
auto ceil_tmp =
expr_builder.constant(-ksize_[0] + 2 * paddings_[0] + strides_[0] - 1);
auto ceil1_tmp =
expr_builder.constant(-ksize_[1] + 2 * paddings_[1] + strides_[1] - 1);
if (!ceil_mode_) {
output.d[2] = expr_builder.operation(
nvinfer1::DimensionOperation::kSUM,
*expr_builder.operation(
nvinfer1::DimensionOperation::kFLOOR_DIV,
*expr_builder.operation(
nvinfer1::DimensionOperation::kSUM, *inputs[0].d[2], *v0_tmp),
*stri_0),
*one_value);
output.d[3] = expr_builder.operation(
nvinfer1::DimensionOperation::kSUM,
*expr_builder.operation(
nvinfer1::DimensionOperation::kFLOOR_DIV,
*expr_builder.operation(
nvinfer1::DimensionOperation::kSUM, *inputs[0].d[3], *v1_tmp),
*stri_1),
*one_value);
} else {
output.d[2] = expr_builder.operation(
nvinfer1::DimensionOperation::kSUM,
*expr_builder.operation(
nvinfer1::DimensionOperation::kFLOOR_DIV,
*expr_builder.operation(
nvinfer1::DimensionOperation::kSUM, *inputs[0].d[2], *ceil_tmp),
*stri_0),
*one_value);
output.d[3] = expr_builder.operation(
nvinfer1::DimensionOperation::kSUM,
*expr_builder.operation(
nvinfer1::DimensionOperation::kFLOOR_DIV,
*expr_builder.operation(nvinfer1::DimensionOperation::kSUM,
*inputs[0].d[3],
*ceil1_tmp),
*stri_1),
*one_value);
}
return output;
}
bool PoolPluginDynamic::supportsFormatCombination(
int pos,
const nvinfer1::PluginTensorDesc *in_out,
int nb_inputs,
int nb_outputs) TRT_NOEXCEPT {
PADDLE_ENFORCE_NOT_NULL(
in_out,
common::errors::InvalidArgument(
"The input of swish plugin should not be nullptr."));
PADDLE_ENFORCE_LT(
pos,
nb_inputs + nb_outputs,
common::errors::InvalidArgument("The pos(%d) should be less than the "
"num(%d) of the input and the output.",
pos,
nb_inputs + nb_outputs));
(in_out && pos < (nb_inputs + nb_outputs));
return ((in_out[pos].type == nvinfer1::DataType::kFLOAT) &&
in_out[pos].format == nvinfer1::PluginFormat::kLINEAR);
}
nvinfer1::DataType PoolPluginDynamic::getOutputDataType(
int index,
const nvinfer1::DataType *input_types,
int nb_inputs) const TRT_NOEXCEPT {
PADDLE_ENFORCE_EQ(index,
0,
common::errors::InvalidArgument(
"The Pool Plugin only has one input, so the "
"index value should be 0, but get %d.",
index));
PADDLE_ENFORCE_EQ(
(input_types[0] == nvinfer1::DataType::kFLOAT),
true,
common::errors::InvalidArgument("The input type should be float"));
return input_types[0];
}
int PoolPluginDynamic::enqueue(const nvinfer1::PluginTensorDesc *input_desc,
const nvinfer1::PluginTensorDesc *output_desc,
const void *const *inputs,
void *const *outputs,
void *workspace,
cudaStream_t stream) TRT_NOEXCEPT {
auto input_dims = input_desc[0].dims;
int n = input_dims.d[0];
int c = input_dims.d[1];
int h = input_dims.d[2];
int w = input_dims.d[3];
const float *input = static_cast<const float *>(inputs[0]);
float *output = static_cast<float *>(outputs[0]);
std::vector<int> input_shape, output_shape;
for (int i = 0; i < input_dims.nbDims; i++)
input_shape.push_back(input_dims.d[i]);
output_shape = input_shape;
std::vector<int> ksize = ksize_;
std::vector<int> paddings = paddings_;
if (is_global_) {
ksize[0] = h;
ksize[1] = w;
paddings[0] = 0;
paddings[1] = 0;
output_shape[2] = 1;
output_shape[3] = 1;
if (adaptive_) {
output_shape[2] = h;
output_shape[3] = w;
}
} else {
auto data_dim = CalcOutputSize(
{h, w}, ceil_mode_, adaptive_, ksize_, strides_, paddings_);
output_shape[2] = data_dim[0];
output_shape[3] = data_dim[1];
}
if (pool_type_ == "max") {
phi::funcs::MaxPool<float> pool_process;
phi::funcs::Pool2dDirectCUDAFunctor<phi::funcs::MaxPool<float>, float>
pool2d_forward;
pool2d_forward(input,
input_shape,
output_shape,
ksize,
strides_,
paddings,
true,
false,
output,
stream,
pool_process);
} else if (pool_type_ == "avg") {
phi::funcs::AvgPool<float> pool_process;
phi::funcs::Pool2dDirectCUDAFunctor<phi::funcs::AvgPool<float>, float>
pool2d_forward;
pool2d_forward(input,
input_shape,
output_shape,
ksize,
strides_,
paddings,
exclusive_,
adaptive_,
output,
stream,
pool_process);
}
return cudaGetLastError() != cudaSuccess;
}
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,339 @@
// Copyright (c) 2018 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.
#pragma once
#include <stdio.h>
#include <cassert>
#include <string>
#include <vector>
#include "paddle/fluid/inference/tensorrt/plugin/trt_plugin.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
static std::vector<int> CalcOutputSize(const std::vector<int>& input_shape,
const bool& ceil_mode,
const bool& adaptive,
const std::vector<int>& ksize,
const std::vector<int>& strides,
const std::vector<int>& real_paddings) {
std::vector<int> output_shape = input_shape;
if (adaptive) {
output_shape[0] = ksize[0];
output_shape[1] = ksize[1];
} else {
int output_h = 0, output_w = 0;
if (ceil_mode) {
output_h = (input_shape[0] - ksize[0] + real_paddings[0] +
real_paddings[1] + strides[0] - 1) /
strides[0] +
1;
output_w = (input_shape[1] - ksize[1] + real_paddings[2] +
real_paddings[3] + strides[1] - 1) /
strides[1] +
1;
}
// TRT will use native layer when ceil_model=false
/*
else{
output_h = (input_shape[0] - ksize[0] + real_paddings[0] +
real_paddings[1]) / strides[0] + 1;
output_w = (input_shape[1] - ksize[1] + real_paddings[2] +
real_paddings[3]) / strides[1] + 1;
}
*/
output_shape[0] = output_h;
output_shape[1] = output_w;
}
return output_shape;
}
class PoolPlugin : public PluginTensorRT {
public:
size_t getSerializationSize() const TRT_NOEXCEPT override;
void serialize(void* buffer) const TRT_NOEXCEPT override;
enum class PoolType {
max = 0,
avg,
};
PoolPlugin() {}
PoolPlugin(bool ceil_mode,
PoolType pool_type,
bool adaptive,
bool exclusive,
std::vector<int> ksize,
std::vector<int> strides,
std::vector<int> paddings,
std::vector<int> input_shape,
std::vector<int> real_paddings)
: ceil_mode_(ceil_mode),
pool_type_(pool_type),
adaptive_(adaptive),
exclusive_(exclusive),
ksize_(ksize),
strides_(strides),
paddings_(paddings),
real_paddings_(real_paddings),
input_shape_(input_shape) {
output_shape_ = input_shape_;
std::vector<int> output_shape =
CalcOutputSize({input_shape_[1], input_shape_[2]},
ceil_mode_,
adaptive_,
ksize_,
strides_,
real_paddings_);
output_shape_[1] = output_shape[0];
output_shape_[2] = output_shape[1];
}
// It was used for tensorrt deserialization.
// It should not be called by users.
PoolPlugin(void const* serialData, size_t serialLength) {
deserializeBase(serialData, serialLength);
DeserializeValue(&serialData, &serialLength, &ceil_mode_);
DeserializeValue(&serialData, &serialLength, &pool_type_);
DeserializeValue(&serialData, &serialLength, &adaptive_);
DeserializeValue(&serialData, &serialLength, &exclusive_);
DeserializeValue(&serialData, &serialLength, &ksize_);
DeserializeValue(&serialData, &serialLength, &strides_);
DeserializeValue(&serialData, &serialLength, &paddings_);
DeserializeValue(&serialData, &serialLength, &real_paddings_);
DeserializeValue(&serialData, &serialLength, &input_shape_);
DeserializeValue(&serialData, &serialLength, &output_shape_);
}
PoolPlugin* clone() const TRT_NOEXCEPT override;
const char* getPluginType() const TRT_NOEXCEPT override {
return "pool_plugin";
}
int getNbOutputs() const TRT_NOEXCEPT override { return 1; }
nvinfer1::Dims getOutputDimensions(int index,
const nvinfer1::Dims* inputs,
int nbInputDims) TRT_NOEXCEPT override;
int initialize() TRT_NOEXCEPT override { return 0; }
int enqueue(int batchSize,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
private:
bool ceil_mode_;
PoolType pool_type_;
bool adaptive_;
bool exclusive_;
std::vector<int> ksize_;
std::vector<int> strides_;
std::vector<int> paddings_;
std::vector<int> real_paddings_;
std::vector<int> input_shape_;
std::vector<int> output_shape_;
};
class PoolPluginCreator : public TensorRTPluginCreator {
public:
const char* getPluginName() const TRT_NOEXCEPT override {
return "pool_plugin";
}
const char* getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
nvinfer1::IPluginV2* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override {
return new PoolPlugin(serial_data, serial_length);
}
};
REGISTER_TRT_PLUGIN_V2(PoolPluginCreator);
class PoolPluginDynamic : public DynamicPluginTensorRT {
public:
PoolPluginDynamic() {}
PoolPluginDynamic(const bool& ceil_mode,
const std::string& pool_type,
const bool& adaptive,
bool exclusive,
const std::vector<int>& ksize,
const std::vector<int>& strides,
const std::vector<int>& paddings,
const bool& is_global)
: ceil_mode_(ceil_mode),
pool_type_(pool_type),
adaptive_(adaptive),
exclusive_(exclusive),
ksize_(ksize),
strides_(strides),
paddings_(paddings),
is_global_(is_global) {}
PoolPluginDynamic(void const* serialData, size_t serialLength);
~PoolPluginDynamic() {}
nvinfer1::IPluginV2DynamicExt* clone() const TRT_NOEXCEPT override;
const char* getPluginType() const TRT_NOEXCEPT override {
return "pool_plugin_dynamic";
}
int getNbOutputs() const TRT_NOEXCEPT override { return 1; }
int initialize() TRT_NOEXCEPT override { return 0; }
size_t getSerializationSize() const TRT_NOEXCEPT override;
void serialize(void* buffer) const TRT_NOEXCEPT override;
nvinfer1::DimsExprs getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs* inputs,
int nb_inputs,
nvinfer1::IExprBuilder& expr_builder) // NOLINT
TRT_NOEXCEPT override;
bool supportsFormatCombination(int pos,
const nvinfer1::PluginTensorDesc* inOut,
int nbInputs,
int nbOutputs) TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::DynamicPluginTensorDesc* in,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc* out,
int nbOutputs) TRT_NOEXCEPT override {}
size_t getWorkspaceSize(const nvinfer1::PluginTensorDesc* inputs,
int nbInputs,
const nvinfer1::PluginTensorDesc* outputs,
int nbOutputs) const TRT_NOEXCEPT override {
return 0;
}
int enqueue(const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* inputTypes,
int nbInputs) const
TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override { delete this; }
private:
bool ceil_mode_;
std::string pool_type_;
bool adaptive_;
bool exclusive_;
std::vector<int> ksize_;
std::vector<int> strides_;
std::vector<int> paddings_;
bool is_global_;
};
class PoolPluginDynamicCreator : public TensorRTPluginCreator {
public:
const char* getPluginName() const TRT_NOEXCEPT override {
return "pool_plugin_dynamic";
}
const char* getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
nvinfer1::IPluginV2* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override {
return new PoolPluginDynamic(serial_data, serial_length);
}
};
class PIRPoolPluginDynamicCreator : public TensorRTPluginCreator {
public:
const char* getPluginName() const TRT_NOEXCEPT override {
return "pir_pool_plugin_dynamic";
}
const char* getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
nvinfer1::IPluginV2* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override {
return new PoolPluginDynamic(serial_data, serial_length);
}
nvinfer1::IPluginV2* createPlugin(const char* name,
const nvinfer1::PluginFieldCollection* fc)
TRT_NOEXCEPT override {
bool ceil_mode = false;
std::string pool_type;
bool adaptive = false;
bool exclusive = false;
std::vector<int> ksize;
std::vector<int> strides;
std::vector<int> paddings;
bool global_pooling = false;
for (int i = 0; i < fc->nbFields; ++i) {
const nvinfer1::PluginField& field = fc->fields[i];
const std::string field_name(field.name);
if (field_name.compare("ceil_mode") == 0) {
ceil_mode = *static_cast<const bool*>(field.data);
} else if (field_name.compare("pool_type") == 0) {
pool_type = std::string(static_cast<const char*>(fc->fields[i].data),
fc->fields[i].length);
} else if (field_name.compare("adaptive") == 0) {
adaptive = *static_cast<const bool*>(field.data);
} else if (field_name.compare("exclusive") == 0) {
exclusive = *static_cast<const bool*>(field.data);
} else if (field_name.compare("ksize") == 0) {
const int length = fc->fields[i].length;
const int* data = static_cast<const int*>(fc->fields[i].data);
ksize.insert(ksize.end(), data, data + length);
} else if (field_name.compare("strides") == 0) {
const int length = fc->fields[i].length;
const int* data = static_cast<const int*>(fc->fields[i].data);
strides.insert(strides.end(), data, data + length);
} else if (field_name.compare("paddings") == 0) {
const int length = fc->fields[i].length;
const int* data = static_cast<const int*>(fc->fields[i].data);
paddings.insert(paddings.end(), data, data + length);
} else if (field_name.compare("global_pooling") == 0) {
global_pooling = *static_cast<const bool*>(field.data);
} else {
assert(false && "unknown plugin field name.");
}
}
return new PoolPluginDynamic(ceil_mode,
pool_type,
adaptive,
exclusive,
ksize,
strides,
paddings,
global_pooling);
}
};
REGISTER_TRT_PLUGIN_V2(PoolPluginDynamicCreator);
REGISTER_TRT_PLUGIN_V2(PIRPoolPluginDynamicCreator);
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,497 @@
/* Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
SPDX-FileCopyrightText: Copyright (c) 1993-2022 NVIDIA CORPORATION & AFFILIATES.
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/plugin/preln_groupnorm_act_op_plugin.h"
#include <cub/cub.cuh>
#include "paddle/common/layout.h"
#include "paddle/phi/backends/gpu/gpu_context.h"
#include "paddle/phi/kernels/funcs/math_function.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
nvinfer1::DimsExprs PrelnGroupnormActPluginDynamic::getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs *inputDims,
int nb_inputs,
nvinfer1::IExprBuilder &expr_builder) TRT_NOEXCEPT {
return inputDims[0];
}
bool PrelnGroupnormActPluginDynamic::supportsFormatCombination(
int pos,
const nvinfer1::PluginTensorDesc *in_out,
int nb_inputs,
int nb_outputs) TRT_NOEXCEPT {
PADDLE_ENFORCE_NOT_NULL(
in_out,
common::errors::InvalidArgument(
"The input of prelnGroupnormAct plugin should not be nullptr."));
PADDLE_ENFORCE_LT(
pos,
nb_inputs + nb_outputs,
common::errors::InvalidArgument("The pos(%d) should be less than the "
"num(%d) of the input and the output.",
pos,
nb_inputs + nb_outputs));
const nvinfer1::PluginTensorDesc &in = in_out[pos];
if (pos == 0) {
if (with_fp16_) {
return ((in.type == nvinfer1::DataType::kHALF) &&
(in.format == nvinfer1::PluginFormat::kHWC8));
} else {
PADDLE_THROW(common::errors::Fatal(
"PrelnGroupnormAct TRT Plugin is fp16 only so far"));
return (in.type == nvinfer1::DataType::kFLOAT) &&
(in.format == nvinfer1::TensorFormat::kLINEAR);
}
}
const nvinfer1::PluginTensorDesc &prev = in_out[pos - 1];
// output
return in.type == prev.type && in.format == prev.format;
}
nvinfer1::DataType PrelnGroupnormActPluginDynamic::getOutputDataType(
int index,
const nvinfer1::DataType *input_types,
int nb_inputs) const TRT_NOEXCEPT {
return input_types[0];
}
int PrelnGroupnormActPluginDynamic::initialize() TRT_NOEXCEPT { return 0; }
template <typename T>
static inline T divUp(T m, T n) {
return (m + n - 1) / n;
}
static int64_t findMaxDivisor(int64_t n, int64_t maxAllowedDivisor) {
int64_t maxDivisor = -1;
for (int64_t i = 1; i <= std::sqrt(n); i++) {
if (n % i == 0) {
int64_t divisor1 = n / i;
int64_t divisor2 = i;
if (divisor1 > maxDivisor && divisor1 < maxAllowedDivisor) {
maxDivisor = divisor1;
}
if (divisor2 > maxDivisor && divisor2 < maxAllowedDivisor) {
maxDivisor = divisor2;
}
}
}
return maxDivisor;
}
static inline __device__ __host__ float sigmoid(float x) {
return 1.F / (1.F + expf(-x));
}
struct GroupSums {
// Is it the 1st element of the group?
int32_t flag;
// The sum.
float sum;
// The sum of squares.
float sumSq;
};
struct GroupSumsOp {
inline __device__ GroupSums operator()(GroupSums const &a,
GroupSums const &b) {
GroupSums dst;
dst.sum = b.flag ? b.sum : (a.sum + b.sum);
dst.sumSq = b.flag ? b.sumSq : (a.sumSq + b.sumSq);
dst.flag = a.flag + b.flag;
return dst;
}
};
template <int32_t tTHREADS_PER_BLOCK>
__global__ void prelnGroupNormNDHWCSumKernel(
GroupNormNDHWCParams<__half> params) {
// The object in charge of doing the sums for the different blocks.
typedef cub::BlockScan<GroupSums, tTHREADS_PER_BLOCK> BlockScan;
// Allocate shared memory for BlockScan.
__shared__ typename BlockScan::TempStorage tempStorage;
// Allocate shared memory for the groups. We could reduce the amount of shared
// memory reserved.
__shared__ float2 smem[tTHREADS_PER_BLOCK];
// The instance in the batch.
int32_t ni = blockIdx.z;
// The channel loaded by that thread (2 channels per thread for F16x2).
int32_t ci = blockIdx.x * params.cPerBlock + threadIdx.x * 2;
// The first activation loaded by that block.
int64_t dhwBegin = static_cast<int64_t>(blockIdx.y) * params.dhwPerBlock;
// The last activation loaded by that block.
int64_t dhwEnd = min(dhwBegin + params.dhwPerBlock, params.dhw);
// The sums.
float sum = 0.F;
float sumSq = 0.F;
// Iterate over the activations to compute the sums.
for (int64_t dhwi = dhwBegin; dhwi < dhwEnd; ++dhwi) {
// The offset.
int64_t offset = static_cast<int64_t>(ni) * params.dhwc +
static_cast<int64_t>(dhwi) * params.c + ci;
// Fetch two channels per thread.
__half2 h2(0, 0);
if (ci < params.c) {
// int64_t offsetY = static_cast<int64_t>(ni) * params.c + ci;
__half2 y = *reinterpret_cast<__half2 const *>(&params.srcY[offset]);
h2 = *reinterpret_cast<__half2 const *>(&params.srcX[offset]);
#if __CUDA_ARCH__ >= 530
h2 = __hadd2(h2, y);
#else
float2 out{};
out.x = __half2float(h2.x) + __half2float(y.x);
out.y = __half2float(h2.y) + __half2float(y.y);
h2 = __float22half2_rn(out);
#endif
// elementwise_add
*reinterpret_cast<__half2 *>(&params.eleOut[offset]) = h2;
}
// Extract the two half values.
float2 f2 = __half22float2(h2);
// Update the sum.
sum += f2.x + f2.y;
// Update the sum of squares.
sumSq += f2.x * f2.x + f2.y * f2.y;
}
// The group that thread works on and the channel in the group (modulus).
int32_t gi = threadIdx.x * 2 / params.cPerGroup;
int32_t cj = threadIdx.x * 2 - params.cPerGroup * gi;
// The data for the summations.
GroupSums inp{cj == 0 ? 1 : 0, sum, sumSq};
// Do the segmented scan.
GroupSums out;
BlockScan(tempStorage).InclusiveScan(inp, out, GroupSumsOp());
// Store the results for the groups in shared memory (to produce coalesced
// stores later).
if (cj == params.cPerGroup - 2 /* 2 channels per thread */) {
smem[gi] = make_float2(out.sum, out.sumSq);
}
// Make sure the data is in shared memory.
__syncthreads();
// The global group index.
int32_t gj = blockIdx.x * params.groupsPerBlock + threadIdx.x;
// Threads that have nothing left to do, exit.
if (threadIdx.x >= params.groupsPerBlock || gj >= params.groups) {
return;
}
// The first threads (those storing to global memory, load the values).
float2 sums = smem[threadIdx.x];
// Store to global memory.
atomicAdd(&params.redBuffer[(2 * ni + 0) * params.groups + gj], sums.x);
atomicAdd(&params.redBuffer[(2 * ni + 1) * params.groups + gj], sums.y);
}
void prelnGroupNormNDHWCSum(GroupNormNDHWCParams<__half> const &params,
cudaStream_t stream) {
// Make sure the values are as we expect.
PADDLE_ENFORCE_EQ(params.c % params.cPerBlock,
0,
common::errors::InvalidArgument(
"The groupNormNDHWCSum of prelnGroupnormAct Plugin got "
"wrong parameters: "
"params.c %% params.cPerBlock should be 0, but get %d.",
params.c % params.cPerBlock));
PADDLE_ENFORCE_EQ(
params.dhw % params.dhwPerBlock,
0,
common::errors::InvalidArgument(
"The groupNormNDHWCSum of prelnGroupnormAct Plugin got wrong "
"parameters: "
"params.dhw %% params.dhwPerBlock should be 0, but get %d.",
params.dhw % params.dhwPerBlock));
// Make sure a group does not span multiple blocks.
PADDLE_ENFORCE_EQ(
params.cPerBlock % params.cPerGroup,
0,
common::errors::InvalidArgument(
"The groupNormNDHWCSum of prelnGroupnormAct Plugin got wrong "
"parameters: "
"params.cPerBlock %% params.cPerGroup should be 0, but get %d.",
params.cPerBlock % params.cPerGroup));
dim3 grid;
// The number of blocks to compute all the channels.
grid.x = params.c / params.cPerBlock;
// The number of blocks to compute all the activations in a given instance.
grid.y = divUp(params.dhw, params.dhwPerBlock);
// The number of instances.
grid.z = params.n;
switch (params.cPerBlock) {
case 320:
prelnGroupNormNDHWCSumKernel<160><<<grid, 160, 0, stream>>>(params);
break;
case 480:
prelnGroupNormNDHWCSumKernel<256><<<grid, 256, 0, stream>>>(params);
break;
case 256:
prelnGroupNormNDHWCSumKernel<128><<<grid, 128, 0, stream>>>(params);
break;
case 128:
prelnGroupNormNDHWCSumKernel<64><<<grid, 64, 0, stream>>>(params);
break;
case 8:
prelnGroupNormNDHWCSumKernel<4><<<grid, 4, 0, stream>>>(params);
break;
default:
PADDLE_THROW(common::errors::Fatal(
"The function groupNormNDHWCSum of prelnGroupnormAct TRT Plugin "
"encounter error"));
}
}
template <int32_t tTHREADS_PER_BLOCK>
__global__ void prelnGroupNormNDHWCScaleKernel(
GroupNormNDHWCParams<__half> params) {
// The instance in the batch.
int32_t ni = blockIdx.z;
// The channel loaded by that thread (2 channels per thread for F16x2).
int32_t ci = blockIdx.x * params.cPerBlock + threadIdx.x * 2;
// The group that thread works on and the channel in the group (modulus).
int32_t gi = ci / params.cPerGroup;
// Load the sum and sum of squares for the group.
float sum = 0.F, sumSq = 0.F;
if (gi < params.groups) {
sum = params.redBuffer[(2 * ni + 0) * params.groups + gi];
sumSq = params.redBuffer[(2 * ni + 1) * params.groups + gi];
}
// Load gamma/beta.
float2 gammaF2, betaF2;
if (ci < params.c) {
gammaF2 = *reinterpret_cast<float2 const *>(
reinterpret_cast<float const *>(params.gamma) + ci);
betaF2 = *reinterpret_cast<float2 const *>(
reinterpret_cast<float const *>(params.beta) + ci);
}
// Compute the mean.
float mean = sum * params.invDHWC;
// Compute the variance.
float var = sumSq * params.invDHWC - (mean * mean);
// Compute the inverse of the stddev.
float invStdDev = rsqrtf(var + params.eps);
// The first activation loaded by that block.
int64_t dhwBegin = static_cast<int64_t>(blockIdx.y) * params.dhwPerBlock;
// The last activation loaded by that block.
int64_t dhwEnd = min(dhwBegin + params.dhwPerBlock, params.dhw);
// Iterate over the activations to compute the sums.
for (int64_t dhwi = dhwBegin; dhwi < dhwEnd; ++dhwi) {
// The src/dst offset.
int64_t offset = (int64_t)ni * params.dhwc + dhwi * params.c + ci;
// Fetch two channels per thread.
__half2 h2(0, 0);
if (ci < params.c) {
h2 = *reinterpret_cast<__half2 const *>(&params.eleOut[offset]);
}
// Extract the two half values.
float2 f2 = __half22float2(h2);
// Normalize the channels.
f2.x = (f2.x - mean) * invStdDev;
f2.y = (f2.y - mean) * invStdDev;
// Scale by gamma and add beta.
f2.x = gammaF2.x * f2.x + betaF2.x;
f2.y = gammaF2.y * f2.y + betaF2.y;
// Apply Silu if needed.
if (params.withSilu) {
f2.x = f2.x * sigmoid(f2.x);
f2.y = f2.y * sigmoid(f2.y);
}
// Store the scaled values.
if (ci < params.c) {
*reinterpret_cast<__half2 *>(&params.dst[offset]) = __float22half2_rn(f2);
}
}
}
void prelnGroupNormNDHWCScale(GroupNormNDHWCParams<__half> const &params,
cudaStream_t stream) {
// Make sure the dimensions are aligned with what we expect.
PADDLE_ENFORCE_EQ(
params.c % params.cPerBlock,
0,
common::errors::InvalidArgument(
"The groupNormNDHWCScale of prelnGroupnormAct Plugin got "
"wrong parameters: "
"params.c %% params.cPerBlock should be 0, but get %d.",
params.c % params.cPerBlock));
// Make sure a group does not span multiple blocks.
PADDLE_ENFORCE_EQ(
params.cPerBlock % params.cPerGroup,
0,
common::errors::InvalidArgument(
"The groupNormNDHWCScale of prelnGroupnormAct Plugin got wrong "
"parameters: "
"params.cPerBlock %% params.cPerGroup should be 0, but get %d.",
params.cPerBlock % params.cPerGroup));
dim3 grid;
// The number of blocks to compute all the channels.
grid.x = params.c / params.cPerBlock;
// The number of blocks to compute all the activations in a given instance.
grid.y = divUp(params.dhw, params.dhwPerBlock);
// The number of instances.
grid.z = params.n;
switch (params.cPerBlock) {
case 320:
prelnGroupNormNDHWCScaleKernel<160><<<grid, 160, 0, stream>>>(params);
break;
case 480:
prelnGroupNormNDHWCScaleKernel<256><<<grid, 256, 0, stream>>>(params);
break;
case 256:
prelnGroupNormNDHWCScaleKernel<128><<<grid, 128, 0, stream>>>(params);
break;
case 128:
prelnGroupNormNDHWCScaleKernel<64><<<grid, 64, 0, stream>>>(params);
break;
case 8:
prelnGroupNormNDHWCScaleKernel<4><<<grid, 4, 0, stream>>>(params);
break;
default:
PADDLE_THROW(common::errors::Fatal(
"The function groupNormNDHWCSum of prelnGroupnormAct TRT Plugin "
"encounter error"));
}
}
int PrelnGroupnormActPluginDynamic::enqueue(
const nvinfer1::PluginTensorDesc *input_desc,
const nvinfer1::PluginTensorDesc *output_desc,
const void *const *inputs,
void *const *outputs,
void *workspace,
cudaStream_t stream) TRT_NOEXCEPT {
auto input_type = input_desc[0].type;
if (input_type == nvinfer1::DataType::kFLOAT) {
VLOG(1) << "TRT Plugin DataType selected. prelnGroupnormAct-->fp32";
PADDLE_THROW(common::errors::Fatal(
"The prelnGroupnormAct TRT Plugin's only support fp16 input"));
} else if (input_type == nvinfer1::DataType::kHALF) {
VLOG(1) << "TRT Plugin DataType selected. prelnGroupnormAct-->fp16";
int32_t cPerBlock = 320;
int32_t maxBlocksPerDHW = 1024;
switch (input_desc[0].dims.d[1]) {
case 960:
case 1920:
cPerBlock = 480;
break;
case 512:
case 256:
cPerBlock = 256;
break;
case 128:
cPerBlock = 128;
break;
default:
cPerBlock = 320;
}
if (cPerBlock > input_desc[0].dims.d[1]) {
cPerBlock = 8;
}
auto d_dim = input_desc[0].dims.nbDims;
params_.n = input_desc[0].dims.d[0];
if (d_dim == 3) {
params_.c = input_desc[0].dims.d[1];
params_.d = 1;
params_.h = 1;
params_.w = input_desc[0].dims.d[2];
} else if (d_dim == 4) {
params_.c = input_desc[0].dims.d[1];
params_.d = 1;
params_.h = input_desc[0].dims.d[2];
params_.w = input_desc[0].dims.d[3];
} else {
// d_dim == 5
params_.c = input_desc[0].dims.d[1];
params_.d = input_desc[0].dims.d[2];
params_.h = input_desc[0].dims.d[3];
params_.w = input_desc[0].dims.d[4];
}
params_.withSilu = with_silu_;
params_.dst = static_cast<half *>(outputs[1]);
params_.eleOut = static_cast<half *>(outputs[0]);
params_.srcX = static_cast<half const *>(inputs[0]);
params_.srcY = static_cast<half const *>(inputs[1]);
params_.gamma = scale_gpu_.get();
params_.beta = bias_gpu_.get();
params_.redBuffer = static_cast<float *>(workspace);
// params_.n = input_desc[0].dims.d[0];
// params_.h = input_desc[0].dims.d[2];
// params_.w = input_desc[0].dims.d[3];
// params_.c = input_desc[0].dims.d[1];
params_.groups = groups_;
params_.dhw = static_cast<int64_t>(params_.d) * params_.h * params_.w;
const int64_t blocksPerDHW =
findMaxDivisor(params_.dhw, static_cast<int64_t>(maxBlocksPerDHW));
params_.dhwPerBlock = divUp(params_.dhw, blocksPerDHW);
params_.cPerBlock = cPerBlock;
params_.cPerGroup = params_.c / params_.groups;
params_.dhwc = params_.dhw * params_.c;
params_.invDHWC = 1.F / static_cast<float>(params_.dhw * params_.cPerGroup);
params_.groupsPerBlock = cPerBlock / params_.cPerGroup;
params_.eps = eps_;
cudaMemsetAsync(params_.redBuffer, 0, ws_, stream);
prelnGroupNormNDHWCSum(params_, stream);
prelnGroupNormNDHWCScale(params_, stream);
} else {
// input not fp16
PADDLE_THROW(common::errors::Fatal(
"The PrelnGroupnormAct TRT Plugin's only support fp16 input"));
}
return cudaGetLastError() != cudaSuccess;
}
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,201 @@
/* Copyright (c) 2022 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. */
#pragma once
#include <algorithm>
#include <string>
#include <vector>
#include "paddle/fluid/framework/tensor.h"
#include "paddle/fluid/framework/tensor_util.h"
#include "paddle/fluid/inference/tensorrt/engine.h"
#include "paddle/fluid/inference/tensorrt/plugin/trt_plugin.h"
#include "paddle/phi/kernels/group_norm_kernel.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
using phi::GroupNormNDHWCParams;
class PrelnGroupnormActPluginDynamic : public DynamicPluginTensorRT {
public:
PrelnGroupnormActPluginDynamic(const float* scale,
const int scale_num,
const float* bias,
const int bias_num,
float eps,
int groups,
bool with_silu,
bool with_fp16,
std::shared_ptr<void> scale_gpu = nullptr,
std::shared_ptr<void> bias_gpu = nullptr)
: scale_gpu_(scale_gpu),
bias_gpu_(bias_gpu),
groups_(groups),
eps_(eps),
with_silu_(with_silu),
with_fp16_(with_fp16) {
scale_.resize(scale_num);
bias_.resize(bias_num);
std::copy(scale, scale + scale_num, scale_.data());
std::copy(bias, bias + bias_num, bias_.data());
if (scale_gpu_ == nullptr) {
void* p;
cudaMalloc(reinterpret_cast<void**>(&p), scale_num * sizeof(float));
scale_gpu_.reset(p, [](void* ptr) { cudaFree(ptr); });
cudaMemcpy(
p, scale_.data(), scale_num * sizeof(float), cudaMemcpyHostToDevice);
}
if (bias_gpu_ == nullptr) {
void* p;
cudaMalloc(reinterpret_cast<void**>(&p), bias_num * sizeof(float));
bias_gpu_.reset(p, [](void* ptr) { cudaFree(ptr); });
cudaMemcpy(
p, bias_.data(), bias_num * sizeof(float), cudaMemcpyHostToDevice);
}
}
PrelnGroupnormActPluginDynamic(void const* serialData, size_t serialLength) {
DeserializeValue(&serialData, &serialLength, &scale_);
DeserializeValue(&serialData, &serialLength, &bias_);
DeserializeValue(&serialData, &serialLength, &eps_);
DeserializeValue(&serialData, &serialLength, &groups_);
DeserializeValue(&serialData, &serialLength, &with_silu_);
DeserializeValue(&serialData, &serialLength, &with_fp16_);
{
void* p;
cudaMalloc(reinterpret_cast<void**>(&p), scale_.size() * sizeof(float));
scale_gpu_.reset(p, [](void* ptr) { cudaFree(ptr); });
cudaMemcpy(p,
scale_.data(),
scale_.size() * sizeof(float),
cudaMemcpyHostToDevice);
}
{
void* p;
cudaMalloc(reinterpret_cast<void**>(&p), bias_.size() * sizeof(float));
bias_gpu_.reset(p, [](void* ptr) { cudaFree(ptr); });
cudaMemcpy(p,
bias_.data(),
bias_.size() * sizeof(float),
cudaMemcpyHostToDevice);
}
}
nvinfer1::IPluginV2DynamicExt* clone() const TRT_NOEXCEPT override {
auto* ptr = new PrelnGroupnormActPluginDynamic(scale_.data(),
scale_.size(),
bias_.data(),
bias_.size(),
eps_,
groups_,
with_silu_,
with_fp16_,
scale_gpu_,
bias_gpu_);
return ptr;
}
const char* getPluginType() const TRT_NOEXCEPT override {
return "preln_groupnorm_act_plugin_dynamic";
}
int getNbOutputs() const TRT_NOEXCEPT override { return 2; }
int initialize() TRT_NOEXCEPT override;
size_t getSerializationSize() const TRT_NOEXCEPT override {
return SerializedSize(scale_) + SerializedSize(bias_) +
SerializedSize(eps_) + SerializedSize(groups_) +
SerializedSize(with_silu_) + SerializedSize(with_fp16_);
}
void serialize(void* buffer) const TRT_NOEXCEPT override {
SerializeValue(&buffer, scale_);
SerializeValue(&buffer, bias_);
SerializeValue(&buffer, eps_);
SerializeValue(&buffer, groups_);
SerializeValue(&buffer, with_silu_);
SerializeValue(&buffer, with_fp16_);
}
nvinfer1::DimsExprs getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs* inputs,
int nb_inputs,
nvinfer1::IExprBuilder& expr_builder) // NOLINT
TRT_NOEXCEPT override;
bool supportsFormatCombination(int pos,
const nvinfer1::PluginTensorDesc* inOut,
int nbInputs,
int nbOutputs) TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::DynamicPluginTensorDesc* in,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc* out,
int nbOutputs) TRT_NOEXCEPT override {
// sizeof(float2) * maxBatchSize * maxNumberOfGroup. float2
// contains two buffers for sum and squared sum;
ws_ = sizeof(float) * 2 * in[0].max.d[0] * groups_;
}
size_t getWorkspaceSize(const nvinfer1::PluginTensorDesc* inputs,
int nbInputs,
const nvinfer1::PluginTensorDesc* outputs,
int nbOutputs) const TRT_NOEXCEPT override {
return ws_;
}
int enqueue(const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* inputTypes,
int nbInputs) const
TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override { delete this; }
void terminate() TRT_NOEXCEPT override{};
private:
size_t ws_;
std::vector<float> scale_;
std::vector<float> bias_;
std::shared_ptr<void> scale_gpu_;
std::shared_ptr<void> bias_gpu_;
GroupNormNDHWCParams<__half> params_;
int groups_;
float eps_;
bool with_silu_;
bool with_fp16_;
};
class PrelnGroupnormActPluginDynamicCreator : public TensorRTPluginCreator {
public:
const char* getPluginName() const TRT_NOEXCEPT override {
return "preln_groupnorm_act_plugin_dynamic";
}
const char* getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
nvinfer1::IPluginV2* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override {
return new PrelnGroupnormActPluginDynamic(serial_data, serial_length);
}
};
REGISTER_TRT_PLUGIN_V2(PrelnGroupnormActPluginDynamicCreator);
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,714 @@
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
// Copyright (c) 2019-2022, NVIDIA CORPORATION. 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 <stdio.h>
#include <cassert>
#include <vector>
#include "glog/logging.h"
#include "paddle/fluid/inference/tensorrt/plugin/preln_layernorm_shift_partition_op.h"
#include "paddle/phi/kernels/layer_norm_kernel.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
#define FINAL_MASK 0xffffffff
template <typename T>
__inline__ __device__ T warpReduceSum(T val) {
#pragma unroll
for (int mask = 16; mask > 0; mask >>= 1)
val += __shfl_xor_sync(FINAL_MASK, val, mask, 32);
return val;
}
/* Calculate the sum of all elements in a block */
template <typename T>
__inline__ __device__ T blockReduceSum(T val) {
static __shared__ T shared[32];
int lane = threadIdx.x & 0x1f;
int wid = threadIdx.x >> 5;
val = warpReduceSum<T>(val);
if (lane == 0) shared[wid] = val;
__syncthreads();
// Modify from blockDim.x << 5 to blockDim.x / 32. to prevent
// blockDim.x is not divided by 32
val = (threadIdx.x < (blockDim.x / 32.f)) ? shared[lane] : (T)(0.0f);
val = warpReduceSum<T>(val);
return val;
}
template <typename T>
__global__ void preln_layernorm_shift_partition(T *out0,
T *out1,
const T *input0,
const T *input1,
const T *gamma,
const T *beta,
int batch,
int H,
int W,
int n,
int shift_size,
int window_size,
const float eps) {
int tid = threadIdx.x;
const int batch_offset = blockIdx.z * gridDim.y * gridDim.x;
const int bid = batch_offset + blockIdx.y * gridDim.x + blockIdx.x;
const int shifted_H_idx =
(shift_size != 0) ? ((blockIdx.y - shift_size + gridDim.y) % gridDim.y)
: blockIdx.y;
const int shifted_W_idx =
(shift_size != 0) ? ((blockIdx.x - shift_size + gridDim.x) % gridDim.x)
: blockIdx.x;
const int window_H_idx = shifted_H_idx / window_size;
const int window_W_idx = shifted_W_idx / window_size;
const int stride_of_window_H = W / window_size;
const int window_idx = window_H_idx * stride_of_window_H + window_W_idx;
const int idx_in_window = (shifted_H_idx % window_size) * window_size +
(shifted_W_idx % window_size);
const int output_bid =
batch_offset + window_idx * window_size * window_size + idx_in_window;
__shared__ float s_mean;
__shared__ float s_variance;
float mean = 0.0f;
float variance = 0.0f;
const int index = bid * n + tid;
float local_out = 0;
if (tid < n) {
#if CUDA_ARCH_FP16_SUPPORTED(__CUDA_ARCH__)
local_out = static_cast<float>(__ldg(input0 + index));
#else
local_out = static_cast<float>(input0[index]);
#endif
#if CUDA_ARCH_FP16_SUPPORTED(__CUDA_ARCH__)
local_out += static_cast<float>(__ldg(input1 + index));
#else
local_out += static_cast<float>(input1[index]);
#endif
out0[index] = local_out;
}
mean = blockReduceSum<float>(local_out);
if (threadIdx.x == 0) {
s_mean = mean / n;
}
__syncthreads();
float diff = (tid < n) ? (local_out - s_mean) : 0.0f;
variance = blockReduceSum<float>(diff * diff);
if (threadIdx.x == 0) {
s_variance = variance / n + eps;
}
__syncthreads();
if (tid < n) {
#if CUDA_ARCH_FP16_SUPPORTED(__CUDA_ARCH__)
out1[output_bid * n + tid] =
(T)(((local_out - s_mean) * rsqrtf(s_variance)) *
static_cast<float>(__ldg(&gamma[tid])) +
static_cast<float>(__ldg(&beta[tid])));
#else
out1[output_bid * n + tid] =
(T)(((local_out - s_mean) * rsqrtf(s_variance)) *
static_cast<float>(gamma[tid]) +
static_cast<float>(beta[tid]));
#endif
}
}
template <>
__global__ void preln_layernorm_shift_partition(half2 *out0_ptr,
half2 *out1_ptr,
const half2 *input0_ptr,
const half2 *input1_ptr,
const half2 *gamma_ptr,
const half2 *beta_ptr,
int batch,
int H,
int W,
int n,
int shift_size,
int window_size,
const float eps) {
#if CUDA_ARCH_FP16_SUPPORTED(__CUDA_ARCH__)
const int batch_offset = blockIdx.z * gridDim.y * gridDim.x;
const int bid = batch_offset + blockIdx.y * gridDim.x + blockIdx.x;
const int shifted_H_idx =
(shift_size != 0) ? ((blockIdx.y - shift_size + gridDim.y) % gridDim.y)
: blockIdx.y;
const int shifted_W_idx =
(shift_size != 0) ? ((blockIdx.x - shift_size + gridDim.x) % gridDim.x)
: blockIdx.x;
const int window_H_idx = shifted_H_idx / window_size;
const int window_W_idx = shifted_W_idx / window_size;
const int stride_of_window_H = W / window_size;
const int window_idx = window_H_idx * stride_of_window_H + window_W_idx;
const int idx_in_window = (shifted_H_idx % window_size) * window_size +
(shifted_W_idx % window_size);
const int output_bid =
batch_offset + window_idx * window_size * window_size + idx_in_window;
int tid = threadIdx.x;
__shared__ float s_mean;
__shared__ float s_variance;
float mean = 0.0f;
float variance = 0.0f;
float2 local_out_fp2;
float local_out = 0.0f;
int id = bid * n + tid;
if (tid < n) {
half2 tmp = __hadd2(__ldg(input0_ptr + id), __ldg(input1_ptr + id));
local_out_fp2 = __half22float2(tmp);
local_out += local_out_fp2.x;
local_out += local_out_fp2.y;
out0_ptr[id] = tmp;
}
mean = blockReduceSum<float>(local_out);
if (threadIdx.x == 0) {
s_mean = mean / (n * 2);
}
__syncthreads();
if (tid < n) {
variance = (local_out_fp2.x - s_mean) * (local_out_fp2.x - s_mean);
variance += (local_out_fp2.y - s_mean) * (local_out_fp2.y - s_mean);
}
variance = blockReduceSum<float>(variance);
if (threadIdx.x == 0) {
s_variance = rsqrtf(variance / (n * 2) + eps);
}
__syncthreads();
if (tid < n) {
float2 gamma_val = __half22float2(__ldg(&gamma_ptr[tid]));
float2 beta_val = __half22float2(__ldg(&beta_ptr[tid]));
local_out_fp2.x =
(local_out_fp2.x - s_mean) * s_variance * gamma_val.x + beta_val.x;
local_out_fp2.y =
(local_out_fp2.y - s_mean) * s_variance * gamma_val.y + beta_val.y;
out1_ptr[output_bid * n + tid] = __float22half2_rn(local_out_fp2);
}
#endif
}
#define kITE 4
template <typename T>
__global__ void preln_layernorm_shift_partition_v2(T *out0,
T *out1,
const T *__restrict input0,
const T *__restrict input1,
const T *__restrict gamma,
const T *__restrict beta,
int batch,
int H,
int W,
int n,
int shift_size,
int window_size,
const float eps) {
// constexpr int kITE = 4;
const int tid = threadIdx.x;
const int batch_offset = blockIdx.z * gridDim.y * gridDim.x;
const int bid = batch_offset + blockIdx.y * gridDim.x + blockIdx.x;
const int shifted_H_idx =
(shift_size != 0) ? ((blockIdx.y - shift_size + gridDim.y) % gridDim.y)
: blockIdx.y;
const int shifted_W_idx =
(shift_size != 0) ? ((blockIdx.x - shift_size + gridDim.x) % gridDim.x)
: blockIdx.x;
const int window_H_idx = shifted_H_idx / window_size;
const int window_W_idx = shifted_W_idx / window_size;
const int stride_of_window_H = W / window_size;
const int window_idx = window_H_idx * stride_of_window_H + window_W_idx;
const int idx_in_window = (shifted_H_idx % window_size) * window_size +
(shifted_W_idx % window_size);
const int output_bid =
batch_offset + window_idx * window_size * window_size + idx_in_window;
const int offset = bid * n;
const int output_offset = output_bid * n;
__shared__ float s_mean;
__shared__ float s_variance;
float mean = 0.0f;
float variance = 0.0f;
float local_out[kITE];
float sum = 0.0f;
#pragma unroll
for (int i = 0; i < kITE; i++) {
int col_id = i * blockDim.x + tid;
int index = offset + col_id;
if (col_id < n) {
#if CUDA_ARCH_FP16_SUPPORTED(__CUDA_ARCH__)
local_out[i] = static_cast<float>(__ldg(input0 + index));
#else
local_out[i] = static_cast<float>(input0[index]);
#endif
#if CUDA_ARCH_FP16_SUPPORTED(__CUDA_ARCH__)
local_out[i] += static_cast<float>(__ldg(input1 + index));
#else
local_out[i] += static_cast<float>(input1[index]);
#endif
out0[index] = local_out[i];
sum += local_out[i];
}
}
mean = blockReduceSum<float>(sum);
if (tid == 0) {
s_mean = mean / n;
}
__syncthreads();
float var = 0.0f;
#pragma unroll
for (int i = 0; i < kITE; i++) {
int col_id = i * blockDim.x + tid;
if (col_id < n) {
float diff = local_out[i] - s_mean;
local_out[i] = diff;
var += diff * diff;
}
}
variance = blockReduceSum<float>(var);
if (tid == 0) {
s_variance = rsqrtf(variance / n + eps);
}
__syncthreads();
#pragma unroll
for (int i = 0; i < kITE; i++) {
int col_id = i * blockDim.x + tid;
if (col_id < n) {
#if CUDA_ARCH_FP16_SUPPORTED(__CUDA_ARCH__)
out1[output_offset + col_id] =
(T)(local_out[i] * s_variance *
static_cast<float>(__ldg(&gamma[col_id])) +
static_cast<float>(__ldg(&beta[col_id])));
#else
out1[output_offset + col_id] =
(T)(local_out[i] * s_variance * static_cast<float>(gamma[col_id]) +
static_cast<float>(beta[col_id]));
#endif
}
}
}
template <>
__global__ void preln_layernorm_shift_partition_v2(
half2 *out0_ptr,
half2 *out1_ptr,
const half2 *__restrict input0_ptr,
const half2 *__restrict input1_ptr,
const half2 *__restrict gamma_ptr,
const half2 *__restrict beta_ptr,
int batch,
int H,
int W,
int n,
int shift_size,
int window_size,
const float eps) {
#if CUDA_ARCH_FP16_SUPPORTED(__CUDA_ARCH__)
// constexpr int ite = 4;
const int tid = threadIdx.x;
const int batch_offset = blockIdx.z * gridDim.y * gridDim.x;
const int bid = batch_offset + blockIdx.y * gridDim.x + blockIdx.x;
const int shifted_H_idx =
(shift_size != 0) ? ((blockIdx.y - shift_size + gridDim.y) % gridDim.y)
: blockIdx.y;
const int shifted_W_idx =
(shift_size != 0) ? ((blockIdx.x - shift_size + gridDim.x) % gridDim.x)
: blockIdx.x;
const int window_H_idx = shifted_H_idx / window_size;
const int window_W_idx = shifted_W_idx / window_size;
const int stride_of_window_H = W / window_size;
const int window_idx = window_H_idx * stride_of_window_H + window_W_idx;
const int idx_in_window = (shifted_H_idx % window_size) * window_size +
(shifted_W_idx % window_size);
const int output_bid =
batch_offset + window_idx * window_size * window_size + idx_in_window;
const int offset = bid * n;
const int output_offset = output_bid * n;
__shared__ float s_mean;
__shared__ float s_variance;
float mean = 0.0f;
float variance = 0.0f;
half2 local_out_half2[kITE];
// float sum = 0.0f;
half2 sum = __float2half2_rn(0.0f);
#pragma unroll
for (int i = 0; i < kITE; i++) {
int col_id = i * blockDim.x + tid;
if (col_id < n) {
int index = offset + col_id;
local_out_half2[i] = __ldg(input0_ptr + index);
local_out_half2[i] =
__hadd2(local_out_half2[i], __ldg(input1_ptr + index));
out0_ptr[i] = local_out_half2[i];
sum += local_out_half2[i];
}
}
mean = blockReduceSum<float>(static_cast<float>(sum.x + sum.y));
if (threadIdx.x == 0) {
s_mean = mean / (n * 2);
}
__syncthreads();
float var = 0.0f;
half2 s_mean_2 = __float2half2_rn(s_mean);
#pragma unroll
for (int i = 0; i < kITE; i++) {
int col_id = i * blockDim.x + tid;
if (col_id < n) {
local_out_half2[i] = local_out_half2[i] - s_mean_2;
float v1 = static_cast<float>(local_out_half2[i].x);
float v2 = static_cast<float>(local_out_half2[i].y);
var += v1 * v1 + v2 * v2;
}
}
variance = blockReduceSum<float>(var);
if (threadIdx.x == 0) {
s_variance = rsqrtf(variance / (n * 2) + eps);
}
__syncthreads();
half2 s_var_2 = __float2half2_rn(s_variance);
#pragma unroll
for (int i = 0; i < kITE; i++) {
int col_id = i * blockDim.x + tid;
if (col_id < n) {
out1_ptr[output_offset + col_id] =
local_out_half2[i] * s_var_2 * __ldg(&gamma_ptr[col_id]) +
__ldg(&beta_ptr[col_id]);
}
}
#endif
}
template <typename T>
void invokePrelnLayernormShiftPartition(T *out0,
T *out1,
const T *input0,
const T *input1,
const T *gamma,
const T *beta,
int batch,
int H,
int W,
int n,
int shift_size,
int window_size,
const float eps,
cudaStream_t stream) {
dim3 grid(W, H, batch);
int blockSize = (n + 31) / 32 * 32;
if (blockSize >= 768) {
blockSize = ((blockSize / 4) + 31) / 32 * 32;
preln_layernorm_shift_partition_v2<T>
<<<grid, blockSize, 0, stream>>>(out0,
out1,
input0,
input1,
gamma,
beta,
batch,
H,
W,
n,
shift_size,
window_size,
eps);
} else {
preln_layernorm_shift_partition<T>
<<<grid, blockSize, 0, stream>>>(out0,
out1,
input0,
input1,
gamma,
beta,
batch,
H,
W,
n,
shift_size,
window_size,
eps);
}
}
template <>
void invokePrelnLayernormShiftPartition(half *out0,
half *out1,
const half *input0,
const half *input1,
const half *gamma,
const half *beta,
int batch,
int H,
int W,
int n,
int shift_size,
int window_size,
const float eps,
cudaStream_t stream) {
dim3 grid(W, H, batch);
int blockSize = n / 2;
blockSize = (blockSize + 31) / 32 * 32;
if ((batch * H * W >= 512 && blockSize >= 768) || blockSize > 1024) {
blockSize = ((blockSize / 4) + 31) / 32 * 32;
preln_layernorm_shift_partition_v2<<<grid, blockSize, 0, stream>>>(
reinterpret_cast<half2 *>(out0),
reinterpret_cast<half2 *>(out1),
(const half2 *)input0,
(const half2 *)input1,
(const half2 *)gamma,
(const half2 *)beta,
batch,
H,
W,
n / 2,
shift_size,
window_size,
eps);
} else {
preln_layernorm_shift_partition<<<grid, blockSize, 0, stream>>>(
reinterpret_cast<half2 *>(out0),
reinterpret_cast<half2 *>(out1),
(const half2 *)input0,
(const half2 *)input1,
(const half2 *)gamma,
(const half2 *)beta,
batch,
H,
W,
n / 2,
shift_size,
window_size,
eps);
}
}
template <typename T>
static void convertAndCopy(const std::vector<float> &host, T *dev) {
T *host_ptr = new T[host.size()];
std::transform(host.begin(), host.end(), host_ptr, [](float x) {
return static_cast<T>(x);
});
cudaMemcpy(dev, host_ptr, sizeof(T) * host.size(), cudaMemcpyHostToDevice);
delete host_ptr;
}
void PrelnLnormShiftPartitionPluginDynamic::configurePlugin(
const nvinfer1::DynamicPluginTensorDesc *in,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc *out,
int nbOutputs) TRT_NOEXCEPT {}
PrelnLnormShiftPartitionPluginDynamic::PrelnLnormShiftPartitionPluginDynamic(
const float *gamma,
const float *beta,
const int param_num,
int shift_size,
int window_size,
int input_resolution,
float eps,
bool with_fp16,
std::shared_ptr<void> gamma_dev,
std::shared_ptr<void> beta_dev)
: with_fp16_(with_fp16),
window_size_(window_size),
shift_size_(shift_size),
input_resolution_(input_resolution),
eps_(eps),
param_num_(param_num),
gamma_dev_(gamma_dev),
beta_dev_(beta_dev) {
beta_.resize(param_num);
gamma_.resize(param_num);
std::copy(gamma, gamma + param_num, gamma_.data());
std::copy(beta, beta + param_num, beta_.data());
int type_size = with_fp16 ? sizeof(half) : sizeof(float);
if (gamma_dev_ == nullptr) {
void *p;
cudaMalloc(reinterpret_cast<void **>(&p), param_num_ * type_size);
gamma_dev_.reset(p, [](void *ptr) { cudaFree(ptr); });
if (with_fp16)
convertAndCopy(gamma_, reinterpret_cast<half *>(p));
else
convertAndCopy(gamma_, reinterpret_cast<float *>(p));
}
if (beta_dev_ == nullptr) {
void *p;
cudaMalloc(reinterpret_cast<void **>(&p), param_num_ * type_size);
beta_dev_.reset(p, [](void *ptr) { cudaFree(ptr); });
if (with_fp16)
convertAndCopy(beta_, reinterpret_cast<half *>(p));
else
convertAndCopy(beta_, reinterpret_cast<float *>(p));
}
}
PrelnLnormShiftPartitionPluginDynamic::PrelnLnormShiftPartitionPluginDynamic(
void const *serialData, size_t serialLength) {
DeserializeValue(&serialData, &serialLength, &beta_);
DeserializeValue(&serialData, &serialLength, &gamma_);
DeserializeValue(&serialData, &serialLength, &param_num_);
DeserializeValue(&serialData, &serialLength, &with_fp16_);
DeserializeValue(&serialData, &serialLength, &shift_size_);
DeserializeValue(&serialData, &serialLength, &window_size_);
DeserializeValue(&serialData, &serialLength, &input_resolution_);
DeserializeValue(&serialData, &serialLength, &eps_);
int type_size = with_fp16_ ? sizeof(half) : sizeof(float);
{
void *p;
cudaMalloc(reinterpret_cast<void **>(&p), param_num_ * type_size);
gamma_dev_.reset(p, [](void *ptr) { cudaFree(ptr); });
if (with_fp16_)
convertAndCopy(gamma_, reinterpret_cast<half *>(p));
else
convertAndCopy(gamma_, reinterpret_cast<float *>(p));
}
{
void *p;
cudaMalloc(reinterpret_cast<void **>(&p), param_num_ * type_size);
beta_dev_.reset(p, [](void *ptr) { cudaFree(ptr); });
if (with_fp16_)
convertAndCopy(beta_, reinterpret_cast<half *>(p));
else
convertAndCopy(beta_, reinterpret_cast<float *>(p));
}
}
bool PrelnLnormShiftPartitionPluginDynamic::supportsFormatCombination(
int pos,
const nvinfer1::PluginTensorDesc *in_out,
int nb_inputs,
int nb_outputs) TRT_NOEXCEPT {
const nvinfer1::PluginTensorDesc &in = in_out[pos];
if (pos == 0) {
if (with_fp16_) {
return in.type == nvinfer1::DataType::kHALF &&
in.format == nvinfer1::TensorFormat::kLINEAR;
} else {
return in.type == nvinfer1::DataType::kFLOAT &&
in.format == nvinfer1::TensorFormat::kLINEAR;
}
}
const nvinfer1::PluginTensorDesc &prev = in_out[pos - 1];
// output
return in.type == prev.type && in.format == prev.format;
}
nvinfer1::DataType PrelnLnormShiftPartitionPluginDynamic::getOutputDataType(
int index,
const nvinfer1::DataType *input_types,
int nb_inputs) const TRT_NOEXCEPT {
return input_types[0];
}
nvinfer1::DimsExprs PrelnLnormShiftPartitionPluginDynamic::getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs *inputs,
int nb_inputs,
nvinfer1::IExprBuilder &expr_builder) TRT_NOEXCEPT {
if (output_index == 0) return inputs[0];
nvinfer1::DimsExprs ret;
ret.nbDims = 3;
ret.d[0] = expr_builder.operation(
nvinfer1::DimensionOperation::kFLOOR_DIV,
*expr_builder.operation(nvinfer1::DimensionOperation::kPROD,
*inputs[0].d[0],
*inputs[0].d[1]),
*expr_builder.constant(window_size_ * window_size_));
ret.d[1] = expr_builder.constant(window_size_ * window_size_);
ret.d[2] = inputs[0].d[2];
return ret;
}
int PrelnLnormShiftPartitionPluginDynamic::enqueue(
const nvinfer1::PluginTensorDesc *input_desc,
const nvinfer1::PluginTensorDesc *output_desc,
const void *const *inputs,
void *const *outputs,
void *workspace,
cudaStream_t stream) TRT_NOEXCEPT {
const auto &input_dims = input_desc[0].dims;
auto input_type = input_desc[0].type;
int batch = input_dims.d[0];
int emb_dim = input_dims.d[2];
if (input_type == nvinfer1::DataType::kFLOAT) {
VLOG(3)
<< "TRT Plugin DataType selected. PreLayernormShiftPartition-->fp32";
invokePrelnLayernormShiftPartition(
reinterpret_cast<float *>(outputs[0]),
reinterpret_cast<float *>(outputs[1]),
reinterpret_cast<const float *>(inputs[0]),
reinterpret_cast<const float *>(inputs[1]),
reinterpret_cast<const float *>(gamma_dev_.get()),
reinterpret_cast<const float *>(beta_dev_.get()),
batch,
input_resolution_,
input_resolution_,
emb_dim,
shift_size_,
window_size_,
eps_,
stream);
} else if (input_type == nvinfer1::DataType::kHALF) {
VLOG(3)
<< "TRT Plugin DataType selected. PreLayernormShiftPartition-->half";
invokePrelnLayernormShiftPartition(
reinterpret_cast<half *>(outputs[0]),
reinterpret_cast<half *>(outputs[1]),
reinterpret_cast<const half *>(inputs[0]),
reinterpret_cast<const half *>(inputs[1]),
reinterpret_cast<const half *>(gamma_dev_.get()),
reinterpret_cast<const half *>(beta_dev_.get()),
batch,
input_resolution_,
input_resolution_,
emb_dim,
shift_size_,
window_size_,
eps_,
stream);
}
return cudaGetLastError() != cudaSuccess;
}
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,158 @@
// Copyright (c) 2022 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.
#pragma once
#include <algorithm>
#include <string>
#include <vector>
#include "paddle/fluid/framework/tensor.h"
#include "paddle/fluid/framework/tensor_util.h"
#include "paddle/fluid/inference/tensorrt/engine.h"
#include "paddle/fluid/inference/tensorrt/plugin/trt_plugin.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
class PrelnLnormShiftPartitionPluginDynamic : public DynamicPluginTensorRT {
public:
PrelnLnormShiftPartitionPluginDynamic(
const float* gamma,
const float* beta,
const int param_num,
int shift_size,
int window_size,
int input_resolution,
float eps,
bool with_fp16,
std::shared_ptr<void> gamma_dev = nullptr,
std::shared_ptr<void> beta_dev = nullptr);
PrelnLnormShiftPartitionPluginDynamic(void const* serialData,
size_t serialLength);
nvinfer1::IPluginV2DynamicExt* clone() const TRT_NOEXCEPT override {
return new PrelnLnormShiftPartitionPluginDynamic(gamma_.data(),
beta_.data(),
beta_.size(),
shift_size_,
window_size_,
input_resolution_,
eps_,
with_fp16_,
gamma_dev_,
beta_dev_);
}
const char* getPluginType() const TRT_NOEXCEPT override {
return "prelnlnorm_shift_partition_dynamic";
}
int getNbOutputs() const TRT_NOEXCEPT override { return 2; }
int initialize() TRT_NOEXCEPT override { return 0; }
size_t getSerializationSize() const TRT_NOEXCEPT override {
return SerializedSize(beta_) + SerializedSize(gamma_) +
SerializedSize(param_num_) + SerializedSize(with_fp16_) +
SerializedSize(shift_size_) + SerializedSize(window_size_) +
SerializedSize(input_resolution_) + SerializedSize(eps_);
}
void serialize(void* buffer) const TRT_NOEXCEPT override {
SerializeValue(&buffer, beta_);
SerializeValue(&buffer, gamma_);
SerializeValue(&buffer, param_num_);
SerializeValue(&buffer, with_fp16_);
SerializeValue(&buffer, shift_size_);
SerializeValue(&buffer, window_size_);
SerializeValue(&buffer, input_resolution_);
SerializeValue(&buffer, eps_);
}
nvinfer1::DimsExprs getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs* inputs,
int nb_inputs,
nvinfer1::IExprBuilder& expr_builder) // NOLINT
TRT_NOEXCEPT override;
bool supportsFormatCombination(int pos,
const nvinfer1::PluginTensorDesc* inOut,
int nbInputs,
int nbOutputs) TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::DynamicPluginTensorDesc* in,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc* out,
int nbOutputs) TRT_NOEXCEPT override;
size_t getWorkspaceSize(const nvinfer1::PluginTensorDesc* inputs,
int nbInputs,
const nvinfer1::PluginTensorDesc* outputs,
int nbOutputs) const TRT_NOEXCEPT override {
return 0;
}
int enqueue(const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* inputTypes,
int nbInputs) const
TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override { delete this; }
private:
bool with_fp16_;
std::vector<float> gamma_;
std::vector<float> beta_;
int window_size_;
int shift_size_;
int input_resolution_;
int param_num_;
float eps_;
std::shared_ptr<void> gamma_dev_;
std::shared_ptr<void> beta_dev_;
};
class PrelnLnormShiftPartitionPluginDynamicCreator
: public TensorRTPluginCreator {
public:
const char* getPluginName() const TRT_NOEXCEPT override {
return "prelnlnorm_shift_partition_dynamic";
}
const char* getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
nvinfer1::IPluginV2* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override {
return new PrelnLnormShiftPartitionPluginDynamic(serial_data,
serial_length);
}
};
REGISTER_TRT_PLUGIN_V2(PrelnLnormShiftPartitionPluginDynamicCreator);
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,343 @@
// Copyright (c) 2022 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.
#pragma once
#include <algorithm>
#include <string>
#include <vector>
#include "paddle/fluid/inference/tensorrt/engine.h"
#include "paddle/fluid/inference/tensorrt/plugin/trt_plugin.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
using half = phi::dtype::float16;
class PrelnResidualBiasPluginDynamic : public DynamicPluginTensorRT {
public:
explicit PrelnResidualBiasPluginDynamic(const float* bias,
const float* scale,
const half* ele_bias,
int bias_size,
int scale_size,
int ele_bias_size,
const float eps,
bool with_fp16)
: bias_size_(bias_size),
scale_size_(scale_size),
ele_bias_size_(ele_bias_size),
eps_(eps) {
with_fp16_ = with_fp16;
bias_.resize(bias_size);
scale_.resize(scale_size);
fp16_bias_.resize(bias_size);
fp16_scale_.resize(scale_size);
fp16_ele_bias_.resize(ele_bias_size);
std::copy(ele_bias, ele_bias + ele_bias_size, fp16_ele_bias_.data());
std::copy(bias, bias + bias_size, bias_.data());
std::copy(scale, scale + scale_size, scale_.data());
for (int i = 0; i < bias_size; i++) {
fp16_bias_[i] = static_cast<half>(bias[i]);
}
for (int i = 0; i < scale_size; i++) {
fp16_scale_[i] = static_cast<half>(scale[i]);
}
}
explicit PrelnResidualBiasPluginDynamic(const float* bias,
const float* scale,
const float* ele_bias,
int bias_size,
int scale_size,
int ele_bias_size,
const float eps,
bool with_fp16)
: bias_size_(bias_size),
scale_size_(scale_size),
ele_bias_size_(ele_bias_size),
eps_(eps) {
with_fp16_ = with_fp16;
bias_.resize(bias_size);
scale_.resize(scale_size);
fp32_ele_bias_.resize(ele_bias_size);
std::copy(ele_bias, ele_bias + ele_bias_size, fp32_ele_bias_.data());
std::copy(bias, bias + bias_size, bias_.data());
std::copy(scale, scale + scale_size, scale_.data());
}
PrelnResidualBiasPluginDynamic(void const* serial_data,
size_t serial_length) {
DeserializeValue(&serial_data, &serial_length, &bias_);
DeserializeValue(&serial_data, &serial_length, &fp16_bias_);
DeserializeValue(&serial_data, &serial_length, &scale_);
DeserializeValue(&serial_data, &serial_length, &fp16_scale_);
DeserializeValue(&serial_data, &serial_length, &fp32_ele_bias_);
DeserializeValue(&serial_data, &serial_length, &fp16_ele_bias_);
DeserializeValue(&serial_data, &serial_length, &bias_size_);
DeserializeValue(&serial_data, &serial_length, &scale_size_);
DeserializeValue(&serial_data, &serial_length, &ele_bias_size_);
DeserializeValue(&serial_data, &serial_length, &eps_);
DeserializeValue(&serial_data, &serial_length, &with_fp16_);
}
nvinfer1::IPluginV2DynamicExt* clone() const TRT_NOEXCEPT override;
const char* getPluginType() const TRT_NOEXCEPT override;
int getNbOutputs() const TRT_NOEXCEPT override;
int initialize() TRT_NOEXCEPT override;
size_t getSerializationSize() const TRT_NOEXCEPT override;
void serialize(void* buffer) const TRT_NOEXCEPT override;
nvinfer1::DimsExprs getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs* inputs,
int nb_inputs,
nvinfer1::IExprBuilder& expr_builder) // NOLINT
TRT_NOEXCEPT override;
bool supportsFormatCombination(int pos,
const nvinfer1::PluginTensorDesc* in_out,
int nb_inputs,
int nb_outputs) TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::DynamicPluginTensorDesc* in,
int nb_inputs,
const nvinfer1::DynamicPluginTensorDesc* out,
int nb_outputs) TRT_NOEXCEPT override;
size_t getWorkspaceSize(const nvinfer1::PluginTensorDesc* inputs,
int nb_inputs,
const nvinfer1::PluginTensorDesc* outputs,
int nb_outputs) const TRT_NOEXCEPT override;
int enqueue(const nvinfer1::PluginTensorDesc* input_desc,
const nvinfer1::PluginTensorDesc* output_desc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* input_types,
int nb_inputs) const
TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override;
void terminate() TRT_NOEXCEPT override;
private:
// bias for fp32 mode
std::vector<float> bias_;
// bias for fp16 mode
std::vector<half> fp16_bias_;
// scale for fp32 mode
std::vector<float> scale_;
// scale for fp16 mode
std::vector<half> fp16_scale_;
std::vector<float> fp32_ele_bias_;
std::vector<half> fp16_ele_bias_;
float* bias_gpu_{nullptr};
half* fp16_bias_gpu_{nullptr};
float* scale_gpu_{nullptr};
half* fp16_scale_gpu_{nullptr};
void* ele_bias_gpu_{nullptr};
int bias_size_;
int scale_size_;
int ele_bias_size_;
float eps_;
bool with_fp16_;
};
class PrelnResidualBiasPluginDynamicCreator : public TensorRTPluginCreator {
public:
const char* getPluginName() const TRT_NOEXCEPT override;
const char* getPluginVersion() const TRT_NOEXCEPT override;
nvinfer1::IPluginV2* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override;
};
class PIRPrelnResidualBiasPluginDynamic : public DynamicPluginTensorRT {
public:
explicit PIRPrelnResidualBiasPluginDynamic(const float* bias,
const float* scale,
const half* ele_bias,
int bias_size,
int scale_size,
int ele_bias_size,
const float eps,
bool with_fp16)
: bias_size_(bias_size),
scale_size_(scale_size),
ele_bias_size_(ele_bias_size),
eps_(eps) {
with_fp16_ = with_fp16;
bias_.resize(bias_size);
scale_.resize(scale_size);
fp16_bias_.resize(bias_size);
fp16_scale_.resize(scale_size);
fp16_ele_bias_.resize(ele_bias_size);
std::copy(ele_bias, ele_bias + ele_bias_size, fp16_ele_bias_.data());
std::copy(bias, bias + bias_size, bias_.data());
std::copy(scale, scale + scale_size, scale_.data());
for (int i = 0; i < bias_size; i++) {
fp16_bias_[i] = static_cast<half>(bias[i]);
}
for (int i = 0; i < scale_size; i++) {
fp16_scale_[i] = static_cast<half>(scale[i]);
}
}
explicit PIRPrelnResidualBiasPluginDynamic(const float* bias,
const float* scale,
const float* ele_bias,
int bias_size,
int scale_size,
int ele_bias_size,
const float eps,
bool with_fp16)
: bias_size_(bias_size),
scale_size_(scale_size),
ele_bias_size_(ele_bias_size),
eps_(eps) {
with_fp16_ = with_fp16;
bias_.resize(bias_size);
scale_.resize(scale_size);
fp32_ele_bias_.resize(ele_bias_size);
std::copy(ele_bias, ele_bias + ele_bias_size, fp32_ele_bias_.data());
std::copy(bias, bias + bias_size, bias_.data());
std::copy(scale, scale + scale_size, scale_.data());
}
PIRPrelnResidualBiasPluginDynamic(void const* serial_data,
size_t serial_length) {
DeserializeValue(&serial_data, &serial_length, &bias_);
DeserializeValue(&serial_data, &serial_length, &fp16_bias_);
DeserializeValue(&serial_data, &serial_length, &scale_);
DeserializeValue(&serial_data, &serial_length, &fp16_scale_);
DeserializeValue(&serial_data, &serial_length, &fp32_ele_bias_);
DeserializeValue(&serial_data, &serial_length, &fp16_ele_bias_);
DeserializeValue(&serial_data, &serial_length, &bias_size_);
DeserializeValue(&serial_data, &serial_length, &scale_size_);
DeserializeValue(&serial_data, &serial_length, &ele_bias_size_);
DeserializeValue(&serial_data, &serial_length, &eps_);
DeserializeValue(&serial_data, &serial_length, &with_fp16_);
}
nvinfer1::IPluginV2DynamicExt* clone() const TRT_NOEXCEPT override;
const char* getPluginType() const TRT_NOEXCEPT override;
int getNbOutputs() const TRT_NOEXCEPT override;
int initialize() TRT_NOEXCEPT override;
size_t getSerializationSize() const TRT_NOEXCEPT override;
void serialize(void* buffer) const TRT_NOEXCEPT override;
nvinfer1::DimsExprs getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs* inputs,
int nb_inputs,
nvinfer1::IExprBuilder& expr_builder) // NOLINT
TRT_NOEXCEPT override;
bool supportsFormatCombination(int pos,
const nvinfer1::PluginTensorDesc* in_out,
int nb_inputs,
int nb_outputs) TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::DynamicPluginTensorDesc* in,
int nb_inputs,
const nvinfer1::DynamicPluginTensorDesc* out,
int nb_outputs) TRT_NOEXCEPT override;
size_t getWorkspaceSize(const nvinfer1::PluginTensorDesc* inputs,
int nb_inputs,
const nvinfer1::PluginTensorDesc* outputs,
int nb_outputs) const TRT_NOEXCEPT override;
int enqueue(const nvinfer1::PluginTensorDesc* input_desc,
const nvinfer1::PluginTensorDesc* output_desc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* input_types,
int nb_inputs) const
TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override;
void terminate() TRT_NOEXCEPT override;
private:
// bias for fp32 mode
std::vector<float> bias_;
// bias for fp16 mode
std::vector<half> fp16_bias_;
// scale for fp32 mode
std::vector<float> scale_;
// scale for fp16 mode
std::vector<half> fp16_scale_;
std::vector<float> fp32_ele_bias_;
std::vector<half> fp16_ele_bias_;
float* bias_gpu_{nullptr};
half* fp16_bias_gpu_{nullptr};
float* scale_gpu_{nullptr};
half* fp16_scale_gpu_{nullptr};
void* ele_bias_gpu_{nullptr};
int bias_size_;
int scale_size_;
int ele_bias_size_;
float eps_;
bool with_fp16_;
};
class PIRPrelnResidualBiasPluginDynamicCreator : public TensorRTPluginCreator {
public:
const char* getPluginName() const TRT_NOEXCEPT override;
const char* getPluginVersion() const TRT_NOEXCEPT override;
nvinfer1::IPluginV2* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override;
nvinfer1::IPluginV2* createPlugin(const char* name,
const nvinfer1::PluginFieldCollection* fc)
TRT_NOEXCEPT override;
};
REGISTER_TRT_PLUGIN_V2(PrelnResidualBiasPluginDynamicCreator);
REGISTER_TRT_PLUGIN_V2(PIRPrelnResidualBiasPluginDynamicCreator);
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,204 @@
// Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
// SPDX-FileCopyrightText: Copyright (c) 1993-2023 NVIDIA CORPORATION &
// AFFILIATES. 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 <cuda.h>
#include <cassert>
#include <cstring>
#include <iostream>
#include <vector>
#include "NvInfer.h"
#include "paddle/fluid/inference/tensorrt/plugin/common/common.cuh"
#include "paddle/fluid/inference/tensorrt/plugin/prompt_tuning_emb_layernorm_varseqlen_plugin.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
template <typename T, unsigned TPB>
__global__ void prompt_tuning_embKernel(int32_t B,
int32_t ld,
int32_t const* inputIds0,
int32_t const* inputIds1,
int32_t const* inputIds2,
T const* dense_vector,
float const* beta,
float const* gamma,
T const* mIdsEmbDev0,
T const* mIdsEmbDev1,
T const* mIdsEmbDev2,
int32_t IdsSize0,
int32_t IdsSize1,
int32_t IdsSize2,
T* output,
int32_t* new_pos_id) {
cub::Sum pairSum;
int32_t const s = blockIdx.x;
int32_t const b = blockIdx.y;
int32_t const sumS = inputIds0[b];
int32_t const s_b = inputIds0[b + 1] - inputIds0[b];
int32_t const new_sumS = sumS + b;
// new pos_id: Add an id to each sentence
new_pos_id[b] = new_sumS;
// last id
if (b == B - 1) {
new_pos_id[B] = inputIds0[B] + B;
}
T const rld = T(1.f) / T(ld);
int32_t const seqPos = sumS + s;
int32_t const out_seqPos = new_sumS + s + 1;
int32_t const new_out_seqPos = new_sumS + s;
kvp<T> threadData(0, 0);
int32_t const new_outoffset = new_out_seqPos * ld;
int32_t const prompt_tuning_offset = new_sumS * ld;
int32_t const dense_vector_offset = b * ld;
if (s < s_b) {
extern __shared__ int32_t word_id[];
if (threadIdx.x == 0) {
if (static_cast<int32_t const*>(inputIds1)[seqPos] < 0 ||
static_cast<int32_t const*>(inputIds1)[seqPos] >= IdsSize1) {
printf(
"Error!!!!!!(embLayerNormVarSeqlenPlugin): ID cannot be lookup "
"table: ID < 0 or ID > max ");
return;
} else {
word_id[0] = static_cast<int32_t const*>(inputIds1)[seqPos];
}
if (static_cast<int32_t const*>(inputIds2)[seqPos] < 0 ||
static_cast<int32_t const*>(inputIds2)[seqPos] >= IdsSize2) {
printf(
"Error!!!!!!(embLayerNormVarSeqlenPlugin): ID cannot be lookup "
"table: ID < 0 or ID > max ");
return;
} else {
word_id[1] = static_cast<int32_t const*>(inputIds2)[seqPos];
}
}
__syncthreads();
// 2. load pos/tok/word embeddings and add them together
// offset into embeddings is given by wordId * hidden_size
int32_t const poffset = blockIdx.x * ld;
int32_t const outoffset = out_seqPos * ld;
// the output offset is given by b * (S*hidden_size) + s * hidden_size
for (int32_t it = threadIdx.x; it < ld; it += TPB) {
T p(mIdsEmbDev0[poffset + it]); // pos id
T val = p;
int32_t const offset0 = word_id[0] * ld;
val += mIdsEmbDev1[offset0 + it];
int32_t const offset1 = word_id[1] * ld;
val += mIdsEmbDev2[offset1 + it];
output[outoffset + it] = val;
T const rldval = rld * val;
threadData = pairSum(threadData, kvp<T>(rldval, rldval * val));
}
// 3. layer norm on the sum
layerNorm<T, T, float, TPB>(threadData, ld, outoffset, beta, gamma, output);
} else if (s == s_b) {
for (int32_t it = threadIdx.x; it < ld; it += TPB) {
T val = dense_vector[dense_vector_offset + it];
output[prompt_tuning_offset + it] = val;
T const rldval = rld * val;
threadData = pairSum(threadData, kvp<T>(rldval, rldval * val));
// 3. layer norm on the sum
}
layerNorm<T, T, float, TPB>(
threadData, ld, prompt_tuning_offset, beta, gamma, output);
} else {
return; // This CTA has nothing to do
}
}
template <typename T>
int32_t prompt_tuning_emb(cudaStream_t stream,
int32_t ld,
int32_t B,
int32_t S,
int const* inputIds0,
int const* inputIds1,
int const* inputIds2,
T const* dense_vector,
int32_t nbLookupTables,
float const* beta,
float const* gamma,
T const* mIdsEmbDev0,
T const* mIdsEmbDev1,
T const* mIdsEmbDev2,
int32_t IdsSize0,
int32_t IdsSize1,
int32_t IdsSize2,
T* output,
int32_t* new_pos_id) {
constexpr int32_t tpb = 256;
dim3 const grid(S, B, 1);
dim3 const block(tpb, 1, 1);
size_t cache_size = sizeof(int32_t) * (nbLookupTables - 1);
prompt_tuning_embKernel<T, tpb>
<<<grid, block, cache_size, stream>>>(B,
ld,
inputIds0,
inputIds1,
inputIds2,
dense_vector,
beta,
gamma,
mIdsEmbDev0,
mIdsEmbDev1,
mIdsEmbDev2,
IdsSize0,
IdsSize1,
IdsSize2,
output,
new_pos_id);
return cudaPeekAtLastError();
}
template int32_t prompt_tuning_emb<half>(cudaStream_t,
int32_t,
int32_t,
int32_t,
int32_t const*,
int32_t const*,
int32_t const*,
half const*,
int32_t,
float const*,
float const*,
half const*,
half const*,
half const*,
int32_t,
int32_t,
int32_t,
half*,
int32_t*);
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,562 @@
// Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
// SPDX-FileCopyrightText: Copyright (c) 1993-2023 NVIDIA CORPORATION &
// AFFILIATES. 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/plugin/prompt_tuning_emb_layernorm_varseqlen_plugin.h"
#include <cuda.h>
#include <cstring>
#include <vector>
#include "NvInfer.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
constexpr size_t threadsPerCta128 = 2 * 2 * 32;
constexpr size_t threadsPerCta256 = 1 * 4 * 32;
constexpr size_t threadsPerCta384 = 1 * 8 * 32;
// The number of xmmas in the M dimension. We use one uint32_t per XMMA in the M
// dimension: (s + 16*warps_m - 1) / (16*warps_m);
constexpr size_t xmmasM128 = 4;
constexpr size_t xmmasM256 = 16;
constexpr size_t xmmasM384 = 24;
// Packed mask size per batch. Layout is XMMAS_M * THREADS_PER_CTA.
constexpr size_t packedMaskSize128 = xmmasM128 * threadsPerCta128;
constexpr size_t packedMaskSize256 = xmmasM256 * threadsPerCta256;
constexpr size_t packedMaskSize384 = xmmasM384 * threadsPerCta384;
char const* PTUNING_EMB_LAYER_NORM_VAR_SEQLEN_VERSION_HFACE{"1"};
char const* PTUNING_EMB_LAYER_NORM_VAR_SEQLEN_NAME{
"PromptTuningEmbLayerNormVarlenPluginDynamic"};
// Static class fields initialization
nvinfer1::PluginFieldCollection
TrtPromptTuningEmbLayerNormVarSeqlenPluginBaseCreator::mFC{};
std::vector<nvinfer1::PluginField>
TrtPromptTuningEmbLayerNormVarSeqlenPluginBaseCreator::mPluginAttributes;
TrtPromptTuningEmbLayerNormVarSeqlenPluginBase::
TrtPromptTuningEmbLayerNormVarSeqlenPluginBase(
std::string const& name,
nvinfer1::DataType const type,
nvinfer1::Weights const& beta,
nvinfer1::Weights const& gamma,
const std::vector<nvinfer1::Weights>& IdsEmb)
: mLayerName(name),
mLd(beta.count),
mType(type),
mIdsEmb_(IdsEmb),
nbLookupTables_(static_cast<int>(IdsEmb.size())) {
// Assuming Weights.count is the number of elements and not bytes
assert(beta.count == gamma.count);
mBeta.convertAndCopy(beta, nvinfer1::DataType::kFLOAT);
mGamma.convertAndCopy(gamma, nvinfer1::DataType::kFLOAT);
copyToDevice(&mGamma, sizeof(float) * mGamma.count, &mGammaDev);
copyToDevice(&mBeta, sizeof(float) * mBeta.count, &mBetaDev);
for (size_t i = 0; i < mIdsEmb_.size(); ++i) {
assert(mIdsEmb_[i].count % mLd == 0);
mIdsVocabSize.push_back(int32_t(mIdsEmb_[i].count / mLd));
WeightsWithOwnership tem_weight;
tem_weight.convertAndCopy(mIdsEmb_[i], mType);
void* cudaMem{nullptr};
PADDLE_ENFORCE_GPU_SUCCESS(
cudaMalloc(&cudaMem, getWeightsSize(tem_weight, mType)));
PADDLE_ENFORCE_GPU_SUCCESS(cudaMemcpy(cudaMem,
tem_weight.values,
getWeightsSize(tem_weight, mType),
cudaMemcpyHostToDevice));
mIdsEmbPtrs.push_back(cudaMem);
}
}
TrtPromptTuningEmbLayerNormVarSeqlenPluginBase::
TrtPromptTuningEmbLayerNormVarSeqlenPluginBase(std::string const& name,
void const* data,
size_t length)
: mLayerName(name),
mGammaDev(nullptr),
mBetaDev(nullptr),
mIdsEmbPtrs{},
mIdsEmb_{} {
// Deserialize in the same order as serialization
deserialize_value(&data, &length, &mType);
deserialize_value(&data, &length, &mLd);
deserialize_value(&data, &length, &nbLookupTables_);
for (int32_t i = 0; i < nbLookupTables_; ++i) {
int32_t tem;
deserialize_value(&data, &length, &tem);
mIdsVocabSize.push_back(tem);
}
char const* d = static_cast<char const*>(data);
mBeta.convertAndCopy(&d, mLd, nvinfer1::DataType::kFLOAT);
mGamma.convertAndCopy(&d, mLd, nvinfer1::DataType::kFLOAT);
for (int32_t i = 0; i < nbLookupTables_; ++i) {
nvinfer1::Weights pre_tem_weight;
pre_tem_weight.type = mType;
pre_tem_weight.count = mLd * size_t(mIdsVocabSize[i]);
const auto nbBytes = mLd * size_t(mIdsVocabSize[i]) * getElementSize(mType);
auto destBuf = new char[nbBytes];
pre_tem_weight.values = destBuf;
std::copy_n(d, nbBytes, destBuf);
d += nbBytes;
mIdsEmb_.push_back(pre_tem_weight);
}
}
TrtPromptTuningEmbLayerNormVarSeqlenPluginHFace::
TrtPromptTuningEmbLayerNormVarSeqlenPluginHFace(
std::string const& name,
nvinfer1::DataType const type,
nvinfer1::Weights const& beta,
nvinfer1::Weights const& gamma,
const std::vector<nvinfer1::Weights>& IdsEmb)
: TrtPromptTuningEmbLayerNormVarSeqlenPluginBase(
name, type, beta, gamma, IdsEmb) {}
TrtPromptTuningEmbLayerNormVarSeqlenPluginHFace::
TrtPromptTuningEmbLayerNormVarSeqlenPluginHFace(std::string const& name,
void const* data,
size_t length)
: TrtPromptTuningEmbLayerNormVarSeqlenPluginBase(name, data, length) {
TRANSFORMER_DEBUG_MSG(
"TrtPromptTuningEmbLayerNormVarSeqlenPluginHFace deserialize");
}
// IPluginV2DynamicExt Methods
nvinfer1::IPluginV2DynamicExt*
TrtPromptTuningEmbLayerNormVarSeqlenPluginHFace::clone() const noexcept {
TRANSFORMER_DEBUG_MSG(
"TrtPromptTuningEmbLayerNormVarSeqlenPluginHFace clone");
auto p = new TrtPromptTuningEmbLayerNormVarSeqlenPluginHFace(
mLayerName, mType, mBeta, mGamma, mIdsEmb_);
p->setPluginNamespace(mNamespace.c_str());
return p;
}
nvinfer1::DimsExprs
TrtPromptTuningEmbLayerNormVarSeqlenPluginHFace::getOutputDimensions(
int32_t outputIndex,
nvinfer1::DimsExprs const* inputs,
int32_t nbInputs,
nvinfer1::IExprBuilder& exprBuilder) noexcept {
for (int i = 1; i < nbInputs - 2; ++i) {
assert(inputs[i].nbDims == 1); // seq length
assert(inputs[i].nbDims == inputs[1].nbDims); // same shape
}
assert(inputs[0].nbDims == 1); // pos_id: B+1
auto one = exprBuilder.constant(1);
auto Bplus1 = inputs[0].d[0]; // pos_id
auto B =
exprBuilder.operation(nvinfer1::DimensionOperation::kSUB, *Bplus1, *one);
if (outputIndex == 0) {
nvinfer1::DimsExprs ret;
ret.nbDims = 4;
ret.d[0] = exprBuilder.operation(nvinfer1::DimensionOperation::kSUM,
*inputs[1].d[0],
*B); // sum of seq length
ret.d[1] = exprBuilder.constant(mLd);
ret.d[2] = exprBuilder.constant(1);
ret.d[3] = exprBuilder.constant(1);
return ret;
} else if (outputIndex == 1) {
// This is a hack: we just report some mask size and rely the plugins to
// play nicely together.
// At runtime, depending on the actual maxSeqlen, the size might be
// different.
int32_t maskSize_ = packedMaskSize384;
auto maskSize = exprBuilder.constant(maskSize_);
auto fp16maskSize =
exprBuilder.operation(nvinfer1::DimensionOperation::kPROD,
*maskSize,
*exprBuilder.constant(2));
nvinfer1::DimsExprs ret;
ret.nbDims = 2;
ret.d[0] = B;
ret.d[1] = fp16maskSize;
return ret;
} else if (outputIndex == 2) {
nvinfer1::DimsExprs ret;
ret.nbDims = 1;
ret.d[0] = exprBuilder.operation(nvinfer1::DimensionOperation::kSUM,
*inputs[nbInputs - 2].d[1],
*one); // max seqlen
return ret;
} else if (outputIndex == 3) {
nvinfer1::DimsExprs ret = inputs[nbInputs - 2]; // new mask_id
ret.d[1] = exprBuilder.operation(
nvinfer1::DimensionOperation::kSUM, *inputs[nbInputs - 2].d[1], *one);
return ret;
} else if (outputIndex == 4) {
nvinfer1::DimsExprs ret = inputs[0]; // new pos_id
return ret;
}
}
bool TrtPromptTuningEmbLayerNormVarSeqlenPluginBase::supportsFormatCombination(
int32_t pos,
nvinfer1::PluginTensorDesc const* inOut,
int32_t nbInputs,
int32_t nbOutputs) noexcept {
assert(nbOutputs == 5);
nvinfer1::PluginTensorDesc const& desc = inOut[pos];
if (desc.format != nvinfer1::TensorFormat::kLINEAR) {
return false;
}
if (pos == 0) { // pos_id
return desc.dims.nbDims == 1 && desc.type == nvinfer1::DataType::kINT32;
}
if (pos == 1) { // input_id
return desc.dims.nbDims == 1 && desc.type == nvinfer1::DataType::kINT32;
}
nvinfer1::PluginTensorDesc const& prev = inOut[1]; // input_ids
if (1 < pos &&
pos < (nbInputs - 2)) { // other ids: check it's the same as input_ids
return desc.type == prev.type && desc.dims.nbDims == 1 &&
desc.dims.d[0] == prev.dims.d[0];
}
if (pos == nbInputs - 2) { // mask id
return desc.type == mType;
}
if (pos == nbInputs - 1) { // dense vector
return desc.type == mType;
}
// embedded sequence
if (pos == nbInputs) {
return desc.type == mType && desc.dims.nbDims == 4 && desc.dims.d[2] == 1 &&
desc.dims.d[3] == 1;
}
// mask(HFace)
if (pos == nbInputs + 1) {
return desc.type == mType;
}
// max seqlen
if (pos == nbInputs + 2) {
return desc.type == mType;
}
// new mask_id
if (pos == nbInputs + 3) {
return desc.type == mType;
}
// new pos_id
if (pos == nbInputs + 4) {
return desc.dims.nbDims == 1 && desc.type == nvinfer1::DataType::kINT32;
}
}
void check_tensors(nvinfer1::DynamicPluginTensorDesc const* inputs,
int32_t nbInputs,
nvinfer1::DynamicPluginTensorDesc const* outputs,
int32_t nbOutputs) noexcept {
// Validate input arguments
assert(nbOutputs == 5);
assert(inputs[0].desc.dims.nbDims == 1);
assert(inputs[0].desc.type == nvinfer1::DataType::kINT32);
for (int i = 1; i < nbInputs - 2; ++i) {
assert(inputs[i].desc.dims.nbDims == 1);
assert(inputs[i].desc.dims.d[0] == inputs[1].desc.dims.d[0]);
assert(inputs[i].desc.type == nvinfer1::DataType::kINT32);
}
assert(outputs[0].desc.dims.nbDims == 4);
assert(outputs[0].desc.dims.d[2] == 1);
assert(outputs[0].desc.dims.d[3] == 1);
}
void TrtPromptTuningEmbLayerNormVarSeqlenPluginHFace::configurePlugin(
nvinfer1::DynamicPluginTensorDesc const* inputs,
int32_t nbInputs,
nvinfer1::DynamicPluginTensorDesc const* outputs,
int32_t nbOutputs) noexcept {
TRANSFORMER_DEBUG_MSG(
"TrtPromptTuningEmbLayerNormVarSeqlenPluginHFace configurePlugin");
check_tensors(inputs, nbInputs, outputs, nbOutputs);
assert(static_cast<size_t>(outputs[0].desc.dims.d[1]) ==
static_cast<size_t>(mLd));
int32_t const B = inputs[0].desc.dims.d[0] - 1;
// check mask
assert(outputs[1].desc.dims.nbDims == 2);
if (B > 0) {
assert(outputs[1].desc.dims.d[0] == B);
}
assert((outputs[1].desc.dims.d[1] == 2 * packedMaskSize384) ||
(outputs[1].desc.dims.d[1] == 2 * packedMaskSize128) ||
(outputs[1].desc.dims.d[1] == 2 * packedMaskSize256));
assert(outputs[0].desc.type == mType);
assert(outputs[1].desc.type == nvinfer1::DataType::kHALF);
}
size_t TrtPromptTuningEmbLayerNormVarSeqlenPluginBase::getWorkspaceSize(
nvinfer1::PluginTensorDesc const* inputs,
int32_t nbInputs,
nvinfer1::PluginTensorDesc const* outputs,
int32_t nbOutputs) const noexcept {
return 0;
}
int32_t TrtPromptTuningEmbLayerNormVarSeqlenPluginHFace::enqueue(
nvinfer1::PluginTensorDesc const* inputDesc,
nvinfer1::PluginTensorDesc const* outputDesc,
void const* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) noexcept {
int32_t batchSize = inputDesc[0].dims.d[0] - 1;
// read out the maximum sequence length from the dummy input
int32_t const maxSeqlen = inputDesc[nbLookupTables_].dims.d[1] + 1;
int32_t S;
if (maxSeqlen <= 128) {
S = 128;
} else if (maxSeqlen <= 192) {
S = 192;
} else if (maxSeqlen <= 256) {
S = 256;
} else if (maxSeqlen <= 384) {
S = 384;
} else if (maxSeqlen <= 512) {
S = 512;
} else {
PADDLE_THROW(common::errors::Fatal("The max seqlenth is 512."));
}
const float* beta = mBetaDev.get();
const float* gamma = mGammaDev.get();
auto output = static_cast<half*>(outputs[0]);
auto new_pos_id = static_cast<int32_t*>(outputs[4]);
return prompt_tuning_emb<half>(stream,
static_cast<int32_t>(mLd),
batchSize,
S,
static_cast<int32_t const*>(inputs[0]),
static_cast<int32_t const*>(inputs[1]),
static_cast<int32_t const*>(inputs[2]),
static_cast<half const*>(inputs[4]),
nbLookupTables_,
beta,
gamma,
static_cast<half const*>(mIdsEmbPtrs[0]),
static_cast<half const*>(mIdsEmbPtrs[1]),
static_cast<half const*>(mIdsEmbPtrs[2]),
mIdsVocabSize[0],
mIdsVocabSize[1],
mIdsVocabSize[2],
output,
new_pos_id);
}
// IPluginV2Ext Methods
nvinfer1::DataType
TrtPromptTuningEmbLayerNormVarSeqlenPluginBase::getOutputDataType(
int32_t index,
nvinfer1::DataType const* inputTypes,
int32_t nbInputs) const noexcept {
assert(mType == nvinfer1::DataType::kHALF);
if (index == 0) {
return mType;
} else if (index == 1) {
return mType;
} else if (index == 2) {
return mType;
} else if (index == 3) {
return mType;
} else if (index == 4) {
return nvinfer1::DataType::kINT32;
}
}
// IPluginV2 Methods
char const* TrtPromptTuningEmbLayerNormVarSeqlenPluginBase::getPluginType()
const noexcept {
return PTUNING_EMB_LAYER_NORM_VAR_SEQLEN_NAME;
}
char const* TrtPromptTuningEmbLayerNormVarSeqlenPluginHFace::getPluginVersion()
const noexcept {
return PTUNING_EMB_LAYER_NORM_VAR_SEQLEN_VERSION_HFACE;
}
int32_t TrtPromptTuningEmbLayerNormVarSeqlenPluginBase::getNbOutputs()
const noexcept {
return 5;
}
int32_t TrtPromptTuningEmbLayerNormVarSeqlenPluginHFace::initialize() noexcept {
TRANSFORMER_DEBUG_MSG(
"TrtPromptTuningEmbLayerNormVarSeqlenPluginHFace initialize");
return 0;
}
void TrtPromptTuningEmbLayerNormVarSeqlenPluginHFace::terminate() noexcept {
TRANSFORMER_DEBUG_MSG(
"TrtPromptTuningEmbLayerNormVarSeqlenPluginHFace terminate");
}
size_t TrtPromptTuningEmbLayerNormVarSeqlenPluginBase::getSerializationSize()
const noexcept {
size_t const wordSize = getElementSize(mType);
return 2 * sizeof(float) * mLd // beta + gamma
+ sizeof(mType) //
+ sizeof(mLd) //
+ mIdsVocabSize.size() * sizeof(mIdsVocabSize[0]) //
+ wordSize * mLd *
accumulate(
mIdsVocabSize.begin(), mIdsVocabSize.end(), 0) // ids emb
+ sizeof(nbLookupTables_); // numbers of lookup_table
}
void TrtPromptTuningEmbLayerNormVarSeqlenPluginBase::serialize(
void* buffer) const noexcept {
serialize_value(&buffer, mType);
serialize_value(&buffer, mLd);
serialize_value(&buffer, nbLookupTables_);
for (size_t i = 0; i < mIdsVocabSize.size(); ++i) {
serialize_value(&buffer, mIdsVocabSize[i]);
}
char* d = static_cast<char*>(buffer);
size_t const wordSize = getElementSize(mType);
serFromDev(&d, mBetaDev.get(), mLd);
serFromDev(&d, mGammaDev.get(), mLd);
for (size_t i = 0; i < mIdsEmbPtrs.size(); ++i) {
serFromDev(&d,
static_cast<char*>(mIdsEmbPtrs[i]),
mLd * mIdsVocabSize[i] * wordSize);
}
}
void TrtPromptTuningEmbLayerNormVarSeqlenPluginBase::destroy() noexcept {
// This gets called when the network containing plugin is destroyed
mBetaDev.reset(nullptr);
mGammaDev.reset(nullptr);
for (size_t i = 0; i < mIdsEmbPtrs.size(); ++i) {
cudaFree(mIdsEmbPtrs[i]);
}
delete this;
}
void TrtPromptTuningEmbLayerNormVarSeqlenPluginHFace::destroy() noexcept {
TRANSFORMER_DEBUG_MSG(
"TrtPromptTuningEmbLayerNormVarSeqlenPluginHFace destroy");
TrtPromptTuningEmbLayerNormVarSeqlenPluginBase::destroy();
}
void TrtPromptTuningEmbLayerNormVarSeqlenPluginBase::setPluginNamespace(
char const* libNamespace) noexcept {
mNamespace = libNamespace;
}
char const* TrtPromptTuningEmbLayerNormVarSeqlenPluginBase::getPluginNamespace()
const noexcept {
return mNamespace.c_str();
}
TrtPromptTuningEmbLayerNormVarSeqlenPluginBaseCreator::
TrtPromptTuningEmbLayerNormVarSeqlenPluginBaseCreator() = default;
char const*
TrtPromptTuningEmbLayerNormVarSeqlenPluginBaseCreator::getPluginName()
const noexcept {
return PTUNING_EMB_LAYER_NORM_VAR_SEQLEN_NAME;
}
char const*
TrtPromptTuningEmbLayerNormVarSeqlenPluginHFaceCreator::getPluginVersion()
const noexcept {
return PTUNING_EMB_LAYER_NORM_VAR_SEQLEN_VERSION_HFACE;
}
nvinfer1::PluginFieldCollection const*
TrtPromptTuningEmbLayerNormVarSeqlenPluginBaseCreator::
getFieldNames() noexcept {
return &mFC;
}
bool InitializeFields(nvinfer1::PluginFieldCollection const* fc,
nvinfer1::Weights* beta,
nvinfer1::Weights* gamma,
std::vector<nvinfer1::Weights>* IdsEmb) {
bool output_fp16 = false;
for (int32_t i = 0; i < fc->nbFields; i++) {
std::string field_name(fc->fields[i].name);
if (field_name.compare("bert_embeddings_layernorm_beta") == 0) {
TRANSFORMER_DEBUG_MSG("Building bert_embeddings_layernorm_beta...");
beta->values = fc->fields[i].data;
beta->count = fc->fields[i].length;
beta->type = fieldTypeToDataType(fc->fields[i].type);
}
if (field_name.compare("bert_embeddings_layernorm_gamma") == 0) {
TRANSFORMER_DEBUG_MSG("Building bert_embeddings_layernorm_gamma...");
gamma->values = fc->fields[i].data;
gamma->count = fc->fields[i].length;
gamma->type = fieldTypeToDataType(fc->fields[i].type);
}
if (field_name.compare("output_fp16") == 0) {
TRANSFORMER_DEBUG_MSG("Building output_fp16...");
assert(fc->fields[i].type == nvinfer1::PluginFieldType::kINT32);
output_fp16 = static_cast<int32_t const*>(fc->fields[i].data)[0] != 0;
}
if (field_name.compare("bert_embeddings_word_embeddings_" +
std::to_string(i - 3)) == 0) {
TRANSFORMER_DEBUG_MSG(
("bert_embeddings_word_embeddings_" + std::to_string(i - 3)).c_str());
nvinfer1::Weights tem;
tem.values = fc->fields[i].data;
tem.count = fc->fields[i].length;
tem.type = fieldTypeToDataType(fc->fields[i].type);
IdsEmb->push_back(tem);
}
}
return output_fp16;
}
nvinfer1::IPluginV2*
TrtPromptTuningEmbLayerNormVarSeqlenPluginHFaceCreator::createPlugin(
char const* name, nvinfer1::PluginFieldCollection const* fc) noexcept {
TRANSFORMER_DEBUG_MSG("PromptTuningEmbLayerNormVarSeqlenHFace createPlugin");
nvinfer1::Weights beta;
nvinfer1::Weights gamma;
std::vector<nvinfer1::Weights> IdsEmb;
bool output_fp16 = InitializeFields(fc, &beta, &gamma, &IdsEmb);
TRANSFORMER_DEBUG_MSG("Building the Plugin...");
TrtPromptTuningEmbLayerNormVarSeqlenPluginHFace* p =
new TrtPromptTuningEmbLayerNormVarSeqlenPluginHFace(
name,
output_fp16 ? nvinfer1::DataType::kHALF : nvinfer1::DataType::kFLOAT,
beta,
gamma,
IdsEmb);
return p;
}
nvinfer1::IPluginV2*
TrtPromptTuningEmbLayerNormVarSeqlenPluginHFaceCreator::deserializePlugin(
char const* name, void const* serialData, size_t serialLength) noexcept {
return new TrtPromptTuningEmbLayerNormVarSeqlenPluginHFace(
name, serialData, serialLength);
}
void TrtPromptTuningEmbLayerNormVarSeqlenPluginBaseCreator::setPluginNamespace(
char const* libNamespace) noexcept {
mNamespace = libNamespace;
}
char const*
TrtPromptTuningEmbLayerNormVarSeqlenPluginBaseCreator::getPluginNamespace()
const noexcept {
return mNamespace.c_str();
}
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,189 @@
// Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
// SPDX-FileCopyrightText: Copyright (c) 1993-2023 NVIDIA CORPORATION &
// AFFILIATES. 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.
#pragma once
#include <cuda.h>
#include "NvInferPlugin.h"
#include "NvInferRuntime.h"
#include "paddle/fluid/inference/tensorrt/plugin/common/bertCommon.h"
#include "paddle/fluid/inference/tensorrt/plugin/common/plugin.h"
#include "paddle/fluid/inference/tensorrt/plugin/common/serialize.h"
#include "paddle/fluid/inference/tensorrt/plugin/trt_plugin.h"
#include "paddle/fluid/platform/enforce.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
template <typename T>
int32_t prompt_tuning_emb(cudaStream_t,
int32_t,
int32_t,
int32_t,
int32_t const*,
int32_t const*,
int32_t const*,
T const*,
int32_t,
float const*,
float const*,
T const*,
T const*,
T const*,
int32_t,
int32_t,
int32_t,
T*,
int32_t*);
class TrtPromptTuningEmbLayerNormVarSeqlenPluginBase
: public nvinfer1::IPluginV2DynamicExt {
public:
TrtPromptTuningEmbLayerNormVarSeqlenPluginBase(
std::string const& name,
nvinfer1::DataType const type,
nvinfer1::Weights const& beta,
nvinfer1::Weights const& gamma,
const std::vector<nvinfer1::Weights>& ids_emb);
TrtPromptTuningEmbLayerNormVarSeqlenPluginBase(std::string const& name,
void const* data,
size_t length);
// It doesn't make sense to make TrtPromptTuningEmbLayerNormVarSeqlenPlugin
// without arguments, so we delete default constructor.
TrtPromptTuningEmbLayerNormVarSeqlenPluginBase() = delete;
// IPluginV2DynamicExt Methods
bool supportsFormatCombination(int32_t pos,
nvinfer1::PluginTensorDesc const* inOut,
int32_t nbInputs,
int32_t nbOutputs) noexcept override;
size_t getWorkspaceSize(nvinfer1::PluginTensorDesc const* inputs,
int32_t nbInputs,
nvinfer1::PluginTensorDesc const* outputs,
int32_t nbOutputs) const noexcept override;
// IPluginV2Ext Methods
nvinfer1::DataType getOutputDataType(
int32_t index,
nvinfer1::DataType const* inputTypes,
int32_t nbInputs) const noexcept override;
// IPluginV2 Methods
char const* getPluginType() const noexcept override;
int32_t getNbOutputs() const noexcept override;
size_t getSerializationSize() const noexcept override;
void serialize(void* buffer) const noexcept override;
void destroy() noexcept override;
char const* getPluginNamespace() const noexcept override;
void setPluginNamespace(char const* pluginNamespace) noexcept override;
protected:
std::string const mLayerName;
std::string mNamespace;
cuda_unique_ptr<float> mGammaDev;
cuda_unique_ptr<float> mBetaDev;
std::vector<void*> mIdsEmbPtrs;
size_t mLd; // leading dim = hidden size
std::vector<int32_t> mIdsVocabSize;
WeightsWithOwnership mBeta;
WeightsWithOwnership mGamma;
nvinfer1::DataType mType;
std::vector<nvinfer1::Weights> mIdsEmb_;
int32_t nbLookupTables_ = 0;
};
class TrtPromptTuningEmbLayerNormVarSeqlenPluginHFace
: public TrtPromptTuningEmbLayerNormVarSeqlenPluginBase {
public:
TrtPromptTuningEmbLayerNormVarSeqlenPluginHFace(
std::string const& name,
nvinfer1::DataType const type,
nvinfer1::Weights const& beta,
nvinfer1::Weights const& gamma,
const std::vector<nvinfer1::Weights>& ids_emb);
TrtPromptTuningEmbLayerNormVarSeqlenPluginHFace(std::string const& name,
void const* data,
size_t length);
// It doesn't make sense to make TrtPromptTuningEmbLayerNormVarSeqlenPlugin
// without arguments, so we delete default constructor.
TrtPromptTuningEmbLayerNormVarSeqlenPluginHFace() = delete;
// IPluginV2DynamicExt Methods
nvinfer1::IPluginV2DynamicExt* clone() const noexcept override;
nvinfer1::DimsExprs getOutputDimensions(
int32_t outputIndex,
const nvinfer1::DimsExprs* inputs,
int32_t nbInputs,
nvinfer1::IExprBuilder& exprBuilder) noexcept override;
void configurePlugin(nvinfer1::DynamicPluginTensorDesc const* in,
int32_t nbInputs,
nvinfer1::DynamicPluginTensorDesc const* out,
int32_t nbOutputs) noexcept override;
int32_t enqueue(nvinfer1::PluginTensorDesc const* inputDesc,
nvinfer1::PluginTensorDesc const* outputDesc,
void const* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) noexcept override;
// IPluginV2 Methods
int32_t initialize() noexcept override;
void terminate() noexcept override;
void destroy() noexcept override;
char const* getPluginVersion() const noexcept override;
};
class TrtPromptTuningEmbLayerNormVarSeqlenPluginBaseCreator
: public nvinfer1::IPluginCreator {
public:
TrtPromptTuningEmbLayerNormVarSeqlenPluginBaseCreator();
char const* getPluginName() const noexcept override;
const nvinfer1::PluginFieldCollection* getFieldNames() noexcept override;
void setPluginNamespace(char const* pluginNamespace) noexcept override;
char const* getPluginNamespace() const noexcept override;
protected:
static nvinfer1::PluginFieldCollection mFC;
static std::vector<nvinfer1::PluginField> mPluginAttributes;
std::string mNamespace;
};
class TrtPromptTuningEmbLayerNormVarSeqlenPluginHFaceCreator
: public TrtPromptTuningEmbLayerNormVarSeqlenPluginBaseCreator {
public:
nvinfer1::IPluginV2* createPlugin(
char const* name,
const nvinfer1::PluginFieldCollection* fc) noexcept override;
char const* getPluginVersion() const noexcept override;
nvinfer1::IPluginV2* deserializePlugin(char const* name,
void const* serialData,
size_t serialLength) noexcept override;
};
REGISTER_TRT_PLUGIN_V2(TrtPromptTuningEmbLayerNormVarSeqlenPluginHFaceCreator);
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,533 @@
// Copyright (c) 2018 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 <stdio.h>
#include <cassert>
#include <cub/cub.cuh> // NOLINT
#include <vector>
#include "glog/logging.h"
#include "paddle/fluid/framework/tensor.h"
#include "paddle/fluid/framework/tensor_util.h"
#include "paddle/fluid/inference/tensorrt/plugin/common/common.cuh"
#include "paddle/fluid/inference/tensorrt/plugin/qkv_to_context_plugin.h"
#include "paddle/fluid/inference/tensorrt/plugin/trt_plugin_utils.h"
#include "paddle/phi/core/platform/device_context.h"
#include "paddle/phi/kernels/funcs/blas/blas.h"
#include "paddle/phi/kernels/funcs/multihead_matmul_functor.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
inline int round_up(int seq_len, int multiple = 32) {
PADDLE_ENFORCE_GT(
multiple,
0,
common::errors::InvalidArgument(
"multiple should be a positive number, but it's (%d)", multiple));
return ((seq_len + multiple - 1) / multiple) * multiple;
}
template <typename T>
__global__ void reset_qk_bias(T *input, int real_seq_len, int seq_len) {
if (threadIdx.x < seq_len) {
int id = threadIdx.x + blockIdx.x * seq_len;
input[id] = threadIdx.x >= real_seq_len ? (T)0.0f : (T)1.0f;
}
}
template <typename T>
__global__ void transpose_qkv_padding(
const T *src, // (Batch, real_seq_len, 3 , head_num * size_per_head)
T *dst, // (3 * batch * head_num * seq_len * size_per_head)
const int batch_size,
const int seq_len,
const int head_num,
const int size_per_head,
const int real_seq_len) {
// const dim3 grid(seq_len, batch, 3);
// const dim3 block(head_size, head_num, 1);
int qkv_id = blockIdx.z;
int batch_id = blockIdx.y;
int seq_id = blockIdx.x;
int head_id = threadIdx.y;
const int dst_offset =
qkv_id * batch_size * head_num * seq_len * size_per_head +
batch_id * head_num * seq_len * size_per_head +
head_id * seq_len * size_per_head + seq_id * size_per_head;
const int src_offset =
batch_id * real_seq_len * 3 * head_num * size_per_head +
seq_id * 3 * head_num * size_per_head +
qkv_id * head_num * size_per_head + head_id * size_per_head;
if (seq_id < real_seq_len) {
dst[threadIdx.x + dst_offset] = src[threadIdx.x + src_offset];
}
}
template <typename T>
__global__ void transpose_qkv_unpadding(const T *src,
T *dst,
const int batch_size,
const int seq_len,
const int head_num,
const int size_per_head,
const int real_seq_len) {
int batch_id = blockIdx.y;
int seq_id = blockIdx.x;
int head_id = threadIdx.y;
const int src_offset = batch_id * head_num * seq_len * size_per_head +
head_id * seq_len * size_per_head +
seq_id * size_per_head;
const int dst_offset = batch_id * real_seq_len * head_num * size_per_head +
seq_id * head_num * size_per_head +
head_id * size_per_head;
dst[threadIdx.x + dst_offset] = src[threadIdx.x + src_offset];
}
#define LAUNCH_TRANSPOSE_KERNEL(TYPE, VECTOR_SIZE, PAD_TYPE) \
do { \
int h = head_size / VECTOR_SIZE; \
const TYPE *input##VECTOR_SIZE = reinterpret_cast<const TYPE *>(input); \
TYPE *output##VECTOR_SIZE = reinterpret_cast<TYPE *>(output); \
dim3 block(h, head_num, 1); \
transpose_qkv_##PAD_TYPE<TYPE> \
<<<grid, block, 0, stream>>>(input##VECTOR_SIZE, \
output##VECTOR_SIZE, \
batch, \
seq_len, \
head_num, \
h, \
real_seq_len); \
} while (0)
inline void TransposePadding(const half *input,
half *output,
const int batch,
const int seq_len,
const int head_num,
const int head_size,
const int real_seq_len,
cudaStream_t stream) {
const dim3 grid(seq_len, batch, 3);
if (head_size % 8 == 0) {
LAUNCH_TRANSPOSE_KERNEL(int4, 8, padding);
} else if (head_size % 2 == 0) {
LAUNCH_TRANSPOSE_KERNEL(half2, 2, padding);
} else {
LAUNCH_TRANSPOSE_KERNEL(half, 1, padding);
}
}
inline void TransposeUnPadding(const half *input,
half *output,
const int batch,
const int seq_len,
const int head_num,
const int head_size,
const int real_seq_len,
cudaStream_t stream) {
const dim3 grid(real_seq_len, batch);
if (head_size % 8 == 0) {
LAUNCH_TRANSPOSE_KERNEL(int4, 8, unpadding);
} else if (head_size % 2 == 0) {
LAUNCH_TRANSPOSE_KERNEL(half2, 2, unpadding);
} else {
LAUNCH_TRANSPOSE_KERNEL(half, 1, unpadding);
}
}
int QkvToContextPluginDynamic::initialize() TRT_NOEXCEPT { return 0; }
nvinfer1::DimsExprs QkvToContextPluginDynamic::getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs *inputs,
int nb_inputs,
nvinfer1::IExprBuilder &expr_builder) TRT_NOEXCEPT {
// input[0], (B, S, 3 * N * H, 1, 1)
// input[1], (B, head_num, seq_len, seq_len)
// output, (B, seq_len, hidden)
PADDLE_ENFORCE_EQ(output_index,
0,
common::errors::InvalidArgument(
"There is only one output of the EmbEltwiseLayernorm, "
"so the index should be zero,"
"but it's (%d)",
output_index));
PADDLE_ENFORCE_EQ(
nb_inputs,
2,
common::errors::InvalidArgument(
"The Input of the EmbEltwiseLayernorm should be 3, but we found "
"it has (%d) inputs",
nb_inputs));
nvinfer1::DimsExprs ret;
ret.nbDims = 3;
ret.d[0] = inputs[0].d[0];
ret.d[1] = inputs[0].d[1];
ret.d[2] = expr_builder.constant(head_size_ * head_number_);
return ret;
}
void QkvToContextPluginDynamic::configurePlugin(
const nvinfer1::DynamicPluginTensorDesc *in,
int nb_inputs,
const nvinfer1::DynamicPluginTensorDesc *out,
int nb_outputs) TRT_NOEXCEPT {
auto input_dims = in[0].desc.dims;
int batch = input_dims.d[0];
int real_seq_len = input_dims.d[1];
int seq_len = round_up(real_seq_len, 8);
if (batch != -1 && real_seq_len != -1) {
int device_id = 0;
cudaGetDevice(&device_id);
auto *device_ctx = static_cast<phi::GPUContext *>(
phi::DeviceContextPool::Instance().Get(GPUPlace(device_id)));
const phi::GPUContext &dev_ctx = *device_ctx;
auto stream = dev_ctx.stream();
tensor_.Resize({batch, seq_len, seq_len, head_number_});
if (in[0].desc.type == nvinfer1::DataType::kHALF) {
tensor_.Resize({batch, seq_len, seq_len, 1});
int blocks = batch * 1 * seq_len;
mask_half_ = reinterpret_cast<half *>(
tensor_.mutable_data<int16_t>(GPUPlace(device_id)));
reset_qk_bias<<<blocks, 1024, 0, stream>>>(
mask_half_, real_seq_len, seq_len);
} else if (in[0].desc.type == nvinfer1::DataType::kFLOAT) {
fake_qk_bias_ = reinterpret_cast<float *>(
tensor_.mutable_data<int32_t>(GPUPlace(device_id)));
int64_t size = sizeof(int32_t) * batch * seq_len * seq_len * head_number_;
#ifdef PADDLE_WITH_HIP
PADDLE_ENFORCE_GPU_SUCCESS(
hipMemsetAsync(fake_qk_bias_, 0, size, dev_ctx.stream()));
#else
PADDLE_ENFORCE_GPU_SUCCESS(
cudaMemsetAsync(fake_qk_bias_, 0, size, dev_ctx.stream()));
#endif
} else {
PADDLE_THROW(common::errors::Fatal(
"The QKV TRT Plugin's input type should be float or half."));
}
}
}
bool QkvToContextPluginDynamic::supportsFormatCombination(
int pos,
const nvinfer1::PluginTensorDesc *in_out,
int nb_inputs,
int nb_outputs) TRT_NOEXCEPT {
PADDLE_ENFORCE_NOT_NULL(
in_out,
common::errors::InvalidArgument(
"The input of swish plugin should not be nullptr."));
PADDLE_ENFORCE_LT(
pos,
nb_inputs + nb_outputs,
common::errors::InvalidArgument("The pos(%d) should be less than the "
"num(%d) of the input and the output.",
pos,
nb_inputs + nb_outputs));
const nvinfer1::PluginTensorDesc &in = in_out[pos];
if (pos == 0) {
if (with_fp16_) {
return (in.type == nvinfer1::DataType::kFLOAT ||
in.type == nvinfer1::DataType::kHALF) &&
(in.format == nvinfer1::TensorFormat::kLINEAR);
} else {
return (in.type == nvinfer1::DataType::kFLOAT) &&
(in.format == nvinfer1::TensorFormat::kLINEAR);
}
}
const nvinfer1::PluginTensorDesc &prev = in_out[pos - 1];
if (pos == 1) {
return in.type == prev.type && in.format == prev.format;
}
// output
return in.type == prev.type && in.format == prev.format;
}
nvinfer1::DataType QkvToContextPluginDynamic::getOutputDataType(
int index,
const nvinfer1::DataType *input_types,
int nb_inputs) const TRT_NOEXCEPT {
PADDLE_ENFORCE_EQ(
index,
0,
common::errors::InvalidArgument(
"The EmbEltwiseLayernorm Plugin only has one input, so the "
"index value should be 0, but get %d.",
index));
return input_types[0];
}
template <typename T>
__global__ void apply_scale(T *data, T scale, int n) {
#if CUDA_ARCH_FP16_SUPPORTED(__CUDA_ARCH__)
int tid = blockIdx.x * blockDim.x + threadIdx.x;
if (tid < n) {
data[tid] = data[tid] * scale;
}
#endif
}
template <typename T>
__global__ void broadcast(const T *src,
T *dst,
const int seq_len,
const int head_num) {
int batch_id = blockIdx.x / (head_num * seq_len);
int dst_offset = blockIdx.x * seq_len;
if (threadIdx.x < seq_len) {
dst[threadIdx.x + dst_offset] = src[threadIdx.x + batch_id * seq_len];
}
}
template <typename T>
__global__ void broadcast_batch_head_number(const T *src,
T *dst,
const int batch_size,
const int seq_len,
const int head_num) {
int batch_id = blockIdx.x % seq_len;
int dst_offset = blockIdx.x * seq_len;
if (threadIdx.x < seq_len) {
dst[threadIdx.x + dst_offset] = src[threadIdx.x + batch_id * seq_len];
}
}
int QkvToContextPluginDynamic::enqueue(
const nvinfer1::PluginTensorDesc *input_desc,
const nvinfer1::PluginTensorDesc *output_desc,
const void *const *inputs,
void *const *outputs,
void *workspace,
cudaStream_t stream) TRT_NOEXCEPT {
auto input_dims = input_desc[0].dims;
int input_num = ProductDim(input_dims);
// input[0], (B, S, 3 * N * H, 1, 1)
int batch = input_dims.d[0];
int seq_len = input_dims.d[1];
phi::DenseTensor multihead_temp_tensor;
int scratch_size = batch * head_number_ * seq_len * seq_len * 1;
int device_id;
cudaGetDevice(&device_id);
multihead_temp_tensor.Resize({scratch_size + input_num});
auto input_type = input_desc[0].type;
if (input_type == nvinfer1::DataType::kFLOAT) {
VLOG(1) << "TRT Plugin DataType selected. QkvToContext-->fp32";
auto *multihead_temp_data =
multihead_temp_tensor.mutable_data<float>(GPUPlace(device_id));
auto *qkptr = multihead_temp_data;
auto *tptr = multihead_temp_data + scratch_size;
const float *input0_data = static_cast<const float *>(inputs[0]);
// fit to [batch, head_num, length, length] + [batch, 1, 1, length]
phi::DenseTensor temp_qk_bias_tensor;
float *qk_bias = const_cast<float *>(static_cast<const float *>(inputs[1]));
if (ProductDim(input_desc[1].dims) == (batch * seq_len)) {
temp_qk_bias_tensor.Resize({batch, head_number_, seq_len, seq_len});
auto *temp_qk_bias =
temp_qk_bias_tensor.mutable_data<float>(GPUPlace(device_id));
int grid = batch * head_number_ * seq_len;
int block = round_up(seq_len);
broadcast<<<grid, block, 0, stream>>>(
static_cast<const float *>(inputs[1]),
temp_qk_bias,
seq_len,
head_number_);
qk_bias = temp_qk_bias;
}
// fit to [batch, head_num, length, length] + [1, 1, length, length]
if (ProductDim(input_desc[1].dims) == (seq_len * seq_len)) {
temp_qk_bias_tensor.Resize({batch, head_number_, seq_len, seq_len});
auto *temp_qk_bias = reinterpret_cast<float *>(
temp_qk_bias_tensor.mutable_data<float>(GPUPlace(device_id)));
int grid = batch * head_number_ * seq_len;
int block = round_up(seq_len);
broadcast_batch_head_number<<<grid, block, 0, stream>>>(
static_cast<const float *>(inputs[1]),
temp_qk_bias,
batch,
seq_len,
head_number_);
qk_bias = temp_qk_bias;
}
// fake qk_bias
if (ProductDim(input_desc[1].dims) == ProductDim(input_desc[0].dims)) {
qk_bias = fake_qk_bias_;
}
const float *input1_data = static_cast<const float *>(qk_bias);
// BxSx3xNxH => tptr: 3xBxNxSxH.
TransposeQKV(
batch, seq_len, head_size_, head_number_, input0_data, tptr, stream);
auto *device_ctx = static_cast<phi::GPUContext *>(
phi::DeviceContextPool::Instance().Get(GPUPlace(device_id)));
const phi::GPUContext &dev_ctx = *device_ctx;
phi::funcs::MultiheadGPUComputeFunctor<float> multihead_compute_func;
multihead_compute_func(dev_ctx,
batch,
seq_len,
head_number_,
head_size_,
qkptr,
input1_data,
false,
tptr,
scale_,
static_cast<float>(0.0));
int grid = batch * head_number_ * seq_len;
int block = head_size_;
float *output = static_cast<float *>(outputs[0]);
transpose<float><<<grid, block, 0, stream>>>(
tptr, output, batch, seq_len, head_number_, head_size_);
} else if (input_type == nvinfer1::DataType::kHALF) {
VLOG(1) << "TRT Plugin DataType selected. QkvToContext-->fp16";
int real_seq_len = seq_len;
int need_padding = false;
// fake qk_bias
if (ProductDim(input_desc[1].dims) == ProductDim(input_desc[0].dims)) {
seq_len = round_up(real_seq_len, 8);
scratch_size = batch * head_number_ * seq_len * seq_len * 1;
input_num = batch * seq_len * 3 * head_number_ * head_size_;
multihead_temp_tensor.Resize({scratch_size + input_num});
need_padding = (real_seq_len != seq_len) ? true : false;
}
auto *multihead_temp_data =
multihead_temp_tensor.mutable_data<int16_t>( // NOLINT
GPUPlace(device_id));
half *qkptr = reinterpret_cast<half *>(multihead_temp_data);
half *tptr = qkptr + scratch_size;
const half *input0_data = static_cast<const half *>(inputs[0]);
// fit to [batch, head_num, length, length] + [batch, 1, 1, length]
phi::DenseTensor temp_qk_bias_tensor;
half *qk_bias = const_cast<half *>(static_cast<const half *>(inputs[1]));
if (ProductDim(input_desc[1].dims) == (batch * seq_len)) {
temp_qk_bias_tensor.Resize({batch, head_number_, seq_len, seq_len});
auto *temp_qk_bias = reinterpret_cast<half *>(
temp_qk_bias_tensor.mutable_data<int16_t>(GPUPlace(device_id)));
int grid = batch * head_number_ * seq_len;
int block = round_up(seq_len);
broadcast<<<grid, block, 0, stream>>>(
static_cast<const half *>(inputs[1]),
temp_qk_bias,
seq_len,
head_number_);
qk_bias = temp_qk_bias;
}
// fit to [batch, head_num, length, length] + [1, 1, length, length]
if (ProductDim(input_desc[1].dims) == (seq_len * seq_len)) {
temp_qk_bias_tensor.Resize({batch, head_number_, seq_len, seq_len});
auto *temp_qk_bias = reinterpret_cast<half *>(
temp_qk_bias_tensor.mutable_data<int16_t>(GPUPlace(device_id)));
int grid = batch * head_number_ * seq_len;
int block = round_up(seq_len);
broadcast_batch_head_number<<<grid, block, 0, stream>>>(
static_cast<const half *>(inputs[1]),
temp_qk_bias,
batch,
seq_len,
head_number_);
qk_bias = temp_qk_bias;
}
// padding: mask_half_ = [1.0,....1.0...1.0....,0.0f]
// no_padding: mask_half_ = [1.0,....1.0,.........,1.0f]
bool bias_is_mask = false;
if (ProductDim(input_desc[1].dims) == ProductDim(input_desc[0].dims)) {
qk_bias = mask_half_;
bias_is_mask = true;
}
const half *input1_data = static_cast<const half *>(qk_bias);
// BxSx3xNxH => tptr: 3xBxNxSxH.
if (need_padding) {
PADDLE_ENFORCE_GPU_SUCCESS(
cudaMemsetAsync(tptr, 0, sizeof(half) * input_num, stream));
TransposePadding(input0_data,
tptr,
batch,
seq_len,
head_number_,
head_size_,
real_seq_len,
stream);
} else {
TransposeQKV(
batch, seq_len, head_size_, head_number_, input0_data, tptr, stream);
}
auto *device_ctx = static_cast<phi::GPUContext *>(
phi::DeviceContextPool::Instance().Get(GPUPlace(device_id)));
int n_q = seq_len * head_number_ * head_size_ * batch;
constexpr int threads = 128;
int blocks = (n_q + threads - 1) / threads;
apply_scale<<<blocks, threads, 0, stream>>>(
tptr, static_cast<half>(scale_), n_q);
const phi::GPUContext &dev_ctx = *device_ctx;
phi::funcs::MultiheadGPUComputeFunctor<half> multihead_compute_func;
multihead_compute_func(dev_ctx,
batch,
seq_len,
head_number_,
head_size_,
qkptr,
input1_data,
bias_is_mask,
tptr,
half(1.),
half(0.0));
int grid = batch * head_number_ * seq_len;
int block = head_size_;
half *output = static_cast<half *>(outputs[0]);
if (need_padding) {
TransposeUnPadding(tptr,
output,
batch,
seq_len,
head_number_,
head_size_,
real_seq_len,
stream);
} else {
transpose<half><<<grid, block, 0, stream>>>(
tptr, output, batch, seq_len, head_number_, head_size_);
}
} else {
PADDLE_THROW(common::errors::Fatal(
"The QKV TRT Plugin's input type should be float or half."));
}
return cudaGetLastError() != cudaSuccess;
}
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,178 @@
// Copyright (c) 2020 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.
// Copyright (c) 2018 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.
#pragma once
#include <algorithm>
#include <string>
#include <vector>
#include "paddle/fluid/inference/tensorrt/engine.h"
#include "paddle/fluid/inference/tensorrt/plugin/trt_plugin.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
class QkvToContextPluginDynamic : public DynamicPluginTensorRT {
public:
explicit QkvToContextPluginDynamic(
int hidden, int head_number, int head_size, float scale, bool with_fp16)
: hidden_(hidden),
head_number_(head_number),
head_size_(head_size),
scale_(scale) {
with_fp16_ = with_fp16;
}
QkvToContextPluginDynamic(void const* serial_data, size_t serial_length) {
DeserializeValue(&serial_data, &serial_length, &hidden_);
DeserializeValue(&serial_data, &serial_length, &head_number_);
DeserializeValue(&serial_data, &serial_length, &head_size_);
DeserializeValue(&serial_data, &serial_length, &scale_);
DeserializeValue(&serial_data, &serial_length, &with_fp16_);
}
nvinfer1::IPluginV2DynamicExt* clone() const TRT_NOEXCEPT override {
return new QkvToContextPluginDynamic(
hidden_, head_number_, head_size_, scale_, with_fp16_);
}
const char* getPluginType() const TRT_NOEXCEPT override {
return "qkv_to_context_plugin";
}
int getNbOutputs() const TRT_NOEXCEPT override { return 1; }
int initialize() TRT_NOEXCEPT override;
size_t getSerializationSize() const TRT_NOEXCEPT override {
return SerializedSize(hidden_) + SerializedSize(head_number_) +
SerializedSize(head_size_) + SerializedSize(scale_) +
SerializedSize(with_fp16_);
}
void serialize(void* buffer) const TRT_NOEXCEPT override {
SerializeValue(&buffer, hidden_);
SerializeValue(&buffer, head_number_);
SerializeValue(&buffer, head_size_);
SerializeValue(&buffer, scale_);
SerializeValue(&buffer, with_fp16_);
}
nvinfer1::DimsExprs getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs* inputs,
int nb_inputs,
nvinfer1::IExprBuilder& expr_builder) // NOLINT
TRT_NOEXCEPT override;
bool supportsFormatCombination(int pos,
const nvinfer1::PluginTensorDesc* in_out,
int nb_inputs,
int nb_outputs) TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::DynamicPluginTensorDesc* in,
int nb_inputs,
const nvinfer1::DynamicPluginTensorDesc* out,
int nb_outputs) TRT_NOEXCEPT override;
size_t getWorkspaceSize(const nvinfer1::PluginTensorDesc* inputs,
int nb_inputs,
const nvinfer1::PluginTensorDesc* outputs,
int nb_outputs) const TRT_NOEXCEPT override {
return 0;
}
int enqueue(const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* input_types,
int nb_inputs) const
TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override { delete this; }
private:
int hidden_;
int head_number_;
int head_size_;
float scale_;
phi::DenseTensor tensor_;
half* mask_half_;
float* fake_qk_bias_;
};
class QkvToContextPluginDynamicCreator : public nvinfer1::IPluginCreator {
public:
QkvToContextPluginDynamicCreator() {}
const char* getPluginName() const TRT_NOEXCEPT override {
return "qkv_to_context_plugin";
}
const char* getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
const nvinfer1::PluginFieldCollection* getFieldNames() TRT_NOEXCEPT override {
return &field_collection_;
}
nvinfer1::IPluginV2* createPlugin(const char* name,
const nvinfer1::PluginFieldCollection* fc)
TRT_NOEXCEPT override {
return nullptr;
}
nvinfer1::IPluginV2* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override {
auto plugin = new QkvToContextPluginDynamic(serial_data, serial_length);
return plugin;
}
void setPluginNamespace(const char* lib_namespace) TRT_NOEXCEPT override {
plugin_namespace_ = lib_namespace;
}
const char* getPluginNamespace() const TRT_NOEXCEPT override {
return plugin_namespace_.c_str();
}
private:
std::string plugin_namespace_;
std::string plugin_name_;
nvinfer1::PluginFieldCollection field_collection_;
std::vector<nvinfer1::PluginField> plugin_attributes_;
};
REGISTER_TRT_PLUGIN_V2(QkvToContextPluginDynamicCreator);
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,162 @@
/* Copyright (c) 2022 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/plugin/recover_padding_plugin.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
__global__ void RecoverPaddingKernel(const half* input0,
const int32_t* input1,
half* output) {
int word_id = blockIdx.x * gridDim.y + blockIdx.y;
int32_t sequence_length = input1[blockIdx.x + 1] - input1[blockIdx.x];
if (blockIdx.y < sequence_length) {
output[word_id * gridDim.z * blockDim.x + blockIdx.z * blockDim.x +
threadIdx.x] =
input0[(input1[blockIdx.x] + blockIdx.y) * gridDim.z * blockDim.x +
blockIdx.z * blockDim.x + threadIdx.x];
} else {
output[word_id * gridDim.z * blockDim.x + blockIdx.z * blockDim.x +
threadIdx.x] = 0;
}
}
nvinfer1::DataType RecoverPaddingPlugin::getOutputDataType(
int index,
const nvinfer1::DataType* input_types,
int nb_inputs) const TRT_NOEXCEPT {
return input_types[0];
}
nvinfer1::DimsExprs RecoverPaddingPlugin::getOutputDimensions(
int outputIndex,
const nvinfer1::DimsExprs* inputs,
int nbInputs,
nvinfer1::IExprBuilder& exprBuilder) TRT_NOEXCEPT {
nvinfer1::DimsExprs output_dims{};
output_dims.nbDims = 3;
const auto* one = exprBuilder.constant(1);
output_dims.d[0] = exprBuilder.operation(
nvinfer1::DimensionOperation::kSUB, *inputs[1].d[0], *one);
output_dims.d[1] = inputs[2].d[1];
output_dims.d[2] = inputs[0].d[1];
return output_dims;
}
bool RecoverPaddingPlugin::supportsFormatCombination(
int pos,
const nvinfer1::PluginTensorDesc* inOut,
int nbInputs,
int nbOutputs) TRT_NOEXCEPT {
PADDLE_ENFORCE_EQ(nbInputs,
3,
common::errors::InvalidArgument("Must have 3 inputs, "
"but got %d input(s). ",
nbInputs));
PADDLE_ENFORCE_EQ(nbOutputs,
getNbOutputs(),
common::errors::InvalidArgument("Must have 1 output, "
"but got %d output(s). ",
nbOutputs));
if (pos == 1) { // PosId
return inOut[pos].type == nvinfer1::DataType::kINT32 &&
inOut[pos].format == nvinfer1::TensorFormat::kLINEAR;
} else if (pos == 2) { // mask_id
return inOut[pos].type == nvinfer1::DataType::kFLOAT &&
inOut[pos].format == nvinfer1::TensorFormat::kLINEAR;
} else {
return inOut[pos].type == nvinfer1::DataType::kHALF &&
inOut[pos].format == nvinfer1::TensorFormat::kLINEAR;
}
// return (inOut[pos].type == nvinfer1::DataType::kFLOAT && inOut[pos].format
// == nvinfer1::TensorFormat::kLINEAR)||
// (inOut[pos].type == nvinfer1::DataType::kHALF && inOut[pos].format ==
// nvinfer1::TensorFormat::kLINEAR)||
// (inOut[pos].type == nvinfer1::DataType::kINT8 && inOut[pos].format ==
// nvinfer1::TensorFormat::kCHW32);
}
void RecoverPaddingPlugin::configurePlugin(
const nvinfer1::DynamicPluginTensorDesc* inputs,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc* outputs,
int nbOutputs) TRT_NOEXCEPT {}
void RecoverPaddingPlugin::attachToContext(
cudnnContext* cudnnContext,
cublasContext* cublasContext,
nvinfer1::IGpuAllocator* gpuAllocator) TRT_NOEXCEPT {}
void RecoverPaddingPlugin::detachFromContext() TRT_NOEXCEPT {}
void RecoverPaddingPlugin::terminate() TRT_NOEXCEPT {}
int RecoverPaddingPlugin::enqueue(const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT {
const auto input0_desc = inputDesc[0];
const auto input1_desc = inputDesc[1];
const auto input2_desc = inputDesc[2];
const half* input0 = static_cast<const half*>(inputs[0]);
const int32_t* input1 =
static_cast<const int32_t*>(inputs[1]); // pos_id_tensor
half* output = static_cast<half*>(outputs[0]);
const int32_t vector_length = input0_desc.dims.d[1];
int32_t num_threads;
if (vector_length < 1024) {
num_threads = vector_length;
} else {
if (vector_length % 512 == 0) {
num_threads = 512;
} else if (vector_length % 256 == 0) {
num_threads = 256;
} else if (vector_length % 128 == 0) {
num_threads = 128;
} else if (vector_length % 64 == 0) {
num_threads = 64;
} else if (vector_length % 32 == 0) {
num_threads = 32;
} else if (vector_length % 16 == 0) {
num_threads = 16;
} else if (vector_length % 8 == 0) {
num_threads = 8;
} else if (vector_length % 4 == 0) {
num_threads = 4;
} else if (vector_length % 2 == 0) {
num_threads = 2;
} else {
num_threads = 1;
}
}
const dim3 num_blocks(
input1_desc.dims.d[0] - 1,
input2_desc.dims.d[1],
vector_length / num_threads); // batches, max sequence length
// (mask_id.dims.d[1]),
// input.dims.d[1]/***
RecoverPaddingKernel<<<num_blocks, num_threads, 0, stream>>>(
input0, input1, output);
return cudaGetLastError() != cudaSuccess;
}
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,141 @@
/* Copyright (c) 2022 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. */
#pragma once
#include <cassert>
#include <string>
#include "paddle/fluid/inference/tensorrt/plugin/trt_plugin.h"
#include "paddle/fluid/platform/enforce.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
class RecoverPaddingPlugin : public DynamicPluginTensorRT {
public:
RecoverPaddingPlugin() {}
RecoverPaddingPlugin(void const* serial_data, size_t serial_length) {}
nvinfer1::IPluginV2DynamicExt* clone() const TRT_NOEXCEPT override {
RecoverPaddingPlugin* ptr = new RecoverPaddingPlugin();
return ptr;
}
const char* getPluginType() const TRT_NOEXCEPT override {
return "recover_padding_plugin";
}
int getNbOutputs() const TRT_NOEXCEPT override { return 1; }
int initialize() TRT_NOEXCEPT { return 0; }
void terminate() TRT_NOEXCEPT;
nvinfer1::DimsExprs getOutputDimensions(
int outputIndex,
const nvinfer1::DimsExprs* inputs,
int nbInputs,
nvinfer1::IExprBuilder& exprBuilder) // NOLINT
TRT_NOEXCEPT override;
bool supportsFormatCombination(int pos,
const nvinfer1::PluginTensorDesc* inOut,
int nbInputs,
int nbOutputs) TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::DynamicPluginTensorDesc* inputs,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc* outputs,
int nbOutputs) TRT_NOEXCEPT override;
size_t getWorkspaceSize(const nvinfer1::PluginTensorDesc* inputs,
int nbInputs,
const nvinfer1::PluginTensorDesc* outputs,
int nbOutputs) const TRT_NOEXCEPT override {
return 0;
}
void attachToContext(cudnnContext* cudnnContext,
cublasContext* cublasContext,
nvinfer1::IGpuAllocator* gpuAllocator)
TRT_NOEXCEPT override;
void detachFromContext() TRT_NOEXCEPT override;
int enqueue(const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* inputTypes,
int nbInputs) const
TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override { delete this; }
protected:
size_t getSerializationSize() const TRT_NOEXCEPT override { return 0; }
void serialize(void* buffer) const TRT_NOEXCEPT override {}
};
class RecoverPaddingPluginCreator : public nvinfer1::IPluginCreator {
public:
RecoverPaddingPluginCreator() {}
const char* getPluginName() const TRT_NOEXCEPT override {
return "recover_padding_plugin";
}
const char* getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
const nvinfer1::PluginFieldCollection* getFieldNames() TRT_NOEXCEPT override {
return &field_collection_;
}
nvinfer1::IPluginV2* createPlugin(
const char* name, const nvinfer1::PluginFieldCollection* plugin_field)
TRT_NOEXCEPT override {
return nullptr;
}
nvinfer1::IPluginV2* deserializePlugin(const char* name,
void const* serial_data,
size_t serial_length)
TRT_NOEXCEPT override {
RecoverPaddingPlugin* obj =
new RecoverPaddingPlugin(serial_data, serial_length);
obj->setPluginNamespace(name);
return obj;
}
void setPluginNamespace(const char* lib_namespace) TRT_NOEXCEPT override {
plugin_namespace_ = lib_namespace;
}
const char* getPluginNamespace() const TRT_NOEXCEPT override {
return plugin_namespace_.c_str();
}
private:
std::string plugin_namespace_;
std::string plugin_name_;
nvinfer1::PluginFieldCollection field_collection_{0, nullptr};
};
REGISTER_TRT_PLUGIN_V2(RecoverPaddingPluginCreator);
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,154 @@
/* Copyright (c) 2022 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/plugin/remove_padding_plugin.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
__global__ void RemovePaddingKernel(const half* input0,
const int32_t* input1,
half* output) {
int word_id = blockIdx.x * gridDim.y + blockIdx.y;
int32_t sequence_length = input1[blockIdx.x + 1] - input1[blockIdx.x];
if (blockIdx.y < sequence_length) {
output[(input1[blockIdx.x] + blockIdx.y) * gridDim.z * blockDim.x +
blockIdx.z * blockDim.x + threadIdx.x] =
input0[word_id * gridDim.z * blockDim.x + blockIdx.z * blockDim.x +
threadIdx.x];
}
}
nvinfer1::DataType RemovePaddingPlugin::getOutputDataType(
int index,
const nvinfer1::DataType* input_types,
int nb_inputs) const TRT_NOEXCEPT {
return input_types[0];
}
nvinfer1::DimsExprs RemovePaddingPlugin::getOutputDimensions(
int outputIndex,
const nvinfer1::DimsExprs* inputs,
int nbInputs,
nvinfer1::IExprBuilder& exprBuilder) TRT_NOEXCEPT {
nvinfer1::DimsExprs output_dims{};
output_dims.nbDims = 4;
output_dims.d[0] = inputs[2].d[0];
output_dims.d[1] = inputs[0].d[2];
output_dims.d[2] = exprBuilder.constant(1);
output_dims.d[3] = exprBuilder.constant(1);
return output_dims;
}
bool RemovePaddingPlugin::supportsFormatCombination(
int pos,
const nvinfer1::PluginTensorDesc* inOut,
int nbInputs,
int nbOutputs) TRT_NOEXCEPT {
PADDLE_ENFORCE_EQ(nbInputs,
3,
common::errors::InvalidArgument("Must have 3 inputs, "
"but got %d input(s). ",
nbInputs));
PADDLE_ENFORCE_EQ(nbOutputs,
getNbOutputs(),
common::errors::InvalidArgument("Must have 1 output, "
"but got %d output(s). ",
nbOutputs));
if (pos == 1 || pos == 2) { // pos_id, work_id
return inOut[pos].type == nvinfer1::DataType::kINT32 &&
inOut[pos].format == nvinfer1::TensorFormat::kLINEAR;
} else {
return inOut[pos].type == nvinfer1::DataType::kHALF &&
inOut[pos].format == nvinfer1::TensorFormat::kLINEAR;
}
// return (inOut[pos].type == nvinfer1::DataType::kFLOAT && inOut[pos].format
// == nvinfer1::TensorFormat::kLINEAR)||
// (inOut[pos].type == nvinfer1::DataType::kHALF && inOut[pos].format ==
// nvinfer1::TensorFormat::kLINEAR)||
// (inOut[pos].type == nvinfer1::DataType::kINT8 && inOut[pos].format ==
// nvinfer1::TensorFormat::kCHW32);
}
void RemovePaddingPlugin::configurePlugin(
const nvinfer1::DynamicPluginTensorDesc* inputs,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc* outputs,
int nbOutputs) TRT_NOEXCEPT {}
void RemovePaddingPlugin::attachToContext(cudnnContext* cudnnContext,
cublasContext* cublasContext,
nvinfer1::IGpuAllocator* gpuAllocator)
TRT_NOEXCEPT {}
void RemovePaddingPlugin::detachFromContext() TRT_NOEXCEPT {}
void RemovePaddingPlugin::terminate() TRT_NOEXCEPT {}
int RemovePaddingPlugin::enqueue(const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT {
const half* input0 = static_cast<const half*>(inputs[0]);
const int32_t* input1 =
static_cast<const int32_t*>(inputs[1]); // pos_id_tensor
half* output = static_cast<half*>(outputs[0]);
const auto input0_desc = inputDesc[0];
const int32_t vector_length = input0_desc.dims.d[2];
int32_t num_threads;
if (vector_length < 1024) {
num_threads = vector_length;
} else {
if (vector_length % 512 == 0) {
num_threads = 512;
} else if (vector_length % 256 == 0) {
num_threads = 256;
} else if (vector_length % 128 == 0) {
num_threads = 128;
} else if (vector_length % 64 == 0) {
num_threads = 64;
} else if (vector_length % 32 == 0) {
num_threads = 32;
} else if (vector_length % 16 == 0) {
num_threads = 16;
} else if (vector_length % 8 == 0) {
num_threads = 8;
} else if (vector_length % 4 == 0) {
num_threads = 4;
} else if (vector_length % 2 == 0) {
num_threads = 2;
} else {
num_threads = 1;
}
}
const dim3 num_blocks(
input0_desc.dims.d[0],
input0_desc.dims.d[1],
vector_length /
num_threads); // batches, max sequence length, input0.dims.d[2]/***
RemovePaddingKernel<<<num_blocks, num_threads, 0, stream>>>(
input0, input1, output);
return cudaGetLastError() != cudaSuccess;
}
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,141 @@
/* Copyright (c) 2022 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. */
#pragma once
#include <cassert>
#include <string>
#include "paddle/fluid/inference/tensorrt/plugin/trt_plugin.h"
#include "paddle/fluid/platform/enforce.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
class RemovePaddingPlugin : public DynamicPluginTensorRT {
public:
RemovePaddingPlugin() {}
RemovePaddingPlugin(void const* serial_data, size_t serial_length) {}
nvinfer1::IPluginV2DynamicExt* clone() const TRT_NOEXCEPT override {
RemovePaddingPlugin* ptr = new RemovePaddingPlugin();
return ptr;
}
const char* getPluginType() const TRT_NOEXCEPT override {
return "remove_padding_plugin";
}
int getNbOutputs() const TRT_NOEXCEPT override { return 1; }
int initialize() TRT_NOEXCEPT { return 0; }
void terminate() TRT_NOEXCEPT;
nvinfer1::DimsExprs getOutputDimensions(
int outputIndex,
const nvinfer1::DimsExprs* inputs,
int nbInputs,
nvinfer1::IExprBuilder& exprBuilder) // NOLINT
TRT_NOEXCEPT override;
bool supportsFormatCombination(int pos,
const nvinfer1::PluginTensorDesc* inOut,
int nbInputs,
int nbOutputs) TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::DynamicPluginTensorDesc* inputs,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc* outputs,
int nbOutputs) TRT_NOEXCEPT override;
size_t getWorkspaceSize(const nvinfer1::PluginTensorDesc* inputs,
int nbInputs,
const nvinfer1::PluginTensorDesc* outputs,
int nbOutputs) const TRT_NOEXCEPT override {
return 0;
}
void attachToContext(cudnnContext* cudnnContext,
cublasContext* cublasContext,
nvinfer1::IGpuAllocator* gpuAllocator)
TRT_NOEXCEPT override;
void detachFromContext() TRT_NOEXCEPT override;
int enqueue(const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* inputTypes,
int nbInputs) const
TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override { delete this; }
protected:
size_t getSerializationSize() const TRT_NOEXCEPT override { return 0; }
void serialize(void* buffer) const TRT_NOEXCEPT override {}
};
class RemovePaddingPluginCreator : public nvinfer1::IPluginCreator {
public:
RemovePaddingPluginCreator() {}
const char* getPluginName() const TRT_NOEXCEPT override {
return "remove_padding_plugin";
}
const char* getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
const nvinfer1::PluginFieldCollection* getFieldNames() TRT_NOEXCEPT override {
return &field_collection_;
}
nvinfer1::IPluginV2* createPlugin(
const char* name, const nvinfer1::PluginFieldCollection* plugin_field)
TRT_NOEXCEPT override {
return nullptr;
}
nvinfer1::IPluginV2* deserializePlugin(const char* name,
void const* serial_data,
size_t serial_length)
TRT_NOEXCEPT override {
RemovePaddingPlugin* obj =
new RemovePaddingPlugin(serial_data, serial_length);
obj->setPluginNamespace(name);
return obj;
}
void setPluginNamespace(const char* lib_namespace) TRT_NOEXCEPT override {
plugin_namespace_ = lib_namespace;
}
const char* getPluginNamespace() const TRT_NOEXCEPT override {
return plugin_namespace_.c_str();
}
private:
std::string plugin_namespace_;
std::string plugin_name_;
nvinfer1::PluginFieldCollection field_collection_{0, nullptr};
};
REGISTER_TRT_PLUGIN_V2(RemovePaddingPluginCreator);
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,260 @@
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
// Copyright (c) 2019-2022, NVIDIA CORPORATION. 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/plugin/reverse_roll_op_plugin.h"
#include <vector>
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
/******************* invokeReverseRoll ***********************/
// src is [batch*window_num, window_len, dim]
// dst is [batch, H, W, dim] + rolled
// grid(W, H, batch)
// block(min(1024, dim))
template <typename T>
__global__ void reverse_roll(T *dst,
const T *src,
const int batch,
const int window_num,
const int window_len,
const int window_size,
const int H,
const int W,
const int shift_size,
const int dim) {
const int batch_idx = blockIdx.z;
const int H_idx_shifted = (blockIdx.y + shift_size) % H;
const int W_idx_shifted = (blockIdx.x + shift_size) % W;
const int H_idx = blockIdx.y;
const int W_idx = blockIdx.x;
const int window_idx =
H_idx / window_size * (W / window_size) + W_idx / window_size;
const int idx_in_window =
(H_idx % window_size) * window_size + (W_idx % window_size);
const int input_offset =
(batch_idx * window_num + window_idx) * window_len + idx_in_window;
const int output_offset = (batch_idx * H + H_idx_shifted) * W + W_idx_shifted;
for (int tid = threadIdx.x; tid < dim; tid += blockDim.x) {
dst[output_offset * dim + tid] = src[input_offset * dim + tid];
}
}
// src is [batch*window_num, window_len, dim]
// dst is [batch, H, W, dim] + rolled
// grid(W, H, batch)
// block(min(1024, dim))
template <typename T>
void invokeReverseRoll(T *dst,
const T *src,
int batch,
int window_num,
int window_len,
int window_size,
int H,
int W,
int dim,
int shift_size,
cudaStream_t stream) {
dim3 grid(W, H, batch);
int blockSize = dim;
if (std::is_same<T, half>::value && (dim % 2 == 0)) {
blockSize = dim / 2;
if (blockSize > 1024) {
blockSize = 1024;
}
using T2 = half2;
reverse_roll<<<grid, blockSize, 0, stream>>>(
reinterpret_cast<T2 *>(dst),
reinterpret_cast<const T2 *>(src),
batch,
window_num,
window_len,
window_size,
H,
W,
shift_size,
dim / 2);
} else {
if (blockSize > 1024) {
blockSize = 1024;
}
reverse_roll<<<grid, blockSize, 0, stream>>>(dst,
src,
batch,
window_num,
window_len,
window_size,
H,
W,
shift_size,
dim);
}
}
template void invokeReverseRoll(float *dst,
const float *src,
int batch,
int window_num,
int window_len,
int window_size,
int H,
int W,
int dim,
int shift_size,
cudaStream_t stream);
template void invokeReverseRoll(half *dst,
const half *src,
int batch,
int window_num,
int window_len,
int window_size,
int H,
int W,
int dim,
int shift_size,
cudaStream_t stream);
void ReverseRollPluginDynamic::configurePlugin(
const nvinfer1::DynamicPluginTensorDesc *in,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc *out,
int nbOutputs) TRT_NOEXCEPT {}
bool ReverseRollPluginDynamic::supportsFormatCombination(
int pos,
const nvinfer1::PluginTensorDesc *in_out,
int nb_inputs,
int nb_outputs) TRT_NOEXCEPT {
PADDLE_ENFORCE_NOT_NULL(
in_out,
common::errors::InvalidArgument("The input of ReverseRoll "
"plugin should not be nullptr."));
PADDLE_ENFORCE_LT(
pos,
nb_inputs + nb_outputs,
common::errors::InvalidArgument("The pos(%d) should be less than the "
"num(%d) of the input and the output.",
pos,
nb_inputs + nb_outputs));
const nvinfer1::PluginTensorDesc &in = in_out[pos];
if (pos == 0) {
if (with_fp16_) {
return in.type == nvinfer1::DataType::kHALF &&
in.format == nvinfer1::TensorFormat::kLINEAR;
} else {
return in.type == nvinfer1::DataType::kFLOAT &&
in.format == nvinfer1::TensorFormat::kLINEAR;
}
}
const nvinfer1::PluginTensorDesc &prev = in_out[pos - 1];
// output
return in.type == prev.type && in.format == prev.format;
}
nvinfer1::DataType ReverseRollPluginDynamic::getOutputDataType(
int index,
const nvinfer1::DataType *input_types,
int nb_inputs) const TRT_NOEXCEPT {
PADDLE_ENFORCE_EQ(index,
0,
common::errors::InvalidArgument(
"The ReverseRoll only has one input, so the "
"index value should be 0, but get %d.",
index));
return input_types[0];
}
nvinfer1::DimsExprs ReverseRollPluginDynamic::getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs *inputs,
int nb_inputs,
nvinfer1::IExprBuilder &expr_builder) TRT_NOEXCEPT {
PADDLE_ENFORCE_EQ(output_index,
0,
common::errors::InvalidArgument(
"There is only one output of the ReverseRoll, "
"so the index should be zero,"
"but it's (%d)",
output_index));
PADDLE_ENFORCE_EQ(
nb_inputs,
1,
common::errors::InvalidArgument(
"The Input of the ReverseRoll should be 1, but we found "
"it has (%d) inputs",
nb_inputs));
nvinfer1::DimsExprs ret;
ret.nbDims = 3;
ret.d[0] = expr_builder.operation(nvinfer1::DimensionOperation::kFLOOR_DIV,
*inputs[0].d[0],
*expr_builder.constant(window_num_));
ret.d[1] = expr_builder.operation(nvinfer1::DimensionOperation::kPROD,
*inputs[0].d[1],
*expr_builder.constant(window_num_));
ret.d[2] = inputs[0].d[2];
return ret;
}
int ReverseRollPluginDynamic::enqueue(
const nvinfer1::PluginTensorDesc *input_desc,
const nvinfer1::PluginTensorDesc *output_desc,
const void *const *inputs,
void *const *outputs,
void *workspace,
cudaStream_t stream) TRT_NOEXCEPT {
const auto &input_dims = input_desc[0].dims;
auto input_type = input_desc[0].type;
int batch = input_dims.d[0] / window_num_;
int dim = input_dims.d[2];
if (input_type == nvinfer1::DataType::kFLOAT) {
VLOG(3) << "TRT Plugin DataType selected. ReverseRoll-->fp32";
invokeReverseRoll(reinterpret_cast<float *>(outputs[0]),
reinterpret_cast<const float *>(inputs[0]),
batch,
window_num_,
window_len_,
window_size_,
input_resolution_,
input_resolution_,
dim,
shift_size_,
stream);
} else if (input_type == nvinfer1::DataType::kHALF) {
VLOG(3) << "TRT Plugin DataType selected. ReverseRoll-->fp16";
invokeReverseRoll(reinterpret_cast<half *>(outputs[0]),
reinterpret_cast<const half *>(inputs[0]),
batch,
window_num_,
window_len_,
window_size_,
input_resolution_,
input_resolution_,
dim,
shift_size_,
stream);
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"The ReverseRoll TRT Plugin's input type should be float or half."));
}
return cudaGetLastError() != cudaSuccess;
}
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,138 @@
// Copyright (c) 2022 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.
#pragma once
#include "paddle/fluid/framework/tensor.h"
#include "paddle/fluid/framework/tensor_util.h"
#include "paddle/fluid/inference/tensorrt/engine.h"
#include "paddle/fluid/inference/tensorrt/plugin/trt_plugin.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
class ReverseRollPluginDynamic : public DynamicPluginTensorRT {
public:
ReverseRollPluginDynamic(int window_num,
int window_len,
int window_size,
int input_resolution,
int shift_size,
bool with_fp16)
: window_num_(window_num),
window_len_(window_len),
window_size_(window_size),
input_resolution_(input_resolution),
shift_size_(shift_size),
with_fp16_(with_fp16) {}
ReverseRollPluginDynamic(void const* serialData, size_t serialLength) {
DeserializeValue(&serialData, &serialLength, &window_num_);
DeserializeValue(&serialData, &serialLength, &window_len_);
DeserializeValue(&serialData, &serialLength, &window_size_);
DeserializeValue(&serialData, &serialLength, &input_resolution_);
DeserializeValue(&serialData, &serialLength, &shift_size_);
DeserializeValue(&serialData, &serialLength, &with_fp16_);
}
nvinfer1::IPluginV2DynamicExt* clone() const TRT_NOEXCEPT override {
return new ReverseRollPluginDynamic(window_num_,
window_len_,
window_size_,
input_resolution_,
shift_size_,
with_fp16_);
}
const char* getPluginType() const TRT_NOEXCEPT override {
return "reverse_roll_dynamic";
}
int getNbOutputs() const TRT_NOEXCEPT override { return 1; }
int initialize() TRT_NOEXCEPT override { return 0; }
size_t getSerializationSize() const TRT_NOEXCEPT override {
return SerializedSize(window_num_) + SerializedSize(window_len_) +
SerializedSize(window_size_) + SerializedSize(input_resolution_) +
SerializedSize(shift_size_) + SerializedSize(with_fp16_);
}
void serialize(void* buffer) const TRT_NOEXCEPT override {
SerializeValue(&buffer, window_num_);
SerializeValue(&buffer, window_len_);
SerializeValue(&buffer, window_size_);
SerializeValue(&buffer, input_resolution_);
SerializeValue(&buffer, shift_size_);
SerializeValue(&buffer, with_fp16_);
}
nvinfer1::DimsExprs getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs* inputs,
int nb_inputs,
nvinfer1::IExprBuilder& expr_builder) // NOLINT
TRT_NOEXCEPT override;
bool supportsFormatCombination(int pos,
const nvinfer1::PluginTensorDesc* inOut,
int nbInputs,
int nbOutputs) TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::DynamicPluginTensorDesc* in,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc* out,
int nbOutputs) TRT_NOEXCEPT override;
size_t getWorkspaceSize(const nvinfer1::PluginTensorDesc* inputs,
int nbInputs,
const nvinfer1::PluginTensorDesc* outputs,
int nbOutputs) const TRT_NOEXCEPT override {
return 0;
}
int enqueue(const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* inputTypes,
int nbInputs) const
TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override { delete this; }
private:
int window_num_;
int window_len_;
int window_size_;
int input_resolution_;
int shift_size_;
bool with_fp16_;
};
class ReverseRollPluginDynamicCreator : public TensorRTPluginCreator {
public:
const char* getPluginName() const TRT_NOEXCEPT override {
return "reverse_roll_dynamic";
}
const char* getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
nvinfer1::IPluginV2* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override {
return new ReverseRollPluginDynamic(serial_data, serial_length);
}
};
REGISTER_TRT_PLUGIN_V2(ReverseRollPluginDynamicCreator);
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,791 @@
// Copyright (c) 2018 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 <cuda_fp16.h>
#include <cuda_runtime.h>
#include <algorithm>
#include "paddle/fluid/inference/tensorrt/plugin/roi_align_op_plugin.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
template <class T>
__inline__ __device__ T BilinearInterpolate(
const T* input_data, const int height, const int width, T y, T x) {
if (y < -1.f || y > height || x < -1.f || x > width) return 0;
y = y <= 0.f ? 0.f : y;
x = x <= 0.f ? 0.f : x;
int y_low = static_cast<int>(y);
int x_low = static_cast<int>(x);
int y_high;
int x_high;
if (y_low >= height - 1) {
y_high = y_low = height - 1;
y = static_cast<T>(y_low);
} else {
y_high = y_low + 1;
}
if (x_low >= width - 1) {
x_high = x_low = width - 1;
x = static_cast<T>(x_low);
} else {
x_high = x_low + 1;
}
T ly = y - y_low, lx = x - x_low;
T hy = 1.f - ly, hx = 1.f - lx;
T v1 = input_data[y_low * width + x_low];
T v2 = input_data[y_low * width + x_high];
T v3 = input_data[y_high * width + x_low];
T v4 = input_data[y_high * width + x_high];
T w1 = hy * hx, w2 = hy * lx, w3 = ly * hx, w4 = ly * lx;
T val = (w1 * v1 + w2 * v2 + w3 * v3 + w4 * v4);
return val;
}
template <typename T, typename OutT, bool USE_SMEM>
__global__ void GPUROIAlignOpt(const int nthreads,
const T* __restrict__ input_data,
const T* __restrict__ input_rois,
const float spatial_scale,
const int channels,
const int height,
const int width,
const int pooled_height,
const int pooled_width,
const int sampling_ratio,
const int num_rois,
const bool aligned,
OutT* __restrict__ output_data) {
const int batch = blockIdx.x;
const int channel = blockIdx.y;
const T* offset_input_data =
input_data + (batch * channels + channel) * height * width;
extern __shared__ T s_input_data[];
if (USE_SMEM) {
for (int idx = threadIdx.x; idx < height * width; idx += blockDim.x) {
s_input_data[idx] = offset_input_data[idx];
}
__syncthreads();
}
for (int idx = threadIdx.x; idx < num_rois * pooled_height * pooled_width;
idx += blockDim.x) {
const int pw = idx % pooled_width;
const int ph = (idx / pooled_width) % pooled_height;
const int roi_idx = (idx / pooled_width / pooled_height) % num_rois;
const int n = batch * num_rois + roi_idx;
const float4 rois_offset = reinterpret_cast<const float4*>(input_rois)[n];
const T roi_offset = aligned ? static_cast<T>(0.5) : 0;
const T roi_xmin = rois_offset.x * spatial_scale - roi_offset;
const T roi_ymin = rois_offset.y * spatial_scale - roi_offset;
const T roi_xmax = rois_offset.z * spatial_scale - roi_offset;
const T roi_ymax = rois_offset.w * spatial_scale - roi_offset;
T roi_width = roi_xmax - roi_xmin;
T roi_height = roi_ymax - roi_ymin;
if (!aligned) {
roi_width = max(roi_width, static_cast<T>(1.));
roi_height = max(roi_height, static_cast<T>(1.));
}
const T bin_size_h =
static_cast<T>(roi_height) / static_cast<T>(pooled_height);
const T bin_size_w =
static_cast<T>(roi_width) / static_cast<T>(pooled_width);
const int roi_bin_grid_h = (sampling_ratio > 0)
? sampling_ratio
: ceil(roi_height / pooled_height);
const int roi_bin_grid_w =
(sampling_ratio > 0) ? sampling_ratio : ceil(roi_width / pooled_width);
const T count = max(roi_bin_grid_h * roi_bin_grid_w, 1);
T output_val = 0.f;
for (int iy = 0; iy < roi_bin_grid_h; ++iy) {
const T y = roi_ymin + ph * bin_size_h +
static_cast<T>(iy + .5f) * bin_size_h /
static_cast<T>(roi_bin_grid_h);
for (int ix = 0; ix < roi_bin_grid_w; ++ix) {
const T x = roi_xmin + pw * bin_size_w +
static_cast<T>(ix + .5f) * bin_size_w /
static_cast<T>(roi_bin_grid_w);
if (USE_SMEM) {
T val = BilinearInterpolate<T>(s_input_data, height, width, y, x);
output_val += val;
} else {
T val =
BilinearInterpolate<T>(offset_input_data, height, width, y, x);
output_val += val;
}
}
}
output_val /= count;
const int out_offset =
batch * num_rois * channels * pooled_height * pooled_width +
roi_idx * channels * pooled_height * pooled_width +
channel * pooled_height * pooled_width + ph * pooled_width + pw;
output_data[out_offset] = static_cast<OutT>(output_val);
}
}
RoiAlignPluginDynamic::RoiAlignPluginDynamic(const nvinfer1::DataType data_type,
const int pooled_height,
const int pooled_width,
float spatial_scale,
int sampling_ratio,
bool aligned)
: data_type_(data_type),
pooled_height_(pooled_height),
pooled_width_(pooled_width),
spatial_scale_(spatial_scale),
sampling_ratio_(sampling_ratio),
aligned_(aligned) {
bool data_type_is_valid = data_type_ == nvinfer1::DataType::kFLOAT ||
data_type_ == nvinfer1::DataType::kHALF;
PADDLE_ENFORCE_EQ(data_type_is_valid,
true,
common::errors::InvalidArgument(
"TRT RoiAlign plugin only accepts kFLOAT(%d) or "
"kHALF(%d) data type, but the received data type = %d",
static_cast<int>(nvinfer1::DataType::kFLOAT),
static_cast<int>(nvinfer1::DataType::kHALF),
static_cast<int>(data_type_)));
PADDLE_ENFORCE_GT(pooled_height_,
0,
common::errors::InvalidArgument(
"TRT RoiAlign plugin only accepts pooled_height "
"greater than %d, but the received pooled_height = %d",
0,
pooled_height_));
PADDLE_ENFORCE_GT(pooled_width_,
0,
common::errors::InvalidArgument(
"TRT RoiAlign plugin only accepts pooled_width greater "
"than %d, but the received pooled_width = %d",
0,
pooled_height_));
PADDLE_ENFORCE_GT(spatial_scale_,
0.f,
common::errors::InvalidArgument(
"TRT RoiAlign plugin only accepts spatial_scale "
"greater than %f, but the received spatial_scale = %f",
0,
spatial_scale_));
int smem_per_block = -1;
int device = -1;
cudaGetDevice(&device);
PADDLE_ENFORCE_GE(
device,
0,
common::errors::InvalidArgument(
"The cuda device ID should be greater than %d, but device ID is %d",
0,
device));
cudaDeviceGetAttribute(
&smem_per_block, cudaDevAttrMaxSharedMemoryPerBlock, device);
smem_per_block_ = smem_per_block;
}
RoiAlignPluginDynamic::RoiAlignPluginDynamic(void const* data, size_t length) {
DeserializeValue(&data, &length, &data_type_);
DeserializeValue(&data, &length, &pooled_height_);
DeserializeValue(&data, &length, &pooled_width_);
DeserializeValue(&data, &length, &spatial_scale_);
DeserializeValue(&data, &length, &sampling_ratio_);
DeserializeValue(&data, &length, &aligned_);
int smem_per_block = -1;
int device = -1;
cudaGetDevice(&device);
PADDLE_ENFORCE_GE(
device,
0,
common::errors::InvalidArgument(
"The cuda device ID should be greater than %d, but device ID is %d",
0,
device));
cudaDeviceGetAttribute(
&smem_per_block, cudaDevAttrMaxSharedMemoryPerBlock, device);
smem_per_block_ = smem_per_block;
}
nvinfer1::IPluginV2DynamicExt* RoiAlignPluginDynamic::clone() const
TRT_NOEXCEPT {
auto* plugin = new RoiAlignPluginDynamic(data_type_,
pooled_height_,
pooled_width_,
spatial_scale_,
sampling_ratio_,
aligned_);
plugin->setPluginNamespace(namespace_.c_str());
return plugin;
}
nvinfer1::DimsExprs RoiAlignPluginDynamic::getOutputDimensions(
int outputIndex,
const nvinfer1::DimsExprs* inputs,
int nbInputs,
nvinfer1::IExprBuilder& exprBuilder) TRT_NOEXCEPT {
nvinfer1::DimsExprs ret{};
ret.nbDims = 4;
ret.d[0] = inputs[1].d[0]; // roi
ret.d[1] = inputs[0].d[1]; // X
ret.d[2] = exprBuilder.constant(pooled_height_);
ret.d[3] = exprBuilder.constant(pooled_width_);
return ret;
}
bool RoiAlignPluginDynamic::supportsFormatCombination(
int pos,
const nvinfer1::PluginTensorDesc* inOut,
int nbInputs,
int nbOutputs) TRT_NOEXCEPT {
if (inOut[pos].format != nvinfer1::TensorFormat::kLINEAR) {
return false;
}
if (pos < 2) { // input
return inOut[pos].type == nvinfer1::DataType::kFLOAT;
}
return inOut[pos].type == data_type_;
}
void RoiAlignPluginDynamic::configurePlugin(
const nvinfer1::DynamicPluginTensorDesc* in,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc* out,
int nbOutputs) TRT_NOEXCEPT {}
size_t RoiAlignPluginDynamic::getWorkspaceSize(
const nvinfer1::PluginTensorDesc* inputs,
int nbInputs,
const nvinfer1::PluginTensorDesc* outputs,
int nbOutputs) const TRT_NOEXCEPT {
return 0;
}
template <typename T, typename OutT>
int RoiAlignPluginDynamic::enqueue_impl(
const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) {
auto in_dims = inputDesc[0].dims;
auto rois_dims = inputDesc[1].dims;
auto out_dims = outputDesc[0].dims;
int rois_num = rois_dims.d[0];
if (rois_num == 0) return cudaGetLastError() != cudaSuccess;
int batch = in_dims.d[0];
int channels = in_dims.d[1];
int height = in_dims.d[2];
int width = in_dims.d[3];
int output_size =
out_dims.d[0] * out_dims.d[1] * out_dims.d[2] * out_dims.d[3];
const dim3 blocks(batch, channels);
const int threads = 512;
if (smem_per_block_ < width * height * sizeof(T)) {
GPUROIAlignOpt<T, OutT, false>
<<<blocks, threads, 0, stream>>>(output_size,
static_cast<const T*>(inputs[0]),
static_cast<const T*>(inputs[1]),
spatial_scale_,
channels,
height,
width,
pooled_height_,
pooled_width_,
sampling_ratio_,
rois_num / batch,
aligned_,
static_cast<OutT*>(outputs[0]));
} else {
GPUROIAlignOpt<T, OutT, false>
<<<blocks, threads, width * height * sizeof(T), stream>>>(
output_size,
static_cast<const T*>(inputs[0]),
static_cast<const T*>(inputs[1]),
spatial_scale_,
channels,
height,
width,
pooled_height_,
pooled_width_,
sampling_ratio_,
rois_num / batch,
aligned_,
static_cast<OutT*>(outputs[0]));
}
return cudaGetLastError() != cudaSuccess;
}
int RoiAlignPluginDynamic::enqueue(const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT {
PADDLE_ENFORCE_EQ(outputDesc[0].type,
data_type_,
common::errors::InvalidArgument(
"TRT RoiAlignPluginDynamic expects outputDesc[0].type "
"equal to data_type_"));
if (data_type_ == nvinfer1::DataType::kHALF) {
return enqueue_impl<float, half>(
inputDesc, outputDesc, inputs, outputs, workspace, stream);
}
return enqueue_impl<float, float>(
inputDesc, outputDesc, inputs, outputs, workspace, stream);
}
nvinfer1::DataType RoiAlignPluginDynamic::getOutputDataType(
int index,
const nvinfer1::DataType* inputTypes,
int nbInputs) const TRT_NOEXCEPT {
return inputTypes[0];
}
const char* RoiAlignPluginDynamic::getPluginType() const TRT_NOEXCEPT {
return "roi_align_plugin_dynamic";
}
const char* RoiAlignPluginDynamic::getPluginVersion() const TRT_NOEXCEPT {
return "2";
}
int RoiAlignPluginDynamic::getNbOutputs() const TRT_NOEXCEPT { return 1; }
int RoiAlignPluginDynamic::initialize() TRT_NOEXCEPT { return 0; }
void RoiAlignPluginDynamic::terminate() TRT_NOEXCEPT {}
size_t RoiAlignPluginDynamic::getSerializationSize() const TRT_NOEXCEPT {
size_t serialize_size = 0;
serialize_size += SerializedSize(data_type_);
serialize_size += SerializedSize(pooled_height_);
serialize_size += SerializedSize(pooled_width_);
serialize_size += SerializedSize(spatial_scale_);
serialize_size += SerializedSize(sampling_ratio_);
serialize_size += SerializedSize(aligned_);
return serialize_size;
}
void RoiAlignPluginDynamic::serialize(void* buffer) const TRT_NOEXCEPT {
SerializeValue(&buffer, data_type_);
SerializeValue(&buffer, pooled_height_);
SerializeValue(&buffer, pooled_width_);
SerializeValue(&buffer, spatial_scale_);
SerializeValue(&buffer, sampling_ratio_);
SerializeValue(&buffer, aligned_);
}
void RoiAlignPluginDynamic::destroy() TRT_NOEXCEPT {}
RoiAlignPluginDynamicCreator::RoiAlignPluginDynamicCreator() = default;
void RoiAlignPluginDynamicCreator::setPluginNamespace(const char* lib_namespace)
TRT_NOEXCEPT {
namespace_ = std::string(lib_namespace);
}
const char* RoiAlignPluginDynamicCreator::getPluginNamespace() const
TRT_NOEXCEPT {
return namespace_.c_str();
}
const char* RoiAlignPluginDynamicCreator::getPluginName() const TRT_NOEXCEPT {
return "roi_align_plugin_dynamic";
}
const char* RoiAlignPluginDynamicCreator::getPluginVersion() const
TRT_NOEXCEPT {
return "2";
}
const nvinfer1::PluginFieldCollection*
RoiAlignPluginDynamicCreator::getFieldNames() TRT_NOEXCEPT {
return &field_collection_;
}
nvinfer1::IPluginV2Ext* RoiAlignPluginDynamicCreator::createPlugin(
const char* name, const nvinfer1::PluginFieldCollection* fc) TRT_NOEXCEPT {
const nvinfer1::PluginField* fields = fc->fields;
return nullptr;
}
nvinfer1::IPluginV2Ext* RoiAlignPluginDynamicCreator::deserializePlugin(
const char* name,
const void* serial_data,
size_t serial_length) TRT_NOEXCEPT {
auto plugin = new RoiAlignPluginDynamic(serial_data, serial_length);
plugin->setPluginNamespace(namespace_.c_str());
return plugin;
}
PIRRoiAlignPluginDynamic::PIRRoiAlignPluginDynamic(
const nvinfer1::DataType data_type,
const int pooled_height,
const int pooled_width,
float spatial_scale,
int sampling_ratio,
bool aligned)
: data_type_(data_type),
pooled_height_(pooled_height),
pooled_width_(pooled_width),
spatial_scale_(spatial_scale),
sampling_ratio_(sampling_ratio),
aligned_(aligned) {
bool data_type_is_valid = data_type_ == nvinfer1::DataType::kFLOAT ||
data_type_ == nvinfer1::DataType::kHALF;
PADDLE_ENFORCE_EQ(data_type_is_valid,
true,
common::errors::InvalidArgument(
"TRT RoiAlign plugin only accepts kFLOAT(%d) or "
"kHALF(%d) data type, but the received data type = %d",
static_cast<int>(nvinfer1::DataType::kFLOAT),
static_cast<int>(nvinfer1::DataType::kHALF),
static_cast<int>(data_type_)));
PADDLE_ENFORCE_GT(pooled_height_,
0,
common::errors::InvalidArgument(
"TRT RoiAlign plugin only accepts pooled_height "
"greater than %d, but the received pooled_height = %d",
0,
pooled_height_));
PADDLE_ENFORCE_GT(pooled_width_,
0,
common::errors::InvalidArgument(
"TRT RoiAlign plugin only accepts pooled_width greater "
"than %d, but the received pooled_width = %d",
0,
pooled_height_));
PADDLE_ENFORCE_GT(spatial_scale_,
0.f,
common::errors::InvalidArgument(
"TRT RoiAlign plugin only accepts spatial_scale "
"greater than %f, but the received spatial_scale = %f",
0,
spatial_scale_));
int smem_per_block = -1;
int device = -1;
cudaGetDevice(&device);
PADDLE_ENFORCE_GE(
device,
0,
common::errors::InvalidArgument(
"The cuda device ID should be greater than %d, but device ID is %d",
0,
device));
cudaDeviceGetAttribute(
&smem_per_block, cudaDevAttrMaxSharedMemoryPerBlock, device);
smem_per_block_ = smem_per_block;
}
PIRRoiAlignPluginDynamic::PIRRoiAlignPluginDynamic(void const* data,
size_t length) {
DeserializeValue(&data, &length, &data_type_);
DeserializeValue(&data, &length, &pooled_height_);
DeserializeValue(&data, &length, &pooled_width_);
DeserializeValue(&data, &length, &spatial_scale_);
DeserializeValue(&data, &length, &sampling_ratio_);
DeserializeValue(&data, &length, &aligned_);
int smem_per_block = -1;
int device = -1;
cudaGetDevice(&device);
PADDLE_ENFORCE_GE(
device,
0,
common::errors::InvalidArgument(
"The cuda device ID should be greater than %d, but device ID is %d",
0,
device));
cudaDeviceGetAttribute(
&smem_per_block, cudaDevAttrMaxSharedMemoryPerBlock, device);
smem_per_block_ = smem_per_block;
}
nvinfer1::IPluginV2DynamicExt* PIRRoiAlignPluginDynamic::clone() const
TRT_NOEXCEPT {
auto* plugin = new PIRRoiAlignPluginDynamic(data_type_,
pooled_height_,
pooled_width_,
spatial_scale_,
sampling_ratio_,
aligned_);
plugin->setPluginNamespace(namespace_.c_str());
return plugin;
}
nvinfer1::DimsExprs PIRRoiAlignPluginDynamic::getOutputDimensions(
int outputIndex,
const nvinfer1::DimsExprs* inputs,
int nbInputs,
nvinfer1::IExprBuilder& exprBuilder) TRT_NOEXCEPT {
nvinfer1::DimsExprs ret{};
ret.nbDims = 4;
ret.d[0] = inputs[1].d[0]; // roi
ret.d[1] = inputs[0].d[1]; // X
ret.d[2] = exprBuilder.constant(pooled_height_);
ret.d[3] = exprBuilder.constant(pooled_width_);
return ret;
}
bool PIRRoiAlignPluginDynamic::supportsFormatCombination(
int pos,
const nvinfer1::PluginTensorDesc* inOut,
int nbInputs,
int nbOutputs) TRT_NOEXCEPT {
if (inOut[pos].format != nvinfer1::TensorFormat::kLINEAR) {
return false;
}
if (pos < 2) { // input
return inOut[pos].type == nvinfer1::DataType::kFLOAT;
}
return inOut[pos].type == data_type_;
}
void PIRRoiAlignPluginDynamic::configurePlugin(
const nvinfer1::DynamicPluginTensorDesc* in,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc* out,
int nbOutputs) TRT_NOEXCEPT {}
size_t PIRRoiAlignPluginDynamic::getWorkspaceSize(
const nvinfer1::PluginTensorDesc* inputs,
int nbInputs,
const nvinfer1::PluginTensorDesc* outputs,
int nbOutputs) const TRT_NOEXCEPT {
return 0;
}
template <typename T, typename OutT>
int PIRRoiAlignPluginDynamic::enqueue_impl(
const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) {
auto in_dims = inputDesc[0].dims;
auto rois_dims = inputDesc[1].dims;
auto out_dims = outputDesc[0].dims;
int rois_num = rois_dims.d[0];
if (rois_num == 0) return cudaGetLastError() != cudaSuccess;
int batch = in_dims.d[0];
int channels = in_dims.d[1];
int height = in_dims.d[2];
int width = in_dims.d[3];
int output_size =
out_dims.d[0] * out_dims.d[1] * out_dims.d[2] * out_dims.d[3];
const dim3 blocks(batch, channels);
const int threads = 512;
if (smem_per_block_ < width * height * sizeof(T)) {
GPUROIAlignOpt<T, OutT, false>
<<<blocks, threads, 0, stream>>>(output_size,
static_cast<const T*>(inputs[0]),
static_cast<const T*>(inputs[1]),
spatial_scale_,
channels,
height,
width,
pooled_height_,
pooled_width_,
sampling_ratio_,
rois_num / batch,
aligned_,
static_cast<OutT*>(outputs[0]));
} else {
GPUROIAlignOpt<T, OutT, false>
<<<blocks, threads, width * height * sizeof(T), stream>>>(
output_size,
static_cast<const T*>(inputs[0]),
static_cast<const T*>(inputs[1]),
spatial_scale_,
channels,
height,
width,
pooled_height_,
pooled_width_,
sampling_ratio_,
rois_num / batch,
aligned_,
static_cast<OutT*>(outputs[0]));
}
return cudaGetLastError() != cudaSuccess;
}
int PIRRoiAlignPluginDynamic::enqueue(
const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT {
PADDLE_ENFORCE_EQ(
outputDesc[0].type,
data_type_,
common::errors::InvalidArgument(
"TRT PIRRoiAlignPluginDynamic expects outputDesc[0].type "
"equal to data_type_"));
if (data_type_ == nvinfer1::DataType::kHALF) {
return enqueue_impl<float, half>(
inputDesc, outputDesc, inputs, outputs, workspace, stream);
}
return enqueue_impl<float, float>(
inputDesc, outputDesc, inputs, outputs, workspace, stream);
}
nvinfer1::DataType PIRRoiAlignPluginDynamic::getOutputDataType(
int index,
const nvinfer1::DataType* inputTypes,
int nbInputs) const TRT_NOEXCEPT {
return inputTypes[0];
}
const char* PIRRoiAlignPluginDynamic::getPluginType() const TRT_NOEXCEPT {
return "pir_roi_align_plugin_dynamic";
}
const char* PIRRoiAlignPluginDynamic::getPluginVersion() const TRT_NOEXCEPT {
return "2";
}
int PIRRoiAlignPluginDynamic::getNbOutputs() const TRT_NOEXCEPT { return 1; }
int PIRRoiAlignPluginDynamic::initialize() TRT_NOEXCEPT { return 0; }
void PIRRoiAlignPluginDynamic::terminate() TRT_NOEXCEPT {}
size_t PIRRoiAlignPluginDynamic::getSerializationSize() const TRT_NOEXCEPT {
size_t serialize_size = 0;
serialize_size += SerializedSize(data_type_);
serialize_size += SerializedSize(pooled_height_);
serialize_size += SerializedSize(pooled_width_);
serialize_size += SerializedSize(spatial_scale_);
serialize_size += SerializedSize(sampling_ratio_);
serialize_size += SerializedSize(aligned_);
return serialize_size;
}
void PIRRoiAlignPluginDynamic::serialize(void* buffer) const TRT_NOEXCEPT {
SerializeValue(&buffer, data_type_);
SerializeValue(&buffer, pooled_height_);
SerializeValue(&buffer, pooled_width_);
SerializeValue(&buffer, spatial_scale_);
SerializeValue(&buffer, sampling_ratio_);
SerializeValue(&buffer, aligned_);
}
void PIRRoiAlignPluginDynamic::destroy() TRT_NOEXCEPT {}
PIRRoiAlignPluginDynamicCreator::PIRRoiAlignPluginDynamicCreator() = default;
void PIRRoiAlignPluginDynamicCreator::setPluginNamespace(
const char* lib_namespace) TRT_NOEXCEPT {
namespace_ = std::string(lib_namespace);
}
const char* PIRRoiAlignPluginDynamicCreator::getPluginNamespace() const
TRT_NOEXCEPT {
return namespace_.c_str();
}
const char* PIRRoiAlignPluginDynamicCreator::getPluginName() const
TRT_NOEXCEPT {
return "pir_roi_align_plugin_dynamic";
}
const char* PIRRoiAlignPluginDynamicCreator::getPluginVersion() const
TRT_NOEXCEPT {
return "2";
}
const nvinfer1::PluginFieldCollection*
PIRRoiAlignPluginDynamicCreator::getFieldNames() TRT_NOEXCEPT {
return &field_collection_;
}
nvinfer1::IPluginV2Ext* PIRRoiAlignPluginDynamicCreator::createPlugin(
const char* name, const nvinfer1::PluginFieldCollection* fc) TRT_NOEXCEPT {
const nvinfer1::PluginField* fields = fc->fields;
int type_id = -1;
int pooled_height = 1;
int pooled_width = 1;
float spatial_scale = 1.0;
int sampling_ratio = -1;
bool aligned = false;
for (int i = 0; i < fc->nbFields; ++i) {
const std::string field_name(fc->fields[i].name);
if (field_name.compare("type_id") == 0) {
type_id = *static_cast<const int*>(fc->fields[i].data);
} else if (field_name.compare("pooled_height") == 0) {
pooled_height = *static_cast<const int*>(fc->fields[i].data);
} else if (field_name.compare("pooled_width") == 0) {
pooled_width = *static_cast<const int*>(fc->fields[i].data);
} else if (field_name.compare("spatial_scale") == 0) {
spatial_scale = *static_cast<const float*>(fc->fields[i].data);
} else if (field_name.compare("sampling_ratio") == 0) {
sampling_ratio = *static_cast<const int*>(fc->fields[i].data);
} else if (field_name.compare("aligned") == 0) {
aligned = *static_cast<const bool*>(fc->fields[i].data);
} else {
assert(false && "unknown plugin field name.");
}
}
return new PIRRoiAlignPluginDynamic(
type_id ? nvinfer1::DataType::kHALF : nvinfer1::DataType::kFLOAT,
pooled_height,
pooled_width,
spatial_scale,
sampling_ratio,
aligned);
}
nvinfer1::IPluginV2Ext* PIRRoiAlignPluginDynamicCreator::deserializePlugin(
const char* name,
const void* serial_data,
size_t serial_length) TRT_NOEXCEPT {
auto plugin = new PIRRoiAlignPluginDynamic(serial_data, serial_length);
plugin->setPluginNamespace(namespace_.c_str());
return plugin;
}
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,220 @@
// Copyright (c) 2018 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.
#pragma once
#include <string>
#include <vector>
#include "paddle/fluid/inference/tensorrt/engine.h"
#include "paddle/fluid/inference/tensorrt/plugin/trt_plugin.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
class RoiAlignPluginDynamic : public DynamicPluginTensorRT {
public:
explicit RoiAlignPluginDynamic(const nvinfer1::DataType data_type,
const int pooled_height,
const int pooled_width,
float spatial_scale,
int sampling_ratio,
bool aligned);
RoiAlignPluginDynamic(void const* data, size_t length);
~RoiAlignPluginDynamic() = default;
nvinfer1::IPluginV2DynamicExt* clone() const TRT_NOEXCEPT override;
nvinfer1::DimsExprs getOutputDimensions(
int outputIndex,
const nvinfer1::DimsExprs* inputs,
int nbInputs,
nvinfer1::IExprBuilder& exprBuilder) // NOLINT
TRT_NOEXCEPT override;
bool supportsFormatCombination(int pos,
const nvinfer1::PluginTensorDesc* inOut,
int nbInputs,
int nbOutputs) TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::DynamicPluginTensorDesc* in,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc* out,
int nbOutputs) TRT_NOEXCEPT override;
size_t getWorkspaceSize(const nvinfer1::PluginTensorDesc* inputs,
int nbInputs,
const nvinfer1::PluginTensorDesc* outputs,
int nbOutputs) const TRT_NOEXCEPT override;
int enqueue(const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* inputTypes,
int nbInputs) const
TRT_NOEXCEPT override;
const char* getPluginType() const TRT_NOEXCEPT override;
int getNbOutputs() const TRT_NOEXCEPT override;
int initialize() TRT_NOEXCEPT override;
void terminate() TRT_NOEXCEPT override;
size_t getSerializationSize() const TRT_NOEXCEPT override;
void serialize(void* buffer) const TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override;
const char* getPluginVersion() const TRT_NOEXCEPT override;
private:
template <typename T, typename OutT>
int enqueue_impl(const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream);
nvinfer1::DataType data_type_;
int pooled_height_;
int pooled_width_;
float spatial_scale_;
int sampling_ratio_;
int smem_per_block_;
bool aligned_;
std::string namespace_;
};
class RoiAlignPluginDynamicCreator : public nvinfer1::IPluginCreator {
public:
RoiAlignPluginDynamicCreator();
~RoiAlignPluginDynamicCreator() override = default;
void setPluginNamespace(const char* lib_namespace) TRT_NOEXCEPT override;
const char* getPluginNamespace() const TRT_NOEXCEPT override;
const char* getPluginName() const TRT_NOEXCEPT override;
const char* getPluginVersion() const TRT_NOEXCEPT override;
const nvinfer1::PluginFieldCollection* getFieldNames() TRT_NOEXCEPT override;
nvinfer1::IPluginV2Ext* createPlugin(
const char* name,
const nvinfer1::PluginFieldCollection* fc) TRT_NOEXCEPT override;
nvinfer1::IPluginV2Ext* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override;
private:
std::string namespace_;
nvinfer1::PluginFieldCollection field_collection_;
};
class PIRRoiAlignPluginDynamic : public DynamicPluginTensorRT {
public:
explicit PIRRoiAlignPluginDynamic(const nvinfer1::DataType data_type,
const int pooled_height,
const int pooled_width,
float spatial_scale,
int sampling_ratio,
bool aligned);
PIRRoiAlignPluginDynamic(void const* data, size_t length);
~PIRRoiAlignPluginDynamic() = default;
nvinfer1::IPluginV2DynamicExt* clone() const TRT_NOEXCEPT override;
nvinfer1::DimsExprs getOutputDimensions(
int outputIndex,
const nvinfer1::DimsExprs* inputs,
int nbInputs,
nvinfer1::IExprBuilder& exprBuilder) // NOLINT
TRT_NOEXCEPT override;
bool supportsFormatCombination(int pos,
const nvinfer1::PluginTensorDesc* inOut,
int nbInputs,
int nbOutputs) TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::DynamicPluginTensorDesc* in,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc* out,
int nbOutputs) TRT_NOEXCEPT override;
size_t getWorkspaceSize(const nvinfer1::PluginTensorDesc* inputs,
int nbInputs,
const nvinfer1::PluginTensorDesc* outputs,
int nbOutputs) const TRT_NOEXCEPT override;
int enqueue(const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* inputTypes,
int nbInputs) const
TRT_NOEXCEPT override;
const char* getPluginType() const TRT_NOEXCEPT override;
int getNbOutputs() const TRT_NOEXCEPT override;
int initialize() TRT_NOEXCEPT override;
void terminate() TRT_NOEXCEPT override;
size_t getSerializationSize() const TRT_NOEXCEPT override;
void serialize(void* buffer) const TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override;
const char* getPluginVersion() const TRT_NOEXCEPT override;
private:
template <typename T, typename OutT>
int enqueue_impl(const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream);
nvinfer1::DataType data_type_;
int pooled_height_;
int pooled_width_;
float spatial_scale_;
int sampling_ratio_;
int smem_per_block_;
bool aligned_;
std::string namespace_;
};
class PIRRoiAlignPluginDynamicCreator : public nvinfer1::IPluginCreator {
public:
PIRRoiAlignPluginDynamicCreator();
~PIRRoiAlignPluginDynamicCreator() override = default;
void setPluginNamespace(const char* lib_namespace) TRT_NOEXCEPT override;
const char* getPluginNamespace() const TRT_NOEXCEPT override;
const char* getPluginName() const TRT_NOEXCEPT override;
const char* getPluginVersion() const TRT_NOEXCEPT override;
const nvinfer1::PluginFieldCollection* getFieldNames() TRT_NOEXCEPT override;
nvinfer1::IPluginV2Ext* createPlugin(
const char* name,
const nvinfer1::PluginFieldCollection* fc) TRT_NOEXCEPT override;
nvinfer1::IPluginV2Ext* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override;
private:
std::string namespace_;
nvinfer1::PluginFieldCollection field_collection_;
};
REGISTER_TRT_PLUGIN_V2(RoiAlignPluginDynamicCreator);
REGISTER_TRT_PLUGIN_V2(PIRRoiAlignPluginDynamicCreator);
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,507 @@
/* Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
SPDX-FileCopyrightText: Copyright (c) 1993-2022 NVIDIA CORPORATION & AFFILIATES.
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/plugin/skip_groupnorm_act_op_plugin.h"
#include <cub/cub.cuh>
#include "paddle/common/layout.h"
#include "paddle/phi/backends/gpu/gpu_context.h"
#include "paddle/phi/kernels/funcs/math_function.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
nvinfer1::DimsExprs SkipGroupnormActPluginDynamic::getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs *inputDims,
int nb_inputs,
nvinfer1::IExprBuilder &expr_builder) TRT_NOEXCEPT {
return inputDims[0];
}
bool SkipGroupnormActPluginDynamic::supportsFormatCombination(
int pos,
const nvinfer1::PluginTensorDesc *in_out,
int nb_inputs,
int nb_outputs) TRT_NOEXCEPT {
PADDLE_ENFORCE_NOT_NULL(
in_out,
common::errors::InvalidArgument(
"The input of SkipGroupnormAct plugin should not be nullptr."));
PADDLE_ENFORCE_LT(
pos,
nb_inputs + nb_outputs,
common::errors::InvalidArgument("The pos(%d) should be less than the "
"num(%d) of the input and the output.",
pos,
nb_inputs + nb_outputs));
const nvinfer1::PluginTensorDesc &in = in_out[pos];
if (pos == 0) {
if (with_fp16_) {
return ((in.type == nvinfer1::DataType::kHALF) &&
(in.format == nvinfer1::PluginFormat::kHWC8));
} else {
PADDLE_THROW(common::errors::Fatal(
"SkipGroupnormAct TRT Plugin is fp16 only so far"));
return (in.type == nvinfer1::DataType::kFLOAT) &&
(in.format == nvinfer1::TensorFormat::kLINEAR);
}
}
const nvinfer1::PluginTensorDesc &prev = in_out[pos - 1];
// output
return in.type == prev.type && in.format == prev.format;
}
nvinfer1::DataType SkipGroupnormActPluginDynamic::getOutputDataType(
int index,
const nvinfer1::DataType *input_types,
int nb_inputs) const TRT_NOEXCEPT {
PADDLE_ENFORCE_EQ(
index,
0,
common::errors::InvalidArgument(
"The SkipGroupnormAct Plugin only has one input, so the "
"index value should be 0, but get %d.",
index));
PADDLE_ENFORCE_EQ((input_types[0] == nvinfer1::DataType::kFLOAT ||
input_types[0] == nvinfer1::DataType::kHALF),
true,
common::errors::InvalidArgument(
"The input type should be half or float"));
return input_types[0];
}
int SkipGroupnormActPluginDynamic::initialize() TRT_NOEXCEPT { return 0; }
template <typename T>
static inline T divUp(T m, T n) {
return (m + n - 1) / n;
}
static int64_t findMaxDivisor(int64_t n, int64_t maxAllowedDivisor) {
int64_t maxDivisor = -1;
for (int64_t i = 1; i <= std::sqrt(n); i++) {
if (n % i == 0) {
int64_t divisor1 = n / i;
int64_t divisor2 = i;
if (divisor1 > maxDivisor && divisor1 < maxAllowedDivisor) {
maxDivisor = divisor1;
}
if (divisor2 > maxDivisor && divisor2 < maxAllowedDivisor) {
maxDivisor = divisor2;
}
}
}
return maxDivisor;
}
static inline __device__ __host__ float sigmoid(float x) {
return 1.F / (1.F + expf(-x));
}
struct GroupSums {
// Is it the 1st element of the group?
int32_t flag;
// The sum.
float sum;
// The sum of squares.
float sumSq;
};
struct GroupSumsOp {
inline __device__ GroupSums operator()(GroupSums const &a,
GroupSums const &b) {
GroupSums dst;
dst.sum = b.flag ? b.sum : (a.sum + b.sum);
dst.sumSq = b.flag ? b.sumSq : (a.sumSq + b.sumSq);
dst.flag = a.flag + b.flag;
return dst;
}
};
template <int32_t tTHREADS_PER_BLOCK>
__global__ void skipGroupNormNDHWCSumKernel(
GroupNormNDHWCParams<__half> params) {
// The object in charge of doing the sums for the different blocks.
typedef cub::BlockScan<GroupSums, tTHREADS_PER_BLOCK> BlockScan;
// Allocate shared memory for BlockScan.
__shared__ typename BlockScan::TempStorage tempStorage;
// Allocate shared memory for the groups. We could reduce the amount of shared
// memory reserved.
__shared__ float2 smem[tTHREADS_PER_BLOCK];
// The instance in the batch.
int32_t ni = blockIdx.z;
// The channel loaded by that thread (2 channels per thread for F16x2).
int32_t ci = blockIdx.x * params.cPerBlock + threadIdx.x * 2;
// The first activation loaded by that block.
int64_t dhwBegin = static_cast<int64_t>(blockIdx.y) * params.dhwPerBlock;
// The last activation loaded by that block.
int64_t dhwEnd = min(dhwBegin + params.dhwPerBlock, params.dhw);
// The sums.
float sum = 0.F;
float sumSq = 0.F;
// Iterate over the activations to compute the sums.
for (int64_t dhwi = dhwBegin; dhwi < dhwEnd; ++dhwi) {
// The offset.
int64_t offset = static_cast<int64_t>(ni) * params.dhwc +
static_cast<int64_t>(dhwi) * params.c + ci;
// Fetch two channels per thread.
__half2 h2(0, 0);
if (ci < params.c) {
// W = 1, H = 1
int64_t offsetY = static_cast<int64_t>(ni) * params.c + ci;
__half2 y = *reinterpret_cast<__half2 const *>(&params.srcY[offsetY]);
h2 = *reinterpret_cast<__half2 const *>(&params.srcX[offset]);
#if __CUDA_ARCH__ >= 530
h2 = __hadd2(h2, y);
#else
float2 out{};
out.x = __half2float(h2.x) + __half2float(y.x);
out.y = __half2float(h2.y) + __half2float(y.y);
h2 = __float22half2_rn(out);
#endif
// elementwise_add
*reinterpret_cast<__half2 *>(&params.dst[offset]) = h2;
}
// Extract the two half values.
float2 f2 = __half22float2(h2);
// Update the sum.
sum += f2.x + f2.y;
// Update the sum of squares.
sumSq += f2.x * f2.x + f2.y * f2.y;
}
// The group that thread works on and the channel in the group (modulus).
int32_t gi = threadIdx.x * 2 / params.cPerGroup;
int32_t cj = threadIdx.x * 2 - params.cPerGroup * gi;
// The data for the summations.
GroupSums inp{cj == 0 ? 1 : 0, sum, sumSq};
// Do the segmented scan.
GroupSums out;
BlockScan(tempStorage).InclusiveScan(inp, out, GroupSumsOp());
// Store the results for the groups in shared memory (to produce coalesced
// stores later).
if (cj == params.cPerGroup - 2 /* 2 channels per thread */) {
smem[gi] = make_float2(out.sum, out.sumSq);
}
// Make sure the data is in shared memory.
__syncthreads();
// The global group index.
int32_t gj = blockIdx.x * params.groupsPerBlock + threadIdx.x;
// Threads that have nothing left to do, exit.
if (threadIdx.x >= params.groupsPerBlock || gj >= params.groups) {
return;
}
// The first threads (those storing to global memory, load the values).
float2 sums = smem[threadIdx.x];
// Store to global memory.
atomicAdd(&params.redBuffer[(2 * ni + 0) * params.groups + gj], sums.x);
atomicAdd(&params.redBuffer[(2 * ni + 1) * params.groups + gj], sums.y);
}
void skipGroupNormNDHWCSum(GroupNormNDHWCParams<__half> const &params,
cudaStream_t stream) {
// Make sure the values are as we expect.
PADDLE_ENFORCE_EQ(params.c % params.cPerBlock,
0,
common::errors::InvalidArgument(
"The groupNormNDHWCSum of SkipGroupnormAct Plugin got "
"wrong parameters: "
"params.c %% params.cPerBlock should be 0, but get %d.",
params.c % params.cPerBlock));
PADDLE_ENFORCE_EQ(
params.dhw % params.dhwPerBlock,
0,
common::errors::InvalidArgument(
"The groupNormNDHWCSum of SkipGroupnormAct Plugin got wrong "
"parameters: "
"params.dhw %% params.dhwPerBlock should be 0, but get %d.",
params.dhw % params.dhwPerBlock));
// Make sure a group does not span multiple blocks.
PADDLE_ENFORCE_EQ(
params.cPerBlock % params.cPerGroup,
0,
common::errors::InvalidArgument(
"The groupNormNDHWCSum of SkipGroupnormAct Plugin got wrong "
"parameters: "
"params.cPerBlock %% params.cPerGroup should be 0, but get %d.",
params.cPerBlock % params.cPerGroup));
dim3 grid;
// The number of blocks to compute all the channels.
grid.x = params.c / params.cPerBlock;
// The number of blocks to compute all the activations in a given instance.
grid.y = divUp(params.dhw, params.dhwPerBlock);
// The number of instances.
grid.z = params.n;
switch (params.cPerBlock) {
case 320:
skipGroupNormNDHWCSumKernel<160><<<grid, 160, 0, stream>>>(params);
break;
case 480:
skipGroupNormNDHWCSumKernel<256><<<grid, 256, 0, stream>>>(params);
break;
case 256:
skipGroupNormNDHWCSumKernel<128><<<grid, 128, 0, stream>>>(params);
break;
case 128:
skipGroupNormNDHWCSumKernel<64><<<grid, 64, 0, stream>>>(params);
break;
case 8:
skipGroupNormNDHWCSumKernel<4><<<grid, 4, 0, stream>>>(params);
break;
default:
PADDLE_THROW(common::errors::Fatal(
"The function groupNormNDHWCSum of SkipGroupnormAct TRT Plugin "
"encounter error"));
}
}
template <int32_t tTHREADS_PER_BLOCK>
__global__ void skipGroupNormNDHWCScaleKernel(
GroupNormNDHWCParams<__half> params) {
// The instance in the batch.
int32_t ni = blockIdx.z;
// The channel loaded by that thread (2 channels per thread for F16x2).
int32_t ci = blockIdx.x * params.cPerBlock + threadIdx.x * 2;
// The group that thread works on and the channel in the group (modulus).
int32_t gi = ci / params.cPerGroup;
// Load the sum and sum of squares for the group.
float sum = 0.F, sumSq = 0.F;
if (gi < params.groups) {
sum = params.redBuffer[(2 * ni + 0) * params.groups + gi];
sumSq = params.redBuffer[(2 * ni + 1) * params.groups + gi];
}
// Load gamma/beta.
float2 gammaF2, betaF2;
if (ci < params.c) {
gammaF2 = *reinterpret_cast<float2 const *>(
reinterpret_cast<float const *>(params.gamma) + ci);
betaF2 = *reinterpret_cast<float2 const *>(
reinterpret_cast<float const *>(params.beta) + ci);
}
// Compute the mean.
float mean = sum * params.invDHWC;
// Compute the variance.
float var = sumSq * params.invDHWC - (mean * mean);
// Compute the inverse of the stddev.
float invStdDev = rsqrtf(var + params.eps);
// The first activation loaded by that block.
int64_t dhwBegin = static_cast<int64_t>(blockIdx.y) * params.dhwPerBlock;
// The last activation loaded by that block.
int64_t dhwEnd = min(dhwBegin + params.dhwPerBlock, params.dhw);
// Iterate over the activations to compute the sums.
for (int64_t dhwi = dhwBegin; dhwi < dhwEnd; ++dhwi) {
// The src/dst offset.
int64_t offset = (int64_t)ni * params.dhwc + dhwi * params.c + ci;
// Fetch two channels per thread.
__half2 h2(0, 0);
if (ci < params.c) {
h2 = *reinterpret_cast<__half2 const *>(&params.dst[offset]);
}
// Extract the two half values.
float2 f2 = __half22float2(h2);
// Normalize the channels.
f2.x = (f2.x - mean) * invStdDev;
f2.y = (f2.y - mean) * invStdDev;
// Scale by gamma and add beta.
f2.x = gammaF2.x * f2.x + betaF2.x;
f2.y = gammaF2.y * f2.y + betaF2.y;
// Apply Silu if needed.
if (params.withSilu) {
f2.x = f2.x * sigmoid(f2.x);
f2.y = f2.y * sigmoid(f2.y);
}
// Store the scaled values.
if (ci < params.c) {
*reinterpret_cast<__half2 *>(&params.dst[offset]) = __float22half2_rn(f2);
}
}
}
void skipGroupNormNDHWCScale(GroupNormNDHWCParams<__half> const &params,
cudaStream_t stream) {
// Make sure the dimensions are aligned with what we expect.
PADDLE_ENFORCE_EQ(
params.c % params.cPerBlock,
0,
common::errors::InvalidArgument(
"The groupNormNDHWCScale of SkipGroupnormAct Plugin got "
"wrong parameters: "
"params.c %% params.cPerBlock should be 0, but get %d.",
params.c % params.cPerBlock));
// Make sure a group does not span multiple blocks.
PADDLE_ENFORCE_EQ(
params.cPerBlock % params.cPerGroup,
0,
common::errors::InvalidArgument(
"The groupNormNDHWCScale of SkipGroupnormAct Plugin got wrong "
"parameters: "
"params.cPerBlock %% params.cPerGroup should be 0, but get %d.",
params.cPerBlock % params.cPerGroup));
dim3 grid;
// The number of blocks to compute all the channels.
grid.x = params.c / params.cPerBlock;
// The number of blocks to compute all the activations in a given instance.
grid.y = divUp(params.dhw, params.dhwPerBlock);
// The number of instances.
grid.z = params.n;
switch (params.cPerBlock) {
case 320:
skipGroupNormNDHWCScaleKernel<160><<<grid, 160, 0, stream>>>(params);
break;
case 480:
skipGroupNormNDHWCScaleKernel<256><<<grid, 256, 0, stream>>>(params);
break;
case 256:
skipGroupNormNDHWCScaleKernel<128><<<grid, 128, 0, stream>>>(params);
break;
case 128:
skipGroupNormNDHWCScaleKernel<64><<<grid, 64, 0, stream>>>(params);
break;
case 8:
skipGroupNormNDHWCScaleKernel<4><<<grid, 4, 0, stream>>>(params);
break;
default:
PADDLE_THROW(common::errors::Fatal(
"The function groupNormNDHWCSum of SkipGroupnormAct TRT Plugin "
"encounter error"));
}
}
int SkipGroupnormActPluginDynamic::enqueue(
const nvinfer1::PluginTensorDesc *input_desc,
const nvinfer1::PluginTensorDesc *output_desc,
const void *const *inputs,
void *const *outputs,
void *workspace,
cudaStream_t stream) TRT_NOEXCEPT {
auto input_type = input_desc[0].type;
if (input_type == nvinfer1::DataType::kFLOAT) {
VLOG(1) << "TRT Plugin DataType selected. SkipGroupnormAct-->fp32";
PADDLE_THROW(common::errors::Fatal(
"The SkipGroupnormAct TRT Plugin's only support fp16 input"));
} else if (input_type == nvinfer1::DataType::kHALF) {
VLOG(1) << "TRT Plugin DataType selected. SkipGroupnormAct-->fp16";
int32_t cPerBlock = 320;
int32_t maxBlocksPerDHW = 1024;
switch (input_desc[0].dims.d[1]) {
case 960:
case 1920:
cPerBlock = 480;
break;
case 512:
case 256:
cPerBlock = 256;
break;
case 128:
cPerBlock = 128;
break;
default:
cPerBlock = 320;
}
if (cPerBlock > input_desc[0].dims.d[1]) {
cPerBlock = 8;
}
auto d_dim = input_desc[0].dims.nbDims;
params_.n = input_desc[0].dims.d[0];
if (d_dim == 3) {
params_.c = input_desc[0].dims.d[1];
params_.d = 1;
params_.h = 1;
params_.w = input_desc[0].dims.d[2];
} else if (d_dim == 4) {
params_.c = input_desc[0].dims.d[1];
params_.d = 1;
params_.h = input_desc[0].dims.d[2];
params_.w = input_desc[0].dims.d[3];
} else {
// d_dim == 5
params_.c = input_desc[0].dims.d[1];
params_.d = input_desc[0].dims.d[2];
params_.h = input_desc[0].dims.d[3];
params_.w = input_desc[0].dims.d[4];
}
params_.withSilu = true;
params_.dst = static_cast<half *>(outputs[0]);
params_.srcX = static_cast<half const *>(inputs[0]);
params_.srcY = static_cast<half const *>(inputs[1]);
params_.gamma = scale_gpu_.get();
params_.beta = bias_gpu_.get();
params_.redBuffer = static_cast<float *>(workspace);
// params_.n = input_desc[0].dims.d[0];
// params_.h = input_desc[0].dims.d[2];
// params_.w = input_desc[0].dims.d[3];
// params_.c = input_desc[0].dims.d[1];
params_.groups = groups_;
params_.dhw = static_cast<int64_t>(params_.d) * params_.h * params_.w;
const int64_t blocksPerDHW =
findMaxDivisor(params_.dhw, static_cast<int64_t>(maxBlocksPerDHW));
params_.dhwPerBlock = divUp(params_.dhw, blocksPerDHW);
params_.cPerBlock = cPerBlock;
params_.cPerGroup = params_.c / params_.groups;
params_.dhwc = params_.dhw * params_.c;
params_.invDHWC = 1.F / static_cast<float>(params_.dhw * params_.cPerGroup);
params_.groupsPerBlock = cPerBlock / params_.cPerGroup;
params_.eps = eps_;
cudaMemsetAsync(params_.redBuffer, 0, ws_, stream);
skipGroupNormNDHWCSum(params_, stream);
skipGroupNormNDHWCScale(params_, stream);
} else {
// input not fp16
PADDLE_THROW(common::errors::Fatal(
"The SkipGroupnormAct TRT Plugin's only support fp16 input"));
}
return cudaGetLastError() != cudaSuccess;
}
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,195 @@
/* Copyright (c) 2022 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. */
#pragma once
#include <algorithm>
#include <string>
#include <vector>
#include "paddle/fluid/framework/tensor.h"
#include "paddle/fluid/framework/tensor_util.h"
#include "paddle/fluid/inference/tensorrt/engine.h"
#include "paddle/fluid/inference/tensorrt/plugin/trt_plugin.h"
#include "paddle/phi/kernels/group_norm_kernel.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
using phi::GroupNormNDHWCParams;
class SkipGroupnormActPluginDynamic : public DynamicPluginTensorRT {
public:
SkipGroupnormActPluginDynamic(const float* scale,
const int scale_num,
const float* bias,
const int bias_num,
float eps,
int groups,
bool with_fp16,
std::shared_ptr<void> scale_gpu = nullptr,
std::shared_ptr<void> bias_gpu = nullptr)
: scale_gpu_(scale_gpu),
bias_gpu_(bias_gpu),
groups_(groups),
eps_(eps),
with_fp16_(with_fp16) {
scale_.resize(scale_num);
bias_.resize(bias_num);
std::copy(scale, scale + scale_num, scale_.data());
std::copy(bias, bias + bias_num, bias_.data());
if (scale_gpu_ == nullptr) {
void* p;
cudaMalloc(reinterpret_cast<void**>(&p), scale_num * sizeof(float));
scale_gpu_.reset(p, [](void* ptr) { cudaFree(ptr); });
cudaMemcpy(
p, scale_.data(), scale_num * sizeof(float), cudaMemcpyHostToDevice);
}
if (bias_gpu_ == nullptr) {
void* p;
cudaMalloc(reinterpret_cast<void**>(&p), bias_num * sizeof(float));
bias_gpu_.reset(p, [](void* ptr) { cudaFree(ptr); });
cudaMemcpy(
p, bias_.data(), bias_num * sizeof(float), cudaMemcpyHostToDevice);
}
}
SkipGroupnormActPluginDynamic(void const* serialData, size_t serialLength) {
DeserializeValue(&serialData, &serialLength, &scale_);
DeserializeValue(&serialData, &serialLength, &bias_);
DeserializeValue(&serialData, &serialLength, &eps_);
DeserializeValue(&serialData, &serialLength, &groups_);
DeserializeValue(&serialData, &serialLength, &with_fp16_);
{
void* p;
cudaMalloc(reinterpret_cast<void**>(&p), scale_.size() * sizeof(float));
scale_gpu_.reset(p, [](void* ptr) { cudaFree(ptr); });
cudaMemcpy(p,
scale_.data(),
scale_.size() * sizeof(float),
cudaMemcpyHostToDevice);
}
{
void* p;
cudaMalloc(reinterpret_cast<void**>(&p), bias_.size() * sizeof(float));
bias_gpu_.reset(p, [](void* ptr) { cudaFree(ptr); });
cudaMemcpy(p,
bias_.data(),
bias_.size() * sizeof(float),
cudaMemcpyHostToDevice);
}
}
nvinfer1::IPluginV2DynamicExt* clone() const TRT_NOEXCEPT override {
auto* ptr = new SkipGroupnormActPluginDynamic(scale_.data(),
scale_.size(),
bias_.data(),
bias_.size(),
eps_,
groups_,
with_fp16_,
scale_gpu_,
bias_gpu_);
return ptr;
}
const char* getPluginType() const TRT_NOEXCEPT override {
return "skip_groupnorm_act_plugin_dynamic";
}
int getNbOutputs() const TRT_NOEXCEPT override { return 1; }
int initialize() TRT_NOEXCEPT override;
size_t getSerializationSize() const TRT_NOEXCEPT override {
return SerializedSize(scale_) + SerializedSize(bias_) +
SerializedSize(eps_) + SerializedSize(groups_) +
SerializedSize(with_fp16_);
}
void serialize(void* buffer) const TRT_NOEXCEPT override {
SerializeValue(&buffer, scale_);
SerializeValue(&buffer, bias_);
SerializeValue(&buffer, eps_);
SerializeValue(&buffer, groups_);
SerializeValue(&buffer, with_fp16_);
}
nvinfer1::DimsExprs getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs* inputs,
int nb_inputs,
nvinfer1::IExprBuilder& expr_builder) // NOLINT
TRT_NOEXCEPT override;
bool supportsFormatCombination(int pos,
const nvinfer1::PluginTensorDesc* inOut,
int nbInputs,
int nbOutputs) TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::DynamicPluginTensorDesc* in,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc* out,
int nbOutputs) TRT_NOEXCEPT override {
// sizeof(float2) * maxBatchSize * maxNumberOfGroup. float2
// contains two buffers for sum and squared sum;
ws_ = sizeof(float) * 2 * in[0].max.d[0] * groups_;
}
size_t getWorkspaceSize(const nvinfer1::PluginTensorDesc* inputs,
int nbInputs,
const nvinfer1::PluginTensorDesc* outputs,
int nbOutputs) const TRT_NOEXCEPT override {
return ws_;
}
int enqueue(const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* inputTypes,
int nbInputs) const
TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override { delete this; }
void terminate() TRT_NOEXCEPT override{};
private:
size_t ws_;
std::vector<float> scale_;
std::vector<float> bias_;
std::shared_ptr<void> scale_gpu_;
std::shared_ptr<void> bias_gpu_;
GroupNormNDHWCParams<__half> params_;
int groups_;
float eps_;
bool with_fp16_;
};
class SkipGroupnormActPluginDynamicCreator : public TensorRTPluginCreator {
public:
const char* getPluginName() const TRT_NOEXCEPT override {
return "skip_groupnorm_act_plugin_dynamic";
}
const char* getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
nvinfer1::IPluginV2* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override {
return new SkipGroupnormActPluginDynamic(serial_data, serial_length);
}
};
REGISTER_TRT_PLUGIN_V2(SkipGroupnormActPluginDynamicCreator);
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,340 @@
/* Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
Copyright (c) 2019-2022, NVIDIA CORPORATION. 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 <algorithm>
#include "paddle/fluid/inference/tensorrt/plugin/skip_merge_layernorm_op_plugin.h"
#include "paddle/phi/kernels/funcs/math_cuda_utils.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
#define FINAL_MASK 0xffffffff
template <typename T>
__global__ void merge_layernorm_v2(T *out,
const T *__restrict input0,
const T *__restrict input1,
const T *__restrict gamma,
const T *__restrict beta,
const float layernorm_eps,
int batch,
int H,
int W,
int n) {
// input is [batch, 2*H, 2*W, n/4]
// output is [batch, H, W, n]
// grid (W, H, batch)
// block (n)
const int kIte = 4;
const int tid = threadIdx.x;
const int W_idx = blockIdx.x;
const int H_idx = blockIdx.y;
const size_t batch_offset = blockIdx.z * H * W * n;
const int input_H_stride = W * n / 2;
const int output_H_stride = W * n;
const int n_4 = n >> 2;
__shared__ float s_mean;
__shared__ float s_variance;
float mean = 0.0f;
float variance = 0.0f;
float local_out[kIte];
float sum = 0.0f;
#pragma unroll
for (int i = 0; i < kIte; i++) {
int col_id = i * blockDim.x + tid;
if (col_id < n) {
int part_id = col_id / n_4;
int offset_in_W = part_id / 2;
int offset_in_H = part_id % 2;
size_t input_id = batch_offset +
(2 * H_idx + offset_in_H) * input_H_stride +
(2 * W_idx + offset_in_W) * n_4 + (col_id % n_4);
local_out[i] = static_cast<float>(__ldg(input0 + input_id));
local_out[i] += static_cast<float>(__ldg(input1 + input_id));
sum += local_out[i];
}
}
mean = phi::funcs::BlockReduceSum<float>(sum, FINAL_MASK);
if (tid == 0) {
s_mean = mean / n;
}
__syncthreads();
float var = 0.0f;
#pragma unroll
for (int i = 0; i < kIte; i++) {
int col_id = i * blockDim.x + tid;
if (col_id < n) {
local_out[i] = local_out[i] - s_mean;
var += local_out[i] * local_out[i];
}
}
variance = phi::funcs::BlockReduceSum<float>(var, FINAL_MASK);
if (tid == 0) {
s_variance = rsqrtf(variance / n + layernorm_eps);
}
__syncthreads();
#pragma unroll
for (int i = 0; i < kIte; i++) {
int col_id = i * blockDim.x + tid;
if (col_id < n) {
size_t output_idx =
batch_offset + H_idx * output_H_stride + W_idx * n + col_id;
out[output_idx] =
static_cast<T>(local_out[i] * s_variance *
static_cast<float>(__ldg(&gamma[col_id])) +
static_cast<float>(__ldg(&beta[col_id])));
}
}
}
template <typename T>
void invokeMergeLayernorm(T *output,
const T *input0,
const T *input1,
const T *gamma,
const T *beta,
float layernorm_eps,
int batch,
int H,
int W,
int n,
cudaStream_t stream) {
if ((W % 2 != 0) || (H % 2 != 0)) {
PADDLE_THROW(common::errors::InvalidArgument(
"H(W) of merge layernorm should be a multiple of 2."));
}
dim3 grid(W / 2, H / 2, batch);
int blockSize = (n + 31) / 32 * 32;
merge_layernorm_v2<T><<<grid, blockSize, 0, stream>>>(output,
input0,
input1,
gamma,
beta,
layernorm_eps,
batch,
H / 2,
W / 2,
n * 4);
}
template void invokeMergeLayernorm<float>(float *output,
const float *input0,
const float *input1,
const float *gamma,
const float *beta,
float layernorm_eps,
int batch,
int H,
int W,
int n,
cudaStream_t stream);
template void invokeMergeLayernorm<half>(half *output,
const half *input0,
const half *input1,
const half *gamma,
const half *beta,
float layernorm_eps,
int batch,
int H,
int W,
int n,
cudaStream_t stream);
template <typename T>
static void convertAndCopy(const std::vector<float> &host, T *dev) {
T *host_ptr = new T[host.size()];
std::transform(host.begin(), host.end(), host_ptr, [](float x) {
return static_cast<T>(x);
});
cudaMemcpy(dev, host_ptr, sizeof(T) * host.size(), cudaMemcpyHostToDevice);
delete host_ptr;
}
void SkipMergeLayernormPluginDynamic::configurePlugin(
const nvinfer1::DynamicPluginTensorDesc *in,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc *out,
int nbOutputs) TRT_NOEXCEPT {}
SkipMergeLayernormPluginDynamic::SkipMergeLayernormPluginDynamic(
const float *bias_d,
const size_t bias_num,
const float *scale_d,
const size_t scale_num,
const float eps,
const int begin_norm_axis,
const bool with_fp16,
std::shared_ptr<void> bias_device,
std::shared_ptr<void> scale_device)
: eps_(eps),
begin_norm_axis_(begin_norm_axis),
with_fp16_(with_fp16),
bias_device_(bias_device),
scale_device_(scale_device) {
bias_.resize(bias_num);
scale_.resize(scale_num);
std::copy(bias_d, bias_d + bias_num, bias_.data());
std::copy(scale_d, scale_d + scale_num, scale_.data());
int type_size = with_fp16_ ? sizeof(half) : sizeof(float);
if (bias_device_ == nullptr) {
void *p;
cudaMalloc(&p, bias_num * type_size);
bias_device_.reset(p, [](void *ptr) { cudaFree(ptr); });
if (with_fp16) {
convertAndCopy<half>(bias_, reinterpret_cast<half *>(p));
} else {
convertAndCopy<float>(bias_, reinterpret_cast<float *>(p));
}
}
if (scale_device_ == nullptr) {
void *p;
cudaMalloc(&p, scale_num * type_size);
scale_device_.reset(p, [](void *ptr) { cudaFree(ptr); });
if (with_fp16) {
convertAndCopy<half>(scale_, reinterpret_cast<half *>(p));
} else {
convertAndCopy<float>(scale_, reinterpret_cast<float *>(p));
}
}
}
bool SkipMergeLayernormPluginDynamic::supportsFormatCombination(
int pos,
const nvinfer1::PluginTensorDesc *in_out,
int nb_inputs,
int nb_outputs) TRT_NOEXCEPT {
PADDLE_ENFORCE_NOT_NULL(
in_out,
common::errors::InvalidArgument("The input of MergeLayernorm "
"plugin should not be nullptr."));
PADDLE_ENFORCE_LT(
pos,
nb_inputs + nb_outputs,
common::errors::InvalidArgument("The pos(%d) should be less than the "
"num(%d) of the input and the output.",
pos,
nb_inputs + nb_outputs));
const nvinfer1::PluginTensorDesc &in = in_out[pos];
if (pos == 0) {
if (with_fp16_) {
return in.type == nvinfer1::DataType::kHALF &&
in.format == nvinfer1::TensorFormat::kLINEAR;
} else {
return in.type == nvinfer1::DataType::kFLOAT &&
in.format == nvinfer1::TensorFormat::kLINEAR;
}
}
const nvinfer1::PluginTensorDesc &prev = in_out[pos - 1];
// output
return in.type == prev.type && in.format == prev.format;
}
nvinfer1::DataType SkipMergeLayernormPluginDynamic::getOutputDataType(
int index,
const nvinfer1::DataType *input_types,
int nb_inputs) const TRT_NOEXCEPT {
PADDLE_ENFORCE_EQ(index,
0,
common::errors::InvalidArgument(
"The MergeLayernorm only has one input, so the "
"index value should be 0, but get %d.",
index));
return input_types[0];
}
nvinfer1::DimsExprs SkipMergeLayernormPluginDynamic::getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs *inputs,
int nb_inputs,
nvinfer1::IExprBuilder &expr_builder) TRT_NOEXCEPT {
nvinfer1::DimsExprs ret;
ret.nbDims = 3;
ret.d[0] = inputs[0].d[0];
ret.d[1] = expr_builder.operation(nvinfer1::DimensionOperation::kFLOOR_DIV,
*inputs[0].d[1],
*expr_builder.constant(4));
ret.d[2] = expr_builder.operation(nvinfer1::DimensionOperation::kPROD,
*inputs[0].d[2],
*expr_builder.constant(4));
return ret;
}
int SkipMergeLayernormPluginDynamic::enqueue(
const nvinfer1::PluginTensorDesc *input_desc,
const nvinfer1::PluginTensorDesc *output_desc,
const void *const *inputs,
void *const *outputs,
void *workspace,
cudaStream_t stream) TRT_NOEXCEPT {
const auto &input_dims = input_desc[0].dims;
auto input_type = input_desc[0].type;
int batch = input_dims.d[0];
int input_resolution = static_cast<int>(std::sqrt(input_dims.d[1]));
int dim = static_cast<int>(input_dims.d[2]);
PADDLE_ENFORCE_EQ(
input_resolution * input_resolution,
input_dims.d[1],
common::errors::InvalidArgument(
"The MergeLayernorm TRT Plugin get invalid input_resolution %d",
input_resolution));
if (input_type == nvinfer1::DataType::kFLOAT) {
VLOG(3) << "TRT Plugin DataType selected. MergeLayernorm-->fp32";
invokeMergeLayernorm<float>(
reinterpret_cast<float *>(outputs[0]),
reinterpret_cast<const float *>(inputs[0]),
reinterpret_cast<const float *>(inputs[1]),
reinterpret_cast<const float *>(scale_device_.get()),
reinterpret_cast<const float *>(bias_device_.get()),
eps_,
batch,
input_resolution,
input_resolution,
dim,
stream);
} else if (input_type == nvinfer1::DataType::kHALF) {
VLOG(3) << "TRT Plugin DataType selected. MergeLayernorm-->fp16";
invokeMergeLayernorm<half>(
reinterpret_cast<half *>(outputs[0]),
reinterpret_cast<const half *>(inputs[0]),
reinterpret_cast<const half *>(inputs[1]),
reinterpret_cast<const half *>(scale_device_.get()),
reinterpret_cast<const half *>(bias_device_.get()),
eps_,
batch,
input_resolution,
input_resolution,
dim,
stream);
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"The MergeLayernorm TRT Plugin's input type should be float or half."));
}
return cudaGetLastError() != cudaSuccess;
}
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,141 @@
/* Copyright (c) 2022 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. */
#pragma once
#include <memory>
#include <vector>
#include "paddle/fluid/framework/tensor.h"
#include "paddle/fluid/framework/tensor_util.h"
#include "paddle/fluid/inference/tensorrt/engine.h"
#include "paddle/fluid/inference/tensorrt/plugin/trt_plugin.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
class SkipMergeLayernormPluginDynamic : public DynamicPluginTensorRT {
public:
SkipMergeLayernormPluginDynamic(const float* bias_d,
const size_t bias_num,
const float* scale_d,
const size_t scale_num,
const float eps,
const int begin_norm_axis,
const bool with_fp16,
std::shared_ptr<void> bias_device = nullptr,
std::shared_ptr<void> scale_device = nullptr);
SkipMergeLayernormPluginDynamic(void const* serialData, size_t serialLength) {
DeserializeValue(&serialData, &serialLength, &bias_);
DeserializeValue(&serialData, &serialLength, &scale_);
DeserializeValue(&serialData, &serialLength, &eps_);
DeserializeValue(&serialData, &serialLength, &begin_norm_axis_);
DeserializeValue(&serialData, &serialLength, &with_fp16_);
}
nvinfer1::IPluginV2DynamicExt* clone() const TRT_NOEXCEPT override {
return new SkipMergeLayernormPluginDynamic(bias_.data(),
bias_.size(),
scale_.data(),
scale_.size(),
eps_,
begin_norm_axis_,
with_fp16_,
bias_device_,
scale_device_);
}
const char* getPluginType() const TRT_NOEXCEPT override {
return "skip_merge_layernorm_plugin_dynamic";
}
int getNbOutputs() const TRT_NOEXCEPT override { return 1; }
int initialize() TRT_NOEXCEPT override { return 0; }
size_t getSerializationSize() const TRT_NOEXCEPT override {
return SerializedSize(bias_) + SerializedSize(scale_) +
SerializedSize(eps_) + SerializedSize(begin_norm_axis_) +
SerializedSize(with_fp16_);
}
void serialize(void* buffer) const TRT_NOEXCEPT override {
SerializeValue(&buffer, bias_);
SerializeValue(&buffer, scale_);
SerializeValue(&buffer, eps_);
SerializeValue(&buffer, begin_norm_axis_);
SerializeValue(&buffer, with_fp16_);
}
nvinfer1::DimsExprs getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs* inputs,
int nb_inputs,
nvinfer1::IExprBuilder& expr_builder) // NOLINT
TRT_NOEXCEPT override;
bool supportsFormatCombination(int pos,
const nvinfer1::PluginTensorDesc* inOut,
int nbInputs,
int nbOutputs) TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::DynamicPluginTensorDesc* in,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc* out,
int nbOutputs) TRT_NOEXCEPT override;
size_t getWorkspaceSize(const nvinfer1::PluginTensorDesc* inputs,
int nbInputs,
const nvinfer1::PluginTensorDesc* outputs,
int nbOutputs) const TRT_NOEXCEPT override {
return 0;
}
int enqueue(const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* inputTypes,
int nbInputs) const
TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override { delete this; }
private:
std::vector<float> bias_;
std::vector<float> scale_;
float eps_;
int begin_norm_axis_;
bool with_fp16_;
std::shared_ptr<void> bias_device_ = nullptr;
std::shared_ptr<void> scale_device_ = nullptr;
};
class SkipMergeLayernormPluginDynamicCreator : public TensorRTPluginCreator {
public:
const char* getPluginName() const TRT_NOEXCEPT override {
return "skip_merge_layernorm_plugin_dynamic";
}
const char* getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
nvinfer1::IPluginV2* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override {
return new SkipMergeLayernormPluginDynamic(serial_data, serial_length);
}
};
REGISTER_TRT_PLUGIN_V2(SkipMergeLayernormPluginDynamicCreator);
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,338 @@
// Copyright (c) 2018 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 <cuda_fp16.h>
#include <thrust/device_vector.h>
#include <algorithm>
#include "paddle/fluid/inference/tensorrt/plugin/split_op_plugin.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
template <typename T>
__device__ int upper_bound(T const* vals, int n, T const& key) {
int i = 0;
while (n > 0) {
int m = n / 2;
int j = i + m;
if (!(key < vals[j])) {
i = j + 1;
n -= m + 1;
} else {
n = m;
}
}
return i;
}
nvinfer1::Dims SplitPlugin::getOutputDimensions(
int index, const nvinfer1::Dims* input_dims, int num_inputs) TRT_NOEXCEPT {
PADDLE_ENFORCE_EQ(num_inputs,
1,
common::errors::InvalidArgument(
"Invalid number of inputs of split TRT plugin. "
"Expected 1, received %d.",
num_inputs));
PADDLE_ENFORCE_LT(
index,
this->getNbOutputs(),
common::errors::InvalidArgument(
"Index of output should be less than the total number of outputs in "
"split TensorRT plugin. Received index = %d >= total outputs = %d",
index,
this->getNbOutputs()));
nvinfer1::Dims output_dims = input_dims[0];
output_dims.d[axis_] = output_length_.at(index);
return output_dims;
}
void SplitPlugin::shareData(const SplitPlugin* another) {
outer_rows_ = another->outer_rows_;
inner_cols_ = another->inner_cols_;
same_shape_ = another->same_shape_;
axis_shape_ = another->axis_shape_;
segment_offsets_ = another->segment_offsets_;
}
int SplitPlugin::initialize() TRT_NOEXCEPT {
PADDLE_ENFORCE_LE(axis_,
nvinfer1::Dims::MAX_DIMS,
common::errors::InvalidArgument(
"Axis dimension exceeds max dimension in TensorRT. "
"Received axis = %d > MAX_DIMS = %d",
axis_,
nvinfer1::Dims::MAX_DIMS));
// notice input dims is [C, H, W]
nvinfer1::Dims dims = this->getInputDims(0);
outer_rows_ = 1;
inner_cols_ = 1;
for (int i = 0; i < axis_; ++i) {
outer_rows_ *= dims.d[i];
}
for (int i = axis_ + 1; i < dims.nbDims; ++i) {
inner_cols_ *= dims.d[i];
}
same_shape_ = true;
std::vector<int> segment_offsets(1, 0);
for (int i = 0; i < this->getNbOutputs(); ++i) {
if (output_length_[i] != output_length_[0]) {
same_shape_ = false;
}
segment_offsets.push_back(segment_offsets.back() + output_length_[i]);
}
axis_shape_ = dims.d[axis_];
segment_offsets_ = std::move(segment_offsets);
return 0;
}
// nothing to release according to initialize
void SplitPlugin::terminate() TRT_NOEXCEPT {}
// The following part of the code refers to onnx-tensorrt
// https://github.com/onnx/onnx-tensorrt/blob/master/Split.cu
template <typename T>
__global__ void split_kernel(int nsegment,
int const* __restrict__ segment_offsets,
T const* __restrict__ idata,
T* const* odatas,
int inner_cols,
int axis_shape,
int outer_rows) {
int x0 = threadIdx.x + blockIdx.x * blockDim.x;
int src_y0 = threadIdx.y + blockIdx.y * blockDim.y;
int z0 = threadIdx.z + blockIdx.z * blockDim.z;
for (int z = z0; z < outer_rows; z += blockDim.z * gridDim.z) {
for (int src_y = src_y0; src_y < axis_shape;
src_y += blockDim.y * gridDim.y) {
for (int x = x0; x < inner_cols; x += blockDim.x * gridDim.x) {
int segment = upper_bound(segment_offsets, nsegment, src_y) - 1;
int dst_y = src_y - segment_offsets[segment];
int dst_ny = segment_offsets[segment + 1] - segment_offsets[segment];
odatas[segment][x + inner_cols * (dst_y + dst_ny * z)] =
idata[x + inner_cols * (src_y + axis_shape * z)];
}
}
}
}
int SplitPlugin::enqueue(int batchSize,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT {
// this two thrust variables declared here , not with in .h
// to avoid compiling error in cuda 11.6
thrust::device_vector<int> d_segment_offsets = segment_offsets_;
thrust::device_vector<float*> d_output_ptrs;
d_output_ptrs.resize(segment_offsets_.size(), nullptr);
const int* d_segment_offsets_ptr =
thrust::raw_pointer_cast(&d_segment_offsets[0]);
float const* input_ptr = reinterpret_cast<float const*>(inputs[0]);
float* const* h_odatas = reinterpret_cast<float* const*>(outputs);
float** output_ptrs = thrust::raw_pointer_cast(&d_output_ptrs[0]);
PADDLE_ENFORCE_GPU_SUCCESS(
cudaMemcpyAsync(output_ptrs,
h_odatas,
d_output_ptrs.size() * sizeof(float*),
cudaMemcpyHostToDevice,
stream));
int outer_rows = outer_rows_ * batchSize;
dim3 block(32, 16);
dim3 grid(std::min((inner_cols_ - 1) / block.x + 1, 65535u),
std::min((axis_shape_ - 1) / block.y + 1, 65535u),
std::min((outer_rows_ - 1) / block.z + 1, 65535u));
split_kernel<<<grid, block, 0, stream>>>(segment_offsets_.size(),
d_segment_offsets_ptr,
input_ptr,
output_ptrs,
inner_cols_,
axis_shape_,
outer_rows);
return cudaGetLastError() != cudaSuccess;
}
// Dynamic Plugin below.
int SplitPluginDynamic::initialize() TRT_NOEXCEPT { return 0; }
size_t SplitPluginDynamic::getSerializationSize() const TRT_NOEXCEPT {
return SerializedSize(axis_) + SerializedSize(output_length_) +
SerializedSize(with_fp16_);
}
void SplitPluginDynamic::serialize(void* buffer) const TRT_NOEXCEPT {
SerializeValue(&buffer, axis_);
SerializeValue(&buffer, output_length_);
SerializeValue(&buffer, with_fp16_);
}
nvinfer1::DimsExprs SplitPluginDynamic::getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs* inputs,
int nb_inputs,
nvinfer1::IExprBuilder& expr_builder) TRT_NOEXCEPT {
PADDLE_ENFORCE_EQ(nb_inputs,
1,
common::errors::InvalidArgument(
"The Split plugin should be only one input."));
PADDLE_ENFORCE_LT(output_index,
output_length_.size(),
common::errors::InvalidArgument(
"When GetOutputDimensions, the index(%d) should not "
"greater the num(%d) of the outputs.",
output_index,
output_length_.size()));
nvinfer1::DimsExprs output_dims = inputs[0];
output_dims.d[axis_] = expr_builder.constant(output_length_.at(output_index));
return output_dims;
}
bool SplitPluginDynamic::supportsFormatCombination(
int pos,
const nvinfer1::PluginTensorDesc* in_out,
int nb_inputs,
int nb_outputs) TRT_NOEXCEPT {
PADDLE_ENFORCE_NOT_NULL(
in_out,
common::errors::InvalidArgument(
"The input of split plugin should not be nullptr."));
PADDLE_ENFORCE_LT(
pos,
nb_inputs + nb_outputs,
common::errors::InvalidArgument("The pos(%d) should be less than the "
"num(%d) of the input and the output.",
pos,
nb_inputs + nb_outputs));
(in_out && pos < (nb_inputs + nb_outputs));
const nvinfer1::PluginTensorDesc& in = in_out[pos];
if (pos == 0) {
if (with_fp16_) {
return (in.type == nvinfer1::DataType::kFLOAT ||
in.type == nvinfer1::DataType::kHALF) &&
(in.format == nvinfer1::TensorFormat::kLINEAR);
} else {
return (in.type == nvinfer1::DataType::kFLOAT) &&
(in.format == nvinfer1::TensorFormat::kLINEAR);
}
}
const nvinfer1::PluginTensorDesc& prev = in_out[pos - 1];
// output
return in.type == prev.type && in.format == prev.format;
}
nvinfer1::DataType SplitPluginDynamic::getOutputDataType(
int index,
const nvinfer1::DataType* input_types,
int nb_inputs) const TRT_NOEXCEPT {
return input_types[0];
}
int SplitPluginDynamic::enqueue(const nvinfer1::PluginTensorDesc* input_desc,
const nvinfer1::PluginTensorDesc* output_desc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT {
auto input_dims = input_desc[0].dims;
int outer_rows = 1;
int inner_cols = 1;
// with batch
for (int i = 0; i < axis_; i++) {
outer_rows *= input_dims.d[i];
}
for (int i = axis_ + 1; i < input_dims.nbDims; i++) {
inner_cols *= input_dims.d[i];
}
std::vector<int> segment_offsets(1, 0);
for (int i = 0; i < this->getNbOutputs(); i++) {
segment_offsets.push_back(segment_offsets.back() + output_length_[i]);
}
int axis_shape = input_dims.d[axis_];
thrust::device_vector<int> d_segment_offsets = segment_offsets;
const int* d_segment_offsets_ptr =
thrust::raw_pointer_cast(&d_segment_offsets[0]);
dim3 block(32, 16);
dim3 grid(std::min((inner_cols - 1) / block.x + 1, 65535u),
std::min((axis_shape - 1) / block.y + 1, 65535u),
std::min((outer_rows - 1) / block.z + 1, 65535u));
auto input_type = input_desc[0].type;
if (input_type == nvinfer1::DataType::kFLOAT) {
VLOG(1) << "TRT Plugin DataType selected. Split-->fp32";
thrust::device_vector<float*> d_output_ptrs;
d_output_ptrs.resize(this->getNbOutputs(), nullptr);
const float* input_ptr = static_cast<const float*>(inputs[0]);
float* const* h_odatas = reinterpret_cast<float* const*>(outputs);
float** output_ptrs = thrust::raw_pointer_cast(&d_output_ptrs[0]);
PADDLE_ENFORCE_GPU_SUCCESS(
cudaMemcpyAsync(output_ptrs,
h_odatas,
d_output_ptrs.size() * sizeof(float*),
cudaMemcpyHostToDevice,
stream));
split_kernel<<<grid, block, 0, stream>>>(d_segment_offsets.size(),
d_segment_offsets_ptr,
input_ptr,
output_ptrs,
inner_cols,
axis_shape,
outer_rows);
} else if (input_type == nvinfer1::DataType::kHALF) {
VLOG(1) << "TRT Plugin DataType selected. Split-->fp16";
thrust::device_vector<half*> d_output_ptrs;
d_output_ptrs.resize(this->getNbOutputs(), nullptr);
const half* input_ptr = static_cast<const half*>(inputs[0]);
half* const* h_odatas = reinterpret_cast<half* const*>(outputs);
half** output_ptrs = thrust::raw_pointer_cast(&d_output_ptrs[0]);
PADDLE_ENFORCE_GPU_SUCCESS(
cudaMemcpyAsync(output_ptrs,
h_odatas,
d_output_ptrs.size() * sizeof(half*),
cudaMemcpyHostToDevice,
stream));
split_kernel<<<grid, block, 0, stream>>>(d_segment_offsets.size(),
d_segment_offsets_ptr,
input_ptr,
output_ptrs,
inner_cols,
axis_shape,
outer_rows);
}
return cudaGetLastError() != cudaSuccess;
}
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,264 @@
// Copyright (c) 2018 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.
#pragma once
#include <string>
#include <utility>
#include <vector>
#include "paddle/fluid/inference/tensorrt/plugin/trt_plugin.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
class SplitPlugin : public PluginTensorRTV2Ext {
public:
SplitPlugin() {}
SplitPlugin(int axis, std::vector<int> const& output_lengths, bool with_fp16)
: axis_(axis), same_shape_(true), output_length_(output_lengths) {
with_fp16_ = with_fp16;
}
SplitPlugin(void const* serial_data, size_t serial_length) {
deserializeBase(serial_data, serial_length);
DeserializeValue(&serial_data, &serial_length, &axis_);
DeserializeValue(&serial_data, &serial_length, &output_length_);
}
nvinfer1::IPluginV2Ext* clone() const TRT_NOEXCEPT override {
SplitPlugin* ptr = new SplitPlugin(axis_, output_length_, with_fp16_);
ptr->setPluginNamespace(this->getPluginNamespace());
ptr->shareData(this);
return ptr;
}
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* input_types,
int nb_inputs) const
TRT_NOEXCEPT override {
return input_types[0];
}
const char* getPluginType() const TRT_NOEXCEPT override {
return "split_plugin_v2ext";
}
int getNbOutputs() const TRT_NOEXCEPT override {
return output_length_.size();
}
nvinfer1::Dims getOutputDimensions(int index,
const nvinfer1::Dims* input_dims,
int num_inputs) TRT_NOEXCEPT override;
int initialize() TRT_NOEXCEPT override;
void terminate() TRT_NOEXCEPT override;
int enqueue(int batch_size,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override { delete this; }
protected:
size_t getSerializationSize() const TRT_NOEXCEPT override {
return SerializedSize(axis_) + SerializedSize(output_length_) +
getBaseSerializationSize();
}
void serialize(void* buffer) const TRT_NOEXCEPT override {
serializeBase(buffer);
SerializeValue(&buffer, axis_);
SerializeValue(&buffer, output_length_);
}
int axis_;
int outer_rows_;
int inner_cols_;
int axis_shape_;
bool same_shape_;
std::vector<int> output_length_;
std::vector<int> segment_offsets_;
private:
void shareData(const SplitPlugin* another);
};
class SplitPluginCreator : public nvinfer1::IPluginCreator {
public:
SplitPluginCreator() {}
const char* getPluginName() const TRT_NOEXCEPT override {
return "split_plugin_v2ext";
}
const char* getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
const nvinfer1::PluginFieldCollection* getFieldNames() TRT_NOEXCEPT override {
return &field_collection_;
}
nvinfer1::IPluginV2* createPlugin(const char* name,
const nvinfer1::PluginFieldCollection* fc)
TRT_NOEXCEPT override {
// not implemented
return nullptr;
}
nvinfer1::IPluginV2* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override {
auto plugin = new SplitPlugin(serial_data, serial_length);
return plugin;
}
void setPluginNamespace(const char* lib_namespace) TRT_NOEXCEPT override {
plugin_namespace_ = lib_namespace;
}
const char* getPluginNamespace() const TRT_NOEXCEPT override {
return plugin_namespace_.c_str();
}
private:
std::string plugin_namespace_;
std::string plugin_name_;
nvinfer1::PluginFieldCollection field_collection_{0, nullptr};
std::vector<nvinfer1::PluginField> plugin_attributes_;
};
REGISTER_TRT_PLUGIN_V2(SplitPluginCreator);
class SplitPluginDynamic : public DynamicPluginTensorRT {
public:
SplitPluginDynamic(int axis,
std::vector<int> const& output_lengths,
bool with_fp16)
: axis_(axis), output_length_(output_lengths) {
with_fp16_ = with_fp16;
}
SplitPluginDynamic(void const* serial_data, size_t serial_length) {
DeserializeValue(&serial_data, &serial_length, &axis_);
DeserializeValue(&serial_data, &serial_length, &output_length_);
DeserializeValue(&serial_data, &serial_length, &with_fp16_);
}
nvinfer1::IPluginV2DynamicExt* clone() const TRT_NOEXCEPT override {
return new SplitPluginDynamic(axis_, output_length_, with_fp16_);
}
const char* getPluginType() const TRT_NOEXCEPT override {
return "split_plugin";
}
int getNbOutputs() const TRT_NOEXCEPT override {
return output_length_.size();
}
int initialize() TRT_NOEXCEPT override;
size_t getSerializationSize() const TRT_NOEXCEPT override;
void serialize(void* buffer) const TRT_NOEXCEPT override;
nvinfer1::DimsExprs getOutputDimensions(
int outputIndex,
const nvinfer1::DimsExprs* inputs,
int nbInputs,
nvinfer1::IExprBuilder& exprBuilder) // NOLINT
TRT_NOEXCEPT override;
bool supportsFormatCombination(int pos,
const nvinfer1::PluginTensorDesc* inOut,
int nbInputs,
int nbOutputs) TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::DynamicPluginTensorDesc* in,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc* out,
int nbOutputs) TRT_NOEXCEPT override {}
size_t getWorkspaceSize(const nvinfer1::PluginTensorDesc* inputs,
int nbInputs,
const nvinfer1::PluginTensorDesc* outputs,
int nbOutputs) const TRT_NOEXCEPT override {
return 0;
}
int enqueue(const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* inputTypes,
int nbInputs) const
TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override { delete this; }
private:
int axis_;
std::vector<int> output_length_;
};
class SplitPluginDynamicCreator : public nvinfer1::IPluginCreator {
public:
SplitPluginDynamicCreator() {}
const char* getPluginName() const TRT_NOEXCEPT override {
return "split_plugin";
}
const char* getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
const nvinfer1::PluginFieldCollection* getFieldNames() TRT_NOEXCEPT override {
return &field_collection_;
}
nvinfer1::IPluginV2* createPlugin(const char* name,
const nvinfer1::PluginFieldCollection* fc)
TRT_NOEXCEPT override {
return nullptr;
}
nvinfer1::IPluginV2* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override {
auto plugin = new SplitPluginDynamic(serial_data, serial_length);
return plugin;
}
void setPluginNamespace(const char* lib_namespace) TRT_NOEXCEPT override {
plugin_namespace_ = lib_namespace;
}
const char* getPluginNamespace() const TRT_NOEXCEPT override {
return plugin_namespace_.c_str();
}
private:
std::string plugin_namespace_;
std::string plugin_name_;
nvinfer1::PluginFieldCollection field_collection_{0, nullptr};
std::vector<nvinfer1::PluginField> plugin_attributes_;
};
REGISTER_TRT_PLUGIN_V2(SplitPluginDynamicCreator);
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,180 @@
/* Copyright (c) 2022, PaddlePaddle Authors, NVIDIA CORPORATION. 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.
*/
#pragma once
#include <algorithm>
#include <cassert>
#include <iostream>
#include <stdexcept>
#include <vector>
#include "NvInfer.h"
#include "NvInferPlugin.h"
#include "paddle/fluid/inference/tensorrt/engine.h"
#include "paddle/fluid/inference/tensorrt/plugin/trt_plugin.h"
#include "paddle/phi/backends/dynload/cusparseLt.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
class SpmmPluginDynamic : public nvinfer1::IPluginV2DynamicExt {
public:
enum class Activation { kNone, kRelu, kGelu };
SpmmPluginDynamic(const std::string& name,
const nvinfer1::DataType precision,
const int out_dim,
const nvinfer1::Weights& weight,
const nvinfer1::Weights& bias,
Activation activation);
// The second constructor is for clone member function
SpmmPluginDynamic(const std::string& name,
const nvinfer1::DataType precision,
const int out_dim,
const int k,
const void* weight,
size_t compressed_size,
const void* bias,
bool is_configured,
const int m_max,
const int optim_alg,
Activation activation);
SpmmPluginDynamic(const std::string name, const void* data, size_t length);
SpmmPluginDynamic() = delete;
nvinfer1::IPluginV2DynamicExt* clone() const noexcept override;
nvinfer1::DimsExprs getOutputDimensions(
int outputIndex,
const nvinfer1::DimsExprs* inputs,
int nbInputs,
nvinfer1::IExprBuilder& exprBuilder) noexcept override;
bool supportsFormatCombination(int pos,
const nvinfer1::PluginTensorDesc* inOut,
int nbInputs,
int nbOutputs) noexcept override;
void configurePlugin(const nvinfer1::DynamicPluginTensorDesc* in,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc* out,
int nbOutputs) noexcept override;
size_t getWorkspaceSize(const nvinfer1::PluginTensorDesc* inputs,
int nbInputs,
const nvinfer1::PluginTensorDesc* outputs,
int nbOutputs) const noexcept override;
int enqueue(const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) noexcept override;
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* inputTypes,
int nbInputs) const noexcept override;
const char* getPluginType() const noexcept override;
const char* getPluginVersion() const noexcept override;
int getNbOutputs() const noexcept override;
int initialize() noexcept override;
void terminate() noexcept override;
size_t getSerializationSize() const noexcept override;
void serialize(void* buffer) const noexcept override;
void destroy() noexcept override;
void setPluginNamespace(const char* pluginNamespace) noexcept override;
const char* getPluginNamespace() const noexcept override;
private:
struct cusparseLtContext {
cusparseLtHandle_t handle;
cusparseLtMatDescriptor_t matA;
cusparseLtMatDescriptor_t matB;
cusparseLtMatDescriptor_t matC;
cusparseLtMatmulDescriptor_t matmul;
cusparseLtMatmulAlgSelection_t alg_sel;
cusparseLtMatmulPlan_t plan;
cusparseLtContext();
~cusparseLtContext();
size_t workspace_size{0};
bool is_initialized{false};
int activation{0};
float relu_upper_bound{0};
float relu_threshold{0};
void init(int m,
int n,
int k,
cudaDataType_t type,
void* bias_ptr,
SpmmPluginDynamic::Activation activation);
void setAlgo(int id);
void destroy();
void compressMatB(int n,
int k,
cudaDataType_t type,
void* src,
void** dest,
size_t* compressed_size);
}; // struct SpmmPluginDynamic::cusparseLtContext
const std::string layer_name_;
std::string namespace_;
nvinfer1::DataType precision_;
size_t precision_size_;
size_t
element_size_; // size of weight (float if INT8 or FLOAT; half if HALF)
int out_dim_;
int k_;
int m_max_;
bool is_configured_; // already get m, scale bias, and search the optim alg
// or not
int optim_alg_; // the index of optimal algorithm
float weight_scale_; // record the weight scale from constructor
void* weight_compressed_; // host compressed weight
void* weight_compressed_dev_; // device compressed weight
std::shared_ptr<void>
weight_compressed_dev_global_; // shared pointer to the
// device compressed weight
size_t compressed_size_; // size of compressed weight
bool has_bias_; // there is bias or not
void* bias_; // host bias
void* bias_dev_; // device bias
Activation activation_; // record the activation type
cusparseLtContext spmm_context_;
}; // class SpmmPluginDynamic
class SpmmPluginDynamicCreator : public nvinfer1::IPluginCreator {
public:
SpmmPluginDynamicCreator();
const char* getPluginName() const noexcept override;
const char* getPluginVersion() const noexcept override;
const nvinfer1::PluginFieldCollection* getFieldNames() noexcept override;
nvinfer1::IPluginV2* createPlugin(
const char* name,
const nvinfer1::PluginFieldCollection* fc) noexcept override;
nvinfer1::IPluginV2* deserializePlugin(const char* name,
const void* serialData,
size_t serialLength) noexcept override;
void setPluginNamespace(const char* pluginNamespace) noexcept override;
const char* getPluginNamespace() const noexcept override;
private:
static nvinfer1::PluginFieldCollection field_collection_;
static std::vector<nvinfer1::PluginField> plugin_attr_;
std::string namespace_;
}; // class SpmmPluginDynamicCreator
REGISTER_TRT_PLUGIN_V2(SpmmPluginDynamicCreator);
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,284 @@
// Copyright (c) 2018 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 <cassert>
#include <cstring>
#include <vector>
#include "paddle/fluid/inference/tensorrt/plugin/stack_op_plugin.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
StackPluginDynamic::StackPluginDynamic(int axis, int num_stack, bool with_fp16)
: axis_(axis), num_stack_(num_stack) {
with_fp16_ = with_fp16;
}
StackPluginDynamic::StackPluginDynamic(void const* serial_data,
size_t serial_length) {
DeserializeValue(&serial_data, &serial_length, &axis_);
DeserializeValue(&serial_data, &serial_length, &num_stack_);
DeserializeValue(&serial_data, &serial_length, &with_fp16_);
}
StackPluginDynamic::~StackPluginDynamic() = default;
nvinfer1::IPluginV2DynamicExt* StackPluginDynamic::clone() const TRT_NOEXCEPT {
return new StackPluginDynamic(axis_, num_stack_, with_fp16_);
}
const char* StackPluginDynamic::getPluginType() const TRT_NOEXCEPT {
return "stack_plugin";
}
int StackPluginDynamic::getNbOutputs() const TRT_NOEXCEPT { return 1; }
int StackPluginDynamic::initialize() TRT_NOEXCEPT { return 0; }
size_t StackPluginDynamic::getSerializationSize() const TRT_NOEXCEPT {
size_t serialize_size = 0;
serialize_size += SerializedSize(axis_);
serialize_size += SerializedSize(num_stack_);
serialize_size += SerializedSize(with_fp16_);
return serialize_size;
}
void StackPluginDynamic::serialize(void* buffer) const TRT_NOEXCEPT {
SerializeValue(&buffer, axis_);
SerializeValue(&buffer, num_stack_);
SerializeValue(&buffer, with_fp16_);
}
nvinfer1::DimsExprs StackPluginDynamic::getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs* inputs,
int nb_inputs,
nvinfer1::IExprBuilder& expr_builder) TRT_NOEXCEPT {
nvinfer1::DimsExprs output(inputs[0]);
output.nbDims = inputs[0].nbDims + 1;
for (int i = inputs[0].nbDims; i > axis_; --i) {
output.d[i] = inputs[0].d[i - 1];
}
output.d[axis_] = expr_builder.constant(nb_inputs);
return output;
}
void StackPluginDynamic::configurePlugin(
const nvinfer1::DynamicPluginTensorDesc* in,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc* out,
int nbOutputs) TRT_NOEXCEPT {}
size_t StackPluginDynamic::getWorkspaceSize(
const nvinfer1::PluginTensorDesc* inputs,
int nbInputs,
const nvinfer1::PluginTensorDesc* outputs,
int nbOutputs) const TRT_NOEXCEPT {
return num_stack_ * sizeof(uintptr_t);
}
void StackPluginDynamic::destroy() TRT_NOEXCEPT { delete this; }
void StackPluginDynamic::terminate() TRT_NOEXCEPT {}
bool StackPluginDynamic::supportsFormatCombination(
int pos,
const nvinfer1::PluginTensorDesc* in_out,
int nb_inputs,
int nb_outputs) TRT_NOEXCEPT {
PADDLE_ENFORCE_NOT_NULL(
in_out,
common::errors::InvalidArgument(
"The input of stack plugin should not be nullptr."));
PADDLE_ENFORCE_LT(
pos,
nb_inputs + nb_outputs,
common::errors::InvalidArgument("The pos(%d) should be less than the "
"num(%d) of the input and the output.",
pos,
nb_inputs + nb_outputs));
const nvinfer1::PluginTensorDesc& in = in_out[pos];
if (pos == 0) {
if (with_fp16_) {
return (in.type == nvinfer1::DataType::kHALF) &&
(in.format == nvinfer1::TensorFormat::kLINEAR);
} else {
return (in.type == nvinfer1::DataType::kFLOAT) &&
(in.format == nvinfer1::TensorFormat::kLINEAR);
}
}
const nvinfer1::PluginTensorDesc& prev = in_out[pos - 1];
// output
return in.type == prev.type && in.format == prev.format;
}
nvinfer1::DataType StackPluginDynamic::getOutputDataType(
int index,
const nvinfer1::DataType* input_types,
int nb_inputs) const TRT_NOEXCEPT {
PADDLE_ENFORCE_EQ(
index,
0,
common::errors::InvalidArgument("The index should be equal to 0"));
return input_types[0];
}
template <typename T>
__global__ void StackKernel(const T* const* input,
T* output,
int num_stack,
int base_unit) {
int stack_id = blockIdx.y;
int lead_id = blockIdx.x;
for (int i = threadIdx.x; i < base_unit; i += blockDim.x) {
output[lead_id * num_stack * base_unit + stack_id * base_unit + i] =
input[stack_id][lead_id * base_unit + i];
}
}
int StackPluginDynamic::enqueue(const nvinfer1::PluginTensorDesc* input_desc,
const nvinfer1::PluginTensorDesc* output_desc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT {
auto input_dims = input_desc[0].dims; // (batch, seq, seq)
auto out_dims = output_desc[0].dims; // (batch, num_head, seq, seq)
auto out_num_dims = out_dims.nbDims;
int base_unit = 1;
for (int i = axis_ + 1; i < out_num_dims; ++i) {
PADDLE_ENFORCE_GT(out_dims.d[i],
0,
common::errors::InvalidArgument(
"Input dimensions should be greater than 0"));
base_unit *= out_dims.d[i];
}
int lead_unit = 1;
for (int i = 0; i < axis_; ++i) {
PADDLE_ENFORCE_GT(out_dims.d[i],
0,
common::errors::InvalidArgument(
"Input dimensions should be greater than 0"));
lead_unit *= out_dims.d[i];
}
PADDLE_ENFORCE_EQ(
out_dims.d[axis_],
num_stack_,
common::errors::InvalidArgument("number of stack axis should be same"));
cudaMemcpyAsync(workspace,
reinterpret_cast<const void* const>(inputs),
sizeof(void*) * out_dims.d[axis_],
cudaMemcpyHostToDevice,
stream);
const int num_stacks = out_dims.d[axis_];
// lead_unit may be very large, so make it be blockIdx.x
dim3 num_blocks(lead_unit, num_stacks);
const int num_threads = 256;
auto infer_type = input_desc[0].type;
if (infer_type == nvinfer1::DataType::kFLOAT) {
VLOG(1) << "TRT Plugin DataType selected. Stack-->fp32";
float* output = static_cast<float*>(outputs[0]);
StackKernel<float><<<num_blocks, num_threads, 0, stream>>>(
reinterpret_cast<const float* const*>(workspace),
output,
num_stacks,
base_unit);
} else if (infer_type == nvinfer1::DataType::kHALF) {
VLOG(1) << "TRT Plugin DataType selected. Stack-->fp16";
__half* output = static_cast<__half*>(outputs[0]);
StackKernel<__half><<<num_blocks, num_threads, 0, stream>>>(
reinterpret_cast<const __half* const*>(workspace),
output,
num_stacks,
base_unit);
} else {
PADDLE_THROW(
common::errors::Fatal("The Stack TRT Plugin's input type only "
"support float or half currently."));
}
return cudaGetLastError() != cudaSuccess;
}
StackPluginDynamicCreator::StackPluginDynamicCreator() = default;
const char* StackPluginDynamicCreator::getPluginName() const TRT_NOEXCEPT {
return "stack_plugin";
}
const char* StackPluginDynamicCreator::getPluginVersion() const TRT_NOEXCEPT {
return "1";
}
const nvinfer1::PluginFieldCollection*
StackPluginDynamicCreator::getFieldNames() TRT_NOEXCEPT {
return &field_collection_;
}
nvinfer1::IPluginV2* StackPluginDynamicCreator::createPlugin(
const char* name, const nvinfer1::PluginFieldCollection* fc) TRT_NOEXCEPT {
int axis = -1;
int num_stack = -1;
bool with_fp16 = false;
for (int i = 0; i < fc->nbFields; ++i) {
const std::string name(fc->fields[i].name);
if (name == "axis") {
axis = static_cast<const int*>(fc->fields[i].data)[0];
} else if (name == "num_stack") {
num_stack = static_cast<const int*>(fc->fields[i].data)[0];
} else if (name == "with_fp16") {
with_fp16 = static_cast<const bool*>(fc->fields[i].data)[0];
} else {
PADDLE_THROW(common::errors::Fatal("Meet an unknown plugin field '" +
name +
"' when creating stack op plugin."));
}
}
return new StackPluginDynamic(axis, num_stack, with_fp16);
}
nvinfer1::IPluginV2* StackPluginDynamicCreator::deserializePlugin(
const char* name,
const void* serial_data,
size_t serial_length) TRT_NOEXCEPT {
auto plugin = new StackPluginDynamic(serial_data, serial_length);
return plugin;
}
void StackPluginDynamicCreator::setPluginNamespace(const char* lib_namespace)
TRT_NOEXCEPT {
plugin_namespace_ = lib_namespace;
}
const char* StackPluginDynamicCreator::getPluginNamespace() const TRT_NOEXCEPT {
return plugin_namespace_.c_str();
}
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,103 @@
// 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.
#pragma once
#include <stdio.h>
#include <cassert>
#include <string>
#include <vector>
#include "paddle/fluid/framework/tensor.h"
#include "paddle/fluid/inference/tensorrt/plugin/trt_plugin.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
class StackPluginDynamic : public DynamicPluginTensorRT {
public:
explicit StackPluginDynamic(int axis, int num_stack, bool with_fp16);
StackPluginDynamic(void const* serial_data, size_t serial_length);
~StackPluginDynamic();
nvinfer1::IPluginV2DynamicExt* clone() const TRT_NOEXCEPT override;
nvinfer1::DimsExprs getOutputDimensions(
int outputIndex,
const nvinfer1::DimsExprs* inputs,
int nbInputs,
nvinfer1::IExprBuilder& exprBuilder) // NOLINT
TRT_NOEXCEPT override;
bool supportsFormatCombination(int pos,
const nvinfer1::PluginTensorDesc* inOut,
int nbInputs,
int nbOutputs) TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::DynamicPluginTensorDesc* in,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc* out,
int nbOutputs) TRT_NOEXCEPT override;
size_t getWorkspaceSize(const nvinfer1::PluginTensorDesc* inputs,
int nbInputs,
const nvinfer1::PluginTensorDesc* outputs,
int nbOutputs) const TRT_NOEXCEPT override;
int enqueue(const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* inputTypes,
int nbInputs) const
TRT_NOEXCEPT override;
const char* getPluginType() const TRT_NOEXCEPT override;
int getNbOutputs() const TRT_NOEXCEPT override;
int initialize() TRT_NOEXCEPT override;
void terminate() TRT_NOEXCEPT override;
size_t getSerializationSize() const TRT_NOEXCEPT override;
void serialize(void* buffer) const TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override;
private:
int axis_;
int num_stack_;
};
class StackPluginDynamicCreator : public nvinfer1::IPluginCreator {
public:
StackPluginDynamicCreator();
const char* getPluginName() const TRT_NOEXCEPT override;
const char* getPluginVersion() const TRT_NOEXCEPT override;
const nvinfer1::PluginFieldCollection* getFieldNames() TRT_NOEXCEPT override;
nvinfer1::IPluginV2* createPlugin(const char* name,
const nvinfer1::PluginFieldCollection* fc)
TRT_NOEXCEPT override;
nvinfer1::IPluginV2* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override;
void setPluginNamespace(const char* lib_namespace) TRT_NOEXCEPT override;
const char* getPluginNamespace() const TRT_NOEXCEPT override;
private:
std::string plugin_namespace_;
nvinfer1::PluginFieldCollection field_collection_{0, nullptr};
std::vector<nvinfer1::PluginField> plugin_attributes_;
};
REGISTER_TRT_PLUGIN_V2(StackPluginDynamicCreator);
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,234 @@
// Copyright (c) 2018 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 <stdio.h>
#include <cassert>
#include <vector>
#include "glog/logging.h"
#include "paddle/fluid/inference/tensorrt/plugin/swish_op_plugin.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
int SwishPlugin::initialize() TRT_NOEXCEPT { return 0; }
void SwishPlugin::terminate() TRT_NOEXCEPT {}
bool SwishPlugin::supportsFormat(
nvinfer1::DataType type, nvinfer1::PluginFormat format) const TRT_NOEXCEPT {
if (with_fp16_) {
return (type == nvinfer1::DataType::kFLOAT ||
type == nvinfer1::DataType::kHALF) &&
(format == nvinfer1::TensorFormat::kLINEAR);
}
return (type == nvinfer1::DataType::kFLOAT) &&
(format == nvinfer1::TensorFormat::kLINEAR);
}
nvinfer1::Dims SwishPlugin::getOutputDimensions(int index,
const nvinfer1::Dims *inputDims,
int nbInputs) TRT_NOEXCEPT {
assert(nbInputs == 1);
assert(index < this->getNbOutputs());
nvinfer1::Dims const &input_dims = inputDims[0];
nvinfer1::Dims output_dims = input_dims;
return output_dims;
}
template <typename T>
__device__ T math_exp(T a);
template <>
__device__ half math_exp<half>(half a) {
#if CUDA_ARCH_FP16_SUPPORTED(__CUDA_ARCH__)
return hexp(a);
#endif
}
template <>
__device__ float math_exp<float>(float a) {
return expf(a);
}
template <typename T>
__global__ void swish_kernel(int num, const T *input, T *output, T beta) {
int index = blockIdx.x * blockDim.x + threadIdx.x;
if (index < num) {
#if __CUDA_ARCH__ >= 350
output[index] =
__ldg(input + index) /
(static_cast<T>(1.0) + math_exp<T>(-beta * __ldg(input + index)));
#else
output[index] = input[index] /
(static_cast<T>(1.0) + math_exp<T>(-beta * input[index]));
#endif
}
}
template <>
__global__ void swish_kernel<half>(int num,
const half *input,
half *output,
half beta) {
int index = blockIdx.x * blockDim.x + threadIdx.x;
if (index < num) {
#if CUDA_ARCH_FP16_SUPPORTED(__CUDA_ARCH__)
output[index] =
__ldg(input + index) /
(static_cast<half>(1.0) + math_exp<half>(-beta * __ldg(input + index)));
#endif
}
}
int SwishPlugin::enqueue(int batch_size,
const void *const *inputs,
void *const *outputs,
void *workspace,
cudaStream_t stream) TRT_NOEXCEPT {
const auto &input_dims = this->getInputDims(0);
int num = batch_size;
for (int i = 0; i < input_dims.nbDims; i++) {
num *= input_dims.d[i];
}
int threads = 1024;
int blocks = (num + threads - 1) / threads;
auto type = getDataType();
if (type == nvinfer1::DataType::kFLOAT) {
VLOG(1) << "TRT Plugin DataType selected. Swish-->fp32";
const float *input = reinterpret_cast<const float *>(inputs[0]);
float *output = reinterpret_cast<float *const *>(outputs)[0];
swish_kernel<<<blocks, threads, 0, stream>>>(num, input, output, beta_);
} else if (type == nvinfer1::DataType::kHALF) {
VLOG(1) << "TRT Plugin DataType selected. Swish-->fp16";
const half *input = reinterpret_cast<const half *>(inputs[0]);
half *output = reinterpret_cast<half *const *>(outputs)[0];
swish_kernel<<<blocks, threads, 0, stream>>>(
num, input, output, (half)beta_);
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"The Swish TRT Plugin's input type should be float or half."));
}
return cudaGetLastError() != cudaSuccess;
}
int SwishPluginDynamic::initialize() TRT_NOEXCEPT {
getPluginNamespace();
return 0;
}
size_t SwishPluginDynamic::getSerializationSize() const TRT_NOEXCEPT {
return SerializedSize(beta_) + SerializedSize(with_fp16_);
}
void SwishPluginDynamic::serialize(void *buffer) const TRT_NOEXCEPT {
SerializeValue(&buffer, beta_);
SerializeValue(&buffer, with_fp16_);
}
nvinfer1::DimsExprs SwishPluginDynamic::getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs *inputs,
int nb_inputs,
nvinfer1::IExprBuilder &expr_builder) TRT_NOEXCEPT {
return inputs[0];
}
bool SwishPluginDynamic::supportsFormatCombination(
int pos,
const nvinfer1::PluginTensorDesc *in_out,
int nb_inputs,
int nb_outputs) TRT_NOEXCEPT {
PADDLE_ENFORCE_NOT_NULL(
in_out,
common::errors::InvalidArgument(
"The input of swish plugin should not be nullptr."));
PADDLE_ENFORCE_LT(
pos,
nb_inputs + nb_outputs,
common::errors::InvalidArgument("The pos(%d) should be less than the "
"num(%d) of the input and the output.",
pos,
nb_inputs + nb_outputs));
(in_out && pos < (nb_inputs + nb_outputs));
const nvinfer1::PluginTensorDesc &in = in_out[pos];
if (pos == 0) {
if (with_fp16_) {
bool res = (in.type == nvinfer1::DataType::kFLOAT ||
in.type == nvinfer1::DataType::kHALF);
res = res && (in.format == nvinfer1::TensorFormat::kLINEAR);
return res;
} else {
return (in.type == nvinfer1::DataType::kFLOAT) &&
(in.format == nvinfer1::TensorFormat::kLINEAR);
}
}
const nvinfer1::PluginTensorDesc &prev = in_out[pos - 1];
// output
return in.type == prev.type && in.format == prev.format;
}
nvinfer1::DataType SwishPluginDynamic::getOutputDataType(
int index,
const nvinfer1::DataType *input_types,
int nb_inputs) const TRT_NOEXCEPT {
PADDLE_ENFORCE_EQ(index,
0,
common::errors::InvalidArgument(
"The Swish Plugin only has one input, so the "
"index value should be 0, but get %d.",
index));
return input_types[0];
}
int SwishPluginDynamic::enqueue(const nvinfer1::PluginTensorDesc *input_desc,
const nvinfer1::PluginTensorDesc *output_desc,
const void *const *inputs,
void *const *outputs,
void *workspace,
cudaStream_t stream) TRT_NOEXCEPT {
auto input_dims = input_desc[0].dims;
size_t num = ProductDim(input_dims);
int threads = 1024;
int blocks = (num + threads - 1) / threads;
auto input_type = input_desc[0].type;
if (input_type == nvinfer1::DataType::kFLOAT) {
VLOG(1) << "TRT Plugin DataType selected. Swish-->fp32";
const float *input = static_cast<const float *>(inputs[0]);
float *output = static_cast<float *>(outputs[0]);
swish_kernel<float>
<<<blocks, threads, 0, stream>>>(num, input, output, beta_);
} else if (input_type == nvinfer1::DataType::kHALF) {
VLOG(1) << "TRT Plugin DataType selected. Swish-->fp16";
const half *input = static_cast<const half *>(inputs[0]);
half *output = static_cast<half *>(outputs[0]);
swish_kernel<half><<<blocks, threads, 0, stream>>>(
num, input, output, static_cast<half>(beta_));
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"The Swish TRT Plugin's input type should be float or half."));
}
return cudaGetLastError() != cudaSuccess;
}
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,196 @@
// Copyright (c) 2018 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.
#pragma once
#include <algorithm>
#include <string>
#include <vector>
#include "paddle/fluid/inference/tensorrt/engine.h"
#include "paddle/fluid/inference/tensorrt/plugin/trt_plugin.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
class SwishPlugin : public PluginTensorRTV2Ext {
private:
float beta_;
public:
size_t getSerializationSize() const TRT_NOEXCEPT override {
return getBaseSerializationSize() + SerializedSize(beta_);
}
void serialize(void* buffer) const TRT_NOEXCEPT override {
serializeBase(buffer);
SerializeValue(&buffer, beta_);
}
explicit SwishPlugin(const float beta, const bool with_fp16) : beta_(beta) {
with_fp16_ = with_fp16;
}
// It was used for tensorrt deserialization.
// It should not be called by users.
SwishPlugin(void const* serialData, size_t serialLength) {
deserializeBase(serialData, serialLength);
DeserializeValue(&serialData, &serialLength, &beta_);
}
~SwishPlugin() {}
int initialize() TRT_NOEXCEPT override;
nvinfer1::IPluginV2Ext* clone() const TRT_NOEXCEPT override {
auto* plugin = new SwishPlugin(beta_, with_fp16_);
plugin->data_format_ = data_format_;
plugin->data_type_ = data_type_;
plugin->input_dims_ = input_dims_;
return plugin;
}
const char* getPluginType() const TRT_NOEXCEPT override {
return "swish_plugin";
}
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* input_types,
int nb_inputs) const
TRT_NOEXCEPT override {
return input_types[0];
}
int getNbOutputs() const TRT_NOEXCEPT override { return 1; }
nvinfer1::Dims getOutputDimensions(int index,
const nvinfer1::Dims* inputs,
int nbInputDims) TRT_NOEXCEPT override;
int enqueue(int batchSize,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
void terminate() TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override { delete this; }
const char* getPluginVersion() const TRT_NOEXCEPT override { return "2"; }
bool supportsFormat(nvinfer1::DataType type, nvinfer1::PluginFormat format)
const TRT_NOEXCEPT override;
};
class SwishPluginCreator : public TensorRTPluginCreator {
public:
const char* getPluginName() const TRT_NOEXCEPT override {
return "swish_plugin";
}
const char* getPluginVersion() const TRT_NOEXCEPT override { return "2"; }
nvinfer1::IPluginV2* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override {
return new SwishPlugin(serial_data, serial_length);
}
};
REGISTER_TRT_PLUGIN_V2(SwishPluginCreator);
class SwishPluginDynamic : public DynamicPluginTensorRT {
public:
explicit SwishPluginDynamic(const float beta, const bool with_fp16)
: beta_(beta) {
with_fp16_ = with_fp16;
}
SwishPluginDynamic(void const* serialData, size_t serialLength) {
DeserializeValue(&serialData, &serialLength, &beta_);
DeserializeValue(&serialData, &serialLength, &with_fp16_);
}
nvinfer1::IPluginV2DynamicExt* clone() const TRT_NOEXCEPT override {
return new SwishPluginDynamic(beta_, with_fp16_);
}
const char* getPluginType() const TRT_NOEXCEPT override {
return "swish_plugin_dynamic";
}
int getNbOutputs() const TRT_NOEXCEPT override { return 1; }
int initialize() TRT_NOEXCEPT override;
size_t getSerializationSize() const TRT_NOEXCEPT override;
void serialize(void* buffer) const TRT_NOEXCEPT override;
nvinfer1::DimsExprs getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs* inputs,
int nb_inputs,
nvinfer1::IExprBuilder& expr_builder) // NOLINT
TRT_NOEXCEPT override;
bool supportsFormatCombination(int pos,
const nvinfer1::PluginTensorDesc* inOut,
int nbInputs,
int nbOutputs) TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::DynamicPluginTensorDesc* in,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc* out,
int nbOutputs) TRT_NOEXCEPT override {}
size_t getWorkspaceSize(const nvinfer1::PluginTensorDesc* inputs,
int nbInputs,
const nvinfer1::PluginTensorDesc* outputs,
int nbOutputs) const TRT_NOEXCEPT override {
return 0;
}
int enqueue(const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* inputTypes,
int nbInputs) const
TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override { delete this; }
private:
float beta_;
};
class SwishPluginDynamicCreator : public TensorRTPluginCreator {
public:
const char* getPluginName() const TRT_NOEXCEPT override {
return "swish_plugin_dynamic";
}
const char* getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
nvinfer1::IPluginV2* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override {
return new SwishPluginDynamic(serial_data, serial_length);
}
};
REGISTER_TRT_PLUGIN_V2(SwishPluginDynamicCreator);
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,553 @@
// Copyright (c) 2023 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 <stdio.h>
#include <cassert>
#include <vector>
#include "glog/logging.h"
#include "paddle/fluid/inference/tensorrt/plugin/trans_layernorm_op_plugin.h"
#include "paddle/phi/kernels/funcs/math_cuda_utils.h"
#include "paddle/phi/kernels/layer_norm_kernel.h"
#include "paddle/phi/kernels/transpose_kernel.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
inline int getSMVersion() {
const int device = phi::backends::gpu::GetCurrentDeviceId();
const phi::gpuDeviceProp prop =
phi::backends::gpu::GetDeviceProperties(device);
return prop.major * 10 + prop.minor;
}
#define FINAL_MASK 0xffffffff
template <int UNROLL_FACTOR>
__global__ void GeneralResidualLayerNormOpt2(half2 *normed_output,
half2 *output,
const half2 *__restrict src,
const half2 *__restrict gamma,
const half2 *__restrict beta,
int m,
int n,
float epsilon) {
#if CUDA_ARCH_FP16_SUPPORTED(__CUDA_ARCH__)
__shared__ float s_mean;
__shared__ float s_variance;
float x_sum = 0.0f;
float x2_sum = 0.0f;
const int b_offset = blockIdx.x * n;
#pragma unroll UNROLL_FACTOR
for (int i = threadIdx.x; i < n; i += blockDim.x) {
const int index = b_offset + i;
float val_1 = 0.0f;
float val_2 = 0.0f;
half2 tmp;
tmp = __ldg(&src[index]);
val_1 += static_cast<float>(tmp.x);
val_2 += static_cast<float>(tmp.y);
output[index] = tmp;
x_sum += val_1 + val_2;
x2_sum += val_1 * val_1 + val_2 * val_2;
}
float sums[2];
sums[0] = x_sum;
sums[1] = x2_sum;
phi::funcs::BlockReduceSumV2<float, 2>(sums);
constexpr int Half2VecSize = 2;
if (threadIdx.x == 0) {
s_mean = sums[0] / n / Half2VecSize;
s_variance = rsqrtf(sums[1] / n / Half2VecSize - s_mean * s_mean + epsilon);
}
__syncthreads();
half2 mean_2 = __float2half2_rn(s_mean);
half2 var_2 = __float2half2_rn(s_variance);
#pragma unroll UNROLL_FACTOR
for (int i = threadIdx.x; i < n; i += blockDim.x) {
const int index = b_offset + i;
half2 val = __hmul2(__hmul2(__hsub2(output[index], mean_2), var_2),
__ldg(&gamma[i]));
if (beta) {
val = __hadd2(val, __ldg(&beta[i]));
}
normed_output[index] = val;
}
#endif
}
#define HALF2_RESIDUAL_LAYERNORM_OPT2(UNROLL_FACTOR) \
GeneralResidualLayerNormOpt2<UNROLL_FACTOR> \
<<<rows, block, 0, stream>>>(reinterpret_cast<half2 *>(layernorm_dst), \
reinterpret_cast<half2 *>(dst), \
(const half2 *)input, \
(const half2 *)fp16_scale_gpu_, \
(const half2 *)fp16_bias_gpu_, \
rows, \
half_n, \
eps);
int TransLayerNormPluginDynamic::initialize() TRT_NOEXCEPT {
if (!with_fp16_) {
cudaMalloc(&bias_gpu_, sizeof(float) * bias_.size());
cudaMemcpy(bias_gpu_,
bias_.data(),
bias_.size() * sizeof(float),
cudaMemcpyHostToDevice);
cudaMalloc(&scale_gpu_, sizeof(float) * scale_.size());
cudaMemcpy(scale_gpu_,
scale_.data(),
scale_.size() * sizeof(float),
cudaMemcpyHostToDevice);
} else {
cudaMalloc(&bias_gpu_, sizeof(float) * bias_.size());
cudaMemcpy(bias_gpu_,
bias_.data(),
bias_.size() * sizeof(float),
cudaMemcpyHostToDevice);
cudaMalloc(&scale_gpu_, sizeof(float) * scale_.size());
cudaMemcpy(scale_gpu_,
scale_.data(),
scale_.size() * sizeof(float),
cudaMemcpyHostToDevice);
std::vector<half> fp16_bias_;
std::vector<half> fp16_scale_;
fp16_bias_.resize(bias_.size());
fp16_scale_.resize(scale_.size());
for (int i = 0; i < bias_.size(); i++) {
fp16_bias_[i] = static_cast<half>(bias_[i]);
}
for (int i = 0; i < scale_.size(); i++) {
fp16_scale_[i] = static_cast<half>(scale_[i]);
}
cudaMalloc(&fp16_bias_gpu_, sizeof(half) * fp16_bias_.size());
cudaMemcpy(fp16_bias_gpu_,
fp16_bias_.data(),
fp16_bias_.size() * sizeof(half),
cudaMemcpyHostToDevice);
cudaMalloc(&fp16_scale_gpu_, sizeof(half) * fp16_scale_.size());
cudaMemcpy(fp16_scale_gpu_,
fp16_scale_.data(),
fp16_scale_.size() * sizeof(half),
cudaMemcpyHostToDevice);
}
return 0;
}
void TransLayerNormPluginDynamic::terminate() TRT_NOEXCEPT {
if (bias_gpu_) {
cudaFree(bias_gpu_);
bias_gpu_ = nullptr;
}
if (scale_gpu_) {
cudaFree(scale_gpu_);
scale_gpu_ = nullptr;
}
if (fp16_bias_gpu_) {
cudaFree(fp16_bias_gpu_);
fp16_bias_gpu_ = nullptr;
}
if (fp16_scale_gpu_) {
cudaFree(fp16_scale_gpu_);
fp16_scale_gpu_ = nullptr;
}
}
nvinfer1::DimsExprs TransLayerNormPluginDynamic::getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs *inputDims,
int nb_inputs,
nvinfer1::IExprBuilder &expr_builder) TRT_NOEXCEPT {
nvinfer1::DimsExprs ret;
ret.nbDims = 3;
ret.d[0] = inputDims[0].d[0];
ret.d[1] = expr_builder.operation(nvinfer1::DimensionOperation::kPROD,
*inputDims[0].d[2],
*inputDims[0].d[3]);
ret.d[2] = inputDims[0].d[1];
return ret;
}
bool TransLayerNormPluginDynamic::supportsFormatCombination(
int pos,
const nvinfer1::PluginTensorDesc *in_out,
int nb_inputs,
int nb_outputs) TRT_NOEXCEPT {
int feature_size = bias_.size();
PADDLE_ENFORCE_GE(
feature_size,
0,
common::errors::InvalidArgument(
"The feature size of layernorm feature_size must be positive,"
"but got:%d",
feature_size));
PADDLE_ENFORCE_NOT_NULL(
in_out,
common::errors::InvalidArgument(
"The input of layernorm plugin should not be nullptr."));
PADDLE_ENFORCE_LT(
pos,
nb_inputs + nb_outputs,
common::errors::InvalidArgument("The pos(%d) should be less than the "
"num(%d) of the input and the output.",
pos,
nb_inputs + nb_outputs));
const nvinfer1::PluginTensorDesc &in = in_out[pos];
if (pos == 0) {
if (with_fp16_) {
if (feature_size % 8 == 0) {
// now, we only support khwc8 for feature_size % 8 == 0
return ((in.type == nvinfer1::DataType::kHALF) &&
(in.format == nvinfer1::PluginFormat::kLINEAR ||
in.format == nvinfer1::PluginFormat::kHWC8));
} else {
return ((in.type == nvinfer1::DataType::kHALF) &&
(in.format == nvinfer1::PluginFormat::kLINEAR));
}
} else {
return (in.type == nvinfer1::DataType::kFLOAT) &&
(in.format == nvinfer1::TensorFormat::kLINEAR);
}
}
if (pos == 1) {
if (with_fp16_) {
return (in.type == in_out[0].type &&
(in.format == nvinfer1::PluginFormat::kLINEAR));
} else {
return (in.type == in_out[0].type) &&
(in.format == nvinfer1::TensorFormat::kLINEAR);
}
}
if (pos == 2) {
if (with_fp16_) {
return (in.type == in_out[0].type &&
(in.format == nvinfer1::PluginFormat::kLINEAR));
} else {
return (in.type == in_out[0].type) &&
(in.format == nvinfer1::TensorFormat::kLINEAR);
}
}
}
void TransLayerNormPluginDynamic::configurePlugin(
const nvinfer1::DynamicPluginTensorDesc *in,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc *out,
int nbOutputs) TRT_NOEXCEPT {
PADDLE_ENFORCE_EQ(
begin_norm_axis_,
3,
common::errors::InvalidArgument(
"The transpose_LayerNorm Plugin only has begin_norm_axis_ = 3"
"but get %d.",
begin_norm_axis_));
const auto &input_dims = in[0].desc.dims;
int statis_num = input_dims.d[0] * input_dims.d[2] * input_dims.d[3];
mean_shape_[0] = statis_num;
variance_shape_[0] = statis_num;
}
nvinfer1::DataType TransLayerNormPluginDynamic::getOutputDataType(
int index,
const nvinfer1::DataType *input_types,
int nb_inputs) const TRT_NOEXCEPT {
PADDLE_ENFORCE_EQ(
nb_inputs,
1,
common::errors::InvalidArgument(
"The transpose_LayerNorm Plugin only has one input, so the "
"nb_inputs value should be 1, but get %d.",
nb_inputs));
PADDLE_ENFORCE_EQ((input_types[0] == nvinfer1::DataType::kFLOAT ||
input_types[0] == nvinfer1::DataType::kHALF),
true,
common::errors::InvalidArgument(
"The input type should be half or float"));
return input_types[0];
}
int TransLayerNormPluginDynamic::enqueue(
const nvinfer1::PluginTensorDesc *input_desc,
const nvinfer1::PluginTensorDesc *output_desc,
const void *const *inputs,
void *const *outputs,
void *workspace,
cudaStream_t stream) TRT_NOEXCEPT {
const auto &input_dims = input_desc[0].dims;
int begin_norm_axis = begin_norm_axis_;
float eps = eps_;
std::vector<int64_t> input_shape;
for (int i = 0; i < input_dims.nbDims; i++) {
input_shape.push_back(input_dims.d[i]);
}
int input_numel = 1;
for (int i = 0; i < input_dims.nbDims; i++) {
input_numel *= input_dims.d[i];
}
PADDLE_ENFORCE_EQ(1,
mean_shape_.size(),
common::errors::InvalidArgument(
"Size of mean_shape vector should be equal to 1,"
"but got Size of mean_shape vector:%d",
mean_shape_.size()));
PADDLE_ENFORCE_EQ(1,
variance_shape_.size(),
common::errors::InvalidArgument(
"Size of variance_shape vector should be equal to 1,"
"but got Size of mean_shape vector:%d",
mean_shape_.size()));
PADDLE_ENFORCE_GE(mean_shape_[0],
0,
common::errors::InvalidArgument(
"The size of mean vector should be positive,"
"but got:%d",
mean_shape_[0]));
PADDLE_ENFORCE_GE(variance_shape_[0],
0,
common::errors::InvalidArgument(
"The size of mean vector should be positive,"
"but got:%d",
variance_shape_[0]));
// transpose do not change numel
int trans_result_numel = input_numel;
std::vector<int64_t> trans_result_shape{
input_shape[0], input_shape[2], input_shape[3], input_shape[1]};
const auto input_ddim = common::make_ddim(input_shape);
int feature_size = static_cast<int>(input_ddim[1]);
PADDLE_ENFORCE_EQ(feature_size,
scale_.size(),
common::errors::InvalidArgument(
"scale's size should be equal to the feature_size,"
"but got feature_size:%d, scale's size:%d.",
feature_size,
scale_.size()));
PADDLE_ENFORCE_EQ(feature_size,
bias_.size(),
common::errors::InvalidArgument(
"bias's size should be equal to the feature_size,"
"but got feature_size:%d, bias's size:%d.",
feature_size,
bias_.size()));
int device_id = -1;
cudaGetDevice(&device_id);
PADDLE_ENFORCE_GE(
device_id,
0,
common::errors::InvalidArgument("device_id should be positive,"
"but got:%d",
device_id));
auto input_type = input_desc[0].type;
phi::DeviceContextPool &pool = phi::DeviceContextPool::Instance();
GPUPlace place(platform::GetCurrentDeviceId());
auto *device_context = static_cast<phi::GPUContext *>(pool.Get(place));
const phi::GPUContext &dev_ctx = *device_context;
mean_t.Resize(common::make_ddim(mean_shape_));
variance_t.Resize(common::make_ddim(variance_shape_));
float *mean_d =
dev_ctx.template Alloc<float>(&mean_t, mean_shape_[0] * sizeof(float));
float *variance_d = dev_ctx.template Alloc<float>(
&variance_t, variance_shape_[0] * sizeof(float));
if (input_type == nvinfer1::DataType::kFLOAT) {
VLOG(1) << "TRT Plugin DataType selected. trans_layernorm-->fp32";
VLOG(1) << "TRT Plugin format selected. trans_layernorm-->kLINEAR";
const float *input = reinterpret_cast<const float *>(inputs[0]);
float *layernorm_dst = static_cast<float *>(outputs[0]);
float *dst = static_cast<float *>(outputs[1]);
// transpose and norm do not change numel
int trans_result_numel = input_numel;
int norm_result_numel = input_numel;
phi::DenseTensorMeta input_meta(phi::DataType::FLOAT32,
common::make_ddim(input_shape));
phi::DenseTensorMeta bias_meta(phi::DataType::FLOAT32,
common::make_ddim({feature_size}));
phi::DenseTensorMeta scale_meta(phi::DataType::FLOAT32,
common::make_ddim({feature_size}));
phi::DenseTensorMeta trans_result_meta(
phi::DataType::FLOAT32, common::make_ddim(trans_result_shape));
phi::DenseTensorMeta norm_result_meta(
phi::DataType::FLOAT32, common::make_ddim(trans_result_shape));
std::shared_ptr<phi::Allocation> input_alloc(new phi::Allocation(
static_cast<void *>(const_cast<float *>(input)), // NOLINT
input_numel * sizeof(float),
place));
std::shared_ptr<phi::Allocation> bias_alloc(
new phi::Allocation(static_cast<float *>(bias_gpu_), // NOLINT
feature_size * sizeof(float),
place));
std::shared_ptr<phi::Allocation> scale_alloc(new phi::Allocation(
static_cast<float *>(scale_gpu_), feature_size * sizeof(float), place));
std::shared_ptr<phi::Allocation> trans_result_alloc(
new phi::Allocation(static_cast<float *>(dst), // NOLINT
trans_result_numel * sizeof(float),
place));
std::shared_ptr<phi::Allocation> norm_result_alloc(
new phi::Allocation(static_cast<float *>(layernorm_dst), // NOLINT
norm_result_numel * sizeof(float),
place));
const phi::DenseTensor input_tensor =
phi::DenseTensor(input_alloc, input_meta);
phi::DenseTensor bias_tensor = phi::DenseTensor(bias_alloc, bias_meta);
phi::DenseTensor scale_tensor = phi::DenseTensor(scale_alloc, scale_meta);
phi::DenseTensor trans_result_tensor =
phi::DenseTensor(trans_result_alloc, trans_result_meta);
phi::DenseTensor norm_result_tensor =
phi::DenseTensor(norm_result_alloc, norm_result_meta);
phi::TransposeKernel<float, phi::GPUContext>(dev_ctx,
input_tensor,
std::vector<int>{0, 2, 3, 1},
&trans_result_tensor);
phi::LayerNormKernel<float, phi::GPUContext>(dev_ctx,
trans_result_tensor,
scale_tensor,
bias_tensor,
eps,
begin_norm_axis,
&norm_result_tensor,
&mean_t,
&variance_t);
} else if (input_type == nvinfer1::DataType::kHALF) {
VLOG(1) << "TRT Plugin DataType selected. trans_layernorm-->fp16";
const half *input = reinterpret_cast<const half *>(inputs[0]);
half *layernorm_dst = static_cast<half *>(outputs[0]);
half *dst = static_cast<half *>(outputs[1]);
if (input_desc[0].format == nvinfer1::PluginFormat::kLINEAR) {
VLOG(1) << "TRT Plugin format selected. trans_layernorm-->kLINEAR";
phi::DenseTensorMeta input_meta(phi::DataType::FLOAT16,
common::make_ddim(input_shape));
std::shared_ptr<phi::Allocation> input_alloc(new phi::Allocation(
static_cast<void *>(const_cast<half *>(input)), // NOLINT
input_numel * sizeof(half),
place));
phi::DenseTensorMeta trans_result_meta(
phi::DataType::FLOAT16, common::make_ddim(trans_result_shape));
std::shared_ptr<phi::Allocation> trans_result_alloc(
new phi::Allocation(static_cast<void *>(dst), // NOLINT
trans_result_numel * sizeof(half),
place));
const phi::DenseTensor input_tensor =
phi::DenseTensor(input_alloc, input_meta);
phi::DenseTensor trans_result_tensor =
phi::DenseTensor(trans_result_alloc, trans_result_meta);
phi::TransposeKernel<phi::dtype::float16, phi::GPUContext>(
dev_ctx,
input_tensor,
std::vector<int>{0, 2, 3, 1},
&trans_result_tensor);
phi::LayerNormDirectCUDAFunctor<half, float> layer_norm;
layer_norm(stream,
dst,
trans_result_shape,
bias_gpu_,
scale_gpu_,
layernorm_dst,
mean_d,
variance_d,
begin_norm_axis,
eps);
} else if (input_desc[0].format == nvinfer1::PluginFormat::kHWC8) {
VLOG(1) << "TRT Plugin format selected. trans_layernorm-->kHWC8";
int sm = getSMVersion();
// sm >= 60 to support __ldg
if (sm >= 60) {
int64_t hidden = input_shape[1];
if (hidden % 2 == 0) {
const size_t rows =
static_cast<size_t>(input_shape[0] * input_shape[2] *
input_shape[3]); // batch * seq_length
int half_n = hidden / 2;
int half_n_32 = (half_n + 31) / 32 * 32;
dim3 block(std::min(half_n_32, 512));
int rolls_per_thread = half_n / block.x;
int unroll_factor = 8;
while (unroll_factor > rolls_per_thread && unroll_factor > 1) {
unroll_factor /= 2;
}
switch (unroll_factor) {
case 1:
HALF2_RESIDUAL_LAYERNORM_OPT2(1);
break;
case 2:
HALF2_RESIDUAL_LAYERNORM_OPT2(2);
break;
case 4:
HALF2_RESIDUAL_LAYERNORM_OPT2(4);
break;
case 8:
HALF2_RESIDUAL_LAYERNORM_OPT2(8);
break;
default:
PADDLE_THROW(common::errors::Fatal(
"Invalid UNROLL_FACTOR in transpose_layernorm trt plugin."));
}
} else {
cudaMemcpyAsync(
dst, input, input_numel * sizeof(half), cudaMemcpyDeviceToDevice);
phi::LayerNormDirectCUDAFunctor<half, float> layer_norm;
layer_norm(stream,
input,
trans_result_shape,
bias_gpu_,
scale_gpu_,
layernorm_dst,
mean_d,
variance_d,
begin_norm_axis,
eps);
}
} else {
cudaMemcpyAsync(
dst, input, input_numel * sizeof(half), cudaMemcpyDeviceToDevice);
phi::LayerNormDirectCUDAFunctor<half, float> layer_norm;
layer_norm(stream,
input,
trans_result_shape,
bias_gpu_,
scale_gpu_,
layernorm_dst,
mean_d,
variance_d,
begin_norm_axis,
eps);
}
}
} else {
PADDLE_THROW(
common::errors::Fatal("The TransLayerNormPluginDynamic TRT Plugin's "
"input type should be float or half."));
}
return cudaGetLastError() != cudaSuccess;
}
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,176 @@
// Copyright (c) 2022 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.
#pragma once
#include <algorithm>
#include <string>
#include <vector>
#include "paddle/fluid/framework/tensor.h"
#include "paddle/fluid/framework/tensor_util.h"
#include "paddle/fluid/inference/tensorrt/engine.h"
#include "paddle/fluid/inference/tensorrt/plugin/trt_plugin.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
class TransLayerNormPluginDynamic : public DynamicPluginTensorRT {
public:
TransLayerNormPluginDynamic(const float* bias,
const int bias_num,
const float* scale,
const int scale_num,
int begin_norm_axis,
float eps,
std::vector<int64_t> mean_shape,
std::vector<int64_t> variance_shape,
bool with_fp16)
: begin_norm_axis_(begin_norm_axis),
eps_(eps),
mean_shape_(mean_shape),
variance_shape_(variance_shape) {
with_fp16_ = with_fp16;
bias_.resize(bias_num);
scale_.resize(scale_num);
std::copy(bias, bias + bias_num, bias_.data());
std::copy(scale, scale + scale_num, scale_.data());
}
TransLayerNormPluginDynamic(void const* serialData, size_t serialLength) {
DeserializeValue(&serialData, &serialLength, &bias_);
DeserializeValue(&serialData, &serialLength, &scale_);
DeserializeValue(&serialData, &serialLength, &begin_norm_axis_);
DeserializeValue(&serialData, &serialLength, &eps_);
DeserializeValue(&serialData, &serialLength, &mean_shape_);
DeserializeValue(&serialData, &serialLength, &variance_shape_);
DeserializeValue(&serialData, &serialLength, &with_fp16_);
}
nvinfer1::IPluginV2DynamicExt* clone() const TRT_NOEXCEPT override {
auto ptr = new TransLayerNormPluginDynamic(bias_.data(),
bias_.size(),
scale_.data(),
scale_.size(),
begin_norm_axis_,
eps_,
mean_shape_,
variance_shape_,
with_fp16_);
ptr->bias_gpu_ = bias_gpu_;
ptr->scale_gpu_ = scale_gpu_;
ptr->fp16_bias_gpu_ = fp16_bias_gpu_;
ptr->fp16_scale_gpu_ = fp16_scale_gpu_;
return ptr;
}
const char* getPluginType() const TRT_NOEXCEPT override {
return "trans_layernorm_plugin_dynamic";
}
int getNbOutputs() const TRT_NOEXCEPT override { return 2; }
int initialize() TRT_NOEXCEPT override;
void terminate() TRT_NOEXCEPT override;
size_t getSerializationSize() const TRT_NOEXCEPT override {
return SerializedSize(bias_) + SerializedSize(scale_) +
SerializedSize(begin_norm_axis_) + SerializedSize(eps_) +
SerializedSize(mean_shape_) + SerializedSize(variance_shape_) +
SerializedSize(with_fp16_);
}
void serialize(void* buffer) const TRT_NOEXCEPT override {
SerializeValue(&buffer, bias_);
SerializeValue(&buffer, scale_);
SerializeValue(&buffer, begin_norm_axis_);
SerializeValue(&buffer, eps_);
SerializeValue(&buffer, mean_shape_);
SerializeValue(&buffer, variance_shape_);
SerializeValue(&buffer, with_fp16_);
}
nvinfer1::DimsExprs getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs* inputs,
int nb_inputs,
nvinfer1::IExprBuilder& expr_builder) // NOLINT
TRT_NOEXCEPT override;
bool supportsFormatCombination(int pos,
const nvinfer1::PluginTensorDesc* inOut,
int nbInputs,
int nbOutputs) TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::DynamicPluginTensorDesc* in,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc* out,
int nbOutputs) TRT_NOEXCEPT override;
size_t getWorkspaceSize(const nvinfer1::PluginTensorDesc* inputs,
int nbInputs,
const nvinfer1::PluginTensorDesc* outputs,
int nbOutputs) const TRT_NOEXCEPT override {
return 0;
}
int enqueue(const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* inputTypes,
int nbInputs) const
TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override { delete this; }
private:
std::vector<float> bias_;
std::vector<float> scale_;
phi::DenseTensor mean_t;
phi::DenseTensor variance_t;
int begin_norm_axis_;
float eps_;
std::vector<int64_t> mean_shape_;
std::vector<int64_t> variance_shape_;
// data on devices
float* bias_gpu_{nullptr};
float* scale_gpu_{nullptr};
half* fp16_bias_gpu_{nullptr};
half* fp16_scale_gpu_{nullptr};
};
class TransLayerNormPluginDynamicCreator : public TensorRTPluginCreator {
public:
const char* getPluginName() const TRT_NOEXCEPT override {
return "trans_layernorm_plugin_dynamic";
}
const char* getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
nvinfer1::IPluginV2* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override {
return new TransLayerNormPluginDynamic(serial_data, serial_length);
}
};
REGISTER_TRT_PLUGIN_V2(TransLayerNormPluginDynamicCreator);
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,359 @@
/* Copyright (c) 2022 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/phi/common/memory_utils.h"
#include "paddle/phi/core/platform/device/gpu/gpu_info.h"
#include "paddle/phi/core/platform/device_context.h"
#include "cub/cub.cuh"
#include "paddle/fluid/inference/tensorrt/plugin/transformer_input_output_convert_plugin.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
__global__ void remove_padding_kernel(const half* input0,
const int32_t* input1,
half* output) {
int word_id = blockIdx.x * gridDim.y + blockIdx.y;
int32_t sequence_length = input1[blockIdx.x + 1] - input1[blockIdx.x];
if (blockIdx.y < sequence_length) {
output[(input1[blockIdx.x] + blockIdx.y) * gridDim.z * blockDim.x +
blockIdx.z * blockDim.x + threadIdx.x] =
input0[word_id * gridDim.z * blockDim.x + blockIdx.z * blockDim.x +
threadIdx.x];
}
}
__global__ void recover_padding_kernel(const half* input0,
const int32_t* input1,
half* output) {
int word_id = blockIdx.x * gridDim.y + blockIdx.y;
int32_t sequence_length = input1[blockIdx.x + 1] - input1[blockIdx.x];
if (blockIdx.y < sequence_length) {
output[word_id * gridDim.z * blockDim.x + blockIdx.z * blockDim.x +
threadIdx.x] =
input0[(input1[blockIdx.x] + blockIdx.y) * gridDim.z * blockDim.x +
blockIdx.z * blockDim.x + threadIdx.x];
} else {
output[word_id * gridDim.z * blockDim.x + blockIdx.z * blockDim.x +
threadIdx.x] = 0;
}
}
nvinfer1::DataType TransformerInputConvertPlugin::getOutputDataType(
int index,
const nvinfer1::DataType* input_types,
int nb_inputs) const TRT_NOEXCEPT {
if (index == 0) { // new input
return nvinfer1::DataType::kHALF;
} else if (index == 1) { // mask
return nvinfer1::DataType::kHALF;
} else if (index == 2) { // pos id
return nvinfer1::DataType::kINT32;
} else if (index == 3) { // max_seqlen_tensor
return nvinfer1::DataType::kHALF;
}
}
nvinfer1::DimsExprs TransformerInputConvertPlugin::getOutputDimensions(
int outputIndex,
const nvinfer1::DimsExprs* inputs,
int nbInputs,
nvinfer1::IExprBuilder& exprBuilder) TRT_NOEXCEPT {
constexpr size_t threadsPerCta384 = 1 * 8 * 32;
constexpr size_t xmmasM384 = 24;
constexpr size_t packedMaskSize384 = xmmasM384 * threadsPerCta384;
int32_t maskSize_ = packedMaskSize384;
auto maskSize = exprBuilder.constant(maskSize_);
auto fp16maskSize = exprBuilder.operation(
nvinfer1::DimensionOperation::kPROD, *maskSize, *exprBuilder.constant(2));
auto one = exprBuilder.constant(1);
auto B = inputs[0].d[0];
auto MaxLength = inputs[0].d[1];
auto Hidden = inputs[0].d[2];
nvinfer1::DimsExprs output_dims;
if (outputIndex == 0) { // new input
output_dims.nbDims = 4;
output_dims.d[0] = exprBuilder.operation(
nvinfer1::DimensionOperation::kPROD, *B, *MaxLength);
output_dims.d[1] = Hidden;
output_dims.d[2] = exprBuilder.constant(1);
output_dims.d[3] = exprBuilder.constant(1);
} else if (outputIndex == 1) { // mask
output_dims.nbDims = 2;
output_dims.d[0] = B;
output_dims.d[1] = fp16maskSize;
} else if (outputIndex == 2) { // pos id
output_dims.nbDims = 1;
output_dims.d[0] =
exprBuilder.operation(nvinfer1::DimensionOperation::kSUM, *B, *one);
} else if (outputIndex == 3) { // max_seqlen_tensor
output_dims.nbDims = 1;
output_dims.d[0] = MaxLength;
}
return output_dims;
}
bool TransformerInputConvertPlugin::supportsFormatCombination(
int pos,
const nvinfer1::PluginTensorDesc* inOut,
int nbInputs,
int nbOutputs) TRT_NOEXCEPT {
PADDLE_ENFORCE_EQ(nbInputs,
2,
common::errors::InvalidArgument(
"TransformerInputConvertPlugin must have 2 inputs, "
"but got %d input(s). ",
nbInputs));
PADDLE_ENFORCE_EQ(nbOutputs,
4,
common::errors::InvalidArgument(
"TransformerInputConvertPlugin must have 4 outputs, "
"but got %d output(s). ",
nbOutputs));
if (pos == 0) { // input
return inOut[pos].format == nvinfer1::TensorFormat::kLINEAR &&
inOut[pos].type == nvinfer1::DataType::kHALF;
} else if (pos == 1) { // reducesum_qk_bias
return inOut[pos].format == nvinfer1::TensorFormat::kLINEAR &&
inOut[pos].type == nvinfer1::DataType::kINT32;
} else if (pos == 2) { // new input
return inOut[pos].format == nvinfer1::TensorFormat::kLINEAR &&
inOut[pos].type == nvinfer1::DataType::kHALF;
} else if (pos == 3) { // mask
return inOut[pos].format == nvinfer1::TensorFormat::kLINEAR &&
inOut[pos].type == nvinfer1::DataType::kHALF;
} else if (pos == 4) { // pos id
return inOut[pos].format == nvinfer1::TensorFormat::kLINEAR &&
inOut[pos].type == nvinfer1::DataType::kINT32;
} else if (pos == 5) { // max_seqlen_tensor
return inOut[pos].format == nvinfer1::TensorFormat::kLINEAR &&
inOut[pos].type == nvinfer1::DataType::kHALF;
}
}
void TransformerInputConvertPlugin::configurePlugin(
const nvinfer1::DynamicPluginTensorDesc* inputs,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc* outputs,
int nbOutputs) TRT_NOEXCEPT {}
void TransformerInputConvertPlugin::attachToContext(
cudnnContext* cudnnContext,
cublasContext* cublasContext,
nvinfer1::IGpuAllocator* gpuAllocator) TRT_NOEXCEPT {}
void TransformerInputConvertPlugin::detachFromContext() TRT_NOEXCEPT {}
void TransformerInputConvertPlugin::terminate() TRT_NOEXCEPT {}
int TransformerInputConvertPlugin::enqueue(
const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT {
// input(no_varlen), reducesum_qk_bias, input(varlen), mask, pos_id,
// max_seqlen_tensor
const half* input0 = static_cast<const half*>(inputs[0]); // input(no_varlen)
const int32_t* input1 =
static_cast<const int32_t*>(inputs[1]); // reducesum_qk_bias
half* output0 = static_cast<half*>(outputs[0]); // input(varlen)
int32_t* output2 = static_cast<int32_t*>(outputs[2]); // pos_id
const auto input0_desc = inputDesc[0];
const int32_t B = input0_desc.dims.d[0]; // batches
const int32_t MaxLength = input0_desc.dims.d[1]; // max token length
const int32_t HiddenSize = input0_desc.dims.d[2]; // hidden size
// Determine temporary device storage requirements
size_t temp_storage_bytes = 0;
cub::DeviceScan::ExclusiveSum(
NULL, temp_storage_bytes, input1, output2, B + 1);
// Allocate temporary storage
GPUPlace place(platform::GetCurrentDeviceId());
auto d_temp_storage = phi::memory_utils::Alloc(place, temp_storage_bytes);
// Run exclusive prefix sum
cub::DeviceScan::ExclusiveSum(
d_temp_storage->ptr(), temp_storage_bytes, input1, output2, B + 1);
const int32_t vector_length = HiddenSize;
int32_t num_threads;
if (vector_length < 1024) {
num_threads = vector_length;
} else {
if (vector_length % 512 == 0) {
num_threads = 512;
} else if (vector_length % 256 == 0) {
num_threads = 256;
} else if (vector_length % 128 == 0) {
num_threads = 128;
} else if (vector_length % 64 == 0) {
num_threads = 64;
} else if (vector_length % 32 == 0) {
num_threads = 32;
} else if (vector_length % 16 == 0) {
num_threads = 16;
} else if (vector_length % 8 == 0) {
num_threads = 8;
} else if (vector_length % 4 == 0) {
num_threads = 4;
} else if (vector_length % 2 == 0) {
num_threads = 2;
} else {
num_threads = 1;
}
}
const dim3 num_blocks(
B,
MaxLength,
vector_length /
num_threads); // batches, max sequence length, input0.dims.d[2]/*
remove_padding_kernel<<<num_blocks, num_threads, 0, stream>>>(
input0, output2, output0); // input(no_varlen), pos_id, input(varlen)
return cudaGetLastError() != cudaSuccess;
}
nvinfer1::DataType TransformerOutputConvertPlugin::getOutputDataType(
int index,
const nvinfer1::DataType* input_types,
int nb_inputs) const TRT_NOEXCEPT {
if (index == 0) {
return nvinfer1::DataType::kHALF;
}
}
nvinfer1::DimsExprs TransformerOutputConvertPlugin::getOutputDimensions(
int outputIndex,
const nvinfer1::DimsExprs* inputs,
int nbInputs,
nvinfer1::IExprBuilder& exprBuilder) TRT_NOEXCEPT {
nvinfer1::DimsExprs output_dims;
if (outputIndex == 0) {
output_dims = inputs[1];
}
return output_dims;
}
bool TransformerOutputConvertPlugin::supportsFormatCombination(
int pos,
const nvinfer1::PluginTensorDesc* inOut,
int nbInputs,
int nbOutputs) TRT_NOEXCEPT {
PADDLE_ENFORCE_EQ(nbInputs,
3,
common::errors::InvalidArgument(
"TransformerOutputConvertPlugin must have 3 inputs, "
"but got %d input(s). ",
nbInputs));
PADDLE_ENFORCE_EQ(nbOutputs,
1,
common::errors::InvalidArgument(
"TransformerOutputConvertPlugin must have 1 output, "
"but got %d output(s). ",
nbOutputs));
if (pos == 0) { // qkv plugin output(varlen)
return inOut[pos].format == nvinfer1::TensorFormat::kLINEAR &&
inOut[pos].type == nvinfer1::DataType::kHALF;
} else if (pos == 1) { // qkv plugin input(no_varlen)
return inOut[pos].format == nvinfer1::TensorFormat::kLINEAR &&
inOut[pos].type == nvinfer1::DataType::kHALF;
} else if (pos == 2) { // pos id
return inOut[pos].format == nvinfer1::TensorFormat::kLINEAR &&
inOut[pos].type == nvinfer1::DataType::kINT32;
} else if (pos == 3) { // qkv plugin output(no_varlen)
return inOut[pos].format == nvinfer1::TensorFormat::kLINEAR &&
inOut[pos].type == nvinfer1::DataType::kHALF;
}
}
void TransformerOutputConvertPlugin::configurePlugin(
const nvinfer1::DynamicPluginTensorDesc* inputs,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc* outputs,
int nbOutputs) TRT_NOEXCEPT {}
void TransformerOutputConvertPlugin::attachToContext(
cudnnContext* cudnnContext,
cublasContext* cublasContext,
nvinfer1::IGpuAllocator* gpuAllocator) TRT_NOEXCEPT {}
void TransformerOutputConvertPlugin::detachFromContext() TRT_NOEXCEPT {}
void TransformerOutputConvertPlugin::terminate() TRT_NOEXCEPT {}
int TransformerOutputConvertPlugin::enqueue(
const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT {
const half* input0 =
static_cast<const half*>(inputs[0]); // qkv plugin output(varlen)
const half* input1 =
static_cast<const half*>(inputs[1]); // qkv plugin input(no_varlen)
const int32_t* input2 = static_cast<const int32_t*>(inputs[2]); // pos id
half* output =
static_cast<half*>(outputs[0]); // qkv plugin output(no_varlen)
const auto input1_desc = inputDesc[1];
const int32_t B = input1_desc.dims.d[0]; // batches
const int32_t MaxLength = input1_desc.dims.d[1]; // max token length
const int32_t HiddenSize = input1_desc.dims.d[2]; // hidden size
const int32_t vector_length = HiddenSize;
int32_t num_threads;
if (vector_length < 1024) {
num_threads = vector_length;
} else {
if (vector_length % 512 == 0) {
num_threads = 512;
} else if (vector_length % 256 == 0) {
num_threads = 256;
} else if (vector_length % 128 == 0) {
num_threads = 128;
} else if (vector_length % 64 == 0) {
num_threads = 64;
} else if (vector_length % 32 == 0) {
num_threads = 32;
} else if (vector_length % 16 == 0) {
num_threads = 16;
} else if (vector_length % 8 == 0) {
num_threads = 8;
} else if (vector_length % 4 == 0) {
num_threads = 4;
} else if (vector_length % 2 == 0) {
num_threads = 2;
} else {
num_threads = 1;
}
}
const dim3 num_blocks(
B,
MaxLength,
vector_length / num_threads); // batches, max sequence length
// (mask_id.dims.d[1]),
// input.dims.d[1]/*
recover_padding_kernel<<<num_blocks, num_threads, 0, stream>>>(
input0, input2, output);
return cudaGetLastError() != cudaSuccess;
}
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,256 @@
/* Copyright (c) 2022 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. */
#pragma once
#include <cassert>
#include <string>
#include "paddle/fluid/inference/tensorrt/plugin/trt_plugin.h"
#include "paddle/fluid/platform/enforce.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
class TransformerInputConvertPlugin : public DynamicPluginTensorRT {
public:
TransformerInputConvertPlugin() {}
TransformerInputConvertPlugin(void const* serial_data, size_t serial_length) {
}
nvinfer1::IPluginV2DynamicExt* clone() const TRT_NOEXCEPT override {
TransformerInputConvertPlugin* ptr = new TransformerInputConvertPlugin();
return ptr;
}
const char* getPluginType() const TRT_NOEXCEPT override {
return "transformer_input_convert_plugin";
}
int getNbOutputs() const TRT_NOEXCEPT override { return 4; }
int initialize() TRT_NOEXCEPT { return 0; }
void terminate() TRT_NOEXCEPT;
nvinfer1::DimsExprs getOutputDimensions(
int outputIndex,
const nvinfer1::DimsExprs* inputs,
int nbInputs,
nvinfer1::IExprBuilder& exprBuilder) // NOLINT
TRT_NOEXCEPT override;
bool supportsFormatCombination(int pos,
const nvinfer1::PluginTensorDesc* inOut,
int nbInputs,
int nbOutputs) TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::DynamicPluginTensorDesc* inputs,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc* outputs,
int nbOutputs) TRT_NOEXCEPT override;
size_t getWorkspaceSize(const nvinfer1::PluginTensorDesc* inputs,
int nbInputs,
const nvinfer1::PluginTensorDesc* outputs,
int nbOutputs) const TRT_NOEXCEPT override {
return 0;
}
void attachToContext(cudnnContext* cudnnContext,
cublasContext* cublasContext,
nvinfer1::IGpuAllocator* gpuAllocator)
TRT_NOEXCEPT override;
void detachFromContext() TRT_NOEXCEPT override;
int enqueue(const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* inputTypes,
int nbInputs) const
TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override { delete this; }
protected:
size_t getSerializationSize() const TRT_NOEXCEPT override { return 0; }
void serialize(void* buffer) const TRT_NOEXCEPT override {}
};
class TransformerInputConvertPluginCreator : public nvinfer1::IPluginCreator {
public:
TransformerInputConvertPluginCreator() {}
const char* getPluginName() const TRT_NOEXCEPT override {
return "transformer_input_convert_plugin";
}
const char* getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
const nvinfer1::PluginFieldCollection* getFieldNames() TRT_NOEXCEPT override {
return &field_collection_;
}
nvinfer1::IPluginV2* createPlugin(
const char* name, const nvinfer1::PluginFieldCollection* plugin_field)
TRT_NOEXCEPT override {
return nullptr;
}
nvinfer1::IPluginV2* deserializePlugin(const char* name,
void const* serial_data,
size_t serial_length)
TRT_NOEXCEPT override {
TransformerInputConvertPlugin* obj =
new TransformerInputConvertPlugin(serial_data, serial_length);
obj->setPluginNamespace(name);
return obj;
}
void setPluginNamespace(const char* lib_namespace) TRT_NOEXCEPT override {
plugin_namespace_ = lib_namespace;
}
const char* getPluginNamespace() const TRT_NOEXCEPT override {
return plugin_namespace_.c_str();
}
private:
std::string plugin_namespace_;
std::string plugin_name_;
nvinfer1::PluginFieldCollection field_collection_{0, nullptr};
};
class TransformerOutputConvertPlugin : public DynamicPluginTensorRT {
public:
TransformerOutputConvertPlugin() {}
TransformerOutputConvertPlugin(void const* serial_data,
size_t serial_length) {}
nvinfer1::IPluginV2DynamicExt* clone() const TRT_NOEXCEPT override {
TransformerOutputConvertPlugin* ptr = new TransformerOutputConvertPlugin();
return ptr;
}
const char* getPluginType() const TRT_NOEXCEPT override {
return "transformer_output_convert_plugin";
}
int getNbOutputs() const TRT_NOEXCEPT override { return 1; }
int initialize() TRT_NOEXCEPT { return 0; }
void terminate() TRT_NOEXCEPT;
nvinfer1::DimsExprs getOutputDimensions(
int outputIndex,
const nvinfer1::DimsExprs* inputs,
int nbInputs,
nvinfer1::IExprBuilder& exprBuilder) // NOLINT
TRT_NOEXCEPT override;
bool supportsFormatCombination(int pos,
const nvinfer1::PluginTensorDesc* inOut,
int nbInputs,
int nbOutputs) TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::DynamicPluginTensorDesc* inputs,
int nbInputs,
const nvinfer1::DynamicPluginTensorDesc* outputs,
int nbOutputs) TRT_NOEXCEPT override;
size_t getWorkspaceSize(const nvinfer1::PluginTensorDesc* inputs,
int nbInputs,
const nvinfer1::PluginTensorDesc* outputs,
int nbOutputs) const TRT_NOEXCEPT override {
return 0;
}
void attachToContext(cudnnContext* cudnnContext,
cublasContext* cublasContext,
nvinfer1::IGpuAllocator* gpuAllocator)
TRT_NOEXCEPT override;
void detachFromContext() TRT_NOEXCEPT override;
int enqueue(const nvinfer1::PluginTensorDesc* inputDesc,
const nvinfer1::PluginTensorDesc* outputDesc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* inputTypes,
int nbInputs) const
TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override { delete this; }
protected:
size_t getSerializationSize() const TRT_NOEXCEPT override { return 0; }
void serialize(void* buffer) const TRT_NOEXCEPT override {}
};
class TransformerOutputConvertPluginCreator : public nvinfer1::IPluginCreator {
public:
TransformerOutputConvertPluginCreator() {}
const char* getPluginName() const TRT_NOEXCEPT override {
return "transformer_output_convert_plugin";
}
const char* getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
const nvinfer1::PluginFieldCollection* getFieldNames() TRT_NOEXCEPT override {
return &field_collection_;
}
nvinfer1::IPluginV2* createPlugin(
const char* name, const nvinfer1::PluginFieldCollection* plugin_field)
TRT_NOEXCEPT override {
return nullptr;
}
nvinfer1::IPluginV2* deserializePlugin(const char* name,
void const* serial_data,
size_t serial_length)
TRT_NOEXCEPT override {
TransformerOutputConvertPlugin* obj =
new TransformerOutputConvertPlugin(serial_data, serial_length);
obj->setPluginNamespace(name);
return obj;
}
void setPluginNamespace(const char* lib_namespace) TRT_NOEXCEPT override {
plugin_namespace_ = lib_namespace;
}
const char* getPluginNamespace() const TRT_NOEXCEPT override {
return plugin_namespace_.c_str();
}
private:
std::string plugin_namespace_;
std::string plugin_name_;
nvinfer1::PluginFieldCollection field_collection_{0, nullptr};
};
REGISTER_TRT_PLUGIN_V2(TransformerInputConvertPluginCreator);
REGISTER_TRT_PLUGIN_V2(TransformerOutputConvertPluginCreator);
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,139 @@
// Copyright (c) 2018 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/plugin/trt_plugin.h"
namespace paddle::inference::tensorrt::plugin {
inline void Serialize(void*& buffer, // NOLINT
const std::vector<nvinfer1::Dims>& input_dims,
nvinfer1::DataType data_type,
nvinfer1::PluginFormat data_format,
bool with_fp16) {
SerializeValue(&buffer, input_dims);
SerializeValue(&buffer, data_type);
SerializeValue(&buffer, data_format);
SerializeValue(&buffer, with_fp16);
}
inline void Deserialize(void const*& serial_data, // NOLINT
size_t& serial_length, // NOLINT
std::vector<nvinfer1::Dims>* input_dims,
nvinfer1::DataType* data_type,
nvinfer1::PluginFormat* data_format,
bool* with_fp16) {
DeserializeValue(&serial_data, &serial_length, input_dims);
DeserializeValue(&serial_data, &serial_length, data_type);
DeserializeValue(&serial_data, &serial_length, data_format);
DeserializeValue(&serial_data, &serial_length, with_fp16);
}
inline size_t SerializeSize(const std::vector<nvinfer1::Dims>& input_dims,
nvinfer1::DataType data_type,
nvinfer1::PluginFormat data_format,
bool with_fp16) {
return (SerializedSize(input_dims) + SerializedSize(data_type) +
SerializedSize(data_format) + SerializedSize(with_fp16));
}
void PluginTensorRT::serializeBase(void*& buffer) const {
Serialize(buffer, input_dims_, data_type_, data_format_, with_fp16_);
}
void PluginTensorRT::deserializeBase(void const*& serial_data,
size_t& serial_length) {
Deserialize(serial_data,
serial_length,
&input_dims_,
&data_type_,
&data_format_,
&with_fp16_);
}
size_t PluginTensorRT::getBaseSerializationSize() const {
return SerializeSize(input_dims_, data_type_, data_format_, with_fp16_);
}
bool PluginTensorRT::supportsFormat(
nvinfer1::DataType type, nvinfer1::PluginFormat format) const TRT_NOEXCEPT {
return ((type == nvinfer1::DataType::kFLOAT) &&
(format == nvinfer1::PluginFormat::kLINEAR));
}
void PluginTensorRT::configureWithFormat(const nvinfer1::Dims* input_dims,
int num_inputs,
const nvinfer1::Dims* output_dims,
int num_outputs,
nvinfer1::DataType type,
nvinfer1::PluginFormat format,
int max_batch_size) TRT_NOEXCEPT {
data_type_ = type;
data_format_ = format;
input_dims_.assign(input_dims, input_dims + num_inputs);
}
void PluginTensorRTV2Ext::serializeBase(void*& buffer) const {
Serialize(buffer, input_dims_, data_type_, data_format_, with_fp16_);
}
void PluginTensorRTV2Ext::deserializeBase(void const*& serial_data,
size_t& serial_length) {
Deserialize(serial_data,
serial_length,
&input_dims_,
&data_type_,
&data_format_,
&with_fp16_);
}
size_t PluginTensorRTV2Ext::getBaseSerializationSize() const {
return SerializeSize(input_dims_, data_type_, data_format_, with_fp16_);
}
void PluginTensorRTV2Ext::configurePlugin(
const nvinfer1::Dims* input_dims,
int32_t nb_inputs,
const nvinfer1::Dims* output_dims,
int32_t nb_outputs,
const nvinfer1::DataType* input_types,
const nvinfer1::DataType* output_types,
const bool* input_is_broadcast,
const bool* output_is_broadcast,
nvinfer1::PluginFormat float_format,
int32_t max_batch_size) TRT_NOEXCEPT {
input_dims_.assign(input_dims, input_dims + nb_inputs);
data_format_ = float_format;
data_type_ = input_types[0];
}
const nvinfer1::PluginFieldCollection* TensorRTPluginCreator::getFieldNames()
TRT_NOEXCEPT {
return &field_collection_;
}
nvinfer1::IPluginV2* TensorRTPluginCreator::createPlugin(
const char* name, const nvinfer1::PluginFieldCollection* fc) TRT_NOEXCEPT {
return nullptr;
}
void TensorRTPluginCreator::setPluginNamespace(const char* lib_namespace)
TRT_NOEXCEPT {
plugin_namespace_ = lib_namespace;
}
const char* TensorRTPluginCreator::getPluginNamespace() const TRT_NOEXCEPT {
return plugin_namespace_.c_str();
}
} // namespace paddle::inference::tensorrt::plugin
@@ -0,0 +1,377 @@
// Copyright (c) 2018 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.
#pragma once
#include <NvInfer.h>
#include <cstring>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include "paddle/fluid/inference/tensorrt/helper.h"
#include "paddle/fluid/inference/tensorrt/plugin/trt_plugin_utils.h"
#include "paddle/fluid/platform/enforce.h"
#include "paddle/fluid/platform/tensorrt/trt_plugin.h"
#include "paddle/phi/core/platform/profiler/event_tracing.h"
namespace nvinfer1 {
class ITensor;
} // namespace nvinfer1
PD_DECLARE_bool(profile);
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
#if defined(_WIN32)
#define UNUSED
#define __builtin_expect(EXP, C) (EXP)
#else
#define UNUSED __attribute__((unused))
#endif
class PluginTensorRT;
typedef std::function<PluginTensorRT*(const void*, size_t)>
PluginDeserializeFunc;
typedef std::function<PluginTensorRT*(void)> PluginConstructFunc;
// Deprecated. Do not inherit this class, please refer to PluginTensorRTV2Ext
class PluginTensorRT : public nvinfer1::IPluginV2 {
public:
PluginTensorRT() : with_fp16_(false) {}
// It was used for TensorRT deserialization.
// It should not be called by users.
PluginTensorRT(const void* serialized_data, size_t length) {}
virtual ~PluginTensorRT() {}
nvinfer1::Dims const& getInputDims(int index) const {
return input_dims_.at(index);
}
nvinfer1::DataType getDataType() const { return data_type_; }
nvinfer1::PluginFormat getDataFormat() const { return data_format_; }
// IPluginV2
virtual const char* getPluginType() const TRT_NOEXCEPT = 0;
virtual const char* getPluginVersion() const TRT_NOEXCEPT { return "1"; }
int getNbOutputs() const TRT_NOEXCEPT { return 1; }
virtual nvinfer1::Dims getOutputDimensions(int index,
const nvinfer1::Dims* input_dims,
int num_inputs) TRT_NOEXCEPT = 0;
// Check format support. The default is FLOAT32 and kLINEAR.
bool supportsFormat(nvinfer1::DataType type, nvinfer1::PluginFormat format)
const TRT_NOEXCEPT override;
// Configure the layer
void configureWithFormat(const nvinfer1::Dims* input_dims,
int num_inputs,
const nvinfer1::Dims* output_dims,
int num_outputs,
nvinfer1::DataType type,
nvinfer1::PluginFormat format,
int max_batch_size) TRT_NOEXCEPT override;
// Initialize the layer for execution.
int initialize() TRT_NOEXCEPT override { return 0; }
// Shutdown the layer. This is called when the engine is destroyed
void terminate() TRT_NOEXCEPT override {}
// Find the workspace size required by the layer
size_t getWorkspaceSize(int) const TRT_NOEXCEPT override { return 0; }
// Execute the layer
virtual int enqueue(int batch_size,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT = 0;
// Find the size of the serialization buffer required
virtual size_t getSerializationSize() const TRT_NOEXCEPT = 0;
// Serialize the layer config to buffer.
// TensorRT will call this func to serialize the configuration of TensorRT
// engine. It should not be called by users.
virtual void serialize(void* buffer) const TRT_NOEXCEPT = 0;
void destroy() TRT_NOEXCEPT override { delete this; }
virtual nvinfer1::IPluginV2* clone() const TRT_NOEXCEPT = 0;
void setPluginNamespace(const char* plugin_namespace) TRT_NOEXCEPT override {
namespace_ = plugin_namespace;
}
const char* getPluginNamespace() const TRT_NOEXCEPT override {
return namespace_.c_str();
}
protected:
// Deserialize input_dims, max_batch_size, data_type, data_format
void deserializeBase(void const*& serial_data, // NOLINT
size_t& serial_length); // NOLINT
size_t getBaseSerializationSize() const;
// Serialize input_dims, max_batch_size, data_type, data_format
void serializeBase(void*& buffer) const; // NOLINT
std::vector<nvinfer1::Dims> input_dims_;
nvinfer1::DataType data_type_;
nvinfer1::PluginFormat data_format_;
bool with_fp16_;
private:
std::string namespace_;
};
// TensorRT introduced IPluginV2Ext after 5.1, Paddle no longer supports
// versions before 5.1
class PluginTensorRTV2Ext : public nvinfer1::IPluginV2Ext {
public:
PluginTensorRTV2Ext() : with_fp16_(false) {}
PluginTensorRTV2Ext(const void* serialized_data, size_t length) {}
nvinfer1::Dims const& getInputDims(int index) const {
return input_dims_.at(index);
}
nvinfer1::DataType getDataType() const { return data_type_; }
nvinfer1::PluginFormat getDataFormat() const { return data_format_; }
// The Func in IPluginV2Ext
virtual nvinfer1::DataType getOutputDataType(
int index,
const nvinfer1::DataType* input_types,
int nb_inputs) const TRT_NOEXCEPT = 0;
virtual bool isOutputBroadcastAcrossBatch(int32_t output_index,
const bool* input_is_broadcasted,
int32_t nb_inputs) const
TRT_NOEXCEPT {
return false;
}
virtual bool canBroadcastInputAcrossBatch(int32_t input_index) const
TRT_NOEXCEPT {
return false;
}
void configurePlugin(const nvinfer1::Dims* input_dims,
int32_t nb_inputs,
const nvinfer1::Dims* output_dims,
int32_t nb_outputs,
const nvinfer1::DataType* input_types,
const nvinfer1::DataType* output_types,
const bool* input_is_broadcast,
const bool* output_is_broadcast,
nvinfer1::PluginFormat float_format,
int32_t max_batch_size) TRT_NOEXCEPT override;
virtual IPluginV2Ext* clone() const TRT_NOEXCEPT = 0;
void attachToContext(cudnnContext*,
cublasContext*,
nvinfer1::IGpuAllocator*) TRT_NOEXCEPT override {}
void detachFromContext() TRT_NOEXCEPT override {}
// The Func in IPluginV2
virtual const char* getPluginType() const TRT_NOEXCEPT = 0;
const char* getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
virtual int32_t getNbOutputs() const TRT_NOEXCEPT { return 1; }
virtual nvinfer1::Dims getOutputDimensions(int32_t index,
const nvinfer1::Dims* inputs,
int32_t nb_input) TRT_NOEXCEPT = 0;
// Check format support. The default is FLOAT32 and NCHW.
bool supportsFormat(nvinfer1::DataType type, nvinfer1::PluginFormat format)
const TRT_NOEXCEPT override {
return ((type == nvinfer1::DataType::kFLOAT) &&
(format == nvinfer1::PluginFormat::kLINEAR));
}
// Initialize the layer for execution.
// This is called when the engine is created.
int initialize() TRT_NOEXCEPT override { return 0; }
// Shutdown the layer. This is called when the engine is destroyed
void terminate() TRT_NOEXCEPT override {}
// Find the workspace size required by the layer
size_t getWorkspaceSize(int) const TRT_NOEXCEPT override { return 0; }
// Execute the layer
virtual int enqueue(int batch_size,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT = 0;
// Find the size of the serialization buffer required
virtual size_t getSerializationSize() const TRT_NOEXCEPT = 0;
// Serialize the layer config to buffer.
// TensorRT will call this func to serialize the configuration of TensorRT
// engine. It should not be called by users.
virtual void serialize(void* buffer) const TRT_NOEXCEPT = 0;
virtual void destroy() TRT_NOEXCEPT = 0;
void setPluginNamespace(const char* plugin_namespace) TRT_NOEXCEPT override {
name_space_ = plugin_namespace;
}
const char* getPluginNamespace() const TRT_NOEXCEPT override {
return name_space_.c_str();
}
protected:
void deserializeBase(void const*& serial_data, // NOLINT
size_t& serial_length); // NOLINT
size_t getBaseSerializationSize() const;
void serializeBase(void*& buffer) const; // NOLINT
protected:
std::vector<nvinfer1::Dims> input_dims_;
nvinfer1::DataType data_type_;
nvinfer1::PluginFormat data_format_;
bool with_fp16_;
private:
std::string name_space_;
};
class DynamicPluginTensorRT : public nvinfer1::IPluginV2DynamicExt {
public:
DynamicPluginTensorRT() : with_fp16_(false) {}
DynamicPluginTensorRT(const void* serialized_data, size_t length) {}
// The Func in IPluginExt or IpluginExtV2
virtual const char* getPluginVersion() const TRT_NOEXCEPT { return "1"; }
virtual const char* getPluginType() const TRT_NOEXCEPT = 0;
int getNbOutputs() const TRT_NOEXCEPT { return 1; }
int initialize() TRT_NOEXCEPT override { return 0; }
void terminate() TRT_NOEXCEPT override{};
virtual size_t getSerializationSize() const TRT_NOEXCEPT = 0;
virtual void serialize(void* buffer) const TRT_NOEXCEPT = 0;
// The Func in IPluginV2
nvinfer1::IPluginV2DynamicExt* clone() const TRT_NOEXCEPT = 0;
virtual nvinfer1::DimsExprs getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs* inputs,
int nb_inputs,
nvinfer1::IExprBuilder& expr_builder) TRT_NOEXCEPT = 0; // NOLINT
virtual bool supportsFormatCombination(
int pos,
const nvinfer1::PluginTensorDesc* in_out,
int nb_inputs,
int nb_outputs) TRT_NOEXCEPT = 0;
virtual void configurePlugin(const nvinfer1::DynamicPluginTensorDesc* in,
int nb_inputs,
const nvinfer1::DynamicPluginTensorDesc* out,
int nb_outputs) TRT_NOEXCEPT = 0;
size_t getWorkspaceSize(const nvinfer1::PluginTensorDesc* inputs,
int nb_inputs,
const nvinfer1::PluginTensorDesc* outputs,
int nb_outputs) const TRT_NOEXCEPT override {
return 0;
}
virtual int enqueue(const nvinfer1::PluginTensorDesc* input_desc,
const nvinfer1::PluginTensorDesc* output_desc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT = 0;
virtual nvinfer1::DataType getOutputDataType(
int index,
const nvinfer1::DataType* input_types,
int nb_inputs) const TRT_NOEXCEPT = 0;
void setPluginNamespace(const char* plugin_namespace) TRT_NOEXCEPT override {
name_space_ = plugin_namespace;
}
const char* getPluginNamespace() const TRT_NOEXCEPT override {
return name_space_.c_str();
}
virtual void destroy() TRT_NOEXCEPT = 0;
protected:
void deserializeBase(void const*& serial_data, // NOLINT
size_t& serial_length); // NOLINT
size_t getBaseSerializationSize() const;
void serializeBase(void*& buffer) const; // NOLINT
bool with_fp16_;
private:
std::string name_space_;
std::string plugin_base_;
};
class TensorRTPluginCreator : public nvinfer1::IPluginCreator {
public:
TensorRTPluginCreator() = default;
virtual const char* getPluginName() const TRT_NOEXCEPT = 0;
virtual const char* getPluginVersion() const TRT_NOEXCEPT = 0;
const nvinfer1::PluginFieldCollection* getFieldNames() TRT_NOEXCEPT override;
nvinfer1::IPluginV2* createPlugin(const char* name,
const nvinfer1::PluginFieldCollection* fc)
TRT_NOEXCEPT override;
virtual nvinfer1::IPluginV2* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT = 0;
void setPluginNamespace(const char* lib_namespace) TRT_NOEXCEPT override;
const char* getPluginNamespace() const TRT_NOEXCEPT override;
private:
std::string plugin_namespace_;
std::string plugin_name_;
nvinfer1::PluginFieldCollection field_collection_{0, nullptr};
std::vector<nvinfer1::PluginField> plugin_attributes_;
};
using TrtPluginRegistry = paddle::platform::TrtPluginRegistry;
template <typename T>
using TrtPluginRegistrarV2 = paddle::platform::TrtPluginRegistrarV2<T>;
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,155 @@
// Copyright (c) 2018 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.
#pragma once
#include <cuda_fp16.h>
#include <cstring>
#include <string>
#include <type_traits>
#include <vector>
#include "paddle/fluid/platform/enforce.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
// Some trt base classes lack of the destructor.
// We use a assisted class to fix this.
struct DeleteHelper {
protected:
virtual ~DeleteHelper() {}
};
template <typename T>
inline void SerializeValue(void** buffer, T const& value);
template <typename T>
inline void DeserializeValue(void const** buffer,
size_t* buffer_size,
T* value);
namespace details {
template <typename T, class Enable = void>
struct Serializer {};
template <typename T>
struct Serializer<
T,
typename std::enable_if<std::is_arithmetic<T>::value ||
std::is_enum<T>::value || std::is_pod<T>::value ||
std::is_same<T, half>::value>::type> {
static size_t SerializedSize(T const& value) { return sizeof(T); }
static void Serialize(void** buffer, T const& value) {
std::memcpy(*buffer, &value, sizeof(T));
reinterpret_cast<char*&>(*buffer) += sizeof(T);
}
static void Deserialize(void const** buffer, size_t* buffer_size, T* value) {
assert(*buffer_size >= sizeof(T));
std::memcpy(value, *buffer, sizeof(T));
reinterpret_cast<char const*&>(*buffer) += sizeof(T);
*buffer_size -= sizeof(T);
}
};
template <>
struct Serializer<const char*> {
static size_t SerializedSize(const char* value) { return strlen(value) + 1; }
static void Serialize(void** buffer, const char* value) {
std::strcpy(static_cast<char*>(*buffer), value); // NOLINT
reinterpret_cast<char*&>(*buffer) += strlen(value) + 1;
}
static void Deserialize(void const** buffer,
size_t* buffer_size,
const char** value) {
*value = static_cast<char const*>(*buffer);
size_t data_size = strnlen(*value, *buffer_size) + 1;
assert(*buffer_size >= data_size);
reinterpret_cast<char const*&>(*buffer) += data_size;
*buffer_size -= data_size;
}
};
template <typename T>
struct Serializer<
std::vector<T>,
typename std::enable_if<std::is_arithmetic<T>::value ||
std::is_enum<T>::value || std::is_pod<T>::value ||
std::is_same<T, half>::value>::type> {
static size_t SerializedSize(std::vector<T> const& value) {
return sizeof(value.size()) + value.size() * sizeof(T);
}
static void Serialize(void** buffer, std::vector<T> const& value) {
SerializeValue(buffer, value.size());
size_t nbyte = value.size() * sizeof(T);
std::memcpy(*buffer, value.data(), nbyte);
reinterpret_cast<char*&>(*buffer) += nbyte;
}
static void Deserialize(void const** buffer,
size_t* buffer_size,
std::vector<T>* value) {
size_t size;
DeserializeValue(buffer, buffer_size, &size);
value->resize(size);
size_t nbyte = value->size() * sizeof(T);
PADDLE_ENFORCE_GE(*buffer_size,
nbyte,
common::errors::InvalidArgument(
"Insufficient data in buffer, expect contains %d "
"byte, but actually only contains %d byte.",
*buffer_size,
nbyte));
std::memcpy(value->data(), *buffer, nbyte);
reinterpret_cast<char const*&>(*buffer) += nbyte;
*buffer_size -= nbyte;
}
};
} // namespace details
template <typename T>
inline size_t SerializedSize(T const& value) {
return details::Serializer<T>::SerializedSize(value);
}
template <typename T>
inline void SerializeValue(void** buffer, T const& value) {
return details::Serializer<T>::Serialize(buffer, value);
}
template <typename T>
inline void DeserializeValue(void const** buffer,
size_t* buffer_size,
T* value) {
return details::Serializer<T>::Deserialize(buffer, buffer_size, value);
}
template <typename T>
inline void SerializeCudaPointer(void** buffer, T* value, int size) {
cudaMemcpy((*buffer), value, size * sizeof(T), cudaMemcpyDeviceToHost);
reinterpret_cast<char*&>(*buffer) += size * sizeof(T);
}
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,95 @@
// Copyright (c) 2022 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/plugin/yolo_box_head_op_plugin.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
inline __device__ float SigmoidGPU(const float& x) {
return 1.0f / (1.0f + __expf(-x));
}
__global__ void YoloBoxHeadKernel(const float* input,
float* output,
const int grid_size_x,
const int grid_size_y,
const int class_num,
const int anchors_num) {
int x_id = blockIdx.x * blockDim.x + threadIdx.x;
int y_id = blockIdx.y * blockDim.y + threadIdx.y;
int z_id = blockIdx.z * blockDim.z + threadIdx.z;
if ((x_id >= grid_size_x) || (y_id >= grid_size_y) || (z_id >= anchors_num)) {
return;
}
const int grids_num = grid_size_x * grid_size_y;
const int bbindex = y_id * grid_size_x + x_id;
// objectness
output[bbindex + grids_num * (z_id * (5 + class_num) + 4)] =
SigmoidGPU(input[bbindex + grids_num * (z_id * (5 + class_num) + 4)]);
// x
output[bbindex + grids_num * (z_id * (5 + class_num) + 0)] =
SigmoidGPU(input[bbindex + grids_num * (z_id * (5 + class_num) + 0)]);
// y
output[bbindex + grids_num * (z_id * (5 + class_num) + 1)] =
SigmoidGPU(input[bbindex + grids_num * (z_id * (5 + class_num) + 1)]);
// w
output[bbindex + grids_num * (z_id * (5 + class_num) + 2)] =
__expf(input[bbindex + grids_num * (z_id * (5 + class_num) + 2)]);
// h
output[bbindex + grids_num * (z_id * (5 + class_num) + 3)] =
__expf(input[bbindex + grids_num * (z_id * (5 + class_num) + 3)]);
// Probabilities of classes
for (int i = 0; i < class_num; ++i) {
output[bbindex + grids_num * (z_id * (5 + class_num) + (5 + i))] =
SigmoidGPU(
input[bbindex + grids_num * (z_id * (5 + class_num) + (5 + i))]);
}
}
int YoloBoxHeadPlugin::enqueue(int batch_size,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT {
const int h = input_dims_[0].d[1];
const int w = input_dims_[0].d[2];
const int grid_size_x = w;
const int grid_size_y = h;
const int anchors_num = anchors_.size() / 2;
const float* input_data = static_cast<const float*>(inputs[0]);
float* output_data = static_cast<float*>(outputs[0]);
const int volume = input_dims_[0].d[0] * h * w;
dim3 block(16, 16, 4);
dim3 grid((grid_size_x / block.x) + 1,
(grid_size_y / block.y) + 1,
(anchors_num / block.z) + 1);
for (int n = 0; n < batch_size; n++) {
YoloBoxHeadKernel<<<grid, block, 0, stream>>>(input_data + n * volume,
output_data + n * volume,
grid_size_x,
grid_size_y,
class_num_,
anchors_num);
}
return 0;
}
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
@@ -0,0 +1,105 @@
// Copyright (c) 2022 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.
#pragma once
#include <string>
#include <vector>
#include "paddle/fluid/inference/tensorrt/engine.h"
#include "paddle/fluid/inference/tensorrt/plugin/trt_plugin.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
class YoloBoxHeadPlugin : public PluginTensorRT {
public:
explicit YoloBoxHeadPlugin(const std::vector<int>& anchors,
const int class_num)
: anchors_(anchors), class_num_(class_num) {}
YoloBoxHeadPlugin(const void* data, size_t length) {
deserializeBase(data, length);
DeserializeValue(&data, &length, &anchors_);
DeserializeValue(&data, &length, &class_num_);
}
~YoloBoxHeadPlugin() override{};
nvinfer1::IPluginV2* clone() const TRT_NOEXCEPT override {
return new YoloBoxHeadPlugin(anchors_, class_num_);
}
const char* getPluginType() const TRT_NOEXCEPT override {
return "yolo_box_head_plugin";
}
int getNbOutputs() const TRT_NOEXCEPT override { return 1; }
int initialize() TRT_NOEXCEPT override { return 0; }
nvinfer1::Dims getOutputDimensions(int index,
const nvinfer1::Dims* inputs,
int nb_input_dims) TRT_NOEXCEPT override {
assert(index == 0);
assert(nb_input_dims == 1);
return inputs[0];
}
int enqueue(int batch_size,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
size_t getSerializationSize() const TRT_NOEXCEPT override {
return getBaseSerializationSize() + SerializedSize(anchors_) +
SerializedSize(class_num_);
}
void serialize(void* buffer) const TRT_NOEXCEPT override {
serializeBase(buffer);
SerializeValue(&buffer, anchors_);
SerializeValue(&buffer, class_num_);
}
private:
std::vector<int> anchors_;
int class_num_;
std::string namespace_;
};
class YoloBoxHeadPluginCreator : public TensorRTPluginCreator {
public:
const char* getPluginName() const TRT_NOEXCEPT override {
return "yolo_box_head_plugin";
}
const char* getPluginVersion() const TRT_NOEXCEPT override { return "1"; }
nvinfer1::IPluginV2* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override {
return new YoloBoxHeadPlugin(serial_data, serial_length);
}
};
REGISTER_TRT_PLUGIN_V2(YoloBoxHeadPluginCreator);
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,352 @@
// Copyright (c) 2018 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.
#pragma once
#include <string>
#include <vector>
#include "paddle/fluid/inference/tensorrt/engine.h"
#include "paddle/fluid/inference/tensorrt/plugin/trt_plugin.h"
namespace paddle {
namespace inference {
namespace tensorrt {
namespace plugin {
class YoloBoxPlugin : public nvinfer1::IPluginV2Ext {
public:
explicit YoloBoxPlugin(const nvinfer1::DataType data_type,
const std::vector<int>& anchors,
const int class_num,
const float conf_thresh,
const int downsample_ratio,
const bool clip_bbox,
const float scale_x_y,
const bool iou_aware,
const float iou_aware_factor,
const int input_h,
const int input_w);
YoloBoxPlugin(const void* data, size_t length);
~YoloBoxPlugin() override;
const char* getPluginType() const TRT_NOEXCEPT override;
const char* getPluginVersion() const TRT_NOEXCEPT override;
int getNbOutputs() const TRT_NOEXCEPT override;
nvinfer1::Dims getOutputDimensions(int index,
const nvinfer1::Dims* inputs,
int nb_input_dims) TRT_NOEXCEPT override;
bool supportsFormat(nvinfer1::DataType type, nvinfer1::TensorFormat format)
const TRT_NOEXCEPT override;
size_t getWorkspaceSize(int max_batch_size) const TRT_NOEXCEPT override;
int enqueue(int batch_size,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
template <typename T>
int enqueue_impl(int batch_size,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream);
int initialize() TRT_NOEXCEPT override;
void terminate() TRT_NOEXCEPT override;
size_t getSerializationSize() const TRT_NOEXCEPT override;
void serialize(void* buffer) const TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override;
void setPluginNamespace(const char* lib_namespace) TRT_NOEXCEPT override;
const char* getPluginNamespace() const TRT_NOEXCEPT override;
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* input_type,
int nb_inputs) const
TRT_NOEXCEPT override;
bool isOutputBroadcastAcrossBatch(int output_index,
const bool* input_is_broadcast,
int nb_inputs) const TRT_NOEXCEPT override;
bool canBroadcastInputAcrossBatch(int input_index) const
TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::Dims* input_dims,
int nb_inputs,
const nvinfer1::Dims* output_dims,
int nb_outputs,
const nvinfer1::DataType* input_types,
const nvinfer1::DataType* output_types,
const bool* input_is_broadcast,
const bool* output_is_broadcast,
nvinfer1::PluginFormat float_format,
int max_batch_size) TRT_NOEXCEPT override;
nvinfer1::IPluginV2Ext* clone() const TRT_NOEXCEPT override;
private:
nvinfer1::DataType data_type_;
std::vector<int> anchors_;
int* anchors_device_;
int class_num_;
float conf_thresh_;
int downsample_ratio_;
bool clip_bbox_;
float scale_x_y_;
int input_h_;
int input_w_;
bool iou_aware_;
float iou_aware_factor_;
std::string namespace_;
};
class YoloBoxPluginCreator : public nvinfer1::IPluginCreator {
public:
YoloBoxPluginCreator();
~YoloBoxPluginCreator() override = default;
void setPluginNamespace(const char* lib_namespace) TRT_NOEXCEPT override;
const char* getPluginNamespace() const TRT_NOEXCEPT override;
const char* getPluginName() const TRT_NOEXCEPT override;
const char* getPluginVersion() const TRT_NOEXCEPT override;
const nvinfer1::PluginFieldCollection* getFieldNames() TRT_NOEXCEPT override;
nvinfer1::IPluginV2Ext* createPlugin(
const char* name,
const nvinfer1::PluginFieldCollection* fc) TRT_NOEXCEPT override;
nvinfer1::IPluginV2Ext* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override;
private:
std::string namespace_;
nvinfer1::PluginFieldCollection field_collection_;
};
class YoloBoxPluginDynamic : public DynamicPluginTensorRT {
public:
explicit YoloBoxPluginDynamic(const nvinfer1::DataType data_type,
const std::vector<int>& anchors,
const int class_num,
const float conf_thresh,
const int downsample_ratio,
const bool clip_bbox,
const float scale_x_y,
const bool iou_aware,
const float iou_aware_factor);
YoloBoxPluginDynamic(void const* serialData, size_t serialLength);
~YoloBoxPluginDynamic() {}
nvinfer1::IPluginV2DynamicExt* clone() const TRT_NOEXCEPT override;
const char* getPluginType() const TRT_NOEXCEPT override {
return "yolo_box_plugin_dynamic";
}
int getNbOutputs() const TRT_NOEXCEPT override { return 2; }
int initialize() TRT_NOEXCEPT override { return 0; }
void terminate() TRT_NOEXCEPT override;
size_t getSerializationSize() const TRT_NOEXCEPT override;
void serialize(void* buffer) const TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override;
const char* getPluginVersion() const TRT_NOEXCEPT override;
nvinfer1::DimsExprs getOutputDimensions(
int output_index,
const nvinfer1::DimsExprs* inputs,
int nb_inputs,
nvinfer1::IExprBuilder& expr_builder) // NOLINT
TRT_NOEXCEPT override;
bool supportsFormatCombination(int pos,
const nvinfer1::PluginTensorDesc* in_out,
int nb_inputs,
int nb_outputs) TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::DynamicPluginTensorDesc* in,
int nb_inputs,
const nvinfer1::DynamicPluginTensorDesc* out,
int nb_outputs) TRT_NOEXCEPT override;
size_t getWorkspaceSize(const nvinfer1::PluginTensorDesc* inputs,
int nbInputs,
const nvinfer1::PluginTensorDesc* outputs,
int nbOutputs) const TRT_NOEXCEPT override {
return 0;
}
int enqueue(const nvinfer1::PluginTensorDesc* input_desc,
const nvinfer1::PluginTensorDesc* output_desc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
template <typename T>
int enqueue_impl(const nvinfer1::PluginTensorDesc* input_desc,
const nvinfer1::PluginTensorDesc* output_desc,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream);
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* input_types,
int nb_inputs) const
TRT_NOEXCEPT override;
private:
nvinfer1::DataType data_type_;
std::vector<int> anchors_;
int* anchors_device_;
int class_num_;
float conf_thresh_;
int downsample_ratio_;
bool clip_bbox_;
float scale_x_y_;
bool iou_aware_;
float iou_aware_factor_;
};
class YoloBoxPluginDynamicCreator : public nvinfer1::IPluginCreator {
public:
YoloBoxPluginDynamicCreator();
~YoloBoxPluginDynamicCreator() override = default;
void setPluginNamespace(const char* lib_namespace) TRT_NOEXCEPT override;
const char* getPluginNamespace() const TRT_NOEXCEPT override;
const char* getPluginName() const TRT_NOEXCEPT override;
const char* getPluginVersion() const TRT_NOEXCEPT override;
const nvinfer1::PluginFieldCollection* getFieldNames() TRT_NOEXCEPT override;
nvinfer1::IPluginV2Ext* createPlugin(
const char* name,
const nvinfer1::PluginFieldCollection* fc) TRT_NOEXCEPT override;
nvinfer1::IPluginV2Ext* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override;
private:
std::string namespace_;
nvinfer1::PluginFieldCollection field_collection_;
};
class PIRYoloBoxPlugin : public nvinfer1::IPluginV2Ext {
public:
explicit PIRYoloBoxPlugin(const nvinfer1::DataType data_type,
const std::vector<int>& anchors,
const int class_num,
const float conf_thresh,
const int downsample_ratio,
const bool clip_bbox,
const float scale_x_y,
const bool iou_aware,
const float iou_aware_factor,
const int input_h,
const int input_w);
PIRYoloBoxPlugin(const void* data, size_t length);
~PIRYoloBoxPlugin() override;
const char* getPluginType() const TRT_NOEXCEPT override;
const char* getPluginVersion() const TRT_NOEXCEPT override;
int getNbOutputs() const TRT_NOEXCEPT override;
nvinfer1::Dims getOutputDimensions(int index,
const nvinfer1::Dims* inputs,
int nb_input_dims) TRT_NOEXCEPT override;
bool supportsFormat(nvinfer1::DataType type, nvinfer1::TensorFormat format)
const TRT_NOEXCEPT override;
size_t getWorkspaceSize(int max_batch_size) const TRT_NOEXCEPT override;
int enqueue(int batch_size,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream) TRT_NOEXCEPT override;
template <typename T>
int enqueue_impl(int batch_size,
const void* const* inputs,
void* const* outputs,
void* workspace,
cudaStream_t stream);
int initialize() TRT_NOEXCEPT override;
void terminate() TRT_NOEXCEPT override;
size_t getSerializationSize() const TRT_NOEXCEPT override;
void serialize(void* buffer) const TRT_NOEXCEPT override;
void destroy() TRT_NOEXCEPT override;
void setPluginNamespace(const char* lib_namespace) TRT_NOEXCEPT override;
const char* getPluginNamespace() const TRT_NOEXCEPT override;
nvinfer1::DataType getOutputDataType(int index,
const nvinfer1::DataType* input_type,
int nb_inputs) const
TRT_NOEXCEPT override;
bool isOutputBroadcastAcrossBatch(int output_index,
const bool* input_is_broadcast,
int nb_inputs) const TRT_NOEXCEPT override;
bool canBroadcastInputAcrossBatch(int input_index) const
TRT_NOEXCEPT override;
void configurePlugin(const nvinfer1::Dims* input_dims,
int nb_inputs,
const nvinfer1::Dims* output_dims,
int nb_outputs,
const nvinfer1::DataType* input_types,
const nvinfer1::DataType* output_types,
const bool* input_is_broadcast,
const bool* output_is_broadcast,
nvinfer1::PluginFormat float_format,
int max_batch_size) TRT_NOEXCEPT override;
nvinfer1::IPluginV2Ext* clone() const TRT_NOEXCEPT override;
private:
nvinfer1::DataType data_type_;
std::vector<int> anchors_;
int* anchors_device_;
int class_num_;
float conf_thresh_;
int downsample_ratio_;
bool clip_bbox_;
float scale_x_y_;
int input_h_;
int input_w_;
bool iou_aware_;
float iou_aware_factor_;
std::string namespace_;
};
class PIRYoloBoxPluginCreator : public nvinfer1::IPluginCreator {
public:
PIRYoloBoxPluginCreator();
~PIRYoloBoxPluginCreator() override = default;
void setPluginNamespace(const char* lib_namespace) TRT_NOEXCEPT override;
const char* getPluginNamespace() const TRT_NOEXCEPT override;
const char* getPluginName() const TRT_NOEXCEPT override;
const char* getPluginVersion() const TRT_NOEXCEPT override;
const nvinfer1::PluginFieldCollection* getFieldNames() TRT_NOEXCEPT override;
nvinfer1::IPluginV2Ext* createPlugin(
const char* name,
const nvinfer1::PluginFieldCollection* fc) TRT_NOEXCEPT override;
nvinfer1::IPluginV2Ext* deserializePlugin(const char* name,
const void* serial_data,
size_t serial_length)
TRT_NOEXCEPT override;
private:
std::string namespace_;
nvinfer1::PluginFieldCollection field_collection_;
};
REGISTER_TRT_PLUGIN_V2(YoloBoxPluginCreator);
REGISTER_TRT_PLUGIN_V2(PIRYoloBoxPluginCreator);
REGISTER_TRT_PLUGIN_V2(YoloBoxPluginDynamicCreator);
} // namespace plugin
} // namespace tensorrt
} // namespace inference
} // namespace paddle