/* * 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 #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 #include #include #include using namespace nvinfer1; using namespace nvinfer1::plugin; namespace nvinfer1 { namespace plugin { namespace bert { template __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(&input[idx], inLocal); copy(&skip[idx], skipLocal); copy(&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(&beta[threadIdx.x * VPT], biasLocal); copy(&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::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(outLocal, &output[idx]); } template __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(&input[idx], inLocal); copy(&skip[idx], skipLocal); copy(&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(&beta[threadIdx.x * VPT], biasLocal); copy(&gamma[threadIdx.x * VPT], skipLocal); using BlockReduce = cub::BlockReduce, TPB>; __shared__ typename BlockReduce::TempStorage tempStorage; __shared__ T mu; // mean __shared__ T rsigma; // 1 / std.dev. auto const sumKV = BlockReduce(tempStorage).Reduce(kvp(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::epsilon()); } __syncthreads(); ///* #pragma unroll for (int32_t it = 0; it < VPT; it++) { inLocal[it] = skipLocal[it] * (inLocal[it] - mu) * rsigma + biasLocal[it]; } /* */ copy(inLocal, &output[idx]); } template __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 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(rldval, rldval * val); } layerNormSmall(val, threadData, ld, idx, beta, gamma, output); } template __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 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(rldval, rldval * val); output[idx] = val; } layerNorm(threadData, ld, offset, beta, gamma, output); } template 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 <<>>(ld, input, skip, output, beta, gamma, bias, dqScaleIn, dqScaleSkip, qScale); } else if (ld == 1024) { constexpr int32_t TPB = 1024 / VPT; skiplnDQQ <<>>(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 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 <<>>(ld, input, skip, beta, gamma, output, bias); } else if (ld == 768) { constexpr int32_t TPB = 768 / VPT; skipln_vec<<>>(ld, input, skip, output, beta, gamma, bias); } else if (ld == 1024) { constexpr int32_t TPB = 1024 / VPT; skipln_vec<<>>(ld, input, skip, output, beta, gamma, bias); } else { constexpr int32_t blockSize = 256; skipLayerNormKernel <<>>(ld, input, skip, beta, gamma, output, bias); } PLUGIN_CHECK(cudaPeekAtLastError()); return 0; } template 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 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 int32_t computeSkipLayerNorm(cudaStream_t, int32_t const, int32_t const, float const*, float const*, float const*, float const*, float*, float const*); template int32_t computeSkipLayerNorm(cudaStream_t, int32_t const, int32_t const, float const*, float const*, float const*, float const*, float*, float const*); template int32_t computeSkipLayerNorm( cudaStream_t, int32_t const, int32_t const, half const*, half const*, half const*, half const*, half*, half const*); template int32_t computeSkipLayerNorm( 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