Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
ROperator_Gemm.hxx
Go to the documentation of this file.
1#ifndef TMVA_SOFIE_ROPERATOR_GEMM
2#define TMVA_SOFIE_ROPERATOR_GEMM
3
4
6#include "TMVA/ROperator.hxx"
7#include "TMVA/RModel.hxx"
8
9#include <sstream>
10#include <algorithm>
11#include <iterator>
12#include <iomanip>
13#include <limits>
14#include <cassert>
15
16namespace TMVA{
17namespace Experimental{
18namespace SOFIE{
19
20
21 template <typename T>
22 class ROperator_Gemm final : public ROperator
23 {
24
25 private:
26 float fAttrAlpha = 1.0;
27 float fAttrBeta = 1.0;
30
31 std::string fNA;
32 std::string fNB;
33 std::string fNC = "";
34 std::string fNC2; // bias tensor name after broadcasting
35 std::string fNY;
36 std::vector<size_t> fShapeA;
37 std::vector<size_t> fShapeB;
38 std::vector<size_t> fShapeC;
39 std::vector<size_t> fShapeY;
40
41 std::string fType;
42
43 public:
44
46 ROperator_Gemm(float alpha, float beta, int_t transA, int_t transB, std::string nameA, std::string nameB, std::string nameY):
47 fAttrAlpha(alpha), fAttrBeta(beta), fAttrTransA(transA), fAttrTransB(transB), fNA(UTILITY::Clean_name(nameA)),
48 fNB(UTILITY::Clean_name(nameB)), fNY(UTILITY::Clean_name(nameY)) {
49
50 if (std::is_same<T, float>::value) {
51 fType = "float";
52 }else{
53 throw std::runtime_error("TMVA SOFIE Encountered unsupported type parsing a gemm operator");
54 }
55 }
56
57 ROperator_Gemm(float alpha, float beta, int_t transA, int_t transB, std::string nameA, std::string nameB, std::string nameC, std::string nameY):
58 fAttrAlpha(alpha), fAttrBeta(beta), fAttrTransA(transA), fAttrTransB(transB), fNA(UTILITY::Clean_name(nameA)),
59 fNB(UTILITY::Clean_name(nameB)), fNC(UTILITY::Clean_name(nameC)), fNY(UTILITY::Clean_name(nameY)) {
60
61 if (std::is_same<T, float>::value) {
62 fType = "float";
63 }else{
64 throw std::runtime_error("TMVA SOFIE Encountered unsupported type parsing a gemm operator");
65 }
66 }
67
68 std::vector<ETensorType> TypeInference(std::vector<ETensorType> input){
69 ETensorType out = input[0];
70 return {out};
71 }
72
73 std::vector<std::vector<size_t>> ShapeInference(std::vector<std::vector<size_t>> input){
74 if (input.size() > 3) throw std::runtime_error("TMVA SOFIE Gemm Op Shape Inference only need 2 or 3 input tensor");
75 for (auto& i: input){
76 if (i.size() > 2){
77 throw std::runtime_error("TMVA SOFIE Gemm Op Shape Inference only accept input tensor with 2 dimensions");
78 }
79 }
80 std::vector<std::vector<size_t>> ret;
81 if (input.size() == 3){
82 ret.push_back(input[2]); //shape of C is shape of Y
83 return ret;
84 }
85 std::vector<size_t> s_a(input[0]);
86 std::vector<size_t> s_b(input[1]);
87 if (fAttrTransA){
88 std::reverse(s_a.begin(), s_a.end());
89 }
90 if (fAttrTransB){
91 std::reverse(s_b.begin(), s_b.end());
92 }
93 std::vector<size_t> s_y(2);
94 s_y[0] = s_a[0];
95 s_y[1] = s_b[1];
96 ret.push_back(s_y);
97 return ret;
98 }
99
100
101
102 void Initialize(RModel& model){
103 //TODO: propagate A or B as specified by ONNX standard
104
105 if ((model.CheckIfTensorAlreadyExist(fNA) == false) || (model.CheckIfTensorAlreadyExist(fNB) == false) ){ //input must be a graph input, or already initialized intermediate tensor
106 throw std::runtime_error("TMVA SOFIE Gemm Op Input Tensor " + fNA + " or " + fNB + " is not found in model");
107 }
108 if (fNC != ""){
109 if (model.CheckIfTensorAlreadyExist(fNC) == false){ //input must be a graph input, or already initialized intermediate tensor
110 throw std::runtime_error("TMVA SOFIE Gemm Op Input Tensor" + fNC + " is not found in model");
111 }
112 }
113 fShapeA = model.GetTensorShape(fNA);
114 if (fShapeA.size() != 2){
115 throw std::runtime_error("TMVA SOFIE Gemm Op Input Tensor" + fNA +
116 " is not of 2 dimensions: A " + ConvertShapeToString(fShapeA));
117 }
118 fShapeB = model.GetTensorShape(fNB);
119 if (fShapeB.size() != 2){
120 throw std::runtime_error("TMVA SOFIE Gemm Op Input Tensor" + fNB + " is not of 2 dimensions: B " + ConvertShapeToString(fShapeB));
121 }
123 if (fNC != ""){
124 fShapeC = model.GetTensorShape(fNC);
125 fNC2 = fNC;
126 bool broadcast_needed = false;
127
128 // broadcast is not needed if fShapeY[0] == 1 i.e. C and Y have same length
130 broadcast_needed = true;
131 }
132
133 // std::cout << "doing broadcast " << broadcast_needed << " use session " << model.UseSession() <<
134 // " shape C " << ConvertShapeToString(fShapeC) << " shape Y " << ConvertShapeToString(fShapeY)
135 // << std::endl;
136
137 if (broadcast_needed) {
138 if (!model.UseSession()) {
139 auto original_data = model.GetInitializedTensorData(fNC);
140 if (fType == "float") {
141
142 std::shared_ptr<void> new_data_ptr(UTILITY::Unidirectional_broadcast<float>(
143 static_cast<float *>(original_data.get()), fShapeC, fShapeY),
144 std::default_delete<float[]>());
145
146 model.UpdateInitializedTensor(fNC, model.GetTensorType(fNC), fShapeY, new_data_ptr);
148 }
149 } else {
150 // In case of session add broadcasting code in Session constructor and in GenerateInitCode
151 // we need to add a new intermediate tensor for broadcasted bias tensor
152 fNC2 = fNC + "bcast";
154 }
155 }
156 }
157
158
159
160
162 model.AddNeededStdLib("algorithm");
163
164 }
165
166 std::string GenerateInitCode()
167 {
168 std::stringstream out;
169 // generate initialization code for broadcasting of bias tensor
170 if (fShapeC.size() != fShapeY.size() && fNC != fNC2) {
171 // include a separate scope to avoid defining unique operator temp variables
172 out << " {\n";
173 out << " std::vector<size_t> oldShape = " << ConvertShapeToString(fShapeC) << ";\n";
174 out << " std::vector<size_t> newShape = " << ConvertShapeToString(fShapeY) << ";\n";
175 std::string original_bias_tensor = "tensor_" + fNC;
176 std::string new_bias_tensor = "tensor_" + fNC2;
177 out << " float * newData_ptr = TMVA::Experimental::SOFIE::UTILITY::Unidirectional_broadcast<float>("
178 << original_bias_tensor << ", oldShape, newShape);\n";
179 int length = TMVA::Experimental::SOFIE::ConvertShapeToLength(fShapeY); // output size
180 out << " std::copy(newData_ptr, newData_ptr + " << length << ", " << new_bias_tensor << ");\n";
181 out << " delete [] newData_ptr;\n";
182 out << " }\n";
183 }
184 return out.str();
185 }
186
187 std::string Generate(std::string OpName){
188 OpName = "op_" + OpName;
189
190 if (fShapeA.empty() || fShapeB.empty() || fShapeY.empty() || (fNC != "" && fShapeC.empty())) {
191 throw std::runtime_error("TMVA SOFIE Gemm Op called to Generate without being initialized first");
192 }
193 std::stringstream out;
194 out << "\n//--------- Gemm\n";
195 out << SP << "char " << OpName << "_transA = " << (fAttrTransA ? "\'t\'" : "\'n\'") << ";\n";
196 out << SP << "char " << OpName << "_transB = " << (fAttrTransB ? "\'t\'" : "\'n\'") << ";\n";
197 int m = (fAttrTransA ? fShapeA[1] : fShapeA[0]);
198 int n = (fAttrTransB ? fShapeB[0] : fShapeB[1]);
199 int k = (fAttrTransA ? fShapeA[0] : fShapeA[1]);
200 out << SP << "int " << OpName << "_m = " << m << ";\n";
201 out << SP << "int " << OpName << "_n = " << n << ";\n";
202 out << SP << "int " << OpName << "_k = " << k << ";\n";
203 out << SP << "float " << OpName << "_alpha = " << std::setprecision(std::numeric_limits<float>::max_digits10) << fAttrAlpha << ";\n";
204 out << SP << "float " << OpName << "_beta = " << std::setprecision(std::numeric_limits<float>::max_digits10) << fAttrBeta << ";\n";
205 out << SP << "int " << OpName << "_lda = " << (fAttrTransA ? m : k) << ";\n";
206 out << SP << "int " << OpName << "_ldb = " << (fAttrTransB ? k : n) << ";\n";
207 if (fNC != ""){
208 size_t length = ConvertShapeToLength(fShapeY);
209 if (fNC2 == fNC)
210 // case broadcasting was not needed or done otside of session
211 assert(length == ConvertShapeToLength(fShapeC));
212 out << SP << "std::copy(" << "tensor_" << fNC2 << ", " << "tensor_" << fNC2 << " + " << length << ", " << "tensor_" << fNY << ");\n";
213 }
214 if (fType == "float"){
215 out << SP << "BLAS::sgemm_(&" << OpName << "_transB, &" << OpName << "_transA, &" << OpName
216 << "_n, &" << OpName << "_m, &" << OpName << "_k, &" << OpName << "_alpha, " << "tensor_" << fNB
217 << ", &" << OpName << "_ldb, " << "tensor_" << fNA << ", &" << OpName << "_lda, &" << OpName << "_beta, " << "tensor_" << fNY << ", &"
218 << OpName << "_n);\n";
219 }
220
221 return out.str();
222
223 }
224
225
226
227 };
228
229
230}//SOFIE
231}//Experimental
232}//TMVA
233
234
235#endif //TMVA_SOFIE_ROPERATOR_GEMM
const ETensorType & GetTensorType(std::string name)
Definition RModel.cxx:70
void AddIntermediateTensor(std::string tensor_name, ETensorType type, std::vector< std::size_t > shape)
Definition RModel.cxx:136
bool CheckIfTensorAlreadyExist(std::string tensor_name)
Definition RModel.cxx:91
void AddNeededStdLib(std::string libname)
Definition RModel.hxx:77
const std::vector< size_t > & GetTensorShape(std::string name)
Definition RModel.cxx:49
std::shared_ptr< void > GetInitializedTensorData(std::string tensor_name)
Definition RModel.cxx:160
void UpdateInitializedTensor(std::string tensor_name, ETensorType type, std::vector< std::size_t > shape, std::shared_ptr< void > data)
Definition RModel.cxx:151
ROperator_Gemm(float alpha, float beta, int_t transA, int_t transB, std::string nameA, std::string nameB, std::string nameC, std::string nameY)
std::string Generate(std::string OpName)
std::vector< std::vector< size_t > > ShapeInference(std::vector< std::vector< size_t > > input)
ROperator_Gemm(float alpha, float beta, int_t transA, int_t transB, std::string nameA, std::string nameB, std::string nameY)
std::vector< ETensorType > TypeInference(std::vector< ETensorType > input)
const std::string SP
space used to correctly indent the generated C++ code
Definition ROperator.hxx:39
const Int_t n
Definition legend1.C:16
std::string ConvertShapeToString(std::vector< size_t > shape)
std::size_t ConvertShapeToLength(std::vector< size_t > shape)
create variable transformations
auto * m
Definition textangle.C:8