first commit
This commit is contained in:
59
nvdsinfer_custom_impl_Yolo/Makefile
Normal file
59
nvdsinfer_custom_impl_Yolo/Makefile
Normal file
@@ -0,0 +1,59 @@
|
||||
################################################################################
|
||||
# Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a
|
||||
# copy of this software and associated documentation files (the "Software"),
|
||||
# to deal in the Software without restriction, including without limitation
|
||||
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
# and/or sell copies of the Software, and to permit persons to whom the
|
||||
# Software is furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
# DEALINGS IN THE SOFTWARE.
|
||||
################################################################################
|
||||
|
||||
CUDA_VER?=11.3
|
||||
ifeq ($(CUDA_VER),)
|
||||
$(error "CUDA_VER is not set")
|
||||
endif
|
||||
CC:= g++
|
||||
NVCC:=/usr/local/cuda-$(CUDA_VER)/bin/nvcc
|
||||
|
||||
CFLAGS:= -Wall -std=c++11 -shared -fPIC -Wno-error=deprecated-declarations
|
||||
CFLAGS+= -I../includes -I/usr/local/cuda-$(CUDA_VER)/include
|
||||
|
||||
LIBS:= -lnvinfer_plugin -lnvinfer -lnvparsers -L/usr/local/cuda-$(CUDA_VER)/lib64 -lcudart -lcublas -lstdc++fs
|
||||
LFLAGS:= -shared -Wl,--start-group $(LIBS) -Wl,--end-group
|
||||
|
||||
INCS:= $(wildcard *.h)
|
||||
SRCFILES:= nvdsinfer_yolo_engine.cpp \
|
||||
nvdsparsebbox_Yolo.cpp \
|
||||
trt_utils.cpp \
|
||||
yolo.cpp \
|
||||
yoloPlugins.cpp
|
||||
TARGET_LIB:= libnvdsinfer_custom_impl_Yolo.so
|
||||
|
||||
TARGET_OBJS:= $(SRCFILES:.cpp=.o)
|
||||
TARGET_OBJS:= $(TARGET_OBJS:.cu=.o)
|
||||
|
||||
all: $(TARGET_LIB)
|
||||
|
||||
%.o: %.cpp $(INCS) Makefile
|
||||
$(CC) -c -o $@ $(CFLAGS) $<
|
||||
|
||||
%.o: %.cu $(INCS) Makefile
|
||||
$(NVCC) -c -o $@ --compiler-options '-fPIC' $<
|
||||
|
||||
$(TARGET_LIB) : $(TARGET_OBJS)
|
||||
$(CC) -o $@ $(TARGET_OBJS) $(LFLAGS)
|
||||
|
||||
clean:
|
||||
rm -rf $(TARGET_LIB)
|
||||
BIN
nvdsinfer_custom_impl_Yolo/libnvdsinfer_custom_impl_Yolo.so
Executable file
BIN
nvdsinfer_custom_impl_Yolo/libnvdsinfer_custom_impl_Yolo.so
Executable file
Binary file not shown.
123
nvdsinfer_custom_impl_Yolo/nvdsinfer_yolo_engine.cpp
Normal file
123
nvdsinfer_custom_impl_Yolo/nvdsinfer_yolo_engine.cpp
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "nvdsinfer_custom_impl.h"
|
||||
#include "nvdsinfer_context.h"
|
||||
//#include "yoloPlugins.h"
|
||||
#include "yolo.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#define USE_CUDA_ENGINE_GET_API 1
|
||||
|
||||
static bool getYoloNetworkInfo (NetworkInfo &networkInfo, const NvDsInferContextInitParams* initParams)
|
||||
{
|
||||
std::string yoloCfg = initParams->customNetworkConfigFilePath;
|
||||
std::string yoloType;
|
||||
|
||||
std::transform (yoloCfg.begin(), yoloCfg.end(), yoloCfg.begin(), [] (uint8_t c) {
|
||||
return std::tolower (c);});
|
||||
|
||||
if (yoloCfg.find("yolov2") != std::string::npos) {
|
||||
if (yoloCfg.find("yolov2-tiny") != std::string::npos)
|
||||
yoloType = "yolov2-tiny";
|
||||
else
|
||||
yoloType = "yolov2";
|
||||
} else if (yoloCfg.find("yolov3") != std::string::npos) {
|
||||
if (yoloCfg.find("yolov3-tiny") != std::string::npos)
|
||||
yoloType = "yolov3-tiny";
|
||||
else
|
||||
yoloType = "yolov3";
|
||||
} else {
|
||||
std::cerr << "Yolo type is not defined from config file name:"
|
||||
<< yoloCfg << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
networkInfo.networkType = yoloType;
|
||||
networkInfo.configFilePath = initParams->customNetworkConfigFilePath;
|
||||
networkInfo.wtsFilePath = initParams->modelFilePath;
|
||||
networkInfo.deviceType = (initParams->useDLA ? "kDLA" : "kGPU");
|
||||
networkInfo.inputBlobName = "data";
|
||||
|
||||
if (networkInfo.configFilePath.empty() ||
|
||||
networkInfo.wtsFilePath.empty()) {
|
||||
std::cerr << "Yolo config file or weights file is NOT specified."
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!fileExists(networkInfo.configFilePath) ||
|
||||
!fileExists(networkInfo.wtsFilePath)) {
|
||||
std::cerr << "Yolo config file or weights file is NOT exist."
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#if !USE_CUDA_ENGINE_GET_API
|
||||
IModelParser* NvDsInferCreateModelParser(
|
||||
const NvDsInferContextInitParams* initParams) {
|
||||
NetworkInfo networkInfo;
|
||||
if (!getYoloNetworkInfo(networkInfo, initParams)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::cout << "Build cuda engine hase successed on USE_CUDA_ENGINE_GET_API=0" << std::endl;
|
||||
|
||||
return new Yolo(networkInfo);
|
||||
}
|
||||
#else
|
||||
extern "C"
|
||||
bool NvDsInferYoloCudaEngineGet(nvinfer1::IBuilder * const builder,
|
||||
const NvDsInferContextInitParams * const initParams,
|
||||
nvinfer1::DataType dataType,
|
||||
nvinfer1::ICudaEngine *& cudaEngine);
|
||||
|
||||
extern "C"
|
||||
bool NvDsInferYoloCudaEngineGet(nvinfer1::IBuilder * const builder,
|
||||
const NvDsInferContextInitParams * const initParams,
|
||||
nvinfer1::DataType dataType,
|
||||
nvinfer1::ICudaEngine *& cudaEngine)
|
||||
{
|
||||
std::cout << "Begin cuda engine build..." << std::endl;
|
||||
NetworkInfo networkInfo;
|
||||
if (!getYoloNetworkInfo(networkInfo, initParams)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Yolo yolo(networkInfo);
|
||||
cudaEngine = yolo.createEngine (builder);
|
||||
if (cudaEngine == nullptr)
|
||||
{
|
||||
std::cerr << "Failed to build cuda engine on "
|
||||
<< networkInfo.configFilePath << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::cout << "Build cuda engine hase successed on " << networkInfo.configFilePath << std::endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
BIN
nvdsinfer_custom_impl_Yolo/nvdsinfer_yolo_engine.o
Normal file
BIN
nvdsinfer_custom_impl_Yolo/nvdsinfer_yolo_engine.o
Normal file
Binary file not shown.
596
nvdsinfer_custom_impl_Yolo/nvdsparsebbox_Yolo.cpp
Normal file
596
nvdsinfer_custom_impl_Yolo/nvdsparsebbox_Yolo.cpp
Normal file
@@ -0,0 +1,596 @@
|
||||
/*
|
||||
* Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <unordered_map>
|
||||
#include "nvdsinfer_custom_impl.h"
|
||||
#include "trt_utils.h"
|
||||
|
||||
static const int NUM_CLASSES_YOLO = 6;
|
||||
#define NMS_THRESH 0.5
|
||||
#define CONF_THRESH 0.4
|
||||
#define BATCH_SIZE 1
|
||||
|
||||
extern "C" bool NvDsInferParseCustomYoloV5(
|
||||
std::vector<NvDsInferLayerInfo> const &outputLayersInfo,
|
||||
NvDsInferNetworkInfo const &networkInfo,
|
||||
NvDsInferParseDetectionParams const &detectionParams,
|
||||
std::vector<NvDsInferParseObjectInfo> &objectList);
|
||||
|
||||
extern "C" bool NvDsInferParseCustomYoloV4(
|
||||
std::vector<NvDsInferLayerInfo> const &outputLayersInfo,
|
||||
NvDsInferNetworkInfo const &networkInfo,
|
||||
NvDsInferParseDetectionParams const &detectionParams,
|
||||
std::vector<NvDsInferParseObjectInfo> &objectList);
|
||||
|
||||
extern "C" bool NvDsInferParseCustomYoloV3(
|
||||
std::vector<NvDsInferLayerInfo> const& outputLayersInfo,
|
||||
NvDsInferNetworkInfo const& networkInfo,
|
||||
NvDsInferParseDetectionParams const& detectionParams,
|
||||
std::vector<NvDsInferParseObjectInfo>& objectList);
|
||||
|
||||
extern "C" bool NvDsInferParseCustomYoloV3Tiny(
|
||||
std::vector<NvDsInferLayerInfo> const& outputLayersInfo,
|
||||
NvDsInferNetworkInfo const& networkInfo,
|
||||
NvDsInferParseDetectionParams const& detectionParams,
|
||||
std::vector<NvDsInferParseObjectInfo>& objectList);
|
||||
|
||||
extern "C" bool NvDsInferParseCustomYoloV2(
|
||||
std::vector<NvDsInferLayerInfo> const& outputLayersInfo,
|
||||
NvDsInferNetworkInfo const& networkInfo,
|
||||
NvDsInferParseDetectionParams const& detectionParams,
|
||||
std::vector<NvDsInferParseObjectInfo>& objectList);
|
||||
|
||||
extern "C" bool NvDsInferParseCustomYoloV2Tiny(
|
||||
std::vector<NvDsInferLayerInfo> const& outputLayersInfo,
|
||||
NvDsInferNetworkInfo const& networkInfo,
|
||||
NvDsInferParseDetectionParams const& detectionParams,
|
||||
std::vector<NvDsInferParseObjectInfo>& objectList);
|
||||
|
||||
extern "C" bool NvDsInferParseCustomYoloTLT(
|
||||
std::vector<NvDsInferLayerInfo> const& outputLayersInfo,
|
||||
NvDsInferNetworkInfo const& networkInfo,
|
||||
NvDsInferParseDetectionParams const& detectionParams,
|
||||
std::vector<NvDsInferParseObjectInfo>& objectList);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
static constexpr int LOCATIONS = 4;
|
||||
struct alignas(float) Detection{
|
||||
//center_x center_y w h
|
||||
float bbox[LOCATIONS];
|
||||
float conf; // bbox_conf * cls_conf
|
||||
float class_id;
|
||||
};
|
||||
|
||||
float iou(float lbox[4], float rbox[4]) {
|
||||
float interBox[] = {
|
||||
std::max(lbox[0] - lbox[2]/2.f , rbox[0] - rbox[2]/2.f), //left
|
||||
std::min(lbox[0] + lbox[2]/2.f , rbox[0] + rbox[2]/2.f), //right
|
||||
std::max(lbox[1] - lbox[3]/2.f , rbox[1] - rbox[3]/2.f), //top
|
||||
std::min(lbox[1] + lbox[3]/2.f , rbox[1] + rbox[3]/2.f), //bottom
|
||||
};
|
||||
|
||||
if(interBox[2] > interBox[3] || interBox[0] > interBox[1])
|
||||
return 0.0f;
|
||||
|
||||
float interBoxS =(interBox[1]-interBox[0])*(interBox[3]-interBox[2]);
|
||||
return interBoxS/(lbox[2]*lbox[3] + rbox[2]*rbox[3] -interBoxS);
|
||||
}
|
||||
|
||||
bool cmp(Detection& a, Detection& b) {
|
||||
return a.conf > b.conf;
|
||||
}
|
||||
|
||||
void nms(std::vector<Detection>& res, float *output, float conf_thresh, float nms_thresh = 0.5) {
|
||||
int det_size = sizeof(Detection) / sizeof(float);
|
||||
std::map<float, std::vector<Detection>> m;
|
||||
for (int i = 0; i < output[0] && i < 1000; i++) {
|
||||
if (output[1 + det_size * i + 4] <= conf_thresh) continue;
|
||||
Detection det;
|
||||
memcpy(&det, &output[1 + det_size * i], det_size * sizeof(float));
|
||||
if (m.count(det.class_id) == 0) m.emplace(det.class_id, std::vector<Detection>());
|
||||
m[det.class_id].push_back(det);
|
||||
}
|
||||
for (auto it = m.begin(); it != m.end(); it++) {
|
||||
//std::cout << it->second[0].class_id << " --- " << std::endl;
|
||||
auto& dets = it->second;
|
||||
std::sort(dets.begin(), dets.end(), cmp);
|
||||
for (size_t m = 0; m < dets.size(); ++m) {
|
||||
auto& item = dets[m];
|
||||
res.push_back(item);
|
||||
for (size_t n = m + 1; n < dets.size(); ++n) {
|
||||
if (iou(item.bbox, dets[n].bbox) > nms_thresh) {
|
||||
dets.erase(dets.begin()+n);
|
||||
--n;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/* This is a sample bounding box parsing function for the sample YoloV5m detector model */
|
||||
static bool NvDsInferParseYoloV5(
|
||||
std::vector<NvDsInferLayerInfo> const& outputLayersInfo,
|
||||
NvDsInferNetworkInfo const& networkInfo,
|
||||
NvDsInferParseDetectionParams const& detectionParams,
|
||||
std::vector<NvDsInferParseObjectInfo>& objectList)
|
||||
{
|
||||
if (NUM_CLASSES_YOLO != detectionParams.numClassesConfigured)
|
||||
{
|
||||
std::cerr << "WARNING: Num classes mismatch. Configured:"
|
||||
<< detectionParams.numClassesConfigured
|
||||
<< ", detected by network: " << NUM_CLASSES_YOLO << std::endl;
|
||||
}
|
||||
|
||||
std::vector<Detection> res;
|
||||
|
||||
nms(res, (float*)(outputLayersInfo[0].buffer), CONF_THRESH, NMS_THRESH);
|
||||
//std::cout<<"Nms done sucessfully----"<<std::endl;
|
||||
|
||||
for(auto& r : res) {
|
||||
NvDsInferParseObjectInfo oinfo;
|
||||
|
||||
oinfo.classId = r.class_id;
|
||||
oinfo.left = static_cast<unsigned int>(r.bbox[0]-r.bbox[2]*0.5f);
|
||||
oinfo.top = static_cast<unsigned int>(r.bbox[1]-r.bbox[3]*0.5f);
|
||||
oinfo.width = static_cast<unsigned int>(r.bbox[2]);
|
||||
oinfo.height = static_cast<unsigned int>(r.bbox[3]);
|
||||
oinfo.detectionConfidence = r.conf;
|
||||
//std::cout << static_cast<unsigned int>(r.bbox[0]) << "," << static_cast<unsigned int>(r.bbox[1]) << "," << static_cast<unsigned int>(r.bbox[2]) << ","
|
||||
// << static_cast<unsigned int>(r.bbox[3]) << "," << static_cast<unsigned int>(r.class_id) << "," << static_cast<unsigned int>(r.conf) << std::endl;
|
||||
objectList.push_back(oinfo);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/* This is a sample bounding box parsing function for the sample YoloV4 detector model */
|
||||
static bool NvDsInferParseYoloV4(
|
||||
std::vector<NvDsInferLayerInfo> const& outputLayersInfo,
|
||||
NvDsInferNetworkInfo const& networkInfo,
|
||||
NvDsInferParseDetectionParams const& detectionParams,
|
||||
std::vector<NvDsInferParseObjectInfo>& objectList)
|
||||
{
|
||||
if (NUM_CLASSES_YOLO != detectionParams.numClassesConfigured)
|
||||
{
|
||||
std::cerr << "WARNING: Num classes mismatch. Configured:"
|
||||
<< detectionParams.numClassesConfigured
|
||||
<< ", detected by network: " << NUM_CLASSES_YOLO << std::endl;
|
||||
}
|
||||
|
||||
std::vector<Detection> res;
|
||||
|
||||
nms(res, (float*)(outputLayersInfo[0].buffer), CONF_THRESH, NMS_THRESH);
|
||||
//std::cout<<"Nms done sucessfully----"<<std::endl;
|
||||
|
||||
for(auto& r : res) {
|
||||
NvDsInferParseObjectInfo oinfo;
|
||||
|
||||
oinfo.classId = r.class_id;
|
||||
oinfo.left = static_cast<unsigned int>(r.bbox[0]-r.bbox[2]*0.5f);
|
||||
oinfo.top = static_cast<unsigned int>(r.bbox[1]-r.bbox[3]*0.5f);
|
||||
oinfo.width = static_cast<unsigned int>(r.bbox[2]);
|
||||
oinfo.height = static_cast<unsigned int>(r.bbox[3]);
|
||||
oinfo.detectionConfidence = r.conf;
|
||||
//std::cout << static_cast<unsigned int>(r.bbox[0]) << "," << static_cast<unsigned int>(r.bbox[1]) << "," << static_cast<unsigned int>(r.bbox[2]) << ","
|
||||
// << static_cast<unsigned int>(r.bbox[3]) << "," << static_cast<unsigned int>(r.class_id) << "," << static_cast<unsigned int>(r.conf) << std::endl;
|
||||
objectList.push_back(oinfo);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/* This is a sample bounding box parsing function for the sample YoloV3 detector model */
|
||||
static NvDsInferParseObjectInfo convertBBox(const float& bx, const float& by, const float& bw,
|
||||
const float& bh, const int& stride, const uint& netW,
|
||||
const uint& netH)
|
||||
{
|
||||
NvDsInferParseObjectInfo b;
|
||||
// Restore coordinates to network input resolution
|
||||
float xCenter = bx * stride;
|
||||
float yCenter = by * stride;
|
||||
float x0 = xCenter - bw / 2;
|
||||
float y0 = yCenter - bh / 2;
|
||||
float x1 = x0 + bw;
|
||||
float y1 = y0 + bh;
|
||||
|
||||
x0 = clamp(x0, 0, netW);
|
||||
y0 = clamp(y0, 0, netH);
|
||||
x1 = clamp(x1, 0, netW);
|
||||
y1 = clamp(y1, 0, netH);
|
||||
|
||||
b.left = x0;
|
||||
b.width = clamp(x1 - x0, 0, netW);
|
||||
b.top = y0;
|
||||
b.height = clamp(y1 - y0, 0, netH);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
static void addBBoxProposal(const float bx, const float by, const float bw, const float bh,
|
||||
const uint stride, const uint& netW, const uint& netH, const int maxIndex,
|
||||
const float maxProb, std::vector<NvDsInferParseObjectInfo>& binfo)
|
||||
{
|
||||
NvDsInferParseObjectInfo bbi = convertBBox(bx, by, bw, bh, stride, netW, netH);
|
||||
if (bbi.width < 1 || bbi.height < 1) return;
|
||||
|
||||
bbi.detectionConfidence = maxProb;
|
||||
bbi.classId = maxIndex;
|
||||
binfo.push_back(bbi);
|
||||
}
|
||||
|
||||
static std::vector<NvDsInferParseObjectInfo>
|
||||
decodeYoloV2Tensor(
|
||||
const float* detections, const std::vector<float> &anchors,
|
||||
const uint gridSizeW, const uint gridSizeH, const uint stride, const uint numBBoxes,
|
||||
const uint numOutputClasses, const uint& netW,
|
||||
const uint& netH)
|
||||
{
|
||||
std::vector<NvDsInferParseObjectInfo> binfo;
|
||||
for (uint y = 0; y < gridSizeH; ++y) {
|
||||
for (uint x = 0; x < gridSizeW; ++x) {
|
||||
for (uint b = 0; b < numBBoxes; ++b)
|
||||
{
|
||||
const float pw = anchors[b * 2];
|
||||
const float ph = anchors[b * 2 + 1];
|
||||
|
||||
const int numGridCells = gridSizeH * gridSizeW;
|
||||
const int bbindex = y * gridSizeW + x;
|
||||
const float bx
|
||||
= x + detections[bbindex + numGridCells * (b * (5 + numOutputClasses) + 0)];
|
||||
const float by
|
||||
= y + detections[bbindex + numGridCells * (b * (5 + numOutputClasses) + 1)];
|
||||
const float bw
|
||||
= pw * exp (detections[bbindex + numGridCells * (b * (5 + numOutputClasses) + 2)]);
|
||||
const float bh
|
||||
= ph * exp (detections[bbindex + numGridCells * (b * (5 + numOutputClasses) + 3)]);
|
||||
|
||||
const float objectness
|
||||
= detections[bbindex + numGridCells * (b * (5 + numOutputClasses) + 4)];
|
||||
|
||||
float maxProb = 0.0f;
|
||||
int maxIndex = -1;
|
||||
|
||||
for (uint i = 0; i < numOutputClasses; ++i)
|
||||
{
|
||||
float prob
|
||||
= (detections[bbindex
|
||||
+ numGridCells * (b * (5 + numOutputClasses) + (5 + i))]);
|
||||
|
||||
if (prob > maxProb)
|
||||
{
|
||||
maxProb = prob;
|
||||
maxIndex = i;
|
||||
}
|
||||
}
|
||||
maxProb = objectness * maxProb;
|
||||
|
||||
addBBoxProposal(bx, by, bw, bh, stride, netW, netH, maxIndex, maxProb, binfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
return binfo;
|
||||
}
|
||||
|
||||
static std::vector<NvDsInferParseObjectInfo>
|
||||
decodeYoloV3Tensor(
|
||||
const float* detections, const std::vector<int> &mask, const std::vector<float> &anchors,
|
||||
const uint gridSizeW, const uint gridSizeH, const uint stride, const uint numBBoxes,
|
||||
const uint numOutputClasses, const uint& netW,
|
||||
const uint& netH)
|
||||
{
|
||||
std::vector<NvDsInferParseObjectInfo> binfo;
|
||||
for (uint y = 0; y < gridSizeH; ++y) {
|
||||
for (uint x = 0; x < gridSizeW; ++x) {
|
||||
for (uint b = 0; b < numBBoxes; ++b)
|
||||
{
|
||||
const float pw = anchors[mask[b] * 2];
|
||||
const float ph = anchors[mask[b] * 2 + 1];
|
||||
|
||||
const int numGridCells = gridSizeH * gridSizeW;
|
||||
const int bbindex = y * gridSizeW + x;
|
||||
const float bx
|
||||
= x + detections[bbindex + numGridCells * (b * (5 + numOutputClasses) + 0)];
|
||||
const float by
|
||||
= y + detections[bbindex + numGridCells * (b * (5 + numOutputClasses) + 1)];
|
||||
const float bw
|
||||
= pw * detections[bbindex + numGridCells * (b * (5 + numOutputClasses) + 2)];
|
||||
const float bh
|
||||
= ph * detections[bbindex + numGridCells * (b * (5 + numOutputClasses) + 3)];
|
||||
|
||||
const float objectness
|
||||
= detections[bbindex + numGridCells * (b * (5 + numOutputClasses) + 4)];
|
||||
|
||||
float maxProb = 0.0f;
|
||||
int maxIndex = -1;
|
||||
|
||||
for (uint i = 0; i < numOutputClasses; ++i)
|
||||
{
|
||||
float prob
|
||||
= (detections[bbindex
|
||||
+ numGridCells * (b * (5 + numOutputClasses) + (5 + i))]);
|
||||
|
||||
if (prob > maxProb)
|
||||
{
|
||||
maxProb = prob;
|
||||
maxIndex = i;
|
||||
}
|
||||
}
|
||||
maxProb = objectness * maxProb;
|
||||
|
||||
addBBoxProposal(bx, by, bw, bh, stride, netW, netH, maxIndex, maxProb, binfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
return binfo;
|
||||
}
|
||||
|
||||
static inline std::vector<const NvDsInferLayerInfo*>
|
||||
SortLayers(const std::vector<NvDsInferLayerInfo> & outputLayersInfo)
|
||||
{
|
||||
std::vector<const NvDsInferLayerInfo*> outLayers;
|
||||
for (auto const &layer : outputLayersInfo) {
|
||||
outLayers.push_back (&layer);
|
||||
}
|
||||
std::sort(outLayers.begin(), outLayers.end(),
|
||||
[](const NvDsInferLayerInfo* a, const NvDsInferLayerInfo* b) {
|
||||
return a->inferDims.d[1] < b->inferDims.d[1];
|
||||
});
|
||||
return outLayers;
|
||||
}
|
||||
|
||||
static bool NvDsInferParseYoloV3(
|
||||
std::vector<NvDsInferLayerInfo> const& outputLayersInfo,
|
||||
NvDsInferNetworkInfo const& networkInfo,
|
||||
NvDsInferParseDetectionParams const& detectionParams,
|
||||
std::vector<NvDsInferParseObjectInfo>& objectList,
|
||||
const std::vector<float> &anchors,
|
||||
const std::vector<std::vector<int>> &masks)
|
||||
{
|
||||
const uint kNUM_BBOXES = 3;
|
||||
|
||||
const std::vector<const NvDsInferLayerInfo*> sortedLayers =
|
||||
SortLayers (outputLayersInfo);
|
||||
|
||||
if (sortedLayers.size() != masks.size()) {
|
||||
std::cerr << "ERROR: yoloV3 output layer.size: " << sortedLayers.size()
|
||||
<< " does not match mask.size: " << masks.size() << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (NUM_CLASSES_YOLO != detectionParams.numClassesConfigured)
|
||||
{
|
||||
std::cerr << "WARNING: Num classes mismatch. Configured:"
|
||||
<< detectionParams.numClassesConfigured
|
||||
<< ", detected by network: " << NUM_CLASSES_YOLO << std::endl;
|
||||
}
|
||||
|
||||
std::vector<NvDsInferParseObjectInfo> objects;
|
||||
|
||||
for (uint idx = 0; idx < masks.size(); ++idx) {
|
||||
const NvDsInferLayerInfo &layer = *sortedLayers[idx]; // 255 x Grid x Grid
|
||||
|
||||
assert(layer.inferDims.numDims == 3);
|
||||
const uint gridSizeH = layer.inferDims.d[1];
|
||||
const uint gridSizeW = layer.inferDims.d[2];
|
||||
const uint stride = DIVUP(networkInfo.width, gridSizeW);
|
||||
assert(stride == DIVUP(networkInfo.height, gridSizeH));
|
||||
|
||||
std::vector<NvDsInferParseObjectInfo> outObjs =
|
||||
decodeYoloV3Tensor((const float*)(layer.buffer), masks[idx], anchors, gridSizeW, gridSizeH, stride, kNUM_BBOXES,
|
||||
NUM_CLASSES_YOLO, networkInfo.width, networkInfo.height);
|
||||
objects.insert(objects.end(), outObjs.begin(), outObjs.end());
|
||||
}
|
||||
|
||||
|
||||
objectList = objects;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool NvDsInferParseYoloV2(
|
||||
std::vector<NvDsInferLayerInfo> const& outputLayersInfo,
|
||||
NvDsInferNetworkInfo const& networkInfo,
|
||||
NvDsInferParseDetectionParams const& detectionParams,
|
||||
std::vector<NvDsInferParseObjectInfo>& objectList)
|
||||
{
|
||||
// copy anchor data from yolov2.cfg file
|
||||
std::vector<float> anchors = {0.57273, 0.677385, 1.87446, 2.06253, 3.33843,
|
||||
5.47434, 7.88282, 3.52778, 9.77052, 9.16828};
|
||||
const uint kNUM_BBOXES = 5;
|
||||
|
||||
if (outputLayersInfo.empty()) {
|
||||
std::cerr << "Could not find output layer in bbox parsing" << std::endl;;
|
||||
return false;
|
||||
}
|
||||
const NvDsInferLayerInfo &layer = outputLayersInfo[0];
|
||||
|
||||
if (NUM_CLASSES_YOLO != detectionParams.numClassesConfigured)
|
||||
{
|
||||
std::cerr << "WARNING: Num classes mismatch. Configured:"
|
||||
<< detectionParams.numClassesConfigured
|
||||
<< ", detected by network: " << NUM_CLASSES_YOLO << std::endl;
|
||||
}
|
||||
|
||||
assert(layer.inferDims.numDims == 3);
|
||||
const uint gridSizeH = layer.inferDims.d[1];
|
||||
const uint gridSizeW = layer.inferDims.d[2];
|
||||
const uint stride = DIVUP(networkInfo.width, gridSizeW);
|
||||
assert(stride == DIVUP(networkInfo.height, gridSizeH));
|
||||
for (auto& anchor : anchors) {
|
||||
anchor *= stride;
|
||||
}
|
||||
std::vector<NvDsInferParseObjectInfo> objects =
|
||||
decodeYoloV2Tensor((const float*)(layer.buffer), anchors, gridSizeW, gridSizeH, stride, kNUM_BBOXES,
|
||||
NUM_CLASSES_YOLO, networkInfo.width, networkInfo.height);
|
||||
|
||||
objectList = objects;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/* C-linkage to prevent name-mangling */
|
||||
extern "C" bool NvDsInferParseCustomYoloV5(
|
||||
std::vector<NvDsInferLayerInfo> const &outputLayersInfo,
|
||||
NvDsInferNetworkInfo const &networkInfo,
|
||||
NvDsInferParseDetectionParams const &detectionParams,
|
||||
std::vector<NvDsInferParseObjectInfo> &objectList)
|
||||
{
|
||||
return NvDsInferParseYoloV5(
|
||||
outputLayersInfo, networkInfo, detectionParams, objectList);
|
||||
}
|
||||
|
||||
extern "C" bool NvDsInferParseCustomYoloV4(
|
||||
std::vector<NvDsInferLayerInfo> const &outputLayersInfo,
|
||||
NvDsInferNetworkInfo const &networkInfo,
|
||||
NvDsInferParseDetectionParams const &detectionParams,
|
||||
std::vector<NvDsInferParseObjectInfo> &objectList)
|
||||
{
|
||||
return NvDsInferParseYoloV4 (
|
||||
outputLayersInfo, networkInfo, detectionParams, objectList);
|
||||
}
|
||||
|
||||
extern "C" bool NvDsInferParseCustomYoloV3(
|
||||
std::vector<NvDsInferLayerInfo> const& outputLayersInfo,
|
||||
NvDsInferNetworkInfo const& networkInfo,
|
||||
NvDsInferParseDetectionParams const& detectionParams,
|
||||
std::vector<NvDsInferParseObjectInfo>& objectList)
|
||||
{
|
||||
static const std::vector<float> kANCHORS = {
|
||||
10.0, 13.0, 16.0, 30.0, 33.0, 23.0, 30.0, 61.0, 62.0,
|
||||
45.0, 59.0, 119.0, 116.0, 90.0, 156.0, 198.0, 373.0, 326.0};
|
||||
static const std::vector<std::vector<int>> kMASKS = {
|
||||
{6, 7, 8},
|
||||
{3, 4, 5},
|
||||
{0, 1, 2}};
|
||||
return NvDsInferParseYoloV3 (
|
||||
outputLayersInfo, networkInfo, detectionParams, objectList,
|
||||
kANCHORS, kMASKS);
|
||||
}
|
||||
|
||||
extern "C" bool NvDsInferParseCustomYoloV3Tiny(
|
||||
std::vector<NvDsInferLayerInfo> const& outputLayersInfo,
|
||||
NvDsInferNetworkInfo const& networkInfo,
|
||||
NvDsInferParseDetectionParams const& detectionParams,
|
||||
std::vector<NvDsInferParseObjectInfo>& objectList)
|
||||
{
|
||||
static const std::vector<float> kANCHORS = {
|
||||
10, 14, 23, 27, 37, 58, 81, 82, 135, 169, 344, 319};
|
||||
static const std::vector<std::vector<int>> kMASKS = {
|
||||
{3, 4, 5},
|
||||
//{0, 1, 2}}; // as per output result, select {1,2,3}
|
||||
{1, 2, 3}};
|
||||
|
||||
return NvDsInferParseYoloV3 (
|
||||
outputLayersInfo, networkInfo, detectionParams, objectList,
|
||||
kANCHORS, kMASKS);
|
||||
}
|
||||
|
||||
extern "C" bool NvDsInferParseCustomYoloV2(
|
||||
std::vector<NvDsInferLayerInfo> const& outputLayersInfo,
|
||||
NvDsInferNetworkInfo const& networkInfo,
|
||||
NvDsInferParseDetectionParams const& detectionParams,
|
||||
std::vector<NvDsInferParseObjectInfo>& objectList)
|
||||
{
|
||||
return NvDsInferParseYoloV2 (
|
||||
outputLayersInfo, networkInfo, detectionParams, objectList);
|
||||
}
|
||||
|
||||
extern "C" bool NvDsInferParseCustomYoloV2Tiny(
|
||||
std::vector<NvDsInferLayerInfo> const& outputLayersInfo,
|
||||
NvDsInferNetworkInfo const& networkInfo,
|
||||
NvDsInferParseDetectionParams const& detectionParams,
|
||||
std::vector<NvDsInferParseObjectInfo>& objectList)
|
||||
{
|
||||
return NvDsInferParseYoloV2 (
|
||||
outputLayersInfo, networkInfo, detectionParams, objectList);
|
||||
}
|
||||
|
||||
extern "C" bool NvDsInferParseCustomYoloTLT(
|
||||
std::vector<NvDsInferLayerInfo> const& outputLayersInfo,
|
||||
NvDsInferNetworkInfo const& networkInfo,
|
||||
NvDsInferParseDetectionParams const& detectionParams,
|
||||
std::vector<NvDsInferParseObjectInfo>& objectList)
|
||||
{
|
||||
|
||||
if(outputLayersInfo.size() != 4)
|
||||
{
|
||||
std::cerr << "Mismatch in the number of output buffers."
|
||||
<< "Expected 4 output buffers, detected in the network :"
|
||||
<< outputLayersInfo.size() << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
const int topK = 200;
|
||||
const int* keepCount = static_cast <const int*>(outputLayersInfo.at(0).buffer);
|
||||
const float* boxes = static_cast <const float*>(outputLayersInfo.at(1).buffer);
|
||||
const float* scores = static_cast <const float*>(outputLayersInfo.at(2).buffer);
|
||||
const float* cls = static_cast <const float*>(outputLayersInfo.at(3).buffer);
|
||||
|
||||
for (int i = 0; (i < keepCount[0]) && (objectList.size() <= topK); ++i)
|
||||
{
|
||||
const float* loc = &boxes[0] + (i * 4);
|
||||
const float* conf = &scores[0] + i;
|
||||
const float* cls_id = &cls[0] + i;
|
||||
|
||||
if(conf[0] > 1.001)
|
||||
continue;
|
||||
|
||||
if((loc[0] < 0) || (loc[1] < 0) || (loc[2] < 0) || (loc[3] < 0))
|
||||
continue;
|
||||
|
||||
if((loc[0] > networkInfo.width) || (loc[2] > networkInfo.width) || (loc[1] > networkInfo.height) || (loc[3] > networkInfo.width))
|
||||
continue;
|
||||
|
||||
if((loc[2] < loc[0]) || (loc[3] < loc[1]))
|
||||
continue;
|
||||
|
||||
if(((loc[3] - loc[1]) > networkInfo.height) || ((loc[2]-loc[0]) > networkInfo.width))
|
||||
continue;
|
||||
|
||||
NvDsInferParseObjectInfo curObj{static_cast<unsigned int>(cls_id[0]),
|
||||
loc[0],loc[1],(loc[2]-loc[0]),
|
||||
(loc[3]-loc[1]), conf[0]};
|
||||
objectList.push_back(curObj);
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Check that the custom function has been defined correctly */
|
||||
CHECK_CUSTOM_PARSE_FUNC_PROTOTYPE(NvDsInferParseCustomYoloV5);
|
||||
CHECK_CUSTOM_PARSE_FUNC_PROTOTYPE(NvDsInferParseCustomYoloV4);
|
||||
CHECK_CUSTOM_PARSE_FUNC_PROTOTYPE(NvDsInferParseCustomYoloV3);
|
||||
CHECK_CUSTOM_PARSE_FUNC_PROTOTYPE(NvDsInferParseCustomYoloV3Tiny);
|
||||
CHECK_CUSTOM_PARSE_FUNC_PROTOTYPE(NvDsInferParseCustomYoloV2);
|
||||
CHECK_CUSTOM_PARSE_FUNC_PROTOTYPE(NvDsInferParseCustomYoloV2Tiny);
|
||||
CHECK_CUSTOM_PARSE_FUNC_PROTOTYPE(NvDsInferParseCustomYoloTLT);
|
||||
BIN
nvdsinfer_custom_impl_Yolo/nvdsparsebbox_Yolo.o
Normal file
BIN
nvdsinfer_custom_impl_Yolo/nvdsparsebbox_Yolo.o
Normal file
Binary file not shown.
447
nvdsinfer_custom_impl_Yolo/trt_utils.cpp
Normal file
447
nvdsinfer_custom_impl_Yolo/trt_utils.cpp
Normal file
@@ -0,0 +1,447 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "trt_utils.h"
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <functional>
|
||||
#include <algorithm>
|
||||
#include <math.h>
|
||||
|
||||
#include "NvInferPlugin.h"
|
||||
|
||||
static void leftTrim(std::string& s)
|
||||
{
|
||||
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) { return !isspace(ch); }));
|
||||
}
|
||||
|
||||
static void rightTrim(std::string& s)
|
||||
{
|
||||
s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) { return !isspace(ch); }).base(), s.end());
|
||||
}
|
||||
|
||||
std::string trim(std::string s)
|
||||
{
|
||||
leftTrim(s);
|
||||
rightTrim(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
float clamp(const float val, const float minVal, const float maxVal)
|
||||
{
|
||||
assert(minVal <= maxVal);
|
||||
return std::min(maxVal, std::max(minVal, val));
|
||||
}
|
||||
|
||||
bool fileExists(const std::string fileName, bool verbose)
|
||||
{
|
||||
if (!std::experimental::filesystem::exists(std::experimental::filesystem::path(fileName)))
|
||||
{
|
||||
if (verbose) std::cout << "File does not exist : " << fileName << std::endl;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<float> loadWeights(const std::string weightsFilePath, const std::string& networkType)
|
||||
{
|
||||
assert(fileExists(weightsFilePath));
|
||||
std::cout << "Loading pre-trained weights..." << std::endl;
|
||||
std::ifstream file(weightsFilePath, std::ios_base::binary);
|
||||
assert(file.good());
|
||||
std::string line;
|
||||
|
||||
if (networkType == "yolov2")
|
||||
{
|
||||
// Remove 4 int32 bytes of data from the stream belonging to the header
|
||||
file.ignore(4 * 4);
|
||||
}
|
||||
else if ((networkType == "yolov3") || (networkType == "yolov3-tiny")
|
||||
|| (networkType == "yolov2-tiny"))
|
||||
{
|
||||
// Remove 5 int32 bytes of data from the stream belonging to the header
|
||||
file.ignore(4 * 5);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Invalid network type" << std::endl;
|
||||
assert(0);
|
||||
}
|
||||
|
||||
std::vector<float> weights;
|
||||
char floatWeight[4];
|
||||
while (!file.eof())
|
||||
{
|
||||
file.read(floatWeight, 4);
|
||||
assert(file.gcount() == 4);
|
||||
weights.push_back(*reinterpret_cast<float*>(floatWeight));
|
||||
if (file.peek() == std::istream::traits_type::eof()) break;
|
||||
}
|
||||
std::cout << "Loading weights of " << networkType << " complete!"
|
||||
<< std::endl;
|
||||
std::cout << "Total Number of weights read : " << weights.size() << std::endl;
|
||||
return weights;
|
||||
}
|
||||
|
||||
std::string dimsToString(const nvinfer1::Dims d)
|
||||
{
|
||||
std::stringstream s;
|
||||
assert(d.nbDims >= 1);
|
||||
for (int i = 0; i < d.nbDims - 1; ++i)
|
||||
{
|
||||
s << std::setw(4) << d.d[i] << " x";
|
||||
}
|
||||
s << std::setw(4) << d.d[d.nbDims - 1];
|
||||
|
||||
return s.str();
|
||||
}
|
||||
|
||||
int getNumChannels(nvinfer1::ITensor* t)
|
||||
{
|
||||
nvinfer1::Dims d = t->getDimensions();
|
||||
assert(d.nbDims == 3);
|
||||
|
||||
return d.d[0];
|
||||
}
|
||||
|
||||
uint64_t get3DTensorVolume(nvinfer1::Dims inputDims)
|
||||
{
|
||||
assert(inputDims.nbDims == 3);
|
||||
return inputDims.d[0] * inputDims.d[1] * inputDims.d[2];
|
||||
}
|
||||
|
||||
nvinfer1::ILayer* netAddMaxpool(int layerIdx, std::map<std::string, std::string>& block,
|
||||
nvinfer1::ITensor* input, nvinfer1::INetworkDefinition* network)
|
||||
{
|
||||
assert(block.at("type") == "maxpool");
|
||||
assert(block.find("size") != block.end());
|
||||
assert(block.find("stride") != block.end());
|
||||
|
||||
int size = std::stoi(block.at("size"));
|
||||
int stride = std::stoi(block.at("stride"));
|
||||
|
||||
nvinfer1::IPoolingLayer* pool
|
||||
= network->addPooling(*input, nvinfer1::PoolingType::kMAX, nvinfer1::DimsHW{size, size});
|
||||
assert(pool);
|
||||
std::string maxpoolLayerName = "maxpool_" + std::to_string(layerIdx);
|
||||
pool->setStride(nvinfer1::DimsHW{stride, stride});
|
||||
pool->setPaddingMode(nvinfer1::PaddingMode::kSAME_UPPER);
|
||||
pool->setName(maxpoolLayerName.c_str());
|
||||
|
||||
return pool;
|
||||
}
|
||||
|
||||
nvinfer1::ILayer* netAddConvLinear(int layerIdx, std::map<std::string, std::string>& block,
|
||||
std::vector<float>& weights,
|
||||
std::vector<nvinfer1::Weights>& trtWeights, int& weightPtr,
|
||||
int& inputChannels, nvinfer1::ITensor* input,
|
||||
nvinfer1::INetworkDefinition* network)
|
||||
{
|
||||
assert(block.at("type") == "convolutional");
|
||||
assert(block.find("batch_normalize") == block.end());
|
||||
assert(block.at("activation") == "linear");
|
||||
assert(block.find("filters") != block.end());
|
||||
assert(block.find("pad") != block.end());
|
||||
assert(block.find("size") != block.end());
|
||||
assert(block.find("stride") != block.end());
|
||||
|
||||
int filters = std::stoi(block.at("filters"));
|
||||
int padding = std::stoi(block.at("pad"));
|
||||
int kernelSize = std::stoi(block.at("size"));
|
||||
int stride = std::stoi(block.at("stride"));
|
||||
int pad;
|
||||
if (padding)
|
||||
pad = (kernelSize - 1) / 2;
|
||||
else
|
||||
pad = 0;
|
||||
// load the convolution layer bias
|
||||
nvinfer1::Weights convBias{nvinfer1::DataType::kFLOAT, nullptr, filters};
|
||||
float* val = new float[filters];
|
||||
for (int i = 0; i < filters; ++i)
|
||||
{
|
||||
val[i] = weights[weightPtr];
|
||||
weightPtr++;
|
||||
}
|
||||
convBias.values = val;
|
||||
trtWeights.push_back(convBias);
|
||||
// load the convolutional layer weights
|
||||
int size = filters * inputChannels * kernelSize * kernelSize;
|
||||
nvinfer1::Weights convWt{nvinfer1::DataType::kFLOAT, nullptr, size};
|
||||
val = new float[size];
|
||||
for (int i = 0; i < size; ++i)
|
||||
{
|
||||
val[i] = weights[weightPtr];
|
||||
weightPtr++;
|
||||
}
|
||||
convWt.values = val;
|
||||
trtWeights.push_back(convWt);
|
||||
nvinfer1::IConvolutionLayer* conv = network->addConvolution(
|
||||
*input, filters, nvinfer1::DimsHW{kernelSize, kernelSize}, convWt, convBias);
|
||||
assert(conv != nullptr);
|
||||
std::string convLayerName = "conv_" + std::to_string(layerIdx);
|
||||
conv->setName(convLayerName.c_str());
|
||||
conv->setStride(nvinfer1::DimsHW{stride, stride});
|
||||
conv->setPadding(nvinfer1::DimsHW{pad, pad});
|
||||
|
||||
return conv;
|
||||
}
|
||||
|
||||
nvinfer1::ILayer* netAddConvBNLeaky(int layerIdx, std::map<std::string, std::string>& block,
|
||||
std::vector<float>& weights,
|
||||
std::vector<nvinfer1::Weights>& trtWeights, int& weightPtr,
|
||||
int& inputChannels, nvinfer1::ITensor* input,
|
||||
nvinfer1::INetworkDefinition* network)
|
||||
{
|
||||
assert(block.at("type") == "convolutional");
|
||||
assert(block.find("batch_normalize") != block.end());
|
||||
assert(block.at("batch_normalize") == "1");
|
||||
assert(block.at("activation") == "leaky");
|
||||
assert(block.find("filters") != block.end());
|
||||
assert(block.find("pad") != block.end());
|
||||
assert(block.find("size") != block.end());
|
||||
assert(block.find("stride") != block.end());
|
||||
|
||||
bool batchNormalize, bias;
|
||||
if (block.find("batch_normalize") != block.end())
|
||||
{
|
||||
batchNormalize = (block.at("batch_normalize") == "1");
|
||||
bias = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
batchNormalize = false;
|
||||
bias = true;
|
||||
}
|
||||
// all conv_bn_leaky layers assume bias is false
|
||||
assert(batchNormalize == true && bias == false);
|
||||
UNUSED(batchNormalize);
|
||||
UNUSED(bias);
|
||||
|
||||
int filters = std::stoi(block.at("filters"));
|
||||
int padding = std::stoi(block.at("pad"));
|
||||
int kernelSize = std::stoi(block.at("size"));
|
||||
int stride = std::stoi(block.at("stride"));
|
||||
int pad;
|
||||
if (padding)
|
||||
pad = (kernelSize - 1) / 2;
|
||||
else
|
||||
pad = 0;
|
||||
|
||||
/***** CONVOLUTION LAYER *****/
|
||||
/*****************************/
|
||||
// batch norm weights are before the conv layer
|
||||
// load BN biases (bn_biases)
|
||||
std::vector<float> bnBiases;
|
||||
for (int i = 0; i < filters; ++i)
|
||||
{
|
||||
bnBiases.push_back(weights[weightPtr]);
|
||||
weightPtr++;
|
||||
}
|
||||
// load BN weights
|
||||
std::vector<float> bnWeights;
|
||||
for (int i = 0; i < filters; ++i)
|
||||
{
|
||||
bnWeights.push_back(weights[weightPtr]);
|
||||
weightPtr++;
|
||||
}
|
||||
// load BN running_mean
|
||||
std::vector<float> bnRunningMean;
|
||||
for (int i = 0; i < filters; ++i)
|
||||
{
|
||||
bnRunningMean.push_back(weights[weightPtr]);
|
||||
weightPtr++;
|
||||
}
|
||||
// load BN running_var
|
||||
std::vector<float> bnRunningVar;
|
||||
for (int i = 0; i < filters; ++i)
|
||||
{
|
||||
// 1e-05 for numerical stability
|
||||
bnRunningVar.push_back(sqrt(weights[weightPtr] + 1.0e-5));
|
||||
weightPtr++;
|
||||
}
|
||||
// load Conv layer weights (GKCRS)
|
||||
int size = filters * inputChannels * kernelSize * kernelSize;
|
||||
nvinfer1::Weights convWt{nvinfer1::DataType::kFLOAT, nullptr, size};
|
||||
float* val = new float[size];
|
||||
for (int i = 0; i < size; ++i)
|
||||
{
|
||||
val[i] = weights[weightPtr];
|
||||
weightPtr++;
|
||||
}
|
||||
convWt.values = val;
|
||||
trtWeights.push_back(convWt);
|
||||
nvinfer1::Weights convBias{nvinfer1::DataType::kFLOAT, nullptr, 0};
|
||||
trtWeights.push_back(convBias);
|
||||
nvinfer1::IConvolutionLayer* conv = network->addConvolution(
|
||||
*input, filters, nvinfer1::DimsHW{kernelSize, kernelSize}, convWt, convBias);
|
||||
assert(conv != nullptr);
|
||||
std::string convLayerName = "conv_" + std::to_string(layerIdx);
|
||||
conv->setName(convLayerName.c_str());
|
||||
conv->setStride(nvinfer1::DimsHW{stride, stride});
|
||||
conv->setPadding(nvinfer1::DimsHW{pad, pad});
|
||||
|
||||
/***** BATCHNORM LAYER *****/
|
||||
/***************************/
|
||||
size = filters;
|
||||
// create the weights
|
||||
nvinfer1::Weights shift{nvinfer1::DataType::kFLOAT, nullptr, size};
|
||||
nvinfer1::Weights scale{nvinfer1::DataType::kFLOAT, nullptr, size};
|
||||
nvinfer1::Weights power{nvinfer1::DataType::kFLOAT, nullptr, size};
|
||||
float* shiftWt = new float[size];
|
||||
for (int i = 0; i < size; ++i)
|
||||
{
|
||||
shiftWt[i]
|
||||
= bnBiases.at(i) - ((bnRunningMean.at(i) * bnWeights.at(i)) / bnRunningVar.at(i));
|
||||
}
|
||||
shift.values = shiftWt;
|
||||
float* scaleWt = new float[size];
|
||||
for (int i = 0; i < size; ++i)
|
||||
{
|
||||
scaleWt[i] = bnWeights.at(i) / bnRunningVar[i];
|
||||
}
|
||||
scale.values = scaleWt;
|
||||
float* powerWt = new float[size];
|
||||
for (int i = 0; i < size; ++i)
|
||||
{
|
||||
powerWt[i] = 1.0;
|
||||
}
|
||||
power.values = powerWt;
|
||||
trtWeights.push_back(shift);
|
||||
trtWeights.push_back(scale);
|
||||
trtWeights.push_back(power);
|
||||
// Add the batch norm layers
|
||||
nvinfer1::IScaleLayer* bn = network->addScale(
|
||||
*conv->getOutput(0), nvinfer1::ScaleMode::kCHANNEL, shift, scale, power);
|
||||
assert(bn != nullptr);
|
||||
std::string bnLayerName = "batch_norm_" + std::to_string(layerIdx);
|
||||
bn->setName(bnLayerName.c_str());
|
||||
/***** ACTIVATION LAYER *****/
|
||||
/****************************/
|
||||
nvinfer1::ITensor* bnOutput = bn->getOutput(0);
|
||||
nvinfer1::IActivationLayer* leaky = network->addActivation(
|
||||
*bnOutput, nvinfer1::ActivationType::kLEAKY_RELU);
|
||||
leaky->setAlpha(0.1);
|
||||
assert(leaky != nullptr);
|
||||
std::string leakyLayerName = "leaky_" + std::to_string(layerIdx);
|
||||
leaky->setName(leakyLayerName.c_str());
|
||||
|
||||
return leaky;
|
||||
}
|
||||
|
||||
nvinfer1::ILayer* netAddUpsample(int layerIdx, std::map<std::string, std::string>& block,
|
||||
std::vector<float>& weights,
|
||||
std::vector<nvinfer1::Weights>& trtWeights, int& inputChannels,
|
||||
nvinfer1::ITensor* input, nvinfer1::INetworkDefinition* network)
|
||||
{
|
||||
assert(block.at("type") == "upsample");
|
||||
nvinfer1::Dims inpDims = input->getDimensions();
|
||||
assert(inpDims.nbDims == 3);
|
||||
assert(inpDims.d[1] == inpDims.d[2]);
|
||||
int h = inpDims.d[1];
|
||||
int w = inpDims.d[2];
|
||||
int stride = std::stoi(block.at("stride"));
|
||||
// add pre multiply matrix as a constant
|
||||
nvinfer1::Dims preDims{3,
|
||||
{1, stride * h, w}};
|
||||
|
||||
int size = stride * h * w;
|
||||
nvinfer1::Weights preMul{nvinfer1::DataType::kFLOAT, nullptr, size};
|
||||
float* preWt = new float[size];
|
||||
/* (2*h * w)
|
||||
[ [1, 0, ..., 0],
|
||||
[1, 0, ..., 0],
|
||||
[0, 1, ..., 0],
|
||||
[0, 1, ..., 0],
|
||||
...,
|
||||
...,
|
||||
[0, 0, ..., 1],
|
||||
[0, 0, ..., 1] ]
|
||||
*/
|
||||
for (int i = 0, idx = 0; i < h; ++i)
|
||||
{
|
||||
for (int s = 0; s < stride; ++s)
|
||||
{
|
||||
for (int j = 0; j < w; ++j, ++idx)
|
||||
{
|
||||
preWt[idx] = (i == j) ? 1.0 : 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
preMul.values = preWt;
|
||||
trtWeights.push_back(preMul);
|
||||
nvinfer1::IConstantLayer* preM = network->addConstant(preDims, preMul);
|
||||
assert(preM != nullptr);
|
||||
std::string preLayerName = "preMul_" + std::to_string(layerIdx);
|
||||
preM->setName(preLayerName.c_str());
|
||||
// add post multiply matrix as a constant
|
||||
nvinfer1::Dims postDims{3,
|
||||
{1, h, stride * w}};
|
||||
|
||||
size = stride * h * w;
|
||||
nvinfer1::Weights postMul{nvinfer1::DataType::kFLOAT, nullptr, size};
|
||||
float* postWt = new float[size];
|
||||
/* (h * 2*w)
|
||||
[ [1, 1, 0, 0, ..., 0, 0],
|
||||
[0, 0, 1, 1, ..., 0, 0],
|
||||
...,
|
||||
...,
|
||||
[0, 0, 0, 0, ..., 1, 1] ]
|
||||
*/
|
||||
for (int i = 0, idx = 0; i < h; ++i)
|
||||
{
|
||||
for (int j = 0; j < stride * w; ++j, ++idx)
|
||||
{
|
||||
postWt[idx] = (j / stride == i) ? 1.0 : 0.0;
|
||||
}
|
||||
}
|
||||
postMul.values = postWt;
|
||||
trtWeights.push_back(postMul);
|
||||
nvinfer1::IConstantLayer* post_m = network->addConstant(postDims, postMul);
|
||||
assert(post_m != nullptr);
|
||||
std::string postLayerName = "postMul_" + std::to_string(layerIdx);
|
||||
post_m->setName(postLayerName.c_str());
|
||||
// add matrix multiply layers for upsampling
|
||||
nvinfer1::IMatrixMultiplyLayer* mm1
|
||||
= network->addMatrixMultiply(*preM->getOutput(0), nvinfer1::MatrixOperation::kNONE, *input,
|
||||
nvinfer1::MatrixOperation::kNONE);
|
||||
assert(mm1 != nullptr);
|
||||
std::string mm1LayerName = "mm1_" + std::to_string(layerIdx);
|
||||
mm1->setName(mm1LayerName.c_str());
|
||||
nvinfer1::IMatrixMultiplyLayer* mm2
|
||||
= network->addMatrixMultiply(*mm1->getOutput(0), nvinfer1::MatrixOperation::kNONE,
|
||||
*post_m->getOutput(0), nvinfer1::MatrixOperation::kNONE);
|
||||
assert(mm2 != nullptr);
|
||||
std::string mm2LayerName = "mm2_" + std::to_string(layerIdx);
|
||||
mm2->setName(mm2LayerName.c_str());
|
||||
return mm2;
|
||||
}
|
||||
|
||||
void printLayerInfo(std::string layerIndex, std::string layerName, std::string layerInput,
|
||||
std::string layerOutput, std::string weightPtr)
|
||||
{
|
||||
std::cout << std::setw(6) << std::left << layerIndex << std::setw(15) << std::left << layerName;
|
||||
std::cout << std::setw(20) << std::left << layerInput << std::setw(20) << std::left
|
||||
<< layerOutput;
|
||||
std::cout << std::setw(6) << std::left << weightPtr << std::endl;
|
||||
}
|
||||
69
nvdsinfer_custom_impl_Yolo/trt_utils.h
Normal file
69
nvdsinfer_custom_impl_Yolo/trt_utils.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __TRT_UTILS_H__
|
||||
#define __TRT_UTILS_H__
|
||||
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include "NvInfer.h"
|
||||
|
||||
#define UNUSED(expr) (void)(expr)
|
||||
#define DIVUP(n, d) ((n) + (d)-1) / (d)
|
||||
|
||||
std::string trim(std::string s);
|
||||
float clamp(const float val, const float minVal, const float maxVal);
|
||||
bool fileExists(const std::string fileName, bool verbose = true);
|
||||
std::vector<float> loadWeights(const std::string weightsFilePath, const std::string& networkType);
|
||||
std::string dimsToString(const nvinfer1::Dims d);
|
||||
void displayDimType(const nvinfer1::Dims d);
|
||||
int getNumChannels(nvinfer1::ITensor* t);
|
||||
uint64_t get3DTensorVolume(nvinfer1::Dims inputDims);
|
||||
|
||||
// Helper functions to create yolo engine
|
||||
nvinfer1::ILayer* netAddMaxpool(int layerIdx, std::map<std::string, std::string>& block,
|
||||
nvinfer1::ITensor* input, nvinfer1::INetworkDefinition* network);
|
||||
nvinfer1::ILayer* netAddConvLinear(int layerIdx, std::map<std::string, std::string>& block,
|
||||
std::vector<float>& weights,
|
||||
std::vector<nvinfer1::Weights>& trtWeights, int& weightPtr,
|
||||
int& inputChannels, nvinfer1::ITensor* input,
|
||||
nvinfer1::INetworkDefinition* network);
|
||||
nvinfer1::ILayer* netAddConvBNLeaky(int layerIdx, std::map<std::string, std::string>& block,
|
||||
std::vector<float>& weights,
|
||||
std::vector<nvinfer1::Weights>& trtWeights, int& weightPtr,
|
||||
int& inputChannels, nvinfer1::ITensor* input,
|
||||
nvinfer1::INetworkDefinition* network);
|
||||
nvinfer1::ILayer* netAddUpsample(int layerIdx, std::map<std::string, std::string>& block,
|
||||
std::vector<float>& weights,
|
||||
std::vector<nvinfer1::Weights>& trtWeights, int& inputChannels,
|
||||
nvinfer1::ITensor* input, nvinfer1::INetworkDefinition* network);
|
||||
void printLayerInfo(std::string layerIndex, std::string layerName, std::string layerInput,
|
||||
std::string layerOutput, std::string weightPtr);
|
||||
|
||||
#endif
|
||||
BIN
nvdsinfer_custom_impl_Yolo/trt_utils.o
Normal file
BIN
nvdsinfer_custom_impl_Yolo/trt_utils.o
Normal file
Binary file not shown.
478
nvdsinfer_custom_impl_Yolo/yolo.cpp
Normal file
478
nvdsinfer_custom_impl_Yolo/yolo.cpp
Normal file
@@ -0,0 +1,478 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "yolo.h"
|
||||
#include "yoloPlugins.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iterator>
|
||||
|
||||
Yolo::Yolo(const NetworkInfo& networkInfo)
|
||||
: m_NetworkType(networkInfo.networkType), // yolov3
|
||||
m_ConfigFilePath(networkInfo.configFilePath), // yolov3.cfg
|
||||
m_WtsFilePath(networkInfo.wtsFilePath), // yolov3.weights
|
||||
m_DeviceType(networkInfo.deviceType), // kDLA, kGPU
|
||||
m_InputBlobName(networkInfo.inputBlobName), // data
|
||||
m_InputH(0),
|
||||
m_InputW(0),
|
||||
m_InputC(0),
|
||||
m_InputSize(0)
|
||||
{}
|
||||
|
||||
Yolo::~Yolo()
|
||||
{
|
||||
destroyNetworkUtils();
|
||||
}
|
||||
|
||||
nvinfer1::ICudaEngine *Yolo::createEngine (nvinfer1::IBuilder* builder)
|
||||
{
|
||||
assert (builder);
|
||||
|
||||
std::vector<float> weights = loadWeights(m_WtsFilePath, m_NetworkType);
|
||||
std::vector<nvinfer1::Weights> trtWeights;
|
||||
|
||||
nvinfer1::INetworkDefinition *network = builder->createNetworkV2(0);
|
||||
if (parseModel(*network) != NVDSINFER_SUCCESS) {
|
||||
network->destroy();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Build the engine
|
||||
std::cout << "Building the TensorRT Engine..." << std::endl;
|
||||
nvinfer1::IBuilderConfig *config = builder->createBuilderConfig();
|
||||
nvinfer1::ICudaEngine * engine = builder->buildEngineWithConfig(*network, *config);
|
||||
if (engine) {
|
||||
std::cout << "Building complete!" << std::endl;
|
||||
} else {
|
||||
std::cerr << "Building engine failed!" << std::endl;
|
||||
}
|
||||
|
||||
// destroy
|
||||
network->destroy();
|
||||
delete config;
|
||||
return engine;
|
||||
}
|
||||
|
||||
NvDsInferStatus Yolo::parseModel(nvinfer1::INetworkDefinition& network) {
|
||||
destroyNetworkUtils();
|
||||
|
||||
m_ConfigBlocks = parseConfigFile(m_ConfigFilePath);
|
||||
parseConfigBlocks();
|
||||
|
||||
std::vector<float> weights = loadWeights(m_WtsFilePath, m_NetworkType);
|
||||
// build yolo network
|
||||
std::cout << "Building Yolo network..." << std::endl;
|
||||
NvDsInferStatus status = buildYoloNetwork(weights, network);
|
||||
|
||||
if (status == NVDSINFER_SUCCESS) {
|
||||
std::cout << "Building yolo network complete!" << std::endl;
|
||||
} else {
|
||||
std::cerr << "Building yolo network failed!" << std::endl;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
NvDsInferStatus Yolo::buildYoloNetwork(
|
||||
std::vector<float>& weights, nvinfer1::INetworkDefinition& network) {
|
||||
int weightPtr = 0;
|
||||
int channels = m_InputC;
|
||||
|
||||
nvinfer1::ITensor* data =
|
||||
network.addInput(m_InputBlobName.c_str(), nvinfer1::DataType::kFLOAT,
|
||||
nvinfer1::Dims3{static_cast<int>(m_InputC),
|
||||
static_cast<int>(m_InputH), static_cast<int>(m_InputW)});
|
||||
assert(data != nullptr && data->getDimensions().nbDims > 0);
|
||||
|
||||
nvinfer1::ITensor* previous = data;
|
||||
std::vector<nvinfer1::ITensor*> tensorOutputs;
|
||||
uint outputTensorCount = 0;
|
||||
|
||||
// build the network using the network API
|
||||
for (uint i = 0; i < m_ConfigBlocks.size(); ++i) {
|
||||
// check if num. of channels is correct
|
||||
assert(getNumChannels(previous) == channels);
|
||||
std::string layerIndex = "(" + std::to_string(tensorOutputs.size()) + ")";
|
||||
|
||||
if (m_ConfigBlocks.at(i).at("type") == "net") {
|
||||
printLayerInfo("", "layer", " inp_size", " out_size", "weightPtr");
|
||||
} else if (m_ConfigBlocks.at(i).at("type") == "convolutional") {
|
||||
std::string inputVol = dimsToString(previous->getDimensions());
|
||||
nvinfer1::ILayer* out;
|
||||
std::string layerType;
|
||||
// check if batch_norm enabled
|
||||
if (m_ConfigBlocks.at(i).find("batch_normalize") !=
|
||||
m_ConfigBlocks.at(i).end()) {
|
||||
out = netAddConvBNLeaky(i, m_ConfigBlocks.at(i), weights,
|
||||
m_TrtWeights, weightPtr, channels, previous, &network);
|
||||
layerType = "conv-bn-leaky";
|
||||
}
|
||||
else
|
||||
{
|
||||
out = netAddConvLinear(i, m_ConfigBlocks.at(i), weights,
|
||||
m_TrtWeights, weightPtr, channels, previous, &network);
|
||||
layerType = "conv-linear";
|
||||
}
|
||||
previous = out->getOutput(0);
|
||||
assert(previous != nullptr);
|
||||
channels = getNumChannels(previous);
|
||||
std::string outputVol = dimsToString(previous->getDimensions());
|
||||
tensorOutputs.push_back(out->getOutput(0));
|
||||
printLayerInfo(layerIndex, layerType, inputVol, outputVol, std::to_string(weightPtr));
|
||||
} else if (m_ConfigBlocks.at(i).at("type") == "shortcut") {
|
||||
assert(m_ConfigBlocks.at(i).at("activation") == "linear");
|
||||
assert(m_ConfigBlocks.at(i).find("from") !=
|
||||
m_ConfigBlocks.at(i).end());
|
||||
int from = stoi(m_ConfigBlocks.at(i).at("from"));
|
||||
|
||||
std::string inputVol = dimsToString(previous->getDimensions());
|
||||
// check if indexes are correct
|
||||
assert((i - 2 >= 0) && (i - 2 < tensorOutputs.size()));
|
||||
assert((i + from - 1 >= 0) && (i + from - 1 < tensorOutputs.size()));
|
||||
assert(i + from - 1 < i - 2);
|
||||
nvinfer1::IElementWiseLayer* ew = network.addElementWise(
|
||||
*tensorOutputs[i - 2], *tensorOutputs[i + from - 1],
|
||||
nvinfer1::ElementWiseOperation::kSUM);
|
||||
assert(ew != nullptr);
|
||||
std::string ewLayerName = "shortcut_" + std::to_string(i);
|
||||
ew->setName(ewLayerName.c_str());
|
||||
previous = ew->getOutput(0);
|
||||
assert(previous != nullptr);
|
||||
std::string outputVol = dimsToString(previous->getDimensions());
|
||||
tensorOutputs.push_back(ew->getOutput(0));
|
||||
printLayerInfo(layerIndex, "skip", inputVol, outputVol, " -");
|
||||
} else if (m_ConfigBlocks.at(i).at("type") == "yolo") {
|
||||
nvinfer1::Dims prevTensorDims = previous->getDimensions();
|
||||
assert(prevTensorDims.d[1] == prevTensorDims.d[2]);
|
||||
TensorInfo& curYoloTensor = m_OutputTensors.at(outputTensorCount);
|
||||
curYoloTensor.gridSize = prevTensorDims.d[1];
|
||||
curYoloTensor.stride = m_InputW / curYoloTensor.gridSize;
|
||||
m_OutputTensors.at(outputTensorCount).volume = curYoloTensor.gridSize
|
||||
* curYoloTensor.gridSize
|
||||
* (curYoloTensor.numBBoxes * (5 + curYoloTensor.numClasses));
|
||||
std::string layerName = "yolo_" + std::to_string(i);
|
||||
curYoloTensor.blobName = layerName;
|
||||
nvinfer1::IPluginV2* yoloPlugin
|
||||
= new YoloLayerV3(m_OutputTensors.at(outputTensorCount).numBBoxes,
|
||||
m_OutputTensors.at(outputTensorCount).numClasses,
|
||||
m_OutputTensors.at(outputTensorCount).gridSize);
|
||||
assert(yoloPlugin != nullptr);
|
||||
nvinfer1::IPluginV2Layer* yolo =
|
||||
network.addPluginV2(&previous, 1, *yoloPlugin);
|
||||
assert(yolo != nullptr);
|
||||
yolo->setName(layerName.c_str());
|
||||
std::string inputVol = dimsToString(previous->getDimensions());
|
||||
previous = yolo->getOutput(0);
|
||||
assert(previous != nullptr);
|
||||
previous->setName(layerName.c_str());
|
||||
std::string outputVol = dimsToString(previous->getDimensions());
|
||||
network.markOutput(*previous);
|
||||
channels = getNumChannels(previous);
|
||||
tensorOutputs.push_back(yolo->getOutput(0));
|
||||
printLayerInfo(layerIndex, "yolo", inputVol, outputVol, std::to_string(weightPtr));
|
||||
++outputTensorCount;
|
||||
} else if (m_ConfigBlocks.at(i).at("type") == "region") {
|
||||
std::string layerName = "region_" + std::to_string(i);
|
||||
|
||||
nvinfer1::Dims prevTensorDims = previous->getDimensions();
|
||||
assert(prevTensorDims.d[1] == prevTensorDims.d[2]);
|
||||
|
||||
TensorInfo& curRegionTensor = m_OutputTensors.at(outputTensorCount);
|
||||
curRegionTensor.gridSize = prevTensorDims.d[1];
|
||||
curRegionTensor.stride = m_InputW / curRegionTensor.gridSize;
|
||||
m_OutputTensors.at(outputTensorCount).volume = curRegionTensor.gridSize
|
||||
* curRegionTensor.gridSize
|
||||
* (curRegionTensor.numBBoxes * (5 + curRegionTensor.numClasses));
|
||||
curRegionTensor.blobName = layerName;
|
||||
|
||||
auto creator = getPluginRegistry()->getPluginCreator("Region_TRT", "1");
|
||||
|
||||
int num = static_cast<int>(curRegionTensor.numBBoxes);
|
||||
int coords = 4;
|
||||
int classes = static_cast<int>(curRegionTensor.numClasses);
|
||||
nvinfer1::PluginField fields[]{
|
||||
{"num", &num, nvinfer1::PluginFieldType::kINT32, 1},
|
||||
{"coords", &coords, nvinfer1::PluginFieldType::kINT32, 1},
|
||||
{"classes", &classes, nvinfer1::PluginFieldType::kINT32, 1},
|
||||
{"smTree", nullptr, nvinfer1::PluginFieldType::kINT32, 1}
|
||||
};
|
||||
nvinfer1::PluginFieldCollection pluginData;
|
||||
pluginData.nbFields = 4;
|
||||
pluginData.fields = fields;
|
||||
|
||||
nvinfer1::IPluginV2 *regionPlugin = creator->createPlugin(layerName.c_str(), &pluginData);
|
||||
assert(regionPlugin != nullptr);
|
||||
nvinfer1::IPluginV2Layer* region =
|
||||
network.addPluginV2(&previous, 1, *regionPlugin);
|
||||
assert(region != nullptr);
|
||||
|
||||
std::string inputVol = dimsToString(previous->getDimensions());
|
||||
previous = region->getOutput(0);
|
||||
assert(previous != nullptr);
|
||||
previous->setName(layerName.c_str());
|
||||
std::string outputVol = dimsToString(previous->getDimensions());
|
||||
network.markOutput(*previous);
|
||||
channels = getNumChannels(previous);
|
||||
tensorOutputs.push_back(region->getOutput(0));
|
||||
printLayerInfo(layerIndex, "region", inputVol, outputVol, std::to_string(weightPtr));
|
||||
std::cout << "Anchors are being converted to network input resolution i.e. Anchors x "
|
||||
<< curRegionTensor.stride << " (stride)" << std::endl;
|
||||
for (auto& anchor : curRegionTensor.anchors) anchor *= curRegionTensor.stride;
|
||||
++outputTensorCount;
|
||||
} else if (m_ConfigBlocks.at(i).at("type") == "reorg") {
|
||||
auto creator = getPluginRegistry()->getPluginCreator("Reorg_TRT", "1");
|
||||
|
||||
|
||||
int stride = 2;
|
||||
nvinfer1::PluginField strideField{"stride", &stride, nvinfer1::PluginFieldType::kINT32, 1};
|
||||
nvinfer1::PluginFieldCollection pluginData;
|
||||
pluginData.nbFields = 1;
|
||||
pluginData.fields = &strideField;
|
||||
|
||||
std::string layerName = "reorg_" + std::to_string(i);
|
||||
nvinfer1::IPluginV2 *reorgPlugin = creator->createPlugin(layerName.c_str(), &pluginData);
|
||||
assert(reorgPlugin != nullptr);
|
||||
nvinfer1::IPluginV2Layer* reorg =
|
||||
network.addPluginV2(&previous, 1, *reorgPlugin);
|
||||
assert(reorg != nullptr);
|
||||
|
||||
std::string inputVol = dimsToString(previous->getDimensions());
|
||||
previous = reorg->getOutput(0);
|
||||
assert(previous != nullptr);
|
||||
std::string outputVol = dimsToString(previous->getDimensions());
|
||||
channels = getNumChannels(previous);
|
||||
tensorOutputs.push_back(reorg->getOutput(0));
|
||||
printLayerInfo(layerIndex, "reorg", inputVol, outputVol, std::to_string(weightPtr));
|
||||
}
|
||||
// route layers (single or concat)
|
||||
else if (m_ConfigBlocks.at(i).at("type") == "route") {
|
||||
std::string strLayers = m_ConfigBlocks.at(i).at("layers");
|
||||
std::vector<int> idxLayers;
|
||||
size_t lastPos = 0, pos = 0;
|
||||
while ((pos = strLayers.find(',', lastPos)) != std::string::npos) {
|
||||
int vL = std::stoi(trim(strLayers.substr(lastPos, pos - lastPos)));
|
||||
idxLayers.push_back (vL);
|
||||
lastPos = pos + 1;
|
||||
}
|
||||
if (lastPos < strLayers.length()) {
|
||||
std::string lastV = trim(strLayers.substr(lastPos));
|
||||
if (!lastV.empty()) {
|
||||
idxLayers.push_back (std::stoi(lastV));
|
||||
}
|
||||
}
|
||||
assert (!idxLayers.empty());
|
||||
std::vector<nvinfer1::ITensor*> concatInputs;
|
||||
for (int idxLayer : idxLayers) {
|
||||
if (idxLayer < 0) {
|
||||
idxLayer = tensorOutputs.size() + idxLayer;
|
||||
}
|
||||
assert (idxLayer >= 0 && idxLayer < (int)tensorOutputs.size());
|
||||
concatInputs.push_back (tensorOutputs[idxLayer]);
|
||||
}
|
||||
nvinfer1::IConcatenationLayer* concat =
|
||||
network.addConcatenation(concatInputs.data(), concatInputs.size());
|
||||
assert(concat != nullptr);
|
||||
std::string concatLayerName = "route_" + std::to_string(i - 1);
|
||||
concat->setName(concatLayerName.c_str());
|
||||
// concatenate along the channel dimension
|
||||
concat->setAxis(0);
|
||||
previous = concat->getOutput(0);
|
||||
assert(previous != nullptr);
|
||||
std::string outputVol = dimsToString(previous->getDimensions());
|
||||
// set the output volume depth
|
||||
channels
|
||||
= getNumChannels(previous);
|
||||
tensorOutputs.push_back(concat->getOutput(0));
|
||||
printLayerInfo(layerIndex, "route", " -", outputVol,
|
||||
std::to_string(weightPtr));
|
||||
} else if (m_ConfigBlocks.at(i).at("type") == "upsample") {
|
||||
std::string inputVol = dimsToString(previous->getDimensions());
|
||||
nvinfer1::ILayer* out = netAddUpsample(i - 1, m_ConfigBlocks[i],
|
||||
weights, m_TrtWeights, channels, previous, &network);
|
||||
previous = out->getOutput(0);
|
||||
std::string outputVol = dimsToString(previous->getDimensions());
|
||||
tensorOutputs.push_back(out->getOutput(0));
|
||||
printLayerInfo(layerIndex, "upsample", inputVol, outputVol, " -");
|
||||
} else if (m_ConfigBlocks.at(i).at("type") == "maxpool") {
|
||||
std::string inputVol = dimsToString(previous->getDimensions());
|
||||
nvinfer1::ILayer* out =
|
||||
netAddMaxpool(i, m_ConfigBlocks.at(i), previous, &network);
|
||||
previous = out->getOutput(0);
|
||||
assert(previous != nullptr);
|
||||
std::string outputVol = dimsToString(previous->getDimensions());
|
||||
tensorOutputs.push_back(out->getOutput(0));
|
||||
printLayerInfo(layerIndex, "maxpool", inputVol, outputVol, std::to_string(weightPtr));
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Unsupported layer type --> \""
|
||||
<< m_ConfigBlocks.at(i).at("type") << "\"" << std::endl;
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
if ((int)weights.size() != weightPtr)
|
||||
{
|
||||
std::cout << "Number of unused weights left : " << weights.size() - weightPtr << std::endl;
|
||||
assert(0);
|
||||
}
|
||||
|
||||
std::cout << "Output yolo blob names :" << std::endl;
|
||||
for (auto& tensor : m_OutputTensors) {
|
||||
std::cout << tensor.blobName << std::endl;
|
||||
}
|
||||
|
||||
int nbLayers = network.getNbLayers();
|
||||
std::cout << "Total number of yolo layers: " << nbLayers << std::endl;
|
||||
|
||||
return NVDSINFER_SUCCESS;
|
||||
}
|
||||
|
||||
std::vector<std::map<std::string, std::string>>
|
||||
Yolo::parseConfigFile (const std::string cfgFilePath)
|
||||
{
|
||||
assert(fileExists(cfgFilePath));
|
||||
std::ifstream file(cfgFilePath);
|
||||
assert(file.good());
|
||||
std::string line;
|
||||
std::vector<std::map<std::string, std::string>> blocks;
|
||||
std::map<std::string, std::string> block;
|
||||
|
||||
while (getline(file, line))
|
||||
{
|
||||
if (line.size() == 0) continue;
|
||||
if (line.front() == '#') continue;
|
||||
line = trim(line);
|
||||
if (line.front() == '[')
|
||||
{
|
||||
if (block.size() > 0)
|
||||
{
|
||||
blocks.push_back(block);
|
||||
block.clear();
|
||||
}
|
||||
std::string key = "type";
|
||||
std::string value = trim(line.substr(1, line.size() - 2));
|
||||
block.insert(std::pair<std::string, std::string>(key, value));
|
||||
}
|
||||
else
|
||||
{
|
||||
int cpos = line.find('=');
|
||||
std::string key = trim(line.substr(0, cpos));
|
||||
std::string value = trim(line.substr(cpos + 1));
|
||||
block.insert(std::pair<std::string, std::string>(key, value));
|
||||
}
|
||||
}
|
||||
blocks.push_back(block);
|
||||
return blocks;
|
||||
}
|
||||
|
||||
void Yolo::parseConfigBlocks()
|
||||
{
|
||||
for (auto block : m_ConfigBlocks) {
|
||||
if (block.at("type") == "net")
|
||||
{
|
||||
assert((block.find("height") != block.end())
|
||||
&& "Missing 'height' param in network cfg");
|
||||
assert((block.find("width") != block.end()) && "Missing 'width' param in network cfg");
|
||||
assert((block.find("channels") != block.end())
|
||||
&& "Missing 'channels' param in network cfg");
|
||||
|
||||
m_InputH = std::stoul(block.at("height"));
|
||||
m_InputW = std::stoul(block.at("width"));
|
||||
m_InputC = std::stoul(block.at("channels"));
|
||||
assert(m_InputW == m_InputH);
|
||||
m_InputSize = m_InputC * m_InputH * m_InputW;
|
||||
}
|
||||
else if ((block.at("type") == "region") || (block.at("type") == "yolo"))
|
||||
{
|
||||
assert((block.find("num") != block.end())
|
||||
&& std::string("Missing 'num' param in " + block.at("type") + " layer").c_str());
|
||||
assert((block.find("classes") != block.end())
|
||||
&& std::string("Missing 'classes' param in " + block.at("type") + " layer")
|
||||
.c_str());
|
||||
assert((block.find("anchors") != block.end())
|
||||
&& std::string("Missing 'anchors' param in " + block.at("type") + " layer")
|
||||
.c_str());
|
||||
|
||||
TensorInfo outputTensor;
|
||||
std::string anchorString = block.at("anchors");
|
||||
while (!anchorString.empty())
|
||||
{
|
||||
int npos = anchorString.find_first_of(',');
|
||||
if (npos != -1)
|
||||
{
|
||||
float anchor = std::stof(trim(anchorString.substr(0, npos)));
|
||||
outputTensor.anchors.push_back(anchor);
|
||||
anchorString.erase(0, npos + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
float anchor = std::stof(trim(anchorString));
|
||||
outputTensor.anchors.push_back(anchor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((m_NetworkType == "yolov3") || (m_NetworkType == "yolov3-tiny"))
|
||||
{
|
||||
assert((block.find("mask") != block.end())
|
||||
&& std::string("Missing 'mask' param in " + block.at("type") + " layer")
|
||||
.c_str());
|
||||
|
||||
std::string maskString = block.at("mask");
|
||||
while (!maskString.empty())
|
||||
{
|
||||
int npos = maskString.find_first_of(',');
|
||||
if (npos != -1)
|
||||
{
|
||||
uint mask = std::stoul(trim(maskString.substr(0, npos)));
|
||||
outputTensor.masks.push_back(mask);
|
||||
maskString.erase(0, npos + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint mask = std::stoul(trim(maskString));
|
||||
outputTensor.masks.push_back(mask);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
outputTensor.numBBoxes = outputTensor.masks.size() > 0
|
||||
? outputTensor.masks.size()
|
||||
: std::stoul(trim(block.at("num")));
|
||||
outputTensor.numClasses = std::stoul(block.at("classes"));
|
||||
m_OutputTensors.push_back(outputTensor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Yolo::destroyNetworkUtils() {
|
||||
// deallocate the weights
|
||||
for (uint i = 0; i < m_TrtWeights.size(); ++i) {
|
||||
if (m_TrtWeights[i].count > 0)
|
||||
free(const_cast<void*>(m_TrtWeights[i].values));
|
||||
}
|
||||
m_TrtWeights.clear();
|
||||
}
|
||||
|
||||
103
nvdsinfer_custom_impl_Yolo/yolo.h
Normal file
103
nvdsinfer_custom_impl_Yolo/yolo.h
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _YOLO_H_
|
||||
#define _YOLO_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#include "NvInfer.h"
|
||||
#include "trt_utils.h"
|
||||
|
||||
#include "nvdsinfer_custom_impl.h"
|
||||
|
||||
/**
|
||||
* Holds all the file paths required to build a network.
|
||||
*/
|
||||
struct NetworkInfo
|
||||
{
|
||||
std::string networkType;
|
||||
std::string configFilePath;
|
||||
std::string wtsFilePath;
|
||||
std::string deviceType;
|
||||
std::string inputBlobName;
|
||||
};
|
||||
|
||||
/**
|
||||
* Holds information about an output tensor of the yolo network.
|
||||
*/
|
||||
struct TensorInfo
|
||||
{
|
||||
std::string blobName;
|
||||
uint stride{0};
|
||||
uint gridSize{0};
|
||||
uint numClasses{0};
|
||||
uint numBBoxes{0};
|
||||
uint64_t volume{0};
|
||||
std::vector<uint> masks;
|
||||
std::vector<float> anchors;
|
||||
int bindingIndex{-1};
|
||||
float* hostBuffer{nullptr};
|
||||
};
|
||||
|
||||
class Yolo : public IModelParser {
|
||||
public:
|
||||
Yolo(const NetworkInfo& networkInfo);
|
||||
~Yolo() override;
|
||||
bool hasFullDimsSupported() const override { return false; }
|
||||
const char* getModelName() const override {
|
||||
return m_ConfigFilePath.empty() ? m_NetworkType.c_str()
|
||||
: m_ConfigFilePath.c_str();
|
||||
}
|
||||
NvDsInferStatus parseModel(nvinfer1::INetworkDefinition& network) override;
|
||||
|
||||
nvinfer1::ICudaEngine *createEngine (nvinfer1::IBuilder* builder);
|
||||
|
||||
protected:
|
||||
const std::string m_NetworkType;
|
||||
const std::string m_ConfigFilePath;
|
||||
const std::string m_WtsFilePath;
|
||||
const std::string m_DeviceType;
|
||||
const std::string m_InputBlobName;
|
||||
std::vector<TensorInfo> m_OutputTensors;
|
||||
std::vector<std::map<std::string, std::string>> m_ConfigBlocks;
|
||||
uint m_InputH;
|
||||
uint m_InputW;
|
||||
uint m_InputC;
|
||||
uint64_t m_InputSize;
|
||||
|
||||
// TRT specific members
|
||||
std::vector<nvinfer1::Weights> m_TrtWeights;
|
||||
|
||||
private:
|
||||
NvDsInferStatus buildYoloNetwork(
|
||||
std::vector<float>& weights, nvinfer1::INetworkDefinition& network);
|
||||
std::vector<std::map<std::string, std::string>> parseConfigFile(
|
||||
const std::string cfgFilePath);
|
||||
void parseConfigBlocks();
|
||||
void destroyNetworkUtils();
|
||||
};
|
||||
|
||||
#endif // _YOLO_H_
|
||||
BIN
nvdsinfer_custom_impl_Yolo/yolo.o
Normal file
BIN
nvdsinfer_custom_impl_Yolo/yolo.o
Normal file
Binary file not shown.
127
nvdsinfer_custom_impl_Yolo/yoloPlugins.cpp
Normal file
127
nvdsinfer_custom_impl_Yolo/yoloPlugins.cpp
Normal file
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "yoloPlugins.h"
|
||||
#include "NvInferPlugin.h"
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
namespace {
|
||||
template <typename T>
|
||||
void write(char*& buffer, const T& val)
|
||||
{
|
||||
*reinterpret_cast<T*>(buffer) = val;
|
||||
buffer += sizeof(T);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void read(const char*& buffer, T& val)
|
||||
{
|
||||
val = *reinterpret_cast<const T*>(buffer);
|
||||
buffer += sizeof(T);
|
||||
}
|
||||
} //namespace
|
||||
|
||||
// Forward declaration of cuda kernels
|
||||
cudaError_t cudaYoloLayerV3 (
|
||||
const void* input, void* output, const uint& batchSize,
|
||||
const uint& gridSize, const uint& numOutputClasses,
|
||||
const uint& numBBoxes, uint64_t outputSize, cudaStream_t stream);
|
||||
|
||||
YoloLayerV3::YoloLayerV3 (const void* data, size_t length)
|
||||
{
|
||||
const char *d = static_cast<const char*>(data);
|
||||
read(d, m_NumBoxes);
|
||||
read(d, m_NumClasses);
|
||||
read(d, m_GridSize);
|
||||
read(d, m_OutputSize);
|
||||
};
|
||||
|
||||
YoloLayerV3::YoloLayerV3 (
|
||||
const uint& numBoxes, const uint& numClasses, const uint& gridSize) :
|
||||
m_NumBoxes(numBoxes),
|
||||
m_NumClasses(numClasses),
|
||||
m_GridSize(gridSize)
|
||||
{
|
||||
assert(m_NumBoxes > 0);
|
||||
assert(m_NumClasses > 0);
|
||||
assert(m_GridSize > 0);
|
||||
m_OutputSize = m_GridSize * m_GridSize * (m_NumBoxes * (4 + 1 + m_NumClasses));
|
||||
};
|
||||
|
||||
nvinfer1::Dims
|
||||
YoloLayerV3::getOutputDimensions(
|
||||
int index, const nvinfer1::Dims* inputs, int nbInputDims) noexcept
|
||||
{
|
||||
assert(index == 0);
|
||||
assert(nbInputDims == 1);
|
||||
return inputs[0];
|
||||
}
|
||||
|
||||
bool YoloLayerV3::supportsFormat (
|
||||
nvinfer1::DataType type, nvinfer1::PluginFormat format) const noexcept {
|
||||
return (type == nvinfer1::DataType::kFLOAT &&
|
||||
format == nvinfer1::PluginFormat::kLINEAR);
|
||||
}
|
||||
|
||||
void
|
||||
YoloLayerV3::configureWithFormat (
|
||||
const nvinfer1::Dims* inputDims, int nbInputs,
|
||||
const nvinfer1::Dims* outputDims, int nbOutputs,
|
||||
nvinfer1::DataType type, nvinfer1::PluginFormat format, int maxBatchSize) noexcept
|
||||
{
|
||||
assert(nbInputs == 1);
|
||||
assert (format == nvinfer1::PluginFormat::kLINEAR);
|
||||
assert(inputDims != nullptr);
|
||||
}
|
||||
|
||||
int YoloLayerV3::enqueue(
|
||||
int batchSize, void const* const* inputs, void* const* outputs, void* workspace,
|
||||
cudaStream_t stream) noexcept
|
||||
{
|
||||
CHECK(cudaYoloLayerV3(
|
||||
inputs[0], outputs[0], batchSize, m_GridSize, m_NumClasses, m_NumBoxes,
|
||||
m_OutputSize, stream));
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t YoloLayerV3::getSerializationSize() const noexcept
|
||||
{
|
||||
return sizeof(m_NumBoxes) + sizeof(m_NumClasses) + sizeof(m_GridSize) + sizeof(m_OutputSize);
|
||||
}
|
||||
|
||||
void YoloLayerV3::serialize(void* buffer) const noexcept
|
||||
{
|
||||
char *d = static_cast<char*>(buffer);
|
||||
write(d, m_NumBoxes);
|
||||
write(d, m_NumClasses);
|
||||
write(d, m_GridSize);
|
||||
write(d, m_OutputSize);
|
||||
}
|
||||
|
||||
nvinfer1::IPluginV2* YoloLayerV3::clone() const noexcept
|
||||
{
|
||||
return new YoloLayerV3 (m_NumBoxes, m_NumClasses, m_GridSize);
|
||||
}
|
||||
|
||||
REGISTER_TENSORRT_PLUGIN(YoloLayerV3PluginCreator);
|
||||
136
nvdsinfer_custom_impl_Yolo/yoloPlugins.h
Normal file
136
nvdsinfer_custom_impl_Yolo/yoloPlugins.h
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __YOLO_PLUGINS__
|
||||
#define __YOLO_PLUGINS__
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <cuda_runtime_api.h>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
#include "NvInferPlugin.h"
|
||||
|
||||
#define CHECK(status) \
|
||||
{ \
|
||||
if (status != 0) \
|
||||
{ \
|
||||
std::cout << "Cuda failure: " << cudaGetErrorString(status) << " in file " << __FILE__ \
|
||||
<< " at line " << __LINE__ << std::endl; \
|
||||
abort(); \
|
||||
} \
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
const char* YOLOV3LAYER_PLUGIN_VERSION {"1"};
|
||||
const char* YOLOV3LAYER_PLUGIN_NAME {"YoloLayerV3_TRT"};
|
||||
} // namespace
|
||||
|
||||
class YoloLayerV3 : public nvinfer1::IPluginV2
|
||||
{
|
||||
public:
|
||||
YoloLayerV3 (const void* data, size_t length);
|
||||
YoloLayerV3 (const uint& numBoxes, const uint& numClasses, const uint& gridSize);
|
||||
const char* getPluginType () const noexcept override { return YOLOV3LAYER_PLUGIN_NAME; }
|
||||
const char* getPluginVersion () const noexcept override { return YOLOV3LAYER_PLUGIN_VERSION; }
|
||||
int getNbOutputs () const noexcept override { return 1; }
|
||||
|
||||
nvinfer1::Dims getOutputDimensions (
|
||||
int index, const nvinfer1::Dims* inputs,
|
||||
int nbInputDims) noexcept override;
|
||||
|
||||
bool supportsFormat (
|
||||
nvinfer1::DataType type, nvinfer1::PluginFormat format) const noexcept override;
|
||||
|
||||
void configureWithFormat (
|
||||
const nvinfer1::Dims* inputDims, int nbInputs,
|
||||
const nvinfer1::Dims* outputDims, int nbOutputs,
|
||||
nvinfer1::DataType type, nvinfer1::PluginFormat format, int maxBatchSize) noexcept override;
|
||||
|
||||
int initialize () noexcept override { return 0; }
|
||||
void terminate () noexcept override {}
|
||||
size_t getWorkspaceSize (int maxBatchSize) const noexcept override { return 0; }
|
||||
int enqueue (
|
||||
int batchSize, void const* const* inputs, void* const* outputs,
|
||||
void* workspace, cudaStream_t stream) noexcept override;
|
||||
size_t getSerializationSize() const noexcept override;
|
||||
void serialize (void* buffer) const noexcept override;
|
||||
void destroy () noexcept override { delete this; }
|
||||
nvinfer1::IPluginV2* clone() const noexcept override;
|
||||
|
||||
void setPluginNamespace (const char* pluginNamespace) noexcept override {
|
||||
m_Namespace = pluginNamespace;
|
||||
}
|
||||
virtual const char* getPluginNamespace () const noexcept override {
|
||||
return m_Namespace.c_str();
|
||||
}
|
||||
|
||||
private:
|
||||
uint m_NumBoxes {0};
|
||||
uint m_NumClasses {0};
|
||||
uint m_GridSize {0};
|
||||
uint64_t m_OutputSize {0};
|
||||
std::string m_Namespace {""};
|
||||
};
|
||||
|
||||
class YoloLayerV3PluginCreator : public nvinfer1::IPluginCreator
|
||||
{
|
||||
public:
|
||||
YoloLayerV3PluginCreator () {}
|
||||
~YoloLayerV3PluginCreator () {}
|
||||
|
||||
const char* getPluginName () const noexcept override { return YOLOV3LAYER_PLUGIN_NAME; }
|
||||
const char* getPluginVersion () const noexcept override { return YOLOV3LAYER_PLUGIN_VERSION; }
|
||||
|
||||
const nvinfer1::PluginFieldCollection* getFieldNames() noexcept override {
|
||||
std::cerr<< "YoloLayerV3PluginCreator::getFieldNames is not implemented" << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nvinfer1::IPluginV2* createPlugin (
|
||||
const char* name, const nvinfer1::PluginFieldCollection* fc) noexcept override
|
||||
{
|
||||
std::cerr<< "YoloLayerV3PluginCreator::getFieldNames is not implemented.\n";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nvinfer1::IPluginV2* deserializePlugin (
|
||||
const char* name, const void* serialData, size_t serialLength) noexcept override
|
||||
{
|
||||
std::cout << "Deserialize yoloLayerV3 plugin: " << name << std::endl;
|
||||
return new YoloLayerV3(serialData, serialLength);
|
||||
}
|
||||
|
||||
void setPluginNamespace(const char* libNamespace) noexcept override {
|
||||
m_Namespace = libNamespace;
|
||||
}
|
||||
const char* getPluginNamespace() const noexcept override {
|
||||
return m_Namespace.c_str();
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_Namespace {""};
|
||||
};
|
||||
|
||||
#endif // __YOLO_PLUGINS__
|
||||
BIN
nvdsinfer_custom_impl_Yolo/yoloPlugins.o
Normal file
BIN
nvdsinfer_custom_impl_Yolo/yoloPlugins.o
Normal file
Binary file not shown.
Reference in New Issue
Block a user