Files
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

530 lines
20 KiB
C++

/*
* 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 "nvFasterRCNNPlugin.h"
#include <cstdio>
#include <iostream>
#include <memory>
#include <string_view>
namespace nvinfer1::plugin
{
namespace
{
char const* const kRPROI_PLUGIN_VERSION{"1"};
char const* const kRPROI_PLUGIN_NAME{"RPROI_TRT"};
} // namespace
RPROIPlugin::RPROIPlugin(RPROIParams params, float const* anchorsRatios, float const* anchorsScales)
: params(params)
{
/*
* It only supports the scenario where params.featureStride == params.minBoxSize
* assert(params.featureStride == params.minBoxSize);
*/
PLUGIN_VALIDATE(params.anchorsRatioCount > 0 && params.anchorsScaleCount > 0);
anchorsRatiosHost = copyToHost(anchorsRatios, params.anchorsRatioCount);
anchorsScalesHost = copyToHost(anchorsScales, params.anchorsScaleCount);
PLUGIN_CHECK(
cudaMalloc((void**) &anchorsDev, 4 * params.anchorsRatioCount * params.anchorsScaleCount * sizeof(float)));
pluginStatus_t status = generateAnchors(0, params.anchorsRatioCount, anchorsRatiosHost, params.anchorsScaleCount,
anchorsScalesHost, params.featureStride, anchorsDev);
PLUGIN_VALIDATE(status == STATUS_SUCCESS);
deviceSmemSize = getSmemSize();
}
// Constructor for cloning one plugin instance to another
RPROIPlugin::RPROIPlugin(RPROIParams params, float const* anchorsRatios, float const* anchorsScales, int32_t A,
int32_t C, int32_t H, int32_t W, float const* _anchorsDev, size_t deviceSmemSize, DataType inFeatureType,
DataType outFeatureType, DLayout_t inFeatureLayout)
: deviceSmemSize(deviceSmemSize)
, params(params)
, A(A)
, C(C)
, H(H)
, W(W)
, inFeatureType(inFeatureType)
, outFeatureType(outFeatureType)
, inFeatureLayout(inFeatureLayout)
{
PLUGIN_VALIDATE(params.anchorsRatioCount > 0 && params.anchorsScaleCount > 0);
anchorsRatiosHost = copyToHost(anchorsRatios, params.anchorsRatioCount);
anchorsScalesHost = copyToHost(anchorsScales, params.anchorsScaleCount);
PLUGIN_CHECK(
cudaMalloc((void**) &anchorsDev, 4 * params.anchorsRatioCount * params.anchorsScaleCount * sizeof(float)));
// Perform deep copy
if (_anchorsDev != nullptr)
{
PLUGIN_CHECK(cudaMemcpy(anchorsDev, _anchorsDev,
4 * params.anchorsRatioCount * params.anchorsScaleCount * sizeof(float), cudaMemcpyDeviceToDevice));
}
}
RPROIPlugin::RPROIPlugin(void const* data, size_t length)
{
deserialize(static_cast<int8_t const*>(data), length);
}
void RPROIPlugin::deserialize(int8_t const* data, size_t length)
{
auto const* d{data};
params = *reinterpret_cast<RPROIParams const*>(d);
d += sizeof(RPROIParams);
A = read<int32_t>(d);
C = read<int32_t>(d);
H = read<int32_t>(d);
W = read<int32_t>(d);
inFeatureType = read<DataType>(d);
outFeatureType = read<DataType>(d);
inFeatureLayout = read<DLayout_t>(d);
anchorsRatiosHost = copyToHost(d, params.anchorsRatioCount);
d += params.anchorsRatioCount * sizeof(float);
anchorsScalesHost = copyToHost(d, params.anchorsScaleCount);
d += params.anchorsScaleCount * sizeof(float);
PLUGIN_VALIDATE(d == data + length);
PLUGIN_CHECK(
cudaMalloc((void**) &anchorsDev, 4 * params.anchorsRatioCount * params.anchorsScaleCount * sizeof(float)));
pluginStatus_t status = generateAnchors(0, params.anchorsRatioCount, anchorsRatiosHost, params.anchorsScaleCount,
anchorsScalesHost, params.featureStride, anchorsDev);
PLUGIN_VALIDATE(status == STATUS_SUCCESS);
deviceSmemSize = getSmemSize();
}
RPROIPlugin::~RPROIPlugin()
{
if (anchorsDev != nullptr)
{
PLUGIN_CHECK(cudaFree(anchorsDev));
anchorsDev = nullptr;
}
if (anchorsRatiosHost != nullptr)
{
PLUGIN_CHECK(cudaFreeHost(anchorsRatiosHost));
anchorsRatiosHost = nullptr;
}
if (anchorsScalesHost != nullptr)
{
PLUGIN_CHECK(cudaFreeHost(anchorsScalesHost));
anchorsScalesHost = nullptr;
}
}
int32_t RPROIPlugin::initialize() noexcept
{
return STATUS_SUCCESS;
}
size_t RPROIPlugin::getSmemSize() const noexcept
{
int32_t devId{-1};
PLUGIN_CHECK(cudaGetDevice(&devId));
cudaDeviceProp prop{};
PLUGIN_CHECK(cudaGetDeviceProperties(&prop, devId));
return prop.sharedMemPerBlockOptin;
}
int32_t RPROIPlugin::getNbOutputs() const noexcept
{
return 2;
}
Dims RPROIPlugin::getOutputDimensions(int32_t index, Dims const* inputs, int32_t nbInputDims) noexcept
{
PLUGIN_ASSERT(index >= 0 && index < 2);
PLUGIN_ASSERT(nbInputDims == 4);
PLUGIN_ASSERT(inputs[0].nbDims == 3 && inputs[1].nbDims == 3 && inputs[2].nbDims == 3 && inputs[3].nbDims == 3);
if (index == 0) // rois
{
return Dims3(1, params.nmsMaxOut, 4);
}
// Feature map of each ROI after ROI Pooling
// pool5
return Dims4(params.nmsMaxOut, inputs[2].d[0], params.poolingH, params.poolingW);
}
size_t RPROIPlugin::getWorkspaceSize(int32_t maxBatchSize) const noexcept
{
return RPROIInferenceFusedWorkspaceSize(maxBatchSize, A, H, W, params.nmsMaxOut);
}
int32_t RPROIPlugin::enqueue(
int32_t batchSize, void const* const* inputs, void* const* outputs, void* workspace, cudaStream_t stream) noexcept
{
// Bounding box (region proposal) objectness scores.
void const* const scores = inputs[0];
// Predicted bounding box offsets.
void const* const deltas = inputs[1];
// Feature map using for bounding box regression and classification.
void const* const fmap = inputs[2];
// Original image input information.
void const* const iinfo = inputs[3];
// Coordinates of region of interest (ROI) bounding boxes on the original input image.
void* rois = outputs[0];
// ROI pooled feature map corresponding to the region of interest (ROI).
void* pfmap = outputs[1];
pluginStatus_t status = RPROIInferenceFused(stream, batchSize, A, C, H, W, params.poolingH, params.poolingW,
params.featureStride, params.preNmsTop, params.nmsMaxOut, params.iouThreshold, params.minBoxSize,
params.spatialScale, (float const*) iinfo, this->anchorsDev, nvinfer1::DataType::kFLOAT, NCHW, scores,
nvinfer1::DataType::kFLOAT, NCHW, deltas, inFeatureType, inFeatureLayout, fmap, workspace,
nvinfer1::DataType::kFLOAT, rois, outFeatureType, NCHW, pfmap, deviceSmemSize);
return status;
}
size_t RPROIPlugin::getSerializationSize() const noexcept
{
size_t paramSize = sizeof(RPROIParams);
size_t intSize = sizeof(int32_t) * 4;
size_t ratiosSize = sizeof(float) * params.anchorsRatioCount;
size_t scalesSize = sizeof(float) * params.anchorsScaleCount;
size_t typeSize = sizeof(DataType) * 2;
size_t layoutSize = sizeof(DLayout_t);
return paramSize + intSize + ratiosSize + scalesSize + typeSize + layoutSize;
}
void RPROIPlugin::serialize(void* buffer) const noexcept
{
char *d = reinterpret_cast<char*>(buffer), *a = d;
*reinterpret_cast<RPROIParams*>(d) = params;
d += sizeof(RPROIParams);
*reinterpret_cast<int32_t*>(d) = A;
d += sizeof(int32_t);
*reinterpret_cast<int32_t*>(d) = C;
d += sizeof(int32_t);
*reinterpret_cast<int32_t*>(d) = H;
d += sizeof(int32_t);
*reinterpret_cast<int32_t*>(d) = W;
d += sizeof(int32_t);
*reinterpret_cast<DataType*>(d) = inFeatureType;
d += sizeof(DataType);
*reinterpret_cast<DataType*>(d) = outFeatureType;
d += sizeof(DataType);
*reinterpret_cast<DLayout_t*>(d) = inFeatureLayout;
d += sizeof(DLayout_t);
d += copyFromHost(d, anchorsRatiosHost, params.anchorsRatioCount);
d += copyFromHost(d, anchorsScalesHost, params.anchorsScaleCount);
PLUGIN_ASSERT(d == a + getSerializationSize());
}
float* RPROIPlugin::copyToHost(void const* srcHostData, int32_t count) noexcept
{
float* dstHostPtr = nullptr;
PLUGIN_CHECK(cudaMallocHost(&dstHostPtr, count * sizeof(float)));
PLUGIN_CHECK(cudaMemcpy(dstHostPtr, srcHostData, count * sizeof(float), cudaMemcpyHostToHost));
return dstHostPtr;
}
int32_t RPROIPlugin::copyFromHost(char* dstHostBuffer, void const* source, int32_t count) const noexcept
{
PLUGIN_CHECK(cudaMemcpy(dstHostBuffer, source, count * sizeof(float), cudaMemcpyHostToHost));
return count * sizeof(float);
}
bool RPROIPlugin::supportsFormatCombination(
int32_t pos, PluginTensorDesc const* inOut, int32_t nbInputs, int32_t nbOutputs) const noexcept
{
PLUGIN_ASSERT(nbInputs == PluginNbInputs && nbOutputs == PluginNbOutputs && pos < nbInputs + nbOutputs);
bool isValidCombination = false;
// input: bbox confindence, bbox offset, image info and output: rois
if (pos == 0 || pos == 1 || pos == 3 || pos == 4)
{
isValidCombination |= (inOut[pos].format == TensorFormat::kLINEAR && inOut[pos].type == DataType::kFLOAT);
}
// input: feature map
else if (pos == 2)
{
isValidCombination |= (inOut[pos].format == TensorFormat::kLINEAR && inOut[pos].type == DataType::kINT8);
isValidCombination |= (inOut[pos].format == TensorFormat::kLINEAR && inOut[pos].type == DataType::kFLOAT);
isValidCombination |= (inOut[pos].format == TensorFormat::kCHW4 && inOut[pos].type == DataType::kINT8);
isValidCombination |= (inOut[pos].format == TensorFormat::kCHW32 && inOut[pos].type == DataType::kINT8);
}
// output: pooled feature map (data type should be the same with input feature map)
else if (pos == 5)
{
isValidCombination |= (inOut[pos].format == TensorFormat::kLINEAR && inOut[pos].type == DataType::kINT8);
isValidCombination |= (inOut[pos].format == TensorFormat::kLINEAR && inOut[pos].type == DataType::kFLOAT);
isValidCombination &= inOut[pos].type == inOut[2].type;
}
return isValidCombination;
}
char const* RPROIPlugin::getPluginType() const noexcept
{
return kRPROI_PLUGIN_NAME;
}
char const* RPROIPlugin::getPluginVersion() const noexcept
{
return kRPROI_PLUGIN_VERSION;
}
void RPROIPlugin::terminate() noexcept {}
void RPROIPlugin::destroy() noexcept
{
delete this;
}
IPluginV2Ext* RPROIPlugin::clone() const noexcept
{
try
{
auto plugin = std::make_unique<RPROIPlugin>(params, anchorsRatiosHost, anchorsScalesHost, A, C, H, W,
anchorsDev, deviceSmemSize, inFeatureType, outFeatureType, inFeatureLayout);
plugin->setPluginNamespace(mPluginNamespace.c_str());
return plugin.release();
}
catch (std::exception const& e)
{
caughtError(e);
}
return nullptr;
}
// Set plugin namespace
void RPROIPlugin::setPluginNamespace(char const* pluginNamespace) noexcept
{
mPluginNamespace = pluginNamespace;
}
char const* RPROIPlugin::getPluginNamespace() const noexcept
{
return mPluginNamespace.c_str();
}
// Return the DataType of the plugin output at the requested index.
DataType RPROIPlugin::getOutputDataType(
int32_t index, nvinfer1::DataType const* inputTypes, int32_t nbInputs) const noexcept
{
// Two outputs
PLUGIN_ASSERT(index == 0 || index == 1);
return DataType::kFLOAT;
}
DLayout_t RPROIPlugin::convertTensorFormat(TensorFormat const& srcFormat) const noexcept
{
PLUGIN_ASSERT(
srcFormat == TensorFormat::kLINEAR || srcFormat == TensorFormat::kCHW4 || srcFormat == TensorFormat::kCHW32);
switch (srcFormat)
{
case nvinfer1::TensorFormat::kLINEAR: return DLayout_t::NCHW;
case nvinfer1::TensorFormat::kCHW4: return DLayout_t::NC4HW;
case nvinfer1::TensorFormat::kCHW32: return DLayout_t::NC32HW;
default: return DLayout_t::NCHW;
}
}
void RPROIPlugin::configurePlugin(
PluginTensorDesc const* in, int32_t nbInput, PluginTensorDesc const* out, int32_t nbOutput) noexcept
{
PLUGIN_ASSERT(nbInput == PluginNbInputs);
PLUGIN_ASSERT(nbOutput == PluginNbOutputs);
A = params.anchorsRatioCount * params.anchorsScaleCount;
C = in[2].dims.d[0];
H = in[2].dims.d[1];
W = in[2].dims.d[2];
inFeatureType = in[2].type;
outFeatureType = out[1].type;
inFeatureLayout = convertTensorFormat(in[2].format);
PLUGIN_ASSERT(in[0].dims.d[0] == (2 * A) && in[1].dims.d[0] == (4 * A));
PLUGIN_ASSERT(in[0].dims.d[1] == in[1].dims.d[1] && in[0].dims.d[1] == in[2].dims.d[1]);
PLUGIN_ASSERT(in[0].dims.d[2] == in[1].dims.d[2] && in[0].dims.d[2] == in[2].dims.d[2]);
PLUGIN_ASSERT(out[0].dims.nbDims == 3 // rois
&& out[1].dims.nbDims == 4); // pooled feature map
PLUGIN_ASSERT(out[0].dims.d[0] == 1 && out[0].dims.d[1] == params.nmsMaxOut && out[0].dims.d[2] == 4);
PLUGIN_ASSERT(out[1].dims.d[0] == params.nmsMaxOut && out[1].dims.d[1] == C && out[1].dims.d[2] == params.poolingH
&& out[1].dims.d[3] == params.poolingW);
}
// Attach the plugin object to an execution context and grant the plugin the access to some context resource.
void RPROIPlugin::attachToContext(
cudnnContext* cudnnContext, cublasContext* cublasContext, IGpuAllocator* gpuAllocator) noexcept
{
}
// Detach the plugin object from its execution context.
void RPROIPlugin::detachFromContext() noexcept {}
RPROIPluginCreator::RPROIPluginCreator()
{
mPluginAttributes.clear();
mPluginAttributes.emplace_back(PluginField("poolingH", nullptr, PluginFieldType::kINT32, 1));
mPluginAttributes.emplace_back(PluginField("poolingW", nullptr, PluginFieldType::kINT32, 1));
mPluginAttributes.emplace_back(PluginField("featureStride", nullptr, PluginFieldType::kINT32, 1));
mPluginAttributes.emplace_back(PluginField("preNmsTop", nullptr, PluginFieldType::kINT32, 1));
mPluginAttributes.emplace_back(PluginField("nmsMaxOut", nullptr, PluginFieldType::kINT32, 1));
mPluginAttributes.emplace_back(PluginField("anchorsRatioCount", nullptr, PluginFieldType::kINT32, 1));
mPluginAttributes.emplace_back(PluginField("anchorsScaleCount", nullptr, PluginFieldType::kINT32, 1));
mPluginAttributes.emplace_back(PluginField("iouThreshold", nullptr, PluginFieldType::kFLOAT32, 1));
mPluginAttributes.emplace_back(PluginField("minBoxSize", nullptr, PluginFieldType::kFLOAT32, 1));
mPluginAttributes.emplace_back(PluginField("spatialScale", nullptr, PluginFieldType::kFLOAT32, 1));
// TODO Do we need to pass the size attribute here for float arrarys, we
// dont have that information at this point.
mPluginAttributes.emplace_back(PluginField("anchorsRatios", nullptr, PluginFieldType::kFLOAT32, 1));
mPluginAttributes.emplace_back(PluginField("anchorsScales", nullptr, PluginFieldType::kFLOAT32, 1));
mFC.nbFields = mPluginAttributes.size();
mFC.fields = mPluginAttributes.data();
}
RPROIPluginCreator::~RPROIPluginCreator()
{
// Free allocated memory (if any) here
}
char const* RPROIPluginCreator::getPluginName() const noexcept
{
return kRPROI_PLUGIN_NAME;
}
char const* RPROIPluginCreator::getPluginVersion() const noexcept
{
return kRPROI_PLUGIN_VERSION;
}
PluginFieldCollection const* RPROIPluginCreator::getFieldNames() noexcept
{
return &mFC;
}
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
IPluginV2Ext* RPROIPluginCreator::createPlugin(char const* name, PluginFieldCollection const* fc) noexcept
{
try
{
using namespace std::string_view_literals;
PluginField const* fields = fc->fields;
int32_t nbFields = fc->nbFields;
for (int32_t i = 0; i < nbFields; ++i)
{
std::string_view const attrName = fields[i].name;
if (attrName == "poolingH"sv)
{
PLUGIN_VALIDATE(fields[i].type == PluginFieldType::kINT32);
params.poolingH = *(static_cast<int32_t const*>(fields[i].data));
}
if (attrName == "poolingW"sv)
{
PLUGIN_VALIDATE(fields[i].type == PluginFieldType::kINT32);
params.poolingW = *(static_cast<int32_t const*>(fields[i].data));
}
if (attrName == "featureStride"sv)
{
PLUGIN_VALIDATE(fields[i].type == PluginFieldType::kINT32);
params.featureStride = *(static_cast<int32_t const*>(fields[i].data));
}
if (attrName == "preNmsTop"sv)
{
PLUGIN_VALIDATE(fields[i].type == PluginFieldType::kINT32);
params.preNmsTop = *(static_cast<int32_t const*>(fields[i].data));
}
if (attrName == "nmsMaxOut"sv)
{
PLUGIN_VALIDATE(fields[i].type == PluginFieldType::kINT32);
params.nmsMaxOut = *(static_cast<int32_t const*>(fields[i].data));
}
if (attrName == "anchorsRatioCount"sv)
{
PLUGIN_VALIDATE(fields[i].type == PluginFieldType::kINT32);
params.anchorsRatioCount = *(static_cast<int32_t const*>(fields[i].data));
}
if (attrName == "anchorsScaleCount"sv)
{
PLUGIN_VALIDATE(fields[i].type == PluginFieldType::kINT32);
params.anchorsScaleCount = *(static_cast<int32_t const*>(fields[i].data));
}
if (attrName == "iouThreshold"sv)
{
PLUGIN_VALIDATE(fields[i].type == PluginFieldType::kFLOAT32);
params.iouThreshold = static_cast<float>(*(static_cast<float const*>(fields[i].data)));
}
if (attrName == "minBoxSize"sv)
{
PLUGIN_VALIDATE(fields[i].type == PluginFieldType::kFLOAT32);
params.minBoxSize = static_cast<float>(*(static_cast<float const*>(fields[i].data)));
}
if (attrName == "spatialScale"sv)
{
PLUGIN_VALIDATE(fields[i].type == PluginFieldType::kFLOAT32);
params.spatialScale = static_cast<float>(*(static_cast<float const*>(fields[i].data)));
}
if (attrName == "anchorsRatios"sv)
{
PLUGIN_VALIDATE(fields[i].type == PluginFieldType::kFLOAT32);
anchorsRatios.reserve(params.anchorsRatioCount);
float const* ratios = static_cast<float const*>(fields[i].data);
for (int32_t j = 0; j < params.anchorsRatioCount; ++j)
{
anchorsRatios.push_back(*ratios);
ratios++;
}
}
if (attrName == "anchorsScales"sv)
{
PLUGIN_VALIDATE(fields[i].type == PluginFieldType::kFLOAT32);
anchorsScales.reserve(params.anchorsScaleCount);
float const* scales = static_cast<float const*>(fields[i].data);
for (int32_t j = 0; j < params.anchorsScaleCount; ++j)
{
anchorsScales.push_back(*scales);
scales++;
}
}
}
// This object will be deleted when the network is destroyed, which will
// call RPROIPlugin::terminate()
auto plugin = std::make_unique<RPROIPlugin>(params, anchorsRatios.data(), anchorsScales.data());
plugin->setPluginNamespace(mNamespace.c_str());
return plugin.release();
}
catch (std::exception const& e)
{
caughtError(e);
}
return nullptr;
}
IPluginV2Ext* RPROIPluginCreator::deserializePlugin(
char const* name, void const* serialData, size_t serialLength) noexcept
{
try
{
// This object will be deleted when the network is destroyed, which will
// call RPROIPlugin::terminate()
auto plugin = std::make_unique<RPROIPlugin>(serialData, serialLength);
plugin->setPluginNamespace(mNamespace.c_str());
return plugin.release();
}
catch (std::exception const& e)
{
caughtError(e);
}
return nullptr;
}
} // namespace nvinfer1::plugin