Logo ROOT  
Reference Guide
RModel.cxx
Go to the documentation of this file.
1#include <limits>
2
3#include "TMVA/RModel.hxx"
4
5
6
7
8namespace TMVA{
9namespace Experimental{
10namespace SOFIE{
11
13 fInputTensorInfos = std::move(other.fInputTensorInfos);
14 fReadyInputTensorInfos = std::move(other.fReadyInputTensorInfos);
15 fOutputTensorNames = other.fOutputTensorNames;
16 fOperators = std::move(other.fOperators);
17 fInitializedTensors = std::move(other.fInitializedTensors);
18 fIntermediateTensorInfos = std::move(other.fIntermediateTensorInfos);
19 fName = other.fName;
20 fFileName = other.fFileName;
21 fParseTime = other.fParseTime;
22 fGC = other.fGC;
23 fNeededBlasRoutines = other.fNeededBlasRoutines;
24 fNeededStdLib = other.fNeededStdLib;
25 }
26
28 fInputTensorInfos = std::move(other.fInputTensorInfos);
29 fReadyInputTensorInfos = std::move(other.fReadyInputTensorInfos);
30 fOutputTensorNames = other.fOutputTensorNames;
31 fOperators = std::move(other.fOperators);
32 fInitializedTensors = std::move(other.fInitializedTensors);
33 fIntermediateTensorInfos = std::move(other.fIntermediateTensorInfos);
34 fName = other.fName;
35 fFileName = other.fFileName;
36 fParseTime = other.fParseTime;
37 fGC = other.fGC;
38 fNeededBlasRoutines = other.fNeededBlasRoutines;
39 fNeededStdLib = other.fNeededStdLib;
40 return *this;
41 }
42
43 RModel::RModel(std::string name, std::string parsedtime): fFileName (name), fParseTime(parsedtime) {
44 fName = fFileName.substr(0, fFileName.rfind("."));
45 }
46
47 const std::vector<size_t>& RModel::GetTensorShape(std::string name){
48 auto f = fReadyInputTensorInfos.find(name);
49 if (f != fReadyInputTensorInfos.end()){
50 return f->second.shape;
51 }
52 auto f2 = fInitializedTensors.find(name);
53 if (f2 != fInitializedTensors.end()){
54 return f2->second.fShape;
55 }
56 auto f3 = fInputTensorInfos.find(name);
57 if (f3 != fInputTensorInfos.end()){
58 throw std::runtime_error("TMVA SOFIE tensor [" + name + "] is an input tensor with unspecified dimension parameter");
59 }
60 auto f4 = fIntermediateTensorInfos.find(name);
61 if (f4 != fIntermediateTensorInfos.end()){
62 return f4->second.shape;
63 }
64
65 throw std::runtime_error("TMVA SOFIE tensor [" + name + "] for which the shape is requested is not found");
66 }
67
69 auto f = fReadyInputTensorInfos.find(name);
70 if (f != fReadyInputTensorInfos.end()){
71 return f->second.type;
72 }
73 auto f2 = fInitializedTensors.find(name);
74 if (f2 != fInitializedTensors.end()){
75 return f2->second.fType;
76 }
77 auto f3 = fInputTensorInfos.find(name);
78 if (f3 != fInputTensorInfos.end()){
79 return f3->second.type;
80 }
81 auto f4 = fIntermediateTensorInfos.find(name);
82 if (f4 != fIntermediateTensorInfos.end()){
83 return f4->second.type;
84 }
85
86 throw std::runtime_error("TMVA SOFIE tensor [" + name + "] for which the shape is requested is not found");
87 }
88
89 bool RModel::CheckIfTensorAlreadyExist(std::string tensor_name){
90 if (fReadyInputTensorInfos.find(tensor_name) != fReadyInputTensorInfos.end()) return true;
91 if (fInitializedTensors.find(tensor_name) != fInitializedTensors.end()) return true;
92 if (fIntermediateTensorInfos.find(tensor_name) != fIntermediateTensorInfos.end()) return true;
93 return false;
94 }
95
96 void RModel::AddInputTensorInfo(std::string input_name, ETensorType type, std::vector<Dim> shape){
97 input_name = UTILITY::Clean_name(input_name);
98 if (CheckIfTensorAlreadyExist(input_name)){
99 throw std::runtime_error("TMVA-SOFIE: input tensor with name " + input_name + " already exists \n");
100 }
101
102 InputTensorInfo inputInfo { type, shape };
103 fInputTensorInfos[input_name] = inputInfo;
104 }
105
106 void RModel::AddInputTensorInfo(std::string input_name, ETensorType type, std::vector<size_t> shape){
107 input_name = UTILITY::Clean_name(input_name);
108 if (CheckIfTensorAlreadyExist(input_name)){
109 throw std::runtime_error("TMVA-SOFIE: input tensor with name " + input_name + " already exists \n");
110 }
111 TensorInfo inputInfo { type, shape };
112 fReadyInputTensorInfos[input_name] = inputInfo;
113 }
114
115 void RModel::AddOperator(std::unique_ptr<ROperator> op, int order_execution){
116 if (order_execution >= 0) {
117 fOperators.insert(fOperators.begin() + order_execution, std::move(op));
118 }else{
119 fOperators.push_back(std::move(op));
120 }
121 }
122
123 void RModel::AddInitializedTensor(std::string tensor_name, ETensorType type, std::vector<std::size_t> shape, std::shared_ptr<void> data){
124 tensor_name = UTILITY::Clean_name(tensor_name);
125 //NB: own data
126 if (CheckIfTensorAlreadyExist(tensor_name)){
127 throw std::runtime_error("TMVA-SOFIE: initialized tensor with name " + tensor_name + " already exists \n");
128 }
129 InitializedTensor new_tensor {type, shape, data};
130 fInitializedTensors[tensor_name] = new_tensor;
131
132 }
133
134 void RModel::AddIntermediateTensor(std::string tensor_name, ETensorType type, std::vector<std::size_t> shape){
135 tensor_name = UTILITY::Clean_name(tensor_name);
136 if (CheckIfTensorAlreadyExist(tensor_name)){
137 throw std::runtime_error("TMVA-SOFIE: intermediate tensor with name " + tensor_name + " already exists \n");
138 }
139 TensorInfo new_tensor {type, shape};
140 fIntermediateTensorInfos[tensor_name] = new_tensor;
141 }
142
143 void RModel::AddOutputTensorNameList(std::vector<std::string> outputtensornames){
144 for(auto& it : outputtensornames){
146 }
147 }
148
149 void RModel::UpdateInitializedTensor(std::string tensor_name, ETensorType type, std::vector<std::size_t> shape, std::shared_ptr<void> data){
150 tensor_name = UTILITY::Clean_name(tensor_name);
151 if (!CheckIfTensorAlreadyExist(tensor_name)){
152 throw std::runtime_error("TMVA-SOFIE: tensor " + tensor_name + " not found when trying to update it");
153 }
154 InitializedTensor new_tensor {type, shape, data};
155 fInitializedTensors[tensor_name] = new_tensor;
156 }
157
158 std::shared_ptr<void> RModel::GetInitializedTensorData(std::string tensor_name){
159 auto f = fInitializedTensors.find(tensor_name);
160 if (f == fInitializedTensors.end()){
161 throw std::runtime_error("TMVA-SOFIE: tensor " + tensor_name + " not found when trying to get its data");
162 }else{
163 return f->second.fData;
164 }
165 }
166
168 for (auto& i : fOperators){
169 i->Initialize(*this);
170 }
171 }
172
174 Initialize();
175 fGC += ("//Code generated automatically by TMVA for Inference of Model file [" + fFileName + "] at [" + fParseTime.substr(0, fParseTime.length()-1) +"] \n");
176 for (auto& i: fNeededStdLib) {
177 fGC += "#include<" + i + ">\n";
178 }
179 fGC += ("namespace TMVA_SOFIE_" + fName + "{\n");
180 if (!fNeededBlasRoutines.empty()) {
181 fGC += ("namespace BLAS{\n");
182 for (auto &routine : fNeededBlasRoutines) {
183 if (routine == "Gemm") {
184 fGC += ("\textern \"C\" void sgemm_(const char * transa, const char * transb, const int * m, const int * n, const int * k,\n"
185 "\t const float * alpha, const float * A, const int * lda, const float * B, const int * ldb,\n"
186 "\t const float * beta, float * C, const int * ldc);\n");
187 } else if (routine == "Gemv") {
188 fGC += ("\textern \"C\" void sgemv_(const char * trans, const int * m, const int * n, const float * alpha, const float * A,\n"
189 "\t const int * lda, const float * X, const int * incx, const float * beta, const float * Y, const int * incy);\n");
190 } else if (routine == "Axpy") {
191 fGC += ("\textern \"C\" void saxpy_(const int * n, const float * alpha, const float * x,\n"
192 "\t const int * incx, float * y, const int * incy);\n");
193 }
194 }
195 fGC += ("}//BLAS\n");
196 }
197 for (auto& i: fInitializedTensors){
198 if (i.second.fType == ETensorType::FLOAT){
199 size_t length = 1;
200 for (auto & dim: i.second.fShape){
201 length *= dim;
202 }
203 fGC += "float tensor_" + i.first + "[" + std::to_string(length) + "] = {";
204 std::shared_ptr<float> data = std::static_pointer_cast<float>(i.second.fData);
205 std::stringstream floats;
206 for (size_t idx = 0; idx < length-1; idx++){
207 floats << std::setprecision(std::numeric_limits<float>::max_digits10) << data.get()[idx] << ", ";
208 }
209 floats << std::setprecision(std::numeric_limits<float>::max_digits10) << data.get()[length-1];
210 fGC += floats.str() +"};\n";
211 }
212 }
213 for (auto&i: fIntermediateTensorInfos){
214 if (i.second.type == ETensorType::FLOAT){
215 size_t length = 1;
216 for (auto & dim: i.second.shape){
217 length *= dim;
218 }
219 fGC += "float tensor_" + i.first + "[" + std::to_string(length) + "];\n";
220 }
221 }
222
223 size_t outputSize = fOutputTensorNames.size();
224 if (outputSize == 1) {
226 if (f == fIntermediateTensorInfos.end()){
227 throw std::runtime_error("TMVA-SOFIE: output tensor " + fOutputTensorNames[0] + " not found when trying to get its info");
228 }else{
229 if (f->second.type == ETensorType::FLOAT){
230 fGC += "std::vector<float> ";
231 }
232 }
233 } else {
234 std::vector<ETensorType> outputTensorsTypes(outputSize);
235 for (size_t i = 0; i < outputSize; i++) {
237 if (f == fIntermediateTensorInfos.end()) {
238 throw std::runtime_error("TMVA-SOFIE: output tensor " + fOutputTensorNames[i]
239 + " not found when trying to get its info");
240 } else {
241 outputTensorsTypes[i] = f->second.type;
242 }
243 }
244 ETensorType outputType = outputTensorsTypes[0];
245 for (size_t i = 0; i < outputSize; i++) {
246 if (outputTensorsTypes[i] != outputType) {
247 throw std::runtime_error("TMVA-SOFIE: output tensor " + fOutputTensorNames[i] + " is of different type.");
248 }
249 }
250 if (outputType == ETensorType::FLOAT) {
251 fGC += "std::vector<std::vector<float>> ";
252 }
253 }
254
255 fGC += "infer(";
256 for (auto& i: fReadyInputTensorInfos){
257 size_t length = 1;
258 for (auto& dim: i.second.shape){
259 length *= dim;
260 }
261 if (i.second.type == ETensorType::FLOAT){
262 fGC += "float* tensor_" + i.first + ",";
263 }
264 }
265 fGC.pop_back(); //remove last ","
266 fGC += "){\n";
267
268 for (size_t id = 0; id < fOperators.size() ; id++){
269 fGC+= (fOperators[id]->Generate(std::to_string(id)));
270 }
271 if (outputSize == 1) {
272 fGC += "\tstd::vector<float> ret (tensor_" + fOutputTensorNames[0] + ", tensor_" + fOutputTensorNames[0] + " + sizeof(tensor_" +
273 fOutputTensorNames[0] + ") / sizeof(tensor_" + fOutputTensorNames[0] + "[0]));\n";
274 } else {
275 for (size_t i = 0; i < outputSize; i++) {
276 if (!fOutputTensorNames[i].empty()) {
277 fGC += "\tstd::vector<float> ret_";
278 fGC += std::to_string(i);
279 fGC += " (tensor_" + fOutputTensorNames[i] + ", tensor_" + fOutputTensorNames[i] + " + sizeof(tensor_" + fOutputTensorNames[i] + ") / sizeof(tensor_" + fOutputTensorNames[i] + "[0]));\n";
280 }
281 }
282 fGC += "\tstd::vector<std::vector<float>> ret({";
283 for (size_t i = 0; i < outputSize; i++) {
284 if (fOutputTensorNames[i].empty()) {
285 fGC += "{}";
286 } else {
287 fGC += "ret_";
288 fGC += std::to_string(i);
289 }
290 if (i < outputSize - 1) {
291 fGC += ",";
292 }
293 }
294 fGC += "});\n";
295 }
296 fGC += "\treturn ret;\n";
297 fGC += "}\n";
298 fGC += ("} //TMVA_SOFIE_" + fName + "\n");
299 }
300
301
302
304 std::cout << "Model requires following inputs:\n";
305 for (auto& inputInfo: fInputTensorInfos){
306 std::cout << "Parameterised Tensor name: " << inputInfo.first << "\t";
307 std::cout << "type: " << ConvertTypeToString(inputInfo.second.type) << "\t";
308 std::cout << "shape: [";
309 for (size_t i = 0; i < inputInfo.second.shape.size(); i++){
310 if (inputInfo.second.shape[i].isParam){
311 std::cout << inputInfo.second.shape[i].param;
312 }else{
313 std::cout << inputInfo.second.shape[i].dim ;
314 }
315 if (i < inputInfo.second.shape.size() - 1) std::cout << ",";
316 }
317 std::cout << "]" << std::endl;
318 }
319
320 for (auto& inputInfo: fReadyInputTensorInfos){
321 std::cout << "Fully Specified Tensor name: " << inputInfo.first << "\t";
322 std::cout << "type: " << ConvertTypeToString(inputInfo.second.type) << "\t";
323 std::cout << "shape: [";
324 for (size_t i = 0; i < inputInfo.second.shape.size(); i++){
325 std::cout << inputInfo.second.shape[i];
326 if (i < inputInfo.second.shape.size() - 1) std::cout << ",";
327 }
328 std::cout << "]" << std::endl;
329 }
330
331 }
332
334 std::cout << "Model initialized the following tensors:\n";
335 for (auto& it: fInitializedTensors){
336 std::cout << "Tensor name: \"" << it.first << "\"\t";
337 std::cout << "type: " << ConvertTypeToString(it.second.fType) << "\t";
338 std::cout << "shape: [";
339 for (size_t i = 0; i < it.second.fShape.size(); i++){
340 std::cout << it.second.fShape[i];
341 if (i < it.second.fShape.size() - 1) std::cout << ",";
342 }
343 std::cout << "]" << std::endl;
344 }
345 }
346
348 std::cout << "Model specify the following intermediate tensors:\n";
349 for (auto& it: fIntermediateTensorInfos){
350 std::cout << "Tensor name: \"" << it.first << "\"\t";
351 std::cout << "type: " << ConvertTypeToString(it.second.type) << "\t";
352 std::cout << "shape: [";
353 for (size_t i = 0; i < it.second.shape.size(); i++){
354 std::cout << it.second.shape[i];
355 if (i < it.second.shape.size() - 1) std::cout << ",";
356 }
357 std::cout << "]" << std::endl;
358 }
359 }
360
361 void RModel::HeadInitializedTensors(std::string name, int n_print){
362 auto it = fInitializedTensors.find(name);
363 if (it == fInitializedTensors.end()){
364 std::cout << "Tensor " << name << " not found in model's intiialized tensor list" << std::endl;
365 return;
366 }
367
368 std::cout << "Tensor name: " << it->first << "\t";
369 std::cout << "type: " << ConvertTypeToString(it->second.fType) << "\t";
370 int length =1;
371 std::cout << "shape: [";
372 for (size_t i = 0; i < it->second.fShape.size(); i++){
373 std::cout << it->second.fShape[i];
374 length *= it->second.fShape[i];
375 if (i < it->second.fShape.size() - 1) std::cout << ",";
376 }
377 std::cout << "]" << std::endl;
378 bool ellipsis = true;
379 if (n_print > length){
380 n_print = length;
381 ellipsis = false;
382 }
383
384 std::cout << "data: [" << std::endl;
385 //switch(it->second.type){
386 // case ETensorType::FLOAT : {
387 if (it->second.fType == ETensorType::FLOAT) {
388 auto converted_data = std::static_pointer_cast<float>(it->second.fData).get();
389 for (int i =0; i < n_print; i++){
390 std::cout << converted_data[i];
391 if (i < n_print - 1) std::cout << " ,";
392 }
393 // break;
394 // }
395 }
396 if (ellipsis) std::cout << ", ...";
397 std::cout << "]" << std::endl;
398
399 }
400
401 void RModel::OutputGenerated(std::string filename){
402 if (filename == ""){
403 filename = fName + ".hxx";
404 }
405 std::ofstream f;
406 f.open(filename);
407 if (!f.is_open()){
408 throw std::runtime_error("tmva-sofie failed to open file for output generated inference code");
409 }
410 f << fGC;
411 f.close();
412 }
413
414 void RModel::Streamer(TBuffer &R__b){
415 if (R__b.IsReading()) {
416 RModel::Class()->ReadBuffer(R__b, this);
417 for(auto i=RModel::fInitializedTensors.begin(); i!=RModel::fInitializedTensors.end();++i){
418 i->second.CastPersistentToShared();
419 }
420 }
421 else {
422 for(auto i=RModel::fInitializedTensors.begin(); i!=RModel::fInitializedTensors.end();++i){
423 i->second.CastSharedToPersistent();
424 }
425 RModel::Class()->WriteBuffer(R__b, this);
426 }
427 }
428
429}//SOFIE
430}//Experimental
431}//TMVA
void Class()
Definition: Class.C:29
#define f(i)
Definition: RSha256.hxx:104
XFontStruct * id
Definition: TGX11.cxx:109
char name[80]
Definition: TGX11.cxx:110
int type
Definition: TGX11.cxx:121
Buffer base class used for serializing objects.
Definition: TBuffer.h:43
Bool_t IsReading() const
Definition: TBuffer.h:86
void AddOutputTensorNameList(std::vector< std::string > outputtensornames)
Definition: RModel.cxx:143
const ETensorType & GetTensorType(std::string name)
Definition: RModel.cxx:68
void AddIntermediateTensor(std::string tensor_name, ETensorType type, std::vector< std::size_t > shape)
Definition: RModel.cxx:134
std::unordered_set< std::string > fNeededBlasRoutines
Definition: RModel.hxx:40
bool CheckIfTensorAlreadyExist(std::string tensor_name)
Definition: RModel.cxx:89
std::vector< std::unique_ptr< ROperator > > fOperators
Definition: RModel.hxx:32
void AddInputTensorInfo(std::string input_name, ETensorType type, std::vector< Dim > shape)
Definition: RModel.cxx:96
std::unordered_map< std::string, TensorInfo > fIntermediateTensorInfos
Definition: RModel.hxx:29
std::unordered_map< std::string, TensorInfo > fReadyInputTensorInfos
Definition: RModel.hxx:27
void AddInitializedTensor(std::string tensor_name, ETensorType type, std::vector< std::size_t > shape, std::shared_ptr< void > data)
Definition: RModel.cxx:123
RModel & operator=(RModel &&other)
Definition: RModel.cxx:27
std::vector< std::string > fOutputTensorNames
Definition: RModel.hxx:30
std::unordered_set< std::string > fNeededStdLib
Definition: RModel.hxx:43
void AddOperator(std::unique_ptr< ROperator > op, int order_execution=-1)
Definition: RModel.cxx:115
void HeadInitializedTensors(std::string name, int n_print=50)
Definition: RModel.cxx:361
void OutputGenerated(std::string filename="")
Definition: RModel.cxx:401
const std::vector< size_t > & GetTensorShape(std::string name)
Definition: RModel.cxx:47
std::unordered_map< std::string, InputTensorInfo > fInputTensorInfos
Definition: RModel.hxx:26
std::shared_ptr< void > GetInitializedTensorData(std::string tensor_name)
Definition: RModel.cxx:158
std::unordered_map< std::string, InitializedTensor > fInitializedTensors
Definition: RModel.hxx:28
void UpdateInitializedTensor(std::string tensor_name, ETensorType type, std::vector< std::size_t > shape, std::shared_ptr< void > data)
Definition: RModel.cxx:149
static constexpr double second
std::string Clean_name(std::string input_tensor_name)
std::string ConvertTypeToString(ETensorType type)
create variable transformations