chore: import upstream snapshot with attribution
Docker Image CI / build-ubuntu2004 (push) Waiting to run

This commit is contained in:
wehub-resource-sync
2026-07-13 13:36:55 +08:00
commit c8a779b1bb
1887 changed files with 3245738 additions and 0 deletions
+30
View File
@@ -0,0 +1,30 @@
#
# SPDX-FileCopyrightText: Copyright (c) 1993-2025 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.
#
add_plugin_source(
embLayerNormKernel.cu
embLayerNormPlugin.cpp
embLayerNormPlugin.h
embLayerNormPluginLegacy.cpp
embLayerNormPluginLegacy.h
embLayerNormVarSeqlenKernelHFace.cu
embLayerNormVarSeqlenKernelMTron.cu
embLayerNormVarSeqlenPlugin.cpp
embLayerNormVarSeqlenPlugin.h
embLayerNormVarSeqlenPluginLegacy.cpp
embLayerNormVarSeqlenPluginLegacy.h
)
@@ -0,0 +1,170 @@
#
# SPDX-FileCopyrightText: Copyright (c) 2022-2025 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.
#
---
name: CustomEmbLayerNormPluginDynamic
interface: "IPluginV3"
versions:
"6":
inputs:
- token_id
- segment_id
- input_mask
outputs:
- embedded_input
- maskIdx
input_dims:
token_id: 2
segment_id: 2
input_mask: 2
input_dim_constraints:
- "token_id_0 == bert_embeddings_position_embeddings_0"
- "segment_id_0 == bert_embeddings_position_embeddings_0"
- "segment_id_1 == token_id_1"
- "input_mask_0 == bert_embeddings_position_embeddings_0"
- "input_mask_1 == token_id_1"
input_dim_range:
token_id:
min: "=1, =1"
max: "=pinf, =pinf"
segment_id:
min: "=1, =1"
max: "=pinf, =pinf"
input_mask:
min: "=1, =1"
max: "=pinf, =pinf"
supported_input_types:
combination1:
token_id: int32
segment_id: int32
input_mask: int32
output_dims:
embedded_input: "token_id_0, token_id_1, bert_embeddings_layernorm_beta_0, 1, 1"
maskIdx: "token_id_1, 1"
attributes:
- output_fp16
- full_mask
- mha_type_id
- bert_embeddings_layernorm_beta
- bert_embeddings_layernorm_gamma
- bert_embeddings_word_embeddings
- bert_embeddings_token_type_embeddings
- bert_embeddings_position_embeddings
attribute_types:
output_fp16: int32
full_mask: int32
mha_type_id: int32
bert_embeddings_layernorm_beta: float32
bert_embeddings_layernorm_gamma: float32
bert_embeddings_word_embeddings: float32
bert_embeddings_token_type_embeddings: float32
bert_embeddings_position_embeddings: float32
attribute_dims:
output_fp16: 1
full_mask: 1
mha_type_id: 1
bert_embeddings_layernorm_beta: 1
bert_embeddings_layernorm_gamma: 1
bert_embeddings_word_embeddings: 2
bert_embeddings_token_type_embeddings: 2
bert_embeddings_position_embeddings: 2
attribute_dim_range:
output_fp16:
- min: "=1"
- max: "=1"
full_mask:
- min: "=1"
- max: "=1"
mha_type_id:
- min: "=1"
- max: "=1"
bert_embeddings_layernorm_beta:
- min: "=1"
- max: "=pinf"
bert_embeddings_layernorm_gamma:
- min: "=1"
- max: "=pinf"
bert_embeddings_word_embedding:
- min: "=1, =1"
- max: "=pinf, =pinf"
bert_embeddings_token_type_embeddings:
- min: "=1, =1"
- max: "=pinf, =pinf"
bert_embeddings_position_embeddings:
- min: "=1, =1"
- max: "=pinf, =pinf"
attribute_options:
output_fp16:
- 0
- 1
full_mask:
- 0
- 1
mha_type_id:
- 0
- 1
- 2
bert_embeddings_layernorm_beta:
min: "=ninf"
max: "=pinf"
bert_embeddings_layernorm_gamma:
min: "=ninf"
max: "=pinf"
bert_embeddings_word_embeddings:
min: "=ninf"
max: "=pinf"
bert_embeddings_token_type_embeddings:
min: "=ninf"
max: "=pinf"
bert_embeddings_position_embeddings:
min: "=ninf"
max: "=pinf"
attributes_required:
- bert_embeddings_layernorm_beta
- bert_embeddings_layernorm_gamma
- bert_embeddings_word_embeddings
- bert_embeddings_token_type_embeddings
- bert_embeddings_position_embeddings
golden_reference_script: "plugin/CustomEmbLayerNormPluginDynamic_PluginReference.py"
abs_tol: 1e-5
rel_tol: 1e-5
configs:
config1:
input_types:
token_id: int32
segment_id: int32
input_mask: int32
attribute_options:
output_fp16:
value: 0
shape: "1"
full_mask:
value: 0
shape: "1"
mha_type_id:
value: 0
shape: "1"
bert_embeddings_layernorm_beta:
shape: "128"
bert_embeddings_layernorm_gamma:
shape: "128"
bert_embeddings_word_embeddings:
shape: "100, 128"
bert_embeddings_token_type_embeddings:
shape: "2, 128"
bert_embeddings_position_embeddings:
shape: "20, 128"
...
+144
View File
@@ -0,0 +1,144 @@
# embLayerNormPlugin
**Table Of Contents**
- [Description](#description)
* [Structure](#structure)
- [Parameters](#parameters)
- [Additional resources](#additional-resources)
- [License](#license)
- [Changelog](#changelog)
- [Known issues](#known-issues)
## Description
> NOTE: Versions 1-3 of this plugin (using IPluginV2DynamicExt interface) are deprecated and will be removed in a future release. Versions 4-6 (using IPluginV3 interface) are the recommended replacements.
The plugin performs the following two tasks:
1. Embeds an input sequence consisting of token ids and segment ids. This consists of token embedding lookup, segment embedding lookup, adding positional embeddings and finally, layer normalization.
2. For version 1 of the plugin only, preprocesses input masks, that are used to mark valid input tokens in sequences that are padded to the target sequence length.
Assuming contiguous input masks, encodes the masks as a single number denoting the number of valid elements, e.g.:
```
111100 => 4
110000 => 2
110100: Invalid mask, because it is not contiguous
```
For subsequent versions (2,3,4,5), the input mask is returned after casting to `half` and reshaping to the shape of the embedded output.
### Structure
The version 1 `embLayerNormPlugin` takes three inputs; `token_id`, `segment_id`, and `input_mask`.
The subsequent versions 2,3,4,5 (variable seqlen) take four inputs; `token_id`, `segment_id`, `cu_seqlen`, and `max_seqlen`.
### Version 1 & 6
Inputs:
- `token_id`
An input sequence containing token ids. token_id is an `int32` tensor with shape `[S, B,]` where `S` is the sequence length and `B` is the batch size.
Tokens typically identify words or word pieces that were obtained by preprocessing the input text.
- `segment_id`
An input sequence containing segment ids. segment_id is an `int32` tensor with shape `[S, B]` where `S` is the sequence length and `B` is the batch size.
The segment id is used to distinguish between different parts of the input sequence that might serve different purposes. E.g. in a squad task, the input sequence might consist of a segment representing the knowledge base (i.e. a paragraph of text) and a segment representing the question.
- `input_mask`
input_mask is an `int32` tensor with shape `[S, B]` where `S` is the sequence length and `B` is the batch size.
The input mask denotes valid elements in a sequence that was padded to the sequence length `S`.
Outputs:
- `embedded_output`
embedded_output is a floating point tensor with shape `[S, B, E]` where `S` is sequence length, `B` is batch size, and `E` is hidden size.
The final output embedding is the sum of embeddings for the token, the segment and the position in the sequence.
- `maskIdx`
The `maskIdx` is a more compact representation of the input mask, consisting of the number of valid elements, assuming that the original mask was contiguous.
For fixed sequence length version 1, the `maskIdx` is an `int32` tensor with shape `[B, packSize]` where `B` is batch size, `packSize` is the packed mask size that depends on the sequence length.
### 6 > Version >= 2
Inputs:
- `token_id`
An input sequence containing token ids. token_id is a 1-D, `int32` tensor with shape `[SxB]` where `S` is the sequence length and `B` is the batch size.
Tokens typically identify words or word pieces that were obtained by preprocessing the input text.
- `segment_id`
An input sequence containing segment ids. segment_id is also a 1-D, `int32` tensor with shape `[SxB]` where `S` is the sequence length and `B` is the batch size.
The segment id is used to distinguish between different parts of the input sequence that might serve different purposes. E.g. in a squad task, the input sequence might consist of a segment representing the knowledge base (i.e. a paragraph of text) and a segment representing the question.
- `input_mask`
input_mask is also a 1-D, `int32` tensor with shape `[SxB]` where `S` is the sequence length and `B` is the batch size.
The input mask denotes valid elements in a sequence that was padded to the sequence length `S`.
- `cu_seqlen` (Version 2,3,4,5 only)
An input sequence containing the "cumulative sequence lengths", used to index into the right sequence when sequences have variable lengths. `cu_seqlen` is a 1-D, `int32` tensor with shape `[B+1]` where `B` is the batch size.
- `max_seqlen` (Version 2,3,4,5 only)
Scalar `int32` value that specifies the maximum sequence length.
Outputs:
- `embedded_output`
embedded_output is a floating point tensor with shape `[SxB, E, 1, 1]` where `S` is sequence length, `B` is batch size, and `E` is hidden size.
The final output embedding is the sum of embeddings for the token, the segment and the position in the sequence.
- `maskIdx`
(1) Huggingface variant (versions 2,4): An empty tensor (for backwards compatibility)
(2) Megatron variant (versions 3,5): The inputs masks returned as a `half` tensor with the same shape as `embedded_output` - `[SxB, E, 1, 1]`.
## Parameters
`embLayerNormPlugin` has plugin creator class `EmbLayerNormPluginDynamicCreator` and plugin class `CustomEmbLayerNormPluginDynamic`.
The parameters are defined below and consists of the following attributes:
| Type | Parameter | Version | Description
|----------|----------------------------------------|-------------------|--------------------------------------------------------
|`int` |`output_fp16` | 1, 2, 3, 4, 5, 6 |Integer encoding the DataType, set 0 when build FP32 network and set 1 when build FP32/INT8 network (0: FP32, 1: FP16)
|`int` |`full_mask` | 1, 6 |Whether to output the full mask that works with the specialized multi-head-attention plugin kernels (this is deprecated, please use mha_type_id)
|`int` |`mha_type_id` | 1, 6 |Integer encoding the multi-head-attention plugin DataType (0: FP32, 1: FP16, 2: INT8)
|`Weights` |`bert_embeddings_layernorm_beta` | 1, 2, 3, 4, 5, 6 |Beta parameter for layer norm. Shape: `[E,]` where `E` is hidden size
|`Weights` |`bert_embeddings_layernorm_gamma` | 1, 2, 3, 4, 5, 6 |Gamma parameter for layer norm. Shape: `[E,]` where `E` is hidden size
|`Weights` |`bert_embeddings_word_embeddings` | 1, 2, 3, 4, 5, 6 |Token embedding matrix. Shape: `[word_vocab_size, E]` where `E` is hidden size
|`Weights` |`bert_embeddings_token_type_embeddings` | 1, 2, 3, 4, 5, 6 |Token type embedding matrix. Shape: `[type_vocab_size, E]` where `E` is hidden size
|`Weights` |`bert_embeddings_position_embeddings` | 1, 2, 3, 4, 5, 6 |Positional embedding matrix. Shape: `[S, E]` where `S` is the maximum sequence length and `E` is hidden size
Note: version 1, 2, 3 are deprecated and will be removed in a future release; please use their corresponding updated versions: 6, 4, 5 respectively.
## Additional resources
The following resources provide a deeper understanding of the `embLayerNormPlugin` plugin:
**Networks:**
- [BERT](https://arxiv.org/abs/1810.04805)
## License
For terms and conditions for use, reproduction, and distribution, see the [TensorRT Software License Agreement](https://docs.nvidia.com/deeplearning/sdk/tensorrt-sla/index.html)
documentation.
## Changelog
September 2024:
Added `EmblayerNormPlugin` version 6 that mirrors version 1 in IO and attributes (but uses underlying `IPluginV3` implementation instead of the deprecated `IPluginV2DynamicExt` interface)
July 2024:
Add `EmbLayerNormPlugin` versions 3 & 4 that duplicate the behavior of v2 and v3 plugins respectively, but implement the `IPluginV3` interface instead of the deprecated `IPluginV2DynamicExt` interface.
Update this README with updated description of I/O and structure.
October 2020:
Add V2 plugin that supports variable sequence length.
November 2019:
This is the first release of this `README.md` file.
## Known issues
This plugin only supports GPUs with compute capability >= 7.0. For more information see the [CUDA GPU Compute Capability Support Matrix](https://developer.nvidia.com/cuda-gpus#compute)
@@ -0,0 +1,263 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 1993-2025 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 <cuda.h>
#if CUDA_VERSION >= 10010
#include <cassert>
#include <cstring>
#include <vector>
#include "NvInfer.h"
#include "common/bertCommon.h"
#include "common/common.cuh"
#include "common/serialize.hpp"
#include "common/cubCcclCompat.h"
#include "embLayerNormPlugin.h"
using namespace nvinfer1;
namespace nvinfer1
{
namespace plugin
{
namespace bert
{
__global__ void fillSBSMaskKernel(
uint32_t const warps_m, uint32_t const warps_n, uint32_t const S, int32_t const* inputMaskSB, uint32_t* inputMaskX)
{
extern __shared__ int shm_mask[]; // S mask elements of this batch
size_t const xmmas_n = (S + 16 * warps_n - 1) / (16 * warps_n);
uint32_t const threads_per_cta = blockDim.x;
uint32_t const xmmas_m = gridDim.x;
uint32_t const B = gridDim.y;
uint32_t const mi = blockIdx.x;
uint32_t const bi = blockIdx.y;
uint32_t const tidx = threadIdx.x;
size_t const warp = tidx / 32;
size_t const warp_n = warp / warps_m;
size_t const lane = tidx % 32;
size_t const col = warp_n * 16 + lane % 4 * 2;
// load the mask corresponding to one batch
for (uint32_t si = tidx; si < S; si += threads_per_cta)
{
// not coalesced to conform to current input format: SxB
shm_mask[si] = inputMaskSB[si * B + bi];
}
__syncthreads();
uint32_t mask = 0u;
for (size_t ni = 0; ni < xmmas_n; ++ni)
{
int32_t const offset = ni * 16 * warps_n + col;
mask |= (shm_mask[offset + 0] == 1.f ? 1u : 0u) << (8 * ni + 0);
mask |= (shm_mask[offset + 1] == 1.f ? 1u : 0u) << (8 * ni + 1);
mask |= (shm_mask[offset + 0] == 1.f ? 1u : 0u) << (8 * ni + 2);
mask |= (shm_mask[offset + 1] == 1.f ? 1u : 0u) << (8 * ni + 3);
mask |= (shm_mask[offset + 8] == 1.f ? 1u : 0u) << (8 * ni + 4);
mask |= (shm_mask[offset + 9] == 1.f ? 1u : 0u) << (8 * ni + 5);
mask |= (shm_mask[offset + 8] == 1.f ? 1u : 0u) << (8 * ni + 6);
mask |= (shm_mask[offset + 9] == 1.f ? 1u : 0u) << (8 * ni + 7);
}
inputMaskX[(bi * xmmas_m + mi) * threads_per_cta + tidx] = mask;
}
cudaError_t convertMask(uint32_t const S, uint32_t const B, uint32_t const warps_m, uint32_t const warps_n,
uint32_t const warps_k, int32_t const* inputMaskSB, uint32_t* inputMaskX, cudaStream_t stream)
{
size_t const xmmas_m = (S + 16 * warps_m - 1) / (16 * warps_m);
size_t const threads_per_cta = warps_m * warps_n * warps_k * 32;
dim3 grid(xmmas_m, B);
fillSBSMaskKernel<<<grid, threads_per_cta, S * sizeof(int), stream>>>(warps_m, warps_n, S, inputMaskSB, inputMaskX);
return cudaPeekAtLastError();
}
template <unsigned TPB>
__global__ void maskIdxKernelSmall(int ld, int32_t const* mask, int* maskIdx)
{
using BlockReduce = cub::BlockReduce<int32_t, TPB>;
__shared__ typename BlockReduce::TempStorage tmpStorage;
auto min = compat::getCudaMinOp();
int threadData(ld); // if the mask admits all values
if (threadIdx.x < ld)
{
// mask has input dims {S, B} and gridDims.x is B
int32_t const idx = threadIdx.x * gridDim.x + blockIdx.x;
int32_t const val = mask[idx];
if (val == 0) // masked position: report thread idx
{
threadData = threadIdx.x;
}
}
const auto minIdx = BlockReduce(tmpStorage).Reduce(threadData, min);
if (threadIdx.x == 0)
{
maskIdx[blockIdx.x] = minIdx;
}
}
template <unsigned TPB>
__global__ void maskIdxKernel(int ld, int32_t const* mask, int* maskIdx)
{
using BlockReduce = cub::BlockReduce<int32_t, TPB>;
__shared__ typename BlockReduce::TempStorage tmpStorage;
auto min = compat::getCudaMinOp();
int threadData(ld); // if the mask admits all values
for (int i = threadIdx.x; i < ld; i += TPB)
{
// mask has input dims {S, B} and gridDims.x is B
int32_t const idx = i * gridDim.x + blockIdx.x;
int32_t const val = mask[idx];
if (val == 0) // masked position: report thread idx
{
threadData = min(threadData, i);
}
}
const auto minIdx = BlockReduce(tmpStorage).Reduce(threadData, min);
if (threadIdx.x == 0)
{
maskIdx[blockIdx.x] = minIdx;
}
}
int computeMaskIdx(cudaStream_t stream, int32_t const S, int32_t const B, int32_t const* mask, int* maskIdx)
{
// Mask idx is of length B and assumes the valid region is contiguous starting
// from the beginning of the sequence
// Assume n = BxS
if (S <= 32)
{
maskIdxKernelSmall<32><<<B, 32, 0, stream>>>(S, mask, maskIdx);
}
else if (S <= 128)
{
maskIdxKernelSmall<128><<<B, 128, 0, stream>>>(S, mask, maskIdx);
}
else if (S == 384)
{
maskIdxKernelSmall<384><<<B, 384, 0, stream>>>(S, mask, maskIdx);
}
else
{
maskIdxKernel<256><<<B, 256, 0, stream>>>(S, mask, maskIdx);
}
return cudaPeekAtLastError();
}
template <typename T, unsigned TPB>
__global__ void embLayerNormKernel(int ld, int32_t const* inputIds, int32_t const* tokenIds, float const* beta,
float const* gamma, T const* wordEmb, T const* posEmb, T const* tokEmb, int32_t const wordSize,
int32_t const tokSize, T* output)
{
// 1. lookup word and token of the block
// blockIdx.x = position in the sequence
// blockIdx.y = batch
// gridDim.x = S
// gridDim.y = B
__shared__ int wordId;
__shared__ int tokenId;
T const rld = T(1.f) / T(ld);
int32_t const seqPos = blockIdx.y + blockIdx.x * gridDim.y;
if (threadIdx.x == 0)
{
wordId = inputIds[seqPos];
tokenId = tokenIds[seqPos];
}
__syncthreads();
// 2. load pos/tok/word embeddings and add them toghether
// offset into embeddings is given by wordId * hidden_size
int32_t const poffset = blockIdx.x * ld;
int32_t const woffset = wordId * ld;
int32_t const toffset = tokenId * ld;
// the output offset is given by b * (S*hidden_size) + s * hidden_size
int32_t const outOffset = seqPos * ld;
kvp<T> threadData(0, 0);
if (wordId >= 0 && wordId < wordSize && tokenId >= 0 && tokenId < tokSize)
{
for (int it = threadIdx.x; it < ld; it += TPB)
{
T const w(wordEmb[woffset + it]);
T const t(tokEmb[toffset + it]);
T const p(posEmb[poffset + it]);
T const val = w + t + p;
output[outOffset + it] = val;
T const rldval = rld * val;
threadData = 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>
int embSkipLayerNorm(cudaStream_t stream, int ld, int B, int S, int32_t const* inputIds, int32_t const* tokenIds,
float const* beta, float const* gamma, T const* wordEmb, T const* posEmb, T const* tokEmb, int32_t const wordSize,
int32_t const tokSize, T* output)
{
constexpr int tpb = 256;
dim3 const grid(S, B, 1);
dim3 const block(tpb, 1, 1);
embLayerNormKernel<T, tpb><<<grid, block, 0, stream>>>(
ld, inputIds, tokenIds, beta, gamma, wordEmb, posEmb, tokEmb, wordSize, tokSize, output);
PLUGIN_CHECK(cudaPeekAtLastError());
return 0;
}
template int embSkipLayerNorm<float>(cudaStream_t, int32_t, int32_t, int32_t, int32_t const*, int32_t const*,
float const*, float const*, float const*, float const*, float const*, int32_t const, int32_t const, float*);
template int embSkipLayerNorm<half>(cudaStream_t, int32_t, int32_t, int32_t, int32_t const*, int32_t const*,
float const*, float const*, half const*, half const*, half const*, int32_t const, int32_t const, half*);
} // namespace bert
} // namespace plugin
} // namespace nvinfer1
#endif // CUDA_VERSION >= 10010
@@ -0,0 +1,687 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 1993-2026 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 <cuda.h>
#if CUDA_VERSION >= 10010
#include <memory>
#include <set>
#include <string_view>
#include <vector>
#include "NvInfer.h"
#include "embLayerNormPlugin.h"
using namespace nvinfer1;
using namespace nvinfer1::plugin;
using namespace nvinfer1::plugin::bert;
namespace
{
using namespace std::string_view_literals;
char const* gEmbLayerNormVersion{"6"};
char const* gEmbLayerNormName{"CustomEmbLayerNormPluginDynamic"};
} // namespace
REGISTER_TENSORRT_PLUGIN(EmbLayerNormPluginDynamicCreator);
EmbLayerNormPluginDynamic::EmbLayerNormPluginDynamic(std::string const& name, DataType const type,
DataType const mhaType, Weights const& beta, Weights const& gamma, Weights const& wordEmb, Weights const& posEmb,
Weights const& tokEmb, bool const useFullMask)
: mLayerName(name)
, mLd(beta.count)
, mType(type)
, mMhaType(mhaType)
{
// Assuming Weights.count is the number of elements and not bytes
PLUGIN_VALIDATE(beta.count == gamma.count);
PLUGIN_VALIDATE(mLd > 0U);
PLUGIN_VALIDATE(wordEmb.count % mLd == 0);
PLUGIN_VALIDATE(posEmb.count % mLd == 0);
PLUGIN_VALIDATE(tokEmb.count % mLd == 0);
mWordVocabSize = wordEmb.count / mLd;
mPosVocabSize = posEmb.count / mLd;
mTokVocabSize = tokEmb.count / mLd;
mSM = getSmVersion();
mOutputFp16 = mType == DataType::kHALF ? 1 : 0;
mUseFullMask = static_cast<int32_t>(useFullMask);
// NOTE: mS is set during configure
mBeta.convertAndCopy(beta, nvinfer1::DataType::kFLOAT);
mGamma.convertAndCopy(gamma, nvinfer1::DataType::kFLOAT);
mWordEmb.convertAndCopy(wordEmb, mType);
mTokEmb.convertAndCopy(tokEmb, mType);
mPosEmb.convertAndCopy(posEmb, mType);
copyToDevice(mGamma, sizeof(float) * mGamma.count, mGammaDev);
copyToDevice(mBeta, sizeof(float) * mBeta.count, mBetaDev);
copyToDevice(mWordEmb, getWeightsSize(mWordEmb, mType), mWordEmbDev);
copyToDevice(mPosEmb, getWeightsSize(mPosEmb, mType), mPosEmbDev);
copyToDevice(mTokEmb, getWeightsSize(mTokEmb, mType), mTokEmbDev);
}
EmbLayerNormPluginDynamic::~EmbLayerNormPluginDynamic()
{
try
{
// This gets called when the network containing plugin is destroyed
mGammaDev.reset(nullptr);
mBetaDev.reset(nullptr);
mWordEmbDev.reset(nullptr);
mPosEmbDev.reset(nullptr);
mTokEmbDev.reset(nullptr);
// delete this; TRT or the creator of the plugin will delete this plugin object
}
catch (std::exception const& e)
{
caughtError(e);
}
}
//////
// IPluginV3 method definitions:
// - getCapabilityInterface() (Base)
// - clone() (HFace, MTron)
//////
IPluginCapability* EmbLayerNormPluginDynamic::getCapabilityInterface(PluginCapabilityType type) noexcept
{
try
{
if (type == PluginCapabilityType::kBUILD)
{
return static_cast<IPluginV3OneBuild*>(this);
}
if (type == PluginCapabilityType::kRUNTIME)
{
return static_cast<IPluginV3OneRuntime*>(this);
}
PLUGIN_ASSERT(type == PluginCapabilityType::kCORE);
return static_cast<IPluginV3OneCore*>(this);
}
catch (std::exception const& e)
{
caughtError(e);
}
return nullptr;
}
IPluginV3* EmbLayerNormPluginDynamic::clone() noexcept
{
try
{
BERT_DEBUG_MSG("EmbLayerNormPluginDynamic clone.");
auto p = std::make_unique<EmbLayerNormPluginDynamic>(
mLayerName, mType, mMhaType, mBeta, mGamma, mWordEmb, mPosEmb, mTokEmb, mUseFullMask == 1);
p->mS = mS;
p->setPluginNamespace(mNamespace.c_str());
return p.release();
}
catch (std::exception const& e)
{
caughtError(e);
}
return nullptr;
}
// End IPluginV3 method definitions
//////
// IPluginV3OneRuntime method definitions:
// - getFieldsToSerialize()
// - onShapeChange()
// - attachToContext()
// - enqueue()
/////
PluginFieldCollection const* EmbLayerNormPluginDynamic::getFieldsToSerialize() noexcept
{
mDataToSerialize.clear();
mDataToSerialize.emplace_back("output_fp16", &mOutputFp16, PluginFieldType::kINT32, 1);
mDataToSerialize.emplace_back("full_mask", &mUseFullMask, PluginFieldType::kINT32, 1);
mDataToSerialize.emplace_back("mha_type_id", &mMhaType, PluginFieldType::kINT32, 1);
mDataToSerialize.emplace_back("bert_embeddings_layernorm_beta", static_cast<float const*>(mBeta.values),
PluginFieldType::kFLOAT32, mBeta.count);
mDataToSerialize.emplace_back("bert_embeddings_layernorm_gamma", static_cast<float const*>(mGamma.values),
PluginFieldType::kFLOAT32, mGamma.count);
if (mOutputFp16)
{
mDataToSerialize.emplace_back("bert_embeddings_word_embeddings", static_cast<half const*>(mWordEmb.values),
PluginFieldType::kFLOAT16, mWordEmb.count);
mDataToSerialize.emplace_back("bert_embeddings_token_type_embeddings", static_cast<half const*>(mTokEmb.values),
PluginFieldType::kFLOAT16, mTokEmb.count);
mDataToSerialize.emplace_back("bert_embeddings_position_embeddings", static_cast<half const*>(mPosEmb.values),
PluginFieldType::kFLOAT16, mPosEmb.count);
}
else
{
mDataToSerialize.emplace_back("bert_embeddings_word_embeddings", static_cast<float const*>(mWordEmb.values),
PluginFieldType::kFLOAT32, mWordEmb.count);
mDataToSerialize.emplace_back("bert_embeddings_token_type_embeddings",
static_cast<float const*>(mTokEmb.values), PluginFieldType::kFLOAT32, mTokEmb.count);
mDataToSerialize.emplace_back("bert_embeddings_position_embeddings", static_cast<float const*>(mPosEmb.values),
PluginFieldType::kFLOAT32, mPosEmb.count);
}
mFCToSerialize.nbFields = mDataToSerialize.size();
mFCToSerialize.fields = mDataToSerialize.data();
return &mFCToSerialize;
}
int32_t EmbLayerNormPluginDynamic::onShapeChange(
PluginTensorDesc const* inputs, int32_t nbInputs, PluginTensorDesc const* outputs, int32_t nbOutputs) noexcept
{
BERT_DEBUG_MSG("EmbLayerNormPluginDynamic configurePlugin.");
try
{
// Validate input arguments
PLUGIN_ASSERT(nbOutputs == 2);
PLUGIN_ASSERT(nbInputs == 3);
PLUGIN_ASSERT(inputs[0].dims.nbDims == 2);
int32_t const S = inputs[0].dims.d[SDIM];
mS = S;
int32_t const B = inputs[0].dims.d[BDIM];
TRT_UNUSED B;
PLUGIN_ASSERT(mS == static_cast<size_t>(inputs[1].dims.d[SDIM]));
PLUGIN_ASSERT(B == inputs[1].dims.d[BDIM]);
PLUGIN_ASSERT(mS == static_cast<size_t>(inputs[2].dims.d[SDIM]));
PLUGIN_ASSERT(B == inputs[2].dims.d[BDIM]);
PLUGIN_ASSERT(outputs[0].dims.nbDims == 5);
PLUGIN_ASSERT(static_cast<size_t>(outputs[0].dims.d[SDIM]) == mS);
PLUGIN_ASSERT(outputs[0].dims.d[BDIM] == B);
PLUGIN_ASSERT(static_cast<size_t>(outputs[0].dims.d[2]) == mLd);
PLUGIN_ASSERT(outputs[0].dims.d[3] == 1);
PLUGIN_ASSERT(outputs[0].dims.d[4] == 1);
if (mUseFullMask)
{
// user force full_mask
PLUGIN_ASSERT(outputs[1].dims.nbDims == 2);
PLUGIN_ASSERT(outputs[1].dims.d[0] == B);
PLUGIN_ASSERT((outputs[1].dims.d[1] == -1) || (outputs[1].dims.d[1] == packedMaskSize384)
|| (outputs[1].dims.d[1] == packedMaskSize128));
}
else
{
// auto detect using mhatype
if (S != -1 && B != -1)
{
PLUGIN_ASSERT(outputs[1].dims.nbDims == 2);
PLUGIN_ASSERT(outputs[1].dims.d[0] == B);
int32_t packedSize = getMHAMaskPackedSize(mSM, mMhaType, S);
TRT_UNUSED packedSize;
PLUGIN_ASSERT(outputs[1].dims.d[1] == -1 || outputs[1].dims.d[1] == packedSize);
}
}
PLUGIN_ASSERT(inputs[0].type == DataType::kINT32);
PLUGIN_ASSERT(inputs[1].type == DataType::kINT32);
PLUGIN_ASSERT(inputs[2].type == DataType::kINT32);
PLUGIN_ASSERT(outputs[0].type == mType);
PLUGIN_ASSERT(outputs[1].type == DataType::kINT32);
return pluginStatus_t::STATUS_SUCCESS;
}
catch (std::exception const& e)
{
caughtError(e);
}
return pluginStatus_t::STATUS_FAILURE;
}
IPluginV3* EmbLayerNormPluginDynamic::attachToContext(IPluginResourceContext* context) noexcept
{
return clone();
}
int32_t EmbLayerNormPluginDynamic::enqueue(PluginTensorDesc const* inputDesc, PluginTensorDesc const* /* outputDesc */,
void const* const* inputs, void* const* outputs, void* /* workspace */, cudaStream_t stream) noexcept
{
try
{
PLUGIN_VALIDATE(inputDesc != nullptr && inputs != nullptr && outputs != nullptr);
int32_t const batchSize = inputDesc->dims.d[BDIM];
int32_t const S = inputDesc->dims.d[SDIM];
int32_t status = STATUS_FAILURE;
// Our plugin outputs only one tensor
auto const inputIds = static_cast<int32_t const*>(inputs[0]);
auto const segmentIds = static_cast<int32_t const*>(inputs[1]);
auto const inputMask = static_cast<int32_t const*>(inputs[2]);
float const* beta = mBetaDev.get();
float const* gamma = mGammaDev.get();
if (mType == DataType::kFLOAT)
{
auto output = static_cast<float*>(outputs[0]);
auto const wordEmb = static_cast<float const*>(mWordEmbDev.get());
auto const tokEmb = static_cast<float const*>(mTokEmbDev.get());
auto const posEmb = static_cast<float const*>(mPosEmbDev.get());
status = embSkipLayerNorm<float>(stream, static_cast<int32_t>(mLd), batchSize, S, inputIds, segmentIds,
beta, gamma, wordEmb, posEmb, tokEmb, mWordVocabSize, mTokVocabSize, output);
if (status != cudaSuccess)
{
return status;
}
}
else if (mType == DataType::kHALF)
{
auto output = static_cast<half*>(outputs[0]);
auto const wordEmb = static_cast<half const*>(mWordEmbDev.get());
auto const tokEmb = static_cast<half const*>(mTokEmbDev.get());
auto const posEmb = static_cast<half const*>(mPosEmbDev.get());
status = embSkipLayerNorm<half>(stream, static_cast<int32_t>(mLd), batchSize, S, inputIds, segmentIds, beta,
gamma, wordEmb, posEmb, tokEmb, mWordVocabSize, mTokVocabSize, output);
if (status != cudaSuccess)
{
return status;
}
}
else
{
gLogError << "Unsupported type error, expected [kHALF,kFLOAT], but received " << static_cast<int32_t>(mType)
<< std::endl;
return STATUS_NOT_SUPPORTED;
}
// check mha use fused kernel
if (mUseFullMask || unfusedMaskSize != getMHAMaskPackedSize(mSM, mMhaType, S))
{
size_t warps_m = 0, warps_n = 0, warps_k = 1;
if (S == 64 || S == 96 || S == 128)
{
warps_m = 2;
warps_n = 2;
}
else if (S == 384)
{
warps_m = 1;
warps_n = 8;
}
uint32_t* inputMaskX = static_cast<uint32_t*>(outputs[1]);
status = convertMask(S, batchSize, warps_m, warps_n, warps_k, inputMask, inputMaskX, stream);
}
else
{
int32_t* maskIdx = static_cast<int32_t*>(outputs[1]);
status = computeMaskIdx(stream, S, batchSize, inputMask, maskIdx);
}
return status;
}
catch (std::exception const& e)
{
caughtError(e);
}
return STATUS_FAILURE;
}
// end IPluginV3OneRuntime method definitions
///////
// IPluginV3OneBuild method definitions
// - getNbOutputs()
// - supportsFormatCombination()
// - getOutputShapes
// - getOutputDataTypes()
// - configurePlugin()
// - getWorkSpaceSize()
//////
int32_t EmbLayerNormPluginDynamic::getNbOutputs() const noexcept
{
return 2;
}
bool EmbLayerNormPluginDynamic::supportsFormatCombination(
int32_t pos, DynamicPluginTensorDesc const* inOut, int32_t nbInputs, int32_t nbOutputs) noexcept
{
// 3 inputs of size BxS
PLUGIN_ASSERT(nbInputs == 3);
PLUGIN_ASSERT(nbOutputs == 2);
PluginTensorDesc const& desc = inOut[pos].desc;
if (desc.format != TensorFormat::kLINEAR)
{
return false;
}
if (pos == 0)
{
return desc.type == DataType::kINT32 && desc.dims.nbDims == 2;
}
PluginTensorDesc const& prev = inOut[pos - 1].desc;
if (pos == 1 || pos == 2)
{
return desc.type == DataType::kINT32 && desc.dims.nbDims == 2 && desc.dims.d[BDIM] == prev.dims.d[BDIM]
&& desc.dims.d[SDIM] == prev.dims.d[SDIM];
}
// embedded sequence
if (pos == 3)
{
return desc.type == mType && desc.dims.nbDims == 5 && desc.dims.d[BDIM] == prev.dims.d[BDIM]
&& desc.dims.d[SDIM] == prev.dims.d[SDIM] && desc.dims.d[3] == 1 && desc.dims.d[4] == 1;
}
// mask
return desc.type == DataType::kINT32;
}
int32_t EmbLayerNormPluginDynamic::getOutputShapes(DimsExprs const* inputs, int32_t nbInputs,
DimsExprs const* shapeInputs, int32_t nbShapeInputs, DimsExprs* outputs, int32_t nbOutputs,
IExprBuilder& exprBuilder) noexcept
{
try
{
// Input should be input ids and token ids and the input mask
// Output should be the embeddings tensor and mask indices
PLUGIN_ASSERT(nbInputs == 3);
PLUGIN_ASSERT(inputs != nullptr);
PLUGIN_ASSERT(inputs[0].nbDims == 2); // BxS
PLUGIN_ASSERT(inputs[0].nbDims == inputs[1].nbDims);
PLUGIN_ASSERT(inputs[0].nbDims == inputs[2].nbDims);
PLUGIN_ASSERT(nbOutputs == 2);
PLUGIN_ASSERT(outputs != nullptr);
// output 0: embeddings tensor
outputs[0].nbDims = 5;
outputs[0].d[0] = inputs[0].d[0];
outputs[0].d[1] = inputs[0].d[1];
outputs[0].d[2] = exprBuilder.constant(mLd);
outputs[0].d[3] = exprBuilder.constant(1);
outputs[0].d[4] = exprBuilder.constant(1);
// output 1: mask indices
outputs[1].nbDims = 2;
outputs[1].d[0] = inputs[0].d[BDIM];
auto cms0 = exprBuilder.constant(unfusedMaskSize);
// this code must match getMHAMaskPackedSize in bertCommon.h
bool const isSmOK = elem(mSM, {kSM_75, kSM_80, kSM_86, kSM_87, kSM_89, kSM_90, kSM_100, kSM_120});
bool const isPrecisionOK = (mMhaType == nvinfer1::DataType::kHALF || mMhaType == nvinfer1::DataType::kINT8);
if (mUseFullMask || (isSmOK && isPrecisionOK))
{
// support 128, 384 in both int8 and fp16
auto cms128 = exprBuilder.constant(packedMaskSize128);
auto cms384 = exprBuilder.constant(packedMaskSize384);
auto c128 = exprBuilder.constant(128);
auto c384 = exprBuilder.constant(384);
auto is128 = exprBuilder.operation(DimensionOperation::kEQUAL, *inputs[0].d[SDIM], *c128);
auto is384 = exprBuilder.operation(DimensionOperation::kEQUAL, *inputs[0].d[SDIM], *c384);
auto sel128 = exprBuilder.operation(DimensionOperation::kPROD, *is128, *cms128);
auto sel384 = exprBuilder.operation(DimensionOperation::kPROD, *is384, *cms384);
auto maskSize = exprBuilder.operation(DimensionOperation::kSUM, *sel384, *sel128);
// support 64, 96 in both int8 and fp16
auto cms64 = exprBuilder.constant(packedMaskSize64);
auto cms96 = exprBuilder.constant(packedMaskSize96);
auto c64 = exprBuilder.constant(64);
auto c96 = exprBuilder.constant(96);
auto is64 = exprBuilder.operation(DimensionOperation::kEQUAL, *inputs[0].d[SDIM], *c64);
auto is96 = exprBuilder.operation(DimensionOperation::kEQUAL, *inputs[0].d[SDIM], *c96);
auto sel64 = exprBuilder.operation(DimensionOperation::kPROD, *is64, *cms64);
auto sel96 = exprBuilder.operation(DimensionOperation::kPROD, *is96, *cms96);
auto maskSize2 = exprBuilder.operation(DimensionOperation::kSUM, *sel64, *sel96);
maskSize = exprBuilder.operation(DimensionOperation::kSUM, *maskSize, *maskSize2);
auto is0 = exprBuilder.operation(DimensionOperation::kEQUAL, *maskSize, *exprBuilder.constant(0));
auto sel0 = exprBuilder.operation(DimensionOperation::kPROD, *is0, *cms0);
auto combinedMaskSize = exprBuilder.operation(DimensionOperation::kSUM, *maskSize, *sel0);
outputs[1].d[1] = combinedMaskSize;
}
else
{
outputs[1].d[1] = cms0;
}
return pluginStatus_t::STATUS_SUCCESS;
}
catch (std::exception const& e)
{
caughtError(e);
}
return pluginStatus_t::STATUS_FAILURE;
}
int32_t EmbLayerNormPluginDynamic::getOutputDataTypes(
DataType* outputTypes, int32_t nbOutputs, DataType const* inputTypes, int32_t nbInputs) const noexcept
{
try
{
PLUGIN_ASSERT(outputTypes != nullptr);
PLUGIN_ASSERT(nbOutputs == 2);
PLUGIN_ASSERT(inputTypes != nullptr);
PLUGIN_ASSERT(nbInputs == 3);
PLUGIN_ASSERT(mType == DataType::kHALF || mType == DataType::kFLOAT);
outputTypes[0] = mType;
outputTypes[1] = DataType::kINT32;
return pluginStatus_t::STATUS_SUCCESS;
}
catch (std::exception const& e)
{
caughtError(e);
}
return pluginStatus_t::STATUS_FAILURE;
}
int32_t EmbLayerNormPluginDynamic::configurePlugin(DynamicPluginTensorDesc const* inputs, int32_t nbInputs,
DynamicPluginTensorDesc const* outputs, int32_t nbOutputs) noexcept
{
return pluginStatus_t::STATUS_SUCCESS;
}
size_t EmbLayerNormPluginDynamic::getWorkspaceSize(DynamicPluginTensorDesc const* inputs, int32_t nbInputs,
DynamicPluginTensorDesc const* outputs, int32_t nbOutputs) const noexcept
{
return 0;
}
// End IPluginV3OneBuild method definitions
//////
// IPluginV3OneCore method definitions
// - getPluginVersion()
// - getPluginName()
// - getPluginNamespace()
// - setPluginNamespace()
//////
char const* EmbLayerNormPluginDynamic::getPluginVersion() const noexcept
{
return gEmbLayerNormVersion;
}
char const* EmbLayerNormPluginDynamic::getPluginName() const noexcept
{
return gEmbLayerNormName;
}
void EmbLayerNormPluginDynamic::setPluginNamespace(char const* libNamespace) noexcept
{
try
{
mNamespace = libNamespace;
}
catch (std::exception const& e)
{
caughtError(e);
}
}
char const* EmbLayerNormPluginDynamic::getPluginNamespace() const noexcept
{
return mNamespace.c_str();
}
// End IPluginV3OneCore method definitions
//////////////////////////// Plugin Creator member definitions /////////////////////////////
EmbLayerNormPluginDynamicCreator::EmbLayerNormPluginDynamicCreator()
{
static std::mutex sMutex;
std::lock_guard<std::mutex> lock(sMutex);
mPluginAttributes.clear();
mPluginAttributes.emplace_back(PluginField("bert_embeddings_layernorm_beta"));
mPluginAttributes.emplace_back(PluginField("bert_embeddings_layernorm_gamma"));
mPluginAttributes.emplace_back(PluginField("bert_embeddings_word_embeddings"));
mPluginAttributes.emplace_back(PluginField("bert_embeddings_token_type_embeddings"));
mPluginAttributes.emplace_back(PluginField("bert_embeddings_position_embeddings"));
mPluginAttributes.emplace_back(PluginField("output_fp16"));
mPluginAttributes.emplace_back(PluginField("full_mask"));
mPluginAttributes.emplace_back(PluginField("mha_type_id"));
mFC.nbFields = mPluginAttributes.size();
mFC.fields = mPluginAttributes.data();
}
char const* EmbLayerNormPluginDynamicCreator::getPluginName() const noexcept
{
return gEmbLayerNormName;
}
char const* EmbLayerNormPluginDynamicCreator::getPluginVersion() const noexcept
{
return gEmbLayerNormVersion;
}
PluginFieldCollection const* EmbLayerNormPluginDynamicCreator::getFieldNames() noexcept
{
return &mFC;
}
IPluginV3* EmbLayerNormPluginDynamicCreator::createPlugin(
char const* name, PluginFieldCollection const* fc, TensorRTPhase phase) noexcept
{
try
{
BERT_DEBUG_MSG("EmbLayerNormPluginDynamic createPlugin.");
bool output_fp16 = false;
bool useFullMask = false;
Weights beta{}; // required attribute - validateRequiredAttributesExist() will verify existence
Weights gamma{}; // required attribute - validateRequiredAttributesExist() will verify existence
Weights word_emb{}; // required attribute - validateRequiredAttributesExist() will verify existence
Weights pos_emb{}; // required attribute - validateRequiredAttributesExist() will verify existence
Weights tok_emb{}; // required attribute - validateRequiredAttributesExist() will verify existence
int32_t mhaTypeId = 0;
std::set<std::string> const requiredAttributes{
"bert_embeddings_layernorm_beta",
"bert_embeddings_layernorm_gamma",
"bert_embeddings_word_embeddings",
"bert_embeddings_token_type_embeddings",
"bert_embeddings_position_embeddings",
};
plugin::validateRequiredAttributesExist(requiredAttributes, fc);
for (int32_t i = 0; i < fc->nbFields; i++)
{
std::string_view const field_name = fc->fields[i].name;
if (field_name == "bert_embeddings_layernorm_beta"sv)
{
BERT_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 == "bert_embeddings_layernorm_gamma"sv)
{
BERT_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 == "bert_embeddings_word_embeddings"sv)
{
BERT_DEBUG_MSG("Building bert_embeddings_word_embeddings...");
word_emb.values = fc->fields[i].data;
word_emb.count = fc->fields[i].length;
word_emb.type = fieldTypeToDataType(fc->fields[i].type);
}
if (field_name == "bert_embeddings_token_type_embeddings"sv)
{
BERT_DEBUG_MSG("Building bert_embeddings_token_type_embeddings...");
tok_emb.values = fc->fields[i].data;
tok_emb.count = fc->fields[i].length;
tok_emb.type = fieldTypeToDataType(fc->fields[i].type);
}
if (field_name == "bert_embeddings_position_embeddings"sv)
{
BERT_DEBUG_MSG("Building bert_embeddings_position_embeddings...");
pos_emb.values = fc->fields[i].data;
pos_emb.count = fc->fields[i].length;
pos_emb.type = fieldTypeToDataType(fc->fields[i].type);
}
if (field_name == "output_fp16"sv)
{
BERT_DEBUG_MSG("Building output_fp16...");
PLUGIN_VALIDATE(fc->fields[i].type == PluginFieldType::kINT32);
output_fp16 = static_cast<int32_t const*>(fc->fields[i].data)[0] != 0;
}
if (field_name == "full_mask"sv)
{
BERT_DEBUG_MSG("Building full_mask...");
PLUGIN_VALIDATE(fc->fields[i].type == PluginFieldType::kINT32);
useFullMask = static_cast<int32_t const*>(fc->fields[i].data)[0] != 0;
}
if (field_name == "mha_type_id"sv)
{
mhaTypeId = *static_cast<int32_t const*>(fc->fields[i].data);
PLUGIN_VALIDATE(mhaTypeId >= 0 && mhaTypeId <= 3);
BERT_DEBUG_VALUE("Building mha typeId: ", mhaTypeId);
}
}
BERT_DEBUG_MSG("Building the Plugin...");
DataType mhaType = static_cast<DataType>(mhaTypeId);
auto p = std::make_unique<EmbLayerNormPluginDynamic>(name, output_fp16 ? DataType::kHALF : DataType::kFLOAT,
mhaType, beta, gamma, word_emb, pos_emb, tok_emb, useFullMask);
return p.release();
}
catch (std::exception const& e)
{
caughtError(e);
}
return nullptr;
}
void EmbLayerNormPluginDynamicCreator::setPluginNamespace(char const* libNamespace) noexcept
{
try
{
mNamespace = libNamespace;
}
catch (std::exception const& e)
{
caughtError(e);
}
}
char const* EmbLayerNormPluginDynamicCreator::getPluginNamespace() const noexcept
{
return mNamespace.c_str();
}
#endif // CUDA_VERSION >= 10010
@@ -0,0 +1,174 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 1993-2025 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 <cuda.h>
#if CUDA_VERSION >= 10010
#ifndef TRT_EMB_LAYER_NORM_PLUGIN_H
#define TRT_EMB_LAYER_NORM_PLUGIN_H
#include "NvInferPlugin.h"
#include "NvInferRuntime.h"
#include "common/bertCommon.h"
#include <string>
#include <vector>
namespace nvinfer1
{
namespace plugin
{
namespace bert
{
int32_t computeMaskIdx(cudaStream_t stream, int32_t const S, int32_t const B, int32_t const* mask, int32_t* maskIdx);
template <typename T>
int32_t embSkipLayerNorm(cudaStream_t stream, int32_t ld, int32_t B, int32_t S, int32_t const* inputIds,
int32_t const* token_ids, float const* beta, float const* gamma, T const* wordEmb, T const* posEmb, T const* tokEmb,
int32_t const wordSize, int32_t const tokSize, T* output);
cudaError_t convertMask(uint32_t const S, uint32_t const B, uint32_t const warps_m, uint32_t const warps_n,
uint32_t const warps_k, int32_t const* inputMaskSB, uint32_t* inputMaskX, cudaStream_t stream);
class EmbLayerNormPluginDynamic : public IPluginV3,
public IPluginV3OneCore,
public IPluginV3OneBuild,
public IPluginV3OneRuntime
{
public:
EmbLayerNormPluginDynamic(std::string const& name, nvinfer1::DataType const type, nvinfer1::DataType const mhaType,
nvinfer1::Weights const& beta, nvinfer1::Weights const& gamma, nvinfer1::Weights const& word_emb,
nvinfer1::Weights const& pos_emb, nvinfer1::Weights const& tok_emb, bool const useFullMask);
// It doesn't make sense to make EmbLayerNormPluginDynamic without arguments, so we
// delete default constructor.
EmbLayerNormPluginDynamic() = delete;
~EmbLayerNormPluginDynamic() override;
// IPluginV3 Methods
// NOTE: since this is itself is an abstract class, the rest of virtual methods defined in its children classes
IPluginCapability* getCapabilityInterface(PluginCapabilityType type) noexcept override;
// end of IPluginV3 Methods
// IPluginV3OneCore Methods
char const* getPluginName() const noexcept override;
char const* getPluginNamespace() const noexcept override;
void setPluginNamespace(char const* pluginNamespace) noexcept;
char const* getPluginVersion() const noexcept override;
// end of IPluginV3OneCore Methods
// IPluginV3Build Methods
bool supportsFormatCombination(
int32_t pos, DynamicPluginTensorDesc const* inOut, int32_t nbInputs, int32_t nbOutputs) noexcept override;
int32_t configurePlugin(DynamicPluginTensorDesc const* in, int32_t nbInputs, DynamicPluginTensorDesc const* out,
int32_t nbOutputs) noexcept override;
size_t getWorkspaceSize(DynamicPluginTensorDesc const* inputs, int32_t nbInputs,
DynamicPluginTensorDesc const* outputs, int32_t nbOutputs) const noexcept override;
int32_t getOutputDataTypes(
DataType* outputTypes, int32_t nbOutputs, DataType const* inputTypes, int32_t nbInputs) const noexcept override;
int32_t getNbOutputs() const noexcept override;
int32_t getOutputShapes(DimsExprs const* inputs, int32_t nbInputs, DimsExprs const* shapeInputs,
int32_t nbShapeInputs, DimsExprs* outputs, int32_t nbOutputs, IExprBuilder& exprBuilder) noexcept override;
// end IPluginV3Build Methods
// IPluginV3Runtime Methods
IPluginV3* clone() noexcept override;
int32_t onShapeChange(
PluginTensorDesc const* in, int32_t nbInputs, PluginTensorDesc 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;
IPluginV3* attachToContext(IPluginResourceContext* context) noexcept override;
PluginFieldCollection const* getFieldsToSerialize() noexcept override;
// end IPluginV3Runtime Methods
private:
// metadata fields
std::string const mLayerName;
std::string mNamespace;
// device-side
bert::cuda_unique_ptr<float> mGammaDev;
bert::cuda_unique_ptr<float> mBetaDev;
bert::cuda_unique_ptr<void> mWordEmbDev;
bert::cuda_unique_ptr<void> mTokEmbDev;
bert::cuda_unique_ptr<void> mPosEmbDev;
size_t mLd; // leading dim = hidden size
size_t mS; // sequence length
size_t mWordVocabSize;
size_t mPosVocabSize;
size_t mTokVocabSize;
// members that partcipate in ser/deserialization
bert::WeightsWithOwnership mBeta;
bert::WeightsWithOwnership mGamma;
bert::WeightsWithOwnership mWordEmb;
bert::WeightsWithOwnership mTokEmb;
bert::WeightsWithOwnership mPosEmb;
nvinfer1::DataType mType;
int32_t mOutputFp16;
int32_t mUseFullMask;
nvinfer1::DataType mMhaType;
int32_t mSM;
// IPluginV3 serialization related
std::vector<nvinfer1::PluginField> mDataToSerialize;
nvinfer1::PluginFieldCollection mFCToSerialize;
};
class EmbLayerNormPluginDynamicCreator : public nvinfer1::IPluginCreatorV3One
{
public:
EmbLayerNormPluginDynamicCreator();
~EmbLayerNormPluginDynamicCreator() override = default;
char const* getPluginName() const noexcept override;
char const* getPluginVersion() const noexcept override;
nvinfer1::PluginFieldCollection const* getFieldNames() noexcept override;
IPluginV3* createPlugin(char const* name, PluginFieldCollection const* fc, TensorRTPhase phase) noexcept override;
void setPluginNamespace(char const* pluginNamespace) noexcept;
char const* getPluginNamespace() const noexcept override;
private:
nvinfer1::PluginFieldCollection mFC;
std::vector<nvinfer1::PluginField> mPluginAttributes;
std::string mNamespace;
};
} // namespace bert
} // namespace plugin
} // namespace nvinfer1
#endif // TRT_EMB_LAYER_NORM_PLUGIN_H
#endif // CUDA_VERSION >= 10010
@@ -0,0 +1,666 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 1993-2026 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 <cuda.h>
#if CUDA_VERSION >= 10010
#include <memory>
#include <set>
#include <string_view>
#include <vector>
#include "NvInfer.h"
#include "common/serialize.hpp"
#include "embLayerNormPluginLegacy.h"
using namespace nvinfer1;
using namespace nvinfer1::plugin;
using namespace nvinfer1::plugin::bert;
namespace
{
using namespace std::string_view_literals;
char const* gEmbLayerNormVersion{"1"};
char const* gEmbLayerNormName{"CustomEmbLayerNormPluginDynamic"};
} // namespace
REGISTER_TENSORRT_PLUGIN(EmbLayerNormPluginDynamicLegacyCreator);
EmbLayerNormPluginDynamicLegacy::EmbLayerNormPluginDynamicLegacy(std::string const& name, DataType const type,
DataType const mhaType, Weights const& beta, Weights const& gamma, Weights const& wordEmb, Weights const& posEmb,
Weights const& tokEmb, bool const useFullMask)
: mLayerName(name)
, mLd(beta.count)
, mType(type)
, mUseFullMask(useFullMask)
, mMhaType(mhaType)
{
// Assuming Weights.count is the number of elements and not bytes
PLUGIN_VALIDATE(beta.count == gamma.count);
PLUGIN_VALIDATE(mLd > 0U);
PLUGIN_VALIDATE(wordEmb.count % mLd == 0);
PLUGIN_VALIDATE(posEmb.count % mLd == 0);
PLUGIN_VALIDATE(tokEmb.count % mLd == 0);
mWordVocabSize = wordEmb.count / mLd;
mPosVocabSize = posEmb.count / mLd;
mTokVocabSize = tokEmb.count / mLd;
mSM = getSmVersion();
// mS is set during configure
mBeta.convertAndCopy(beta, nvinfer1::DataType::kFLOAT);
mGamma.convertAndCopy(gamma, nvinfer1::DataType::kFLOAT);
mWordEmb.convertAndCopy(wordEmb, mType);
mTokEmb.convertAndCopy(tokEmb, mType);
mPosEmb.convertAndCopy(posEmb, mType);
copyToDevice(mGamma, sizeof(float) * mGamma.count, mGammaDev);
copyToDevice(mBeta, sizeof(float) * mBeta.count, mBetaDev);
copyToDevice(mWordEmb, getWeightsSize(mWordEmb, mType), mWordEmbDev);
copyToDevice(mPosEmb, getWeightsSize(mPosEmb, mType), mPosEmbDev);
copyToDevice(mTokEmb, getWeightsSize(mTokEmb, mType), mTokEmbDev);
}
EmbLayerNormPluginDynamicLegacy::EmbLayerNormPluginDynamicLegacy(
std::string const& name, void const* data, size_t length)
: mLayerName(name)
, mGammaDev(nullptr)
, mBetaDev(nullptr)
, mWordEmbDev(nullptr)
, mTokEmbDev(nullptr)
, mPosEmbDev(nullptr)
{
BERT_DEBUG_MSG("EmbLayerNormPluginDynamicLegacy deserialize.");
// Deserialize in the same order as serialization
deserialize_value(&data, &length, &mType);
deserialize_value(&data, &length, &mMhaType);
deserialize_value(&data, &length, &mLd);
deserialize_value(&data, &length, &mS);
deserialize_value(&data, &length, &mWordVocabSize);
deserialize_value(&data, &length, &mPosVocabSize);
deserialize_value(&data, &length, &mTokVocabSize);
deserialize_value(&data, &length, &mUseFullMask);
deserialize_value(&data, &length, &mSM);
char const* d = static_cast<char const*>(data);
mBeta.convertAndCopy(d, mLd, nvinfer1::DataType::kFLOAT);
mGamma.convertAndCopy(d, mLd, nvinfer1::DataType::kFLOAT);
mWordEmb.convertAndCopy(d, mLd * mWordVocabSize, mType);
mPosEmb.convertAndCopy(d, mLd * mPosVocabSize, mType);
mTokEmb.convertAndCopy(d, mLd * mTokVocabSize, mType);
copyToDevice(mGamma, sizeof(float) * mGamma.count, mGammaDev);
copyToDevice(mBeta, sizeof(float) * mBeta.count, mBetaDev);
copyToDevice(mWordEmb, getWeightsSize(mWordEmb, mType), mWordEmbDev);
copyToDevice(mPosEmb, getWeightsSize(mPosEmb, mType), mPosEmbDev);
copyToDevice(mTokEmb, getWeightsSize(mTokEmb, mType), mTokEmbDev);
}
// IPluginV2DynamicExt Methods
IPluginV2DynamicExt* EmbLayerNormPluginDynamicLegacy::clone() const noexcept
{
try
{
BERT_DEBUG_MSG("EmbLayerNormPluginDynamicLegacy clone.");
auto p = std::make_unique<EmbLayerNormPluginDynamicLegacy>(
mLayerName, mType, mMhaType, mBeta, mGamma, mWordEmb, mPosEmb, mTokEmb, mUseFullMask);
p->mS = mS;
p->setPluginNamespace(mNamespace.c_str());
return p.release();
}
catch (std::exception const& e)
{
caughtError(e);
}
return nullptr;
}
DimsExprs EmbLayerNormPluginDynamicLegacy::getOutputDimensions(
int32_t outputIndex, DimsExprs const* inputs, int32_t nbInputs, IExprBuilder& exprBuilder) noexcept
{
try
{
// Input should be input ids and token ids and the input mask
// Output should be the embeddings tensor and mask indices
PLUGIN_ASSERT(nbInputs == 3);
PLUGIN_ASSERT(inputs[0].nbDims == 2); // BxS
PLUGIN_ASSERT(inputs[0].nbDims == inputs[1].nbDims);
PLUGIN_ASSERT(inputs[0].nbDims == inputs[2].nbDims);
PLUGIN_ASSERT(outputIndex == 0 || outputIndex == 1);
if (outputIndex == 0)
{
DimsExprs ret;
ret.nbDims = 5;
ret.d[0] = inputs[0].d[0];
ret.d[1] = inputs[0].d[1];
ret.d[2] = exprBuilder.constant(mLd);
ret.d[3] = exprBuilder.constant(1);
ret.d[4] = exprBuilder.constant(1);
return ret;
}
DimsExprs ret;
ret.nbDims = 2;
ret.d[0] = inputs[0].d[BDIM];
auto cms0 = exprBuilder.constant(unfusedMaskSize);
// this code must match getMHAMaskPackedSize in bertCommon.h
bool const isSmOK = elem(mSM, {kSM_75, kSM_80, kSM_86, kSM_87, kSM_89, kSM_90, kSM_100, kSM_120});
bool const isPrecisionOK = (mMhaType == nvinfer1::DataType::kHALF || mMhaType == nvinfer1::DataType::kINT8);
if (mUseFullMask || (isSmOK && isPrecisionOK))
{
// support 128, 384 in both int8 and fp16
auto cms128 = exprBuilder.constant(packedMaskSize128);
auto cms384 = exprBuilder.constant(packedMaskSize384);
auto c128 = exprBuilder.constant(128);
auto c384 = exprBuilder.constant(384);
auto is128 = exprBuilder.operation(DimensionOperation::kEQUAL, *inputs[0].d[SDIM], *c128);
auto is384 = exprBuilder.operation(DimensionOperation::kEQUAL, *inputs[0].d[SDIM], *c384);
auto sel128 = exprBuilder.operation(DimensionOperation::kPROD, *is128, *cms128);
auto sel384 = exprBuilder.operation(DimensionOperation::kPROD, *is384, *cms384);
auto maskSize = exprBuilder.operation(DimensionOperation::kSUM, *sel384, *sel128);
// support 64, 96 in both int8 and fp16
auto cms64 = exprBuilder.constant(packedMaskSize64);
auto cms96 = exprBuilder.constant(packedMaskSize96);
auto c64 = exprBuilder.constant(64);
auto c96 = exprBuilder.constant(96);
auto is64 = exprBuilder.operation(DimensionOperation::kEQUAL, *inputs[0].d[SDIM], *c64);
auto is96 = exprBuilder.operation(DimensionOperation::kEQUAL, *inputs[0].d[SDIM], *c96);
auto sel64 = exprBuilder.operation(DimensionOperation::kPROD, *is64, *cms64);
auto sel96 = exprBuilder.operation(DimensionOperation::kPROD, *is96, *cms96);
auto maskSize2 = exprBuilder.operation(DimensionOperation::kSUM, *sel64, *sel96);
maskSize = exprBuilder.operation(DimensionOperation::kSUM, *maskSize, *maskSize2);
auto is0 = exprBuilder.operation(DimensionOperation::kEQUAL, *maskSize, *exprBuilder.constant(0));
auto sel0 = exprBuilder.operation(DimensionOperation::kPROD, *is0, *cms0);
auto combinedMaskSize = exprBuilder.operation(DimensionOperation::kSUM, *maskSize, *sel0);
ret.d[1] = combinedMaskSize;
}
else
{
ret.d[1] = cms0;
}
return ret;
}
catch (std::exception const& e)
{
caughtError(e);
}
return DimsExprs{};
}
bool EmbLayerNormPluginDynamicLegacy::supportsFormatCombination(
int32_t pos, PluginTensorDesc const* inOut, int32_t nbInputs, int32_t nbOutputs) noexcept
{
// 3 inputs of size BxS
PLUGIN_ASSERT(nbInputs == 3);
PLUGIN_ASSERT(nbOutputs == 2);
PluginTensorDesc const& desc = inOut[pos];
if (desc.format != TensorFormat::kLINEAR)
{
return false;
}
if (pos == 0)
{
return desc.type == DataType::kINT32 && desc.dims.nbDims == 2;
}
PluginTensorDesc const& prev = inOut[pos - 1];
if (pos == 1 || pos == 2)
{
return desc.type == DataType::kINT32 && desc.dims.nbDims == 2 && desc.dims.d[BDIM] == prev.dims.d[BDIM]
&& desc.dims.d[SDIM] == prev.dims.d[SDIM];
}
// embedded sequence
if (pos == 3)
{
return desc.type == mType && desc.dims.nbDims == 5 && desc.dims.d[BDIM] == prev.dims.d[BDIM]
&& desc.dims.d[SDIM] == prev.dims.d[SDIM] && desc.dims.d[3] == 1 && desc.dims.d[4] == 1;
}
// mask
return desc.type == DataType::kINT32;
}
void EmbLayerNormPluginDynamicLegacy::configurePlugin(DynamicPluginTensorDesc const* inputs, int32_t nbInputs,
DynamicPluginTensorDesc const* outputs, int32_t nbOutputs) noexcept
{
BERT_DEBUG_MSG("EmbLayerNormPluginDynamicLegacy configurePlugin.");
// Validate input arguments
PLUGIN_ASSERT(nbOutputs == 2);
PLUGIN_ASSERT(nbInputs == 3);
PLUGIN_ASSERT(inputs[0].desc.dims.nbDims == 2);
int32_t const S = inputs[0].desc.dims.d[SDIM];
mS = S;
int32_t const B = inputs[0].desc.dims.d[BDIM];
TRT_UNUSED B;
PLUGIN_ASSERT(mS == static_cast<size_t>(inputs[1].desc.dims.d[SDIM]));
PLUGIN_ASSERT(B == inputs[1].desc.dims.d[BDIM]);
PLUGIN_ASSERT(mS == static_cast<size_t>(inputs[2].desc.dims.d[SDIM]));
PLUGIN_ASSERT(B == inputs[2].desc.dims.d[BDIM]);
PLUGIN_ASSERT(outputs[0].desc.dims.nbDims == 5);
PLUGIN_ASSERT(static_cast<size_t>(outputs[0].desc.dims.d[SDIM]) == mS);
PLUGIN_ASSERT(outputs[0].desc.dims.d[BDIM] == B);
PLUGIN_ASSERT(static_cast<size_t>(outputs[0].desc.dims.d[2]) == mLd);
PLUGIN_ASSERT(outputs[0].desc.dims.d[3] == 1);
PLUGIN_ASSERT(outputs[0].desc.dims.d[4] == 1);
if (mUseFullMask)
{
// user force full_mask
PLUGIN_ASSERT(outputs[1].desc.dims.nbDims == 2);
PLUGIN_ASSERT(outputs[1].desc.dims.d[0] == B);
PLUGIN_ASSERT((outputs[1].desc.dims.d[1] == -1) || (outputs[1].desc.dims.d[1] == packedMaskSize384)
|| (outputs[1].desc.dims.d[1] == packedMaskSize128));
}
else
{
// auto detect using mhatype
if (S != -1 && B != -1)
{
PLUGIN_ASSERT(outputs[1].desc.dims.nbDims == 2);
PLUGIN_ASSERT(outputs[1].desc.dims.d[0] == B);
int32_t packedSize = getMHAMaskPackedSize(mSM, mMhaType, S);
TRT_UNUSED packedSize;
PLUGIN_ASSERT(outputs[1].desc.dims.d[1] == -1 || outputs[1].desc.dims.d[1] == packedSize);
}
}
PLUGIN_ASSERT(inputs[0].desc.type == DataType::kINT32);
PLUGIN_ASSERT(inputs[1].desc.type == DataType::kINT32);
PLUGIN_ASSERT(inputs[2].desc.type == DataType::kINT32);
PLUGIN_ASSERT(outputs[0].desc.type == mType);
PLUGIN_ASSERT(outputs[1].desc.type == DataType::kINT32);
}
size_t EmbLayerNormPluginDynamicLegacy::getWorkspaceSize(
PluginTensorDesc const* inputs, int32_t nbInputs, PluginTensorDesc const* outputs, int32_t nbOutputs) const noexcept
{
return 0;
}
int32_t EmbLayerNormPluginDynamicLegacy::enqueue(PluginTensorDesc const* inputDesc,
PluginTensorDesc const* /* outputDesc */, void const* const* inputs, void* const* outputs, void* /* workspace */,
cudaStream_t stream) noexcept
{
try
{
PLUGIN_VALIDATE(inputDesc != nullptr && inputs != nullptr && outputs != nullptr);
int32_t const batchSize = inputDesc->dims.d[BDIM];
int32_t const S = inputDesc->dims.d[SDIM];
int32_t status = STATUS_FAILURE;
// Our plugin outputs only one tensor
auto const inputIds = static_cast<int32_t const*>(inputs[0]);
auto const segmentIds = static_cast<int32_t const*>(inputs[1]);
auto const inputMask = static_cast<int32_t const*>(inputs[2]);
float const* beta = mBetaDev.get();
float const* gamma = mGammaDev.get();
if (mType == DataType::kFLOAT)
{
auto output = static_cast<float*>(outputs[0]);
auto const wordEmb = static_cast<float const*>(mWordEmbDev.get());
auto const tokEmb = static_cast<float const*>(mTokEmbDev.get());
auto const posEmb = static_cast<float const*>(mPosEmbDev.get());
status = embSkipLayerNorm<float>(stream, static_cast<int32_t>(mLd), batchSize, S, inputIds, segmentIds,
beta, gamma, wordEmb, posEmb, tokEmb, mWordVocabSize, mTokVocabSize, output);
if (status != cudaSuccess)
{
return status;
}
}
else if (mType == DataType::kHALF)
{
auto output = static_cast<half*>(outputs[0]);
auto const wordEmb = static_cast<half const*>(mWordEmbDev.get());
auto const tokEmb = static_cast<half const*>(mTokEmbDev.get());
auto const posEmb = static_cast<half const*>(mPosEmbDev.get());
status = embSkipLayerNorm<half>(stream, static_cast<int32_t>(mLd), batchSize, S, inputIds, segmentIds, beta,
gamma, wordEmb, posEmb, tokEmb, mWordVocabSize, mTokVocabSize, output);
if (status != cudaSuccess)
{
return status;
}
}
else
{
gLogError << "Unsupported type error, expected [kHALF,kFLOAT], but received " << static_cast<int32_t>(mType)
<< std::endl;
return STATUS_NOT_SUPPORTED;
}
// check mha use fused kernel
if (mUseFullMask || unfusedMaskSize != getMHAMaskPackedSize(mSM, mMhaType, S))
{
size_t warps_m = 0, warps_n = 0, warps_k = 1;
if (S == 64 || S == 96 || S == 128)
{
warps_m = 2;
warps_n = 2;
}
else if (S == 384)
{
warps_m = 1;
warps_n = 8;
}
uint32_t* inputMaskX = static_cast<uint32_t*>(outputs[1]);
status = convertMask(S, batchSize, warps_m, warps_n, warps_k, inputMask, inputMaskX, stream);
}
else
{
int32_t* maskIdx = static_cast<int32_t*>(outputs[1]);
status = computeMaskIdx(stream, S, batchSize, inputMask, maskIdx);
}
return status;
}
catch (std::exception const& e)
{
caughtError(e);
}
return STATUS_FAILURE;
}
// IPluginV2Ext Methods
DataType EmbLayerNormPluginDynamicLegacy::getOutputDataType(
int32_t index, DataType const* inputTypes, int32_t nbInputs) const noexcept
{
PLUGIN_ASSERT(index == 0 || index == 1);
if (index == 0)
{
PLUGIN_ASSERT(mType == DataType::kHALF || mType == DataType::kFLOAT);
return mType;
}
return DataType::kINT32;
}
// IPluginV2 Methods
char const* EmbLayerNormPluginDynamicLegacy::getPluginType() const noexcept
{
return gEmbLayerNormName;
}
char const* EmbLayerNormPluginDynamicLegacy::getPluginVersion() const noexcept
{
return gEmbLayerNormVersion;
}
int32_t EmbLayerNormPluginDynamicLegacy::getNbOutputs() const noexcept
{
return 2;
}
int32_t EmbLayerNormPluginDynamicLegacy::initialize() noexcept
{
return 0;
}
void EmbLayerNormPluginDynamicLegacy::terminate() noexcept
{
BERT_DEBUG_MSG("EmbLayerNormPluginDynamicLegacy terminate.");
}
size_t EmbLayerNormPluginDynamicLegacy::getSerializationSize() const noexcept
{
size_t const wordSize = getElementSize(mType);
return sizeof(mType) // type
+ sizeof(mMhaType) // mha plugin datatype
+ sizeof(mLd) * 5 // mLd, mS, m*VocabSize
+ sizeof(mUseFullMask) // mask type
+ sizeof(mSM) // smversion
+ 2 * sizeof(float) * mLd // beta + gamma
+ wordSize * mLd * mWordVocabSize // word emb
+ wordSize * mLd * mPosVocabSize // pos emb
+ wordSize * mLd * mTokVocabSize // tok emb
;
}
void EmbLayerNormPluginDynamicLegacy::serialize(void* buffer) const noexcept
{
serialize_value(&buffer, mType);
serialize_value(&buffer, mMhaType);
serialize_value(&buffer, mLd);
serialize_value(&buffer, mS);
serialize_value(&buffer, mWordVocabSize);
serialize_value(&buffer, mPosVocabSize);
serialize_value(&buffer, mTokVocabSize);
serialize_value(&buffer, mUseFullMask);
serialize_value(&buffer, mSM);
char* d = static_cast<char*>(buffer);
serFromDev(d, mBetaDev.get(), mLd);
serFromDev(d, mGammaDev.get(), mLd);
size_t const wordSize = getElementSize(mType);
serFromDev(d, static_cast<char*>(mWordEmbDev.get()), mLd * mWordVocabSize * wordSize);
serFromDev(d, static_cast<char*>(mPosEmbDev.get()), mLd * mPosVocabSize * wordSize);
serFromDev(d, static_cast<char*>(mTokEmbDev.get()), mLd * mTokVocabSize * wordSize);
}
void EmbLayerNormPluginDynamicLegacy::destroy() noexcept
{
BERT_DEBUG_MSG("EmbLayerNormPluginDynamicLegacy destroy.");
// This gets called when the network containing plugin is destroyed
mGammaDev.reset(nullptr);
mBetaDev.reset(nullptr);
mWordEmbDev.reset(nullptr);
mPosEmbDev.reset(nullptr);
mTokEmbDev.reset(nullptr);
delete this;
}
void EmbLayerNormPluginDynamicLegacy::setPluginNamespace(char const* libNamespace) noexcept
{
try
{
mNamespace = libNamespace;
}
catch (std::exception const& e)
{
caughtError(e);
}
}
char const* EmbLayerNormPluginDynamicLegacy::getPluginNamespace() const noexcept
{
return mNamespace.c_str();
}
///////////////////////
EmbLayerNormPluginDynamicLegacyCreator::EmbLayerNormPluginDynamicLegacyCreator()
{
mPluginAttributes.clear();
mPluginAttributes.emplace_back(PluginField("bert_embeddings_layernorm_beta"));
mPluginAttributes.emplace_back(PluginField("bert_embeddings_layernorm_gamma"));
mPluginAttributes.emplace_back(PluginField("bert_embeddings_word_embeddings"));
mPluginAttributes.emplace_back(PluginField("bert_embeddings_token_type_embeddings"));
mPluginAttributes.emplace_back(PluginField("bert_embeddings_position_embeddings"));
mPluginAttributes.emplace_back(PluginField("output_fp16"));
mPluginAttributes.emplace_back(PluginField("full_mask"));
mPluginAttributes.emplace_back(PluginField("mha_type_id"));
mFC.nbFields = mPluginAttributes.size();
mFC.fields = mPluginAttributes.data();
}
char const* EmbLayerNormPluginDynamicLegacyCreator::getPluginName() const noexcept
{
return gEmbLayerNormName;
}
char const* EmbLayerNormPluginDynamicLegacyCreator::getPluginVersion() const noexcept
{
return gEmbLayerNormVersion;
}
PluginFieldCollection const* EmbLayerNormPluginDynamicLegacyCreator::getFieldNames() noexcept
{
return &mFC;
}
IPluginV2* EmbLayerNormPluginDynamicLegacyCreator::createPlugin(
char const* name, PluginFieldCollection const* fc) noexcept
{
try
{
BERT_DEBUG_MSG("EmbLayerNormPluginDynamicLegacy createPlugin.");
bool output_fp16 = false;
bool useFullMask = false;
Weights beta{}; // required attribute - validateRequiredAttributesExist() will verify existence
Weights gamma{}; // required attribute - validateRequiredAttributesExist() will verify existence
Weights word_emb{}; // required attribute - validateRequiredAttributesExist() will verify existence
Weights pos_emb{}; // required attribute - validateRequiredAttributesExist() will verify existence
Weights tok_emb{}; // required attribute - validateRequiredAttributesExist() will verify existence
int32_t mhaTypeId = 0;
std::set<std::string> const requiredAttributes{
"bert_embeddings_layernorm_beta",
"bert_embeddings_layernorm_gamma",
"bert_embeddings_word_embeddings",
"bert_embeddings_token_type_embeddings",
"bert_embeddings_position_embeddings",
};
plugin::validateRequiredAttributesExist(requiredAttributes, fc);
for (int32_t i = 0; i < fc->nbFields; i++)
{
std::string_view const field_name = fc->fields[i].name;
if (field_name == "bert_embeddings_layernorm_beta"sv)
{
BERT_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 == "bert_embeddings_layernorm_gamma"sv)
{
BERT_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 == "bert_embeddings_word_embeddings"sv)
{
BERT_DEBUG_MSG("Building bert_embeddings_word_embeddings...");
word_emb.values = fc->fields[i].data;
word_emb.count = fc->fields[i].length;
word_emb.type = fieldTypeToDataType(fc->fields[i].type);
}
if (field_name == "bert_embeddings_token_type_embeddings"sv)
{
BERT_DEBUG_MSG("Building bert_embeddings_token_type_embeddings...");
tok_emb.values = fc->fields[i].data;
tok_emb.count = fc->fields[i].length;
tok_emb.type = fieldTypeToDataType(fc->fields[i].type);
}
if (field_name == "bert_embeddings_position_embeddings"sv)
{
BERT_DEBUG_MSG("Building bert_embeddings_position_embeddings...");
pos_emb.values = fc->fields[i].data;
pos_emb.count = fc->fields[i].length;
pos_emb.type = fieldTypeToDataType(fc->fields[i].type);
}
if (field_name == "output_fp16"sv)
{
BERT_DEBUG_MSG("Building output_fp16...");
PLUGIN_VALIDATE(fc->fields[i].type == PluginFieldType::kINT32);
output_fp16 = static_cast<int32_t const*>(fc->fields[i].data)[0] != 0;
}
if (field_name == "full_mask"sv)
{
BERT_DEBUG_MSG("Building full_mask...");
PLUGIN_VALIDATE(fc->fields[i].type == PluginFieldType::kINT32);
useFullMask = static_cast<int32_t const*>(fc->fields[i].data)[0] != 0;
}
if (field_name == "mha_type_id"sv)
{
mhaTypeId = *static_cast<int32_t const*>(fc->fields[i].data);
PLUGIN_VALIDATE(mhaTypeId >= 0 && mhaTypeId <= 3);
BERT_DEBUG_VALUE("Building mha typeId: ", mhaTypeId);
}
}
BERT_DEBUG_MSG("Building the Plugin...");
DataType mhaType = static_cast<DataType>(mhaTypeId);
auto p
= std::make_unique<EmbLayerNormPluginDynamicLegacy>(name, output_fp16 ? DataType::kHALF : DataType::kFLOAT,
mhaType, beta, gamma, word_emb, pos_emb, tok_emb, useFullMask);
return p.release();
}
catch (std::exception const& e)
{
caughtError(e);
}
return nullptr;
}
IPluginV2* EmbLayerNormPluginDynamicLegacyCreator::deserializePlugin(
char const* name, void const* serialData, size_t serialLength) noexcept
{
try
{
// This object will be deleted when the network is destroyed, which will
// call EmbLayerNormPluginDynamicLegacy::destroy()
return new EmbLayerNormPluginDynamicLegacy(name, serialData, serialLength);
}
catch (std::exception const& e)
{
caughtError(e);
}
return nullptr;
}
void EmbLayerNormPluginDynamicLegacyCreator::setPluginNamespace(char const* libNamespace) noexcept
{
try
{
mNamespace = libNamespace;
}
catch (std::exception const& e)
{
caughtError(e);
}
}
char const* EmbLayerNormPluginDynamicLegacyCreator::getPluginNamespace() const noexcept
{
return mNamespace.c_str();
}
#endif // CUDA_VERSION >= 10010
@@ -0,0 +1,151 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 1993-2025 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 <cuda.h>
#if CUDA_VERSION >= 10010
#ifndef TRT_EMB_LAYER_NORM_PLUGIN_LEGACY_H
#define TRT_EMB_LAYER_NORM_PLUGIN_LEGACY_H
#include "NvInferPlugin.h"
#include "NvInferRuntime.h"
#include "common/bertCommon.h"
#include <string>
#include <vector>
namespace nvinfer1
{
namespace plugin
{
namespace bert
{
int32_t computeMaskIdx(cudaStream_t stream, int32_t const S, int32_t const B, int32_t const* mask, int32_t* maskIdx);
template <typename T>
int32_t embSkipLayerNorm(cudaStream_t stream, int32_t ld, int32_t B, int32_t S, int32_t const* inputIds,
int32_t const* token_ids, float const* beta, float const* gamma, T const* wordEmb, T const* posEmb, T const* tokEmb,
int32_t const wordSize, int32_t const tokSize, T* output);
cudaError_t convertMask(uint32_t const S, uint32_t const B, uint32_t const warps_m, uint32_t const warps_n,
uint32_t const warps_k, int32_t const* inputMaskSB, uint32_t* inputMaskX, cudaStream_t stream);
class EmbLayerNormPluginDynamicLegacy : public nvinfer1::IPluginV2DynamicExt
{
public:
EmbLayerNormPluginDynamicLegacy(std::string const& name, nvinfer1::DataType const type,
nvinfer1::DataType const mhaType, nvinfer1::Weights const& beta, nvinfer1::Weights const& gamma,
nvinfer1::Weights const& word_emb, nvinfer1::Weights const& pos_emb, nvinfer1::Weights const& tok_emb,
bool const useFullMask);
EmbLayerNormPluginDynamicLegacy(std::string const& name, void const* data, size_t length);
// It doesn't make sense to make EmbLayerNormPluginDynamicLegacy without arguments, so we
// delete default constructor.
EmbLayerNormPluginDynamicLegacy() = delete;
// IPluginV2DynamicExt Methods
nvinfer1::IPluginV2DynamicExt* clone() const noexcept override;
nvinfer1::DimsExprs getOutputDimensions(int32_t outputIndex, nvinfer1::DimsExprs const* inputs, int32_t nbInputs,
nvinfer1::IExprBuilder& exprBuilder) noexcept override;
bool supportsFormatCombination(
int32_t pos, nvinfer1::PluginTensorDesc const* inOut, int32_t nbInputs, int32_t nbOutputs) noexcept override;
void configurePlugin(nvinfer1::DynamicPluginTensorDesc const* in, int32_t nbInputs,
nvinfer1::DynamicPluginTensorDesc const* out, 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;
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;
// 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;
char const* getPluginVersion() const noexcept override;
int32_t getNbOutputs() const noexcept override;
int32_t 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(char const* pluginNamespace) noexcept override;
char const* getPluginNamespace() const noexcept override;
private:
std::string const mLayerName;
std::string mNamespace;
bert::cuda_unique_ptr<float> mGammaDev;
bert::cuda_unique_ptr<float> mBetaDev;
bert::cuda_unique_ptr<void> mWordEmbDev;
bert::cuda_unique_ptr<void> mTokEmbDev;
bert::cuda_unique_ptr<void> mPosEmbDev;
size_t mLd; // leading dim = hidden size
size_t mS; // sequence length
size_t mWordVocabSize;
size_t mPosVocabSize;
size_t mTokVocabSize;
bert::WeightsWithOwnership mBeta;
bert::WeightsWithOwnership mGamma;
bert::WeightsWithOwnership mWordEmb;
bert::WeightsWithOwnership mTokEmb;
bert::WeightsWithOwnership mPosEmb;
nvinfer1::DataType mType;
bool mUseFullMask;
nvinfer1::DataType mMhaType;
int32_t mSM;
using IPluginV2::getOutputDimensions;
using IPluginV2::getWorkspaceSize;
using IPluginV2::enqueue;
using IPluginV2Ext::configurePlugin;
};
class EmbLayerNormPluginDynamicLegacyCreator : public nvinfer1::IPluginCreator
{
public:
EmbLayerNormPluginDynamicLegacyCreator();
char const* getPluginName() const noexcept override;
char const* getPluginVersion() const noexcept override;
nvinfer1::PluginFieldCollection const* getFieldNames() noexcept override;
nvinfer1::IPluginV2* createPlugin(char const* name, nvinfer1::PluginFieldCollection const* fc) noexcept override;
nvinfer1::IPluginV2* deserializePlugin(
char const* name, void const* serialData, size_t serialLength) noexcept override;
void setPluginNamespace(char const* pluginNamespace) noexcept override;
char const* getPluginNamespace() const noexcept override;
private:
nvinfer1::PluginFieldCollection mFC;
std::vector<nvinfer1::PluginField> mPluginAttributes;
std::string mNamespace;
};
} // namespace bert
} // namespace plugin
} // namespace nvinfer1
#endif // TRT_EMB_LAYER_NORM_PLUGIN_LEGACY_H
#endif // CUDA_VERSION >= 10010
@@ -0,0 +1,130 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 1993-2024 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 "NvInfer.h"
#include "common/bertCommon.h"
#include "common/common.cuh"
#include "common/plugin.h"
#include "common/serialize.hpp"
#include <cassert>
#include <cstring>
#include <cuda.h>
#include <vector>
using namespace nvinfer1;
namespace nvinfer1
{
namespace plugin
{
namespace bert
{
template <typename T, unsigned TPB>
__global__ void embLayerNormKernelHFace(int32_t ld, int32_t const* inputIds, int32_t const* tokenIds,
int32_t const* cuSeqlens, float const* beta, float const* gamma, T const* wordEmb, T const* posEmb, T const* tokEmb,
int32_t const wordSize, int32_t const tokSize, T* output)
{
// this code currently assumes the input shape is SxB, row-major => seqPos = s * B + b
// instead we want BxS, row-major => seqPos = b * S + s
// 1. lookup word and token of the block
// blockIdx.x = position in the sequence
// blockIdx.y = batch
// gridDim.x = S
// gridDim.y = B
int32_t const s = blockIdx.x;
int32_t const b = blockIdx.y;
int32_t const sumS = cuSeqlens[b];
int32_t const s_b = cuSeqlens[b + 1] - sumS;
if (s >= s_b)
{
return; // This CTA has nothing to do
}
__shared__ int32_t wordId;
__shared__ int32_t tokenId;
T const rld = T(1.f) / T(ld);
// seqPos = b + s * B
// int32_t const seqPos = blockIdx.y + blockIdx.x * gridDim.y;
// int32_t const seqPos = s * B + s;
int32_t const seqPos = sumS + s;
if (threadIdx.x == 0)
{
wordId = inputIds[seqPos];
tokenId = tokenIds[seqPos];
}
__syncthreads();
// 2. load pos/tok/word embeddings and add them toghether
// offset into embeddings is given by wordId * hidden_size
int32_t const poffset = blockIdx.x * ld;
int32_t const woffset = wordId * ld;
int32_t const toffset = tokenId * ld;
// the output offset is given by b * (S*hidden_size) + s * hidden_size
int32_t const outOffset = seqPos * ld;
kvp<T> threadData(0, 0);
if (wordId >= 0 && wordId < wordSize && tokenId >= 0 && tokenId < tokSize)
{
for (int32_t it = threadIdx.x; it < ld; it += TPB)
{
T const w(wordEmb[woffset + it]);
T const t(tokEmb[toffset + it]);
T const p(posEmb[poffset + it]);
T const val = w + t + p;
output[outOffset + it] = val;
T const rldval = rld * val;
threadData = 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(cudaStream_t stream, int32_t ld, int32_t B, int32_t S, int32_t const* inputIds,
int32_t const* tokenIds, int32_t const* cuSeqlens, float const* beta, float const* gamma, T const* wordEmb,
T const* posEmb, T const* tokEmb, int32_t const wordSize, int32_t const tokSize, T* output)
{
constexpr int32_t tpb = 256;
dim3 const grid(S, B, 1);
dim3 const block(tpb, 1, 1);
embLayerNormKernelHFace<T, tpb><<<grid, block, 0, stream>>>(
ld, inputIds, tokenIds, cuSeqlens, beta, gamma, wordEmb, posEmb, tokEmb, wordSize, tokSize, output);
return cudaPeekAtLastError();
}
template int32_t embSkipLayerNormHFace<float>(cudaStream_t, int32_t, int32_t, int32_t, int32_t const*, int32_t const*,
int32_t const*, float const*, float const*, float const*, float const*, float const*, int32_t const, int32_t const,
float*);
template int32_t embSkipLayerNormHFace<half>(cudaStream_t, int32_t, int32_t, int32_t, int32_t const*, int32_t const*,
int32_t const*, float const*, float const*, half const*, half const*, half const*, int32_t const, int32_t const,
half*);
} // namespace bert
} // namespace plugin
} // namespace nvinfer1
@@ -0,0 +1,131 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 1993-2024 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 "NvInfer.h"
#include "common/bertCommon.h"
#include "common/common.cuh"
#include "common/plugin.h"
#include "common/serialize.hpp"
#include <cassert>
#include <cstring>
#include <cuda.h>
#include <vector>
using namespace nvinfer1;
namespace nvinfer1
{
namespace plugin
{
namespace bert
{
template <typename T, unsigned TPB>
__global__ void embLayerNormKernelMTron(int32_t ld, int32_t const* inputIds, int32_t const* tokenIds,
int32_t const* cuSeqlens, float const* beta, float const* gamma, T const* wordEmb, T const* posEmb, T const* tokEmb,
int32_t const wordSize, int32_t const tokSize, T* output, T* skip)
{
// this code currently assumes the input shape is SxB, row-major => seqPos = s * B + b
// instead we want BxS, row-major => seqPos = b * S + s
// 1. lookup word and token of the block
// blockIdx.x = position in the sequence
// blockIdx.y = batch
// gridDim.x = S
// gridDim.y = B
int32_t const s = blockIdx.x;
int32_t const b = blockIdx.y;
int32_t const sumS = cuSeqlens[b];
int32_t const s_b = cuSeqlens[b + 1] - sumS;
if (s >= s_b)
{
return; // This CTA has nothing to do
}
__shared__ int32_t wordId;
__shared__ int32_t tokenId;
T const rld = T(1.f) / T(ld);
// seqPos = b + s * B
// int32_t const seqPos = blockIdx.y + blockIdx.x * gridDim.y;
// int32_t const seqPos = s * B + s;
int32_t const seqPos = sumS + s;
if (threadIdx.x == 0)
{
wordId = inputIds[seqPos];
tokenId = tokenIds[seqPos];
}
__syncthreads();
// 2. load pos/tok/word embeddings and add them toghether
// offset into embeddings is given by wordId * hidden_size
int32_t const poffset = blockIdx.x * ld;
int32_t const woffset = wordId * ld;
int32_t const toffset = tokenId * ld;
// the output offset is given by b * (S*hidden_size) + s * hidden_size
int32_t const outOffset = seqPos * ld;
kvp<T> threadData(0, 0);
if (wordId >= 0 && wordId < wordSize && tokenId >= 0 && tokenId < tokSize)
{
for (int32_t it = threadIdx.x; it < ld; it += TPB)
{
T const w(wordEmb[woffset + it]);
T const t(tokEmb[toffset + it]);
T const p(posEmb[poffset + it]);
T const val = w + t + p;
output[outOffset + it] = val;
skip[outOffset + it] = val;
T const rldval = rld * val;
threadData = 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(cudaStream_t stream, int32_t ld, int32_t B, int32_t S, int32_t const* inputIds,
int32_t const* tokenIds, int32_t const* cuSeqlens, float const* beta, float const* gamma, T const* wordEmb,
T const* posEmb, T const* tokEmb, int32_t const wordSize, int32_t const tokSize, T* output, T* skip)
{
constexpr int32_t tpb = 256;
dim3 const grid(S, B, 1);
dim3 const block(tpb, 1, 1);
embLayerNormKernelMTron<T, tpb><<<grid, block, 0, stream>>>(
ld, inputIds, tokenIds, cuSeqlens, beta, gamma, wordEmb, posEmb, tokEmb, wordSize, tokSize, output, skip);
return cudaPeekAtLastError();
}
template int32_t embSkipLayerNormMTron<float>(cudaStream_t, int32_t, int32_t, int32_t, int32_t const*, int32_t const*,
int32_t const*, float const*, float const*, float const*, float const*, float const*, int32_t const, int32_t const,
float*, float*);
template int32_t embSkipLayerNormMTron<half>(cudaStream_t, int32_t, int32_t, int32_t, int32_t const*, int32_t const*,
int32_t const*, float const*, float const*, half const*, half const*, half const*, int32_t const, int32_t const,
half*, half*);
} // namespace bert
} // namespace plugin
} // namespace nvinfer1
@@ -0,0 +1,832 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 1993-2026 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 <cstring>
#include <cuda.h>
#include <memory>
#include <set>
#include <string_view>
#include <vector>
#include "NvInfer.h"
#include "common/serialize.hpp"
#include "embLayerNormVarSeqlenPlugin.h"
using namespace nvinfer1;
using namespace nvinfer1::plugin;
using namespace nvinfer1::plugin::bert;
namespace
{
using namespace std::string_view_literals;
constexpr char const* kEMB_LAYER_NORM_VAR_SEQLEN_VERSION_HFACE{"4"};
constexpr char const* kEMB_LAYER_NORM_VAR_SEQLEN_VERSION_MTRON{"5"};
constexpr char const* kEMB_LAYER_NORM_VAR_SEQLEN_NAME{"CustomEmbLayerNormPluginDynamic"};
void checkConfigurationInputs(
PluginTensorDesc const* inputs, int32_t nbInputs, PluginTensorDesc const* outputs, int32_t nbOutputs) noexcept
{
// Validate input arguments
PLUGIN_ASSERT(nbInputs == 4);
PLUGIN_ASSERT(nbOutputs == 2);
PLUGIN_ASSERT(inputs[0].dims.nbDims == 1);
PLUGIN_ASSERT(inputs[1].dims.nbDims == 1);
PLUGIN_ASSERT(inputs[1].dims.d[0] == inputs[0].dims.d[0]);
PLUGIN_ASSERT(inputs[2].dims.nbDims == 1);
PLUGIN_ASSERT(outputs[0].dims.nbDims == 4);
PLUGIN_ASSERT(static_cast<size_t>(outputs[0].dims.d[0]) == static_cast<size_t>(inputs[0].dims.d[0]));
PLUGIN_ASSERT(outputs[0].dims.d[2] == 1);
PLUGIN_ASSERT(outputs[0].dims.d[3] == 1);
PLUGIN_ASSERT(inputs[0].type == DataType::kINT32);
PLUGIN_ASSERT(inputs[1].type == DataType::kINT32);
PLUGIN_ASSERT(inputs[2].type == DataType::kINT32);
}
bool initializeFields(char const* name, PluginFieldCollection const* fc, Weights& beta, Weights& gamma,
Weights& word_emb, Weights& pos_emb, Weights& tok_emb)
{
bool output_fp16 = false;
std::set<std::string> const requiredAttributes{
"bert_embeddings_layernorm_beta",
"bert_embeddings_layernorm_gamma",
"bert_embeddings_word_embeddings",
"bert_embeddings_token_type_embeddings",
"bert_embeddings_position_embeddings",
};
plugin::validateRequiredAttributesExist(requiredAttributes, fc);
for (int32_t i = 0; i < fc->nbFields; i++)
{
std::string_view const field_name = fc->fields[i].name;
if (field_name == "bert_embeddings_layernorm_beta"sv)
{
BERT_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);
}
else if (field_name == "bert_embeddings_layernorm_gamma"sv)
{
BERT_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);
}
else if (field_name == "bert_embeddings_word_embeddings"sv)
{
BERT_DEBUG_MSG("Building bert_embeddings_word_embeddings...");
word_emb.values = fc->fields[i].data;
word_emb.count = fc->fields[i].length;
word_emb.type = fieldTypeToDataType(fc->fields[i].type);
}
else if (field_name == "bert_embeddings_token_type_embeddings"sv)
{
BERT_DEBUG_MSG("Building bert_embeddings_token_type_embeddings...");
tok_emb.values = fc->fields[i].data;
tok_emb.count = fc->fields[i].length;
tok_emb.type = fieldTypeToDataType(fc->fields[i].type);
}
else if (field_name == "bert_embeddings_position_embeddings"sv)
{
BERT_DEBUG_MSG("Building bert_embeddings_position_embeddings...");
pos_emb.values = fc->fields[i].data;
pos_emb.count = fc->fields[i].length;
pos_emb.type = fieldTypeToDataType(fc->fields[i].type);
}
else if (field_name == "output_fp16"sv)
{
BERT_DEBUG_MSG("Building output_fp16...");
PLUGIN_VALIDATE(fc->fields[i].type == PluginFieldType::kINT32);
output_fp16 = static_cast<int32_t const*>(fc->fields[i].data)[0] != 0;
}
}
return output_fp16;
}
} // namespace
REGISTER_TENSORRT_PLUGIN(EmbLayerNormVarSeqlenPluginHFaceCreator);
REGISTER_TENSORRT_PLUGIN(EmbLayerNormVarSeqlenPluginMTronCreator);
EmbLayerNormVarSeqlenPluginBase::EmbLayerNormVarSeqlenPluginBase(std::string const& name, DataType type,
Weights const& beta, Weights const& gamma, Weights const& wordEmb, Weights const& posEmb, Weights const& tokEmb,
DataType maskType)
: mLayerName(name)
, mLd(beta.count)
, mType(type)
, mMaskType(maskType)
{
// Assuming Weights.count is the number of elements and not bytes
PLUGIN_VALIDATE(beta.count == gamma.count);
PLUGIN_VALIDATE(mLd > 0U);
PLUGIN_VALIDATE(wordEmb.count % mLd == 0);
PLUGIN_VALIDATE(posEmb.count % mLd == 0);
PLUGIN_VALIDATE(tokEmb.count % mLd == 0);
mWordVocabSize = wordEmb.count / mLd;
mPosVocabSize = posEmb.count / mLd;
mTokVocabSize = tokEmb.count / mLd;
mBeta.convertAndCopy(beta, nvinfer1::DataType::kFLOAT);
mGamma.convertAndCopy(gamma, nvinfer1::DataType::kFLOAT);
mWordEmb.convertAndCopy(wordEmb, mType);
mTokEmb.convertAndCopy(tokEmb, mType);
mPosEmb.convertAndCopy(posEmb, mType);
copyToDevice(mGamma, sizeof(float) * mGamma.count, mGammaDev);
copyToDevice(mBeta, sizeof(float) * mBeta.count, mBetaDev);
copyToDevice(mWordEmb, getWeightsSize(mWordEmb, mType), mWordEmbDev);
copyToDevice(mPosEmb, getWeightsSize(mPosEmb, mType), mPosEmbDev);
copyToDevice(mTokEmb, getWeightsSize(mTokEmb, mType), mTokEmbDev);
}
EmbLayerNormVarSeqlenPluginHFace::EmbLayerNormVarSeqlenPluginHFace(std::string const& name, DataType const type,
Weights const& beta, Weights const& gamma, Weights const& wordEmb, Weights const& posEmb, Weights const& tokEmb)
: EmbLayerNormVarSeqlenPluginBase(name, type, beta, gamma, wordEmb, posEmb, tokEmb, DataType::kINT32)
{
BERT_DEBUG_MSG("EmbLayerNormVarSeqlenPluginHFace creation");
}
EmbLayerNormVarSeqlenPluginMTron::EmbLayerNormVarSeqlenPluginMTron(std::string const& name, DataType const type,
Weights const& beta, Weights const& gamma, Weights const& wordEmb, Weights const& posEmb, Weights const& tokEmb)
: EmbLayerNormVarSeqlenPluginBase(name, type, beta, gamma, wordEmb, posEmb, tokEmb, type)
{
BERT_DEBUG_MSG("EmbLayerNormVarSeqlenPluginMTron creation");
}
EmbLayerNormVarSeqlenPluginBase::~EmbLayerNormVarSeqlenPluginBase()
{
try
{
// This gets called when the network containing plugin is destroyed
mGammaDev.reset(nullptr);
mBetaDev.reset(nullptr);
mWordEmbDev.reset(nullptr);
mPosEmbDev.reset(nullptr);
mTokEmbDev.reset(nullptr);
// delete this; (TRT will delete this plugin object)
}
catch (std::exception const& e)
{
caughtError(e);
}
}
EmbLayerNormVarSeqlenPluginHFace::~EmbLayerNormVarSeqlenPluginHFace()
{
BERT_DEBUG_MSG("EmbLayerNormVarSeqlenPluginHFace destruction");
}
EmbLayerNormVarSeqlenPluginMTron::~EmbLayerNormVarSeqlenPluginMTron()
{
BERT_DEBUG_MSG("EmbLayerNormVarSeqlenPluginMTron destruction");
}
//////
// IPluginV3 method definitions:
// - getCapabilityInterface() (Base)
// - clone() (HFace, MTron)
//////
IPluginCapability* EmbLayerNormVarSeqlenPluginBase::getCapabilityInterface(PluginCapabilityType type) noexcept
{
try
{
if (type == PluginCapabilityType::kBUILD)
{
return static_cast<IPluginV3OneBuild*>(this);
}
if (type == PluginCapabilityType::kRUNTIME)
{
return static_cast<IPluginV3OneRuntime*>(this);
}
PLUGIN_ASSERT(type == PluginCapabilityType::kCORE);
return static_cast<IPluginV3OneCore*>(this);
}
catch (std::exception const& e)
{
caughtError(e);
}
return nullptr;
}
IPluginV3* EmbLayerNormVarSeqlenPluginHFace::clone() noexcept
{
try
{
BERT_DEBUG_MSG("EmbLayerNormVarSeqlenPluginHFace clone");
auto p = std::make_unique<EmbLayerNormVarSeqlenPluginHFace>(
mLayerName, mType, mBeta, mGamma, mWordEmb, mPosEmb, mTokEmb);
p->setPluginNamespace(mNamespace.c_str());
return p.release();
}
catch (std::exception const& e)
{
caughtError(e);
}
return nullptr;
}
IPluginV3* EmbLayerNormVarSeqlenPluginMTron::clone() noexcept
{
try
{
BERT_DEBUG_MSG("EmbLayerNormVarSeqlenPluginMTron clone");
auto p = std::make_unique<EmbLayerNormVarSeqlenPluginMTron>(
mLayerName, mType, mBeta, mGamma, mWordEmb, mPosEmb, mTokEmb);
p->setPluginNamespace(mNamespace.c_str());
return p.release();
}
catch (std::exception const& e)
{
caughtError(e);
}
return nullptr;
}
// End IPluginV3 method definitions
//////
// IPluginV3OneRuntime method definitions:
// - getFieldsToSerialize() (Base)
// - onShapeChange() (Base)
// - attachToContext() (Base)
// - enqueue() (HFace, MTron)
/////
PluginFieldCollection const* EmbLayerNormVarSeqlenPluginBase::getFieldsToSerialize() noexcept
{
mDataToSerialize.clear();
bool output_fp16 = mType == DataType::kHALF;
mDataToSerialize.emplace_back("output_fp16", &output_fp16, PluginFieldType::kINT32, 1);
mDataToSerialize.emplace_back("bert_embeddings_layernorm_beta", static_cast<float const*>(mBeta.values),
PluginFieldType::kFLOAT32, mBeta.count);
mDataToSerialize.emplace_back("bert_embeddings_layernorm_gamma", static_cast<float const*>(mGamma.values),
PluginFieldType::kFLOAT32, mGamma.count);
if (output_fp16)
{
mDataToSerialize.emplace_back("bert_embeddings_word_embeddings", static_cast<half const*>(mWordEmb.values),
PluginFieldType::kFLOAT16, mWordEmb.count);
mDataToSerialize.emplace_back("bert_embeddings_token_type_embeddings", static_cast<half const*>(mTokEmb.values),
PluginFieldType::kFLOAT16, mTokEmb.count);
mDataToSerialize.emplace_back("bert_embeddings_position_embeddings", static_cast<half const*>(mPosEmb.values),
PluginFieldType::kFLOAT16, mPosEmb.count);
}
else
{
mDataToSerialize.emplace_back("bert_embeddings_word_embeddings", static_cast<float const*>(mWordEmb.values),
PluginFieldType::kFLOAT32, mWordEmb.count);
mDataToSerialize.emplace_back("bert_embeddings_token_type_embeddings",
static_cast<float const*>(mTokEmb.values), PluginFieldType::kFLOAT32, mTokEmb.count);
mDataToSerialize.emplace_back("bert_embeddings_position_embeddings", static_cast<float const*>(mPosEmb.values),
PluginFieldType::kFLOAT32, mPosEmb.count);
}
mFCToSerialize.nbFields = mDataToSerialize.size();
mFCToSerialize.fields = mDataToSerialize.data();
return &mFCToSerialize;
}
int32_t EmbLayerNormVarSeqlenPluginHFace::onShapeChange(
PluginTensorDesc const* inputs, int32_t nbInputs, PluginTensorDesc const* outputs, int32_t nbOutputs) noexcept
{
try
{
BERT_DEBUG_MSG("EmbLayerNormVarSeqlenPluginHFace onShapeChange");
checkConfigurationInputs(inputs, nbInputs, outputs, nbOutputs);
// output 0 is the embedding
PLUGIN_ASSERT(static_cast<size_t>(outputs[0].dims.d[1]) == static_cast<size_t>(mLd));
PLUGIN_ASSERT(outputs[0].type == mType);
// output 1 is the mask indices (empty for HFace variant)
PLUGIN_ASSERT(outputs[1].dims.nbDims == 0);
PLUGIN_ASSERT(outputs[1].type == mMaskType);
return pluginStatus_t::STATUS_SUCCESS;
}
catch (std::exception const& e)
{
caughtError(e);
}
return pluginStatus_t::STATUS_FAILURE;
}
int32_t EmbLayerNormVarSeqlenPluginMTron::onShapeChange(
PluginTensorDesc const* inputs, int32_t nbInputs, PluginTensorDesc const* outputs, int32_t nbOutputs) noexcept
{
try
{
// Validate input arguments
BERT_DEBUG_MSG("EmbLayerNormVarSeqlenPluginMTron onShapeChange");
checkConfigurationInputs(inputs, nbInputs, outputs, nbOutputs);
PLUGIN_ASSERT(static_cast<size_t>(outputs[0].dims.d[1]) == static_cast<size_t>(mLd));
PLUGIN_ASSERT(outputs[1].dims.nbDims == 4);
PLUGIN_ASSERT(static_cast<size_t>(outputs[1].dims.d[0]) == static_cast<size_t>(inputs[0].dims.d[0]));
PLUGIN_ASSERT(static_cast<size_t>(outputs[1].dims.d[1]) == static_cast<size_t>(mLd));
PLUGIN_ASSERT(outputs[1].dims.d[2] == 1);
PLUGIN_ASSERT(outputs[1].dims.d[3] == 1);
PLUGIN_ASSERT(outputs[0].type == mType);
PLUGIN_ASSERT(outputs[1].type == mMaskType);
return pluginStatus_t::STATUS_SUCCESS;
}
catch (std::exception const& e)
{
caughtError(e);
}
return pluginStatus_t::STATUS_FAILURE;
}
IPluginV3* EmbLayerNormVarSeqlenPluginBase::attachToContext(IPluginResourceContext* context) noexcept
{
return clone();
}
int32_t EmbLayerNormVarSeqlenPluginHFace::enqueue(PluginTensorDesc const* inputDesc,
PluginTensorDesc const* /* outputDesc */, void const* const* inputs, void* const* outputs, void* /* workspace */,
cudaStream_t stream) noexcept
{
try
{
PLUGIN_VALIDATE(inputDesc != nullptr && inputs != nullptr && outputs != nullptr);
int32_t const batchSize = inputDesc[2].dims.d[0] - 1;
// read out the maximum sequence length from the dummy input
int32_t const maxSeqlen = inputDesc[3].dims.d[0];
// There are four versions of the kernel which are optimized for sequence lengths 384, 256, 192 and 128.
// Find the closest sequence length bigger than the max seq length in this batch.
int32_t S = 384;
if (maxSeqlen <= 128)
{
S = 128;
}
else if (maxSeqlen <= 192)
{
S = 192;
}
else if (maxSeqlen <= 256)
{
S = 256;
}
// Our plugin outputs only one tensor
auto const inputIds = static_cast<int32_t const*>(inputs[0]);
auto const segmentIds = static_cast<int32_t const*>(inputs[1]);
int32_t const* cuSeqlens = static_cast<int32_t const*>(inputs[2]);
float const* beta = mBetaDev.get();
float const* gamma = mGammaDev.get();
if (mType == DataType::kFLOAT)
{
auto output = static_cast<float*>(outputs[0]);
auto const wordEmb = static_cast<float const*>(mWordEmbDev.get());
auto const tokEmb = static_cast<float const*>(mTokEmbDev.get());
auto const posEmb = static_cast<float const*>(mPosEmbDev.get());
return embSkipLayerNormHFace<float>(stream, static_cast<int32_t>(mLd), batchSize, S, inputIds, segmentIds,
cuSeqlens, beta, gamma, wordEmb, posEmb, tokEmb, mWordVocabSize, mTokVocabSize, output);
}
if (mType == DataType::kHALF)
{
auto output = static_cast<half*>(outputs[0]);
auto const wordEmb = static_cast<half const*>(mWordEmbDev.get());
auto const tokEmb = static_cast<half const*>(mTokEmbDev.get());
auto const posEmb = static_cast<half const*>(mPosEmbDev.get());
return embSkipLayerNormHFace<half>(stream, static_cast<int32_t>(mLd), batchSize, S, inputIds, segmentIds,
cuSeqlens, beta, gamma, wordEmb, posEmb, tokEmb, mWordVocabSize, mTokVocabSize, output);
}
else
{
gLogError << "Unsupported type error, expected [kHALF,kFLOAT], but received " << static_cast<int32_t>(mType)
<< std::endl;
return STATUS_NOT_SUPPORTED;
}
return STATUS_SUCCESS;
}
catch (std::exception const& e)
{
caughtError(e);
}
return STATUS_FAILURE;
}
int32_t EmbLayerNormVarSeqlenPluginMTron::enqueue(PluginTensorDesc const* inputDesc,
PluginTensorDesc const* /* outputDesc */, void const* const* inputs, void* const* outputs, void* /* workspace */,
cudaStream_t stream) noexcept
{
try
{
PLUGIN_VALIDATE(inputDesc != nullptr && inputs != nullptr && outputs != nullptr);
int32_t const batchSize = inputDesc[2].dims.d[0] - 1;
// read out the maximum sequence length from the dummy input
int32_t const maxSeqlen = inputDesc[3].dims.d[0];
// There are four versions of the kernel which are optimized for sequence lengths 384, 256, 192 and 128.
// Find the closest sequence length bigger than the max seq length in this batch.
int32_t S = 384;
if (maxSeqlen <= 128)
{
S = 128;
}
else if (maxSeqlen <= 192)
{
S = 192;
}
else if (maxSeqlen <= 256)
{
S = 256;
}
// Our plugin outputs only one tensor
auto const inputIds = static_cast<int32_t const*>(inputs[0]);
auto const segmentIds = static_cast<int32_t const*>(inputs[1]);
int32_t const* cuSeqlens = static_cast<int32_t const*>(inputs[2]);
float const* beta = mBetaDev.get();
float const* gamma = mGammaDev.get();
if (mType == DataType::kFLOAT)
{
auto output = static_cast<float*>(outputs[0]);
auto skip = static_cast<float*>(outputs[1]);
auto const wordEmb = static_cast<float const*>(mWordEmbDev.get());
auto const tokEmb = static_cast<float const*>(mTokEmbDev.get());
auto const posEmb = static_cast<float const*>(mPosEmbDev.get());
return embSkipLayerNormMTron<float>(stream, static_cast<int32_t>(mLd), batchSize, S, inputIds, segmentIds,
cuSeqlens, beta, gamma, wordEmb, posEmb, tokEmb, mWordVocabSize, mTokVocabSize, output, skip);
}
if (mType == DataType::kHALF)
{
auto output = static_cast<half*>(outputs[0]);
auto skip = static_cast<half*>(outputs[1]);
auto const wordEmb = static_cast<half const*>(mWordEmbDev.get());
auto const tokEmb = static_cast<half const*>(mTokEmbDev.get());
auto const posEmb = static_cast<half const*>(mPosEmbDev.get());
return embSkipLayerNormMTron<half>(stream, static_cast<int32_t>(mLd), batchSize, S, inputIds, segmentIds,
cuSeqlens, beta, gamma, wordEmb, posEmb, tokEmb, mWordVocabSize, mTokVocabSize, output, skip);
}
else
{
gLogError << "Unsupported type error, expected [kHALF,kFLOAT], but received " << static_cast<int32_t>(mType)
<< std::endl;
return STATUS_NOT_SUPPORTED;
}
return STATUS_SUCCESS;
}
catch (std::exception const& e)
{
caughtError(e);
}
return STATUS_FAILURE;
}
// end IPluginV3OneRuntime method definitions
///////
// IPluginV3OneBuild method definitions
// - getNbOutputs() (Base)
// - supportsFormatCombination() (Base)
// - getOutputShapes (HFace, MTron)
// - getOutputDataTypes() (Base)
// - configurePlugin() (Base)
// - getWorkSpaceSize() (Base)
//////
int32_t EmbLayerNormVarSeqlenPluginBase::getNbOutputs() const noexcept
{
return 2;
}
bool EmbLayerNormVarSeqlenPluginBase::supportsFormatCombination(
int32_t pos, DynamicPluginTensorDesc const* inOut, int32_t nbInputs, int32_t nbOutputs) noexcept
{
// The four inputs to this plugin input_ids, segment_ids, cu_seqlens and a dummy input with the
// size of the max seq length in that order
PLUGIN_ASSERT(nbInputs == 4);
// The two outputs of the plugin are embedding and the mask
PLUGIN_ASSERT(nbOutputs == 2);
PluginTensorDesc const& desc = inOut[pos].desc;
if (desc.format != TensorFormat::kLINEAR)
{
return false;
}
if (pos == 0 || pos == 2) // input_ids and cu_seqlens
{
return desc.type == DataType::kINT32 && desc.dims.nbDims == 1;
}
PluginTensorDesc const& prev = inOut[pos - 1].desc;
if (pos == 1) // segment ids: check it's the same as input_ids
{
return desc.type == DataType::kINT32 && desc.dims.nbDims == 1 && desc.dims.d[0] == prev.dims.d[0];
}
if (pos == 3)
{
return desc.dims.nbDims == 1;
}
// embedded sequence
if (pos == nbInputs)
{
return desc.type == mType && desc.dims.nbDims == 4 && desc.dims.d[0] == inOut[0].desc.dims.d[0]
&& desc.dims.d[2] == 1 && desc.dims.d[3] == 1;
}
// mask
return desc.type == mMaskType;
}
int32_t EmbLayerNormVarSeqlenPluginHFace::getOutputShapes(DimsExprs const* inputs, int32_t nbInputs,
DimsExprs const* shapeInputs, int32_t nbShapeInputs, DimsExprs* outputs, int32_t nbOutputs,
IExprBuilder& exprBuilder) noexcept
{
try
{
PLUGIN_VALIDATE(inputs != nullptr);
PLUGIN_VALIDATE(outputs != nullptr);
// Input should be input ids and token ids and cumulative seqlens
// Output should be the embeddings tensor and mask indices
PLUGIN_ASSERT(nbInputs == 4);
PLUGIN_ASSERT(nbOutputs == 2);
PLUGIN_ASSERT(inputs[0].nbDims == 1); // sum of all s
PLUGIN_ASSERT(inputs[0].nbDims == inputs[1].nbDims);
PLUGIN_ASSERT(inputs[2].nbDims == 1); // B+1
// output 0 : embedded input
outputs[0].nbDims = 4;
outputs[0].d[0] = inputs[0].d[0];
outputs[0].d[1] = exprBuilder.constant(mLd);
outputs[0].d[2] = exprBuilder.constant(1);
outputs[0].d[3] = exprBuilder.constant(1);
// Output 1 : maskIdx
// Return empty tensor since this is dummy output, we do not delete it for backward compatibility.
outputs[1].nbDims = 0;
return pluginStatus_t::STATUS_SUCCESS;
}
catch (const std::exception& e)
{
caughtError(e);
}
return pluginStatus_t::STATUS_FAILURE;
}
int32_t EmbLayerNormVarSeqlenPluginMTron::getOutputShapes(DimsExprs const* inputs, int32_t nbInputs,
DimsExprs const* shapeInputs, int32_t nbShapeInputs, DimsExprs* outputs, int32_t nbOutputs,
IExprBuilder& exprBuilder) noexcept
{
try
{
PLUGIN_VALIDATE(inputs != nullptr);
PLUGIN_VALIDATE(outputs != nullptr);
// Input should be input ids and token ids and cumulative seqlens
// Output should be the embeddings tensor and mask indices
PLUGIN_ASSERT(nbInputs == 4);
PLUGIN_ASSERT(nbOutputs == 2);
PLUGIN_ASSERT(inputs[0].nbDims == 1); // sum of all s
PLUGIN_ASSERT(inputs[0].nbDims == inputs[1].nbDims);
PLUGIN_ASSERT(inputs[2].nbDims == 1); // B+1
// Output 0 : embedded input
outputs[0].nbDims = 4;
outputs[0].d[0] = inputs[0].d[0];
outputs[0].d[1] = exprBuilder.constant(mLd);
outputs[0].d[2] = exprBuilder.constant(1);
outputs[0].d[3] = exprBuilder.constant(1);
// Output 1 : maskIdx
outputs[1].nbDims = 4;
outputs[1].d[0] = inputs[0].d[0];
outputs[1].d[1] = exprBuilder.constant(mLd);
outputs[1].d[2] = exprBuilder.constant(1);
outputs[1].d[3] = exprBuilder.constant(1);
return pluginStatus_t::STATUS_SUCCESS;
}
catch (const std::exception& e)
{
caughtError(e);
}
return pluginStatus_t::STATUS_FAILURE;
}
int32_t EmbLayerNormVarSeqlenPluginBase::getOutputDataTypes(
DataType* outputTypes, int32_t nbOutputs, DataType const* inputTypes, int32_t nbInputs) const noexcept
{
try
{
PLUGIN_ASSERT(mType == DataType::kHALF || mType == DataType::kFLOAT);
outputTypes[0] = mType;
outputTypes[1] = mMaskType;
return pluginStatus_t::STATUS_SUCCESS;
}
catch (std::exception const& e)
{
caughtError(e);
}
return pluginStatus_t::STATUS_FAILURE;
}
int32_t EmbLayerNormVarSeqlenPluginBase::configurePlugin(DynamicPluginTensorDesc const* inputs, int32_t nbInputs,
DynamicPluginTensorDesc const* outputs, int32_t nbOutputs) noexcept
{
return pluginStatus_t::STATUS_SUCCESS;
}
size_t EmbLayerNormVarSeqlenPluginBase::getWorkspaceSize(DynamicPluginTensorDesc const* inputs, int32_t nbInputs,
DynamicPluginTensorDesc const* outputs, int32_t nbOutputs) const noexcept
{
return 0;
}
// End IPluginV3OneBuild method definitions
//////
// IPluginV3OneCore method definitions
// - getPluginVersion() (MTron, HFace)
// - getPluginName() (Base)
// - getPluginNamespace() (Base)
// - setPluginNamespace() (Base)
//////
char const* EmbLayerNormVarSeqlenPluginHFace::getPluginVersion() const noexcept
{
return kEMB_LAYER_NORM_VAR_SEQLEN_VERSION_HFACE;
}
char const* EmbLayerNormVarSeqlenPluginMTron::getPluginVersion() const noexcept
{
return kEMB_LAYER_NORM_VAR_SEQLEN_VERSION_MTRON;
}
char const* EmbLayerNormVarSeqlenPluginBase::getPluginName() const noexcept
{
return kEMB_LAYER_NORM_VAR_SEQLEN_NAME;
}
char const* EmbLayerNormVarSeqlenPluginBase::getPluginNamespace() const noexcept
{
return mNamespace.c_str();
}
void EmbLayerNormVarSeqlenPluginBase::setPluginNamespace(char const* libNamespace) noexcept
{
mNamespace = libNamespace;
}
// End IPluginV3OneCore method definitions
//////////////////////////// Plugin Creator member definitions /////////////////////////////
EmbLayerNormVarSeqlenPluginBaseCreator::EmbLayerNormVarSeqlenPluginBaseCreator()
{
static std::mutex sMutex;
std::lock_guard<std::mutex> lock(sMutex);
mPluginAttributes.clear();
mPluginAttributes.emplace_back(PluginField("output_fp16", nullptr, PluginFieldType::kINT32, 1));
// the length of beta, gamma, word_emb, pos_emb, and tok_emb will only be known at the time of plugin creation
// so we set it to 0 here
mPluginAttributes.emplace_back(PluginField("bert_embeddings_layernorm_beta", nullptr, PluginFieldType::kFLOAT32, 0));
mPluginAttributes.emplace_back(PluginField("bert_embeddings_layernorm_gamma", nullptr, PluginFieldType::kFLOAT32, 0));
// the embeddings datatype is determined by the output_fp16 attribute known at runtime
// so we set it to kUNKNOWN here
mPluginAttributes.emplace_back(PluginField("bert_embeddings_word_embeddings", nullptr, PluginFieldType::kUNKNOWN, 0));
mPluginAttributes.emplace_back(PluginField("bert_embeddings_token_type_embeddings", nullptr, PluginFieldType::kUNKNOWN, 0));
mPluginAttributes.emplace_back(PluginField("bert_embeddings_position_embeddings", nullptr, PluginFieldType::kUNKNOWN, 0));
mFC.nbFields = mPluginAttributes.size();
mFC.fields = mPluginAttributes.data();
}
char const* EmbLayerNormVarSeqlenPluginBaseCreator::getPluginName() const noexcept
{
return kEMB_LAYER_NORM_VAR_SEQLEN_NAME;
}
char const* EmbLayerNormVarSeqlenPluginHFaceCreator::getPluginVersion() const noexcept
{
return kEMB_LAYER_NORM_VAR_SEQLEN_VERSION_HFACE;
}
char const* EmbLayerNormVarSeqlenPluginMTronCreator::getPluginVersion() const noexcept
{
return kEMB_LAYER_NORM_VAR_SEQLEN_VERSION_MTRON;
}
PluginFieldCollection const* EmbLayerNormVarSeqlenPluginBaseCreator::getFieldNames() noexcept
{
return &mFC;
}
IPluginV3* EmbLayerNormVarSeqlenPluginHFaceCreator::createPlugin(
char const* name, PluginFieldCollection const* fc, TensorRTPhase phase) noexcept
{
try
{
BERT_DEBUG_MSG("EmbLayerNormVarSeqlenHFace createPlugin");
Weights beta{}; // required attribute: validateRequiredAttributesExist() call in initializeFields() will verify
// existence
Weights gamma{}; // required attribute: validateRequiredAttributesExist() call in initializeFields() will verify
// existence
Weights word_emb{}; // required attribute: validateRequiredAttributesExist() call in initializeFields() will
// verify existence
Weights pos_emb{}; // required attribute: validateRequiredAttributesExist() call in initializeFields() will
// verify existence
Weights tok_emb{}; // required attribute: validateRequiredAttributesExist() call in initializeFields() will
// verify existence
bool output_fp16 = initializeFields(name, fc, beta, gamma, word_emb, pos_emb, tok_emb);
BERT_DEBUG_MSG("Building the Plugin...");
auto p = std::make_unique<EmbLayerNormVarSeqlenPluginHFace>(
name, output_fp16 ? DataType::kHALF : DataType::kFLOAT, beta, gamma, word_emb, pos_emb, tok_emb);
return p.release();
}
catch (std::exception const& e)
{
caughtError(e);
}
return nullptr;
}
IPluginV3* EmbLayerNormVarSeqlenPluginMTronCreator::createPlugin(
char const* name, PluginFieldCollection const* fc, TensorRTPhase phase) noexcept
{
try
{
BERT_DEBUG_MSG("EmbLayerNormVarSeqlenMTron createPlugin");
Weights beta{}; // required attribute: validateRequiredAttributesExist() call in initializeFields() will verify
// existence
Weights gamma{}; // required attribute: validateRequiredAttributesExist() call in initializeFields() will verify
// existence
Weights word_emb{}; // required attribute: validateRequiredAttributesExist() call in initializeFields() will
// verify existence
Weights pos_emb{}; // required attribute: validateRequiredAttributesExist() call in initializeFields() will
// verify existence
Weights tok_emb{}; // required attribute: validateRequiredAttributesExist() call in initializeFields() will
// verify existence
bool output_fp16 = initializeFields(name, fc, beta, gamma, word_emb, pos_emb, tok_emb);
BERT_DEBUG_MSG("Building the Plugin...");
auto p = std::make_unique<EmbLayerNormVarSeqlenPluginMTron>(
name, output_fp16 ? DataType::kHALF : DataType::kFLOAT, beta, gamma, word_emb, pos_emb, tok_emb);
return p.release();
}
catch (std::exception const& e)
{
caughtError(e);
}
return nullptr;
}
void EmbLayerNormVarSeqlenPluginBaseCreator::setPluginNamespace(char const* libNamespace) noexcept
{
try
{
mNamespace = libNamespace;
}
catch (std::exception const& e)
{
caughtError(e);
}
}
char const* EmbLayerNormVarSeqlenPluginBaseCreator::getPluginNamespace() const noexcept
{
return mNamespace.c_str();
}
@@ -0,0 +1,223 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 1993-2025 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.
*/
#ifndef TRT_EMB_LAYER_NORM_VARSEQ_PLUGIN_H
#define TRT_EMB_LAYER_NORM_VARSEQ_PLUGIN_H
#include <cuda.h>
#include "NvInferPlugin.h"
#include "NvInferRuntime.h"
#include "common/bertCommon.h"
#include <string>
#include <vector>
namespace nvinfer1
{
namespace plugin
{
namespace bert
{
template <typename T>
int32_t embSkipLayerNormHFace(cudaStream_t stream, int32_t ld, int32_t B, int32_t S, int32_t const* inputIds,
int32_t const* tokenIds, int32_t const* cuSeqlens, float const* beta, float const* gamma, T const* wordEmb,
T const* posEmb, T const* tokEmb, int32_t const wordSize, int32_t const tokSize, T* output);
template <typename T>
int32_t embSkipLayerNormMTron(cudaStream_t stream, int32_t ld, int32_t B, int32_t S, int32_t const* inputIds,
int32_t const* tokenIds, int32_t const* cuSeqlens, float const* beta, float const* gamma, T const* wordEmb,
T const* posEmb, T const* tokEmb, int32_t const wordSize, int32_t const tokSize, T* output, T* skip);
class EmbLayerNormVarSeqlenPluginBase : public IPluginV3,
public IPluginV3OneCore,
public IPluginV3OneBuild,
public IPluginV3OneRuntime
{
public:
EmbLayerNormVarSeqlenPluginBase(std::string const& name, DataType type, Weights const& beta, Weights const& gamma,
Weights const& word_emb, Weights const& pos_emb, Weights const& tok_emb, DataType maskType);
// It doesn't make sense to make EmbLayerNormVarSeqlenPlugin without arguments, so we
// delete default constructor.
EmbLayerNormVarSeqlenPluginBase() = delete;
~EmbLayerNormVarSeqlenPluginBase() override;
// IPluginV3 Methods
// NOTE: since this is itself is an abstract class, the rest of virtual methods defined in its children classes
IPluginCapability* getCapabilityInterface(PluginCapabilityType type) noexcept override;
// end of IPluginV3 Methods
// IPluginV3OneCore Methods
char const* getPluginName() const noexcept override;
char const* getPluginNamespace() const noexcept override;
void setPluginNamespace(char const* pluginNamespace) noexcept;
// end of IPluginV3OneCore Methods
// IPluginV3Build Methods
bool supportsFormatCombination(
int32_t pos, DynamicPluginTensorDesc const* inOut, int32_t nbInputs, int32_t nbOutputs) noexcept override;
int32_t configurePlugin(DynamicPluginTensorDesc const* in, int32_t nbInputs, DynamicPluginTensorDesc const* out,
int32_t nbOutputs) noexcept override;
size_t getWorkspaceSize(DynamicPluginTensorDesc const* inputs, int32_t nbInputs,
DynamicPluginTensorDesc const* outputs, int32_t nbOutputs) const noexcept override;
int32_t getOutputDataTypes(
DataType* outputTypes, int32_t nbOutputs, DataType const* inputTypes, int32_t nbInputs) const noexcept override;
int32_t getNbOutputs() const noexcept override;
// end IPluginV3Build Methods
// IPluginV3Runtime Methods
IPluginV3* attachToContext(IPluginResourceContext* context) noexcept override;
PluginFieldCollection const* getFieldsToSerialize() noexcept override;
// end IPluginV3Runtime Methods
protected:
// metadata fields
std::string const mLayerName;
std::string mNamespace;
// device-side
bert::cuda_unique_ptr<float> mGammaDev;
bert::cuda_unique_ptr<float> mBetaDev;
bert::cuda_unique_ptr<void> mWordEmbDev;
bert::cuda_unique_ptr<void> mTokEmbDev;
bert::cuda_unique_ptr<void> mPosEmbDev;
size_t mLd; // leading dim = hidden size
size_t mWordVocabSize;
size_t mPosVocabSize;
size_t mTokVocabSize;
// members that partcipate in ser/deserialization
bert::WeightsWithOwnership mBeta;
bert::WeightsWithOwnership mGamma;
bert::WeightsWithOwnership mWordEmb;
bert::WeightsWithOwnership mTokEmb;
bert::WeightsWithOwnership mPosEmb;
DataType mType{};
DataType mMaskType{};
// IPluginV3 serialization related
std::vector<nvinfer1::PluginField> mDataToSerialize;
nvinfer1::PluginFieldCollection mFCToSerialize;
};
class EmbLayerNormVarSeqlenPluginHFace : public EmbLayerNormVarSeqlenPluginBase
{
public:
EmbLayerNormVarSeqlenPluginHFace(std::string const& name, nvinfer1::DataType const type,
nvinfer1::Weights const& beta, nvinfer1::Weights const& gamma, nvinfer1::Weights const& word_emb,
nvinfer1::Weights const& pos_emb, nvinfer1::Weights const& tok_emb);
// It doesn't make sense to make EmbLayerNormVarSeqlenPlugin without arguments, so we
// delete default constructor.
EmbLayerNormVarSeqlenPluginHFace() = delete;
~EmbLayerNormVarSeqlenPluginHFace() override;
// IPluginV3Runtime overrides
IPluginV3* clone() noexcept override;
int32_t onShapeChange(
PluginTensorDesc const* in, int32_t nbInputs, PluginTensorDesc 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;
// IPluginV3OneCore override
char const* getPluginVersion() const noexcept override;
// IPluginV3OneBuild override
int32_t getOutputShapes(DimsExprs const* inputs, int32_t nbInputs, DimsExprs const* shapeInputs,
int32_t nbShapeInputs, DimsExprs* outputs, int32_t nbOutputs, IExprBuilder& exprBuilder) noexcept override;
};
class EmbLayerNormVarSeqlenPluginMTron : public EmbLayerNormVarSeqlenPluginBase
{
public:
EmbLayerNormVarSeqlenPluginMTron(std::string const& name, nvinfer1::DataType const type,
nvinfer1::Weights const& beta, nvinfer1::Weights const& gamma, nvinfer1::Weights const& word_emb,
nvinfer1::Weights const& pos_emb, nvinfer1::Weights const& tok_emb);
// It doesn't make sense to make EmbLayerNormVarSeqlenPlugin without arguments, so we
// delete default constructor.
EmbLayerNormVarSeqlenPluginMTron() = delete;
~EmbLayerNormVarSeqlenPluginMTron() override;
// IPluginV3Runtime overrides
IPluginV3* clone() noexcept override;
int32_t onShapeChange(
PluginTensorDesc const* in, int32_t nbInputs, PluginTensorDesc 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;
// IPluginV3OneCore override
char const* getPluginVersion() const noexcept override;
// IPluginV3OneBuild override
int32_t getOutputShapes(DimsExprs const* inputs, int32_t nbInputs, DimsExprs const* shapeInputs,
int32_t nbShapeInputs, DimsExprs* outputs, int32_t nbOutputs, IExprBuilder& exprBuilder) noexcept override;
};
class EmbLayerNormVarSeqlenPluginBaseCreator : public nvinfer1::IPluginCreatorV3One
{
public:
EmbLayerNormVarSeqlenPluginBaseCreator();
char const* getPluginName() const noexcept override;
nvinfer1::PluginFieldCollection const* getFieldNames() noexcept override;
void setPluginNamespace(char const* libNamespace) noexcept;
char const* getPluginNamespace() const noexcept override;
protected:
nvinfer1::PluginFieldCollection mFC;
std::vector<nvinfer1::PluginField> mPluginAttributes;
std::string mNamespace;
};
class EmbLayerNormVarSeqlenPluginHFaceCreator : public EmbLayerNormVarSeqlenPluginBaseCreator
{
public:
IPluginV3* createPlugin(char const* name, PluginFieldCollection const* fc, TensorRTPhase phase) noexcept override;
char const* getPluginVersion() const noexcept override;
};
class EmbLayerNormVarSeqlenPluginMTronCreator : public EmbLayerNormVarSeqlenPluginBaseCreator
{
public:
IPluginV3* createPlugin(char const* name, PluginFieldCollection const* fc, TensorRTPhase phase) noexcept override;
char const* getPluginVersion() const noexcept override;
};
} // namespace bert
} // namespace plugin
} // namespace nvinfer1
#endif // TRT_EMB_LAYER_NORM_VARSEQ_PLUGIN_H
@@ -0,0 +1,813 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 1993-2026 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 <cstring>
#include <cuda.h>
#include <memory>
#include <set>
#include <string_view>
#include <vector>
#include "NvInfer.h"
#include "common/serialize.hpp"
#include "embLayerNormVarSeqlenPluginLegacy.h"
using namespace nvinfer1;
using namespace nvinfer1::plugin;
using namespace nvinfer1::plugin::bert;
namespace
{
using namespace std::string_view_literals;
constexpr char const* kEMB_LAYER_NORM_VAR_SEQLEN_VERSION_HFACE{"2"};
constexpr char const* kEMB_LAYER_NORM_VAR_SEQLEN_VERSION_MTRON{"3"};
constexpr char const* kEMB_LAYER_NORM_VAR_SEQLEN_NAME{"CustomEmbLayerNormPluginDynamic"};
} // namespace
REGISTER_TENSORRT_PLUGIN(EmbLayerNormVarSeqlenPluginLegacyHFaceCreator);
REGISTER_TENSORRT_PLUGIN(EmbLayerNormVarSeqlenPluginLegacyMTronCreator);
EmbLayerNormVarSeqlenPluginLegacyBase::EmbLayerNormVarSeqlenPluginLegacyBase(std::string const& name, DataType type,
Weights const& beta, Weights const& gamma, Weights const& wordEmb, Weights const& posEmb, Weights const& tokEmb,
DataType maskType)
: mLayerName(name)
, mLd(beta.count)
, mType(type)
, mMaskType(maskType)
{
// Assuming Weights.count is the number of elements and not bytes
PLUGIN_VALIDATE(beta.count == gamma.count);
PLUGIN_VALIDATE(mLd > 0U);
PLUGIN_VALIDATE(wordEmb.count % mLd == 0);
PLUGIN_VALIDATE(posEmb.count % mLd == 0);
PLUGIN_VALIDATE(tokEmb.count % mLd == 0);
mWordVocabSize = wordEmb.count / mLd;
mPosVocabSize = posEmb.count / mLd;
mTokVocabSize = tokEmb.count / mLd;
mBeta.convertAndCopy(beta, nvinfer1::DataType::kFLOAT);
mGamma.convertAndCopy(gamma, nvinfer1::DataType::kFLOAT);
mWordEmb.convertAndCopy(wordEmb, mType);
mTokEmb.convertAndCopy(tokEmb, mType);
mPosEmb.convertAndCopy(posEmb, mType);
copyToDevice(mGamma, sizeof(float) * mGamma.count, mGammaDev);
copyToDevice(mBeta, sizeof(float) * mBeta.count, mBetaDev);
copyToDevice(mWordEmb, getWeightsSize(mWordEmb, mType), mWordEmbDev);
copyToDevice(mPosEmb, getWeightsSize(mPosEmb, mType), mPosEmbDev);
copyToDevice(mTokEmb, getWeightsSize(mTokEmb, mType), mTokEmbDev);
}
EmbLayerNormVarSeqlenPluginLegacyBase::EmbLayerNormVarSeqlenPluginLegacyBase(
std::string const& name, void const* data, size_t length)
: mLayerName(name)
, mGammaDev(nullptr)
, mBetaDev(nullptr)
, mWordEmbDev(nullptr)
, mTokEmbDev(nullptr)
, mPosEmbDev(nullptr)
{
// Deserialize in the same order as serialization
deserialize_value(&data, &length, &mType);
deserialize_value(&data, &length, &mLd);
deserialize_value(&data, &length, &mWordVocabSize);
deserialize_value(&data, &length, &mPosVocabSize);
deserialize_value(&data, &length, &mTokVocabSize);
deserialize_value(&data, &length, &mMaskType);
char const* d = static_cast<char const*>(data);
mBeta.convertAndCopy(d, mLd, nvinfer1::DataType::kFLOAT);
mGamma.convertAndCopy(d, mLd, nvinfer1::DataType::kFLOAT);
mWordEmb.convertAndCopy(d, mLd * mWordVocabSize, mType);
mPosEmb.convertAndCopy(d, mLd * mPosVocabSize, mType);
mTokEmb.convertAndCopy(d, mLd * mTokVocabSize, mType);
copyToDevice(mGamma, sizeof(float) * mGamma.count, mGammaDev);
copyToDevice(mBeta, sizeof(float) * mBeta.count, mBetaDev);
copyToDevice(mWordEmb, getWeightsSize(mWordEmb, mType), mWordEmbDev);
copyToDevice(mPosEmb, getWeightsSize(mPosEmb, mType), mPosEmbDev);
copyToDevice(mTokEmb, getWeightsSize(mTokEmb, mType), mTokEmbDev);
}
EmbLayerNormVarSeqlenPluginLegacyHFace::EmbLayerNormVarSeqlenPluginLegacyHFace(std::string const& name,
DataType const type, Weights const& beta, Weights const& gamma, Weights const& wordEmb, Weights const& posEmb,
Weights const& tokEmb)
: EmbLayerNormVarSeqlenPluginLegacyBase(name, type, beta, gamma, wordEmb, posEmb, tokEmb, DataType::kINT32)
{
}
EmbLayerNormVarSeqlenPluginLegacyHFace::EmbLayerNormVarSeqlenPluginLegacyHFace(
std::string const& name, void const* data, size_t length)
: EmbLayerNormVarSeqlenPluginLegacyBase(name, data, length)
{
BERT_DEBUG_MSG("EmbLayerNormVarSeqlenPluginLegacyHFace deserialize");
}
EmbLayerNormVarSeqlenPluginLegacyMTron::EmbLayerNormVarSeqlenPluginLegacyMTron(std::string const& name,
DataType const type, Weights const& beta, Weights const& gamma, Weights const& wordEmb, Weights const& posEmb,
Weights const& tokEmb)
: EmbLayerNormVarSeqlenPluginLegacyBase(name, type, beta, gamma, wordEmb, posEmb, tokEmb, type)
{
}
EmbLayerNormVarSeqlenPluginLegacyMTron::EmbLayerNormVarSeqlenPluginLegacyMTron(
std::string const& name, void const* data, size_t length)
: EmbLayerNormVarSeqlenPluginLegacyBase(name, data, length)
{
BERT_DEBUG_MSG("EmbLayerNormVarSeqlenPluginLegacyMTron deserialize");
}
// IPluginV2DynamicExt Methods
IPluginV2DynamicExt* EmbLayerNormVarSeqlenPluginLegacyHFace::clone() const noexcept
{
try
{
BERT_DEBUG_MSG("EmbLayerNormVarSeqlenPluginLegacyHFace clone");
auto p = std::make_unique<EmbLayerNormVarSeqlenPluginLegacyHFace>(
mLayerName, mType, mBeta, mGamma, mWordEmb, mPosEmb, mTokEmb);
p->setPluginNamespace(mNamespace.c_str());
return p.release();
}
catch (std::exception const& e)
{
caughtError(e);
}
return nullptr;
}
IPluginV2DynamicExt* EmbLayerNormVarSeqlenPluginLegacyMTron::clone() const noexcept
{
try
{
BERT_DEBUG_MSG("EmbLayerNormVarSeqlenPluginLegacyMTron clone");
auto p = std::make_unique<EmbLayerNormVarSeqlenPluginLegacyMTron>(
mLayerName, mType, mBeta, mGamma, mWordEmb, mPosEmb, mTokEmb);
p->setPluginNamespace(mNamespace.c_str());
return p.release();
}
catch (std::exception const& e)
{
caughtError(e);
}
return nullptr;
}
DimsExprs EmbLayerNormVarSeqlenPluginLegacyHFace::getOutputDimensions(
int32_t outputIndex, DimsExprs const* inputs, int32_t nbInputs, IExprBuilder& exprBuilder) noexcept
{
// Input should be input ids and token ids and cumulative seqlens
// Output should be the embeddings tensor and mask indices
PLUGIN_ASSERT(nbInputs == 4);
PLUGIN_ASSERT(inputs[0].nbDims == 1); // sum of all s
PLUGIN_ASSERT(inputs[0].nbDims == inputs[1].nbDims);
PLUGIN_ASSERT(inputs[2].nbDims == 1); // B+1
PLUGIN_ASSERT(outputIndex == 0 || outputIndex == 1);
if (outputIndex == 0)
{
DimsExprs ret;
ret.nbDims = 4;
ret.d[0] = inputs[0].d[0];
ret.d[1] = exprBuilder.constant(mLd);
ret.d[2] = exprBuilder.constant(1);
ret.d[3] = exprBuilder.constant(1);
return ret;
}
// Return empty tensor since this is dummy output, we do not delete it for backward compatibility.
DimsExprs ret{};
ret.nbDims = 0;
return ret;
}
DimsExprs EmbLayerNormVarSeqlenPluginLegacyMTron::getOutputDimensions(
int32_t outputIndex, DimsExprs const* inputs, int32_t nbInputs, IExprBuilder& exprBuilder) noexcept
{
// Input should be input ids and token ids and cumulative seqlens
// Output should be the embeddings tensor and mask indices
PLUGIN_ASSERT(nbInputs == 4);
PLUGIN_ASSERT(inputs[0].nbDims == 1); // sum of all s
PLUGIN_ASSERT(inputs[0].nbDims == inputs[1].nbDims);
PLUGIN_ASSERT(inputs[2].nbDims == 1); // B+1
PLUGIN_ASSERT(outputIndex == 0 || outputIndex == 1);
DimsExprs ret;
ret.nbDims = 4;
ret.d[0] = inputs[0].d[0];
ret.d[1] = exprBuilder.constant(mLd);
ret.d[2] = exprBuilder.constant(1);
ret.d[3] = exprBuilder.constant(1);
return ret;
}
bool EmbLayerNormVarSeqlenPluginLegacyBase::supportsFormatCombination(
int32_t pos, PluginTensorDesc const* inOut, int32_t nbInputs, int32_t nbOutputs) noexcept
{
// The four inputs to this plugin input_ids, segment_ids, cu_seqlens and a dummy input with the
// size of the max seq length in that order
PLUGIN_ASSERT(nbInputs == 4);
// The two outputs of the plugin are embedding and the mask
PLUGIN_ASSERT(nbOutputs == 2);
PluginTensorDesc const& desc = inOut[pos];
if (desc.format != TensorFormat::kLINEAR)
{
return false;
}
if (pos == 0 || pos == 2) // input_ids and cu_seqlens
{
return desc.type == DataType::kINT32 && desc.dims.nbDims == 1;
}
PluginTensorDesc const& prev = inOut[pos - 1];
if (pos == 1) // segment ids: check it's the same as input_ids
{
return desc.type == DataType::kINT32 && desc.dims.nbDims == 1 && desc.dims.d[0] == prev.dims.d[0];
}
if (pos == 3)
{
return desc.dims.nbDims == 1;
}
// embedded sequence
if (pos == nbInputs)
{
return desc.type == mType && desc.dims.nbDims == 4 && desc.dims.d[0] == inOut[0].dims.d[0]
&& desc.dims.d[2] == 1 && desc.dims.d[3] == 1;
}
// mask
return desc.type == mMaskType;
}
void checkConfigurationInputs(DynamicPluginTensorDesc const* inputs, int32_t nbInputs,
DynamicPluginTensorDesc const* outputs, int32_t nbOutputs) noexcept
{
// Validate input arguments
PLUGIN_ASSERT(nbInputs == 4);
PLUGIN_ASSERT(nbOutputs == 2);
PLUGIN_ASSERT(inputs[0].desc.dims.nbDims == 1);
PLUGIN_ASSERT(inputs[1].desc.dims.nbDims == 1);
PLUGIN_ASSERT(inputs[1].desc.dims.d[0] == inputs[0].desc.dims.d[0]);
PLUGIN_ASSERT(inputs[2].desc.dims.nbDims == 1);
PLUGIN_ASSERT(outputs[0].desc.dims.nbDims == 4);
PLUGIN_ASSERT(static_cast<size_t>(outputs[0].desc.dims.d[0]) == static_cast<size_t>(inputs[0].desc.dims.d[0]));
PLUGIN_ASSERT(outputs[0].desc.dims.d[2] == 1);
PLUGIN_ASSERT(outputs[0].desc.dims.d[3] == 1);
PLUGIN_ASSERT(inputs[0].desc.type == DataType::kINT32);
PLUGIN_ASSERT(inputs[1].desc.type == DataType::kINT32);
PLUGIN_ASSERT(inputs[2].desc.type == DataType::kINT32);
}
void EmbLayerNormVarSeqlenPluginLegacyHFace::configurePlugin(DynamicPluginTensorDesc const* inputs, int32_t nbInputs,
DynamicPluginTensorDesc const* outputs, int32_t nbOutputs) noexcept
{
BERT_DEBUG_MSG("EmbLayerNormVarSeqlenPluginLegacyHFace configurePlugin");
checkConfigurationInputs(inputs, nbInputs, outputs, nbOutputs);
PLUGIN_ASSERT(static_cast<size_t>(outputs[0].desc.dims.d[1]) == static_cast<size_t>(mLd));
// check mask
PLUGIN_ASSERT(outputs[1].desc.dims.nbDims == 0);
PLUGIN_ASSERT(outputs[0].desc.type == mType);
PLUGIN_ASSERT(outputs[1].desc.type == mMaskType);
}
void EmbLayerNormVarSeqlenPluginLegacyMTron::configurePlugin(DynamicPluginTensorDesc const* inputs, int32_t nbInputs,
DynamicPluginTensorDesc const* outputs, int32_t nbOutputs) noexcept
{
BERT_DEBUG_MSG("EmbLayerNormVarSeqlenPluginLegacyMTron configurePlugin");
checkConfigurationInputs(inputs, nbInputs, outputs, nbOutputs);
PLUGIN_ASSERT(static_cast<size_t>(outputs[0].desc.dims.d[1]) == static_cast<size_t>(mLd));
PLUGIN_ASSERT(outputs[1].desc.dims.nbDims == 4);
PLUGIN_ASSERT(static_cast<size_t>(outputs[1].desc.dims.d[0]) == static_cast<size_t>(inputs[0].desc.dims.d[0]));
PLUGIN_ASSERT(static_cast<size_t>(outputs[1].desc.dims.d[1]) == static_cast<size_t>(mLd));
PLUGIN_ASSERT(outputs[1].desc.dims.d[2] == 1);
PLUGIN_ASSERT(outputs[1].desc.dims.d[3] == 1);
PLUGIN_ASSERT(outputs[0].desc.type == mType);
PLUGIN_ASSERT(outputs[1].desc.type == mMaskType);
}
size_t EmbLayerNormVarSeqlenPluginLegacyBase::getWorkspaceSize(
PluginTensorDesc const* inputs, int32_t nbInputs, PluginTensorDesc const* outputs, int32_t nbOutputs) const noexcept
{
return 0;
}
int32_t EmbLayerNormVarSeqlenPluginLegacyHFace::enqueue(PluginTensorDesc const* inputDesc,
PluginTensorDesc const* /* outputDesc */, void const* const* inputs, void* const* outputs, void* /* workspace */,
cudaStream_t stream) noexcept
{
try
{
PLUGIN_VALIDATE(inputDesc != nullptr && inputs != nullptr && outputs != nullptr);
int32_t const batchSize = inputDesc[2].dims.d[0] - 1;
// read out the maximum sequence length from the dummy input
int32_t const maxSeqlen = inputDesc[3].dims.d[0];
// There are four versions of the kernel which are optimized for sequence lengths 384, 256, 192 and 128.
// Find the closest sequence length bigger than the max seq length in this batch.
int32_t S = 384;
if (maxSeqlen <= 128)
{
S = 128;
}
else if (maxSeqlen <= 192)
{
S = 192;
}
else if (maxSeqlen <= 256)
{
S = 256;
}
// Our plugin outputs only one tensor
auto const inputIds = static_cast<int32_t const*>(inputs[0]);
auto const segmentIds = static_cast<int32_t const*>(inputs[1]);
int32_t const* cuSeqlens = static_cast<int32_t const*>(inputs[2]);
float const* beta = mBetaDev.get();
float const* gamma = mGammaDev.get();
if (mType == DataType::kFLOAT)
{
auto output = static_cast<float*>(outputs[0]);
auto const wordEmb = static_cast<float const*>(mWordEmbDev.get());
auto const tokEmb = static_cast<float const*>(mTokEmbDev.get());
auto const posEmb = static_cast<float const*>(mPosEmbDev.get());
return embSkipLayerNormHFace<float>(stream, static_cast<int32_t>(mLd), batchSize, S, inputIds, segmentIds,
cuSeqlens, beta, gamma, wordEmb, posEmb, tokEmb, mWordVocabSize, mTokVocabSize, output);
}
if (mType == DataType::kHALF)
{
auto output = static_cast<half*>(outputs[0]);
auto const wordEmb = static_cast<half const*>(mWordEmbDev.get());
auto const tokEmb = static_cast<half const*>(mTokEmbDev.get());
auto const posEmb = static_cast<half const*>(mPosEmbDev.get());
return embSkipLayerNormHFace<half>(stream, static_cast<int32_t>(mLd), batchSize, S, inputIds, segmentIds,
cuSeqlens, beta, gamma, wordEmb, posEmb, tokEmb, mWordVocabSize, mTokVocabSize, output);
}
else
{
gLogError << "Unsupported type error, expected [kHALF,kFLOAT], but received " << static_cast<int32_t>(mType)
<< std::endl;
return STATUS_NOT_SUPPORTED;
}
return STATUS_SUCCESS;
}
catch (std::exception const& e)
{
caughtError(e);
}
return STATUS_FAILURE;
}
int32_t EmbLayerNormVarSeqlenPluginLegacyMTron::enqueue(PluginTensorDesc const* inputDesc,
PluginTensorDesc const* /* outputDesc */, void const* const* inputs, void* const* outputs, void* /* workspace */,
cudaStream_t stream) noexcept
{
try
{
PLUGIN_VALIDATE(inputDesc != nullptr && inputs != nullptr && outputs != nullptr);
int32_t const batchSize = inputDesc[2].dims.d[0] - 1;
// read out the maximum sequence length from the dummy input
int32_t const maxSeqlen = inputDesc[3].dims.d[0];
// There are four versions of the kernel which are optimized for sequence lengths 384, 256, 192 and 128.
// Find the closest sequence length bigger than the max seq length in this batch.
int32_t S = 384;
if (maxSeqlen <= 128)
{
S = 128;
}
else if (maxSeqlen <= 192)
{
S = 192;
}
else if (maxSeqlen <= 256)
{
S = 256;
}
// Our plugin outputs only one tensor
auto const inputIds = static_cast<int32_t const*>(inputs[0]);
auto const segmentIds = static_cast<int32_t const*>(inputs[1]);
int32_t const* cuSeqlens = static_cast<int32_t const*>(inputs[2]);
float const* beta = mBetaDev.get();
float const* gamma = mGammaDev.get();
if (mType == DataType::kFLOAT)
{
auto output = static_cast<float*>(outputs[0]);
auto skip = static_cast<float*>(outputs[1]);
auto const wordEmb = static_cast<float const*>(mWordEmbDev.get());
auto const tokEmb = static_cast<float const*>(mTokEmbDev.get());
auto const posEmb = static_cast<float const*>(mPosEmbDev.get());
return embSkipLayerNormMTron<float>(stream, static_cast<int32_t>(mLd), batchSize, S, inputIds, segmentIds,
cuSeqlens, beta, gamma, wordEmb, posEmb, tokEmb, mWordVocabSize, mTokVocabSize, output, skip);
}
if (mType == DataType::kHALF)
{
auto output = static_cast<half*>(outputs[0]);
auto skip = static_cast<half*>(outputs[1]);
auto const wordEmb = static_cast<half const*>(mWordEmbDev.get());
auto const tokEmb = static_cast<half const*>(mTokEmbDev.get());
auto const posEmb = static_cast<half const*>(mPosEmbDev.get());
return embSkipLayerNormMTron<half>(stream, static_cast<int32_t>(mLd), batchSize, S, inputIds, segmentIds,
cuSeqlens, beta, gamma, wordEmb, posEmb, tokEmb, mWordVocabSize, mTokVocabSize, output, skip);
}
else
{
gLogError << "Unsupported type error, expected [kHALF,kFLOAT], but received " << static_cast<int32_t>(mType)
<< std::endl;
return STATUS_NOT_SUPPORTED;
}
return STATUS_SUCCESS;
}
catch (std::exception const& e)
{
caughtError(e);
}
return STATUS_FAILURE;
}
// IPluginV2Ext Methods
DataType EmbLayerNormVarSeqlenPluginLegacyBase::getOutputDataType(
int32_t index, DataType const* inputTypes, int32_t nbInputs) const noexcept
{
PLUGIN_ASSERT(index == 0 || index == 1);
PLUGIN_ASSERT(mType == DataType::kHALF || mType == DataType::kFLOAT);
return index == 0 ? mType : mMaskType;
}
// IPluginV2 Methods
char const* EmbLayerNormVarSeqlenPluginLegacyBase::getPluginType() const noexcept
{
return kEMB_LAYER_NORM_VAR_SEQLEN_NAME;
}
char const* EmbLayerNormVarSeqlenPluginLegacyHFace::getPluginVersion() const noexcept
{
return kEMB_LAYER_NORM_VAR_SEQLEN_VERSION_HFACE;
}
char const* EmbLayerNormVarSeqlenPluginLegacyMTron::getPluginVersion() const noexcept
{
return kEMB_LAYER_NORM_VAR_SEQLEN_VERSION_MTRON;
}
int32_t EmbLayerNormVarSeqlenPluginLegacyBase::getNbOutputs() const noexcept
{
return 2;
}
int32_t EmbLayerNormVarSeqlenPluginLegacyHFace::initialize() noexcept
{
BERT_DEBUG_MSG("EmbLayerNormVarSeqlenPluginLegacyHFace initialize");
return 0;
}
int32_t EmbLayerNormVarSeqlenPluginLegacyMTron::initialize() noexcept
{
BERT_DEBUG_MSG("EmbLayerNormVarSeqlenPluginLegacyMTron initialize");
return 0;
}
void EmbLayerNormVarSeqlenPluginLegacyHFace::terminate() noexcept
{
BERT_DEBUG_MSG("EmbLayerNormVarSeqlenPluginLegacyHFace terminate");
}
void EmbLayerNormVarSeqlenPluginLegacyMTron::terminate() noexcept
{
BERT_DEBUG_MSG("EmbLayerNormVarSeqlenPluginLegacyMTron terminate");
}
size_t EmbLayerNormVarSeqlenPluginLegacyBase::getSerializationSize() const noexcept
{
size_t const wordSize = getElementSize(mType);
return 2 * sizeof(float) * mLd // beta + gamma
+ sizeof(mType) //
+ sizeof(mLd) //
+ sizeof(mWordVocabSize) //
+ sizeof(mPosVocabSize) //
+ sizeof(mTokVocabSize) //
+ wordSize * mLd * mWordVocabSize // word emb
+ wordSize * mLd * mPosVocabSize // pos emb
+ wordSize * mLd * mTokVocabSize // tok emb
+ sizeof(mMaskType) // mask type
;
}
void EmbLayerNormVarSeqlenPluginLegacyBase::serialize(void* buffer) const noexcept
{
serialize_value(&buffer, mType);
serialize_value(&buffer, mLd);
serialize_value(&buffer, mWordVocabSize);
serialize_value(&buffer, mPosVocabSize);
serialize_value(&buffer, mTokVocabSize);
serialize_value(&buffer, mMaskType);
char* d = static_cast<char*>(buffer);
size_t const wordSize = getElementSize(mType);
serFromDev(d, mBetaDev.get(), mLd);
serFromDev(d, mGammaDev.get(), mLd);
serFromDev(d, static_cast<char*>(mWordEmbDev.get()), mLd * mWordVocabSize * wordSize);
serFromDev(d, static_cast<char*>(mPosEmbDev.get()), mLd * mPosVocabSize * wordSize);
serFromDev(d, static_cast<char*>(mTokEmbDev.get()), mLd * mTokVocabSize * wordSize);
}
void EmbLayerNormVarSeqlenPluginLegacyBase::destroy() noexcept
{
// This gets called when the network containing plugin is destroyed
mGammaDev.reset(nullptr);
mBetaDev.reset(nullptr);
mWordEmbDev.reset(nullptr);
mPosEmbDev.reset(nullptr);
mTokEmbDev.reset(nullptr);
delete this;
}
void EmbLayerNormVarSeqlenPluginLegacyHFace::destroy() noexcept
{
BERT_DEBUG_MSG("EmbLayerNormVarSeqlenPluginLegacyHFace destroy");
EmbLayerNormVarSeqlenPluginLegacyBase::destroy();
}
void EmbLayerNormVarSeqlenPluginLegacyMTron::destroy() noexcept
{
BERT_DEBUG_MSG("EmbLayerNormVarSeqlenPluginLegacyMTron destroy");
EmbLayerNormVarSeqlenPluginLegacyBase::destroy();
}
void EmbLayerNormVarSeqlenPluginLegacyBase::setPluginNamespace(char const* libNamespace) noexcept
{
try
{
mNamespace = libNamespace;
}
catch (std::exception const& e)
{
caughtError(e);
}
}
char const* EmbLayerNormVarSeqlenPluginLegacyBase::getPluginNamespace() const noexcept
{
return mNamespace.c_str();
}
///////////////////////
EmbLayerNormVarSeqlenPluginLegacyBaseCreator::EmbLayerNormVarSeqlenPluginLegacyBaseCreator()
{
mPluginAttributes.clear();
mPluginAttributes.emplace_back(PluginField("bert_embeddings_layernorm_beta"));
mPluginAttributes.emplace_back(PluginField("bert_embeddings_layernorm_gamma"));
mPluginAttributes.emplace_back(PluginField("bert_embeddings_word_embeddings"));
mPluginAttributes.emplace_back(PluginField("bert_embeddings_token_type_embeddings"));
mPluginAttributes.emplace_back(PluginField("bert_embeddings_position_embeddings"));
mPluginAttributes.emplace_back(PluginField("output_fp16"));
mFC.nbFields = mPluginAttributes.size();
mFC.fields = mPluginAttributes.data();
}
char const* EmbLayerNormVarSeqlenPluginLegacyBaseCreator::getPluginName() const noexcept
{
return kEMB_LAYER_NORM_VAR_SEQLEN_NAME;
}
char const* EmbLayerNormVarSeqlenPluginLegacyHFaceCreator::getPluginVersion() const noexcept
{
return kEMB_LAYER_NORM_VAR_SEQLEN_VERSION_HFACE;
}
char const* EmbLayerNormVarSeqlenPluginLegacyMTronCreator::getPluginVersion() const noexcept
{
return kEMB_LAYER_NORM_VAR_SEQLEN_VERSION_MTRON;
}
PluginFieldCollection const* EmbLayerNormVarSeqlenPluginLegacyBaseCreator::getFieldNames() noexcept
{
return &mFC;
}
bool initializeFields(char const* name, PluginFieldCollection const* fc, Weights& beta, Weights& gamma,
Weights& word_emb, Weights& pos_emb, Weights& tok_emb)
{
bool output_fp16 = false;
std::set<std::string> const requiredAttributes{
"bert_embeddings_layernorm_beta",
"bert_embeddings_layernorm_gamma",
"bert_embeddings_word_embeddings",
"bert_embeddings_token_type_embeddings",
"bert_embeddings_position_embeddings",
};
plugin::validateRequiredAttributesExist(requiredAttributes, fc);
for (int32_t i = 0; i < fc->nbFields; i++)
{
std::string_view const field_name = fc->fields[i].name;
if (field_name == "bert_embeddings_layernorm_beta"sv)
{
BERT_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 == "bert_embeddings_layernorm_gamma"sv)
{
BERT_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 == "bert_embeddings_word_embeddings"sv)
{
BERT_DEBUG_MSG("Building bert_embeddings_word_embeddings...");
word_emb.values = fc->fields[i].data;
word_emb.count = fc->fields[i].length;
word_emb.type = fieldTypeToDataType(fc->fields[i].type);
}
if (field_name == "bert_embeddings_token_type_embeddings"sv)
{
BERT_DEBUG_MSG("Building bert_embeddings_token_type_embeddings...");
tok_emb.values = fc->fields[i].data;
tok_emb.count = fc->fields[i].length;
tok_emb.type = fieldTypeToDataType(fc->fields[i].type);
}
if (field_name == "bert_embeddings_position_embeddings"sv)
{
BERT_DEBUG_MSG("Building bert_embeddings_position_embeddings...");
pos_emb.values = fc->fields[i].data;
pos_emb.count = fc->fields[i].length;
pos_emb.type = fieldTypeToDataType(fc->fields[i].type);
}
if (field_name == "output_fp16"sv)
{
BERT_DEBUG_MSG("Building output_fp16...");
PLUGIN_VALIDATE(fc->fields[i].type == PluginFieldType::kINT32);
output_fp16 = static_cast<int32_t const*>(fc->fields[i].data)[0] != 0;
}
}
return output_fp16;
}
IPluginV2* EmbLayerNormVarSeqlenPluginLegacyHFaceCreator::createPlugin(
char const* name, PluginFieldCollection const* fc) noexcept
{
try
{
BERT_DEBUG_MSG("EmbLayerNormVarSeqlenHFace createPlugin");
Weights beta{}; // required attribute: validateRequiredAttributesExist() call in initializeFields() will verify
// existence
Weights gamma{}; // required attribute: validateRequiredAttributesExist() call in initializeFields() will verify
// existence
Weights word_emb{}; // required attribute: validateRequiredAttributesExist() call in initializeFields() will
// verify existence
Weights pos_emb{}; // required attribute: validateRequiredAttributesExist() call in initializeFields() will
// verify existence
Weights tok_emb{}; // required attribute: validateRequiredAttributesExist() call in initializeFields() will
// verify existence
bool output_fp16 = initializeFields(name, fc, beta, gamma, word_emb, pos_emb, tok_emb);
BERT_DEBUG_MSG("Building the Plugin...");
auto p = std::make_unique<EmbLayerNormVarSeqlenPluginLegacyHFace>(
name, output_fp16 ? DataType::kHALF : DataType::kFLOAT, beta, gamma, word_emb, pos_emb, tok_emb);
return p.release();
}
catch (std::exception const& e)
{
caughtError(e);
}
return nullptr;
}
IPluginV2* EmbLayerNormVarSeqlenPluginLegacyMTronCreator::createPlugin(
char const* name, PluginFieldCollection const* fc) noexcept
{
try
{
BERT_DEBUG_MSG("EmbLayerNormVarSeqlenMTron createPlugin");
Weights beta{}; // required attribute: validateRequiredAttributesExist() call in initializeFields() will verify
// existence
Weights gamma{}; // required attribute: validateRequiredAttributesExist() call in initializeFields() will verify
// existence
Weights word_emb{}; // required attribute: validateRequiredAttributesExist() call in initializeFields() will
// verify existence
Weights pos_emb{}; // required attribute: validateRequiredAttributesExist() call in initializeFields() will
// verify existence
Weights tok_emb{}; // required attribute: validateRequiredAttributesExist() call in initializeFields() will
// verify existence
bool output_fp16 = initializeFields(name, fc, beta, gamma, word_emb, pos_emb, tok_emb);
BERT_DEBUG_MSG("Building the Plugin...");
auto p = std::make_unique<EmbLayerNormVarSeqlenPluginLegacyMTron>(
name, output_fp16 ? DataType::kHALF : DataType::kFLOAT, beta, gamma, word_emb, pos_emb, tok_emb);
return p.release();
}
catch (std::exception const& e)
{
caughtError(e);
}
return nullptr;
}
IPluginV2* EmbLayerNormVarSeqlenPluginLegacyHFaceCreator::deserializePlugin(
char const* name, void const* serialData, size_t serialLength) noexcept
{
try
{
// This object will be deleted when the network is destroyed, which will
// call EmbLayerNormVarSeqlen::destroy()
return new EmbLayerNormVarSeqlenPluginLegacyHFace(name, serialData, serialLength);
}
catch (std::exception const& e)
{
caughtError(e);
}
return nullptr;
}
IPluginV2* EmbLayerNormVarSeqlenPluginLegacyMTronCreator::deserializePlugin(
char const* name, void const* serialData, size_t serialLength) noexcept
{
try
{
// This object will be deleted when the network is destroyed, which will
// call EmbLayerNormVarSeqlen::destroy()
return new EmbLayerNormVarSeqlenPluginLegacyMTron(name, serialData, serialLength);
}
catch (std::exception const& e)
{
caughtError(e);
}
return nullptr;
}
void EmbLayerNormVarSeqlenPluginLegacyBaseCreator::setPluginNamespace(char const* libNamespace) noexcept
{
try
{
mNamespace = libNamespace;
}
catch (std::exception const& e)
{
caughtError(e);
}
}
char const* EmbLayerNormVarSeqlenPluginLegacyBaseCreator::getPluginNamespace() const noexcept
{
return mNamespace.c_str();
}
@@ -0,0 +1,198 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 1993-2025 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.
*/
#ifndef TRT_EMB_LAYER_NORM_VARSEQ_PLUGIN_LEGACY_H
#define TRT_EMB_LAYER_NORM_VARSEQ_PLUGIN_LEGACY_H
#include <cuda.h>
#include "NvInferPlugin.h"
#include "NvInferRuntime.h"
#include "common/bertCommon.h"
#include <string>
#include <vector>
namespace nvinfer1
{
namespace plugin
{
namespace bert
{
template <typename T>
int32_t embSkipLayerNormHFace(cudaStream_t stream, int32_t ld, int32_t B, int32_t S, int32_t const* inputIds,
int32_t const* tokenIds, int32_t const* cuSeqlens, float const* beta, float const* gamma, T const* wordEmb,
T const* posEmb, T const* tokEmb, int32_t const wordSize, int32_t const tokSize, T* output);
template <typename T>
int32_t embSkipLayerNormMTron(cudaStream_t stream, int32_t ld, int32_t B, int32_t S, int32_t const* inputIds,
int32_t const* tokenIds, int32_t const* cuSeqlens, float const* beta, float const* gamma, T const* wordEmb,
T const* posEmb, T const* tokEmb, int32_t const wordSize, int32_t const tokSize, T* output, T* skip);
class EmbLayerNormVarSeqlenPluginLegacyBase : public nvinfer1::IPluginV2DynamicExt
{
public:
EmbLayerNormVarSeqlenPluginLegacyBase(std::string const& name, DataType type, Weights const& beta,
Weights const& gamma, Weights const& word_emb, Weights const& pos_emb, Weights const& tok_emb,
DataType maskType);
EmbLayerNormVarSeqlenPluginLegacyBase(std::string const& name, void const* data, size_t length);
// It doesn't make sense to make EmbLayerNormVarSeqlenPluginLegacy without arguments, so we
// delete default constructor.
EmbLayerNormVarSeqlenPluginLegacyBase() = 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;
bert::cuda_unique_ptr<float> mGammaDev;
bert::cuda_unique_ptr<float> mBetaDev;
bert::cuda_unique_ptr<void> mWordEmbDev;
bert::cuda_unique_ptr<void> mTokEmbDev;
bert::cuda_unique_ptr<void> mPosEmbDev;
size_t mLd; // leading dim = hidden size
size_t mWordVocabSize;
size_t mPosVocabSize;
size_t mTokVocabSize;
bert::WeightsWithOwnership mBeta;
bert::WeightsWithOwnership mGamma;
bert::WeightsWithOwnership mWordEmb;
bert::WeightsWithOwnership mTokEmb;
bert::WeightsWithOwnership mPosEmb;
DataType mType{};
DataType mMaskType{};
};
class EmbLayerNormVarSeqlenPluginLegacyHFace : public EmbLayerNormVarSeqlenPluginLegacyBase
{
public:
EmbLayerNormVarSeqlenPluginLegacyHFace(std::string const& name, nvinfer1::DataType const type,
nvinfer1::Weights const& beta, nvinfer1::Weights const& gamma, nvinfer1::Weights const& word_emb,
nvinfer1::Weights const& pos_emb, nvinfer1::Weights const& tok_emb);
EmbLayerNormVarSeqlenPluginLegacyHFace(std::string const& name, void const* data, size_t length);
// It doesn't make sense to make EmbLayerNormVarSeqlenPluginLegacy without arguments, so we
// delete default constructor.
EmbLayerNormVarSeqlenPluginLegacyHFace() = delete;
// IPluginV2DynamicExt Methods
nvinfer1::IPluginV2DynamicExt* clone() const noexcept override;
nvinfer1::DimsExprs getOutputDimensions(int32_t outputIndex, nvinfer1::DimsExprs const* 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 EmbLayerNormVarSeqlenPluginLegacyMTron : public EmbLayerNormVarSeqlenPluginLegacyBase
{
public:
EmbLayerNormVarSeqlenPluginLegacyMTron(std::string const& name, nvinfer1::DataType const type,
nvinfer1::Weights const& beta, nvinfer1::Weights const& gamma, nvinfer1::Weights const& word_emb,
nvinfer1::Weights const& pos_emb, nvinfer1::Weights const& tok_emb);
EmbLayerNormVarSeqlenPluginLegacyMTron(std::string const& name, void const* data, size_t length);
// It doesn't make sense to make EmbLayerNormVarSeqlenPluginLegacy without arguments, so we
// delete default constructor.
EmbLayerNormVarSeqlenPluginLegacyMTron() = delete;
// IPluginV2DynamicExt Methods
nvinfer1::IPluginV2DynamicExt* clone() const noexcept override;
nvinfer1::DimsExprs getOutputDimensions(int32_t outputIndex, nvinfer1::DimsExprs const* 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 EmbLayerNormVarSeqlenPluginLegacyBaseCreator : public nvinfer1::IPluginCreator
{
public:
EmbLayerNormVarSeqlenPluginLegacyBaseCreator();
char const* getPluginName() const noexcept override;
nvinfer1::PluginFieldCollection const* getFieldNames() noexcept override;
void setPluginNamespace(char const* pluginNamespace) noexcept override;
char const* getPluginNamespace() const noexcept override;
protected:
nvinfer1::PluginFieldCollection mFC;
std::vector<nvinfer1::PluginField> mPluginAttributes;
std::string mNamespace;
};
class EmbLayerNormVarSeqlenPluginLegacyHFaceCreator : public EmbLayerNormVarSeqlenPluginLegacyBaseCreator
{
public:
nvinfer1::IPluginV2* createPlugin(char const* name, nvinfer1::PluginFieldCollection const* fc) noexcept override;
char const* getPluginVersion() const noexcept override;
nvinfer1::IPluginV2* deserializePlugin(
char const* name, void const* serialData, size_t serialLength) noexcept override;
};
class EmbLayerNormVarSeqlenPluginLegacyMTronCreator : public EmbLayerNormVarSeqlenPluginLegacyBaseCreator
{
public:
nvinfer1::IPluginV2* createPlugin(char const* name, nvinfer1::PluginFieldCollection const* fc) noexcept override;
char const* getPluginVersion() const noexcept override;
nvinfer1::IPluginV2* deserializePlugin(
char const* name, void const* serialData, size_t serialLength) noexcept override;
};
} // namespace bert
} // namespace plugin
} // namespace nvinfer1
#endif // TRT_EMB_LAYER_NORM_VARSEQ_PLUGIN_LEGACY_H