Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
ROperator_Pool.hxx
Go to the documentation of this file.
1#ifndef TMVA_SOFIE_ROPERATOR_POOL
2#define TMVA_SOFIE_ROPERATOR_POOL
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 // structure that contains Pool attribute
21 std::string auto_pad = "NOTSET";
22 int ceil_mode = 0;
23 int count_include_pad = 0; // not for MaxPool
24 int storage_order = 0; // not for AveragePool
25 std::vector<size_t> dilations; // not for AveragePool
26 std::vector<size_t> kernel_shape;
27 std::vector<size_t> pads;
28 std::vector<size_t> strides;
29};
30
32
33template<typename T>
34class ROperator_Pool final : public ROperator
35{
36
37private:
38
40
44 std::string fAttrAutopad;
45 std::vector<size_t> fAttrDilations;
46 std::vector<size_t> fAttrKernelShape;
47 std::vector<size_t> fAttrPads;
48 std::vector<size_t> fAttrStrides;
49
50 std::string fNX;
51 std::string fNY;
52
53 std::vector<size_t> fShapeX;
54 std::vector<size_t> fShapeY;
55
56 std::string fType;
57
58 size_t fDim; // dimension of the MaxPool
59 bool fUseSession = false;
60
61public:
62
63 std::string Name() {
64 if (fPoolMode == AveragePool) return "AveragePool";
65 if (fPoolMode == MaxPool) return "MaxPool";
66 return "Invalid";
67 }
68
70
71 ROperator_Pool(PoolOpMode mode, RAttributes_Pool attr, std::string nameX, std::string nameY)
72 : fPoolMode(mode), fAttrCeilMode(attr.ceil_mode), fAttrCountIncludePad(attr.count_include_pad),
73 fAttrStorageOrder(attr.storage_order), fAttrAutopad(attr.auto_pad),
74 fAttrDilations(attr.dilations), fAttrKernelShape(attr.kernel_shape), fAttrPads(attr.pads), fAttrStrides(attr.strides),
75 fNX(UTILITY::Clean_name(nameX)), fNY(UTILITY::Clean_name(nameY))
76 {
77 if(std::is_same<T, float>::value) {
78 fType = "float";
79 } else {
80 throw
81 std::runtime_error("TMVA SOFIE Encountered unsupported type parsing a Pool operator");
82 }
83 }
84
85 // return input type (defined abstract in ROperator class )
86 std::vector<ETensorType> TypeInference(std::vector<ETensorType> input) {
87 // only one input in Pool operators
88 return input;
89 }
90
91 // function returning output shape given input
92 std::vector<std::vector<size_t>> ShapeInference(std::vector<std::vector<size_t>> input) {
93 // shape of pooling input has to be (according to ONNX): NxCxHxW
94 // Where N is batch size, C : input channels, H : input height, W = input width
95 // or it can be [N, C, F1,F2,....FN] . Minimum dimension is 3
96 if (input.size() != 1 ) {
97 throw std::runtime_error("TMVA SOFIE" + Name() + "Op Shape inference need 1 input tensor");
98 }
99 if (input[0].size() < 3) {
100 throw std::runtime_error("TMVA SOFIE" + Name() + "Op Shape inference only accept tensor with at least 3 dimensions");
101 }
102 // support only input tensors with dim = 3,4,5
103 if (input[0].size() < 3 || input[0].size() > 5) {
104 throw std::runtime_error("TMVA SOFIE" + Name() + "Op : tensors with dimension " + std::to_string(input[0].size()) + " are not yet supported");
105 }
106
107 if (input[0].size() -2 != fDim) {
108 throw
109 std::runtime_error("TMVA SOFIE Pool Op Shape inference - invalid inputs ");
110 }
111 // kernel shape
112 size_t k1 = ((fAttrKernelShape.empty())? input[0][2] : fAttrKernelShape[0]);
113 size_t k2 = (fDim > 1) ? ((fAttrKernelShape.empty()) ? input[0][3] : fAttrKernelShape[1]) : 1;
114 size_t k3 = (fDim > 2) ? ((fAttrKernelShape.empty()) ? input[0][4] : fAttrKernelShape[2]) : 1;
115
116
117 size_t i1 = (fDim > 1) ? ((fDim > 2) ? 3 : 2) : 1;
118 size_t i2 = (fDim > 2) ? 4 : 3;
119 size_t i3 = 5;
120
121 if (fAttrDilations.empty()) {
122 fAttrDilations = {1, 1, 1};
123 }
124 fAttrDilations.resize(3);
125 if (fDim < 3) {
126 fAttrDilations.resize(3, 1);
127 }
128 // Shape of the kernel
129 fAttrKernelShape = {k1 + (fAttrDilations[0] - 1) * (k1 - 1),
130 k2 + (fAttrDilations[1] - 1) * (k2 - 1),
131 k3 + (fAttrDilations[2] - 1) * (k3 - 1)};
132
133 if (fAttrAutopad == "NOTSET") {
134 // in auto_pad is NOTSET then fAttrPads should have been set or default zero is used
135 if (fAttrPads.empty()) {
136 fAttrPads = {0, 0, 0, 0, 0, 0};
137 }
138 } else if (fAttrAutopad == "SAME_UPPER" || fAttrAutopad == "SAME_LOWER") {
139 if (fDim == 1)
141 else if (fDim == 2)
143 else if (fDim == 3)
145 fAttrKernelShape[0] / 2, fAttrKernelShape[1] / 2, fAttrKernelShape[2] / 2};
146 // add extra padding at beginning or end (depending if SAME_UPPER or SAME_LOWER)
147 // need to check this!
148 if (fAttrKernelShape[0] % 2 == 1) {
149 (fAttrAutopad == "SAME_UPPER") ? fAttrPads[0]++ : fAttrPads[i1]++;
150 }
151 if (fDim > 1 && fAttrKernelShape[1] % 2 == 1) {
152 (fAttrAutopad == "SAME_UPPER") ? fAttrPads[1]++ : fAttrPads[i2]++;
153 }
154 if (fDim > 2 && fAttrKernelShape[2] % 2 == 1) {
155 (fAttrAutopad == "SAME_UPPER") ? fAttrPads[2]++ : fAttrPads[i3]++;
156 }
157 } else if (fAttrAutopad != "VALID") {
158 throw
159 std::runtime_error("TMVA SOFIE" + Name() + "Op invalid Autopad value : " + fAttrAutopad);
160 }
161 // to be sure pad is vector of size 6
162 if (fDim < 3) fAttrPads.resize(6, 0);
163
164 if (fAttrStrides.empty()) {
165 fAttrStrides = {1, 1, 1};
166 }
167
168 if (fDim < 3)
169 fAttrStrides.resize(3, 1);
170
171 size_t input1 = input[0][2];
172 size_t input2 = (fDim > 1) ? input[0][3] : 1;
173 size_t input3 = (fDim > 2) ? input[0][4] : 1;
174
175 size_t pad1 = fAttrPads[0] + fAttrPads[i1];
176 size_t output1 = (input1 + pad1 - fAttrKernelShape[0]) / fAttrStrides[0] + 1;
177
178 size_t batch_size = input[0][0]; // first element in input tensor
179 size_t output_channels = input[0][1]; // first element in output tensor
180
181 std::vector<std::vector<size_t>> ret({{ batch_size, output_channels, output1 }});
182
183 if (fDim == 1)
184 return ret;
185
186 size_t pad2 = fAttrPads[1] + fAttrPads[i2];
187 size_t output2 = (input2 + pad2 - fAttrKernelShape[1]) / fAttrStrides[1] + 1;
188 // output is N x C x OH x OW
189 ret[0].push_back(output2);
190 if (fDim == 2)
191 return ret;
192
193 size_t pad3 = fAttrPads[2] + fAttrPads[i3];
194 size_t output3 = (input3 + pad3 - fAttrKernelShape[2] ) / fAttrStrides[2] + 1;
195
196 // output is N x C x OH x OW x OD
197 ret[0].push_back(output3);
198 return ret;
199 }
200
201 void Initialize(RModel& model) {
202
203 fUseSession = model.UseSession();
204
205 if (!model.CheckIfTensorAlreadyExist(fNX)) {
206 throw
207 std::runtime_error("TMVA SOFIE Pool op Input Tensor " + fNX + " is not found in model");
208 }
209 fShapeX = model.GetTensorShape(fNX);
210 if (fShapeX.size() < 3 || fShapeX.size() > 5) {
211 std::cout << fNX << " : " << ConvertShapeToString(fShapeX) << std::endl;
212 throw
213 std::runtime_error("TMVA SOFIE Pool Op input data tensor" + fNX + " is not of 3,4 or 5 dimensions");
214 }
215 fDim = fShapeX.size() - 2;
216 // case of GlobalAveragePool. It is a pool case with kernel shape == image shape
219 fAttrKernelShape.resize(3);
221 if (fDim > 1)
223 if (fDim > 2)
225 fAttrAutopad = "VALID";
226 fAttrPads = {0, 0, 0, 0, 0, 0 };
227 assert(fAttrStrides.empty());
228 }
229 // find shape of Y and add it in the list of intermediate tensors
232
233 // need cmath for INFINITY when using MaxPool
234 if (fPoolMode == MaxPool) model.AddNeededStdLib("cmath");
235
236 }
237
238 std::string GenerateInitCode() {
239 std::stringstream out;
240 return out.str();
241 }
242
243 // generate code for Session data members (e.g. internal vectors)
244 virtual std::string GenerateSessionMembersCode(std::string opName)
245 {
246 opName = "op_" + opName;
247 std::stringstream out;
248 // input matrix padded with zero
249 if(fDim == 1){
250 out << "std::vector<" << fType << "> fVec_" << opName << "_xpad = std::vector<" << fType << ">("
251 << fShapeX[1] * (fShapeX[2] + fAttrPads[0] + fAttrPads[2]) << ");\n";
252 }
253 else if(fDim == 2){
254 out << "std::vector<" << fType << "> fVec_" << opName << "_xpad = std::vector<" << fType << ">("
255 << fShapeX[1] * (fShapeX[2] + fAttrPads[0] + fAttrPads[2]) * (fShapeX[3] + fAttrPads[1] + fAttrPads[3])
256 << ");\n";
257 }
258 else{ //dim is 3D
259 out << "std::vector<" << fType << "> fVec_" << opName << "_xpad = std::vector<" << fType << ">("
260 << fShapeX[1] * (fShapeX[2] + fAttrPads[0] + fAttrPads[2]) * (fShapeX[3] + fAttrPads[1] + fAttrPads[3]) *
261 (fShapeX[4] + fAttrPads[2] + fAttrPads[4]) << ");\n";
262 }
263
264 return out.str();
265 }
266
267 std::string Generate(std::string OpName) {
268 OpName = "op_" + OpName;
269
270 if (fShapeX.empty() || fShapeY.empty()) {
271 throw std::runtime_error("TMVA SOFIE Pool Op called to Generate without being initialized first");
272 }
273
274 std::stringstream out;
275
276 out << "\n//---- operator " << Name() << " " << OpName << "\n";
277 out << "{\n"; // create a new scope to avoid name clash
278
279 assert(fShapeX[0] == fShapeY[0]);
280 assert(fShapeX[1] == fShapeY[1]);
281 assert(fAttrPads.size() == 6);
282 assert(fAttrKernelShape.size() == 3);
283 // find lower bounds of filtered area
284 int hmin = - fAttrPads[0]; // minimum lower bound value of filter area
285 int hmax = fShapeX[2] + fAttrPads[1] - fAttrKernelShape[0] +1; // maximum lower bound value + 1
286 int wmin,wmax,dmin,dmax;
287
288 if(fDim >= 2){
289 wmin = - fAttrPads[2]; // minimum lower bound value of filter area
290 wmax = fShapeX[3] + fAttrPads[3] - fAttrKernelShape[1] +1; // maximum lower bound value + 1
291 }
292 else{
293 wmin=1;
294 wmax=1;
295 }
296 if(fDim == 3){
297 dmin = - fAttrPads[4]; // minimum lower bound value of filter area
298 dmax = fShapeX[4] + fAttrPads[5] - fAttrKernelShape[2] +1; // maximum lower bound value + 1
299 }
300 else{
301 dmin=1;
302 dmax=1;
303 }
304 out << SP << "constexpr int hsize = " << fShapeX[2] << ";\n";
305 out << SP << "constexpr int hmin = " << hmin << ";\n";
306 out << SP << "constexpr int hmax = " << hmax << ";\n";
307 out << SP << "constexpr int kh = " << fAttrKernelShape[0] << ";\n";
308 if (fDim > 1) {
309 size_t wsize = fShapeX[3];
310 out << SP << "constexpr int wsize = " << wsize << ";\n";
311 out << SP << "constexpr int wmin = " << wmin << ";\n";
312 out << SP << "constexpr int wmax = " << wmax << ";\n";
313 out << SP << "constexpr int kw = " << fAttrKernelShape[1] << ";\n";
314 if (fDim > 2) {
315 size_t dsize = fShapeX[4];
316 out << SP << "constexpr int dsize = " << dsize << ";\n";
317 out << SP << "constexpr int dwsize = " << dsize*wsize << ";\n"; // hstride
318 out << SP << "constexpr int dmin = " << dmin << ";\n";
319 out << SP << "constexpr int dmax = " << dmax << ";\n";
320 out << SP << "constexpr int kd = " << fAttrKernelShape[2] << ";\n";
321 }
322 }
323
324
325 bool doPadding = false;
326 for ( auto & e : fAttrPads)
327 doPadding |= (e > 0);
328
329
330 if(fDim==1){
331 // loop on batches and channels
332 out << SP << "size_t outIndex = 0;\n";
333 out << SP << "for (size_t n = 0; n < " << fShapeX[0]*fShapeX[1] << "; n++) {\n";
334 out << SP << SP << "size_t inputOffset = n*" << fShapeX[2] << ";\n";
335 out << SP << SP << "for (int i = hmin; i < hmax; i+=" << fAttrStrides[0] << ") {\n";
336 // loop on elements of filter region to compute maximum
337 if (fPoolMode == MaxPool)
338 out << SP << SP << SP << SP << "float value = -INFINITY;\n";
339 else if (fPoolMode == AveragePool) {
340 out << SP << SP << SP << SP << "float value = 0;\n";
341 if (fAttrCountIncludePad == 0 && doPadding)
342 out << SP << SP << SP << SP << "int nsum = 0;\n";
343 else // in case we count the pad values in average
344 out << SP << SP << SP << SP << "constexpr int nsum = kh;\n";
345 }
346 // loop on rows of filtered region
347 out << SP << SP << SP << SP << "for (int l = i; l < i + kh; l++) {\n";
348 out << SP << SP << SP << SP << SP << "if (l < 0 || l >= hsize) continue;\n";
349 out << SP << SP << SP << SP << SP << SP << "int index = inputOffset + l;\n";
350 if (fPoolMode == MaxPool) {
351 out << SP << SP << SP << SP << SP << SP << "auto xval = tensor_" << fNX << "[index];\n";
352 out << SP << SP << SP << SP << SP << SP << "if (xval > value) value = xval;\n";
353 }
354 else if (fPoolMode == AveragePool) {
355 // compute sum of values
356 out << SP << SP << SP << SP << SP << SP << "value += tensor_" << fNX << "[index];\n";
357 if (fAttrCountIncludePad == 0 && doPadding)
358 // compute number of elements used for the average
359 out << SP << SP << SP << SP << SP << SP << "nsum++;\n";
360 }
361 out << SP << SP << SP << SP << SP << "}\n"; // end loop on region elements
362 if (fPoolMode == AveragePool) {
363 // compute average
364 out << SP << SP << SP << SP << "value /= float(nsum);\n";
365 }
366
367 out << SP << SP << SP << SP << "tensor_" << fNY << "[outIndex++] = value;\n";
368
369 out << SP << SP << "}\n"; // end loop on i (image rows)
370 out << SP << "}\n"; // end loop on c*b
371 }
372 else if(fDim==2){
373 // loop on batches and channels
374 out << SP << "size_t outIndex = 0;\n";
375 out << SP << "for (size_t n = 0; n < " << fShapeX[0]*fShapeX[1] << "; n++) {\n";
376 out << SP << SP << "size_t inputOffset = n*" << fShapeX[2]*fShapeX[3] << ";\n";
377 out << SP << SP << "for (int i = hmin; i < hmax; i+=" << fAttrStrides[0] << ") {\n";
378 out << SP << SP << SP << "for (int j = wmin; j < wmax; j+=" << fAttrStrides[1] << ") {\n";
379 // loop on elements of filter region to compute maximum
380 if (fPoolMode == MaxPool)
381 out << SP << SP << SP << SP << "float value = -INFINITY;\n";
382 else if (fPoolMode == AveragePool) {
383 out << SP << SP << SP << SP << "float value = 0;\n";
384 if (fAttrCountIncludePad == 0 && doPadding)
385 out << SP << SP << SP << SP << "int nsum = 0;\n";
386 else // in case we count the pad values in average
387 out << SP << SP << SP << SP << "constexpr int nsum = kw*kh;\n";
388 }
389 // loop on rows of filtered region
390 out << SP << SP << SP << SP << "for (int l = i; l < i + kh; l++) {\n";
391 out << SP << SP << SP << SP << SP << "if (l < 0 || l >= hsize) continue;\n";
392 // loop on columns of filtered region
393 out << SP << SP << SP << SP << SP << "for (int m = j; m < j + kw; m++) {\n";
394 out << SP << SP << SP << SP << SP << SP << "if (m < 0 || m >= wsize) continue;\n";
395 out << SP << SP << SP << SP << SP << SP << SP << "int index = inputOffset + l*wsize + m;\n";
396 if (fPoolMode == MaxPool) {
397 out << SP << SP << SP << SP << SP << SP << SP << "auto xval = tensor_" << fNX << "[index];\n";
398 out << SP << SP << SP << SP << SP << SP << SP << "if (xval > value) value = xval;\n";
399 }
400 else if (fPoolMode == AveragePool) {
401 // compute sum of values
402 out << SP << SP << SP << SP << SP << SP << SP << "value += tensor_" << fNX << "[index];\n";
403 if (fAttrCountIncludePad == 0 && doPadding)
404 // compute number of elements used for the average
405 out << SP << SP << SP << SP << SP << SP << SP << "nsum++;\n";
406 }
407 out << SP << SP << SP << SP << SP << SP << "}\n";
408 out << SP << SP << SP << SP << SP << "}\n"; // end loop on region elements
409 if (fPoolMode == AveragePool) {
410 // compute average
411 out << SP << SP << SP << SP << "value /= float(nsum);\n";
412 }
413 out << SP << SP << SP << SP << "tensor_" << fNY << "[outIndex++] = value;\n";
414 out << SP << SP << SP << "}\n"; // end loop on j (columns of image)
415 out << SP << SP << "}\n"; // end loop on i (image rows)
416 out << SP << "}\n"; // end loop on c*b
417 }
418 else if(fDim==3){
419 // loop on batches and channels
420 out << SP << "size_t outIndex = 0;\n";
421 out << SP << "for (size_t n = 0; n < " << fShapeX[0]*fShapeX[1] << "; n++) {\n";
422 out << SP << SP << "size_t inputOffset = n*" << fShapeX[2]*fShapeX[3]*fShapeX[4] << ";\n";
423 out << SP << SP << "for (int i = hmin; i < hmax; i+=" << fAttrStrides[0] << ") {\n";
424 out << SP << SP << SP << "for (int j = wmin; j < wmax; j+=" << fAttrStrides[1] << ") {\n";
425 out << SP << SP << SP << SP << "for (int k = dmin; k < dmax; k+=" << fAttrStrides[2] << ") {\n";
426 // loop on elements of filter region to compute maximum
427 if (fPoolMode == MaxPool)
428 out << SP << SP << SP << SP << "float value = -INFINITY;\n";
429 else if (fPoolMode == AveragePool) {
430 out << SP << SP << SP << SP << "float value = 0;\n";
431 if (fAttrCountIncludePad == 0 && doPadding)
432 out << SP << SP << SP << SP << "int nsum = 0;\n";
433 else // in case we count the pad values in average
434 out << SP << SP << SP << SP << "constexpr int nsum = kw*kh*kd;\n";
435 }
436 // loop on rows of filtered region
437 out << SP << SP << SP << SP << "for (int l = i; l < i + kh; l++) {\n";
438 out << SP << SP << SP << SP << SP << "if (l < 0 || l >= hsize) continue;\n";
439 // loop on columns of filtered region
440 out << SP << SP << SP << SP << SP << "for (int m = j; m < j + kw; m++) {\n";
441 out << SP << SP << SP << SP << SP << SP << "if (m < 0 || m >= wsize) continue;\n";
442 // loop on layers of filtered region
443 out << SP << SP << SP << SP << SP << SP << "for (int p = k; p < k + kd; p++) {\n";
444 out << SP << SP << SP << SP << SP << SP << SP << "if (p < 0 || p >= dsize) continue;\n";
445 out << SP << SP << SP << SP << SP << SP << SP << SP << "int index = inputOffset + l*dwsize + m*dsize + p;\n";
446
447 if (fPoolMode == MaxPool) {
448 out << SP << SP << SP << SP << SP << SP << SP << SP << "auto xval = tensor_" << fNX << "[index];\n";
449 out << SP << SP << SP << SP << SP << SP << SP << SP << "if (xval > value) value = xval;\n";
450 }
451 else if (fPoolMode == AveragePool) {
452 // compute sum of values
453 out << SP << SP << SP << SP << SP << SP << SP << SP << "value += tensor_" << fNX << "[index];\n";
454 if (fAttrCountIncludePad == 0 && doPadding)
455 // compute number of elements used for the average
456 out << SP << SP << SP << SP << SP << SP << SP << SP << "nsum++;\n";
457 }
458 out << SP << SP << SP << SP << SP << SP << "}\n";
459 out << SP << SP << SP << SP << SP << "}\n";
460 out << SP << SP << SP << SP << "}\n"; // end loop on region elements
461 if (fPoolMode == AveragePool) {
462 // compute average
463 out << SP << SP << SP << SP << "value /= float(nsum);\n";
464 }
465
466 out << SP << SP << SP << SP << "tensor_" << fNY << "[outIndex++] = value;\n";
467 out << SP << SP << SP << SP << "}\n" ; // end loop on k (layers of image)
468 out << SP << SP << SP << "}\n"; // end loop on j (columns of image)
469 out << SP << SP << "}\n"; // end loop on i (image rows)
470 out << SP << "}\n"; // end loop on c*b
471 }
472 // end scope
473 out << SP << "}\n";
474
475
476 return out.str();
477 }
478};
479
480} // namespace SOFIE
481} // namespace Experimental
482} // namespace TMVA
483
484
485#endif
#define e(i)
Definition RSha256.hxx:103
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void input
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t hmin
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t hmax
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t wmin
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t attr
Option_t Option_t TPoint TPoint const char mode
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t wmax
void AddNeededStdLib(std::string libname)
const ETensorType & GetTensorType(std::string name)
Definition RModel.cxx:91
void AddIntermediateTensor(std::string tensor_name, ETensorType type, std::vector< Dim > dim_shape)
Definition RModel.cxx:187
bool CheckIfTensorAlreadyExist(std::string tensor_name)
Definition RModel.cxx:116
const std::vector< size_t > & GetTensorShape(std::string name)
Definition RModel.cxx:56
std::string Generate(std::string OpName)
std::vector< ETensorType > TypeInference(std::vector< ETensorType > input)
std::vector< std::vector< size_t > > ShapeInference(std::vector< std::vector< size_t > > input)
virtual std::string GenerateSessionMembersCode(std::string opName)
ROperator_Pool(PoolOpMode mode, RAttributes_Pool attr, std::string nameX, std::string nameY)
const std::string SP
space used to correctly indent the generated C++ code
Definition ROperator.hxx:41
std::string ConvertShapeToString(std::vector< size_t > shape)
create variable transformations