1#ifndef TMVA_SOFIE_ROPERATOR_GEMM
2#define TMVA_SOFIE_ROPERATOR_GEMM
17namespace Experimental{
54 fNB(UTILITY::Clean_name(nameB)),
fNY(UTILITY::Clean_name(nameY))
58 static_assert(std::is_same_v<T, float>,
59 "TMVA::SOFIE - Unsupported type parsing a Gemm operator");
66 fNB(UTILITY::Clean_name(nameB)),
fNC(UTILITY::Clean_name(nameC)),
fNY(UTILITY::Clean_name(nameY)),
fActivation(activation)
77 if (
input.size() > 3)
throw std::runtime_error(
"TMVA SOFIE Gemm Op Shape Inference only need 2 or 3 input tensor");
82 throw std::runtime_error(
"TMVA SOFIE Gemm Op Shape Inference only accept input tensor with >=2 dimensions");
87 if (
input.size() == 3){
92 int ioffset =
input[0].size()-2;
94 std::vector<U> s_a(
input[0].begin() + ioffset,
input[0].begin() + ioffset + 2);
95 std::vector<U> s_b(
input[1].begin() + ioffset,
input[1].begin() + ioffset + 2);
98 std::reverse(s_a.begin(), s_a.end());
101 std::reverse(s_b.begin(), s_b.end());
109 for (
size_t i = 0; i <
input[0].size()-2; i++) {
113 if (valueB.
GetVal() ==
"1")
114 s_y.push_back(
input[0][i]);
115 else if (valueA.
GetVal() ==
"1")
116 s_y.push_back(
input[1][i]);
118 throw std::runtime_error(
"TMVA SOFIE Gemm Op - invalid input shapes " + valueA.
GetVal() +
" and "
123 auto p1 = std::find(dimNames.begin(), dimNames.end(), valueA.
param);
124 auto p2 = std::find(dimNames.begin(), dimNames.end(), valueB.
param);
125 if (p1 < p2) s_y.push_back(
input[0][i]);
126 else s_y.push_back(
input[1][i]);
129 s_y.push_back(
input[0][i]);
131 s_y.push_back(
input[1][i]);
133 throw std::runtime_error(
"TMVA SOFIE Gemm Op - invalid input shapes " + valueA.
GetVal() +
" and "
137 s_y.push_back(
input[0][i]);
141 s_y.push_back(s_a[0]);
142 s_y.push_back(s_b[1]);
147 return DoShapeInference<Dim>(
input);
156 if ((model.CheckIfTensorAlreadyExist(
fNA) ==
false) || (model.CheckIfTensorAlreadyExist(
fNB) ==
false) ){
157 throw std::runtime_error(
"TMVA SOFIE Gemm Op Input Tensor " +
fNA +
" or " +
fNB +
" is not found in model");
160 if (model.CheckIfTensorAlreadyExist(
fNC) ==
false){
161 throw std::runtime_error(
"TMVA SOFIE Gemm Op Input Tensor " +
fNC +
" is not found in model");
164 if (model.IsDynamicTensor(
fNA) || model.IsDimInputTensor(
fNA) ) {
168 auto shapeA_int = model.GetTensorShape(
fNA);
172 bool prependOne =
false;
178 if (model.IsDynamicTensor(
fNB) || model.IsDimInputTensor(
fNB)) {
183 auto shapeB_int = model.GetTensorShape(
fNB);
187 bool appendOne =
false;
208 if (model.IsDynamicTensor(
fNC))
215 bool broadcast_needed =
false;
217 broadcast_needed =
true;
221 broadcast_needed = (
fShapeC != shapeY);
224 if (broadcast_needed) {
230 if ((
r.first & 2) == 2) {
232 }
else if (
r.first == 4) {
245 shapeY.erase(shapeY.begin());
251 shapeY.erase(shapeY.end()-1);
259 && model.IsInitializedTensor(
fNA)
260 && model.IsInitializedTensor(
fNB)
261 && (
fNC.empty() || model.IsInitializedTensor(
fNC))
269 size_t dimA = shapeA_i.size();
270 size_t dimB = shapeB_i.size();
271 size_t m =
fAttrTransA ? shapeA_i[dimA - 1] : shapeA_i[dimA - 2];
272 size_t k =
fAttrTransA ? shapeA_i[dimA - 2] : shapeA_i[dimA - 1];
273 size_t n =
fAttrTransB ? shapeB_i[dimB - 2] : shapeB_i[dimB - 1];
275 auto dataA =
static_cast<T *
>(model.GetInitializedTensorData(
fNA).get());
276 auto dataB =
static_cast<T *
>(model.GetInitializedTensorData(
fNB).get());
279 std::vector<T> dataY(
m *
n, T(0));
280 for (
size_t i = 0; i <
m; i++) {
281 for (
size_t j = 0; j <
n; j++) {
283 for (
size_t p = 0;
p < k;
p++) {
293 auto dataC =
static_cast<T *
>(model.GetInitializedTensorData(
fNC).get());
294 for (
size_t idx = 0; idx < dataY.size(); idx++)
295 dataY[idx] +=
static_cast<T
>(
fAttrBeta) * dataC[idx];
299 for (
auto &
v : dataY)
300 v = std::max(
v, T(0));
303 model.AddConstantTensor<T>(
fNY, shapeY, dataY.data());
305 model.SetNotWritableInitializedTensor(
fNA);
306 model.SetNotWritableInitializedTensor(
fNB);
308 model.SetNotWritableInitializedTensor(
fNC);
311 if (model.Verbose()) {
312 std::cout <<
"Gemm (or MatMul) " <<
fNA <<
" , " <<
fNB;
314 std::cout <<
" , " <<
fNC;
321 model.AddIntermediateTensor(
fNY, model.GetTensorType(
fNA), shapeY);
323 model.AddDynamicTensor(
fNY, model.GetTensorType(
fNA),
fShapeY);
325 if (model.Verbose()){
326 std::cout <<
"Gemm (or MatMul) " <<
" ---> " <<
fNY <<
" shape ";
333 model.AddNeededStdLib(
"algorithm");
336 if (
fType ==
"float")
337 model.AddNeededHelperFunction(
"Gemm_Call");
340 model.AddNeededHelperFunction(
"Copy");
341 model.AddNeededHelperFunction(
"Fill");
344 model.AddNeededHelperFunction(
"Relu");
347 std::string
Generate(std::string opName)
override {
351 opName =
"op_" + opName;
356 std::stringstream out;
364 if (dimA != dimB || dimA != dimY || (
fBroadcastBias && dimC != dimY)) {
369 throw std::runtime_error(
"TMVA SOFIE Gemm(MatMul) has invalid shape for inputs or output");
378 std::vector<Dim> sExtraY;
379 for (int64_t i = 0; i < dimY-2; i++) {
384 std::string lengthExtra_C;
385 std::vector<Dim> sExtraC;
387 bool haveExtraC =
false;
390 for (int64_t i = 0; i < dimC-2; i++) {
394 if (lengthExtra_C !=
"1") haveExtraC =
true;
395 }
else if (dimC > 0) {
396 for (int64_t i = 0; i < dimC; i++) {
416 (haveExtraC && std::stoi(lengthExtra_Y) != std::stoi(lengthExtra_C)))
417 throw std::runtime_error(
"TMVA SOFIE Gemm Op " + opName +
" Bias tensor " +
fNC +
419 " output length " + lengthGemm);
424 out <<
SP <<
"assert(" << lengthExtra_Y <<
" == " << lengthExtra_C <<
");\n";
434 std::cout <<
"WARNING: TMVA SOFIE Gemm Op " + opName +
" Bias tensor is not present but beta value in Gemm is not zero - force it to zero\n";
440 bool doStackMul = dimY > 2 && (
fIsDynamic || std::stoi(lengthExtra_Y) > 1);
442 std::string lengthExtra_A;
443 std::string lengthExtra_B;
444 std::string increment_A;
445 std::string increment_B;
458 bool extraA = (doStackMul && lengthExtra_A !=
"1");
459 bool extraB = (doStackMul && lengthExtra_B !=
"1");
462 std::string biasShapeType = opName +
"_biasShapeType";
468 out <<
SP <<
"int " << biasShapeType <<
" = 0;\n";
470 if (sC[0].GetVal() !=
"1" && sC[1].GetVal() != sY[1].GetVal())
471 out <<
SP <<
"if (" << sC[0] <<
" == 1 && " << sC[1] <<
" == " << sY[1] <<
")\n";
472 else if (sC[0].GetVal() ==
"1")
473 out <<
SP <<
"if (" << sC[1] <<
" == " << sY[1] <<
")\n";
474 else if (sC[1].GetVal() == sY[1].GetVal())
475 out <<
SP <<
"if (" << sC[0] <<
" == 1)\n";
477 out <<
SP <<
SP << biasShapeType <<
" = 1;\n";
480 if (sC[1].GetVal() !=
"1" && sC[0].GetVal() != sY[0].GetVal())
481 out <<
SP <<
"else if (" << sC[1] <<
" == 1 && " << sC[0] <<
" == " << sY[0] <<
")\n";
482 else if (sC[1].GetVal() ==
"1")
483 out <<
SP <<
"else if (" << sC[0] <<
" == " << sY[0] <<
")\n";
484 else if (sC[0].GetVal() == sY[0].GetVal())
485 out <<
SP <<
"else if (" << sC[1] <<
" == 1)\n";
487 out <<
SP <<
SP << biasShapeType <<
" = 2;\n";
490 if (sC[0].GetVal() !=
"1" && sC[1].GetVal() !=
"1")
491 out <<
SP <<
"else if (" << sC[0] <<
" == 1 && " << sC[1] <<
" == 1 )\n";
492 else if (sC[0].GetVal() ==
"1")
493 out <<
SP <<
"else if (" << sC[1] <<
" == 1)\n";
494 else if (sC[1].GetVal() ==
"1")
495 out <<
SP <<
"else if (" << sC[0] <<
" == 1)\n";
496 out <<
SP <<
SP << biasShapeType <<
" = 3;\n";
497 out <<
SP <<
"else\n";
498 out <<
SP <<
SP <<
"throw std::runtime_error(\"TMVA SOFIE Gemm Op - bias tensor "
504 out <<
SP <<
"size_t " << opName <<
"_y_offset = 0;\n";
506 out <<
SP <<
"size_t " << opName <<
"_A_offset = 0;\n";
508 out <<
SP <<
"size_t " << opName <<
"_B_offset = 0;\n";
510 out <<
SP <<
"size_t " << opName <<
"_C_offset = 0;\n";
511 out <<
SP <<
"for (size_t i = 0; i < " << lengthExtra_Y <<
"; i++){\n";
521 out << SP2 <<
"for (size_t j = 0; j < " << sY[0] <<
"; j++) { \n";
522 out << SP2 <<
SP <<
"size_t y_index = ";
524 out << opName <<
"_y_offset + ";
525 if (sY[1].GetVal() !=
"1")
526 out << sY[1] <<
" * j;\n";
530 std::string prefix = SP2 +
SP;
532 if (sC.size() != 2) {
534 }
if (sC[0].GetVal() ==
"1" && sC[1].GetVal() == sY[1].GetVal()) {
535 out << prefix <<
"Copy(" <<
target <<
" + y_index, tensor_" <<
fNC <<
", " << sY[1] <<
");\n";
536 }
else if (sC[1].GetVal() ==
"1" && sC[0].GetVal() == sY[0].GetVal()) {
537 out << prefix <<
"Fill(" <<
target <<
" + y_index, tensor_" <<
fNC <<
"[j], " << sY[1] <<
");\n";
538 }
else if (sC[0].GetVal() ==
"1" && sC[1].GetVal() ==
"1") {
540 out << prefix <<
"Fill(" <<
target <<
" + y_index, tensor_" <<
fNC <<
"[0], " << sY[1] <<
");\n";
545 out << SP2 <<
SP <<
"if (" << biasShapeType <<
" == 1)\n";
546 out <<
SP << prefix <<
"Copy(" <<
target <<
" + y_index, tensor_" <<
fNC <<
", " << sY[1] <<
");\n";
547 out << SP2 <<
SP <<
"else if (" << biasShapeType <<
" == 2)\n";
548 out <<
SP << prefix <<
"Fill(" <<
target <<
" + y_index, tensor_" <<
fNC <<
"[j], " << sY[1] <<
");\n";
549 out << SP2 <<
SP <<
"else \n";
550 out <<
SP << prefix <<
"Fill(" <<
target <<
" + y_index, tensor_" <<
fNC <<
"[0], " << sY[1] <<
");\n";
558 if (
fType ==
"float"){
560 out << SP2 <<
"Gemm_Call(" <<
"tensor_" <<
fNY;
561 if (doStackMul) out <<
" + " << opName <<
"_y_offset";
565 <<
n <<
", " <<
m <<
", " << k <<
", ";
566 out << std::setprecision(std::numeric_limits<float>::max_digits10) <<
fAttrAlpha <<
", tensor_" <<
fNB;
567 if (extraB) out <<
" + " << opName <<
"_B_offset";
568 out <<
", tensor_" <<
fNA;
569 if (extraA) out <<
" + " << opName <<
"_A_offset";
570 out <<
", " << std::setprecision(std::numeric_limits<float>::max_digits10) <<
fAttrBeta <<
",";
573 out <<
"tensor_" <<
fNC;
575 out <<
" + " << opName <<
"_C_offset";
585 out <<
SP <<
SP << opName <<
"_y_offset += " << lengthGemm <<
";\n";
586 if (lengthExtra_A !=
"1")
587 out <<
SP <<
SP << opName <<
"_A_offset += " << increment_A <<
";\n";
588 if (lengthExtra_B !=
"1")
589 out <<
SP <<
SP << opName <<
"_B_offset += " << increment_B <<
";\n";
592 out <<
SP <<
SP << opName <<
"_C_offset += " << lengthGemm <<
";\n";
598 out <<
SP <<
"//--- applying RELU to output\n";
599 std::string tnsr =
"tensor_" +
fNY;
601 out <<
SP <<
"Relu(" << tnsr <<
", " << tnsr <<
", " << reluSize <<
");\n";
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
winID h TVirtualViewer3D TVirtualGLPainter p
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 WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t target
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t r
const std::vector< std::string > & GetDimShapeNames() const
ROperator_Gemm(float alpha, float beta, int_t transA, int_t transB, std::string nameA, std::string nameB, std::string nameC, std::string nameY, EActivationType activation=EActivationType::UNDEFINED)
std::vector< Dim > DynamicShapeInference(const std::vector< std::vector< Dim > > &input)
std::vector< Dim > fShapeY
ROperator_Gemm(float alpha, float beta, int_t transA, int_t transB, std::string nameA, std::string nameB, std::string nameY, EActivationType activation=EActivationType::UNDEFINED)
std::vector< U > DoShapeInference(const std::vector< std::vector< U > > &input)
std::vector< Dim > fShapeA
std::vector< Dim > fShapeB
std::vector< size_t > fShapeC
std::string Generate(std::string opName) override
void Initialize(RModel &model) override
std::vector< Dim > fDimShapeC
bool fBiasBroadcastAssumed
bool fCheckBiasShapeAtRuntime
EActivationType fActivation
std::vector< std::string > GetBlasRoutines() override
std::vector< std::string_view > fInputTensorNames
bool fIsOutputConstant
flag to identify if operator has a constant output (no need to generate code)
const std::string SP
space used to correctly indent the generated C++ code
std::vector< std::string_view > fOutputTensorNames
std::vector< size_t > MultidirectionalBroadcastShape(std::vector< std::vector< size_t > >)
std::string ConvertDimShapeToString(const std::vector< Dim > &shape)
std::vector< Dim > ConvertShapeToDim(const std::vector< size_t > &shape)
Convert shape from integer format to dynamic one (based on Dim)
std::vector< size_t > ConvertShapeToInt(const std::vector< Dim > &shape)
Convert shape based on Dim to integer format.
std::string ConvertDimShapeToLength(const std::vector< Dim > &shape)
std::string ConvertShapeToString(const std::vector< size_t > &shape)
create variable transformations
std::string GetVal() const
static uint64_t sum(uint64_t i)