Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion tmva/sofie/inc/TMVA/RModel.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ private:
MemoryPoolInfo fIntermediateMemoryInfo; ///<! intermediate memory info (transient)
std::unordered_map<std::string_view, size_t> fIntermediateTensorFrequencyLookup; ///<! lookup table for intermediate tensor frequency (transient)

std::string fExtraCodeForDimShapes; // extra code needed for initialization of dynamic parameters (e.g. number of non zero elements in NonZero operator)
Comment thread
guitargeek marked this conversation as resolved.

public:
/**
Default constructor. Needed to allow serialization of ROOT objects. See
Expand Down Expand Up @@ -108,6 +110,7 @@ public:

void AddShapeTensor(const std::string & name, const std::vector<Dim> & shapeValues, bool scalar = false);

void AddExtraCodeForDimShapes(const std::string & code) { fExtraCodeForDimShapes += code; }

// add and initialize subgraph to the model
void InitializeSubGraph(std::shared_ptr<RModel> graph);
Expand Down Expand Up @@ -239,7 +242,7 @@ public:
bool UseVDT() const { return fUseVDT;}

// Use the ClassDef macro to allow definition of custom streaming
ClassDefNV(RModel, 3);
ClassDefNV(RModel, 4);
};

// need to implement here templated member functions and its specialization
Expand Down
2 changes: 1 addition & 1 deletion tmva/sofie/inc/TMVA/ROperator.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ protected:
const std::string SP = " "; ///< space used to correctly indent the generated C++ code
bool fUseSession = false; ///< flag to identify if using the session class
bool fIsOutputConstant = false; ///< flag to identify if operator has a constant output (no need to generate code)
bool fIsOutputParamShape = false; ///< flag to identify of the output represents a parametric shape (can be knwon at compile time)
bool fIsOutputParamShape = false; ///< flag to identify of the output represents a parametric shape (can be known at compile time)

mutable std::vector<std::string_view> fInputTensorNames;
mutable std::vector<std::string_view> fOutputTensorNames;
Expand Down
8 changes: 4 additions & 4 deletions tmva/sofie/inc/TMVA/ROperator_BasicBinary.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -209,8 +209,8 @@ public:
<< ConvertShapeToString(fShapeY) << " : " << ConvertValuesToString(dataY) << std::endl;
}
} else if (((model.IsShapeTensor(fNA) && model.IsShapeTensor(fNB)) ||
(model.IsShapeTensor(fNA) && model.IsConstantTensor(fNB)) ||
(model.IsShapeTensor(fNB) && model.IsConstantTensor(fNA)))
(model.IsShapeTensor(fNA) && model.IsInitializedTensor(fNB)) ||
(model.IsShapeTensor(fNB) && model.IsInitializedTensor(fNA)))
&& (fShapeA.size() <=1 && fShapeB.size() <=1 && model.GetTensorType(fNA) == ETensorType::INT64)) {
// case of shape tensors ( tensors are of rank 0 or 1 )
std::vector<Dim> dimValA;
Expand All @@ -235,9 +235,9 @@ public:
dimValues[i] = Dim{ static_cast<size_t>(data[0])};
}
};
if (model.IsConstantTensor(fNA)) {
if (model.IsInitializedTensor(fNA)) {
convertDataToDim(fNA,fShapeA,dimValA);
} else if (model.IsConstantTensor(fNB)) {
} else if (model.IsInitializedTensor(fNB)) {
convertDataToDim(fNB,fShapeB,dimValB);
}

Expand Down
11 changes: 8 additions & 3 deletions tmva/sofie/inc/TMVA/ROperator_Cast.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,9 @@ public:
if (!fIsOutputConstant)
model.AddIntermediateTensor(fNY, fType, fShape);
if (model.Verbose()) {
std::cout << "Cast : " << ConvertTypeToString(inputType) << " " << fNX << " -> " << ConvertTypeToString(fType) << " for " << fNY
<< " shape " << ConvertDimShapeToString(fShape);
std::cout << "Cast : " << ConvertTypeToString(inputType) << " " << fNX << " -> " << ConvertTypeToString(fType);
if (fType == ETensorType::BOOL) std::cout << " (converted from BOOL) ";
std::cout << " for " << fNY << " shape " << ConvertDimShapeToString(fShape);
if (fIsOutputConstant) std::cout << " (constant) ";
std::cout << std::endl;
}
Expand All @@ -87,7 +88,11 @@ public:

out << SP << "for (int id = 0; id < " << length << " ; id++){\n";

out << SP << SP << "tensor_" << fNY << "[id] = static_cast<"<< ConvertTypeToString(fType) << ">(tensor_" << fNX << "[id]);\n";
// need to handle bool case separatly since casting to uint8 will not give right result
if (fType == ETensorType::BOOL)
out << SP << SP << "tensor_" << fNY << "[id] = (tensor_" << fNX << "[id] != 0) ? 1 : 0;\n";
else
out << SP << SP << "tensor_" << fNY << "[id] = static_cast<"<< ConvertTypeToString(fType) << ">(tensor_" << fNX << "[id]);\n";

out << SP << "}\n";
return out.str();
Expand Down
174 changes: 112 additions & 62 deletions tmva/sofie/inc/TMVA/ROperator_Concat.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
std::vector<std::string> fInputs;
std::string fOutput;
std::vector<Dim>fOutputShape;
std::vector<Dim> fOutputShapeData; // in case output is a shape tensor we store here the output shape value data (can be parametric)
std::vector<std::vector<Dim>> fInputShapes;

public:
Expand Down Expand Up @@ -170,82 +171,125 @@
}

void Initialize(RModel& model) override {
std::vector<std::vector<size_t>> inputIntShapes;
for (auto &it : fInputs) {
if (model.CheckIfTensorAlreadyExist(it) == false) {
throw std::runtime_error("TMVA SOFIE Concat Op Input Tensor " + it + " is not found in model");
}
fInputShapes.push_back(model.GetDimTensorShape(it));
if (!model.IsDynamicTensor(it)) {
inputIntShapes.push_back(ConvertShapeToInt(fInputShapes.back()));
}
}
if (inputIntShapes.size() == fInputs.size()) {
// if all input shapes are static we can compute output shape at initialization time
auto outputIntShape = ShapeInference(inputIntShapes)[0];
fOutputShape = ConvertShapeToDim(outputIntShape);
if (model.Verbose())
std::cout << "Initialize Concat operator with defined inputs shapes, "
<< "output has shape " << ConvertShapeToString(outputIntShape) << std::endl;

} else {
// if at least one input shape is dynamic we need to compute output shape using the symbolic expression for the dimensions
fOutputShape = ShapeInference(fInputShapes, model);
if (model.Verbose())
std::cout << "Initialize Concat operator with dynamic inputs shapes, "
<< "output has shape " << ConvertDimShapeToString(fOutputShape) << std::endl;
}
fOutputShape = ShapeInference(fInputShapes, model);
if (model.Verbose())
std::cout << "Output of concat operator has shape " << ConvertDimShapeToString(fOutputShape) << std::endl;

// check if concat has constant inputs , axis 0(concat contigous memory and type is integer)
bool isOutputShape = false;
if (model.GetTensorType(fInputs[0]) == ETensorType::INT64 && fAxis == 0) {
fIsOutputConstant = true;
isOutputShape = true;

for ( auto & input : fInputs) {
if (!model.IsInitializedTensor(input)) {
fIsOutputConstant = false;
if (!model.IsShapeTensor(input)) {
isOutputShape = false;
break;
}
}
// if (model.GetTensorType(fInputs[0]) == ETensorType::INT64 && fAxis == 0) {
fIsOutputConstant = true;
isOutputShape = true;

for (auto &input : fInputs) {
if (model.IsDynamicTensor(input)) {
fIsOutputConstant = false;
isOutputShape = false;
break;
}
if (fIsOutputConstant) {
auto outputShape = ConvertShapeToInt(fOutputShape); // conversion must be possible
std::vector<int64_t> outputData(ConvertShapeToLength(outputShape));
size_t offset = 0;
for ( auto & input : fInputs) {
auto inputData = static_cast<int64_t*>(model.GetInitializedTensorData(input).get());
auto inputShape = model.GetTensorShape(input); // shape is not dynamic if it is constant
size_t inputLength = ConvertShapeToLength(inputShape);
std::copy(inputData, inputData + inputLength, outputData.begin() + offset );
offset += inputLength;
// the data of the input tensor don't need to be written in the generated code and data file
model.SetNotWritableInitializedTensor(input);
}
model.AddConstantTensor<int64_t>(fOutput, outputShape, outputData.data());
if (model.Verbose()) {
std::cout << "output of Concat is a constant tensor " << ConvertShapeToString(outputShape) << " : "
<< ConvertValuesToString(outputData) << " (constant)" << std::endl;
}
} else if (isOutputShape) {
auto outputShape = ConvertShapeToInt(fOutputShape); // conversion must be possible
std::vector<Dim> outputData(ConvertShapeToLength(outputShape));
size_t offset = 0;
for ( auto & input : fInputs) {
std::vector<Dim> inputData;
auto inputShape = model.GetTensorShape(input); // shape is not dynamic
size_t inputLength = ConvertShapeToLength(inputShape); // shape can be a scalar
if (model.IsShapeTensor(input)) {
inputData = model.GetShapeTensorValues(input);
} else if (model.IsInitializedTensor(input)) {
inputData.resize(inputLength);
auto intData = static_cast<int64_t*>(model.GetInitializedTensorData(input).get());
for (size_t i = 0; i < inputData.size(); i++)
inputData[i] = Dim{ static_cast<size_t>(intData[i])};
}
else {
// this should not happen
throw std::runtime_error("TMVA SOFIE Concat Operator- invalid input type for shape output type");
if (!model.IsInitializedTensor(input)) {
if (model.IsShapeTensor(input)) {
// if it is a shape tensor we can have constant output if the shapes are defined)
auto shapeData = model.GetShapeTensorValues(input);
bool isShapeFullyDefined = ConvertShapeToInt(shapeData).size() == shapeData.size();
if (!isShapeFullyDefined) {
fIsOutputConstant = false;
} else {
// if shape is fully defined we can consider output as constant and we can compute the output
// shape at initialization time
fIsOutputConstant = fIsOutputConstant && true;
}
std::copy(inputData.begin(), inputData.end(), outputData.begin() + offset );
offset += inputLength;
// inputs are then shape tensors and output is a shape tensor
isOutputShape = true;
} else {
// case of standard intermediate tensor
fIsOutputConstant = false;
isOutputShape = false;
break;
}
// add output tensor
model.AddShapeTensor(fOutput,outputData, false); // cannot be a scalar
if (model.Verbose()) {
std::cout << "output of Concat is a shape tensor " << ConvertShapeToString(outputShape) << " : "
<< ConvertDimShapeToString(outputData) << " (shape)" << std::endl;
} else {
fIsOutputConstant = fIsOutputConstant && true;
}
}
//}

if (fIsOutputConstant) {
auto outputShape = ConvertShapeToInt(fOutputShape); // conversion must be possible
std::vector<int64_t> outputData(ConvertShapeToLength(outputShape));
size_t offset = 0;
for (auto &input : fInputs) {
auto inputData = static_cast<int64_t *>(model.GetInitializedTensorData(input).get());
auto inputShape = model.GetTensorShape(input); // shape is not dynamic if it is constant
size_t inputLength = ConvertShapeToLength(inputShape);
std::copy(inputData, inputData + inputLength, outputData.begin() + offset);
offset += inputLength;
// the data of the input tensor don't need to be written in the generated code and data file
model.SetNotWritableInitializedTensor(input);
}
model.AddConstantTensor<int64_t>(fOutput, outputShape, outputData.data());
if (model.Verbose()) {
std::cout << "output of Concat is a constant tensor " << ConvertShapeToString(outputShape) << " : "
<< ConvertValuesToString(outputData) << " (constant)" << std::endl;
}
} else if (isOutputShape) {
auto outputShape = ConvertShapeToInt(fOutputShape); // conversion must be possible
if (outputShape.size() != 1)
throw std::runtime_error("TMVA SOFIE Concat Op - output shape for shape tensor must have rank 1");
// output shape is a rank 1 tensor with size equal to the output rank
std::vector<Dim> outputData(outputShape[0]);
size_t offset = 0;
for (auto &input : fInputs) {
std::vector<Dim> inputData;
auto inputShape = model.GetTensorShape(input); // shape is not dynamic
size_t inputLength = ConvertShapeToLength(inputShape); // shape can be a scalar
if (model.IsShapeTensor(input)) {
inputData = model.GetShapeTensorValues(input);
} else if (model.IsInitializedTensor(input)) {
inputData.resize(inputLength);
auto intData = static_cast<int64_t *>(model.GetInitializedTensorData(input).get());
for (size_t i = 0; i < inputData.size(); i++)
inputData[i] = Dim{static_cast<size_t>(intData[i])};
} else {
// this should not happen
throw std::runtime_error("TMVA SOFIE Concat Operator- invalid tensor input " + input +
" for shape output type");
}
fIsOutputConstant = true;
std::copy(inputData.begin(), inputData.end(), outputData.begin() + offset);
offset += inputLength;
}
// add output tensor
model.AddShapeTensor(fOutput, outputData, false); // cannot be a scalar
fOutputShapeData = outputData;
if (model.Verbose()) {
std::cout << "output of Concat is a shape tensor " << ConvertShapeToString(outputShape) << " : "
<< ConvertDimShapeToString(outputData) << " (shape)" << std::endl;
}
fIsOutputParamShape = true;
}
if (!fIsOutputConstant) {
if (!fIsOutputConstant && !fIsOutputParamShape) {
model.AddIntermediateTensor(fOutput, model.GetTensorType(fInputs[0]), fOutputShape);
if (model.Verbose()) {
std::cout << "Concat ---> " << fOutput << " " << ConvertDimShapeToString(fOutputShape) << std::endl;
Expand All @@ -260,8 +304,14 @@

if (fIsOutputConstant) return out.str();

if(fOutputShape.empty()){
throw std::runtime_error("TMVA SOFIE Concat called to Generate without being initialized first");
if (fIsOutputParamShape) {
// output is a shape tensor defined by the concatenation of the input shapes
out << "// output is a shape tensor defined by the concatenation of the input shapes\n";
for (int i = 0; i < static_cast<int>(fOutputShape
[0].dim); i++) {
out << SP << "tensor_" << fOutput << "[" << i << "] = " << fOutputShapeData[i] << ";\n";
}
return out.str();
}
// special case when memory is contiguous
bool hasShapeOnes = true;
Expand Down
Loading
Loading