/* * 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 "NvInferPluginUtils.h" #include "common/kernels/kernel.h" #include "reducedMathPlugin.h" #include using namespace nvinfer1; using namespace nvinfer1::plugin; using nvinfer1::plugin::ReducedDivisor; template __launch_bounds__(nthdsPerCTA) __global__ void priorBoxKernel(PriorBoxParameters param, const int H, const int W, const int numPriors, const int numAspectRatios, const float* minSize, const float* maxSize, const float* aspectRatios, float* outputData) { // output dims: (H, W, param.numMinSize, (1+haveMaxSize+numAR-1), 4) const int dim = H * W * numPriors; const bool haveMaxSize = param.numMaxSize > 0; const int dimAR = (haveMaxSize ? 1 : 0) + numAspectRatios; for (int i = blockIdx.x * nthdsPerCTA + threadIdx.x; i < dim; i += gridDim.x * nthdsPerCTA) { const int w = (i / numPriors) % W; const int h = (i / numPriors) / W; // Usually param.offset == 0.5 // Calucate the center of prior box at the input image scale const float centerX = (w + param.offset) * param.stepW; const float centerY = (h + param.offset) * param.stepH; // Minimum size index const int minSizeId = (i / dimAR) % param.numMinSize; // Aspect ratio index const int arId = i % dimAR; // Generate square pior box of aspect ratio of 1.0, edge length of minSize[minSizeId] if (arId == 0) { const float boxW = minSize[minSizeId]; const float boxH = boxW; float x, y, z, w; // Calculate [x_topleft, y_topleft, x_bottomright, y_bottomright] // Coordinates were scaled to [0, 1] against the width or height of the original input image x = (centerX - boxW / 2.0f) / param.imgW; y = (centerY - boxH / 2.0f) / param.imgH; z = (centerX + boxW / 2.0f) / param.imgW; w = (centerY + boxH / 2.0f) / param.imgH; // If we decided to clip the prior box make sure all the bounding box are inside the original input image if (param.clip) { x = min(max(x, 0.0f), 1.0f); y = min(max(y, 0.0f), 1.0f); z = min(max(z, 0.0f), 1.0f); w = min(max(w, 0.0f), 1.0f); } // Copy the bounding box coordinates to output outputData[i * 4] = x; outputData[i * 4 + 1] = y; outputData[i * 4 + 2] = z; outputData[i * 4 + 3] = w; } // If have maxSize // Generate square pior box for aspect ratio of 1.0, edge length of sqrt(minSize[minSizeId] * maxSize[minSizeId]) // Described in SSD paper page 6 else if (haveMaxSize && arId == 1) { const float boxW = sqrt(minSize[minSizeId] * maxSize[minSizeId]); const float boxH = boxW; float x, y, z, w; x = (centerX - boxW / 2.0f) / param.imgW; y = (centerY - boxH / 2.0f) / param.imgH; z = (centerX + boxW / 2.0f) / param.imgW; w = (centerY + boxH / 2.0f) / param.imgH; if (param.clip) { x = min(max(x, 0.0f), 1.0f); y = min(max(y, 0.0f), 1.0f); z = min(max(z, 0.0f), 1.0f); w = min(max(w, 0.0f), 1.0f); } outputData[i * 4] = x; outputData[i * 4 + 1] = y; outputData[i * 4 + 2] = z; outputData[i * 4 + 3] = w; } // Generate other bouding boxes with aspect ratios of not one. else { const int arOffset = haveMaxSize ? arId - 1 : arId; // skip aspectRatios[0] which is 1 const float boxW = minSize[minSizeId] * sqrt(aspectRatios[arOffset]); const float boxH = minSize[minSizeId] / sqrt(aspectRatios[arOffset]); float x, y, z, w; x = (centerX - boxW / 2.0f) / param.imgW; y = (centerY - boxH / 2.0f) / param.imgH; z = (centerX + boxW / 2.0f) / param.imgW; w = (centerY + boxH / 2.0f) / param.imgH; if (param.clip) { x = min(max(x, 0.0f), 1.0f); y = min(max(y, 0.0f), 1.0f); z = min(max(z, 0.0f), 1.0f); w = min(max(w, 0.0f), 1.0f); } outputData[i * 4] = x; outputData[i * 4 + 1] = y; outputData[i * 4 + 2] = z; outputData[i * 4 + 3] = w; } } // Simply copy variance to from the parameter to output float* output = outputData + dim * 4; for (int i = blockIdx.x * nthdsPerCTA + threadIdx.x; i < dim; i += gridDim.x * nthdsPerCTA) { float x, y, z, w; x = param.variance[0]; y = param.variance[1]; z = param.variance[2]; w = param.variance[3]; output[i * 4] = x; output[i * 4 + 1] = y; output[i * 4 + 2] = z; output[i * 4 + 3] = w; } } pluginStatus_t priorBoxGpu( cudaStream_t stream, const PriorBoxParameters param, const int H, const int W, const int numPriors, const int numAspectRatios, const void* minSize, const void* maxSize, const void* aspectRatios, void* outputData) { const int dim = H * W * numPriors; if (dim > 5120) { const int BS = 128; const int GS = (dim + BS - 1) / BS; priorBoxKernel<<>>(param, H, W, numPriors, numAspectRatios, (const float*) minSize, (const float*) maxSize, (const float*) aspectRatios, (float*) outputData); CSC(cudaGetLastError(), STATUS_FAILURE); return STATUS_SUCCESS; } else { const int BS = 32; const int GS = (dim + BS - 1) / BS; priorBoxKernel<<>>(param, H, W, numPriors, numAspectRatios, (const float*) minSize, (const float*) maxSize, (const float*) aspectRatios, (float*) outputData); CSC(cudaGetLastError(), STATUS_FAILURE); return STATUS_SUCCESS; } } pluginStatus_t priorBoxInference(cudaStream_t stream, const PriorBoxParameters param, const int H, const int W, const int numPriors, const int numAspectRatios, const void* minSize, const void* maxSize, const void* aspectRatios, void* outputData) { PLUGIN_ASSERT(param.numMaxSize >= 0); if (param.numMaxSize) return priorBoxGpu(stream, param, H, W, numPriors, numAspectRatios, minSize, maxSize, aspectRatios, outputData); else return priorBoxGpu(stream, param, H, W, numPriors, numAspectRatios, minSize, nullptr, aspectRatios, outputData); } namespace nvinfer1 { namespace plugin { pluginStatus_t priorBoxInference(cudaStream_t stream, const PriorBoxParameters param, const int H, const int W, const int numPriors, const int numAspectRatios, const void* minSize, const void* maxSize, const void* aspectRatios, void* outputData) { PLUGIN_ASSERT(param.numMaxSize >= 0); if (param.numMaxSize) return priorBoxGpu(stream, param, H, W, numPriors, numAspectRatios, minSize, maxSize, aspectRatios, outputData); else return priorBoxGpu(stream, param, H, W, numPriors, numAspectRatios, minSize, nullptr, aspectRatios, outputData); } } // namespace nvinfer1 } // namespace plugin