Files
nvidia--tensorrt/plugin/roiAlignPlugin/roiAlignKernel.cu
T
wehub-resource-sync c8a779b1bb
Docker Image CI / build-ubuntu2004 (push) Waiting to run
chore: import upstream snapshot with attribution
2026-07-13 13:36:55 +08:00

280 lines
10 KiB
Plaintext

/*
* 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.
*
* ************************************************************************
* Modified from Pytorch
* Copyright (c) 2016-present, Facebook, Inc.
*
* See https://github.com/pytorch/pytorch/blob/main/LICENSE for details
* ************************************************************************
* Modified from ONNX Runtime
* Copyright (c) Microsoft Corporation
*
* See https://github.com/microsoft/onnxruntime/blob/main/LICENSE for details
* ************************************************************************
*/
#include <cuda.h>
#include <cuda_fp16.h>
#include "common/common.cuh"
#include "roiAlignKernel.h"
using half = __half;
__device__ half floatMax(half a, half b)
{
#if __CUDA_ARCH__ >= 800
return __hmax(a, b);
#else
return __float2half(max(__half2float(a), __half2float(b)));
#endif
}
__device__ float floatMax(float a, float b)
{
return max(a, b);
}
template <typename T>
__device__ T bilinearInterpolate(T const* bottomData, int32_t const height, int32_t const width, T y, T x,
int32_t const isModeAvg, int32_t const index /* index for debug only*/)
{
// deal with cases that inverse elements are out of feature map boundary
if (y < static_cast<T>(-1.0) || y > static_cast<T>(height) || x < static_cast<T>(-1.0) || x > static_cast<T>(width))
{
// empty
return 0;
}
if (y <= static_cast<T>(0))
{
y = 0;
}
if (x <= static_cast<T>(0))
{
x = 0;
}
int32_t yLow = static_cast<int32_t>(y);
int32_t xLow = static_cast<int32_t>(x);
int32_t yHigh;
int32_t xHigh;
if (yLow >= height - 1)
{
yHigh = yLow = height - 1;
y = static_cast<T>(yLow);
}
else
{
yHigh = yLow + 1;
}
if (xLow >= width - 1)
{
xHigh = xLow = width - 1;
x = static_cast<T>(xLow);
}
else
{
xHigh = xLow + 1;
}
T ly = y - static_cast<T>(yLow);
T lx = x - static_cast<T>(xLow);
T hy = static_cast<T>(1.) - ly, hx = static_cast<T>(1.) - lx;
// do bilinear interpolation
T v1 = bottomData[yLow * width + xLow];
T v2 = bottomData[yLow * width + xHigh];
T v3 = bottomData[yHigh * width + xLow];
T v4 = bottomData[yHigh * width + xHigh];
T w1 = hy * hx, w2 = hy * lx, w3 = ly * hx, w4 = ly * lx;
T val;
if (isModeAvg)
{
val = (w1 * v1 + w2 * v2 + w3 * v3 + w4 * v4); // mode Avg
}
else
{
val = floatMax(floatMax(floatMax(w1 * v1, w2 * v2), w3 * v3), w4 * v4); // mode Max
}
return val;
}
template <typename T>
__global__ void RoIAlignForward(int32_t const nthreads, T const* bottomData, T const spatialScale, int32_t const channels,
int32_t const height, int32_t const width, int32_t const pooledHeight, int32_t const pooledWidth, int32_t const samplingRatio,
T const* bottomRois, T* topData, int32_t const isModeAvg, int32_t const* batchIndicesPtr,
int32_t const aligned)
{
for (size_t index = blockIdx.x * blockDim.x + threadIdx.x; index < nthreads; index += blockDim.x * gridDim.x)
{
// (n, c, ph, pw) is an element in the pooled output
int32_t pw = index % pooledWidth;
int32_t ph = (index / pooledWidth) % pooledHeight;
int32_t c = (index / pooledWidth / pooledHeight) % channels;
int32_t n = index / pooledWidth / pooledHeight / channels;
T const* offsetBottomRois = bottomRois + n * 4;
auto const roiBatchInd = batchIndicesPtr[n];
bool continuousCoordinate = aligned;
// Do not using rounding; this implementation detail is critical
T roiOffset = static_cast<T>(continuousCoordinate ? 0.5 : 0);
T roiStartW = offsetBottomRois[0] * spatialScale - roiOffset;
T roiStartH = offsetBottomRois[1] * spatialScale - roiOffset;
T roiEndW = offsetBottomRois[2] * spatialScale - roiOffset;
T roiEndH = offsetBottomRois[3] * spatialScale - roiOffset;
T roiWidth = roiEndW - roiStartW;
T roiHeight = roiEndH - roiStartH;
if (!continuousCoordinate)
{ // backward compatibility
// Force malformed ROIs to be 1x1
roiWidth = floatMax(roiWidth, static_cast<T>(1.));
roiHeight = floatMax(roiHeight, static_cast<T>(1.));
}
T binSizeH = static_cast<T>(roiHeight) / static_cast<T>(pooledHeight);
T binSizeW = static_cast<T>(roiWidth) / static_cast<T>(pooledWidth);
T const* offsetBottomData = bottomData + static_cast<int32_t>((roiBatchInd * channels + c) * height * width);
// We use roiBinGrid to sample the grid and mimic integral
int32_t roiBinGridH;
if (samplingRatio > 0)
{
roiBinGridH = samplingRatio;
}
else
{
roiBinGridH = ceilf(roiHeight / static_cast<T>(pooledHeight));
}
int32_t roiBinGridW;
if (samplingRatio > 0)
{
roiBinGridW = samplingRatio;
}
else
{
roiBinGridW = ceilf(roiWidth / static_cast<T>(pooledWidth));
}
// We do average (integral) pooling inside a bin
T const count = roiBinGridH * roiBinGridW; // e.g. = 4
T const yOff = roiStartH + static_cast<T>(ph) * binSizeH;
T const yFac = binSizeH / static_cast<T>(roiBinGridH);
T const xOff = roiStartW + static_cast<T>(pw) * binSizeW;
T const xFac = binSizeW / static_cast<T>(roiBinGridW);
T outputVal = 0.;
bool maxFlag = false;
for (int32_t iy = 0; iy < roiBinGridH; iy++) // e.g., iy = 0, 1
{
T const y = yOff + static_cast<T>(iy + .5F) * yFac; // e.g., 0.5, 1.5
for (int32_t ix = 0; ix < roiBinGridW; ix++)
{
T const x = xOff + static_cast<T>(ix + .5F) * xFac;
T val = bilinearInterpolate(offsetBottomData, height, width, y, x, isModeAvg, index);
if (isModeAvg)
{
outputVal += val;
}
else
{
if (!maxFlag)
{
outputVal = val;
maxFlag = true;
}
else
{
outputVal = floatMax(outputVal, val);
}
}
}
}
if (isModeAvg)
{
outputVal = outputVal / count;
}
topData[index] = outputVal;
}
}
template <typename T>
cudaError_t RoiAlignImpl(cudaStream_t stream, int32_t const maxThreadsPerBlock, T const* bottomData, T const spatialScale,
int32_t const numRois, int32_t const channels, int32_t const height, int32_t const width, int32_t const pooledHeight,
int32_t const pooledWidth, int32_t const samplingRatio, T const* bottomRois, T* topData, int32_t const isModeAvg,
int32_t const* batchIndicesPtr, int32_t const aligned)
{
PLUGIN_ASSERT(bottomData != nullptr);
PLUGIN_ASSERT(bottomRois != nullptr);
PLUGIN_ASSERT(batchIndicesPtr != nullptr);
PLUGIN_ASSERT(topData != nullptr);
PLUGIN_ASSERT(numRois >= 0);
PLUGIN_ASSERT(maxThreadsPerBlock > 0);
PLUGIN_ASSERT(height > 0);
PLUGIN_ASSERT(width > 0);
PLUGIN_ASSERT(pooledHeight > 0);
PLUGIN_ASSERT(pooledWidth > 0);
PLUGIN_ASSERT(samplingRatio >= 0);
PLUGIN_ASSERT(isModeAvg == 0 || isModeAvg == 1);
PLUGIN_ASSERT(static_cast<float>(spatialScale) > 0.0F);
PLUGIN_ASSERT(aligned == 0 || aligned == 1);
int32_t const outputSize = numRois * channels * pooledHeight * pooledWidth;
int32_t blocksPerGrid = static_cast<int32_t>(ceil(static_cast<float>(outputSize)
/ maxThreadsPerBlock));
RoIAlignForward<T><<<blocksPerGrid, maxThreadsPerBlock, 0, stream>>>(outputSize,// nthreads
bottomData, // bottomData
spatialScale, // spatialScale
channels, // channels
height, // height
width, // width
pooledHeight, // pooledHeight
pooledWidth, // pooledWidth
samplingRatio, // samplingRatio
bottomRois, // bottomRois
topData, // topData
isModeAvg, // isModeAvg
batchIndicesPtr, // batchIndicesPtr
aligned);
return cudaGetLastError();
}
#define SPECIALIZED_IMPL(T) \
template cudaError_t RoiAlignImpl<T>(cudaStream_t stream, int32_t const maxThreadsPerBlock, T const* bottomData, \
T const spatialScale, int32_t const numRois, int32_t const channels, int32_t const height, \
int32_t const width, int32_t const pooledHeight, int32_t const pooledWidth, int32_t const samplingRatio, \
T const* bottomRois, T* topData, int32_t const isModeAvg, int32_t const* batchIndicesPtr, \
int32_t const aligned);
SPECIALIZED_IMPL(float)
SPECIALIZED_IMPL(half)