Skip to content

Commit 80c2c8c

Browse files
committed
[tmva][sofie] Fix a bug in Gather operator when output is a param shape tensor
When output is a param shape tensor the tensor values were not assigned in initialization as in a constant tensor, they need to be set at run time in the infer function because they depend on the provided dynamic shale values Fix also a issue on Windows in the new COnvertValuesTOString implementation dealing with inf values. Create a specialisation for float or double which will handle the infinity values in numerical limits.
1 parent adda7ae commit 80c2c8c

4 files changed

Lines changed: 56 additions & 25 deletions

File tree

tmva/sofie/inc/TMVA/ROperator_Gather.hxx

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ class ROperator_Gather final : public ROperator
1717
{
1818
private:
1919

20+
bool fIsOutputParamShape = false; // for shape outputs
2021
int64_t fAttrAxis = 0;
2122

2223
std::string fNX;
@@ -26,11 +27,13 @@ private:
2627
std::vector<Dim> fShapeX;
2728
std::vector<Dim> fShapeIndices;
2829
std::vector<Dim> fShapeY;
30+
std::vector<Dim> fOutputShapeData;
2931

3032
std::vector<int64_t> fIndices; // indices vector in case they are known at initialization
3133

3234
std::string fType;
3335

36+
3437
public:
3538
ROperator_Gather(){}
3639
ROperator_Gather(int64_t attrAxis, std::string nameX, std::string nameIndices, std::string nameY):
@@ -121,17 +124,17 @@ public:
121124
else if (model.IsShapeTensor(fNX) && q <=1 && fIndices.size() > 0) {
122125
auto inputData = model.GetShapeTensorValues(fNX);
123126
// if r == 1 and q<=1 then output length is 1 (is a scalar or tensor of size1)
124-
std::vector<Dim> outputData(1);
125-
outputData[0] = inputData[fIndices[0]];
126-
if (outputData[0].isParam) {
127-
fIsOutputConstant = true;
127+
fOutputShapeData.resize(1);
128+
fOutputShapeData[0] = inputData[fIndices[0]];
129+
if (fOutputShapeData[0].isParam) {
130+
fIsOutputParamShape = true;
128131
// shapeY can be scalar or vector of size1
129-
model.AddShapeTensor(fNY, outputData, fShapeY.size() == 0);
132+
model.AddShapeTensor(fNY, fOutputShapeData, fShapeY.size() == 0);
130133
if (model.Verbose())
131134
std::cout << "Gather: " << fNX << " " << ConvertDimShapeToString(fShapeX) << " -> " << fNY << " with shape " << ConvertDimShapeToString(fShapeY)
132-
<< " and values " << ConvertDimShapeToString(outputData) << " (shape) " << std::endl;
135+
<< " and values " << ConvertDimShapeToString(fOutputShapeData) << " (shape) " << std::endl;
133136
} else {
134-
int64_t value = static_cast<int64_t>(outputData[0].dim);
137+
int64_t value = static_cast<int64_t>(fOutputShapeData[0].dim);
135138
auto shapeY = ConvertShapeToInt(fShapeY);
136139
model.AddConstantTensor(fNY, shapeY, &value);
137140
fIsOutputConstant = true;
@@ -140,7 +143,7 @@ public:
140143
<< " and values {" << value << "} (constant) " << std::endl;
141144
}
142145
}
143-
if (!fIsOutputConstant) {
146+
if (!fIsOutputConstant && !fIsOutputParamShape) {
144147
// Add output tensor
145148
model.AddIntermediateTensor(fNY, model.GetTensorType(fNX), fShapeY);
146149
fType = ConvertTypeToString(model.GetTensorType(fNX));
@@ -159,6 +162,14 @@ public:
159162
out << "//--------------------(constant)----------\n";
160163
return out.str();
161164
}
165+
if (fIsOutputParamShape) {
166+
// no code to generate here for param shape output. Tensor output is defined in Session constructor
167+
out << "//--------------------(shape)----------\n";
168+
for (int i = 0; i < static_cast<int>(fOutputShapeData.size()); i++) {
169+
out << SP << "tensor_" << fNY << "[" << i << " ] = " << fOutputShapeData[i].GetVal() << ";\n";
170+
}
171+
return out.str();
172+
}
162173
// The shape of the output is q + r - 1
163174
size_t r = fShapeX.size();
164175
// Indices of shape q

tmva/sofie/inc/TMVA/ROperator_Gemm.hxx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,9 @@ namespace SOFIE{
344344
//in this case fAttrBeta needs to be equal to zero otherwise second time we run we will use
345345
// the previous result
346346
if (fAttrBeta != 0) {
347-
throw std::runtime_error("TMVA SOFIE Gemm Op " + opName + " Bias tensor is not present but beta value in Gemm is not zero");
347+
// some model don't have bias but Beta is not zero - force it to zero
348+
fAttrBeta = 0;
349+
std::cout << "WARNING: TMVA SOFIE Gemm Op " + opName + " Bias tensor is not present but beta value in Gemm is not zero - force it to zero";
348350
}
349351
}
350352

tmva/sofie/inc/TMVA/ROperator_Reshape.hxx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,6 @@ public:
293293
}
294294
} else if (!fAttrAxes.empty()) {
295295
// case fNShape is empty and axes are provided as attributes (e.g. for Unsqueeze)
296-
std::cout << "attribute axes exists\n";
297296
fShapeOutput = ShapeInference({fShapeInput})[0];
298297
} else if (fOpMode == Flatten || fOpMode == Squeeze) {
299298
fShapeOutput = ShapeInference({fShapeInput})[0];

tmva/sofie/inc/TMVA/SOFIE_common.hxx

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -215,9 +215,39 @@ std::string ConvertDimShapeToLength(const std::vector<Dim> & shape);
215215
template<class T>
216216
std::string ConvertValToString(T value) {
217217
std::stringstream ret;
218-
if (std::is_floating_point_v<T>)
219-
ret << std::setprecision(std::numeric_limits<T>::max_digits10);
220-
ret << value;
218+
ret << std::to_string(value);
219+
return ret.str();
220+
}
221+
// float specialization
222+
template<>
223+
inline std::string ConvertValToString<float>(float value) {
224+
std::stringstream ret;
225+
// special case for infinity and Nan
226+
if (std::isinf(value))
227+
ret << (value > 0 ? "std::numeric_limits<float>::infinity()" :
228+
"-std::numeric_limits<float>::infinity()");
229+
else if (std::isnan(value))
230+
ret << "std::numeric_limits<float>::quiet_NaN()";
231+
else {
232+
ret << std::setprecision(std::numeric_limits<float>::max_digits10);
233+
ret << value;
234+
}
235+
return ret.str();
236+
}
237+
// double specialization
238+
template<>
239+
inline std::string ConvertValToString<double>(double value) {
240+
std::stringstream ret;
241+
// special case for infinity and Nan
242+
if (std::isinf(value))
243+
ret << (value > 0 ? "std::numeric_limits<double>::infinity()" :
244+
"-std::numeric_limits<double>::infinity()");
245+
else if (std::isnan(value))
246+
ret << "std::numeric_limits<double>::quiet_NaN()";
247+
else {
248+
ret << std::setprecision(std::numeric_limits<double>::max_digits10);
249+
ret << value;
250+
}
221251
return ret.str();
222252
}
223253

@@ -228,18 +258,7 @@ std::string ConvertValuesToString(size_t n, const T * data, size_t maxprint = -1
228258
std::stringstream ret;
229259
ret << "{ ";
230260
for (size_t i = 0; i < std::min(n,maxprint); i++) {
231-
if (std::is_floating_point_v<T>) {
232-
// special case for infinity and Nan
233-
if (std::isinf(data[i]))
234-
ret << (data[i] > 0 ? "std::numeric_limits<" + TensorType<T>::Name() + ">::infinity()" :
235-
"-std::numeric_limits<" + TensorType<T>::Name() + ">::infinity()");
236-
else if (std::isnan(data[i]))
237-
ret << "std::numeric_limits<" + TensorType<T>::Name() + ">::quiet_NaN()";
238-
else
239-
ret << std::setprecision(std::numeric_limits<T>::max_digits10) << data[i];
240-
} else {
241-
ret << std::to_string(data[i]);
242-
}
261+
ret << ConvertValToString(data[i]);
243262
if (i < n-1) ret << ", ";
244263
if (i < n-1 && i == maxprint-1) ret << "..... ";
245264
}

0 commit comments

Comments
 (0)