From 6e856a1a8555dfcb440de748a5b76ef80c4daa41 Mon Sep 17 00:00:00 2001 From: Neel-Shah-29 Date: Fri, 22 Jul 2022 02:14:50 +0530 Subject: [PATCH 1/8] Reduce Operator Initial Code pushed --- tmva/sofie/CMakeLists.txt | 3 +- tmva/sofie/inc/TMVA/OperatorList.hxx | 1 + tmva/sofie/inc/TMVA/ROperator_Reduce.hxx | 301 ++++++++++++++++++ tmva/sofie/test/TestCustomModelsFromONNX.cxx | 27 ++ tmva/sofie/test/input_models/ReduceMean.onnx | Bin 0 -> 167 bytes .../references/ReduceMean.ref.hxx | 5 + .../inc/TMVA/RModelParser_ONNX.hxx | 4 + tmva/sofie_parsers/src/RModelParser_ONNX.cxx | 40 +++ 8 files changed, 380 insertions(+), 1 deletion(-) create mode 100644 tmva/sofie/inc/TMVA/ROperator_Reduce.hxx create mode 100644 tmva/sofie/test/input_models/ReduceMean.onnx create mode 100644 tmva/sofie/test/input_models/references/ReduceMean.ref.hxx diff --git a/tmva/sofie/CMakeLists.txt b/tmva/sofie/CMakeLists.txt index 175918c75aec9..e8bc8a0d9d8e9 100644 --- a/tmva/sofie/CMakeLists.txt +++ b/tmva/sofie/CMakeLists.txt @@ -33,6 +33,7 @@ ROOT_STANDARD_LIBRARY_PACKAGE(ROOTTMVASofie TMVA/ROperator_Concat.hxx TMVA/ROperator_Identity.hxx TMVA/ROperator_Softmax.hxx + TMVA/ROperator_Reduce.hxx TMVA/ROperator_Cast.hxx TMVA/SOFIE_common.hxx TMVA/SOFIEHelpers.hxx @@ -51,4 +52,4 @@ set_target_properties(ROOTTMVASofie PROPERTIES # tests requires protobuf if (tmva-sofie) ROOT_ADD_TEST_SUBDIRECTORY(test) -endif() +endif() \ No newline at end of file diff --git a/tmva/sofie/inc/TMVA/OperatorList.hxx b/tmva/sofie/inc/TMVA/OperatorList.hxx index 43d64b1d9b9a4..0002fb1ffddf5 100644 --- a/tmva/sofie/inc/TMVA/OperatorList.hxx +++ b/tmva/sofie/inc/TMVA/OperatorList.hxx @@ -18,4 +18,5 @@ #include "TMVA/ROperator_Identity.hxx" #include "TMVA/ROperator_Softmax.hxx" #include "TMVA/ROperator_Concat.hxx" +#include "TMVA/ROperator_Reduce.hxx" #include "TMVA/ROperator_Cast.hxx" diff --git a/tmva/sofie/inc/TMVA/ROperator_Reduce.hxx b/tmva/sofie/inc/TMVA/ROperator_Reduce.hxx new file mode 100644 index 0000000000000..8aa3f282cb2c0 --- /dev/null +++ b/tmva/sofie/inc/TMVA/ROperator_Reduce.hxx @@ -0,0 +1,301 @@ + +// #ifndef TMVA_SOFIE_ROPERATOR_Reduce +// #define TMVA_SOFIE_ROPERATOR_Reduce + +// #include "TMVA/SOFIE_common.hxx" +// #include "TMVA/ROperator.hxx" +// #include "TMVA/RModel.hxx" + +// #include +// #include +// #include +// #include +// #include +// #include + +// namespace TMVA{ +// namespace Experimental{ +// namespace SOFIE{ + +// enum ReduceOpMode { ReduceMean, ReduceSumsquare, ReduceProd }; + +// template +// struct ReduceOperatorTrait { +// const char *Name() { return ""; } +// }; +// template +// struct ReduceOperatorTrait { +// static const char *Name() { return "ReduceMean"; } +// }; + +// template +// struct ReduceOperatorTrait { +// static const char *Name() { return "ReduceProd"; } +// }; + +// template +// struct ReduceOperatorTrait { +// static const char *Name() { return "ReduceSumsquare"; } +// }; + +// template +// class ROperator_Reduce final : public ROperator +// { +// private: +// /* Attributes*/ +// int fAxis = 1; +// ReduceOpMode fReduceMode; +// int fkeepdims = 1; //default value +// std::string fNX; +// std::string fNY; +// std::vector fShapeX; +// std::vector fShapeY; + +// public: + +// ROperator_Reduce(){} +// ROperator_Reduce(int keepdims,int axis,std::string nameX, std::string nameY): +// fkeepdims(keepdims), fAxis(axis), fNX(UTILITY::Clean_name(nameX)), fNY(UTILITY::Clean_name(nameY)) {} + +// // type of output given input +// std::vector TypeInference(std::vector input){ +// return input; +// } + +// // shape of output tensors given input tensors +// std::vector> ShapeInference(std::vector> input){ +// // assume now inputs have same shape (no broadcasting) +// auto ret = std::vector>(1, input[0]); // return vector size 1 with first input +// return ret; +// } +// void Initialize(RModel& model){ + +// fUseSession = model.UseSession(); + +// if (model.CheckIfTensorAlreadyExist(fNX) == false){ //input must be a graph input, or already initialized intermediate tensor +// throw std::runtime_error("TMVA SOFIE Reduce Op Input Tensor " + fNX + " is not found in model"); +// } +// fShapeX = model.GetTensorShape(fNX); +// // find shape of Y and add it in the list of intermediate tensors +// fShapeY = ShapeInference({fShapeX})[0]; +// model.AddIntermediateTensor(fNY, model.GetTensorType(fNX), fShapeY); +// } + +// std::string Generate(std::string OpName){ +// OpName = "op_" + OpName; +// if (fShapeX.empty() || fShapeY.empty()) { +// throw std::runtime_error("TMVA SOFIE Reduce Op called to Generate without being initialized first"); +// } + +// size_t outputLength = TMVA::Experimental::SOFIE::ConvertShapeToLength(fShapeY); + +// auto inputStrides = TMVA::Experimental::SOFIE::UTILITY::ComputeStrideFromShape(fShapeX); +// auto outputStrides = TMVA::Experimental::SOFIE::UTILITY::ComputeStrideFromShape(fShapeY); + +// size_t dim = fShapeY.size(); +// std::vector idx(dim); + +// std::stringstream out; +// for (size_t i = 0; i < outputLength; i++) { + +// if (dim == 2) { +// idx[0] = i / outputStrides[0]; +// idx[1] = i % outputStrides[0]; +// } +// if (dim == 3) { +// idx[0] = i / outputStrides[0]; +// idx[1] = (i % outputStrides[0]) / outputStrides[1]; +// idx[2] = (i % outputStrides[0]) % outputStrides[1]; +// } +// if (dim == 4) { +// idx[0] = i / outputStrides[0]; +// idx[1] = (i % outputStrides[0]) / outputStrides[1]; +// idx[2] = ((i % outputStrides[0]) % outputStrides[1]) / outputStrides[2]; +// idx[3] = ((i % outputStrides[0]) % outputStrides[1]) % outputStrides[2]; +// } + +// assert(idx[fAxis] == 0); // we can avoid computing this for the reduction axis which by definition is always zero + +// out << SP << "float sum = 0;\n"; +// // float sum = 0; +// for (size_t k = 0; k < fShapeX[fAxis]; k++) { +// idx[fAxis] = k; +// // compute input index j +// size_t j = 0; +// if (dim == 2) j = idx[0]*inputStrides[0] + idx[1]; +// if (dim == 3) j = idx[0]*inputStrides[0] + idx[1]* inputStrides[1] + idx[2]; +// if (dim == 4) j = idx[0]*inputStrides[0] + idx[1]* inputStrides[1] + idx[2]*inputStrides[2] + idx[3]; + +// out << SP << SP << "sum += tensor_" << fNX[j] << ";\n"; +// } +// out << SP << "float average = sum/float(" << fShapeX[fAxis] << ")\n;"; +// out << SP << "tensor_" << fNY[i] << " = average;\n"; +// } +// return out.str(); +// } + +// }; + +// }//SOFIE +// }//Experimental +// }//TMVA + + +// #endif //TMVA_SOFIE_ROPERATOR_Reduce + +#ifndef TMVA_SOFIE_ROPERATOR_Reduce +#define TMVA_SOFIE_ROPERATOR_Reduce + +#include "TMVA/SOFIE_common.hxx" +#include "TMVA/ROperator.hxx" +#include "TMVA/RModel.hxx" + +#include +#include +#include +#include +#include +#include + +namespace TMVA{ +namespace Experimental{ +namespace SOFIE{ + +template +struct ReduceOperatorTrait { + const char *Name() { return ""; } +}; +template +struct ReduceOperatorTrait { + static const char *Name() { return "ReduceMean"; } +}; + +template +struct ReduceOperatorTrait { + static const char *Name() { return "ReduceProd"; } +}; + +template +struct ReduceOperatorTrait { + static const char *Name() { return "ReduceSumsquare"; } +}; + +template +class ROperator_Reduce final : public ROperator +{ +private: + /* Attributes*/ + int fkeepdims = 1; //default value + std::string fNX; + std::string fNY; + std::vector fShapeX; + std::vector fShapeY; + int fAttrAxes; + +public: + ROperator_Reduce(){} + ROperator_Reduce(int keepdims,int attrAxes,std::string nameX, std::string nameY): + fkeepdims(keepdims), fAttrAxes(attrAxes), fNX(UTILITY::Clean_name(nameX)), fNY(UTILITY::Clean_name(nameY)) {} + + // type of output given input + std::vector TypeInference(std::vector input){ + return input; + } + + // shape of output tensors given input tensors + std::vector> ShapeInference(std::vector> input){ + + // std::vector> ret; + // auto & input_shape = input[0]; + // auto ret = std::vector>(1, input[0]); // return vector size 1 with first input + // return ret; + auto ret = input; //suggest copy to compiler + ret[fAttrAxes] = 1; + return ret; + } + void Initialize(RModel& model){ + + fUseSession = model.UseSession(); + + if (model.CheckIfTensorAlreadyExist(fNX) == false){ //input must be a graph input, or already initialized intermediate tensor + throw std::runtime_error("TMVA SOFIE Reduce Op Input Tensor " + fNX + " is not found in model"); + } + fShapeX = model.GetTensorShape(fNX); + // find shape of Y and add it in the list of intermediate tensors + fShapeY = ShapeInference(fShapeX); + model.AddIntermediateTensor(fNY, model.GetTensorType(fNX), fShapeY); + } + + std::string Generate(std::string OpName){ + OpName = "op_" + OpName; + if (fShapeX.empty() || fShapeY.empty()) { + throw std::runtime_error("TMVA SOFIE Reduce Op called to Generate without being initialized first"); + } + + size_t outputLength = TMVA::Experimental::SOFIE::ConvertShapeToLength(fShapeY); + + auto inputStrides = TMVA::Experimental::SOFIE::UTILITY::ComputeStrideFromShape(fShapeX); + auto outputStrides = TMVA::Experimental::SOFIE::UTILITY::ComputeStrideFromShape(fShapeY); + + // write here according to size of shape + // in generation code can be done automatically + // i0 = i / s0 ; i1 = (i % s0) / s1 ; i2 = ( (i % s0) % s1 ) / s2 and so on + // and we have for the inverse + // i = i0 * s0 + i1 * s1 + i2 * s2 + i3 * s3 .... + + // don't need to divide by last stride s[n-1] since it is 1 by definition + + std::stringstream out; + out << "\n//---- operator " << std::string(ReduceOperatorTrait::Name()) << " " << OpName << "\n"; + out << SP << "size_t dim = " << fShapeY.size() << ";\n"; + + out << SP << "std::vector idx(dim);"; + + + out << SP << "for (size_t i = 0; i < " << outputLength << "; i++) {\n"; + + // write here according to size of shape + // in generation code can be done automatically + // i0 = i / s0 ; i1 = (i % s0) / s1 ; i2 = ( (i % s0) % s1 ) / s2 and so on + // and we have for the inverse + // i = i0 * s0 + i1 * s1 + i2 * s2 + i3 * s3 .... + + // don't need to divide by last stride s[n-1] since it is 1 by definition + + out << SP << SP << "idx[j] = i;\n"; + out << SP << SP << "size_t k = 0;\n"; + out << SP << SP << SP << "for(k=0; k < dim-1; k++){\n"; + out << SP << SP << SP << "idx[k] = idx[k] %" << outputStrides << "[k];\n"; + out << SP << SP << SP << "};\n"; + out << SP << SP << "idx[j] = idx[j] /" << outputStrides << "[k];\n"; + + + out << SP << "assert(idx[" << fAttrAxes << "] == 0);\n"; // we can avoid computing this for the reduction axis which by definition is always zero + + out << SP << "float sum = 0;\n"; + out << SP << SP << " for (size_t k = 0; k < inputShape[" << fAttrAxes << "]; k++) { \n"; + out << SP << SP << " idx[" << fAttrAxes << "] = k;\n"; + // compute input index j + out << SP << SP << "size_t l = 0;\n"; + out << SP << SP << "size_t m = 0;\n"; + out << SP << SP << SP << "for(m=0; m < dim-1; m++){\n"; + out << SP << SP << SP << "l += idx[m] *" << inputStrides << "[m];\n"; + out << SP << SP << SP << "};\n"; + out << SP << SP << "l += idx[m];\n"; + out << SP << SP << "sum += tensor_" << fNX << "[l];\n"; + out << SP << SP << "};\n"; + out << SP << SP << "float average = sum/float(inputShape[" << fAttrAxes << "]);\n"; + out << SP << SP << "tensor_" << fNY << "[i] = average;\n"; + out << SP << "};\n"; + out << SP << "}\n"; + return out.str(); + } + +}; + +}//SOFIE +}//Experimental +}//TMVA + + +#endif //TMVA_SOFIE_ROPERATOR_Reduce \ No newline at end of file diff --git a/tmva/sofie/test/TestCustomModelsFromONNX.cxx b/tmva/sofie/test/TestCustomModelsFromONNX.cxx index 34c3adc2306d6..874c12207eb95 100644 --- a/tmva/sofie/test/TestCustomModelsFromONNX.cxx +++ b/tmva/sofie/test/TestCustomModelsFromONNX.cxx @@ -33,6 +33,9 @@ #include "Cast_FromONNX.hxx" #include "input_models/references/Cast.ref.hxx" +#include "ReduceMean_FromONNX.hxx" +#include "input_models/references/ReduceMean.ref.hxx" + #include "LinearWithLeakyRelu_FromONNX.hxx" #include "input_models/references/LinearWithLeakyRelu.ref.hxx" @@ -781,6 +784,30 @@ TEST(ONNX, Pow_broadcast){ } + TEST(ONNX, ReduceMean){ + constexpr float TOLERANCE = DEFAULT_TOLERANCE; + + // Preparing the standard input + std::vector input({ + 5, 2, 3, + 5, 5, 4 + }); + + TMVA_SOFIE_ReduceMean::Session s("ReduceMean_FromONNX.dat"); + std::vector output = s.infer(input.data()); + // Checking output size + EXPECT_EQ(output.size(), sizeof(ReduceMean_ExpectedOutput::output) / sizeof(float)); + + float *correct = ReduceMean_ExpectedOutput::output; + + // Checking every output value, one by one + for (size_t i = 0; i < output.size(); ++i) { + EXPECT_LE(std::abs(output[i] - correct[i]), TOLERANCE); + } + +} + + TEST(ONNX, RNNBatchwise) { constexpr float TOLERANCE = DEFAULT_TOLERANCE; diff --git a/tmva/sofie/test/input_models/ReduceMean.onnx b/tmva/sofie/test/input_models/ReduceMean.onnx new file mode 100644 index 0000000000000000000000000000000000000000..c72d990e1de2f759634c9813824551fc14cc8b22 GIT binary patch literal 167 zcmd;J5n?Z>EXglQ&X8g=)H5{HGqCDqey3sN$3izOHqFfs`VfKAoS$}G`MttiMZDv8p-YN`;I00*NG4;K>$ aBM>tIF>?|(7o(vN8y5>ug29PNfD-^UIw>3g literal 0 HcmV?d00001 diff --git a/tmva/sofie/test/input_models/references/ReduceMean.ref.hxx b/tmva/sofie/test/input_models/references/ReduceMean.ref.hxx new file mode 100644 index 0000000000000..12a4bd869ebaa --- /dev/null +++ b/tmva/sofie/test/input_models/references/ReduceMean.ref.hxx @@ -0,0 +1,5 @@ +namespace Reduce_mean_ExpectedOutput{ + float output[] = { + 4 + }; +} // namespace Reduce_mean_ExpectedOutput \ No newline at end of file diff --git a/tmva/sofie_parsers/inc/TMVA/RModelParser_ONNX.hxx b/tmva/sofie_parsers/inc/TMVA/RModelParser_ONNX.hxx index dc95ad413c948..9902ab5ecf088 100644 --- a/tmva/sofie_parsers/inc/TMVA/RModelParser_ONNX.hxx +++ b/tmva/sofie_parsers/inc/TMVA/RModelParser_ONNX.hxx @@ -47,6 +47,7 @@ std::unique_ptr make_ROperator_Identity(const onnx::NodeProto &nodepr std::unique_ptr make_ROperator_Softmax(const onnx::NodeProto &nodeproto, const onnx::GraphProto &graphproto, std::unordered_map &tensor_type); std::unique_ptr make_ROperator_Concat(const onnx::NodeProto &nodeproto, const onnx::GraphProto &graphproto, std::unordered_map &tensor_type); std::unique_ptr make_ROperator_Cast(const onnx::NodeProto &nodeproto, const onnx::GraphProto &graphproto, std::unordered_map &tensor_type); +std::unique_ptr make_ROperator_Reduce(const onnx::NodeProto &nodeproto, const onnx::GraphProto &graphproto, std::unordered_map &tensor_type); using factoryMethodMap = std::unordered_map (*)(const onnx::NodeProto&, const onnx::GraphProto&, std::unordered_map&)>; const factoryMethodMap mapOptypeOperator = { @@ -71,6 +72,9 @@ const factoryMethodMap mapOptypeOperator = { {"Div", &make_ROperator_BasicBinary
}, {"Pow", &make_ROperator_BasicBinary}, {"Neg", &make_ROperator_Neg}, + {"ReduceMean", &make_ROperator_Reduce}, + {"ReduceSumsquare", &make_ROperator_Reduce}, + {"ReduceProd", &make_ROperator_Reduce}, {"Reshape", &make_ROperator_Reshape}, {"Flatten", &make_ROperator_Reshape}, {"Slice", &make_ROperator_Slice}, diff --git a/tmva/sofie_parsers/src/RModelParser_ONNX.cxx b/tmva/sofie_parsers/src/RModelParser_ONNX.cxx index ac32bcbbb7de7..c95ea772f5dec 100644 --- a/tmva/sofie_parsers/src/RModelParser_ONNX.cxx +++ b/tmva/sofie_parsers/src/RModelParser_ONNX.cxx @@ -116,6 +116,46 @@ std::unique_ptr make_ROperator_Neg(const onnx::NodeProto& nodeproto, return op; } +template +std::unique_ptr make_ROperator_Reduce(const onnx::NodeProto& nodeproto, const onnx::GraphProto& /*graphproto*/, std::unordered_map& tensor_type){ + + ETensorType input_type; + +auto input_name = nodeproto.input(0); + auto it = tensor_type.find(input_name); + if (it != tensor_type.end()){ + input_type = it->second; + }else{ + throw std::runtime_error("TMVA::SOFIE ONNX Parser Reduce op has input tensor" + input_name + " but its type is not yet registered"); + } + + std::unique_ptr op; + int attr_keepdims = 1; + int attr_axis = 1; + for (int_t i = 0; i < nodeproto.attribute_size(); i++) { + std::string attribute_name = nodeproto.attribute(i).name(); + if (attribute_name == "keepdims") + attr_keepdims = nodeproto.attribute(i).i(); + if(attribute_name == "axis") + attr_axis = nodeproto.attribute(i).i(); + } + switch(input_type){ + case ETensorType::FLOAT: + op.reset(new ROperator_Reduce(attr_keepdims,attr_axis,nodeproto.input(0), nodeproto.output(0))); + break; + default: + throw std::runtime_error("TMVA::SOFIE - Unsupported - Reduce Operator does not yet support input type " + std::to_string(static_cast(input_type))); + } + + ETensorType output_type = (op->TypeInference({input_type}))[0]; + auto it2 = tensor_type.find(nodeproto.output(0)); + if (it2 == tensor_type.end()){ + tensor_type[nodeproto.output(0)] = output_type; + } + + return op; +} + std::unique_ptr make_ROperator_Transpose(const onnx::NodeProto& nodeproto, const onnx::GraphProto& /*graphproto*/, std::unordered_map& tensor_type){ ETensorType input_type; From 6e10bccf36a4b37c99e5dd3b1ea40714efd13289 Mon Sep 17 00:00:00 2001 From: Neel-Shah-29 Date: Mon, 8 Aug 2022 19:14:38 +0530 Subject: [PATCH 2/8] Reduce Operator axis attribute added --- tmva/sofie/inc/TMVA/ROperator_Reduce.hxx | 4 ++-- tmva/sofie_parsers/src/RModelParser_ONNX.cxx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tmva/sofie/inc/TMVA/ROperator_Reduce.hxx b/tmva/sofie/inc/TMVA/ROperator_Reduce.hxx index 8aa3f282cb2c0..b75a9ddf07061 100644 --- a/tmva/sofie/inc/TMVA/ROperator_Reduce.hxx +++ b/tmva/sofie/inc/TMVA/ROperator_Reduce.hxx @@ -1,4 +1,3 @@ - // #ifndef TMVA_SOFIE_ROPERATOR_Reduce // #define TMVA_SOFIE_ROPERATOR_Reduce @@ -298,4 +297,5 @@ public: }//TMVA -#endif //TMVA_SOFIE_ROPERATOR_Reduce \ No newline at end of file +#endif //TMVA_SOFIE_ROPERATOR_Reduce + diff --git a/tmva/sofie_parsers/src/RModelParser_ONNX.cxx b/tmva/sofie_parsers/src/RModelParser_ONNX.cxx index c95ea772f5dec..b3824c4156bfc 100644 --- a/tmva/sofie_parsers/src/RModelParser_ONNX.cxx +++ b/tmva/sofie_parsers/src/RModelParser_ONNX.cxx @@ -131,7 +131,7 @@ auto input_name = nodeproto.input(0); std::unique_ptr op; int attr_keepdims = 1; - int attr_axis = 1; + int attr_axis = 1; for (int_t i = 0; i < nodeproto.attribute_size(); i++) { std::string attribute_name = nodeproto.attribute(i).name(); if (attribute_name == "keepdims") From 3e02561d0e8c5487393e286f904fbfef05b9f2c0 Mon Sep 17 00:00:00 2001 From: Neel Shah Date: Sat, 20 Aug 2022 03:37:56 +0530 Subject: [PATCH 3/8] Made the required changes according the expected generated code and shape in the Reduce Operator --- tmva/sofie/inc/TMVA/ROperator_Reduce.hxx | 279 +++++------------- .../inc/TMVA/RModelParser_ONNX.hxx | 1 + tmva/sofie_parsers/src/RModelParser_ONNX.cxx | 15 +- 3 files changed, 90 insertions(+), 205 deletions(-) diff --git a/tmva/sofie/inc/TMVA/ROperator_Reduce.hxx b/tmva/sofie/inc/TMVA/ROperator_Reduce.hxx index b75a9ddf07061..2b41df48dedab 100644 --- a/tmva/sofie/inc/TMVA/ROperator_Reduce.hxx +++ b/tmva/sofie/inc/TMVA/ROperator_Reduce.hxx @@ -1,147 +1,3 @@ -// #ifndef TMVA_SOFIE_ROPERATOR_Reduce -// #define TMVA_SOFIE_ROPERATOR_Reduce - -// #include "TMVA/SOFIE_common.hxx" -// #include "TMVA/ROperator.hxx" -// #include "TMVA/RModel.hxx" - -// #include -// #include -// #include -// #include -// #include -// #include - -// namespace TMVA{ -// namespace Experimental{ -// namespace SOFIE{ - -// enum ReduceOpMode { ReduceMean, ReduceSumsquare, ReduceProd }; - -// template -// struct ReduceOperatorTrait { -// const char *Name() { return ""; } -// }; -// template -// struct ReduceOperatorTrait { -// static const char *Name() { return "ReduceMean"; } -// }; - -// template -// struct ReduceOperatorTrait { -// static const char *Name() { return "ReduceProd"; } -// }; - -// template -// struct ReduceOperatorTrait { -// static const char *Name() { return "ReduceSumsquare"; } -// }; - -// template -// class ROperator_Reduce final : public ROperator -// { -// private: -// /* Attributes*/ -// int fAxis = 1; -// ReduceOpMode fReduceMode; -// int fkeepdims = 1; //default value -// std::string fNX; -// std::string fNY; -// std::vector fShapeX; -// std::vector fShapeY; - -// public: - -// ROperator_Reduce(){} -// ROperator_Reduce(int keepdims,int axis,std::string nameX, std::string nameY): -// fkeepdims(keepdims), fAxis(axis), fNX(UTILITY::Clean_name(nameX)), fNY(UTILITY::Clean_name(nameY)) {} - -// // type of output given input -// std::vector TypeInference(std::vector input){ -// return input; -// } - -// // shape of output tensors given input tensors -// std::vector> ShapeInference(std::vector> input){ -// // assume now inputs have same shape (no broadcasting) -// auto ret = std::vector>(1, input[0]); // return vector size 1 with first input -// return ret; -// } -// void Initialize(RModel& model){ - -// fUseSession = model.UseSession(); - -// if (model.CheckIfTensorAlreadyExist(fNX) == false){ //input must be a graph input, or already initialized intermediate tensor -// throw std::runtime_error("TMVA SOFIE Reduce Op Input Tensor " + fNX + " is not found in model"); -// } -// fShapeX = model.GetTensorShape(fNX); -// // find shape of Y and add it in the list of intermediate tensors -// fShapeY = ShapeInference({fShapeX})[0]; -// model.AddIntermediateTensor(fNY, model.GetTensorType(fNX), fShapeY); -// } - -// std::string Generate(std::string OpName){ -// OpName = "op_" + OpName; -// if (fShapeX.empty() || fShapeY.empty()) { -// throw std::runtime_error("TMVA SOFIE Reduce Op called to Generate without being initialized first"); -// } - -// size_t outputLength = TMVA::Experimental::SOFIE::ConvertShapeToLength(fShapeY); - -// auto inputStrides = TMVA::Experimental::SOFIE::UTILITY::ComputeStrideFromShape(fShapeX); -// auto outputStrides = TMVA::Experimental::SOFIE::UTILITY::ComputeStrideFromShape(fShapeY); - -// size_t dim = fShapeY.size(); -// std::vector idx(dim); - -// std::stringstream out; -// for (size_t i = 0; i < outputLength; i++) { - -// if (dim == 2) { -// idx[0] = i / outputStrides[0]; -// idx[1] = i % outputStrides[0]; -// } -// if (dim == 3) { -// idx[0] = i / outputStrides[0]; -// idx[1] = (i % outputStrides[0]) / outputStrides[1]; -// idx[2] = (i % outputStrides[0]) % outputStrides[1]; -// } -// if (dim == 4) { -// idx[0] = i / outputStrides[0]; -// idx[1] = (i % outputStrides[0]) / outputStrides[1]; -// idx[2] = ((i % outputStrides[0]) % outputStrides[1]) / outputStrides[2]; -// idx[3] = ((i % outputStrides[0]) % outputStrides[1]) % outputStrides[2]; -// } - -// assert(idx[fAxis] == 0); // we can avoid computing this for the reduction axis which by definition is always zero - -// out << SP << "float sum = 0;\n"; -// // float sum = 0; -// for (size_t k = 0; k < fShapeX[fAxis]; k++) { -// idx[fAxis] = k; -// // compute input index j -// size_t j = 0; -// if (dim == 2) j = idx[0]*inputStrides[0] + idx[1]; -// if (dim == 3) j = idx[0]*inputStrides[0] + idx[1]* inputStrides[1] + idx[2]; -// if (dim == 4) j = idx[0]*inputStrides[0] + idx[1]* inputStrides[1] + idx[2]*inputStrides[2] + idx[3]; - -// out << SP << SP << "sum += tensor_" << fNX[j] << ";\n"; -// } -// out << SP << "float average = sum/float(" << fShapeX[fAxis] << ")\n;"; -// out << SP << "tensor_" << fNY[i] << " = average;\n"; -// } -// return out.str(); -// } - -// }; - -// }//SOFIE -// }//Experimental -// }//TMVA - - -// #endif //TMVA_SOFIE_ROPERATOR_Reduce - #ifndef TMVA_SOFIE_ROPERATOR_Reduce #define TMVA_SOFIE_ROPERATOR_Reduce @@ -160,38 +16,31 @@ namespace TMVA{ namespace Experimental{ namespace SOFIE{ -template -struct ReduceOperatorTrait { - const char *Name() { return ""; } -}; -template -struct ReduceOperatorTrait { - static const char *Name() { return "ReduceMean"; } -}; +enum EReduceOpMode { ReduceMean, ReduceSumsquare, ReduceProd, InvalidReduceOp }; -template -struct ReduceOperatorTrait { - static const char *Name() { return "ReduceProd"; } -}; - -template -struct ReduceOperatorTrait { - static const char *Name() { return "ReduceSumsquare"; } -}; - -template +template class ROperator_Reduce final : public ROperator { private: /* Attributes*/ int fkeepdims = 1; //default value + int fAttrAxes; + EReduceOpMode fReduceOpMode; std::string fNX; std::string fNY; std::vector fShapeX; std::vector fShapeY; - int fAttrAxes; + public: + + std::string Name() { + if (fReduceOpMode == ReduceMean) return "ReduceMean"; + else if (fReduceOpMode == ReduceSumsquare ) return "ReduceSumsquare"; + else if (fReduceOpMode == ReduceProd ) return "ReduceProd"; + return "Invalid"; + } + ROperator_Reduce(){} ROperator_Reduce(int keepdims,int attrAxes,std::string nameX, std::string nameY): fkeepdims(keepdims), fAttrAxes(attrAxes), fNX(UTILITY::Clean_name(nameX)), fNY(UTILITY::Clean_name(nameY)) {} @@ -203,13 +52,8 @@ public: // shape of output tensors given input tensors std::vector> ShapeInference(std::vector> input){ - - // std::vector> ret; - // auto & input_shape = input[0]; - // auto ret = std::vector>(1, input[0]); // return vector size 1 with first input - // return ret; auto ret = input; //suggest copy to compiler - ret[fAttrAxes] = 1; + ret[0][fAttrAxes] = 1; return ret; } void Initialize(RModel& model){ @@ -220,9 +64,10 @@ public: throw std::runtime_error("TMVA SOFIE Reduce Op Input Tensor " + fNX + " is not found in model"); } fShapeX = model.GetTensorShape(fNX); - // find shape of Y and add it in the list of intermediate tensors - fShapeY = ShapeInference(fShapeX); - model.AddIntermediateTensor(fNY, model.GetTensorType(fNX), fShapeY); + // find shape of Y and add it in the list of intermediate tensors + fShapeY = ShapeInference({fShapeX})[0]; + model.AddIntermediateTensor(fNY, model.GetTensorType(fNX), fShapeY); + } std::string Generate(std::string OpName){ @@ -236,21 +81,16 @@ public: auto inputStrides = TMVA::Experimental::SOFIE::UTILITY::ComputeStrideFromShape(fShapeX); auto outputStrides = TMVA::Experimental::SOFIE::UTILITY::ComputeStrideFromShape(fShapeY); - // write here according to size of shape - // in generation code can be done automatically - // i0 = i / s0 ; i1 = (i % s0) / s1 ; i2 = ( (i % s0) % s1 ) / s2 and so on - // and we have for the inverse - // i = i0 * s0 + i1 * s1 + i2 * s2 + i3 * s3 .... + // write here according to size of shape + // in generation code can be done automatically + // i0 = i / s0 ; i1 = (i % s0) / s1 ; i2 = ( (i % s0) % s1 ) / s2 and so on + // and we have for the inverse + // i = i0 * s0 + i1 * s1 + i2 * s2 + i3 * s3 .... - // don't need to divide by last stride s[n-1] since it is 1 by definition + // don't need to divide by last stride s[n-1] since it is 1 by definition std::stringstream out; - out << "\n//---- operator " << std::string(ReduceOperatorTrait::Name()) << " " << OpName << "\n"; - out << SP << "size_t dim = " << fShapeY.size() << ";\n"; - - out << SP << "std::vector idx(dim);"; - - + out << "\n//---- operator " << Name() << " " << OpName << "\n"; out << SP << "for (size_t i = 0; i < " << outputLength << "; i++) {\n"; // write here according to size of shape @@ -260,30 +100,63 @@ public: // i = i0 * s0 + i1 * s1 + i2 * s2 + i3 * s3 .... // don't need to divide by last stride s[n-1] since it is 1 by definition + + size_t dim = fShapeX.size(); // this is the input dimension (e.g. 2, 3 or 4 or more) + out << SP << "std::vector outputStrides = {" ; + for (size_t k = 0; k < dim; k++) { + out << outputStrides[k] ; + if (k < dim-1) + out << " ,"; + else + out << " };\n"; + } + // no compute indices as function of strides + // as in the example I have sent you - out << SP << SP << "idx[j] = i;\n"; - out << SP << SP << "size_t k = 0;\n"; - out << SP << SP << SP << "for(k=0; k < dim-1; k++){\n"; - out << SP << SP << SP << "idx[k] = idx[k] %" << outputStrides << "[k];\n"; - out << SP << SP << SP << "};\n"; - out << SP << SP << "idx[j] = idx[j] /" << outputStrides << "[k];\n"; - + for (size_t k = 0; k < dim; k++) { + size_t j; + out << SP << "size_t idx_" << k <<" = i;\n"; + for(j = 0; j < k; j++ ) + out << SP << "idx_" << k << " = idx_" << k <<" % outputStrides[" << j << "];\n" ; - out << SP << "assert(idx[" << fAttrAxes << "] == 0);\n"; // we can avoid computing this for the reduction axis which by definition is always zero + out << SP << "idx_" << k << " = idx_" << k << "/ outputStrides[" << j << "];\n"; + } + + // out << SP << "assert(idx[" << fAttrAxes << "] == 0);\n"; // we can avoid computing this for the reduction axis which by definition is always zero out << SP << "float sum = 0;\n"; - out << SP << SP << " for (size_t k = 0; k < inputShape[" << fAttrAxes << "]; k++) { \n"; - out << SP << SP << " idx[" << fAttrAxes << "] = k;\n"; + out << SP << SP << " for (size_t k = 0; k < " << fShapeX[fAttrAxes] <<"; k++) { \n"; + out << SP << SP << " idx_" << fAttrAxes << " = k;\n"; // compute input index j + out << SP << "std::vector inputStrides = {" ; + for (size_t k = 0; k < dim; k++) { + out << inputStrides[k] ; + if (k < dim-1) + out << " ,"; + else + out << " };\n"; + } out << SP << SP << "size_t l = 0;\n"; - out << SP << SP << "size_t m = 0;\n"; - out << SP << SP << SP << "for(m=0; m < dim-1; m++){\n"; - out << SP << SP << SP << "l += idx[m] *" << inputStrides << "[m];\n"; - out << SP << SP << SP << "};\n"; - out << SP << SP << "l += idx[m];\n"; - out << SP << SP << "sum += tensor_" << fNX << "[l];\n"; - out << SP << SP << "};\n"; - out << SP << SP << "float average = sum/float(inputShape[" << fAttrAxes << "]);\n"; + for (size_t m = 0; m < dim; m++) { + size_t n; + for(n = 0; n < m; n++ ) + out << SP << "l += idx_" << n << " * inputStrides[" << n << "];\n"; + + out << SP << "l += idx_" << m << ";\n"; + } + if(fReduceOpMode == ReduceMean){ + out << SP << SP << "sum += tensor_" << fNX << "[l];\n"; + out << SP << SP << "};\n"; + } + else if(fReduceOpMode == ReduceSumsquare){ + out << SP << SP << "sum += tensor_" << fNX << "[l] * tensor_" << fNX << "[l];\n"; + out << SP << SP << "};\n"; + } + else if(fReduceOpMode == ReduceProd){ + out << SP << SP << "sum *= tensor_" << fNX << "[l];\n"; + out << SP << SP << "};\n"; + } + out << SP << SP << "float average = sum/(float)" << fShapeX[fAttrAxes] << ";\n"; out << SP << SP << "tensor_" << fNY << "[i] = average;\n"; out << SP << "};\n"; out << SP << "}\n"; diff --git a/tmva/sofie_parsers/inc/TMVA/RModelParser_ONNX.hxx b/tmva/sofie_parsers/inc/TMVA/RModelParser_ONNX.hxx index 9902ab5ecf088..ba82bf1c952a8 100644 --- a/tmva/sofie_parsers/inc/TMVA/RModelParser_ONNX.hxx +++ b/tmva/sofie_parsers/inc/TMVA/RModelParser_ONNX.hxx @@ -47,6 +47,7 @@ std::unique_ptr make_ROperator_Identity(const onnx::NodeProto &nodepr std::unique_ptr make_ROperator_Softmax(const onnx::NodeProto &nodeproto, const onnx::GraphProto &graphproto, std::unordered_map &tensor_type); std::unique_ptr make_ROperator_Concat(const onnx::NodeProto &nodeproto, const onnx::GraphProto &graphproto, std::unordered_map &tensor_type); std::unique_ptr make_ROperator_Cast(const onnx::NodeProto &nodeproto, const onnx::GraphProto &graphproto, std::unordered_map &tensor_type); +template std::unique_ptr make_ROperator_Reduce(const onnx::NodeProto &nodeproto, const onnx::GraphProto &graphproto, std::unordered_map &tensor_type); using factoryMethodMap = std::unordered_map (*)(const onnx::NodeProto&, const onnx::GraphProto&, std::unordered_map&)>; diff --git a/tmva/sofie_parsers/src/RModelParser_ONNX.cxx b/tmva/sofie_parsers/src/RModelParser_ONNX.cxx index b3824c4156bfc..5eb4858df50d5 100644 --- a/tmva/sofie_parsers/src/RModelParser_ONNX.cxx +++ b/tmva/sofie_parsers/src/RModelParser_ONNX.cxx @@ -116,12 +116,23 @@ std::unique_ptr make_ROperator_Neg(const onnx::NodeProto& nodeproto, return op; } -template +template std::unique_ptr make_ROperator_Reduce(const onnx::NodeProto& nodeproto, const onnx::GraphProto& /*graphproto*/, std::unordered_map& tensor_type){ ETensorType input_type; -auto input_name = nodeproto.input(0); + EReduceOpMode op_mode = InvalidReduceOp; + + if (nodeproto.op_type() == "ReduceMean") + op_mode = ReduceMean; + else if (nodeproto.op_type() == "ReduceSumsquare") + op_mode = ReduceSumsquare; + else if (nodeproto.op_type() == "ReduceProd") + op_mode = ReduceProd; + + assert(op_mode != InvalidReduceOp); + + auto input_name = nodeproto.input(0); auto it = tensor_type.find(input_name); if (it != tensor_type.end()){ input_type = it->second; From e8167d2d6980a7e086e86c8cc84d89a203946e4c Mon Sep 17 00:00:00 2001 From: Neel Shah Date: Sat, 20 Aug 2022 17:45:54 +0530 Subject: [PATCH 4/8] Made the required changes to resolve the generated code errors --- tmva/sofie/inc/TMVA/ROperator_Reduce.hxx | 14 +++++----- tmva/sofie/test/TestCustomModelsFromONNX.cxx | 25 ++++++++++++++++++ tmva/sofie/test/input_models/ReduceMean.onnx | Bin 167 -> 181 bytes tmva/sofie/test/input_models/ReduceProd.onnx | Bin 0 -> 181 bytes .../references/ReduceMean.ref.hxx | 2 +- .../references/ReduceProd.ref.hxx | 5 ++++ 6 files changed, 37 insertions(+), 9 deletions(-) create mode 100644 tmva/sofie/test/input_models/ReduceProd.onnx create mode 100644 tmva/sofie/test/input_models/references/ReduceProd.ref.hxx diff --git a/tmva/sofie/inc/TMVA/ROperator_Reduce.hxx b/tmva/sofie/inc/TMVA/ROperator_Reduce.hxx index 2b41df48dedab..4e8cd2902ae6d 100644 --- a/tmva/sofie/inc/TMVA/ROperator_Reduce.hxx +++ b/tmva/sofie/inc/TMVA/ROperator_Reduce.hxx @@ -110,8 +110,6 @@ public: else out << " };\n"; } - // no compute indices as function of strides - // as in the example I have sent you for (size_t k = 0; k < dim; k++) { size_t j; @@ -125,7 +123,7 @@ public: // out << SP << "assert(idx[" << fAttrAxes << "] == 0);\n"; // we can avoid computing this for the reduction axis which by definition is always zero out << SP << "float sum = 0;\n"; - out << SP << SP << " for (size_t k = 0; k < " << fShapeX[fAttrAxes] <<"; k++) { \n"; + out << SP << " for (size_t k = 0; k < " << fShapeX[fAttrAxes] <<"; k++) { \n"; out << SP << SP << " idx_" << fAttrAxes << " = k;\n"; // compute input index j out << SP << "std::vector inputStrides = {" ; @@ -137,13 +135,13 @@ public: out << " };\n"; } out << SP << SP << "size_t l = 0;\n"; - for (size_t m = 0; m < dim; m++) { - size_t n; - for(n = 0; n < m; n++ ) + + size_t n ; + for(n = 0; n < dim-1; n++ ) out << SP << "l += idx_" << n << " * inputStrides[" << n << "];\n"; - out << SP << "l += idx_" << m << ";\n"; - } + out << SP << "l += idx_" << n << ";\n"; + if(fReduceOpMode == ReduceMean){ out << SP << SP << "sum += tensor_" << fNX << "[l];\n"; out << SP << SP << "};\n"; diff --git a/tmva/sofie/test/TestCustomModelsFromONNX.cxx b/tmva/sofie/test/TestCustomModelsFromONNX.cxx index 874c12207eb95..cd8f414059001 100644 --- a/tmva/sofie/test/TestCustomModelsFromONNX.cxx +++ b/tmva/sofie/test/TestCustomModelsFromONNX.cxx @@ -36,6 +36,9 @@ #include "ReduceMean_FromONNX.hxx" #include "input_models/references/ReduceMean.ref.hxx" +#include "ReduceProd_FromONNX.hxx" +#include "input_models/references/ReduceProd.ref.hxx" + #include "LinearWithLeakyRelu_FromONNX.hxx" #include "input_models/references/LinearWithLeakyRelu.ref.hxx" @@ -807,6 +810,28 @@ TEST(ONNX, Pow_broadcast){ } + TEST(ONNX, ReduceProd){ + constexpr float TOLERANCE = DEFAULT_TOLERANCE; + + // Preparing the standard input + std::vector input({ + 5, 2, 3, + 5, 5, 4 + }); + + TMVA_SOFIE_ReduceProd::Session s("ReduceProd_FromONNX.dat"); + std::vector output = s.infer(input.data()); + // Checking output size + EXPECT_EQ(output.size(), sizeof(ReduceProd_ExpectedOutput::output) / sizeof(float)); + + float *correct = ReduceProd_ExpectedOutput::output; + + // Checking every output value, one by one + for (size_t i = 0; i < output.size(); ++i) { + EXPECT_LE(std::abs(output[i] - correct[i]), TOLERANCE); + } + +} TEST(ONNX, RNNBatchwise) { diff --git a/tmva/sofie/test/input_models/ReduceMean.onnx b/tmva/sofie/test/input_models/ReduceMean.onnx index c72d990e1de2f759634c9813824551fc14cc8b22..48b62512bfc584793ba16616181a882466549156 100644 GIT binary patch delta 100 zcmZ3^xRp_YgI$Qdpt2;tC^v<5^o^HXeh;l zETF`N;AwGlu_RWc7CSI5U}V?g=iDNy1!=hC+N?JU|H!s06bUlK?LOV@xU) literal 0 HcmV?d00001 diff --git a/tmva/sofie/test/input_models/references/ReduceMean.ref.hxx b/tmva/sofie/test/input_models/references/ReduceMean.ref.hxx index 12a4bd869ebaa..c57f62c0b8cb6 100644 --- a/tmva/sofie/test/input_models/references/ReduceMean.ref.hxx +++ b/tmva/sofie/test/input_models/references/ReduceMean.ref.hxx @@ -1,5 +1,5 @@ namespace Reduce_mean_ExpectedOutput{ float output[] = { - 4 + 5.0, 3.5, 3.5 }; } // namespace Reduce_mean_ExpectedOutput \ No newline at end of file diff --git a/tmva/sofie/test/input_models/references/ReduceProd.ref.hxx b/tmva/sofie/test/input_models/references/ReduceProd.ref.hxx new file mode 100644 index 0000000000000..234909ca5123a --- /dev/null +++ b/tmva/sofie/test/input_models/references/ReduceProd.ref.hxx @@ -0,0 +1,5 @@ +namespace Reduce_mean_ExpectedOutput{ + float output[] = { + 25.0, 10.0, 12.0 + }; +} // namespace Reduce_mean_ExpectedOutput \ No newline at end of file From 21e8ee97f0ad62b2d5d981d2259e045e48d72b87 Mon Sep 17 00:00:00 2001 From: moneta Date: Fri, 26 Aug 2022 18:03:46 +0200 Subject: [PATCH 5/8] Fix generated code for Reduce operator Fix also correct namespace for reference output in reduce tests --- tmva/sofie/inc/TMVA/ROperator_Reduce.hxx | 129 +++++++++++------- .../references/ReduceMean.ref.hxx | 2 +- .../references/ReduceProd.ref.hxx | 2 +- 3 files changed, 81 insertions(+), 52 deletions(-) diff --git a/tmva/sofie/inc/TMVA/ROperator_Reduce.hxx b/tmva/sofie/inc/TMVA/ROperator_Reduce.hxx index 4e8cd2902ae6d..3c3f1367ceda2 100644 --- a/tmva/sofie/inc/TMVA/ROperator_Reduce.hxx +++ b/tmva/sofie/inc/TMVA/ROperator_Reduce.hxx @@ -30,7 +30,7 @@ private: std::string fNY; std::vector fShapeX; std::vector fShapeY; - + public: @@ -41,9 +41,11 @@ public: return "Invalid"; } - ROperator_Reduce(){} + ROperator_Reduce(){} ROperator_Reduce(int keepdims,int attrAxes,std::string nameX, std::string nameY): - fkeepdims(keepdims), fAttrAxes(attrAxes), fNX(UTILITY::Clean_name(nameX)), fNY(UTILITY::Clean_name(nameY)) {} + fkeepdims(keepdims), fAttrAxes(attrAxes), fNX(UTILITY::Clean_name(nameX)), fNY(UTILITY::Clean_name(nameY)) { + fReduceOpMode = Op; + } // type of output given input std::vector TypeInference(std::vector input){ @@ -80,7 +82,7 @@ public: auto inputStrides = TMVA::Experimental::SOFIE::UTILITY::ComputeStrideFromShape(fShapeX); auto outputStrides = TMVA::Experimental::SOFIE::UTILITY::ComputeStrideFromShape(fShapeY); - + // write here according to size of shape // in generation code can be done automatically // i0 = i / s0 ; i1 = (i % s0) / s1 ; i2 = ( (i % s0) % s1 ) / s2 and so on @@ -88,11 +90,11 @@ public: // i = i0 * s0 + i1 * s1 + i2 * s2 + i3 * s3 .... // don't need to divide by last stride s[n-1] since it is 1 by definition - + std::stringstream out; out << "\n//---- operator " << Name() << " " << OpName << "\n"; out << SP << "for (size_t i = 0; i < " << outputLength << "; i++) {\n"; - + // write here according to size of shape // in generation code can be done automatically // i0 = i / s0 ; i1 = (i % s0) / s1 ; i2 = ( (i % s0) % s1 ) / s2 and so on @@ -102,61 +104,88 @@ public: // don't need to divide by last stride s[n-1] since it is 1 by definition size_t dim = fShapeX.size(); // this is the input dimension (e.g. 2, 3 or 4 or more) - out << SP << "std::vector outputStrides = {" ; - for (size_t k = 0; k < dim; k++) { - out << outputStrides[k] ; - if (k < dim-1) - out << " ,"; - else - out << " };\n"; - } - - for (size_t k = 0; k < dim; k++) { - size_t j; - out << SP << "size_t idx_" << k <<" = i;\n"; - for(j = 0; j < k; j++ ) - out << SP << "idx_" << k << " = idx_" << k <<" % outputStrides[" << j << "];\n" ; - - out << SP << "idx_" << k << " = idx_" << k << "/ outputStrides[" << j << "];\n"; + // out << SP << "std::vector outputStrides = {" ; + // for (size_t k = 0; k < dim; k++) { + // out << outputStrides[k] ; + // if (k < dim-1) + // out << " ,"; + // else + // out << " };\n"; + // } + + // here we find output indices + out << SP << SP << "size_t idx_0 = i / " << outputStrides[0] << ";\n" ; + out << SP << SP << "size_t itmp = i;\n"; + for (size_t k = 1; k < dim; k++) { + out << SP << SP << "itmp = itmp % " << outputStrides[k-1] << ";\n" ; + if (k < dim-1) + out << SP << SP << "size_t idx_" << k << " = itmp / " << outputStrides[k] << ";\n" ; + else + // to avoid division by 1 which is outputStrides[dim-1] + out << SP << SP << "size_t idx_" << k << " = itmp;\n"; } + + // for (size_t k = 0; k < dim; k++) { + // size_t j; + // out << SP << "size_t idx_" << k <<" = i;\n"; + // for(j = 0; j < k; j++ ) + // out << SP << "idx_" << k << " = idx_" << k <<" % outputStrides[" << j << "];\n" ; + + // out << SP << "idx_" << k << " = idx_" << k << "/ outputStrides[" << j << "];\n"; + // } + // out << SP << "assert(idx[" << fAttrAxes << "] == 0);\n"; // we can avoid computing this for the reduction axis which by definition is always zero - out << SP << "float sum = 0;\n"; - out << SP << " for (size_t k = 0; k < " << fShapeX[fAttrAxes] <<"; k++) { \n"; - out << SP << SP << " idx_" << fAttrAxes << " = k;\n"; - // compute input index j - out << SP << "std::vector inputStrides = {" ; - for (size_t k = 0; k < dim; k++) { - out << inputStrides[k] ; - if (k < dim-1) - out << " ,"; - else - out << " };\n"; + // compute reduction + + out << SP << SP << "float sum = 0;\n"; + out << SP << SP << "for (size_t k = 0; k < " << fShapeX[fAttrAxes] <<"; k++) { \n"; + out << SP << SP << SP << "idx_" << fAttrAxes << " = k;\n"; + // compute input index j + out << SP << SP << SP << "size_t l = "; + for(int n = dim-1; n >= 0; n-- ) { + if (n == dim-1) + out << "idx_" << n; + else + out << " + " << "idx_" << n << " * " << inputStrides[n]; } - out << SP << SP << "size_t l = 0;\n"; - - size_t n ; - for(n = 0; n < dim-1; n++ ) - out << SP << "l += idx_" << n << " * inputStrides[" << n << "];\n"; - - out << SP << "l += idx_" << n << ";\n"; - + out << ";\n"; + + + // out << SP << "std::vector inputStrides = {" ; + // for (size_t k = 0; k < dim; k++) { + // out << inputStrides[k] ; + // if (k < dim-1) + // out << " ,"; + // else + // out << " };\n"; + // } + // out << SP << SP << "size_t l = 0;\n"; + + // size_t n ; + // for(n = 0; n < dim-1; n++ ) + // out << SP << "l += idx_" << n << " * inputStrides[" << n << "];\n"; + + // out << SP << "l += idx_" << n << ";\n"; + if(fReduceOpMode == ReduceMean){ - out << SP << SP << "sum += tensor_" << fNX << "[l];\n"; - out << SP << SP << "};\n"; + out << SP << SP << SP << "sum += tensor_" << fNX << "[l];\n"; + out << SP << SP << "}\n"; + out << SP << SP << "float reduceResult = sum/static_cast(" << fShapeX[fAttrAxes] << ");\n"; } else if(fReduceOpMode == ReduceSumsquare){ - out << SP << SP << "sum += tensor_" << fNX << "[l] * tensor_" << fNX << "[l];\n"; - out << SP << SP << "};\n"; + out << SP << SP << SP << "sum += tensor_" << fNX << "[l] * tensor_" << fNX << "[l];\n"; + out << SP << SP << "}\n"; + out << SP << SP << "float reduceResult = sum;\n"; } else if(fReduceOpMode == ReduceProd){ - out << SP << SP << "sum *= tensor_" << fNX << "[l];\n"; - out << SP << SP << "};\n"; + out << SP << SP << SP << "sum *= tensor_" << fNX << "[l];\n"; + out << SP << SP << "}\n"; + out << SP << SP << "float reduceResult = sum;\n"; } - out << SP << SP << "float average = sum/(float)" << fShapeX[fAttrAxes] << ";\n"; - out << SP << SP << "tensor_" << fNY << "[i] = average;\n"; - out << SP << "};\n"; + + out << SP << SP << "tensor_" << fNY << "[i] = reduceResult;\n"; out << SP << "}\n"; return out.str(); } diff --git a/tmva/sofie/test/input_models/references/ReduceMean.ref.hxx b/tmva/sofie/test/input_models/references/ReduceMean.ref.hxx index c57f62c0b8cb6..053a34eebf527 100644 --- a/tmva/sofie/test/input_models/references/ReduceMean.ref.hxx +++ b/tmva/sofie/test/input_models/references/ReduceMean.ref.hxx @@ -1,4 +1,4 @@ -namespace Reduce_mean_ExpectedOutput{ +namespace ReduceMean_ExpectedOutput{ float output[] = { 5.0, 3.5, 3.5 }; diff --git a/tmva/sofie/test/input_models/references/ReduceProd.ref.hxx b/tmva/sofie/test/input_models/references/ReduceProd.ref.hxx index 234909ca5123a..af259b4c69d06 100644 --- a/tmva/sofie/test/input_models/references/ReduceProd.ref.hxx +++ b/tmva/sofie/test/input_models/references/ReduceProd.ref.hxx @@ -1,4 +1,4 @@ -namespace Reduce_mean_ExpectedOutput{ +namespace ReduceProd_ExpectedOutput{ float output[] = { 25.0, 10.0, 12.0 }; From 75d47d73b2e36bad751cd586077cfbb667668909 Mon Sep 17 00:00:00 2001 From: Neel Shah Date: Sat, 27 Aug 2022 00:02:38 +0530 Subject: [PATCH 6/8] Reduce Operator code cleaned and fixed the warning for int to size_t when (n==dim-1) --- tmva/sofie/inc/TMVA/ROperator_Reduce.hxx | 47 +----------------------- 1 file changed, 1 insertion(+), 46 deletions(-) diff --git a/tmva/sofie/inc/TMVA/ROperator_Reduce.hxx b/tmva/sofie/inc/TMVA/ROperator_Reduce.hxx index 3c3f1367ceda2..26d2494b8b133 100644 --- a/tmva/sofie/inc/TMVA/ROperator_Reduce.hxx +++ b/tmva/sofie/inc/TMVA/ROperator_Reduce.hxx @@ -95,23 +95,7 @@ public: out << "\n//---- operator " << Name() << " " << OpName << "\n"; out << SP << "for (size_t i = 0; i < " << outputLength << "; i++) {\n"; - // write here according to size of shape - // in generation code can be done automatically - // i0 = i / s0 ; i1 = (i % s0) / s1 ; i2 = ( (i % s0) % s1 ) / s2 and so on - // and we have for the inverse - // i = i0 * s0 + i1 * s1 + i2 * s2 + i3 * s3 .... - - // don't need to divide by last stride s[n-1] since it is 1 by definition - size_t dim = fShapeX.size(); // this is the input dimension (e.g. 2, 3 or 4 or more) - // out << SP << "std::vector outputStrides = {" ; - // for (size_t k = 0; k < dim; k++) { - // out << outputStrides[k] ; - // if (k < dim-1) - // out << " ,"; - // else - // out << " };\n"; - // } // here we find output indices out << SP << SP << "size_t idx_0 = i / " << outputStrides[0] << ";\n" ; @@ -125,18 +109,6 @@ public: out << SP << SP << "size_t idx_" << k << " = itmp;\n"; } - - // for (size_t k = 0; k < dim; k++) { - // size_t j; - // out << SP << "size_t idx_" << k <<" = i;\n"; - // for(j = 0; j < k; j++ ) - // out << SP << "idx_" << k << " = idx_" << k <<" % outputStrides[" << j << "];\n" ; - - // out << SP << "idx_" << k << " = idx_" << k << "/ outputStrides[" << j << "];\n"; - // } - - // out << SP << "assert(idx[" << fAttrAxes << "] == 0);\n"; // we can avoid computing this for the reduction axis which by definition is always zero - // compute reduction out << SP << SP << "float sum = 0;\n"; @@ -144,7 +116,7 @@ public: out << SP << SP << SP << "idx_" << fAttrAxes << " = k;\n"; // compute input index j out << SP << SP << SP << "size_t l = "; - for(int n = dim-1; n >= 0; n-- ) { + for(size_t n = dim-1; n >= 0; n-- ) { if (n == dim-1) out << "idx_" << n; else @@ -152,23 +124,6 @@ public: } out << ";\n"; - - // out << SP << "std::vector inputStrides = {" ; - // for (size_t k = 0; k < dim; k++) { - // out << inputStrides[k] ; - // if (k < dim-1) - // out << " ,"; - // else - // out << " };\n"; - // } - // out << SP << SP << "size_t l = 0;\n"; - - // size_t n ; - // for(n = 0; n < dim-1; n++ ) - // out << SP << "l += idx_" << n << " * inputStrides[" << n << "];\n"; - - // out << SP << "l += idx_" << n << ";\n"; - if(fReduceOpMode == ReduceMean){ out << SP << SP << SP << "sum += tensor_" << fNX << "[l];\n"; out << SP << SP << "}\n"; From 2333e21d58a318f9d73a8e003903bbc816653e42 Mon Sep 17 00:00:00 2001 From: Neel Shah Date: Tue, 30 Aug 2022 19:51:17 +0530 Subject: [PATCH 7/8] Reduce ONNX Operator warning fixed related to size_t and int --- tmva/sofie/inc/TMVA/ROperator_Reduce.hxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tmva/sofie/inc/TMVA/ROperator_Reduce.hxx b/tmva/sofie/inc/TMVA/ROperator_Reduce.hxx index 26d2494b8b133..6dec12487e4c2 100644 --- a/tmva/sofie/inc/TMVA/ROperator_Reduce.hxx +++ b/tmva/sofie/inc/TMVA/ROperator_Reduce.hxx @@ -116,8 +116,8 @@ public: out << SP << SP << SP << "idx_" << fAttrAxes << " = k;\n"; // compute input index j out << SP << SP << SP << "size_t l = "; - for(size_t n = dim-1; n >= 0; n-- ) { - if (n == dim-1) + for(int n = dim-1; n >=0; n--) { + if (n == int(dim-1)) out << "idx_" << n; else out << " + " << "idx_" << n << " * " << inputStrides[n]; From 048506556fcade52bef51e37266639aa8e3e1780 Mon Sep 17 00:00:00 2001 From: Neel Shah Date: Wed, 31 Aug 2022 00:43:10 +0530 Subject: [PATCH 8/8] Changes related to Reduce Prod done and sum updated to 1 for ReduceProd --- tmva/sofie/inc/TMVA/ROperator_Reduce.hxx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tmva/sofie/inc/TMVA/ROperator_Reduce.hxx b/tmva/sofie/inc/TMVA/ROperator_Reduce.hxx index 6dec12487e4c2..0681573d22876 100644 --- a/tmva/sofie/inc/TMVA/ROperator_Reduce.hxx +++ b/tmva/sofie/inc/TMVA/ROperator_Reduce.hxx @@ -111,7 +111,11 @@ public: // compute reduction - out << SP << SP << "float sum = 0;\n"; + if(fReduceOpMode == ReduceProd) + out << SP << SP << "float sum = 1;\n"; + else + out << SP << SP << "float sum = 0;\n"; + out << SP << SP << "for (size_t k = 0; k < " << fShapeX[fAttrAxes] <<"; k++) { \n"; out << SP << SP << SP << "idx_" << fAttrAxes << " = k;\n"; // compute input index j