chore: import upstream snapshot with attribution
Docker Image CI / build-ubuntu2004 (push) Has been cancelled

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
+31
View File
@@ -0,0 +1,31 @@
#
# 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(
skipLayerNormInt8InterleavedKernelHFace.cu
skipLayerNormInt8InterleavedKernelMTron.cu
skipLayerNormInt8InterleavedPlugin.cpp
skipLayerNormInt8InterleavedPlugin.h
skipLayerNormInt8InterleavedPluginLegacy.cpp
skipLayerNormInt8InterleavedPluginLegacy.h
skipLayerNormKernel.cu
skipLayerNormPlugin.cpp
skipLayerNormPlugin.h
skipLayerNormPluginLegacy.cpp
skipLayerNormPluginLegacy.h
)
@@ -0,0 +1,247 @@
#
# 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: CustomSkipLayerNormPluginDynamic
interface: "IPluginV3"
versions:
"5": # SkipLayerNormPluginV3
inputs:
- input
- skip
outputs:
- output
input_dims:
input: 5
skip: 5
input_dim_constraints:
- "input_2 == bias_2"
- "skip_0 == input_0"
- "skip_1 == input_1"
- "skip_2 == input_2"
input_dim_range:
input:
min: "=1, =1, =1, =1, =1"
max: "=pinf, =pinf, =pinf, =1, =1"
skip:
min: "=1, =1, =1, =1, =1"
max: "=pinf, =pinf, =pinf, =1, =1"
supported_input_types:
- combination1:
input: float32
skip: float32
- combination2:
input: float16
skip: float16
output_dims:
output: "input_0, input_1, input_2, input_3, input_4"
attributes:
- type_id
- ld
- beta
- gamma
- bias
attribute_types:
type_id: int32
ld: int32
beta: float32
gamma: float32
bias: float32
attribute_dims:
type_id: 1
ld: 1
beta: 3
gamma: 3
bias: 3
attribute_dim_range:
type_id:
min: "=1"
max: "=1"
ld:
min: "=1"
max: "=1"
beta:
min: "=1, =1, =1"
max: "=1, =1, =pinf"
gamma:
min: "=1, =1, =1"
max: "=1, =1, =pinf"
bias:
min: "=1, =1, =1"
max: "=1, =1, =pinf"
attribute_options:
type_id:
- 0
- 1
- 2
ld:
min: "=1"
max: "=pinf"
beta:
min: "=ninf"
max: "=pinf"
gamma:
min: "=ninf"
max: "=pinf"
bias:
min: "=ninf"
max: "=pinf"
attributes_required:
- type_id
- ld
- beta
- gamma
golden_reference_script: "plugin/CustomSkipLayerNormPluginDynamic_PluginReference.py"
abs_tol: 1e-2
rel_tol: 1e-2
configs:
config1:
input_types:
input: float32
skip: float32
attribute_options:
type_id:
value: 0
ld:
value: 128
beta:
shape: "1, 1, 128"
gamma:
shape: "1, 1, 128"
bias:
shape: "1, 1, 128"
config2:
input_types:
input: float16
skip: float16
attribute_options:
type_id:
value: 1
ld:
value: 768
beta:
shape: "1, 1, 768"
gamma:
shape: "1, 1, 768"
bias:
shape: "1, 1, 768"
"6": # SkipLayerNormVarSeqlenPluginV3
inputs:
- input
- skip
outputs:
- output
input_dims:
input: 5
skip: 5
input_dim_constraints:
- "input_2 == bias_2"
- "skip_0 == input_0"
- "skip_1 == input_1"
- "skip_2 == input_2"
input_dim_range:
input:
min: "=1, =1, =1, =1, =1"
max: "=pinf, =pinf, =pinf, =1, =1"
skip:
min: "=1, =1, =1, =1, =1"
max: "=pinf, =pinf, =pinf, =1, =1"
supported_input_types:
- combination1:
input: float32
skip: float32
- combination2:
input: float16
skip: float16
output_dims:
output: "input_0, input_1, input_2, input_3, input_4"
attributes:
- type_id
- beta
- gamma
- bias
attribute_types:
type_id: int32
beta: float32
gamma: float32
bias: float32
attribute_dims:
type_id: 1
beta: 3
gamma: 3
bias: 3
attribute_dim_range:
type_id:
min: "=1"
max: "=1"
beta:
min: "=1, =1, =1"
max: "=1, =1, =pinf"
gamma:
min: "=1, =1, =1"
max: "=1, =1, =pinf"
bias:
min: "=1, =1, =1"
max: "=1, =1, =pinf"
attribute_options:
type_id:
- 0
- 1
- 2
beta:
min: "=ninf"
max: "=pinf"
gamma:
min: "=ninf"
max: "=pinf"
bias:
min: "=ninf"
max: "=pinf"
attributes_required:
- type_id
- beta
- gamma
golden_reference_script: "plugin/CustomSkipLayerNormPluginDynamic_PluginReference.py"
abs_tol: 1e-2
rel_tol: 1e-2
configs:
config1:
input_types:
input: float32
skip: float32
attribute_options:
type_id:
value: 0
beta:
shape: "1, 1, 128"
gamma:
shape: "1, 1, 128"
bias:
shape: "1, 1, 128"
config2:
input_types:
input: float16
skip: float16
attribute_options:
type_id:
value: 1
beta:
shape: "1, 1, 768"
gamma:
shape: "1, 1, 768"
bias:
shape: "1, 1, 768"
...
+83
View File
@@ -0,0 +1,83 @@
# skipLayerNormPlugin
**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-4 of this plugin (using IPluginV2DynamicExt interface) are deprecated since TensorRT 10.4. Versions 5-8 (using IPluginV3 interface) are the recommended replacements.
Adds a residual tensor, applies layer normalization, i.e., transforms the mean and standard deviation to beta and gamma respectively.
Optionally, adds a bias vector before layer-normalization.
### Structure
The `skipLayerNormPlugin` takes two inputs; `input` and `skip`.
`input`
For V1, V2, V5, V6, input is a tensor with shape `[S, B, E, 1, 1]` where `S` is the sequence length, `B` is the batch size, `E` is the hidden size, and the last two dimensions are of size 1.
For V3 and V4, input is a tensor with shape `[1, E, S', 1]` where `S'` is the accumulated sequence length, `E` is the hidden size, and the first and last dimensions are of size 1.
`skip`
skip has the same input dimensions as the input.
The purpose of this input is to introduce skip (aka. residual) connections to previously computed tensors.
The `skipLayerNormPlugin` generates the following output:
`output`
output is a tensor with the same shape as the input.
## Parameters
`skipLayerNormPlugin` has plugin creator class `SkipLayerNormPluginDynamicCreator` and plugin class `CustomSkipLayerNormPluginDynamic`.
The parameters are defined below and consists of the following attributes:
| Type | Parameter | Version | Description
|----------|-----------------------------------------|-------------------------|-------------------------------------------------------------------
|`int` |`type_id` | 1, 2, 5, 6 |Integer encoding the DataType (0: FP32, 1: FP16, 2: INT8)
|`int` |`ld` | 1, 5 |The leading dimension of the input tensor, corresponding to the hidden size, denoted by `E` above.
|`Weights` |`beta` | 1, 2, 3, 4, 5, 6, 7, 8 |The mean to normalize to. Shape: `[1, 1, E]`
|`Weights` |`gamma` | 1, 2, 3, 4, 5, 6, 7, 8 |The standard deviation to normalize to. Shape: `[1, 1, E]`
|`Weights` |`bias` | 1, 2, 5, 6 |An optional bias vector to add before normalization. Shape: `[1, 1, E]`
## Additional resources
- [LayerNorm](https://arxiv.org/abs/1607.06450)
## 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
July 2024
Add v5, v6, v7 and v8 plugins that duplicate the behavior of v1, v3, v3 and v4 plugins respectively, but implement the `IPluginV3` interface instead of the deprecated `IPluginV2DynamicExt` interface.
February 2024
Add epsilon to avoid divide by zero.
October 2020
Add V2 plugin that supports variable sequence length.
Add v3 plugin that supports int8 interleaved 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,363 @@
/*
* 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 "NvInfer.h"
#include "common/bertCommon.h"
#include "common/common.cuh"
#include "common/cubCcclCompat.h"
#include <cassert>
#include <cstring>
#include <cuda.h>
#include <type_traits>
#include <vector>
using namespace nvinfer1;
namespace nvinfer1
{
namespace plugin
{
namespace bert
{
inline __device__ void resAdd(
float (&hdata)[4], const uint32_t idata, const uint32_t ires, float const dqData, float const dqRes)
{
char4 ires4 = reinterpret_cast<char4 const&>(ires);
char4 idata4 = reinterpret_cast<char4 const&>(idata);
hdata[0] = float(idata4.x) * dqData + float(ires4.x) * dqRes;
hdata[1] = float(idata4.y) * dqData + float(ires4.y) * dqRes;
hdata[2] = float(idata4.z) * dqData + float(ires4.z) * dqRes;
hdata[3] = float(idata4.w) * dqData + float(ires4.w) * dqRes;
}
template <int32_t tWARPS, int32_t tHEADS, int32_t tTHREADS_PER_ROW>
__global__ void skipln_vec32_hface(int8_t const* input, int8_t const* skip, int8_t* output, half const* beta,
half const* gamma, float const dqScaleIn, float const dqScaleSkip, float const qScale, int32_t const total)
{
// clang-format off
enum { kHEAD_SIZE = 64 };
enum { kBYTES_PER_LDG = 16 };
enum { kTHREADS_PER_CTA = tWARPS * 32 };
enum { kROWS_PER_LDG = kTHREADS_PER_CTA / tTHREADS_PER_ROW };
enum { kVECS_PER_CTA = tTHREADS_PER_ROW / 2 };
enum { kPARAM_BYTES = tHEADS * kHEAD_SIZE * 2 };
enum { kPARAM_LDGS = kPARAM_BYTES / (kTHREADS_PER_CTA * kBYTES_PER_LDG) };
enum { kLDGS = tHEADS * 2 / kROWS_PER_LDG };
// clang-format on
static_assert(kVECS_PER_CTA == 4, "");
static_assert(kPARAM_LDGS == 1, "");
static_assert(kROWS_PER_LDG == tHEADS, "");
static_assert(kLDGS == 2, "");
static_assert(kLDGS * kROWS_PER_LDG == tHEADS * 2, "");
static_assert(kTHREADS_PER_CTA * kBYTES_PER_LDG == kPARAM_BYTES, "");
static_assert(kPARAM_LDGS == 1, "");
extern __shared__ char smem_[];
// space for CTA-wide reduction
__shared__ half2 smemRed[kVECS_PER_CTA][tWARPS];
constexpr float rld = 1.F / (float(tHEADS) * float(kHEAD_SIZE));
int32_t const bidx = blockIdx.x;
int32_t const tidx = threadIdx.x;
int32_t const row = tidx / tTHREADS_PER_ROW;
int32_t const col = tidx % tTHREADS_PER_ROW;
int32_t const lane = tidx % 32;
int32_t const warp = tidx / 32;
bool const isWarpLead = (lane < tTHREADS_PER_ROW) && ((lane & 1) == 0);
bool const isCtaLead = (tidx < tTHREADS_PER_ROW) && ((tidx & 1) == 0);
// token position: every two threads load together the 32B at one token
// position
int32_t const pos = col / 2;
int32_t const posOffset = bidx * kVECS_PER_CTA + pos; // for token positions per block, disabling 2 threads per pos
bool const myPred = posOffset < total;
int32_t const rowStrideBytes = total * 32;
uint4 inData[kLDGS];
uint4 inSkip[kLDGS];
float hdata[kLDGS * 4][4];
int32_t const gmemOffset = row * rowStrideBytes + (bidx * tTHREADS_PER_ROW + col) * kBYTES_PER_LDG;
#pragma unroll
for (int32_t ii = 0; ii < kLDGS; ii++)
{
inData[ii] = {0, 0, 0, 0};
inSkip[ii] = {0, 0, 0, 0};
if (myPred)
{
ldg(input + gmemOffset + ii * kROWS_PER_LDG * rowStrideBytes, inData[ii]);
ldg(skip + gmemOffset + ii * kROWS_PER_LDG * rowStrideBytes, inSkip[ii]);
}
}
uint4* smemB = reinterpret_cast<uint4*>(&smem_[0]) + tidx;
uint4* smemG = reinterpret_cast<uint4*>(&smem_[kPARAM_BYTES]) + tidx;
int8_t const* betaPtr = reinterpret_cast<int8_t const*>(beta) + tidx * kBYTES_PER_LDG;
int8_t const* gammaPtr = reinterpret_cast<int8_t const*>(gamma) + tidx * kBYTES_PER_LDG;
ldg(betaPtr, *smemB);
ldg(gammaPtr, *smemG);
half* b = reinterpret_cast<half*>(&smem_[0]);
half* g = reinterpret_cast<half*>(&smem_[kPARAM_BYTES]);
#pragma unroll
for (int32_t ii = 0; ii < kLDGS; ii++)
{
resAdd(hdata[ii * 4 + 0], inData[ii].x, inSkip[ii].x, dqScaleIn, dqScaleSkip);
resAdd(hdata[ii * 4 + 1], inData[ii].y, inSkip[ii].y, dqScaleIn, dqScaleSkip);
resAdd(hdata[ii * 4 + 2], inData[ii].z, inSkip[ii].z, dqScaleIn, dqScaleSkip);
resAdd(hdata[ii * 4 + 3], inData[ii].w, inSkip[ii].w, dqScaleIn, dqScaleSkip);
}
half2 statsLocal = {0, 0};
#pragma unroll
for (int32_t ii = 0; ii < kLDGS * 4; ii++)
{
#pragma unroll
for (int32_t jj = 0; jj < 4; jj++)
{
float const tmp = hdata[ii][jj] * (rld);
statsLocal = statsLocal + __floats2half2_rn(tmp, tmp * hdata[ii][jj]);
}
}
statsLocal = statsLocal + __shfl_xor_sync(uint32_t(-1), statsLocal, 1);
__syncwarp();
if (kVECS_PER_CTA == 1)
{
statsLocal = statsLocal + __shfl_xor_sync(uint32_t(-1), statsLocal, 2);
__syncwarp();
statsLocal = statsLocal + __shfl_xor_sync(uint32_t(-1), statsLocal, 4);
__syncwarp();
}
else if (kVECS_PER_CTA == 2)
{
statsLocal = statsLocal + __shfl_xor_sync(uint32_t(-1), statsLocal, 4);
__syncwarp();
}
statsLocal = statsLocal + __shfl_xor_sync(uint32_t(-1), statsLocal, 8);
__syncwarp();
statsLocal = statsLocal + __shfl_xor_sync(uint32_t(-1), statsLocal, 16);
__syncwarp();
if (isWarpLead)
{
smemRed[pos][warp] = statsLocal;
}
__syncthreads();
if (isCtaLead)
{
for (int32_t ii = 1; ii < tWARPS; ii++)
{
statsLocal = statsLocal + smemRed[pos][ii];
}
float mu = __low2float(statsLocal);
float sos = __high2float(statsLocal);
float rsigma = rsqrtf(sos - mu * mu + std::numeric_limits<float>::epsilon());
smemRed[pos][0] = __floats2half2_rn(mu, rsigma);
}
__syncthreads();
// load params into smem: 2x Headsx32x2x2B
const float2 statsf = __half22float2(smemRed[pos][0]);
#pragma unroll
for (int32_t ii = 0; ii < kLDGS; ii++)
{
#pragma unroll
for (int32_t jj = 0; jj < 4; jj++)
{
#pragma unroll
for (int32_t kk = 0; kk < 4; kk++)
{
int32_t const paramIdx = (ii * kROWS_PER_LDG + row) * 32 + (jj * 4 + kk) + (tidx & 1) * 16;
float const bb = b[paramIdx];
float const gg = g[paramIdx];
hdata[ii * 4 + jj][kk] = gg * statsf.y * (hdata[ii * 4 + jj][kk] - statsf.x) + bb;
}
}
}
#pragma unroll
for (int32_t ii = 0; ii < kLDGS; ii++)
{
inData[ii].x = pack4(hdata[ii * 4 + 0], qScale);
inData[ii].y = pack4(hdata[ii * 4 + 1], qScale);
inData[ii].z = pack4(hdata[ii * 4 + 2], qScale);
inData[ii].w = pack4(hdata[ii * 4 + 3], qScale);
}
#pragma unroll
for (int32_t ii = 0; ii < kLDGS; ii++)
{
if (myPred)
{
stg(output + gmemOffset + ii * kROWS_PER_LDG * rowStrideBytes, inData[ii]);
}
}
// store
}
int32_t launch_large_hface(cudaStream_t stream, int32_t const ld, int32_t const total, int8_t const* input,
int8_t const* skip, half const* beta, half const* gamma, int8_t* output, float const dqScaleIn,
float const dqScaleSkip, float const qScale)
{
if (ld == 1024)
{
constexpr int32_t tWARPS = 4;
constexpr int32_t tTHREADS_PER_ROW = 8;
constexpr int32_t tHEADS = 16;
constexpr int32_t kPARAM_BYTES = tHEADS * 64 * 2 * sizeof(half);
constexpr int32_t kVECS_PER_CTA = tTHREADS_PER_ROW / 2;
int32_t const blocks = (total + kVECS_PER_CTA - 1) / kVECS_PER_CTA;
skipln_vec32_hface<tWARPS, tHEADS, tTHREADS_PER_ROW><<<blocks, tWARPS * 32, kPARAM_BYTES, stream>>>(
input, skip, output, beta, gamma, dqScaleIn, dqScaleSkip, qScale, total);
}
else if (ld == 768)
{
constexpr int32_t tWARPS = 3;
constexpr int32_t tTHREADS_PER_ROW = 8;
constexpr int32_t tHEADS = 12;
constexpr int32_t kPARAM_BYTES = tHEADS * 64 * 2 * sizeof(half);
constexpr int32_t kVECS_PER_CTA = tTHREADS_PER_ROW / 2;
int32_t const blocks = (total + kVECS_PER_CTA - 1) / kVECS_PER_CTA;
skipln_vec32_hface<tWARPS, tHEADS, tTHREADS_PER_ROW><<<blocks, tWARPS * 32, kPARAM_BYTES, stream>>>(
input, skip, output, beta, gamma, dqScaleIn, dqScaleSkip, qScale, total);
}
else
{
return STATUS_FAILURE;
}
return cudaPeekAtLastError();
}
// naive kernel that only changes the addressing seems to be faster for small
// problem sizes
template <int32_t TPB, int32_t VPT>
__global__ void skiplnDQQ_vec3(int32_t const ld, int8_t const* input, int8_t const* skip, int8_t* output,
half const* beta, half const* gamma, float const dqScaleIn, float const dqScaleSkip, float const qScale,
int32_t const total)
{
int32_t const hinner = threadIdx.x % 4;
int32_t const houter = threadIdx.x / 4;
int32_t const tidx = threadIdx.x;
int32_t const bidx = blockIdx.x;
int32_t const idx = houter * total * 32 + bidx * 32 + hinner * VPT;
// 4 * 1024 * 4 * 2 Bytes = 16KB per block
int8_t inLocal[VPT];
int8_t skipLocal[VPT];
half inLocalDQ[VPT]; // dequantized input + skip
half betaLocal[VPT];
half gammaLocal[VPT];
// load input tensors
copy<sizeof(int8_t) * VPT>(&input[idx], inLocal);
copy<sizeof(int8_t) * VPT>(&skip[idx], skipLocal);
// load parameters
copy<sizeof(half) * VPT>(&beta[tidx * VPT], betaLocal);
copy<sizeof(half) * VPT>(&gamma[tidx * VPT], gammaLocal);
half2 statsLocal = __floats2half2_rn(0.F, 0.F); // accumulator
half const rld = half(1.F) / half(ld);
#pragma unroll
for (int32_t it = 0; it < VPT; it++)
{
// DQ input and skip
float const tmpIn = inLocal[it];
float const tmpSkip = skipLocal[it];
inLocalDQ[it] = dqScaleIn * tmpIn + dqScaleSkip * tmpSkip;
half const tmp = rld * inLocalDQ[it];
half2 const tmp2 = __halves2half2(tmp, tmp * inLocalDQ[it]);
statsLocal = statsLocal + tmp2;
}
using BlockReduce = cub::BlockReduce<half2, TPB>;
__shared__ typename BlockReduce::TempStorage tempStorage;
__shared__ half mu; // mean
__shared__ half rsigma; // 1 / std.dev.
half2 const sum2 = BlockReduce(tempStorage).Reduce(statsLocal, compat::getCudaSumOp());
if (tidx == 0)
{
mu = __low2half(sum2);
rsigma = rsqrtf(__high2half(sum2) - mu * mu + std::numeric_limits<half>::epsilon());
}
__syncthreads();
static_assert(VPT % 4 == 0, "");
uint32_t outLocal[VPT / 4];
#pragma unroll
for (int32_t it = 0; it < VPT / 4; it++)
{
float const tmp0 = gammaLocal[it * 4 + 0] * (inLocalDQ[it * 4 + 0] - mu) * rsigma + betaLocal[it * 4 + 0];
float const tmp1 = gammaLocal[it * 4 + 1] * (inLocalDQ[it * 4 + 1] - mu) * rsigma + betaLocal[it * 4 + 1];
float const tmp2 = gammaLocal[it * 4 + 2] * (inLocalDQ[it * 4 + 2] - mu) * rsigma + betaLocal[it * 4 + 2];
float const tmp3 = gammaLocal[it * 4 + 3] * (inLocalDQ[it * 4 + 3] - mu) * rsigma + betaLocal[it * 4 + 3];
outLocal[it] = float4_to_char4(tmp0 * qScale, tmp1 * qScale, tmp2 * qScale, tmp3 * qScale);
}
copy<sizeof(int8_t) * VPT>(outLocal, &output[idx]);
}
int32_t launch_small_hface(cudaStream_t stream, int32_t const ld, int32_t const total, int8_t const* input,
int8_t const* skip, half const* beta, half const* gamma, int8_t* output, float const dqScaleIn,
float const dqScaleSkip, float const qScale)
{
int32_t const gridSize = total;
// we align reads with the number of parameters, i.e. 8-wide instead of 16
constexpr int32_t VPT = 16 / sizeof(half); // 8
if (ld == 768)
{
constexpr int32_t TPB = 768 / VPT;
skiplnDQQ_vec3<TPB, VPT>
<<<gridSize, TPB, 0, stream>>>(ld, input, skip, output, beta, gamma, dqScaleIn, dqScaleSkip, qScale, total);
}
else if (ld == 1024)
{
constexpr int32_t TPB = 1024 / VPT; // 128
skiplnDQQ_vec3<TPB, VPT>
<<<gridSize, TPB, 0, stream>>>(ld, input, skip, output, beta, gamma, dqScaleIn, dqScaleSkip, qScale, total);
}
else
{
std::cout << "SkipLayerNormDQQ - FATAL: unsupported hidden layer size: " << ld << std::endl;
return STATUS_FAILURE;
}
return cudaPeekAtLastError();
}
} // namespace bert
} // namespace plugin
} // namespace nvinfer1
@@ -0,0 +1,415 @@
/*
* 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 "NvInfer.h"
#include "common/bertCommon.h"
#include "common/common.cuh"
#include "common/cubCcclCompat.h"
#include <cassert>
#include <cstring>
#include <cuda.h>
#include <type_traits>
#include <vector>
using namespace nvinfer1;
namespace nvinfer1
{
namespace plugin
{
namespace bert
{
inline __device__ void res_add(
float (&hdata)[4], const uint32_t idata, const uint32_t ires, float const dqData, float const dqRes)
{
char4 ires4 = reinterpret_cast<char4 const&>(ires);
char4 idata4 = reinterpret_cast<char4 const&>(idata);
hdata[0] = float(idata4.x) * dqData + float(ires4.x) * dqRes;
hdata[1] = float(idata4.y) * dqData + float(ires4.y) * dqRes;
hdata[2] = float(idata4.z) * dqData + float(ires4.z) * dqRes;
hdata[3] = float(idata4.w) * dqData + float(ires4.w) * dqRes;
}
template <int32_t tWARPS, int32_t tHEADS, int32_t tTHREADS_PER_ROW>
__global__ void skipln_vec32_mtron(int8_t const* input, int8_t const* skip, int8_t* output, int8_t* preln,
half const* beta, half const* gamma, float const dqScaleIn, float const dqScaleSkip, float const qScale,
float const qSkipScale, int32_t const total)
{
// clang-format off
enum { kHEAD_SIZE = 64 };
enum { kBYTES_PER_LDG = 16 };
enum { kTHREADS_PER_CTA = tWARPS * 32 };
enum { kROWS_PER_LDG = kTHREADS_PER_CTA / tTHREADS_PER_ROW };
enum { kVECS_PER_CTA = tTHREADS_PER_ROW / 2 };
enum { kPARAM_BYTES = tHEADS * kHEAD_SIZE * 2 };
enum { kPARAM_LDGS = kPARAM_BYTES / (kTHREADS_PER_CTA * kBYTES_PER_LDG) };
enum { kLDGS = tHEADS * 2 / kROWS_PER_LDG };
// clang-format on
static_assert(kVECS_PER_CTA == 4, "");
static_assert(kPARAM_LDGS == 1, "");
static_assert(kROWS_PER_LDG == tHEADS, "");
static_assert(kLDGS == 2, "");
static_assert(kLDGS * kROWS_PER_LDG == tHEADS * 2, "");
static_assert(kTHREADS_PER_CTA * kBYTES_PER_LDG == kPARAM_BYTES, "");
static_assert(kPARAM_LDGS == 1, "");
extern __shared__ char smem_[];
// space for CTA-wide reduction
__shared__ half2 smemRed[kVECS_PER_CTA][tWARPS];
constexpr float rld = 1.F / (float(tHEADS) * float(kHEAD_SIZE));
int32_t const bidx = blockIdx.x;
int32_t const tidx = threadIdx.x;
int32_t const row = tidx / tTHREADS_PER_ROW;
int32_t const col = tidx % tTHREADS_PER_ROW;
int32_t const lane = tidx % 32;
int32_t const warp = tidx / 32;
bool const isWarpLead = (lane < tTHREADS_PER_ROW) && ((lane & 1) == 0);
bool const isCtaLead = (tidx < tTHREADS_PER_ROW) && ((tidx & 1) == 0);
// token position: every two threads load together the 32B at one token
// position
int32_t const pos = col / 2;
int32_t const posOffset = bidx * kVECS_PER_CTA + pos; // for token positions per block, disabling 2 threads per pos
bool const myPred = posOffset < total;
int32_t const rowStrideBytes = total * 32;
uint4 inData[kLDGS];
uint4 in_skip[kLDGS];
float hdata[kLDGS * 4][4];
int32_t const gmemOffset = row * rowStrideBytes + (bidx * tTHREADS_PER_ROW + col) * kBYTES_PER_LDG;
#pragma unroll
for (int32_t ii = 0; ii < kLDGS; ii++)
{
inData[ii] = {0, 0, 0, 0};
in_skip[ii] = {0, 0, 0, 0};
if (myPred)
{
ldg(input + gmemOffset + ii * kROWS_PER_LDG * rowStrideBytes, inData[ii]);
ldg(skip + gmemOffset + ii * kROWS_PER_LDG * rowStrideBytes, in_skip[ii]);
}
}
uint4* smemB = reinterpret_cast<uint4*>(&smem_[0]) + tidx;
uint4* smemG = reinterpret_cast<uint4*>(&smem_[kPARAM_BYTES]) + tidx;
int8_t const* betaPtr = reinterpret_cast<int8_t const*>(beta) + tidx * kBYTES_PER_LDG;
int8_t const* gammaPtr = reinterpret_cast<int8_t const*>(gamma) + tidx * kBYTES_PER_LDG;
ldg(betaPtr, *smemB);
ldg(gammaPtr, *smemG);
half* b = reinterpret_cast<half*>(&smem_[0]);
half* g = reinterpret_cast<half*>(&smem_[kPARAM_BYTES]);
#pragma unroll
for (int32_t ii = 0; ii < kLDGS; ii++)
{
res_add(hdata[ii * 4 + 0], inData[ii].x, in_skip[ii].x, dqScaleIn, dqScaleSkip);
res_add(hdata[ii * 4 + 1], inData[ii].y, in_skip[ii].y, dqScaleIn, dqScaleSkip);
res_add(hdata[ii * 4 + 2], inData[ii].z, in_skip[ii].z, dqScaleIn, dqScaleSkip);
res_add(hdata[ii * 4 + 3], inData[ii].w, in_skip[ii].w, dqScaleIn, dqScaleSkip);
}
half2 statsLocal = {0, 0};
#pragma unroll
for (int32_t ii = 0; ii < kLDGS * 4; ii++)
{
#pragma unroll
for (int32_t jj = 0; jj < 4; jj++)
{
float const tmp = hdata[ii][jj] * (rld);
statsLocal = statsLocal + __floats2half2_rn(tmp, tmp * hdata[ii][jj]);
}
}
statsLocal = statsLocal + __shfl_xor_sync(uint32_t(-1), statsLocal, 1);
__syncwarp();
if (kVECS_PER_CTA == 1)
{
statsLocal = statsLocal + __shfl_xor_sync(uint32_t(-1), statsLocal, 2);
__syncwarp();
statsLocal = statsLocal + __shfl_xor_sync(uint32_t(-1), statsLocal, 4);
__syncwarp();
}
else if (kVECS_PER_CTA == 2)
{
statsLocal = statsLocal + __shfl_xor_sync(uint32_t(-1), statsLocal, 4);
__syncwarp();
}
statsLocal = statsLocal + __shfl_xor_sync(uint32_t(-1), statsLocal, 8);
__syncwarp();
statsLocal = statsLocal + __shfl_xor_sync(uint32_t(-1), statsLocal, 16);
__syncwarp();
if (isWarpLead)
{
smemRed[pos][warp] = statsLocal;
}
__syncthreads();
if (isCtaLead)
{
for (int32_t ii = 1; ii < tWARPS; ii++)
{
statsLocal = statsLocal + smemRed[pos][ii];
}
float mu = __low2float(statsLocal);
float sos = __high2float(statsLocal);
float rsigma = rsqrtf(sos - mu * mu + std::numeric_limits<float>::epsilon());
smemRed[pos][0] = __floats2half2_rn(mu, rsigma);
}
__syncthreads();
// load params into smem: 2x Headsx32x2x2B
const float2 statsf = __half22float2(smemRed[pos][0]);
// Copy skip connection output before Layer Norm
#pragma unroll
for (int32_t ii = 0; ii < kLDGS; ii++)
{
inData[ii].x = pack4(hdata[ii * 4 + 0], qSkipScale);
inData[ii].y = pack4(hdata[ii * 4 + 1], qSkipScale);
inData[ii].z = pack4(hdata[ii * 4 + 2], qSkipScale);
inData[ii].w = pack4(hdata[ii * 4 + 3], qSkipScale);
}
#pragma unroll
for (int32_t ii = 0; ii < kLDGS; ii++)
{
if (myPred)
{
stg(preln + gmemOffset + ii * kROWS_PER_LDG * rowStrideBytes, inData[ii]);
}
}
#pragma unroll
for (int32_t ii = 0; ii < kLDGS; ii++)
{
#pragma unroll
for (int32_t jj = 0; jj < 4; jj++)
{
#pragma unroll
for (int32_t kk = 0; kk < 4; kk++)
{
int32_t const paramIdx = (ii * kROWS_PER_LDG + row) * 32 + (jj * 4 + kk) + (tidx & 1) * 16;
float const bb = b[paramIdx];
float const gg = g[paramIdx];
hdata[ii * 4 + jj][kk] = gg * statsf.y * (hdata[ii * 4 + jj][kk] - statsf.x) + bb;
}
}
}
#pragma unroll
for (int32_t ii = 0; ii < kLDGS; ii++)
{
inData[ii].x = pack4(hdata[ii * 4 + 0], qScale);
inData[ii].y = pack4(hdata[ii * 4 + 1], qScale);
inData[ii].z = pack4(hdata[ii * 4 + 2], qScale);
inData[ii].w = pack4(hdata[ii * 4 + 3], qScale);
}
#pragma unroll
for (int32_t ii = 0; ii < kLDGS; ii++)
{
if (myPred)
{
stg(output + gmemOffset + ii * kROWS_PER_LDG * rowStrideBytes, inData[ii]);
}
}
// store
}
int32_t launch_large_mtron(cudaStream_t stream, int32_t const ld, int32_t const total, int8_t const* input,
int8_t const* skip, half const* beta, half const* gamma, int8_t* output, int8_t* preln, float const dqScaleIn,
float const dqScaleSkip, float const qScale, float const qSkipScale)
{
if (ld == 1024)
{
constexpr int32_t tWARPS = 4;
constexpr int32_t tTHREADS_PER_ROW = 8;
constexpr int32_t tHEADS = 16;
constexpr int32_t kPARAM_BYTES = tHEADS * 64 * 2 * sizeof(half);
constexpr int32_t kVECS_PER_CTA = tTHREADS_PER_ROW / 2;
int32_t const blocks = (total + kVECS_PER_CTA - 1) / kVECS_PER_CTA;
skipln_vec32_mtron<tWARPS, tHEADS, tTHREADS_PER_ROW><<<blocks, tWARPS * 32, kPARAM_BYTES, stream>>>(
input, skip, output, preln, beta, gamma, dqScaleIn, dqScaleSkip, qScale, qSkipScale, total);
}
else if (ld == 768)
{
constexpr int32_t tWARPS = 3;
constexpr int32_t tTHREADS_PER_ROW = 8;
constexpr int32_t tHEADS = 12;
constexpr int32_t kPARAM_BYTES = tHEADS * 64 * 2 * sizeof(half);
constexpr int32_t kVECS_PER_CTA = tTHREADS_PER_ROW / 2;
int32_t const blocks = (total + kVECS_PER_CTA - 1) / kVECS_PER_CTA;
skipln_vec32_mtron<tWARPS, tHEADS, tTHREADS_PER_ROW><<<blocks, tWARPS * 32, kPARAM_BYTES, stream>>>(
input, skip, output, preln, beta, gamma, dqScaleIn, dqScaleSkip, qScale, qSkipScale, total);
}
else
{
return STATUS_FAILURE;
}
return cudaPeekAtLastError();
}
// naive kernel that only changes the addressing seems to be faster for small
// problem sizes
template <int32_t TPB, int32_t VPT>
__global__ void skiplnDQQ_vec4(int32_t const ld, int8_t const* input, int8_t const* skip, int8_t* output, int8_t* preln,
half const* beta, half const* gamma, float const dqScaleIn, float const dqScaleSkip, float const qScale,
float const qSkipScale, int32_t const total)
{
int32_t const hinner = threadIdx.x % 4;
int32_t const houter = threadIdx.x / 4;
int32_t const tidx = threadIdx.x;
int32_t const bidx = blockIdx.x;
int32_t const idx = houter * total * 32 + bidx * 32 + hinner * VPT;
// 4 * 1024 * 4 * 2 Bytes = 16KB per block
int8_t inLocal[VPT];
int8_t skipLocal[VPT];
half inLocalDQ[VPT]; // dequantized input + skip
half betaLocal[VPT];
half gammaLocal[VPT];
// load input tensors
copy<sizeof(int8_t) * VPT>(&input[idx], inLocal);
copy<sizeof(int8_t) * VPT>(&skip[idx], skipLocal);
// load parameters
copy<sizeof(half) * VPT>(&beta[tidx * VPT], betaLocal);
copy<sizeof(half) * VPT>(&gamma[tidx * VPT], gammaLocal);
half2 statsLocal = __floats2half2_rn(0.F, 0.F); // accumulator
half const rld = half(1.F) / half(ld);
#pragma unroll
for (int32_t it = 0; it < VPT; it++)
{
// DQ input and skip
float const tmpIn = inLocal[it];
float const tmpSkip = skipLocal[it];
inLocalDQ[it] = dqScaleIn * tmpIn + dqScaleSkip * tmpSkip;
half const tmp = rld * inLocalDQ[it];
half2 const tmp2 = __halves2half2(tmp, tmp * inLocalDQ[it]);
statsLocal = statsLocal + tmp2;
}
using BlockReduce = cub::BlockReduce<half2, TPB>;
__shared__ typename BlockReduce::TempStorage tempStorage;
__shared__ half mu; // mean
__shared__ half rsigma; // 1 / std.dev.
half2 const sum2 = BlockReduce(tempStorage).Reduce(statsLocal, compat::getCudaSumOp());
// Copy skip connection output before Layer Norm
#pragma unroll
for (int32_t it = 0; it < VPT; it++)
{
inLocal[it] = quantize(inLocalDQ[it], qSkipScale);
}
copy<sizeof(int8_t) * VPT>(inLocal, &preln[idx]);
if (tidx == 0)
{
mu = __low2half(sum2);
rsigma = rsqrtf(__high2half(sum2) - mu * mu + std::numeric_limits<half>::epsilon());
}
__syncthreads();
static_assert(VPT % 4 == 0, "");
uint32_t outLocal[VPT / 4U];
#pragma unroll
for (int32_t it = 0; it < VPT / 4U; it++)
{
float const tmp0 = gammaLocal[it * 4 + 0] * (inLocalDQ[it * 4 + 0] - mu) * rsigma + betaLocal[it * 4 + 0];
float const tmp1 = gammaLocal[it * 4 + 1] * (inLocalDQ[it * 4 + 1] - mu) * rsigma + betaLocal[it * 4 + 1];
float const tmp2 = gammaLocal[it * 4 + 2] * (inLocalDQ[it * 4 + 2] - mu) * rsigma + betaLocal[it * 4 + 2];
float const tmp3 = gammaLocal[it * 4 + 3] * (inLocalDQ[it * 4 + 3] - mu) * rsigma + betaLocal[it * 4 + 3];
outLocal[it] = float4_to_char4(tmp0 * qScale, tmp1 * qScale, tmp2 * qScale, tmp3 * qScale);
}
copy<sizeof(int8_t) * VPT>(outLocal, &output[idx]);
}
int32_t launch_small_mtron(cudaStream_t stream, int32_t const ld, int32_t const total, int8_t const* input,
int8_t const* skip, half const* beta, half const* gamma, int8_t* output, int8_t* preln, float const dqScaleIn,
float const dqScaleSkip, float const qScale, float const qSkipScale)
{
int32_t const gridSize = total;
// we align reads with the number of parameters, i.e. 8-wide instead of 16
int32_t constexpr VPT = 16 / sizeof(half); // 8
if (ld == 768)
{
int32_t constexpr TPB = 768 / VPT;
skiplnDQQ_vec4<TPB, VPT><<<gridSize, TPB, 0, stream>>>(
ld, input, skip, output, preln, beta, gamma, dqScaleIn, dqScaleSkip, qScale, qSkipScale, total);
}
else if (ld == 1024)
{
int32_t constexpr TPB = 1024 / VPT; // 128
skiplnDQQ_vec4<TPB, VPT><<<gridSize, TPB, 0, stream>>>(
ld, input, skip, output, preln, beta, gamma, dqScaleIn, dqScaleSkip, qScale, qSkipScale, total);
}
else if (ld == 1536)
{
int32_t constexpr TPB = 1536 / VPT; // 192
skiplnDQQ_vec4<TPB, VPT><<<gridSize, TPB, 0, stream>>>(
ld, input, skip, output, preln, beta, gamma, dqScaleIn, dqScaleSkip, qScale, qSkipScale, total);
}
else if (ld == 2048)
{
int32_t constexpr TPB = 2048 / VPT; // 256
skiplnDQQ_vec4<TPB, VPT><<<gridSize, TPB, 0, stream>>>(
ld, input, skip, output, preln, beta, gamma, dqScaleIn, dqScaleSkip, qScale, qSkipScale, total);
}
else if (ld == 3072)
{
int32_t constexpr TPB = 3072 / VPT; // 384
skiplnDQQ_vec4<TPB, VPT><<<gridSize, TPB, 0, stream>>>(
ld, input, skip, output, preln, beta, gamma, dqScaleIn, dqScaleSkip, qScale, qSkipScale, total);
}
else if (ld == 4096)
{
int32_t constexpr TPB = 4096 / VPT; // 512
skiplnDQQ_vec4<TPB, VPT><<<gridSize, TPB, 0, stream>>>(
ld, input, skip, output, preln, beta, gamma, dqScaleIn, dqScaleSkip, qScale, qSkipScale, total);
}
else
{
std::cout << "SkipLayerNormDQQ - FATAL: unsupported hidden layer size: " << ld << std::endl;
return STATUS_FAILURE;
}
return cudaPeekAtLastError();
}
} // namespace bert
} // namespace plugin
} // namespace nvinfer1
@@ -0,0 +1,584 @@
/*
* 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 "skipLayerNormInt8InterleavedPlugin.h"
#include "NvInfer.h"
#include "common/serialize.hpp"
#include <cuda.h>
#include <cstring>
#include <memory>
#include <string_view>
#include <vector>
using namespace nvinfer1;
using namespace nvinfer1::plugin;
using namespace nvinfer1::plugin::bert;
// Clip plugin specific constants
namespace
{
using namespace std::string_view_literals;
constexpr char const* kSKIP_LAYER_NORM_INTERLEAVED_VERSION_HFACE{"7"};
constexpr char const* kSKIP_LAYER_NORM_INTERLEAVED_VERSION_MTRON{"8"};
constexpr char const* kSKIP_LAYER_NORM_INTERLEAVED_NAME{"CustomSkipLayerNormPluginDynamic"};
void checkDescs(PluginTensorDesc const& iDesc, PluginTensorDesc const& sDesc, PluginTensorDesc const& oDesc)
{
PLUGIN_VALIDATE(iDesc.dims.nbDims == 4);
PLUGIN_VALIDATE(iDesc.dims.nbDims == sDesc.dims.nbDims);
PLUGIN_VALIDATE(std::equal(iDesc.dims.d, iDesc.dims.d + iDesc.dims.nbDims, sDesc.dims.d));
PLUGIN_VALIDATE(std::equal(iDesc.dims.d, iDesc.dims.d + iDesc.dims.nbDims, oDesc.dims.d));
PLUGIN_VALIDATE(iDesc.dims.d[0] == 1);
PLUGIN_VALIDATE(iDesc.dims.d[3] == 1);
PLUGIN_VALIDATE(iDesc.format == TensorFormat::kCHW32);
PLUGIN_VALIDATE(iDesc.type == DataType::kINT8);
PLUGIN_VALIDATE(iDesc.format == sDesc.format);
PLUGIN_VALIDATE(iDesc.format == oDesc.format);
PLUGIN_VALIDATE(iDesc.type == sDesc.type);
PLUGIN_VALIDATE(iDesc.type == oDesc.type);
}
void buildBetaAndGamma(PluginFieldCollection const* fc, Weights& beta, Weights& gamma)
{
PLUGIN_VALIDATE(fc != nullptr, "SkipLayerNorm: Plugin Field collection is null");
PLUGIN_VALIDATE(fc->fields != nullptr, "SkipLayerNorm: Plugin Fields are null");
plugin::validateRequiredAttributesExist({"beta", "gamma"}, fc);
for (int32_t i = 0; i < fc->nbFields; i++)
{
std::string_view const fieldName = fc->fields[i].name;
if (fieldName == "beta"sv)
{
BERT_DEBUG_MSG("Building beta...");
beta.values = fc->fields[i].data;
beta.count = fc->fields[i].length;
beta.type = fieldTypeToDataType(fc->fields[i].type);
}
if (fieldName == "gamma"sv)
{
BERT_DEBUG_MSG("Building gamma...");
gamma.values = fc->fields[i].data;
gamma.count = fc->fields[i].length;
gamma.type = fieldTypeToDataType(fc->fields[i].type);
}
}
PLUGIN_VALIDATE(beta.values != nullptr, "SkipLayerNorm: invalid beta");
PLUGIN_VALIDATE(beta.count > 0, "SkipLayerNorm: invalid beta");
PLUGIN_VALIDATE(gamma.values != nullptr, "SkipLayerNorm: invalid gamma");
PLUGIN_VALIDATE(gamma.count > 0, "SkipLayerNorm: invalid gamma");
}
} // namespace
REGISTER_TENSORRT_PLUGIN(SkipLayerNormInterleavedPluginHFaceCreator);
REGISTER_TENSORRT_PLUGIN(SkipLayerNormInterleavedPluginMTronCreator);
constexpr auto kPARAM_TYPE = DataType::kHALF;
SkipLayerNormInterleavedPluginBase::SkipLayerNormInterleavedPluginBase(
std::string const& name, Weights const& beta, Weights const& gamma)
: mLayerName(name)
, mGammaDev(nullptr)
, mBetaDev(nullptr)
, mLd(beta.count)
, mParamsOnDevice(false)
{
PLUGIN_VALIDATE(mLd > 0);
PLUGIN_VALIDATE(beta.count == gamma.count);
// dataType for beta, gamma weights is always fp16
mParamWordsize = getElementSize(kPARAM_TYPE);
mBeta.convertAndCopy(beta, kPARAM_TYPE);
mGamma.convertAndCopy(gamma, kPARAM_TYPE);
}
SkipLayerNormInterleavedPluginHFace::SkipLayerNormInterleavedPluginHFace(
std::string const& name, Weights const& beta, Weights const& gamma)
: SkipLayerNormInterleavedPluginBase(name, beta, gamma)
{
}
SkipLayerNormInterleavedPluginMTron::SkipLayerNormInterleavedPluginMTron(
std::string const& name, Weights const& beta, Weights const& gamma)
: SkipLayerNormInterleavedPluginBase(name, beta, gamma)
{
}
SkipLayerNormInterleavedPluginBase::~SkipLayerNormInterleavedPluginBase()
{
try
{
mGammaDev.reset(nullptr);
mBetaDev.reset(nullptr);
}
catch (std::exception const& e)
{
caughtError(e);
}
}
SkipLayerNormInterleavedPluginHFace::~SkipLayerNormInterleavedPluginHFace()
{
BERT_DEBUG_MSG("SkipLayerNormInterleavedPluginHFace destructor");
}
SkipLayerNormInterleavedPluginMTron::~SkipLayerNormInterleavedPluginMTron()
{
BERT_DEBUG_MSG("SkipLayerNormInterleavedPluginMTron destructor");
}
//////
// IPluginV3 method definitions:
// - getCapabilityInterface() (Base)
// - clone() (HFace, MTron)
//////
IPluginCapability* SkipLayerNormInterleavedPluginBase::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* SkipLayerNormInterleavedPluginHFace::clone() noexcept
{
try
{
BERT_DEBUG_MSG("SkipLayerNormInterleavedPluginHFace clone");
auto p = std::make_unique<SkipLayerNormInterleavedPluginHFace>(mLayerName, mBeta, mGamma);
p->setPluginNamespace(mNamespace.c_str());
return p.release();
}
catch (std::exception const& e)
{
caughtError(e);
}
return nullptr;
}
IPluginV3* SkipLayerNormInterleavedPluginMTron::clone() noexcept
{
try
{
BERT_DEBUG_MSG("SkipLayerNormInterleavedPluginMTron clone");
auto p = std::make_unique<SkipLayerNormInterleavedPluginMTron>(mLayerName, mBeta, mGamma);
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() (HFace, MTron)
// - execute() (HFace, MTron)
/////
PluginFieldCollection const* SkipLayerNormInterleavedPluginBase::getFieldsToSerialize() noexcept
{
mDataToSerialize.clear();
mDataToSerialize.emplace_back(
"beta", static_cast<half const*>(mBeta.values), PluginFieldType::kFLOAT16, mBeta.count);
PLUGIN_ASSERT(mBeta.type == kPARAM_TYPE);
mDataToSerialize.emplace_back(
"gamma", static_cast<half const*>(mGamma.values), PluginFieldType::kFLOAT16, mGamma.count);
PLUGIN_ASSERT(mGamma.type == kPARAM_TYPE);
mFCToSerialize.nbFields = mDataToSerialize.size();
mFCToSerialize.fields = mDataToSerialize.data();
return &mFCToSerialize;
}
int32_t SkipLayerNormInterleavedPluginBase::onShapeChange(
PluginTensorDesc const* inputs, int32_t nbInputs, PluginTensorDesc const* outputs, int32_t nbOutputs) noexcept
{
try
{
// Validate input arguments
PLUGIN_VALIDATE(inputs != nullptr);
PLUGIN_VALIDATE(outputs != nullptr);
PLUGIN_VALIDATE(nbOutputs == getNbOutputs());
PLUGIN_VALIDATE(nbInputs == 2);
PLUGIN_VALIDATE(DataType::kINT8 == inputs[0].type);
PLUGIN_VALIDATE(DataType::kINT8 == inputs[1].type);
auto const& inDims0 = inputs[0].dims;
auto const& inDims1 = inputs[1].dims;
TRT_UNUSED inDims1;
PLUGIN_VALIDATE(inDims0.nbDims == inDims1.nbDims);
PLUGIN_VALIDATE(std::equal(inDims0.d, inDims0.d + inDims0.nbDims, inDims1.d));
mParamWordsize = getElementSize(kPARAM_TYPE);
if (!mParamsOnDevice)
{
copyToDevice(mGamma, getWeightsSize(mGamma, kPARAM_TYPE), mGammaDev);
copyToDevice(mBeta, getWeightsSize(mBeta, kPARAM_TYPE), mBetaDev);
mParamsOnDevice = true;
}
return pluginStatus_t::STATUS_SUCCESS;
}
catch (std::exception const& e)
{
caughtError(e);
}
return pluginStatus_t::STATUS_FAILURE;
}
IPluginV3* SkipLayerNormInterleavedPluginBase::attachToContext(IPluginResourceContext* context) noexcept
{
return clone();
}
int32_t SkipLayerNormInterleavedPluginHFace::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 && outputDesc != nullptr && inputs != nullptr && outputs != nullptr);
// Input shape: 1x(hxd)xtotalx1
auto const iDesc = inputDesc[0];
auto const sDesc = inputDesc[1];
auto const oDesc = outputDesc[0];
checkDescs(iDesc, sDesc, oDesc);
const int32_t ld = iDesc.dims.d[1];
const int32_t total = iDesc.dims.d[2];
float const dqScaleIn = iDesc.scale;
float const dqScaleSkip = sDesc.scale;
float const qScale = 1.F / oDesc.scale;
int8_t const* input = static_cast<int8_t const*>(inputs[0]);
int8_t const* skip = static_cast<int8_t const*>(inputs[1]);
int8_t* output = static_cast<int8_t*>(outputs[0]);
half const* gamma = static_cast<half const*>(mGammaDev.get());
half const* beta = static_cast<half const*>(mBetaDev.get());
if (total < 4096)
{
return launch_small_hface(
stream, ld, total, input, skip, beta, gamma, output, dqScaleIn, dqScaleSkip, qScale);
}
return launch_large_hface(stream, ld, total, input, skip, beta, gamma, output, dqScaleIn, dqScaleSkip, qScale);
}
catch (std::exception const& e)
{
caughtError(e);
}
return -1;
}
int32_t SkipLayerNormInterleavedPluginMTron::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 && outputDesc != nullptr && inputs != nullptr && outputs != nullptr);
// Input shape: 1x(hxd)xtotalx1
auto const iDesc = inputDesc[0];
auto const sDesc = inputDesc[1];
auto const oDesc = outputDesc[0];
auto const pDesc = outputDesc[1];
checkDescs(iDesc, sDesc, oDesc);
PLUGIN_VALIDATE(std::equal(iDesc.dims.d, iDesc.dims.d + iDesc.dims.nbDims, pDesc.dims.d));
const int32_t ld = iDesc.dims.d[1];
const int32_t total = iDesc.dims.d[2];
float const dqScaleIn = iDesc.scale;
float const dqScaleSkip = sDesc.scale;
float const qScale = 1.F / oDesc.scale;
float const qSkipScale = 1.F / pDesc.scale;
int8_t const* input = static_cast<int8_t const*>(inputs[0]);
int8_t const* skip = static_cast<int8_t const*>(inputs[1]);
int8_t* output = static_cast<int8_t*>(outputs[0]);
int8_t* preln = static_cast<int8_t*>(outputs[1]);
half const* gamma = static_cast<half const*>(mGammaDev.get());
half const* beta = static_cast<half const*>(mBetaDev.get());
if (total < 4096)
{
return launch_small_mtron(
stream, ld, total, input, skip, beta, gamma, output, preln, dqScaleIn, dqScaleSkip, qScale, qSkipScale);
}
return launch_large_mtron(
stream, ld, total, input, skip, beta, gamma, output, preln, dqScaleIn, dqScaleSkip, qScale, qSkipScale);
}
catch (std::exception const& e)
{
caughtError(e);
}
return -1;
}
// end IPluginV3OneRuntime method definitions
///////
// IPluginV3OneBuild method definitions
// - getNbOutputs() (MTron, HFace)
// - supportsFormatCombination() (Base)
// - getOutputShapes (Base)
// - getOutputDataType() (Base)
// - configurePlugin() (Base)
// - getWorkSpaceSize() (Base)
//////
int32_t SkipLayerNormInterleavedPluginHFace::getNbOutputs() const noexcept
{
return 1;
}
int32_t SkipLayerNormInterleavedPluginMTron::getNbOutputs() const noexcept
{
return 2;
}
bool SkipLayerNormInterleavedPluginBase::supportsFormatCombination(
int32_t pos, DynamicPluginTensorDesc const* inOut, int32_t nbInputs, int32_t nbOutputs) noexcept
{
try
{
PLUGIN_VALIDATE(inOut != nullptr);
PLUGIN_VALIDATE(nbInputs == 2);
PLUGIN_VALIDATE(nbOutputs == getNbOutputs());
PLUGIN_VALIDATE(pos >= 0 && pos < (nbInputs + nbOutputs));
PluginTensorDesc const& desc = inOut[pos].desc;
return desc.type == DataType::kINT8 && desc.format == TensorFormat::kCHW32;
}
catch (std::exception const& e)
{
caughtError(e);
}
return false;
}
int32_t SkipLayerNormInterleavedPluginBase::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(nbInputs == 2);
PLUGIN_VALIDATE(nbOutputs == getNbOutputs());
PLUGIN_VALIDATE(inputs[0].nbDims == inputs[1].nbDims);
for (int32_t i = 0; i < nbOutputs; ++i)
{
outputs[i] = inputs[0];
}
return pluginStatus_t::STATUS_SUCCESS;
}
catch (std::exception const& e)
{
caughtError(e);
}
return pluginStatus_t::STATUS_FAILURE;
}
int32_t SkipLayerNormInterleavedPluginBase::getOutputDataTypes(
DataType* outputTypes, int32_t nbOutputs, DataType const* inputTypes, int32_t nbInputs) const noexcept
{
try
{
PLUGIN_VALIDATE(inputTypes != nullptr);
PLUGIN_VALIDATE(nbOutputs == getNbOutputs());
PLUGIN_VALIDATE(nbInputs == 2);
for (int32_t i = 0; i < nbOutputs; ++i)
{
outputTypes[i] = inputTypes[0];
}
return pluginStatus_t::STATUS_SUCCESS;
}
catch (std::exception const& e)
{
caughtError(e);
}
return pluginStatus_t::STATUS_FAILURE;
}
int32_t SkipLayerNormInterleavedPluginBase::configurePlugin(DynamicPluginTensorDesc const* inputs, int32_t nbInputs,
DynamicPluginTensorDesc const* outputs, int32_t nbOutputs) noexcept
{
return pluginStatus_t::STATUS_SUCCESS;
}
size_t SkipLayerNormInterleavedPluginBase::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* SkipLayerNormInterleavedPluginHFace::getPluginVersion() const noexcept
{
return kSKIP_LAYER_NORM_INTERLEAVED_VERSION_HFACE;
}
char const* SkipLayerNormInterleavedPluginMTron::getPluginVersion() const noexcept
{
return kSKIP_LAYER_NORM_INTERLEAVED_VERSION_MTRON;
}
char const* SkipLayerNormInterleavedPluginBase::getPluginName() const noexcept
{
return kSKIP_LAYER_NORM_INTERLEAVED_NAME;
}
char const* SkipLayerNormInterleavedPluginBase::getPluginNamespace() const noexcept
{
return mNamespace.c_str();
}
void SkipLayerNormInterleavedPluginBase::setPluginNamespace(char const* libNamespace) noexcept
{
mNamespace = libNamespace;
}
// End IPluginV3OneCore method definitions
//////////////////////////// Plugin Creator member definitions /////////////////////////////
SkipLayerNormInterleavedPluginBaseCreator::SkipLayerNormInterleavedPluginBaseCreator()
{
static std::mutex sMutex;
std::lock_guard<std::mutex> lock(sMutex);
mPluginAttributes.clear();
mPluginAttributes.emplace_back(PluginField("beta"));
mPluginAttributes.emplace_back(PluginField("gamma"));
mFC.nbFields = mPluginAttributes.size();
mFC.fields = mPluginAttributes.data();
}
SkipLayerNormInterleavedPluginHFaceCreator::SkipLayerNormInterleavedPluginHFaceCreator()
: SkipLayerNormInterleavedPluginBaseCreator()
{
}
SkipLayerNormInterleavedPluginMTronCreator::SkipLayerNormInterleavedPluginMTronCreator()
: SkipLayerNormInterleavedPluginBaseCreator()
{
}
char const* SkipLayerNormInterleavedPluginBaseCreator::getPluginName() const noexcept
{
return kSKIP_LAYER_NORM_INTERLEAVED_NAME;
}
char const* SkipLayerNormInterleavedPluginHFaceCreator::getPluginVersion() const noexcept
{
return kSKIP_LAYER_NORM_INTERLEAVED_VERSION_HFACE;
}
char const* SkipLayerNormInterleavedPluginMTronCreator::getPluginVersion() const noexcept
{
return kSKIP_LAYER_NORM_INTERLEAVED_VERSION_MTRON;
}
PluginFieldCollection const* SkipLayerNormInterleavedPluginBaseCreator::getFieldNames() noexcept
{
return &mFC;
}
IPluginV3* SkipLayerNormInterleavedPluginHFaceCreator::createPlugin(
char const* name, PluginFieldCollection const* fc, TensorRTPhase phase) noexcept
{
try
{
BERT_DEBUG_MSG("SkipLayerNormInterleavedPluginHFaceCreator createPlugin");
Weights beta{DataType::kFLOAT, nullptr, 0};
Weights gamma{DataType::kFLOAT, nullptr, 0};
buildBetaAndGamma(fc, beta, gamma);
return new SkipLayerNormInterleavedPluginHFace(name, beta, gamma);
}
catch (std::exception const& e)
{
caughtError(e);
}
return nullptr;
}
IPluginV3* SkipLayerNormInterleavedPluginMTronCreator::createPlugin(
char const* name, PluginFieldCollection const* fc, TensorRTPhase phase) noexcept
{
try
{
BERT_DEBUG_MSG("SkipLayerNormInterleavedPluginMTronCreator createPlugin");
PLUGIN_VALIDATE(fc != nullptr);
Weights beta{DataType::kFLOAT, nullptr, 0};
Weights gamma{DataType::kFLOAT, nullptr, 0};
buildBetaAndGamma(fc, beta, gamma);
return new SkipLayerNormInterleavedPluginMTron(name, beta, gamma);
}
catch (std::exception const& e)
{
caughtError(e);
}
return nullptr;
}
void SkipLayerNormInterleavedPluginBaseCreator::setPluginNamespace(char const* libNamespace) noexcept
{
mNamespace = libNamespace;
}
char const* SkipLayerNormInterleavedPluginBaseCreator::getPluginNamespace() const noexcept
{
return mNamespace.c_str();
}
// End Plugin Creator member definitions
@@ -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_SKIP_LAYER_NORM_INTERLEAVED_PLUGIN_H
#define TRT_SKIP_LAYER_NORM_INTERLEAVED_PLUGIN_H
#include "NvInferPlugin.h"
#include <cuda.h>
#include "common/bertCommon.h"
#include <memory>
#include <string>
#include <vector>
namespace nvinfer1
{
namespace plugin
{
namespace bert
{
int32_t launch_small_hface(cudaStream_t stream, int32_t const ld, int32_t const total, int8_t const* input,
int8_t const* skip, half const* beta, half const* gamma, int8_t* output, float const dqScaleIn,
float const dqScaleSkip, float const qScale);
int32_t launch_large_hface(cudaStream_t stream, int32_t const ld, int32_t const total, int8_t const* input,
int8_t const* skip, half const* beta, half const* gamma, int8_t* output, float const dqScaleIn,
float const dqScaleSkip, float const qScale);
int32_t launch_small_mtron(cudaStream_t stream, int32_t const ld, int32_t const total, int8_t const* input,
int8_t const* skip, half const* beta, half const* gamma, int8_t* output, int8_t* preln, float const dqScaleIn,
float const dqScaleSkip, float const qScale, float const qSkipScale);
int32_t launch_large_mtron(cudaStream_t stream, int32_t const ld, int32_t const total, int8_t const* input,
int8_t const* skip, half const* beta, half const* gamma, int8_t* output, int8_t* preln, float const dqScaleIn,
float const dqScaleSkip, float const qScale, float const qSkipScale);
class SkipLayerNormInterleavedPluginBase : public IPluginV3,
public IPluginV3OneCore,
public IPluginV3OneBuild,
public IPluginV3OneRuntime
{
public:
SkipLayerNormInterleavedPluginBase(
std::string const& name, nvinfer1::Weights const& beta, nvinfer1::Weights const& gamma);
// It doesn't make sense to make SkipLayerNormInterleavedPlugin without
// arguments, so we delete default constructor.
SkipLayerNormInterleavedPluginBase() = delete;
~SkipLayerNormInterleavedPluginBase() 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 getOutputShapes(DimsExprs const* inputs, int32_t nbInputs, DimsExprs const* shapeInputs,
int32_t nbShapeInputs, DimsExprs* outputs, int32_t nbOutputs, IExprBuilder& exprBuilder) 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;
// end IPluginV3Build Methods
// IPluginV3Runtime Methods
int32_t onShapeChange(
PluginTensorDesc const* in, int32_t nbInputs, PluginTensorDesc const* out, int32_t nbOutputs) noexcept override;
IPluginV3* attachToContext(IPluginResourceContext* context) noexcept override;
PluginFieldCollection const* getFieldsToSerialize() noexcept override;
// end IPluginV3Runtime Methods
protected:
// metadata fields
std::string const& mLayerName;
std::string mNamespace;
std::vector<nvinfer1::PluginField> mDataToSerialize;
nvinfer1::PluginFieldCollection mFCToSerialize;
// members that participate in ser/deserialization
bert::WeightsWithOwnership mGamma;
bert::WeightsWithOwnership mBeta;
// device-side
bert::cuda_unique_ptr<void> mGammaDev;
bert::cuda_unique_ptr<void> mBetaDev;
// derived members
size_t mLd{}; // leading dim
size_t mParamWordsize{};
bool mParamsOnDevice{};
};
class SkipLayerNormInterleavedPluginHFace : public SkipLayerNormInterleavedPluginBase
{
public:
SkipLayerNormInterleavedPluginHFace(
std::string const& name, nvinfer1::Weights const& beta, nvinfer1::Weights const& gamma);
// It doesn't make sense to make SkipLayerNormInterleavedPlugin without
// arguments, so we delete default constructor.
SkipLayerNormInterleavedPluginHFace() = delete;
~SkipLayerNormInterleavedPluginHFace() override;
// IPluginV3Runtime overrides
IPluginV3* clone() 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 getNbOutputs() const noexcept override;
};
class SkipLayerNormInterleavedPluginMTron : public SkipLayerNormInterleavedPluginBase
{
public:
SkipLayerNormInterleavedPluginMTron(
std::string const& name, nvinfer1::Weights const& beta, nvinfer1::Weights const& gamma);
// It doesn't make sense to make SkipLayerNormInterleavedPlugin without
// arguments, so we delete default constructor.
SkipLayerNormInterleavedPluginMTron() = delete;
~SkipLayerNormInterleavedPluginMTron() override;
// IPluginV3Runtime overrides
IPluginV3* clone() 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 getNbOutputs() const noexcept override;
};
class SkipLayerNormInterleavedPluginBaseCreator : public nvinfer1::IPluginCreatorV3One
{
public:
SkipLayerNormInterleavedPluginBaseCreator();
~SkipLayerNormInterleavedPluginBaseCreator() override = default;
char const* getPluginName() const noexcept override;
nvinfer1::PluginFieldCollection const* getFieldNames() 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;
};
class SkipLayerNormInterleavedPluginHFaceCreator : public SkipLayerNormInterleavedPluginBaseCreator
{
public:
SkipLayerNormInterleavedPluginHFaceCreator();
~SkipLayerNormInterleavedPluginHFaceCreator() override = default;
char const* getPluginVersion() const noexcept override;
IPluginV3* createPlugin(char const* name, PluginFieldCollection const* fc, TensorRTPhase phase) noexcept override;
};
class SkipLayerNormInterleavedPluginMTronCreator : public SkipLayerNormInterleavedPluginBaseCreator
{
public:
SkipLayerNormInterleavedPluginMTronCreator();
~SkipLayerNormInterleavedPluginMTronCreator() override = default;
char const* getPluginVersion() const noexcept override;
IPluginV3* createPlugin(char const* name, PluginFieldCollection const* fc, TensorRTPhase phase) noexcept override;
};
} // namespace bert
} // namespace plugin
} // namespace nvinfer1
#endif // TRT_SKIP_LAYER_NORM_INTERLEAVED_PLUGIN_H
@@ -0,0 +1,604 @@
/*
* 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 "skipLayerNormInt8InterleavedPluginLegacy.h"
#include "NvInfer.h"
#include "common/serialize.hpp"
#include <cuda.h>
#include <memory>
#include <string_view>
#include <vector>
using namespace nvinfer1;
using namespace nvinfer1::plugin;
using namespace nvinfer1::plugin::bert;
// Clip plugin specific constants
namespace
{
using namespace std::string_view_literals;
constexpr char const* kSKIP_LAYER_NORM_INTERLEAVED_VERSION_HFACE_LEGACY{"3"};
constexpr char const* kSKIP_LAYER_NORM_INTERLEAVED_VERSION_MTRON_LEGACY{"4"};
constexpr char const* kSKIP_LAYER_NORM_INTERLEAVED_NAME{"CustomSkipLayerNormPluginDynamic"};
void buildBetaAndGamma(PluginFieldCollection const* fc, Weights& beta, Weights& gamma)
{
plugin::validateRequiredAttributesExist({"beta", "gamma"}, fc);
for (int32_t i = 0; i < fc->nbFields; i++)
{
std::string_view const field_name = fc->fields[i].name;
if (field_name == "beta"sv)
{
BERT_DEBUG_MSG("Building beta...");
beta.values = fc->fields[i].data;
beta.count = fc->fields[i].length;
beta.type = fieldTypeToDataType(fc->fields[i].type);
}
if (field_name == "gamma"sv)
{
BERT_DEBUG_MSG("Building gamma...");
gamma.values = fc->fields[i].data;
gamma.count = fc->fields[i].length;
gamma.type = fieldTypeToDataType(fc->fields[i].type);
}
}
PLUGIN_VALIDATE(beta.values != nullptr, "SkipLayerNorm: invalid beta");
PLUGIN_VALIDATE(beta.count > 0, "SkipLayerNorm: invalid beta");
PLUGIN_VALIDATE(gamma.values != nullptr, "SkipLayerNorm: invalid gamma");
PLUGIN_VALIDATE(gamma.count > 0, "SkipLayerNorm: invalid gamma");
}
void checkDescs(PluginTensorDesc const& iDesc, PluginTensorDesc const& sDesc, PluginTensorDesc const& oDesc)
{
PLUGIN_VALIDATE(iDesc.dims.nbDims == 4);
PLUGIN_VALIDATE(iDesc.dims.nbDims == sDesc.dims.nbDims);
PLUGIN_VALIDATE(std::equal(iDesc.dims.d, iDesc.dims.d + iDesc.dims.nbDims, sDesc.dims.d));
PLUGIN_VALIDATE(std::equal(iDesc.dims.d, iDesc.dims.d + iDesc.dims.nbDims, oDesc.dims.d));
PLUGIN_VALIDATE(iDesc.dims.d[0] == 1);
PLUGIN_VALIDATE(iDesc.dims.d[3] == 1);
PLUGIN_VALIDATE(iDesc.format == TensorFormat::kCHW32);
PLUGIN_VALIDATE(iDesc.type == DataType::kINT8);
PLUGIN_VALIDATE(iDesc.format == sDesc.format);
PLUGIN_VALIDATE(iDesc.format == oDesc.format);
PLUGIN_VALIDATE(iDesc.type == sDesc.type);
PLUGIN_VALIDATE(iDesc.type == oDesc.type);
}
} // namespace
REGISTER_TENSORRT_PLUGIN(SkipLayerNormInterleavedPluginHFaceLegacyCreator);
REGISTER_TENSORRT_PLUGIN(SkipLayerNormInterleavedPluginMTronLegacyCreator);
constexpr auto kPARAM_TYPE = DataType::kHALF;
SkipLayerNormInterleavedPluginBaseLegacy::SkipLayerNormInterleavedPluginBaseLegacy(
std::string const& name, Weights const& beta, Weights const& gamma)
: mLayerName(name)
, mGammaDev(nullptr)
, mBetaDev(nullptr)
, mLd(beta.count)
, mParamsOnDevice(false)
{
PLUGIN_VALIDATE(mLd > 0);
PLUGIN_VALIDATE(beta.count == gamma.count);
// dataType for beta, gamma weights is always fp16
mParamWordsize = getElementSize(kPARAM_TYPE);
mBeta.convertAndCopy(beta, kPARAM_TYPE);
mGamma.convertAndCopy(gamma, kPARAM_TYPE);
}
SkipLayerNormInterleavedPluginHFaceLegacy::SkipLayerNormInterleavedPluginHFaceLegacy(
std::string const& name, Weights const& beta, Weights const& gamma)
: SkipLayerNormInterleavedPluginBaseLegacy(name, beta, gamma)
{
}
SkipLayerNormInterleavedPluginMTronLegacy::SkipLayerNormInterleavedPluginMTronLegacy(
std::string const& name, Weights const& beta, Weights const& gamma)
: SkipLayerNormInterleavedPluginBaseLegacy(name, beta, gamma)
{
}
SkipLayerNormInterleavedPluginBaseLegacy::SkipLayerNormInterleavedPluginBaseLegacy(
std::string const& name, void const* data, size_t length)
: mLayerName(name)
, mGammaDev(nullptr)
, mBetaDev(nullptr)
, mParamsOnDevice(false)
{
// Deserialize in the same order as serialization
deserialize_value(&data, &length, &mLd);
mParamWordsize = getElementSize(kPARAM_TYPE);
char const* d = static_cast<char const*>(data);
mBeta.convertAndCopy(d, mLd, kPARAM_TYPE);
mGamma.convertAndCopy(d, mLd, kPARAM_TYPE);
}
SkipLayerNormInterleavedPluginHFaceLegacy::SkipLayerNormInterleavedPluginHFaceLegacy(
std::string const& name, void const* data, size_t length)
: SkipLayerNormInterleavedPluginBaseLegacy(name, data, length)
{
BERT_DEBUG_MSG("SkipLayerNormInterleavedPluginHFaceLegacy deserialize");
}
SkipLayerNormInterleavedPluginMTronLegacy::SkipLayerNormInterleavedPluginMTronLegacy(
std::string const& name, void const* data, size_t length)
: SkipLayerNormInterleavedPluginBaseLegacy(name, data, length)
{
BERT_DEBUG_MSG("SkipLayerNormInterleavedPluginMTronLegacy deserialize");
}
// IPluginV2DynamicExt Methods
IPluginV2DynamicExt* SkipLayerNormInterleavedPluginHFaceLegacy::clone() const noexcept
{
try
{
BERT_DEBUG_MSG("SkipLayerNormInterleavedPluginHFaceLegacy clone");
auto p = std::make_unique<SkipLayerNormInterleavedPluginHFaceLegacy>(mLayerName, mBeta, mGamma);
p->initialize();
p->setPluginNamespace(mNamespace.c_str());
return p.release();
}
catch (std::exception const& e)
{
caughtError(e);
}
return nullptr;
}
IPluginV2DynamicExt* SkipLayerNormInterleavedPluginMTronLegacy::clone() const noexcept
{
try
{
BERT_DEBUG_MSG("SkipLayerNormInterleavedPluginMTronLegacy clone");
auto p = std::make_unique<SkipLayerNormInterleavedPluginMTronLegacy>(mLayerName, mBeta, mGamma);
p->initialize();
p->setPluginNamespace(mNamespace.c_str());
return p.release();
}
catch (std::exception const& e)
{
caughtError(e);
}
return nullptr;
}
DimsExprs SkipLayerNormInterleavedPluginBaseLegacy::getOutputDimensions(
int32_t outputIndex, DimsExprs const* inputs, int32_t nbInputs, IExprBuilder& exprBuilder) noexcept
{
try
{
PLUGIN_VALIDATE(inputs != nullptr);
PLUGIN_VALIDATE(nbInputs == 2);
PLUGIN_VALIDATE(outputIndex >= 0 && outputIndex < getNbOutputs());
PLUGIN_VALIDATE(inputs[0].nbDims == inputs[1].nbDims);
return inputs[0];
}
catch (std::exception const& e)
{
caughtError(e);
}
return DimsExprs{};
}
bool SkipLayerNormInterleavedPluginBaseLegacy::supportsFormatCombination(
int32_t pos, PluginTensorDesc const* inOut, int32_t nbInputs, int32_t nbOutputs) noexcept
{
try
{
PLUGIN_VALIDATE(inOut != nullptr);
PLUGIN_VALIDATE(nbInputs == 2);
PLUGIN_VALIDATE(nbOutputs == getNbOutputs());
PLUGIN_VALIDATE(pos >= 0 && pos < (nbInputs + nbOutputs));
PluginTensorDesc const& desc = inOut[pos];
return desc.type == DataType::kINT8 && desc.format == TensorFormat::kCHW32;
}
catch (std::exception const& e)
{
caughtError(e);
}
return false;
}
void SkipLayerNormInterleavedPluginBaseLegacy::configurePlugin(DynamicPluginTensorDesc const* inputs, int32_t nbInputs,
DynamicPluginTensorDesc const* outputs, int32_t nbOutputs) noexcept
{
try
{
// Validate input arguments
PLUGIN_VALIDATE(inputs != nullptr);
PLUGIN_VALIDATE(outputs != nullptr);
PLUGIN_VALIDATE(nbOutputs == getNbOutputs());
PLUGIN_VALIDATE(nbInputs == 2);
PLUGIN_VALIDATE(DataType::kINT8 == inputs[0].desc.type);
PLUGIN_VALIDATE(DataType::kINT8 == inputs[1].desc.type);
auto const& inDims0 = inputs[0].desc.dims;
auto const& inDims1 = inputs[1].desc.dims;
TRT_UNUSED inDims1;
PLUGIN_VALIDATE(inDims0.nbDims == inDims1.nbDims);
PLUGIN_VALIDATE(std::equal(inDims0.d, inDims0.d + inDims0.nbDims, inDims1.d));
mParamWordsize = getElementSize(kPARAM_TYPE);
if (!mParamsOnDevice)
{
copyToDevice(mGamma, getWeightsSize(mGamma, kPARAM_TYPE), mGammaDev);
copyToDevice(mBeta, getWeightsSize(mBeta, kPARAM_TYPE), mBetaDev);
mParamsOnDevice = true;
}
}
catch (std::exception const& e)
{
caughtError(e);
}
}
size_t SkipLayerNormInterleavedPluginBaseLegacy::getWorkspaceSize(
PluginTensorDesc const* inputs, int32_t nbInputs, PluginTensorDesc const* outputs, int32_t nbOutputs) const noexcept
{
return 0;
}
int32_t SkipLayerNormInterleavedPluginHFaceLegacy::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 && outputDesc != nullptr && inputs != nullptr && outputs != nullptr);
// Input shape: 1x(hxd)xtotalx1
auto const iDesc = inputDesc[0];
auto const sDesc = inputDesc[1];
auto const oDesc = outputDesc[0];
checkDescs(iDesc, sDesc, oDesc);
int32_t const ld = iDesc.dims.d[1];
int32_t const total = iDesc.dims.d[2];
float const dqScaleIn = iDesc.scale;
float const dqScaleSkip = sDesc.scale;
float const qScale = 1.F / oDesc.scale;
int8_t const* input = static_cast<int8_t const*>(inputs[0]);
int8_t const* skip = static_cast<int8_t const*>(inputs[1]);
int8_t* output = static_cast<int8_t*>(outputs[0]);
half const* gamma = static_cast<half const*>(mGammaDev.get());
half const* beta = static_cast<half const*>(mBetaDev.get());
if (total < 4096)
{
return launch_small_hface(
stream, ld, total, input, skip, beta, gamma, output, dqScaleIn, dqScaleSkip, qScale);
}
return launch_large_hface(stream, ld, total, input, skip, beta, gamma, output, dqScaleIn, dqScaleSkip, qScale);
}
catch (std::exception const& e)
{
caughtError(e);
}
return -1;
}
int32_t SkipLayerNormInterleavedPluginMTronLegacy::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 && outputDesc != nullptr && inputs != nullptr && outputs != nullptr);
// Input shape: 1x(hxd)xtotalx1
auto const iDesc = inputDesc[0];
auto const sDesc = inputDesc[1];
auto const oDesc = outputDesc[0];
auto const pDesc = outputDesc[1];
checkDescs(iDesc, sDesc, oDesc);
PLUGIN_VALIDATE(std::equal(iDesc.dims.d, iDesc.dims.d + iDesc.dims.nbDims, pDesc.dims.d));
int32_t const ld = iDesc.dims.d[1];
int32_t const total = iDesc.dims.d[2];
float const dqScaleIn = iDesc.scale;
float const dqScaleSkip = sDesc.scale;
float const qScale = 1.F / oDesc.scale;
float const qSkipScale = 1.F / pDesc.scale;
int8_t const* input = static_cast<int8_t const*>(inputs[0]);
int8_t const* skip = static_cast<int8_t const*>(inputs[1]);
int8_t* output = static_cast<int8_t*>(outputs[0]);
int8_t* preln = static_cast<int8_t*>(outputs[1]);
half const* gamma = static_cast<half const*>(mGammaDev.get());
half const* beta = static_cast<half const*>(mBetaDev.get());
if (total < 4096)
{
return launch_small_mtron(
stream, ld, total, input, skip, beta, gamma, output, preln, dqScaleIn, dqScaleSkip, qScale, qSkipScale);
}
return launch_large_mtron(
stream, ld, total, input, skip, beta, gamma, output, preln, dqScaleIn, dqScaleSkip, qScale, qSkipScale);
}
catch (std::exception const& e)
{
caughtError(e);
}
return -1;
}
// IPluginV2Ext Methods
DataType SkipLayerNormInterleavedPluginBaseLegacy::getOutputDataType(
int32_t index, DataType const* inputTypes, int32_t nbInputs) const noexcept
{
try
{
PLUGIN_VALIDATE(inputTypes != nullptr);
PLUGIN_VALIDATE(index >= 0 && index < getNbOutputs());
PLUGIN_VALIDATE(nbInputs == 2);
return inputTypes[0];
}
catch (std::exception const& e)
{
caughtError(e);
}
return DataType{};
}
// IPluginV2 Methods
char const* SkipLayerNormInterleavedPluginBaseLegacy::getPluginType() const noexcept
{
return kSKIP_LAYER_NORM_INTERLEAVED_NAME;
}
char const* SkipLayerNormInterleavedPluginHFaceLegacy::getPluginVersion() const noexcept
{
return kSKIP_LAYER_NORM_INTERLEAVED_VERSION_HFACE_LEGACY;
}
char const* SkipLayerNormInterleavedPluginMTronLegacy::getPluginVersion() const noexcept
{
return kSKIP_LAYER_NORM_INTERLEAVED_VERSION_MTRON_LEGACY;
}
int32_t SkipLayerNormInterleavedPluginHFaceLegacy::getNbOutputs() const noexcept
{
return 1;
}
int32_t SkipLayerNormInterleavedPluginMTronLegacy::getNbOutputs() const noexcept
{
return 2;
}
int32_t SkipLayerNormInterleavedPluginHFaceLegacy::initialize() noexcept
{
BERT_DEBUG_MSG("SkipLayerNormInterleavedPluginHFaceLegacy initialize");
return 0;
}
int32_t SkipLayerNormInterleavedPluginMTronLegacy::initialize() noexcept
{
BERT_DEBUG_MSG("SkipLayerNormInterleavedPluginMTronLegacy initialize");
return 0;
}
void SkipLayerNormInterleavedPluginHFaceLegacy::terminate() noexcept
{
BERT_DEBUG_MSG("SkipLayerNormInterleavedPluginHFaceLegacy terminate");
}
void SkipLayerNormInterleavedPluginMTronLegacy::terminate() noexcept
{
BERT_DEBUG_MSG("SkipLayerNormInterleavedPluginMTronLegacy terminate");
}
size_t SkipLayerNormInterleavedPluginBaseLegacy::getSerializationSize() const noexcept
{
return 2 * mParamWordsize * mLd + sizeof(mLd);
}
void SkipLayerNormInterleavedPluginBaseLegacy::serialize(void* buffer) const noexcept
{
try
{
serialize_value(&buffer, mLd);
char* d = static_cast<char*>(buffer);
serFromDev(d, static_cast<char*>(mBetaDev.get()), mLd * mParamWordsize);
serFromDev(d, static_cast<char*>(mGammaDev.get()), mLd * mParamWordsize);
}
catch (std::exception const& e)
{
caughtError(e);
}
}
void SkipLayerNormInterleavedPluginBaseLegacy::destroy() noexcept
{
try
{
// This gets called when the network containing plugin is destroyed
mGammaDev.reset(nullptr);
mBetaDev.reset(nullptr);
delete this;
}
catch (std::exception const& e)
{
caughtError(e);
}
}
void SkipLayerNormInterleavedPluginHFaceLegacy::destroy() noexcept
{
BERT_DEBUG_MSG("SkipLayerNormInterleavedPluginHFaceLegacy destroy");
SkipLayerNormInterleavedPluginBaseLegacy::destroy();
}
void SkipLayerNormInterleavedPluginMTronLegacy::destroy() noexcept
{
BERT_DEBUG_MSG("SkipLayerNormInterleavedPluginMTronLegacy destroy");
SkipLayerNormInterleavedPluginBaseLegacy::destroy();
}
void SkipLayerNormInterleavedPluginBaseLegacy::setPluginNamespace(char const* libNamespace) noexcept
{
mNamespace = libNamespace;
}
char const* SkipLayerNormInterleavedPluginBaseLegacy::getPluginNamespace() const noexcept
{
return mNamespace.c_str();
}
/////////////////////////////////////////////////////////
SkipLayerNormInterleavedPluginBaseLegacyCreator::SkipLayerNormInterleavedPluginBaseLegacyCreator()
{
mPluginAttributes.clear();
mPluginAttributes.emplace_back(PluginField("beta"));
mPluginAttributes.emplace_back(PluginField("gamma"));
mFC.nbFields = mPluginAttributes.size();
mFC.fields = mPluginAttributes.data();
}
SkipLayerNormInterleavedPluginHFaceLegacyCreator::SkipLayerNormInterleavedPluginHFaceLegacyCreator()
: SkipLayerNormInterleavedPluginBaseLegacyCreator()
{
}
SkipLayerNormInterleavedPluginMTronLegacyCreator::SkipLayerNormInterleavedPluginMTronLegacyCreator()
: SkipLayerNormInterleavedPluginBaseLegacyCreator()
{
}
char const* SkipLayerNormInterleavedPluginBaseLegacyCreator::getPluginName() const noexcept
{
return kSKIP_LAYER_NORM_INTERLEAVED_NAME;
}
char const* SkipLayerNormInterleavedPluginHFaceLegacyCreator::getPluginVersion() const noexcept
{
return kSKIP_LAYER_NORM_INTERLEAVED_VERSION_HFACE_LEGACY;
}
char const* SkipLayerNormInterleavedPluginMTronLegacyCreator::getPluginVersion() const noexcept
{
return kSKIP_LAYER_NORM_INTERLEAVED_VERSION_MTRON_LEGACY;
}
PluginFieldCollection const* SkipLayerNormInterleavedPluginBaseLegacyCreator::getFieldNames() noexcept
{
return &mFC;
}
IPluginV2* SkipLayerNormInterleavedPluginHFaceLegacyCreator::createPlugin(
char const* name, PluginFieldCollection const* fc) noexcept
{
try
{
BERT_DEBUG_MSG("SkipLayerNormInterleavedPluginHFaceLegacyCreator createPlugin");
Weights beta{DataType::kFLOAT, nullptr, 0};
Weights gamma{DataType::kFLOAT, nullptr, 0};
buildBetaAndGamma(fc, beta, gamma);
return new SkipLayerNormInterleavedPluginHFaceLegacy(name, beta, gamma);
}
catch (std::exception const& e)
{
caughtError(e);
}
return nullptr;
}
IPluginV2* SkipLayerNormInterleavedPluginMTronLegacyCreator::createPlugin(
char const* name, PluginFieldCollection const* fc) noexcept
{
try
{
BERT_DEBUG_MSG("SkipLayerNormInterleavedPluginMTronLegacyCreator createPlugin");
PLUGIN_VALIDATE(fc != nullptr);
Weights beta{DataType::kFLOAT, nullptr, 0};
Weights gamma{DataType::kFLOAT, nullptr, 0};
buildBetaAndGamma(fc, beta, gamma);
return new SkipLayerNormInterleavedPluginMTronLegacy(name, beta, gamma);
}
catch (std::exception const& e)
{
caughtError(e);
}
return nullptr;
}
IPluginV2* SkipLayerNormInterleavedPluginHFaceLegacyCreator::deserializePlugin(
char const* name, void const* serialData, size_t serialLength) noexcept
{
// This object will be deleted when the network is destroyed, which will
// call SkipLayerNormInterleavedPlugin::destroy()
try
{
BERT_DEBUG_MSG("SkipLayerNormInterleavedPluginHFaceLegacyCreator deserializePlugin");
return new SkipLayerNormInterleavedPluginHFaceLegacy(name, serialData, serialLength);
}
catch (std::exception const& e)
{
caughtError(e);
}
return nullptr;
}
IPluginV2* SkipLayerNormInterleavedPluginMTronLegacyCreator::deserializePlugin(
char const* name, void const* serialData, size_t serialLength) noexcept
{
// This object will be deleted when the network is destroyed, which will
// call SkipLayerNormInterleavedPlugin::destroy()
try
{
BERT_DEBUG_MSG("SkipLayerNormInterleavedPluginMTronLegacyCreator deserializePlugin");
return new SkipLayerNormInterleavedPluginMTronLegacy(name, serialData, serialLength);
}
catch (std::exception const& e)
{
caughtError(e);
}
return nullptr;
}
void SkipLayerNormInterleavedPluginBaseLegacyCreator::setPluginNamespace(char const* libNamespace) noexcept
{
mNamespace = libNamespace;
}
char const* SkipLayerNormInterleavedPluginBaseLegacyCreator::getPluginNamespace() const noexcept
{
return mNamespace.c_str();
}
@@ -0,0 +1,195 @@
/*
* 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_SKIP_LAYER_NORM_INTERLEAVED_PLUGIN_LEGACY_H
#define TRT_SKIP_LAYER_NORM_INTERLEAVED_PLUGIN_LEGACY_H
#include "NvInferPlugin.h"
#include <cuda.h>
#include "common/bertCommon.h"
#include <memory>
#include <string>
#include <vector>
namespace nvinfer1
{
namespace plugin
{
namespace bert
{
int32_t launch_small_hface(cudaStream_t stream, int32_t const ld, int32_t const total, int8_t const* input,
int8_t const* skip, half const* beta, half const* gamma, int8_t* output, float const dqScaleIn,
float const dqScaleSkip, float const qScale);
int32_t launch_large_hface(cudaStream_t stream, int32_t const ld, int32_t const total, int8_t const* input,
int8_t const* skip, half const* beta, half const* gamma, int8_t* output, float const dqScaleIn,
float const dqScaleSkip, float const qScale);
int32_t launch_small_mtron(cudaStream_t stream, int32_t const ld, int32_t const total, int8_t const* input,
int8_t const* skip, half const* beta, half const* gamma, int8_t* output, int8_t* preln, float const dqScaleIn,
float const dqScaleSkip, float const qScale, float const qSkipScale);
int32_t launch_large_mtron(cudaStream_t stream, int32_t const ld, int32_t const total, int8_t const* input,
int8_t const* skip, half const* beta, half const* gamma, int8_t* output, int8_t* preln, float const dqScaleIn,
float const dqScaleSkip, float const qScale, float const qSkipScale);
class SkipLayerNormInterleavedPluginBaseLegacy : public nvinfer1::IPluginV2DynamicExt
{
public:
SkipLayerNormInterleavedPluginBaseLegacy(
std::string const& name, nvinfer1::Weights const& beta, nvinfer1::Weights const& gamma);
SkipLayerNormInterleavedPluginBaseLegacy(std::string const& name, void const* data, size_t length);
// It doesn't make sense to make SkipLayerNormInterleavedPlugin without
// arguments, so we delete default constructor.
SkipLayerNormInterleavedPluginBaseLegacy() = delete;
// IPluginV2DynamicExt Methods
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;
// 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;
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;
protected:
std::string const& mLayerName;
std::string mNamespace;
bert::cuda_unique_ptr<void> mGammaDev;
bert::cuda_unique_ptr<void> mBetaDev;
size_t mLd{}; // leading dim
bert::WeightsWithOwnership mGamma;
bert::WeightsWithOwnership mBeta;
size_t mParamWordsize{};
bool mParamsOnDevice{};
};
class SkipLayerNormInterleavedPluginHFaceLegacy : public SkipLayerNormInterleavedPluginBaseLegacy
{
public:
SkipLayerNormInterleavedPluginHFaceLegacy(
std::string const& name, nvinfer1::Weights const& beta, nvinfer1::Weights const& gamma);
SkipLayerNormInterleavedPluginHFaceLegacy(std::string const& name, void const* data, size_t length);
// It doesn't make sense to make SkipLayerNormInterleavedPlugin without
// arguments, so we delete default constructor.
SkipLayerNormInterleavedPluginHFaceLegacy() = delete;
// IPluginV2DynamicExt Methods
nvinfer1::IPluginV2DynamicExt* clone() 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;
// IPluginV2 Methods
int32_t initialize() noexcept override;
void terminate() noexcept override;
void destroy() noexcept override;
char const* getPluginVersion() const noexcept override;
int32_t getNbOutputs() const noexcept override;
};
class SkipLayerNormInterleavedPluginMTronLegacy : public SkipLayerNormInterleavedPluginBaseLegacy
{
public:
SkipLayerNormInterleavedPluginMTronLegacy(
std::string const& name, nvinfer1::Weights const& beta, nvinfer1::Weights const& gamma);
SkipLayerNormInterleavedPluginMTronLegacy(std::string const& name, void const* data, size_t length);
// It doesn't make sense to make SkipLayerNormInterleavedPlugin without
// arguments, so we delete default constructor.
SkipLayerNormInterleavedPluginMTronLegacy() = delete;
// IPluginV2DynamicExt Methods
nvinfer1::IPluginV2DynamicExt* clone() 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;
// IPluginV2 Methods
int32_t initialize() noexcept override;
void terminate() noexcept override;
void destroy() noexcept override;
char const* getPluginVersion() const noexcept override;
int32_t getNbOutputs() const noexcept override;
};
class SkipLayerNormInterleavedPluginBaseLegacyCreator : public nvinfer1::IPluginCreator
{
public:
SkipLayerNormInterleavedPluginBaseLegacyCreator();
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;
private:
nvinfer1::PluginFieldCollection mFC;
std::vector<nvinfer1::PluginField> mPluginAttributes;
std::string mNamespace;
};
class SkipLayerNormInterleavedPluginHFaceLegacyCreator : public SkipLayerNormInterleavedPluginBaseLegacyCreator
{
public:
SkipLayerNormInterleavedPluginHFaceLegacyCreator();
char const* getPluginVersion() const 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;
};
class SkipLayerNormInterleavedPluginMTronLegacyCreator : public SkipLayerNormInterleavedPluginBaseLegacyCreator
{
public:
SkipLayerNormInterleavedPluginMTronLegacyCreator();
char const* getPluginVersion() const 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;
};
} // namespace bert
} // namespace plugin
} // namespace nvinfer1
#endif // TRT_SKIP_LAYER_NORM_INTERLEAVED_PLUGIN_LEGACY_H
@@ -0,0 +1,307 @@
/*
* 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 <cuda.h>
#if CUDA_VERSION >= 10010
#include "NvInfer.h"
#include "common/bertCommon.h"
#include "common/common.cuh"
#include "common/serialize.hpp"
#include "skipLayerNormPlugin.h"
#include "skipLayerNormPluginLegacy.h"
#include <cassert>
#include <cstring>
#include <limits>
#include <vector>
using namespace nvinfer1;
using namespace nvinfer1::plugin;
namespace nvinfer1
{
namespace plugin
{
namespace bert
{
template <int32_t TPB, int32_t VPT, bool hasBias>
__global__ void skiplnDQQ(int32_t const ld, int8_t const* input, int8_t const* skip, int8_t* output, __half const* beta,
__half const* gamma, __half const* bias, float const dqScaleIn, float const dqScaleSkip, float const qScale)
{
int32_t const idx = ld * blockIdx.x + threadIdx.x * VPT;
// 4 * 1024 * 4 * 2 Bytes = 16KB per block
int8_t inLocal[VPT];
int8_t skipLocal[VPT];
__half inLocalDQ[VPT]; // dequantized input + skip + bias
__half biasLocal[VPT]; // bias and beta
__half gammaLocal[VPT];
copy<sizeof(int8_t) * VPT>(&input[idx], inLocal);
copy<sizeof(int8_t) * VPT>(&skip[idx], skipLocal);
copy<sizeof(__half) * VPT>(&bias[threadIdx.x * VPT], biasLocal);
__half2 loc = __floats2half2_rn(0.f, 0.f); // accumulator
const __half rld = __half(1) / __half(ld);
#pragma unroll
for (int32_t it = 0; it < VPT; it++)
{
// DQ input and skip
float const tmpIn = inLocal[it];
float const tmpSkip = skipLocal[it];
inLocalDQ[it] = dqScaleIn * tmpIn + dqScaleSkip * tmpSkip;
if (hasBias)
inLocalDQ[it] += biasLocal[it];
const __half tmp = rld * inLocalDQ[it];
const __half2 tmp2 = __halves2half2(tmp, tmp * inLocalDQ[it]);
loc = loc + tmp2;
}
// load parameters
copy<sizeof(__half) * VPT>(&beta[threadIdx.x * VPT], biasLocal);
copy<sizeof(__half) * VPT>(&gamma[threadIdx.x * VPT], gammaLocal);
using BlockReduce = cub::BlockReduce<__half2, TPB>;
__shared__ typename BlockReduce::TempStorage tempStorage;
__shared__ __half mu; // mean
__shared__ __half rsigma; // 1 / std.dev.
const __half2 sum2 = BlockReduce(tempStorage).Reduce(loc, [](auto const& lhs, auto const& rhs){return lhs + rhs;});
if (threadIdx.x == 0)
{
mu = __low2half(sum2);
rsigma = rsqrt(__high2half(sum2) - mu * mu + std::numeric_limits<half>::epsilon());
}
__syncthreads();
static_assert(VPT % 4 == 0, "");
uint32_t outLocal[VPT / 4U];
#pragma unroll
for (int32_t it = 0; it < VPT / 4U; it++)
{
float const tmp0 = gammaLocal[it * 4 + 0] * (inLocalDQ[it * 4 + 0] - mu) * rsigma + biasLocal[it * 4 + 0];
float const tmp1 = gammaLocal[it * 4 + 1] * (inLocalDQ[it * 4 + 1] - mu) * rsigma + biasLocal[it * 4 + 1];
float const tmp2 = gammaLocal[it * 4 + 2] * (inLocalDQ[it * 4 + 2] - mu) * rsigma + biasLocal[it * 4 + 2];
float const tmp3 = gammaLocal[it * 4 + 3] * (inLocalDQ[it * 4 + 3] - mu) * rsigma + biasLocal[it * 4 + 3];
outLocal[it] = float4_to_char4(tmp0 * qScale, tmp1 * qScale, tmp2 * qScale, tmp3 * qScale);
}
copy<sizeof(int8_t) * VPT>(outLocal, &output[idx]);
}
template <typename T, int32_t TPB, int32_t VPT, bool hasBias>
__global__ void skipln_vec(
int32_t const ld, const T* input, const T* skip, T* output, const T* beta, const T* gamma, const T* bias)
{
int32_t const idx = ld * blockIdx.x + threadIdx.x * VPT;
// 4 * 1024 * 4 * 2 Bytes = 16KB per block
T inLocal[VPT];
T skipLocal[VPT];
T biasLocal[VPT];
// T gammaLocal[VPT];
copy<sizeof(T) * VPT>(&input[idx], inLocal);
copy<sizeof(T) * VPT>(&skip[idx], skipLocal);
copy<sizeof(T) * VPT>(&bias[threadIdx.x * VPT], biasLocal);
T local = 0.f;
T local2 = 0.f;
const T rld = T(1) / T(ld);
#pragma unroll
for (int32_t it = 0; it < VPT; it++)
{
inLocal[it] += skipLocal[it];
if (hasBias)
inLocal[it] += biasLocal[it];
const T tmp = rld * inLocal[it];
local += tmp;
local2 += tmp * inLocal[it];
}
copy<sizeof(T) * VPT>(&beta[threadIdx.x * VPT], biasLocal);
copy<sizeof(T) * VPT>(&gamma[threadIdx.x * VPT], skipLocal);
using BlockReduce = cub::BlockReduce<kvp<T>, TPB>;
__shared__ typename BlockReduce::TempStorage tempStorage;
__shared__ T mu; // mean
__shared__ T rsigma; // 1 / std.dev.
auto const sumKV = BlockReduce(tempStorage).Reduce(kvp<T>(local, local2), [](auto const& lhs, auto const& rhs){return lhs + rhs;});
if (threadIdx.x == 0)
{
mu = sumKV.key;
rsigma = rsqrt(sumKV.value - mu * mu + std::numeric_limits<T>::epsilon());
}
__syncthreads();
///*
#pragma unroll
for (int32_t it = 0; it < VPT; it++)
{
inLocal[it] = skipLocal[it] * (inLocal[it] - mu) * rsigma + biasLocal[it];
}
/* */
copy<sizeof(T) * VPT>(inLocal, &output[idx]);
}
template <typename T, unsigned TPB, bool hasBias>
__global__ void skipLayerNormKernelSmall(
int32_t const ld, const T* input, const T* skip, const T* beta, const T* gamma, T* output, const T* bias)
{
const T rld = T(1) / T(ld);
int32_t const offset = blockIdx.x * ld;
// reduce x and x^2
kvp<T> threadData(0, 0);
int32_t const idx = offset + threadIdx.x;
T val = 0;
if (threadIdx.x < ld)
{
val = input[idx] + skip[idx];
if (hasBias)
{
val += bias[threadIdx.x];
}
const T rldval = rld * val;
threadData = threadData + kvp<T>(rldval, rldval * val);
}
layerNormSmall<T, T, TPB>(val, threadData, ld, idx, beta, gamma, output);
}
template <typename T, unsigned TPB, bool hasBias>
__global__ void skipLayerNormKernel(
int32_t const ld, const T* input, const T* skip, const T* beta, const T* gamma, T* output, const T* bias)
{
const T rld = T(1) / T(ld);
int32_t const offset = blockIdx.x * ld;
// reduce x and x^2
kvp<T> threadData(0, 0);
for (int32_t i = threadIdx.x; i < ld; i += TPB)
{
int32_t const idx = offset + i;
T val = T(input[idx]) + T(skip[idx]);
if (hasBias)
{
val += T(bias[i]);
}
const T rldval = rld * val;
threadData = threadData + kvp<T>(rldval, rldval * val);
output[idx] = val;
}
layerNorm<T, T, T, TPB>(threadData, ld, offset, beta, gamma, output);
}
template <bool hasBias>
int32_t computeSkipLayerNormDQQ(cudaStream_t stream, int32_t const ld, int32_t const n, int8_t const* input,
int8_t const* skip, __half const* beta, __half const* gamma, int8_t* output, __half const* bias,
float const dqScaleIn, float const dqScaleSkip, float const qScale)
{
// this must be true because n is the total size of the tensor
PLUGIN_VALIDATE(n % ld == 0);
int32_t const gridSize = n / ld;
// we're limited by the size of the parameters, i.e. 8-wide instead of 16
constexpr int32_t VPT = 16 / sizeof(__half);
if (ld == 768)
{
constexpr int32_t TPB = 768 / VPT;
skiplnDQQ<TPB, VPT, hasBias>
<<<gridSize, TPB, 0, stream>>>(ld, input, skip, output, beta, gamma, bias, dqScaleIn, dqScaleSkip, qScale);
}
else if (ld == 1024)
{
constexpr int32_t TPB = 1024 / VPT;
skiplnDQQ<TPB, VPT, hasBias>
<<<gridSize, TPB, 0, stream>>>(ld, input, skip, output, beta, gamma, bias, dqScaleIn, dqScaleSkip, qScale);
}
else
{
// TODO need to implement this
PLUGIN_ERROR(("SkipLayerNormDQQ - FATAL: unsupported hidden layer size: " + std::to_string(ld)).c_str());
}
PLUGIN_CHECK(cudaPeekAtLastError());
return 0;
}
template <typename T, bool hasBias>
int32_t computeSkipLayerNorm(cudaStream_t stream, int32_t const ld, int32_t const n, const T* input, const T* skip,
const T* beta, const T* gamma, T* output, const T* bias)
{
// this must be true because n is the total size of the tensor
PLUGIN_VALIDATE(n % ld == 0);
int32_t const gridSize = n / ld;
constexpr int32_t VPT = 16 / sizeof(T);
if (ld <= 32)
{
constexpr int32_t blockSize = 32;
skipLayerNormKernelSmall<T, blockSize, hasBias>
<<<gridSize, blockSize, 0, stream>>>(ld, input, skip, beta, gamma, output, bias);
}
else if (ld == 768)
{
constexpr int32_t TPB = 768 / VPT;
skipln_vec<T, TPB, VPT, hasBias><<<gridSize, TPB, 0, stream>>>(ld, input, skip, output, beta, gamma, bias);
}
else if (ld == 1024)
{
constexpr int32_t TPB = 1024 / VPT;
skipln_vec<T, TPB, VPT, hasBias><<<gridSize, TPB, 0, stream>>>(ld, input, skip, output, beta, gamma, bias);
}
else
{
constexpr int32_t blockSize = 256;
skipLayerNormKernel<T, blockSize, hasBias>
<<<gridSize, blockSize, 0, stream>>>(ld, input, skip, beta, gamma, output, bias);
}
PLUGIN_CHECK(cudaPeekAtLastError());
return 0;
}
template int32_t computeSkipLayerNormDQQ<true>(cudaStream_t stream, int32_t const ld, int32_t const n,
int8_t const* input, int8_t const* skip, __half const* beta, __half const* gamma, int8_t* output,
__half const* bias, float const dqScaleIn, float const dqScaleSkip, float const qScale);
template int32_t computeSkipLayerNormDQQ<false>(cudaStream_t stream, int32_t const ld, int32_t const n,
int8_t const* input, int8_t const* skip, __half const* beta, __half const* gamma, int8_t* output,
__half const* bias, float const dqScaleIn, float const dqScaleSkip, float const qScale);
template int32_t computeSkipLayerNorm<float, true>(cudaStream_t, int32_t const, int32_t const, float const*,
float const*, float const*, float const*, float*, float const*);
template int32_t computeSkipLayerNorm<float, false>(cudaStream_t, int32_t const, int32_t const, float const*,
float const*, float const*, float const*, float*, float const*);
template int32_t computeSkipLayerNorm<half, true>(
cudaStream_t, int32_t const, int32_t const, half const*, half const*, half const*, half const*, half*, half const*);
template int32_t computeSkipLayerNorm<half, false>(
cudaStream_t, int32_t const, int32_t const, half const*, half const*, half const*, half const*, half*, half const*);
} // namespace bert
} // namespace plugin
} // namespace nvinfer1
#endif // CUDA_VERSION >= 10010
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,274 @@
/*
* 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_SKIP_LAYER_NORM_PLUGIN_H
#define TRT_SKIP_LAYER_NORM_PLUGIN_H
#include "NvInferPlugin.h"
#include "common/bertCommon.h"
#include <memory>
#include <string>
#include <vector>
namespace nvinfer1
{
namespace plugin
{
namespace bert
{
template <bool hasBias>
int32_t computeSkipLayerNormDQQ(cudaStream_t stream, int32_t const ld, int32_t const n, int8_t const* input,
int8_t const* skip, __half const* beta, __half const* gamma, int8_t* output, __half const* bias,
float const dqScaleIn, float const dqScaleSkip, float const qScale);
template <typename T, bool hasBias>
int32_t computeSkipLayerNorm(cudaStream_t stream, int32_t const ld, int32_t const n, T const* input, T const* skip,
T const* beta, T const* gamma, T* output, T const* bias);
class SkipLayerNormPluginV3 : public IPluginV3,
public IPluginV3OneCore,
public IPluginV3OneBuild,
public IPluginV3OneRuntime
{
public:
SkipLayerNormPluginV3(const std::string name, const nvinfer1::DataType type, int32_t const ld,
nvinfer1::Weights const& beta, nvinfer1::Weights const& gamma, nvinfer1::Weights const& bias);
// It doesn't make sense to make SkipLayerNormPluginV3 without arguments,
// so we delete default constructor.
SkipLayerNormPluginV3() = delete;
~SkipLayerNormPluginV3() override;
// IPluginV3 Methods
IPluginCapability* getCapabilityInterface(PluginCapabilityType type) noexcept override;
IPluginV3* clone() noexcept override;
// end of IPluginV3 Methods
// IPluginV3OneCore Methods
char const* getPluginName() const noexcept override;
char const* getPluginVersion() const noexcept override;
char const* getPluginNamespace() const noexcept override;
void setPluginNamespace(char const* pluginNamespace) noexcept;
// end of IPluginV3OneCore Methods
// IPluginV3Build Methods
int32_t getNbOutputs() const noexcept override;
bool supportsFormatCombination(
int32_t pos, DynamicPluginTensorDesc const* inOut, int32_t nbInputs, int32_t nbOutputs) 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;
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;
// end IPluginV3Build Methods
// IPluginV3Runtime Methods
int32_t enqueue(nvinfer1::PluginTensorDesc const* inputDesc, nvinfer1::PluginTensorDesc const* outputDesc,
void const* const* inputs, void* const* outputs, void* workspace, cudaStream_t stream) noexcept override;
int32_t onShapeChange(
PluginTensorDesc const* in, int32_t nbInputs, PluginTensorDesc const* out, int32_t nbOutputs) noexcept override;
IPluginV3* attachToContext(IPluginResourceContext* context) noexcept override;
PluginFieldCollection const* getFieldsToSerialize() noexcept override;
// end IPluginV3Runtime Methods
private:
// metadata
const std::string mLayerName;
std::string mNamespace;
// members that participate in ser/deserialization
bert::WeightsWithOwnership mGamma;
bert::WeightsWithOwnership mBeta;
bert::WeightsWithOwnership mBias;
nvinfer1::DataType mType;
nvinfer1::DataType mCfgType;
int32_t mLd{}; // leading dim
bool mHasBias{};
// device-side
bert::cuda_unique_ptr<void> mGammaDev;
bert::cuda_unique_ptr<void> mBetaDev;
bert::cuda_unique_ptr<void> mBiasDev;
// derived member from mCfgType
size_t mParamWordsize{};
// serialization data structures
std::vector<nvinfer1::PluginField> mDataToSerialize;
nvinfer1::PluginFieldCollection mFCToSerialize;
};
class SkipLayerNormPluginV3Creator : public nvinfer1::IPluginCreatorV3One
{
public:
SkipLayerNormPluginV3Creator();
~SkipLayerNormPluginV3Creator() 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* libNamespace) noexcept;
char const* getPluginNamespace() const noexcept override;
private:
PluginFieldCollection mFC;
std::vector<PluginField> mPluginAttributes;
std::string mNamespace;
};
class SkipLayerNormVarSeqlenPluginV3 : public IPluginV3,
public IPluginV3OneCore,
public IPluginV3OneBuild,
public IPluginV3OneRuntime
{
public:
SkipLayerNormVarSeqlenPluginV3(const std::string name, const nvinfer1::DataType type, nvinfer1::Weights const& beta,
nvinfer1::Weights const& gamma, nvinfer1::Weights const& bias);
SkipLayerNormVarSeqlenPluginV3(const std::string name, void const* data, size_t length);
// It doesn't make sense to make SkipLayerNormVarSeqlenPluginV3 without
// arguments, so we delete default constructor.
SkipLayerNormVarSeqlenPluginV3() = delete;
~SkipLayerNormVarSeqlenPluginV3() override;
// IPluginV3 Methods
IPluginCapability* getCapabilityInterface(PluginCapabilityType type) noexcept override;
IPluginV3* clone() noexcept override;
// end of IPluginV3 Methods
// IPluginV3OneCore Methods
char const* getPluginName() const noexcept override;
char const* getPluginVersion() const noexcept override;
char const* getPluginNamespace() const noexcept override;
void setPluginNamespace(char const* pluginNamespace) noexcept;
// end of IPluginV3OneCore Methods
// IPluginV3Build Methods
int32_t getNbOutputs() const noexcept override;
bool supportsFormatCombination(
int32_t pos, DynamicPluginTensorDesc const* inOut, int32_t nbInputs, int32_t nbOutputs) 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;
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;
// end IPluginV3Build Methods
// IPluginV3Runtime Methods
int32_t enqueue(nvinfer1::PluginTensorDesc const* inputDesc, nvinfer1::PluginTensorDesc const* outputDesc,
void const* const* inputs, void* const* outputs, void* workspace, cudaStream_t stream) noexcept override;
int32_t onShapeChange(
PluginTensorDesc const* in, int32_t nbInputs, PluginTensorDesc const* out, int32_t nbOutputs) noexcept override;
IPluginV3* attachToContext(IPluginResourceContext* context) noexcept override;
PluginFieldCollection const* getFieldsToSerialize() noexcept override;
// end IPluginV3Runtime Methods
private:
const std::string mLayerName;
std::string mNamespace;
bert::cuda_unique_ptr<void> mGammaDev;
bert::cuda_unique_ptr<void> mBetaDev;
int32_t mLd{}; // leading dim
bert::WeightsWithOwnership mGamma;
bert::WeightsWithOwnership mBeta;
nvinfer1::DataType mType;
nvinfer1::DataType mCfgType;
bool mHasBias{};
bert::cuda_unique_ptr<void> mBiasDev;
bert::WeightsWithOwnership mBias;
size_t mParamWordsize{};
std::vector<nvinfer1::PluginField> mDataToSerialize;
nvinfer1::PluginFieldCollection mFCToSerialize;
};
class SkipLayerNormVarSeqlenPluginV3Creator : public nvinfer1::IPluginCreatorV3One
{
public:
SkipLayerNormVarSeqlenPluginV3Creator();
~SkipLayerNormVarSeqlenPluginV3Creator() override = default;
char const* getPluginName() const noexcept override;
char const* getPluginVersion() const noexcept override;
PluginFieldCollection const* getFieldNames() noexcept override;
IPluginV3* createPlugin(char const* name, PluginFieldCollection const* fc, TensorRTPhase phase) noexcept override;
void setPluginNamespace(char const* libNamespace) 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_SKIP_LAYER_NORM_PLUGIN_H
#endif // CUDA_VERSION >= 10010
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,233 @@
/*
* 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_SKIP_LAYER_NORM_PLUGIN_H
#define TRT_SKIP_LAYER_NORM_PLUGIN_H
#include "NvInferPlugin.h"
#include "common/bertCommon.h"
#include <memory>
#include <string>
#include <vector>
namespace nvinfer1
{
namespace plugin
{
namespace bert
{
template <bool hasBias>
int32_t computeSkipLayerNormDQQ(cudaStream_t stream, int32_t const ld, int32_t const n, int8_t const* input,
int8_t const* skip, __half const* beta, __half const* gamma, int8_t* output, __half const* bias,
float const dqScaleIn, float const dqScaleSkip, float const qScale);
template <typename T, bool hasBias>
int32_t computeSkipLayerNorm(cudaStream_t stream, int32_t const ld, int32_t const n, T const* input, T const* skip,
T const* beta, T const* gamma, T* output, T const* bias);
class SkipLayerNormPluginDynamic : public nvinfer1::IPluginV2DynamicExt
{
public:
SkipLayerNormPluginDynamic(const std::string name, const nvinfer1::DataType type, int32_t const ld,
nvinfer1::Weights const& beta, nvinfer1::Weights const& gamma, nvinfer1::Weights const& bias);
SkipLayerNormPluginDynamic(const std::string name, void const* data, size_t length);
// It doesn't make sense to make SkipLayerNormPluginDynamic without arguments,
// so we delete default constructor.
SkipLayerNormPluginDynamic() = 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:
const std::string mLayerName;
std::string mNamespace;
bert::cuda_unique_ptr<void> mGammaDev;
bert::cuda_unique_ptr<void> mBetaDev;
size_t mLd{}; // leading dim
bert::WeightsWithOwnership mGamma;
bert::WeightsWithOwnership mBeta;
nvinfer1::DataType mType;
nvinfer1::DataType mCfgType;
bool mHasBias{};
bert::cuda_unique_ptr<void> mBiasDev;
bert::WeightsWithOwnership mBias;
size_t mParamWordsize{};
using IPluginV2::enqueue;
using IPluginV2::getOutputDimensions;
using IPluginV2::getWorkspaceSize;
using IPluginV2Ext::configurePlugin;
};
class SkipLayerNormPluginDynamicCreator : public nvinfer1::IPluginCreator
{
public:
SkipLayerNormPluginDynamicCreator();
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;
};
class SkipLayerNormVarSeqlenPlugin : public nvinfer1::IPluginV2DynamicExt
{
public:
SkipLayerNormVarSeqlenPlugin(const std::string name, const nvinfer1::DataType type, nvinfer1::Weights const& beta,
nvinfer1::Weights const& gamma, nvinfer1::Weights const& bias);
SkipLayerNormVarSeqlenPlugin(const std::string name, void const* data, size_t length);
// It doesn't make sense to make SkipLayerNormVarSeqlenPlugin without
// arguments, so we delete default constructor.
SkipLayerNormVarSeqlenPlugin() = 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:
const std::string mLayerName;
std::string mNamespace;
bert::cuda_unique_ptr<void> mGammaDev;
bert::cuda_unique_ptr<void> mBetaDev;
size_t mLd{}; // leading dim
bert::WeightsWithOwnership mGamma;
bert::WeightsWithOwnership mBeta;
nvinfer1::DataType mType;
nvinfer1::DataType mCfgType;
bool mHasBias{};
bert::cuda_unique_ptr<void> mBiasDev;
bert::WeightsWithOwnership mBias;
size_t mParamWordsize{};
using IPluginV2::enqueue;
using IPluginV2::getOutputDimensions;
using IPluginV2::getWorkspaceSize;
using IPluginV2Ext::configurePlugin;
};
class SkipLayerNormVarSeqlenPluginCreator : public nvinfer1::IPluginCreator
{
public:
SkipLayerNormVarSeqlenPluginCreator();
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_SKIP_LAYER_NORM_PLUGIN_H
#endif // CUDA_VERSION >= 10010