Hello again, I made a custom parsing function for my classifier
I assigned the values where the sample did
but when I print this in my python code:
print(f"result_class_id {current_obj_classification.result_class_id}, "
f"label_id:{current_obj_classification.label_id} "
f"number of labels {obj_class_meta.num_labels} "
# f"\nlabel {current_obj_classification.result_label}, "
f"result label length {len(current_obj_classification.result_label)}\n"
f"result probability {current_obj_classification.result_prob}"
f"\n\n--------------------------------------------")
I get
result_class_id 0, label_id:32748 number of labels 1 result label length 128
result probability 0.0
--------------------------------------------
result_class_id 0, label_id:0 number of labels 1 result label length 128
result probability 2.0037627128951483e-16
--------------------------------------------
result_class_id 0, label_id:0 number of labels 1 result label length 128
result probability 8918679552.0
--------------------------------------------
result_class_id 0, label_id:0 number of labels 1 result label length 128
result probability 0.0
--------------------------------------------
this is the function I call in my config
custom-lib-path=libnvds_infercustomparser.so
parse-classifier-func-name=NvDsInferClassiferParseCustomSoftmax
(the model itself has a softmax (None,1) but I want to express two classes with it like it shows here, does that affect the output? )
bool NvDsInferClassiferParseCustomSoftmax (std::vector<NvDsInferLayerInfo> const &outputLayersInfo,
NvDsInferNetworkInfo const &networkInfo,
float classifierThreshold,
std::vector<NvDsInferAttribute> &attrList,
std::string &descString)
{
/* Get the number of attributes supported by the classifier. */
unsigned int numAttributes = outputLayersInfo.size();
/* Iterate through all the output coverage layers of the classifier.
*/
// std::cout << "number of attributes "<< numAttributes << std::endl;
for (unsigned int l = 0; l < numAttributes; l++)
{
/* outputCoverageBuffer for classifiers is usually a softmax layer.
* The layer is an array of probabilities of the object belonging
* to each class with each probability being in the range [0,1] and
* sum all probabilities will be 1.
*/
NvDsInferDimsCHW dims;
getDimsCHWFromDims(dims, outputLayersInfo[l].inferDims);
unsigned int numClasses = dims.c;
float *outputCoverageBuffer = (float *) outputLayersInfo[l].buffer;
// float maxProbability = 0;
bool attrFound = false;
NvDsInferAttribute attr;
/* Unlike the original function: this function is made for a classifier with one probability and 2 classes
* 0 emergency 1 non_emergency, so instead of looping over classes we'll just compare the confidenece to the
* threshold where (number> thresh) => none emergency | (number < thresh) => emergency */
float probability = outputCoverageBuffer[0]; //[c];
if (probability > classifierThreshold)
{
attrFound = true;
attr.attributeIndex = l; //l;
attr.attributeValue = 1; //c;
attr.attributeConfidence = (probability-classifierThreshold) / (1-classifierThreshold);
}
else
{ // <= thresh
attrFound = true;
attr.attributeIndex = l;
attr.attributeValue = 0;
attr.attributeConfidence = (classifierThreshold-probability)/classifierThreshold;
}
// std::cout << "***************************" << std::endl;
// std::cout << "Layer name " << outputLayersInfo[l].layerName << "\nattribute index " << attr.attributeIndex <<
// " attribute value " << attr.attributeValue <<
// " calculated confidence " << attr.attributeConfidence << " original confidence " << probability << std::endl;
// std::cout << "***************************" << std::endl << std::endl;
if (attrFound)
{
if (labels.size() > attr.attributeIndex &&
attr.attributeValue < labels[attr.attributeIndex].size())
attr.attributeLabel =
labels[attr.attributeIndex][attr.attributeValue].c_str();
else
attr.attributeLabel = nullptr;
attrList.push_back(attr);
if (attr.attributeLabel)
descString.append(attr.attributeLabel).append(" ");
}
}
return true;
}
The rest of the file at nvdsinfer_customclassifierparser.cpp remains unchanged
#include <cstring>
#include <iostream>
#include "nvdsinfer_custom_impl.h"
/* This is a sample classifier output parsing function from softmax layers for
* the vehicle type classifier model provided with the SDK. */
/* C-linkage to prevent name-mangling */
extern "C"
bool NvDsInferClassiferParseCustomSoftmax (std::vector<NvDsInferLayerInfo> const &outputLayersInfo,
NvDsInferNetworkInfo const &networkInfo,
float classifierThreshold,
std::vector<NvDsInferAttribute> &attrList,
std::string &descString);
static std::vector < std::vector< std:: string > > labels { {
"coupe1", "largevehicle1", "sedan1", "suv1", "truck1", "van1"} };
extern "C"
bool NvDsInferClassiferParseCustomSoftmax (std::vector<NvDsInferLayerInfo> const &outputLayersInfo,
NvDsInferNetworkInfo const &networkInfo,
float classifierThreshold,
std::vector<NvDsInferAttribute> &attrList,
std::string &descString)
{
/* Get the number of attributes supported by the classifier. */
unsigned int numAttributes = outputLayersInfo.size();
/* Iterate through all the output coverage layers of the classifier.
*/
// std::cout << "number of attributes "<< numAttributes << std::endl;
for (unsigned int l = 0; l < numAttributes; l++)
{
/* outputCoverageBuffer for classifiers is usually a softmax layer.
* The layer is an array of probabilities of the object belonging
* to each class with each probability being in the range [0,1] and
* sum all probabilities will be 1.
*/
NvDsInferDimsCHW dims;
getDimsCHWFromDims(dims, outputLayersInfo[l].inferDims);
unsigned int numClasses = dims.c;
float *outputCoverageBuffer = (float *) outputLayersInfo[l].buffer;
// float maxProbability = 0;
bool attrFound = false;
NvDsInferAttribute attr;
/* Unlike the original function: this function is made for a classifier with one probability and 2 classes
* 0 emergency 1 non_emergency, so instead of looping over classes we'll just compare the confidenece to the
* threshold where (number> thresh) => none emergency | (number < thresh) => emergency */
float probability = outputCoverageBuffer[0]; //[c];
if (probability > classifierThreshold)
{
attrFound = true;
attr.attributeIndex = l; //l;
attr.attributeValue = 1; //c;
attr.attributeConfidence = (probability-classifierThreshold) / (1-classifierThreshold);
}
else
{ // <= thresh
attrFound = true;
attr.attributeIndex = l;
attr.attributeValue = 0;
attr.attributeConfidence = (classifierThreshold-probability)/classifierThreshold;
}
// std::cout << "***************************" << std::endl;
// std::cout << "Layer name " << outputLayersInfo[l].layerName << "\nattribute index " << attr.attributeIndex <<
// " attribute value " << attr.attributeValue <<
// " calculated confidence " << attr.attributeConfidence << " original confidence " << probability << std::endl;
// std::cout << "***************************" << std::endl << std::endl;
if (attrFound)
{
if (labels.size() > attr.attributeIndex &&
attr.attributeValue < labels[attr.attributeIndex].size())
attr.attributeLabel =
labels[attr.attributeIndex][attr.attributeValue].c_str();
else
attr.attributeLabel = nullptr;
attrList.push_back(attr);
if (attr.attributeLabel)
descString.append(attr.attributeLabel).append(" ");
}
}
return true;
}
/* Check that the custom function has been defined correctly */
CHECK_CUSTOM_CLASSIFIER_PARSE_FUNC_PROTOTYPE(NvDsInferClassiferParseCustomSoftmax);