File indexing completed on 2025-01-18 10:11:08
0001 #ifndef TMVA_SOFIE_ROPERATOR_POOL
0002 #define TMVA_SOFIE_ROPERATOR_POOL
0003
0004 #include "TMVA/SOFIE_common.hxx"
0005 #include "TMVA/ROperator.hxx"
0006 #include "TMVA/RModel.hxx"
0007
0008 #include <memory>
0009 #include <sstream>
0010 #include <algorithm>
0011 #include <stdexcept>
0012 #include <vector>
0013 #include <cassert>
0014
0015 namespace TMVA {
0016 namespace Experimental {
0017 namespace SOFIE {
0018
0019 struct RAttributes_Pool {
0020
0021 std::string auto_pad = "NOTSET";
0022 int ceil_mode = 0;
0023 int count_include_pad = 0;
0024 int storage_order = 0;
0025 std::vector<size_t> dilations;
0026 std::vector<size_t> kernel_shape;
0027 std::vector<size_t> pads;
0028 std::vector<size_t> strides;
0029 };
0030
0031 enum PoolOpMode { InvalidPool, MaxPool, AveragePool, GlobalAveragePool };
0032
0033 template<typename T>
0034 class ROperator_Pool final : public ROperator
0035 {
0036
0037 private:
0038
0039 PoolOpMode fPoolMode;
0040
0041 size_t fAttrCeilMode;
0042 size_t fAttrCountIncludePad;
0043 size_t fAttrStorageOrder;
0044 std::string fAttrAutopad;
0045 std::vector<size_t> fAttrDilations;
0046 std::vector<size_t> fAttrKernelShape;
0047 std::vector<size_t> fAttrPads;
0048 std::vector<size_t> fAttrStrides;
0049
0050 std::string fNX;
0051 std::string fNY;
0052
0053 std::vector<size_t> fShapeX;
0054 std::vector<size_t> fShapeY;
0055
0056 std::string fType;
0057
0058 size_t fDim;
0059 bool fUseSession = false;
0060
0061 public:
0062
0063 std::string Name() {
0064 if (fPoolMode == AveragePool) return "AveragePool";
0065 if (fPoolMode == MaxPool) return "MaxPool";
0066 return "Invalid";
0067 }
0068
0069 ROperator_Pool() {}
0070
0071 ROperator_Pool(PoolOpMode mode, RAttributes_Pool attr, std::string nameX, std::string nameY)
0072 : fPoolMode(mode), fAttrCeilMode(attr.ceil_mode), fAttrCountIncludePad(attr.count_include_pad),
0073 fAttrStorageOrder(attr.storage_order), fAttrAutopad(attr.auto_pad),
0074 fAttrDilations(attr.dilations), fAttrKernelShape(attr.kernel_shape), fAttrPads(attr.pads), fAttrStrides(attr.strides),
0075 fNX(UTILITY::Clean_name(nameX)), fNY(UTILITY::Clean_name(nameY))
0076 {
0077 if(std::is_same<T, float>::value) {
0078 fType = "float";
0079 } else {
0080 throw
0081 std::runtime_error("TMVA SOFIE Encountered unsupported type parsing a Pool operator");
0082 }
0083 }
0084
0085
0086 std::vector<ETensorType> TypeInference(std::vector<ETensorType> input) {
0087
0088 return input;
0089 }
0090
0091
0092 std::vector<std::vector<size_t>> ShapeInference(std::vector<std::vector<size_t>> input) {
0093
0094
0095
0096 if (input.size() != 1 ) {
0097 throw std::runtime_error("TMVA SOFIE" + Name() + "Op Shape inference need 1 input tensor");
0098 }
0099 if (input[0].size() < 3) {
0100 throw std::runtime_error("TMVA SOFIE" + Name() + "Op Shape inference only accept tensor with at least 3 dimensions");
0101 }
0102
0103 if (input[0].size() < 3 || input[0].size() > 5) {
0104 throw std::runtime_error("TMVA SOFIE" + Name() + "Op : tensors with dimension " + std::to_string(input[0].size()) + " are not yet supported");
0105 }
0106
0107 if (input[0].size() -2 != fDim) {
0108 throw
0109 std::runtime_error("TMVA SOFIE Pool Op Shape inference - invalid inputs ");
0110 }
0111
0112 size_t k1 = ((fAttrKernelShape.empty())? input[0][2] : fAttrKernelShape[0]);
0113 size_t k2 = (fDim > 1) ? ((fAttrKernelShape.empty()) ? input[0][3] : fAttrKernelShape[1]) : 1;
0114 size_t k3 = (fDim > 2) ? ((fAttrKernelShape.empty()) ? input[0][4] : fAttrKernelShape[2]) : 1;
0115
0116
0117 size_t i1 = (fDim > 1) ? ((fDim > 2) ? 3 : 2) : 1;
0118 size_t i2 = (fDim > 2) ? 4 : 3;
0119 size_t i3 = 5;
0120
0121 if (fAttrDilations.empty()) {
0122 fAttrDilations = {1, 1, 1};
0123 }
0124 fAttrDilations.resize(3);
0125 if (fDim < 3) {
0126 fAttrDilations.resize(3, 1);
0127 }
0128
0129 fAttrKernelShape = {k1 + (fAttrDilations[0] - 1) * (k1 - 1),
0130 k2 + (fAttrDilations[1] - 1) * (k2 - 1),
0131 k3 + (fAttrDilations[2] - 1) * (k3 - 1)};
0132
0133 if (fAttrAutopad == "NOTSET") {
0134
0135 if (fAttrPads.empty()) {
0136 fAttrPads = {0, 0, 0, 0, 0, 0};
0137 }
0138 } else if (fAttrAutopad == "SAME_UPPER" || fAttrAutopad == "SAME_LOWER") {
0139 if (fDim == 1)
0140 fAttrPads = {fAttrKernelShape[0] / 2, fAttrKernelShape[0] / 2};
0141 else if (fDim == 2)
0142 fAttrPads = {fAttrKernelShape[0] / 2, fAttrKernelShape[1] / 2, fAttrKernelShape[0] / 2, fAttrKernelShape[1] / 2};
0143 else if (fDim == 3)
0144 fAttrPads = {fAttrKernelShape[0] / 2, fAttrKernelShape[1] / 2, fAttrKernelShape[2] / 2,
0145 fAttrKernelShape[0] / 2, fAttrKernelShape[1] / 2, fAttrKernelShape[2] / 2};
0146
0147
0148 if (fAttrKernelShape[0] % 2 == 1) {
0149 (fAttrAutopad == "SAME_UPPER") ? fAttrPads[0]++ : fAttrPads[i1]++;
0150 }
0151 if (fDim > 1 && fAttrKernelShape[1] % 2 == 1) {
0152 (fAttrAutopad == "SAME_UPPER") ? fAttrPads[1]++ : fAttrPads[i2]++;
0153 }
0154 if (fDim > 2 && fAttrKernelShape[2] % 2 == 1) {
0155 (fAttrAutopad == "SAME_UPPER") ? fAttrPads[2]++ : fAttrPads[i3]++;
0156 }
0157 } else if (fAttrAutopad != "VALID") {
0158 throw
0159 std::runtime_error("TMVA SOFIE" + Name() + "Op invalid Autopad value : " + fAttrAutopad);
0160 }
0161
0162 if (fDim < 3) fAttrPads.resize(6, 0);
0163
0164 if (fAttrStrides.empty()) {
0165 fAttrStrides = {1, 1, 1};
0166 }
0167
0168 if (fDim < 3)
0169 fAttrStrides.resize(3, 1);
0170
0171 size_t input1 = input[0][2];
0172 size_t input2 = (fDim > 1) ? input[0][3] : 1;
0173 size_t input3 = (fDim > 2) ? input[0][4] : 1;
0174
0175 size_t pad1 = fAttrPads[0] + fAttrPads[i1];
0176 size_t output1 = (input1 + pad1 - fAttrKernelShape[0]) / fAttrStrides[0] + 1;
0177
0178 size_t batch_size = input[0][0];
0179 size_t output_channels = input[0][1];
0180
0181 std::vector<std::vector<size_t>> ret({{ batch_size, output_channels, output1 }});
0182
0183 if (fDim == 1)
0184 return ret;
0185
0186 size_t pad2 = fAttrPads[1] + fAttrPads[i2];
0187 size_t output2 = (input2 + pad2 - fAttrKernelShape[1]) / fAttrStrides[1] + 1;
0188
0189 ret[0].push_back(output2);
0190 if (fDim == 2)
0191 return ret;
0192
0193 size_t pad3 = fAttrPads[2] + fAttrPads[i3];
0194 size_t output3 = (input3 + pad3 - fAttrKernelShape[2] ) / fAttrStrides[2] + 1;
0195
0196
0197 ret[0].push_back(output3);
0198 return ret;
0199 }
0200
0201 void Initialize(RModel& model) {
0202
0203 fUseSession = model.UseSession();
0204
0205 if (!model.CheckIfTensorAlreadyExist(fNX)) {
0206 throw
0207 std::runtime_error("TMVA SOFIE Pool op Input Tensor " + fNX + " is not found in model");
0208 }
0209 fShapeX = model.GetTensorShape(fNX);
0210 if (fShapeX.size() < 3 || fShapeX.size() > 5) {
0211 std::cout << fNX << " : " << ConvertShapeToString(fShapeX) << std::endl;
0212 throw
0213 std::runtime_error("TMVA SOFIE Pool Op input data tensor" + fNX + " is not of 3,4 or 5 dimensions");
0214 }
0215 fDim = fShapeX.size() - 2;
0216
0217 if (fPoolMode == GlobalAveragePool) {
0218 fPoolMode = AveragePool;
0219 fAttrKernelShape.resize(3);
0220 fAttrKernelShape[0] = fShapeX[2];
0221 if (fDim > 1)
0222 fAttrKernelShape[1] = fShapeX[3];
0223 if (fDim > 2)
0224 fAttrKernelShape[2] = fShapeX[4];
0225 fAttrAutopad = "VALID";
0226 fAttrPads = {0, 0, 0, 0, 0, 0 };
0227 assert(fAttrStrides.empty());
0228 }
0229
0230 fShapeY = ShapeInference({fShapeX})[0];
0231 model.AddIntermediateTensor(fNY, model.GetTensorType(fNX), fShapeY);
0232
0233
0234 if (fPoolMode == MaxPool) model.AddNeededStdLib("cmath");
0235
0236 }
0237
0238 std::string GenerateInitCode() {
0239 std::stringstream out;
0240 return out.str();
0241 }
0242
0243
0244 virtual std::string GenerateSessionMembersCode(std::string opName)
0245 {
0246 opName = "op_" + opName;
0247 std::stringstream out;
0248
0249 if(fDim == 1){
0250 out << "std::vector<" << fType << "> fVec_" << opName << "_xpad = std::vector<" << fType << ">("
0251 << fShapeX[1] * (fShapeX[2] + fAttrPads[0] + fAttrPads[2]) << ");\n";
0252 }
0253 else if(fDim == 2){
0254 out << "std::vector<" << fType << "> fVec_" << opName << "_xpad = std::vector<" << fType << ">("
0255 << fShapeX[1] * (fShapeX[2] + fAttrPads[0] + fAttrPads[2]) * (fShapeX[3] + fAttrPads[1] + fAttrPads[3])
0256 << ");\n";
0257 }
0258 else{
0259 out << "std::vector<" << fType << "> fVec_" << opName << "_xpad = std::vector<" << fType << ">("
0260 << fShapeX[1] * (fShapeX[2] + fAttrPads[0] + fAttrPads[2]) * (fShapeX[3] + fAttrPads[1] + fAttrPads[3]) *
0261 (fShapeX[4] + fAttrPads[2] + fAttrPads[4]) << ");\n";
0262 }
0263
0264 return out.str();
0265 }
0266
0267 std::string Generate(std::string OpName) {
0268 OpName = "op_" + OpName;
0269
0270 if (fShapeX.empty() || fShapeY.empty()) {
0271 throw std::runtime_error("TMVA SOFIE Pool Op called to Generate without being initialized first");
0272 }
0273
0274 std::stringstream out;
0275
0276 out << "\n//---- operator " << Name() << " " << OpName << "\n";
0277 out << "{\n";
0278
0279 assert(fShapeX[0] == fShapeY[0]);
0280 assert(fShapeX[1] == fShapeY[1]);
0281 assert(fAttrPads.size() == 6);
0282 assert(fAttrKernelShape.size() == 3);
0283
0284 int hmin = - fAttrPads[0];
0285 int hmax = fShapeX[2] + fAttrPads[1] - fAttrKernelShape[0] +1;
0286 int wmin,wmax,dmin,dmax;
0287
0288 if(fDim >= 2){
0289 wmin = - fAttrPads[2];
0290 wmax = fShapeX[3] + fAttrPads[3] - fAttrKernelShape[1] +1;
0291 }
0292 else{
0293 wmin=1;
0294 wmax=1;
0295 }
0296 if(fDim == 3){
0297 dmin = - fAttrPads[4];
0298 dmax = fShapeX[4] + fAttrPads[5] - fAttrKernelShape[2] +1;
0299 }
0300 else{
0301 dmin=1;
0302 dmax=1;
0303 }
0304 out << SP << "constexpr int hsize = " << fShapeX[2] << ";\n";
0305 out << SP << "constexpr int hmin = " << hmin << ";\n";
0306 out << SP << "constexpr int hmax = " << hmax << ";\n";
0307 out << SP << "constexpr int kh = " << fAttrKernelShape[0] << ";\n";
0308 if (fDim > 1) {
0309 size_t wsize = fShapeX[3];
0310 out << SP << "constexpr int wsize = " << wsize << ";\n";
0311 out << SP << "constexpr int wmin = " << wmin << ";\n";
0312 out << SP << "constexpr int wmax = " << wmax << ";\n";
0313 out << SP << "constexpr int kw = " << fAttrKernelShape[1] << ";\n";
0314 if (fDim > 2) {
0315 size_t dsize = fShapeX[4];
0316 out << SP << "constexpr int dsize = " << dsize << ";\n";
0317 out << SP << "constexpr int dwsize = " << dsize*wsize << ";\n";
0318 out << SP << "constexpr int dmin = " << dmin << ";\n";
0319 out << SP << "constexpr int dmax = " << dmax << ";\n";
0320 out << SP << "constexpr int kd = " << fAttrKernelShape[2] << ";\n";
0321 }
0322 }
0323
0324
0325 bool doPadding = false;
0326 for ( auto & e : fAttrPads)
0327 doPadding |= (e > 0);
0328
0329
0330 if(fDim==1){
0331
0332 out << SP << "size_t outIndex = 0;\n";
0333 out << SP << "for (size_t n = 0; n < " << fShapeX[0]*fShapeX[1] << "; n++) {\n";
0334 out << SP << SP << "size_t inputOffset = n*" << fShapeX[2] << ";\n";
0335 out << SP << SP << "for (int i = hmin; i < hmax; i+=" << fAttrStrides[0] << ") {\n";
0336
0337 if (fPoolMode == MaxPool)
0338 out << SP << SP << SP << SP << "float value = -INFINITY;\n";
0339 else if (fPoolMode == AveragePool) {
0340 out << SP << SP << SP << SP << "float value = 0;\n";
0341 if (fAttrCountIncludePad == 0 && doPadding)
0342 out << SP << SP << SP << SP << "int nsum = 0;\n";
0343 else
0344 out << SP << SP << SP << SP << "constexpr int nsum = kh;\n";
0345 }
0346
0347 out << SP << SP << SP << SP << "for (int l = i; l < i + kh; l++) {\n";
0348 out << SP << SP << SP << SP << SP << "if (l < 0 || l >= hsize) continue;\n";
0349 out << SP << SP << SP << SP << SP << SP << "int index = inputOffset + l;\n";
0350 if (fPoolMode == MaxPool) {
0351 out << SP << SP << SP << SP << SP << SP << "auto xval = tensor_" << fNX << "[index];\n";
0352 out << SP << SP << SP << SP << SP << SP << "if (xval > value) value = xval;\n";
0353 }
0354 else if (fPoolMode == AveragePool) {
0355
0356 out << SP << SP << SP << SP << SP << SP << "value += tensor_" << fNX << "[index];\n";
0357 if (fAttrCountIncludePad == 0 && doPadding)
0358
0359 out << SP << SP << SP << SP << SP << SP << "nsum++;\n";
0360 }
0361 out << SP << SP << SP << SP << SP << "}\n";
0362 if (fPoolMode == AveragePool) {
0363
0364 out << SP << SP << SP << SP << "value /= float(nsum);\n";
0365 }
0366
0367 out << SP << SP << SP << SP << "tensor_" << fNY << "[outIndex++] = value;\n";
0368
0369 out << SP << SP << "}\n";
0370 out << SP << "}\n";
0371 }
0372 else if(fDim==2){
0373
0374 out << SP << "size_t outIndex = 0;\n";
0375 out << SP << "for (size_t n = 0; n < " << fShapeX[0]*fShapeX[1] << "; n++) {\n";
0376 out << SP << SP << "size_t inputOffset = n*" << fShapeX[2]*fShapeX[3] << ";\n";
0377 out << SP << SP << "for (int i = hmin; i < hmax; i+=" << fAttrStrides[0] << ") {\n";
0378 out << SP << SP << SP << "for (int j = wmin; j < wmax; j+=" << fAttrStrides[1] << ") {\n";
0379
0380 if (fPoolMode == MaxPool)
0381 out << SP << SP << SP << SP << "float value = -INFINITY;\n";
0382 else if (fPoolMode == AveragePool) {
0383 out << SP << SP << SP << SP << "float value = 0;\n";
0384 if (fAttrCountIncludePad == 0 && doPadding)
0385 out << SP << SP << SP << SP << "int nsum = 0;\n";
0386 else
0387 out << SP << SP << SP << SP << "constexpr int nsum = kw*kh;\n";
0388 }
0389
0390 out << SP << SP << SP << SP << "for (int l = i; l < i + kh; l++) {\n";
0391 out << SP << SP << SP << SP << SP << "if (l < 0 || l >= hsize) continue;\n";
0392
0393 out << SP << SP << SP << SP << SP << "for (int m = j; m < j + kw; m++) {\n";
0394 out << SP << SP << SP << SP << SP << SP << "if (m < 0 || m >= wsize) continue;\n";
0395 out << SP << SP << SP << SP << SP << SP << SP << "int index = inputOffset + l*wsize + m;\n";
0396 if (fPoolMode == MaxPool) {
0397 out << SP << SP << SP << SP << SP << SP << SP << "auto xval = tensor_" << fNX << "[index];\n";
0398 out << SP << SP << SP << SP << SP << SP << SP << "if (xval > value) value = xval;\n";
0399 }
0400 else if (fPoolMode == AveragePool) {
0401
0402 out << SP << SP << SP << SP << SP << SP << SP << "value += tensor_" << fNX << "[index];\n";
0403 if (fAttrCountIncludePad == 0 && doPadding)
0404
0405 out << SP << SP << SP << SP << SP << SP << SP << "nsum++;\n";
0406 }
0407 out << SP << SP << SP << SP << SP << SP << "}\n";
0408 out << SP << SP << SP << SP << SP << "}\n";
0409 if (fPoolMode == AveragePool) {
0410
0411 out << SP << SP << SP << SP << "value /= float(nsum);\n";
0412 }
0413 out << SP << SP << SP << SP << "tensor_" << fNY << "[outIndex++] = value;\n";
0414 out << SP << SP << SP << "}\n";
0415 out << SP << SP << "}\n";
0416 out << SP << "}\n";
0417 }
0418 else if(fDim==3){
0419
0420 out << SP << "size_t outIndex = 0;\n";
0421 out << SP << "for (size_t n = 0; n < " << fShapeX[0]*fShapeX[1] << "; n++) {\n";
0422 out << SP << SP << "size_t inputOffset = n*" << fShapeX[2]*fShapeX[3]*fShapeX[4] << ";\n";
0423 out << SP << SP << "for (int i = hmin; i < hmax; i+=" << fAttrStrides[0] << ") {\n";
0424 out << SP << SP << SP << "for (int j = wmin; j < wmax; j+=" << fAttrStrides[1] << ") {\n";
0425 out << SP << SP << SP << SP << "for (int k = dmin; k < dmax; k+=" << fAttrStrides[2] << ") {\n";
0426
0427 if (fPoolMode == MaxPool)
0428 out << SP << SP << SP << SP << "float value = -INFINITY;\n";
0429 else if (fPoolMode == AveragePool) {
0430 out << SP << SP << SP << SP << "float value = 0;\n";
0431 if (fAttrCountIncludePad == 0 && doPadding)
0432 out << SP << SP << SP << SP << "int nsum = 0;\n";
0433 else
0434 out << SP << SP << SP << SP << "constexpr int nsum = kw*kh*kd;\n";
0435 }
0436
0437 out << SP << SP << SP << SP << "for (int l = i; l < i + kh; l++) {\n";
0438 out << SP << SP << SP << SP << SP << "if (l < 0 || l >= hsize) continue;\n";
0439
0440 out << SP << SP << SP << SP << SP << "for (int m = j; m < j + kw; m++) {\n";
0441 out << SP << SP << SP << SP << SP << SP << "if (m < 0 || m >= wsize) continue;\n";
0442
0443 out << SP << SP << SP << SP << SP << SP << "for (int p = k; p < k + kd; p++) {\n";
0444 out << SP << SP << SP << SP << SP << SP << SP << "if (p < 0 || p >= dsize) continue;\n";
0445 out << SP << SP << SP << SP << SP << SP << SP << SP << "int index = inputOffset + l*dwsize + m*dsize + p;\n";
0446
0447 if (fPoolMode == MaxPool) {
0448 out << SP << SP << SP << SP << SP << SP << SP << SP << "auto xval = tensor_" << fNX << "[index];\n";
0449 out << SP << SP << SP << SP << SP << SP << SP << SP << "if (xval > value) value = xval;\n";
0450 }
0451 else if (fPoolMode == AveragePool) {
0452
0453 out << SP << SP << SP << SP << SP << SP << SP << SP << "value += tensor_" << fNX << "[index];\n";
0454 if (fAttrCountIncludePad == 0 && doPadding)
0455
0456 out << SP << SP << SP << SP << SP << SP << SP << SP << "nsum++;\n";
0457 }
0458 out << SP << SP << SP << SP << SP << SP << "}\n";
0459 out << SP << SP << SP << SP << SP << "}\n";
0460 out << SP << SP << SP << SP << "}\n";
0461 if (fPoolMode == AveragePool) {
0462
0463 out << SP << SP << SP << SP << "value /= float(nsum);\n";
0464 }
0465
0466 out << SP << SP << SP << SP << "tensor_" << fNY << "[outIndex++] = value;\n";
0467 out << SP << SP << SP << SP << "}\n" ;
0468 out << SP << SP << SP << "}\n";
0469 out << SP << SP << "}\n";
0470 out << SP << "}\n";
0471 }
0472
0473 out << SP << "}\n";
0474
0475
0476 return out.str();
0477 }
0478 };
0479
0480 }
0481 }
0482 }
0483
0484
0485 #endif