Skip to content

Commit b7bef8e

Browse files
committed
Made the required changes according the expected generated code and shape in the Reduce Operator
1 parent a0f2f3d commit b7bef8e

File tree

3 files changed

+90
-205
lines changed

3 files changed

+90
-205
lines changed

tmva/sofie/inc/TMVA/ROperator_Reduce.hxx

Lines changed: 76 additions & 203 deletions
Original file line numberDiff line numberDiff line change
@@ -1,147 +1,3 @@
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{
16016
namespace Experimental{
16117
namespace 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>
18322
class ROperator_Reduce final : public ROperator
18423
{
18524
private:
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

19435
public:
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";

tmva/sofie_parsers/inc/TMVA/RModelParser_ONNX.hxx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ std::unique_ptr<ROperator> make_ROperator_Identity(const onnx::NodeProto &nodepr
4747
std::unique_ptr<ROperator> make_ROperator_Softmax(const onnx::NodeProto &nodeproto, const onnx::GraphProto &graphproto, std::unordered_map<std::string, ETensorType> &tensor_type);
4848
std::unique_ptr<ROperator> make_ROperator_Concat(const onnx::NodeProto &nodeproto, const onnx::GraphProto &graphproto, std::unordered_map<std::string, ETensorType> &tensor_type);
4949
std::unique_ptr<ROperator> make_ROperator_Cast(const onnx::NodeProto &nodeproto, const onnx::GraphProto &graphproto, std::unordered_map<std::string, ETensorType> &tensor_type);
50+
template <EReduceOpMode Op1>
5051
std::unique_ptr<ROperator> make_ROperator_Reduce(const onnx::NodeProto &nodeproto, const onnx::GraphProto &graphproto, std::unordered_map<std::string, ETensorType> &tensor_type);
5152

5253
using factoryMethodMap = std::unordered_map<std::string, std::unique_ptr<ROperator> (*)(const onnx::NodeProto&, const onnx::GraphProto&, std::unordered_map<std::string, ETensorType>&)>;

tmva/sofie_parsers/src/RModelParser_ONNX.cxx

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,12 +116,23 @@ std::unique_ptr<ROperator> make_ROperator_Neg(const onnx::NodeProto& nodeproto,
116116
return op;
117117
}
118118

119-
template<ReduceOpMode Op1>
119+
template<EReduceOpMode Op1>
120120
std::unique_ptr<ROperator> make_ROperator_Reduce(const onnx::NodeProto& nodeproto, const onnx::GraphProto& /*graphproto*/, std::unordered_map<std::string, ETensorType>& tensor_type){
121121

122122
ETensorType input_type;
123123

124-
auto input_name = nodeproto.input(0);
124+
EReduceOpMode op_mode = InvalidReduceOp;
125+
126+
if (nodeproto.op_type() == "ReduceMean")
127+
op_mode = ReduceMean;
128+
else if (nodeproto.op_type() == "ReduceSumsquare")
129+
op_mode = ReduceSumsquare;
130+
else if (nodeproto.op_type() == "ReduceProd")
131+
op_mode = ReduceProd;
132+
133+
assert(op_mode != InvalidReduceOp);
134+
135+
auto input_name = nodeproto.input(0);
125136
auto it = tensor_type.find(input_name);
126137
if (it != tensor_type.end()){
127138
input_type = it->second;

0 commit comments

Comments
 (0)