Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
ROperator_Reduce.hxx
Go to the documentation of this file.
1#ifndef TMVA_SOFIE_ROPERATOR_Reduce
2#define TMVA_SOFIE_ROPERATOR_Reduce
3
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
15namespace TMVA{
16namespace Experimental{
17namespace SOFIE{
18
20
21template <typename T, EReduceOpMode Op>
22class ROperator_Reduce final : public ROperator
23{
24private:
25 /* Attributes*/
26 int fkeepdims = 1; //default value
29 std::string fNX;
30 std::string fNY;
31 std::vector<size_t> fShapeX;
32 std::vector<size_t> fShapeY;
33
34
35public:
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
45 ROperator_Reduce(int keepdims,int attrAxes,std::string nameX, std::string nameY):
46 fkeepdims(keepdims), fAttrAxes(attrAxes), fNX(UTILITY::Clean_name(nameX)), fNY(UTILITY::Clean_name(nameY)) {
47 fReduceOpMode = Op;
48 }
49
50 // type of output given input
51 std::vector<ETensorType> TypeInference(std::vector<ETensorType> input){
52 return input;
53 }
54
55 // shape of output tensors given input tensors
56 std::vector<std::vector<size_t>> ShapeInference(std::vector<std::vector<size_t>> input){
57 auto ret = input; //suggest copy to compiler
58 ret[0][fAttrAxes] = 1;
59 return ret;
60 }
61 void Initialize(RModel& model){
62
63 fUseSession = model.UseSession();
64
65 if (model.CheckIfTensorAlreadyExist(fNX) == false){ //input must be a graph input, or already initialized intermediate tensor
66 throw std::runtime_error("TMVA SOFIE Reduce Op Input Tensor " + fNX + " is not found in model");
67 }
68 fShapeX = model.GetTensorShape(fNX);
69 // find shape of Y and add it in the list of intermediate tensors
72
73 }
74
75 std::string Generate(std::string OpName){
76 OpName = "op_" + OpName;
77 if (fShapeX.empty() || fShapeY.empty()) {
78 throw std::runtime_error("TMVA SOFIE Reduce Op called to Generate without being initialized first");
79 }
80
82
85
86 // write here according to size of shape
87 // in generation code can be done automatically
88 // i0 = i / s0 ; i1 = (i % s0) / s1 ; i2 = ( (i % s0) % s1 ) / s2 and so on
89 // and we have for the inverse
90 // i = i0 * s0 + i1 * s1 + i2 * s2 + i3 * s3 ....
91
92 // don't need to divide by last stride s[n-1] since it is 1 by definition
93
94 std::stringstream out;
95 out << "\n//---- operator " << Name() << " " << OpName << "\n";
96 out << SP << "for (size_t i = 0; i < " << outputLength << "; i++) {\n";
97
98 size_t dim = fShapeX.size(); // this is the input dimension (e.g. 2, 3 or 4 or more)
99
100 // here we find output indices
101 out << SP << SP << "size_t idx_0 = i / " << outputStrides[0] << ";\n" ;
102 out << SP << SP << "size_t itmp = i;\n";
103 for (size_t k = 1; k < dim; k++) {
104 out << SP << SP << "itmp = itmp % " << outputStrides[k-1] << ";\n" ;
105 if (k < dim-1)
106 out << SP << SP << "size_t idx_" << k << " = itmp / " << outputStrides[k] << ";\n" ;
107 else
108 // to avoid division by 1 which is outputStrides[dim-1]
109 out << SP << SP << "size_t idx_" << k << " = itmp;\n";
110 }
111
112 // compute reduction
113
115 out << SP << SP << "float sum = 1;\n";
116 else
117 out << SP << SP << "float sum = 0;\n";
118
119 out << SP << SP << "for (size_t k = 0; k < " << fShapeX[fAttrAxes] <<"; k++) { \n";
120 out << SP << SP << SP << "idx_" << fAttrAxes << " = k;\n";
121 // compute input index j
122 out << SP << SP << SP << "size_t l = ";
123 for(int n = dim-1; n >=0; n--) {
124 if (n == int(dim-1))
125 out << "idx_" << n;
126 else
127 out << " + " << "idx_" << n << " * " << inputStrides[n];
128 }
129 out << ";\n";
130
132 out << SP << SP << SP << "sum += tensor_" << fNX << "[l];\n";
133 out << SP << SP << "}\n";
134 out << SP << SP << "float reduceResult = sum/static_cast<float>(" << fShapeX[fAttrAxes] << ");\n";
135 }
136 else if(fReduceOpMode == ReduceSumsquare){
137 out << SP << SP << SP << "sum += tensor_" << fNX << "[l] * tensor_" << fNX << "[l];\n";
138 out << SP << SP << "}\n";
139 out << SP << SP << "float reduceResult = sum;\n";
140 }
141 else if(fReduceOpMode == ReduceProd){
142 out << SP << SP << SP << "sum *= tensor_" << fNX << "[l];\n";
143 out << SP << SP << "}\n";
144 out << SP << SP << "float reduceResult = sum;\n";
145 }
146
147 out << SP << SP << "tensor_" << fNY << "[i] = reduceResult;\n";
148 out << SP << "}\n";
149 return out.str();
150 }
151
152};
153
154}//SOFIE
155}//Experimental
156}//TMVA
157
158
159#endif //TMVA_SOFIE_ROPERATOR_Reduce
160
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void input
const ETensorType & GetTensorType(std::string name)
Definition RModel.cxx:80
void AddIntermediateTensor(std::string tensor_name, ETensorType type, std::vector< std::size_t > shape)
Definition RModel.cxx:160
bool CheckIfTensorAlreadyExist(std::string tensor_name)
Definition RModel.cxx:101
const std::vector< size_t > & GetTensorShape(std::string name)
Definition RModel.cxx:59
ROperator_Reduce(int keepdims, int attrAxes, std::string nameX, std::string nameY)
std::string Generate(std::string OpName)
std::vector< std::vector< size_t > > ShapeInference(std::vector< std::vector< size_t > > input)
std::vector< ETensorType > TypeInference(std::vector< ETensorType > input)
const std::string SP
space used to correctly indent the generated C++ code
Definition ROperator.hxx:41
bool fUseSession
flag to identify if using the session class
Definition ROperator.hxx:42
const Int_t n
Definition legend1.C:16
std::vector< size_t > ComputeStrideFromShape(const std::vector< size_t > &shape)
compute stride of a tensor given its shape (assume layout is row-major)
std::size_t ConvertShapeToLength(std::vector< size_t > shape)
create variable transformations