Skip to content

Commit ae9e986

Browse files
committed
[TMVA][SOFIE] Use unsigned char instead of bool in return types
The `std::vector<bool>` is a special class that doesn't wrap contiguous memory. It limits the usability of the return object (e.g. the memory can't be adopted copy-free by a NumPy array). It prevents us from using C-style arrays under the hood and differentiating through the inference function.
1 parent 8e06818 commit ae9e986

File tree

3 files changed

+23
-26
lines changed

3 files changed

+23
-26
lines changed

Diff for: tmva/sofie/inc/TMVA/RModel.hxx

-2
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,6 @@ private:
3333
std::vector<std::shared_ptr<RModel>> fSubGraphs; ///<! sub-graph models (transient)
3434
RModel * fParentGraph = nullptr;
3535

36-
const std::string SP = " ";
37-
3836
// memory pool information for intermediate tensors
3937
MemoryPoolInfo fIntermediateMemoryInfo; ///<! intermediate memory info (transient)
4038
std::unordered_map<std::string_view, size_t> fIntermediateTensorFrequencyLookup; ///<! lookup table for intermediate tensor frequency (transient)

Diff for: tmva/sofie/src/RModel.cxx

+17-18
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99
#include "TMVA/RModel.hxx"
1010
#include "TMVA/SOFIE_common.hxx"
1111

12+
namespace {
13+
const std::string SP = " ";
14+
}
15+
1216
namespace TMVA {
1317
namespace Experimental {
1418
namespace SOFIE {
@@ -717,25 +721,18 @@ namespace {
717721

718722
std::string createOutputTensor(RModel const &rmodel, std::string const &name, bool isIntermediateTensor)
719723
{
720-
if(name.empty()) return "{}";
724+
if (name.empty())
725+
return "{}";
721726
ETensorType eOutputType = rmodel.GetTensorType(name);
727+
// The std::vector<bool> is a special type that is not wrapping continuous memory.
728+
// We don't want to use it as a return type.
722729
std::string outputType = ConvertTypeToString(eOutputType);
723-
if (isIntermediateTensor) {
724-
725-
if (eOutputType == ETensorType::BOOL) {
726-
return "fTensor_" + name;
727-
} else {
728-
// need to check is size is the same(don't want to return a vector with larger size)
729-
// in that case better to copy
730-
return "std::vector<" + ConvertTypeToString(eOutputType) + ">(tensor_" + name + ", tensor_" + name + " + " +
731-
std::to_string(ConvertShapeToLength(rmodel.GetTensorShape(name))) + ")";
732-
}
733-
}
734-
// include also dynamic tensors since the vectors can be allocated with a size larger than their output
735-
// we need a special handling for bool type allocated as vector<bool>
736-
auto outputLength = ConvertDynamicShapeToLength(rmodel.GetDynamicTensorShape(name));
737-
if (rmodel.IsDynamicTensor(name) && eOutputType == ETensorType::BOOL) {
738-
return "std::vector<bool>(fTensor_" + name + ".begin(), fTensor_" + name + ".begin() + " + outputLength + ")";
730+
auto outputLength = isIntermediateTensor ? std::to_string(ConvertShapeToLength(rmodel.GetTensorShape(name)))
731+
: ConvertDynamicShapeToLength(rmodel.GetDynamicTensorShape(name));
732+
// need to check is size is the same(don't want to return a vector with
733+
// larger size) in that case better to copy
734+
if (eOutputType == ETensorType::BOOL) {
735+
return "std::vector<unsigned char>(fTensor_" + name + ".begin(), fTensor_" + name + ".begin() + " + outputLength + ")";
739736
}
740737
return "std::vector<" + outputType + ">(tensor_" + name + ", tensor_" + name + " + " + outputLength + ")";
741738
}
@@ -755,7 +752,9 @@ void RModel::GenerateOutput() {
755752
bool sameOutputTypes = true;
756753
std::string inferReturnType; // type return by infer function
757754
ETensorType eOutputType = GetTensorType(*fOutputTensorNames.begin());
758-
std::string outputType = ConvertTypeToString(eOutputType);
755+
// The std::vector<bool> is a special type that is not wrapping continuous memory.
756+
// We don't want to use it as a return type.
757+
std::string outputType = eOutputType != ETensorType::BOOL ? ConvertTypeToString(eOutputType) : "unsigned char";
759758
fGC += "\n\n";
760759
if (outputSize == 1) {
761760
fGC += "std::vector<" + outputType + ">";

Diff for: tmva/sofie/test/TestCustomModelsFromONNX.cxx

+6-6
Original file line numberDiff line numberDiff line change
@@ -2515,7 +2515,7 @@ TEST(ONNX, Equal){
25152515
});
25162516

25172517
TMVA_SOFIE_Equal::Session s("Equal_FromONNX.dat");
2518-
std::vector<bool> output = s.infer(input1.data(),input2.data());
2518+
std::vector<unsigned char> output = s.infer(input1.data(),input2.data());
25192519
// Checking output size
25202520
EXPECT_EQ(output.size(), sizeof(Equal_ExpectedOutput::outputs) / sizeof(bool));
25212521

@@ -2540,7 +2540,7 @@ TEST(ONNX, LessOrEqual){
25402540
});
25412541

25422542
TMVA_SOFIE_LessOrEqual::Session s("LessOrEqual_FromONNX.dat");
2543-
std::vector<bool> output = s.infer(input1.data(),input2.data());
2543+
std::vector<unsigned char> output = s.infer(input1.data(),input2.data());
25442544
// Checking output size
25452545
EXPECT_EQ(output.size(), sizeof(LessOrEqual_ExpectedOutput::outputs) / sizeof(bool));
25462546

@@ -2565,7 +2565,7 @@ TEST(ONNX, GreaterOrEqual){
25652565
});
25662566

25672567
TMVA_SOFIE_GreaterOrEqual::Session s("GreaterOrEqual_FromONNX.dat");
2568-
std::vector<bool> output = s.infer(input1.data(),input2.data());
2568+
std::vector<unsigned char> output = s.infer(input1.data(),input2.data());
25692569
// Checking output size
25702570
EXPECT_EQ(output.size(), sizeof(GreaterOrEqual_ExpectedOutput::outputs) / sizeof(bool));
25712571

@@ -2590,7 +2590,7 @@ TEST(ONNX, Greater){
25902590
});
25912591

25922592
TMVA_SOFIE_Greater::Session s("Greater_FromONNX.dat");
2593-
std::vector<bool> output = s.infer(input1.data(),input2.data());
2593+
std::vector<unsigned char> output = s.infer(input1.data(),input2.data());
25942594
// Checking output size
25952595
EXPECT_EQ(output.size(), sizeof(Greater_ExpectedOutput::outputs) / sizeof(bool));
25962596

@@ -2615,7 +2615,7 @@ TEST(ONNX, Less){
26152615
});
26162616

26172617
TMVA_SOFIE_Less::Session s("Less_FromONNX.dat");
2618-
std::vector<bool> output = s.infer(input1.data(),input2.data());
2618+
std::vector<unsigned char> output = s.infer(input1.data(),input2.data());
26192619
// Checking output size
26202620
EXPECT_EQ(output.size(), sizeof(Less_ExpectedOutput::outputs) / sizeof(bool));
26212621

@@ -3213,4 +3213,4 @@ TEST(ONNX, ScatterElements)
32133213
for (size_t i = 0; i < output.size(); ++i) {
32143214
EXPECT_LE(std::abs(output[i] - correct_output[i]), DEFAULT_TOLERANCE);
32153215
}
3216-
}
3216+
}

0 commit comments

Comments
 (0)