1- // #ifndef TMVA_SOFIE_ROPERATOR_Reduce
2- // #define TMVA_SOFIE_ROPERATOR_Reduce
3-
4- // #include "TMVA/SOFIE_common.hxx"
5- // #include "TMVA/ROperator.hxx"
6- // #include "TMVA/RModel.hxx"
7-
8- // #include <memory>
9- // #include <sstream>
10- // #include <algorithm>
11- // #include <stdexcept>
12- // #include <vector>
13- // #include <cassert>
14-
15- // namespace TMVA{
16- // namespace Experimental{
17- // namespace SOFIE{
18-
19- // enum ReduceOpMode { ReduceMean, ReduceSumsquare, ReduceProd };
20-
21- // template <typename T, ReduceOpMode Op1>
22- // struct ReduceOperatorTrait {
23- // const char *Name() { return ""; }
24- // };
25- // template <typename T>
26- // struct ReduceOperatorTrait <T, ReduceMean> {
27- // static const char *Name() { return "ReduceMean"; }
28- // };
29-
30- // template <typename T>
31- // struct ReduceOperatorTrait <T, ReduceProd> {
32- // static const char *Name() { return "ReduceProd"; }
33- // };
34-
35- // template <typename T>
36- // struct ReduceOperatorTrait <T, ReduceSumsquare> {
37- // static const char *Name() { return "ReduceSumsquare"; }
38- // };
39-
40- // template <typename T, ReduceOpMode Op>
41- // class ROperator_Reduce final : public ROperator
42- // {
43- // private:
44- // /* Attributes*/
45- // int fAxis = 1;
46- // ReduceOpMode fReduceMode;
47- // int fkeepdims = 1; //default value
48- // std::string fNX;
49- // std::string fNY;
50- // std::vector<size_t> fShapeX;
51- // std::vector<size_t> fShapeY;
52-
53- // public:
54-
55- // ROperator_Reduce(){}
56- // ROperator_Reduce(int keepdims,int axis,std::string nameX, std::string nameY):
57- // fkeepdims(keepdims), fAxis(axis), fNX(UTILITY::Clean_name(nameX)), fNY(UTILITY::Clean_name(nameY)) {}
58-
59- // // type of output given input
60- // std::vector<ETensorType> TypeInference(std::vector<ETensorType> input){
61- // return input;
62- // }
63-
64- // // shape of output tensors given input tensors
65- // std::vector<std::vector<size_t>> ShapeInference(std::vector<std::vector<size_t>> input){
66- // // assume now inputs have same shape (no broadcasting)
67- // auto ret = std::vector<std::vector<size_t>>(1, input[0]); // return vector size 1 with first input
68- // return ret;
69- // }
70- // void Initialize(RModel& model){
71-
72- // fUseSession = model.UseSession();
73-
74- // if (model.CheckIfTensorAlreadyExist(fNX) == false){ //input must be a graph input, or already initialized intermediate tensor
75- // throw std::runtime_error("TMVA SOFIE Reduce Op Input Tensor " + fNX + " is not found in model");
76- // }
77- // fShapeX = model.GetTensorShape(fNX);
78- // // find shape of Y and add it in the list of intermediate tensors
79- // fShapeY = ShapeInference({fShapeX})[0];
80- // model.AddIntermediateTensor(fNY, model.GetTensorType(fNX), fShapeY);
81- // }
82-
83- // std::string Generate(std::string OpName){
84- // OpName = "op_" + OpName;
85- // if (fShapeX.empty() || fShapeY.empty()) {
86- // throw std::runtime_error("TMVA SOFIE Reduce Op called to Generate without being initialized first");
87- // }
88-
89- // size_t outputLength = TMVA::Experimental::SOFIE::ConvertShapeToLength(fShapeY);
90-
91- // auto inputStrides = TMVA::Experimental::SOFIE::UTILITY::ComputeStrideFromShape(fShapeX);
92- // auto outputStrides = TMVA::Experimental::SOFIE::UTILITY::ComputeStrideFromShape(fShapeY);
93-
94- // size_t dim = fShapeY.size();
95- // std::vector<size_t> idx(dim);
96-
97- // std::stringstream out;
98- // for (size_t i = 0; i < outputLength; i++) {
99-
100- // if (dim == 2) {
101- // idx[0] = i / outputStrides[0];
102- // idx[1] = i % outputStrides[0];
103- // }
104- // if (dim == 3) {
105- // idx[0] = i / outputStrides[0];
106- // idx[1] = (i % outputStrides[0]) / outputStrides[1];
107- // idx[2] = (i % outputStrides[0]) % outputStrides[1];
108- // }
109- // if (dim == 4) {
110- // idx[0] = i / outputStrides[0];
111- // idx[1] = (i % outputStrides[0]) / outputStrides[1];
112- // idx[2] = ((i % outputStrides[0]) % outputStrides[1]) / outputStrides[2];
113- // idx[3] = ((i % outputStrides[0]) % outputStrides[1]) % outputStrides[2];
114- // }
115-
116- // assert(idx[fAxis] == 0); // we can avoid computing this for the reduction axis which by definition is always zero
117-
118- // out << SP << "float sum = 0;\n";
119- // // float sum = 0;
120- // for (size_t k = 0; k < fShapeX[fAxis]; k++) {
121- // idx[fAxis] = k;
122- // // compute input index j
123- // size_t j = 0;
124- // if (dim == 2) j = idx[0]*inputStrides[0] + idx[1];
125- // if (dim == 3) j = idx[0]*inputStrides[0] + idx[1]* inputStrides[1] + idx[2];
126- // if (dim == 4) j = idx[0]*inputStrides[0] + idx[1]* inputStrides[1] + idx[2]*inputStrides[2] + idx[3];
127-
128- // out << SP << SP << "sum += tensor_" << fNX[j] << ";\n";
129- // }
130- // out << SP << "float average = sum/float(" << fShapeX[fAxis] << ")\n;";
131- // out << SP << "tensor_" << fNY[i] << " = average;\n";
132- // }
133- // return out.str();
134- // }
135-
136- // };
137-
138- // }//SOFIE
139- // }//Experimental
140- // }//TMVA
141-
142-
143- // #endif //TMVA_SOFIE_ROPERATOR_Reduce
144-
1451#ifndef TMVA_SOFIE_ROPERATOR_Reduce
1462#define TMVA_SOFIE_ROPERATOR_Reduce
1473
@@ -160,38 +16,31 @@ namespace TMVA{
16016namespace Experimental {
16117namespace SOFIE {
16218
163- template <typename T, ReduceOpMode Op1>
164- struct ReduceOperatorTrait {
165- const char *Name () { return " " ; }
166- };
167- template <typename T>
168- struct ReduceOperatorTrait <T, ReduceMean> {
169- static const char *Name () { return " ReduceMean" ; }
170- };
19+ enum EReduceOpMode { ReduceMean, ReduceSumsquare, ReduceProd, InvalidReduceOp };
17120
172- template <typename T>
173- struct ReduceOperatorTrait <T, ReduceProd> {
174- static const char *Name () { return " ReduceProd" ; }
175- };
176-
177- template <typename T>
178- struct ReduceOperatorTrait <T, ReduceSumsquare> {
179- static const char *Name () { return " ReduceSumsquare" ; }
180- };
181-
182- template <typename T, ReduceOpMode Op>
21+ template <typename T, EReduceOpMode Op>
18322class ROperator_Reduce final : public ROperator
18423{
18524private:
18625 /* Attributes*/
18726 int fkeepdims = 1 ; // default value
27+ int fAttrAxes ;
28+ EReduceOpMode fReduceOpMode ;
18829 std::string fNX ;
18930 std::string fNY ;
19031 std::vector<size_t > fShapeX ;
19132 std::vector<size_t > fShapeY ;
192- int fAttrAxes ;
33+
19334
19435public:
36+
37+ std::string Name () {
38+ if (fReduceOpMode == ReduceMean) return " ReduceMean" ;
39+ else if (fReduceOpMode == ReduceSumsquare ) return " ReduceSumsquare" ;
40+ else if (fReduceOpMode == ReduceProd ) return " ReduceProd" ;
41+ return " Invalid" ;
42+ }
43+
19544 ROperator_Reduce (){}
19645 ROperator_Reduce (int keepdims,int attrAxes,std::string nameX, std::string nameY):
19746 fkeepdims (keepdims), fAttrAxes (attrAxes), fNX (UTILITY::Clean_name(nameX)), fNY (UTILITY::Clean_name(nameY)) {}
@@ -203,13 +52,8 @@ public:
20352
20453 // shape of output tensors given input tensors
20554 std::vector<std::vector<size_t >> ShapeInference (std::vector<std::vector<size_t >> input){
206-
207- // std::vector<std::vector<size_t>> ret;
208- // auto & input_shape = input[0];
209- // auto ret = std::vector<std::vector<size_t>>(1, input[0]); // return vector size 1 with first input
210- // return ret;
21155 auto ret = input; // suggest copy to compiler
212- ret[fAttrAxes ] = 1 ;
56+ ret[0 ][ fAttrAxes ] = 1 ;
21357 return ret;
21458 }
21559 void Initialize (RModel& model){
@@ -220,9 +64,10 @@ public:
22064 throw std::runtime_error (" TMVA SOFIE Reduce Op Input Tensor " + fNX + " is not found in model" );
22165 }
22266 fShapeX = model.GetTensorShape (fNX );
223- // find shape of Y and add it in the list of intermediate tensors
224- fShapeY = ShapeInference (fShapeX );
225- model.AddIntermediateTensor (fNY , model.GetTensorType (fNX ), fShapeY );
67+ // find shape of Y and add it in the list of intermediate tensors
68+ fShapeY = ShapeInference ({fShapeX })[0 ];
69+ model.AddIntermediateTensor (fNY , model.GetTensorType (fNX ), fShapeY );
70+
22671 }
22772
22873 std::string Generate (std::string OpName){
@@ -236,21 +81,16 @@ public:
23681 auto inputStrides = TMVA::Experimental::SOFIE::UTILITY::ComputeStrideFromShape (fShapeX );
23782 auto outputStrides = TMVA::Experimental::SOFIE::UTILITY::ComputeStrideFromShape (fShapeY );
23883
239- // write here according to size of shape
240- // in generation code can be done automatically
241- // i0 = i / s0 ; i1 = (i % s0) / s1 ; i2 = ( (i % s0) % s1 ) / s2 and so on
242- // and we have for the inverse
243- // i = i0 * s0 + i1 * s1 + i2 * s2 + i3 * s3 ....
84+ // write here according to size of shape
85+ // in generation code can be done automatically
86+ // i0 = i / s0 ; i1 = (i % s0) / s1 ; i2 = ( (i % s0) % s1 ) / s2 and so on
87+ // and we have for the inverse
88+ // i = i0 * s0 + i1 * s1 + i2 * s2 + i3 * s3 ....
24489
245- // don't need to divide by last stride s[n-1] since it is 1 by definition
90+ // don't need to divide by last stride s[n-1] since it is 1 by definition
24691
24792 std::stringstream out;
248- out << " \n //---- operator " << std::string (ReduceOperatorTrait<T,Op>::Name ()) << " " << OpName << " \n " ;
249- out << SP << " size_t dim = " << fShapeY .size () << " ;\n " ;
250-
251- out << SP << " std::vector<size_t> idx(dim);" ;
252-
253-
93+ out << " \n //---- operator " << Name () << " " << OpName << " \n " ;
25494 out << SP << " for (size_t i = 0; i < " << outputLength << " ; i++) {\n " ;
25595
25696 // write here according to size of shape
@@ -260,30 +100,63 @@ public:
260100 // i = i0 * s0 + i1 * s1 + i2 * s2 + i3 * s3 ....
261101
262102 // don't need to divide by last stride s[n-1] since it is 1 by definition
103+
104+ size_t dim = fShapeX .size (); // this is the input dimension (e.g. 2, 3 or 4 or more)
105+ out << SP << " std::vector<size_t> outputStrides = {" ;
106+ for (size_t k = 0 ; k < dim; k++) {
107+ out << outputStrides[k] ;
108+ if (k < dim-1 )
109+ out << " ," ;
110+ else
111+ out << " };\n " ;
112+ }
113+ // no compute indices as function of strides
114+ // as in the example I have sent you
263115
264- out << SP << SP << " idx[j] = i;\n " ;
265- out << SP << SP << " size_t k = 0;\n " ;
266- out << SP << SP << SP << " for(k=0; k < dim-1; k++){\n " ;
267- out << SP << SP << SP << " idx[k] = idx[k] %" << outputStrides << " [k];\n " ;
268- out << SP << SP << SP << " };\n " ;
269- out << SP << SP << " idx[j] = idx[j] /" << outputStrides << " [k];\n " ;
270-
116+ for (size_t k = 0 ; k < dim; k++) {
117+ size_t j;
118+ out << SP << " size_t idx_" << k <<" = i;\n " ;
119+ for (j = 0 ; j < k; j++ )
120+ out << SP << " idx_" << k << " = idx_" << k <<" % outputStrides[" << j << " ];\n " ;
271121
272- out << SP << " assert(idx[" << fAttrAxes << " ] == 0);\n " ; // we can avoid computing this for the reduction axis which by definition is always zero
122+ out << SP << " idx_" << k << " = idx_" << k << " / outputStrides[" << j << " ];\n " ;
123+ }
124+
125+ // out << SP << "assert(idx[" << fAttrAxes << "] == 0);\n"; // we can avoid computing this for the reduction axis which by definition is always zero
273126
274127 out << SP << " float sum = 0;\n " ;
275- out << SP << SP << " for (size_t k = 0; k < inputShape[ " << fAttrAxes << " ] ; k++) { \n " ;
276- out << SP << SP << " idx[ " << fAttrAxes << " ] = k;\n " ;
128+ out << SP << SP << " for (size_t k = 0; k < " << fShapeX [ fAttrAxes ] <<" ; k++) { \n " ;
129+ out << SP << SP << " idx_ " << fAttrAxes << " = k;\n " ;
277130 // compute input index j
131+ out << SP << " std::vector<size_t> inputStrides = {" ;
132+ for (size_t k = 0 ; k < dim; k++) {
133+ out << inputStrides[k] ;
134+ if (k < dim-1 )
135+ out << " ," ;
136+ else
137+ out << " };\n " ;
138+ }
278139 out << SP << SP << " size_t l = 0;\n " ;
279- out << SP << SP << " size_t m = 0;\n " ;
280- out << SP << SP << SP << " for(m=0; m < dim-1; m++){\n " ;
281- out << SP << SP << SP << " l += idx[m] *" << inputStrides << " [m];\n " ;
282- out << SP << SP << SP << " };\n " ;
283- out << SP << SP << " l += idx[m];\n " ;
284- out << SP << SP << " sum += tensor_" << fNX << " [l];\n " ;
285- out << SP << SP << " };\n " ;
286- out << SP << SP << " float average = sum/float(inputShape[" << fAttrAxes << " ]);\n " ;
140+ for (size_t m = 0 ; m < dim; m++) {
141+ size_t n;
142+ for (n = 0 ; n < m; n++ )
143+ out << SP << " l += idx_" << n << " * inputStrides[" << n << " ];\n " ;
144+
145+ out << SP << " l += idx_" << m << " ;\n " ;
146+ }
147+ if (fReduceOpMode == ReduceMean){
148+ out << SP << SP << " sum += tensor_" << fNX << " [l];\n " ;
149+ out << SP << SP << " };\n " ;
150+ }
151+ else if (fReduceOpMode == ReduceSumsquare){
152+ out << SP << SP << " sum += tensor_" << fNX << " [l] * tensor_" << fNX << " [l];\n " ;
153+ out << SP << SP << " };\n " ;
154+ }
155+ else if (fReduceOpMode == ReduceProd){
156+ out << SP << SP << " sum *= tensor_" << fNX << " [l];\n " ;
157+ out << SP << SP << " };\n " ;
158+ }
159+ out << SP << SP << " float average = sum/(float)" << fShapeX [fAttrAxes ] << " ;\n " ;
287160 out << SP << SP << " tensor_" << fNY << " [i] = average;\n " ;
288161 out << SP << " };\n " ;
289162 out << SP << " }\n " ;
0 commit comments