Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RModel.cxx
Go to the documentation of this file.
1#include <limits>
2#include <algorithm>
3#include <cctype>
4#include <memory>
5#include <string>
6
7#include "TFile.h"
8
9#include "TMVA/RModel.hxx"
10#include "TMVA/SOFIE_common.hxx"
11
12namespace TMVA {
13namespace Experimental {
14namespace SOFIE {
15
16std::underlying_type_t<Options> operator|(Options opA, Options opB) {
17 return static_cast<std::underlying_type_t<Options>>(opA) | static_cast<std::underlying_type_t<Options>>(opB);
18}
19std::underlying_type_t<Options> operator|(std::underlying_type_t<Options> opA, Options opB) {
20 return opA | static_cast<std::underlying_type_t<Options>>(opB);
21}
22
24 fInputTensorInfos = std::move(other.fInputTensorInfos);
25 fReadyInputTensorInfos = std::move(other.fReadyInputTensorInfos);
26 fOutputTensorNames = other.fOutputTensorNames;
27 fInputTensorNames = other.fInputTensorNames;
28 fOperators = std::move(other.fOperators);
29 fInitializedTensors = std::move(other.fInitializedTensors);
30 fIntermediateTensorInfos = std::move(other.fIntermediateTensorInfos);
31 fName = other.fName;
32 fFileName = other.fFileName;
33 fParseTime = other.fParseTime;
34 fGC = other.fGC;
35 fNeededBlasRoutines = other.fNeededBlasRoutines;
36 fNeededStdLib = other.fNeededStdLib;
37}
38
40 fInputTensorInfos = std::move(other.fInputTensorInfos);
41 fReadyInputTensorInfos = std::move(other.fReadyInputTensorInfos);
42 fOutputTensorNames = other.fOutputTensorNames;
43 fInputTensorNames = other.fInputTensorNames;
44 fOperators = std::move(other.fOperators);
45 fInitializedTensors = std::move(other.fInitializedTensors);
46 fIntermediateTensorInfos = std::move(other.fIntermediateTensorInfos);
47 fName = other.fName;
48 fFileName = other.fFileName;
49 fParseTime = other.fParseTime;
50 fGC = other.fGC;
51 fNeededBlasRoutines = other.fNeededBlasRoutines;
52 fNeededStdLib = other.fNeededStdLib;
53 return *this;
54}
55
56const std::vector<size_t>& RModel::GetTensorShape(std::string name) {
57 auto f = fReadyInputTensorInfos.find(name);
58 if (f != fReadyInputTensorInfos.end()) {
59 return f->second.shape;
60 }
61 auto f2 = fInitializedTensors.find(name);
62 if (f2 != fInitializedTensors.end()) {
63 return f2->second.fShape;
64 }
65 auto f3 = fInputTensorInfos.find(name);
66 if (f3 != fInputTensorInfos.end()) {
67 throw std::runtime_error("TMVA SOFIE tensor [" + name + "] is an input tensor with unspecified dimension parameter");
68 }
69 auto f4 = fIntermediateTensorInfos.find(name);
70 if (f4 != fIntermediateTensorInfos.end()) {
71 return f4->second.shape;
72 }
74 throw std::runtime_error("TMVA SOFIE tensor [" + name + "] is a dynamic tensor. Use GetDynamicTensorShape instead of GetTensorShape");
75
76 throw std::runtime_error("TMVA SOFIE tensor [" + name + "] for which the shape is requested is not found");
77}
78
79std::vector<Dim> RModel::GetDynamicTensorShape(std::string name) {
80 if (auto f = fDynamicTensorInfos.find(name); f != fDynamicTensorInfos.end()) {
81 return f->second.shape;
82 }
83 if (auto f = fInputTensorInfos.find(name); f != fInputTensorInfos.end()) {
84 return f->second.shape;
85 }
86 // in case is not a dynamic tensor convert normal shape to Dim one
87 // for this we need to return the vector by value
89}
90
92 auto f = fReadyInputTensorInfos.find(name);
93 if (f != fReadyInputTensorInfos.end()) {
94 return f->second.type;
95 }
96 auto f2 = fInitializedTensors.find(name);
97 if (f2 != fInitializedTensors.end()) {
98 return f2->second.fType;
99 }
100 auto f3 = fInputTensorInfos.find(name);
101 if (f3 != fInputTensorInfos.end()) {
102 return f3->second.type;
103 }
104 auto f4 = fIntermediateTensorInfos.find(name);
105 if (f4 != fIntermediateTensorInfos.end()) {
106 return f4->second.type;
107 }
108 auto f5 = fDynamicTensorInfos.find(name);
109 if (f5 != fDynamicTensorInfos.end()){
110 return f5->second.type;
111 }
112
113 throw std::runtime_error("TMVA SOFIE tensor [" + name + "] for which the type is requested is not found");
114}
115
116bool RModel::CheckIfTensorAlreadyExist(std::string tensor_name) {
117 if (fReadyInputTensorInfos.find(tensor_name) != fReadyInputTensorInfos.end()) return true;
118 if (fInputTensorInfos.find(tensor_name) != fInputTensorInfos.end()) return true;
119 if (fInitializedTensors.find(tensor_name) != fInitializedTensors.end()) return true;
120 if (fIntermediateTensorInfos.find(tensor_name) != fIntermediateTensorInfos.end()) return true;
121 if (fDynamicTensorInfos.find(tensor_name) != fDynamicTensorInfos.end()) return true;
122 return false;
123}
124
125void RModel::AddInputTensorInfo(std::string input_name, ETensorType type, std::vector<Dim> shape) {
126 input_name = UTILITY::Clean_name(input_name);
127 if (CheckIfTensorAlreadyExist(input_name)) {
128 throw std::runtime_error("TMVA-SOFIE: input tensor with name " + input_name + " already exists \n");
129 }
130
131 InputTensorInfo inputInfo { type, shape };
132 fInputTensorInfos[input_name] = inputInfo;
133}
134
135void RModel::AddInputTensorInfo(std::string input_name, ETensorType type, std::vector<size_t> shape) {
136 input_name = UTILITY::Clean_name(input_name);
137 if (CheckIfTensorAlreadyExist(input_name)) {
138 throw std::runtime_error("TMVA-SOFIE: input tensor with name " + input_name + " already exists \n");
139 }
140 TensorInfo inputInfo { type, shape };
141 fReadyInputTensorInfos[input_name] = inputInfo;
142}
143
144void RModel::AddInputTensorName(std::string input_name) {
145 fInputTensorNames.push_back(UTILITY::Clean_name(input_name));
146}
147
148void RModel::AddOperator(std::unique_ptr<ROperator> op, int order_execution) {
149 AddBlasRoutines(op->GetBlasRoutines());
150 auto libs = op->GetStdLibs();
151 for (auto& stdlib : libs) {
152 AddNeededStdLib(stdlib);
153 }
154 if (order_execution >= 0) {
155 fOperators.insert(fOperators.begin() + order_execution, std::move(op));
156 } else {
157 fOperators.push_back(std::move(op));
158 }
159}
160
161void RModel::AddInitializedTensor(std::string tensor_name, ETensorType type, std::vector<std::size_t> shape, std::shared_ptr<void> data) {
162 tensor_name = UTILITY::Clean_name(tensor_name);
163 //NB: own data
164 if (CheckIfTensorAlreadyExist(tensor_name)) {
165 throw std::runtime_error("TMVA-SOFIE: initialized tensor with name " + tensor_name + " already exists \n");
166 }
167 InitializedTensor new_tensor {type, shape, data};
168 fInitializedTensors[tensor_name] = new_tensor;
169
170}
171
172bool RModel::IsInitializedTensor(const std::string& tensorName) const {
173 std::string name = UTILITY::Clean_name(tensorName);
174 return fInitializedTensors.find(name) != fInitializedTensors.end();
175}
176
177bool RModel::IsDynamicTensor(const std::string& tensorName) const {
178 std::string name = UTILITY::Clean_name(tensorName);
179 return fDynamicTensorInfos.find(name) != fDynamicTensorInfos.end();
180}
181bool RModel::IsInputTensor(const std::string& tensorName) const {
182 std::string name = UTILITY::Clean_name(tensorName);
183 return fInputTensorInfos.find(name) != fInputTensorInfos.end();
184}
185
186// generic addition of a tensor
187void RModel::AddIntermediateTensor(std::string tensor_name, ETensorType type, std::vector<Dim> dim_shape) {
188 auto int_shape = ConvertShapeToInt(dim_shape);
189 if (!int_shape.empty())
190 AddIntermediateTensor(tensor_name, type, int_shape);
191 else
192 AddDynamicTensor(tensor_name, type, dim_shape);
193}
194
195void RModel::AddIntermediateTensor(std::string tensor_name, ETensorType type, std::vector<std::size_t> shape) {
196 tensor_name = UTILITY::Clean_name(tensor_name);
197 if (CheckIfTensorAlreadyExist(tensor_name)) {
198 throw std::runtime_error("TMVA-SOFIE: intermediate tensor with name " + tensor_name + " already exists \n");
199 }
200 TensorInfo new_tensor {type, shape};
201 fIntermediateTensorInfos[tensor_name] = new_tensor;
202}
203
204void RModel::AddDynamicTensor(std::string tensor_name, ETensorType type, std::vector<Dim> shape){
205 tensor_name = UTILITY::Clean_name(tensor_name);
206 if (CheckIfTensorAlreadyExist(tensor_name)){
207 throw std::runtime_error("TMVA-SOFIE: intermediate tensor with name " + tensor_name + " already exists \n");
208 }
209 DynamicTensorInfo new_tensor {type, shape};
210 fDynamicTensorInfos[tensor_name] = new_tensor;
211 // store shape parameter if not existing
212 for (auto &d : shape) {
213 if (d.isParam) {
214 if (fShapeParams.count(d.param) == 0) {
215 // case parameter is an expression of some other existing parameter, no need to
216 // register it
217 if (d.dim != size_t(-1)) {
218 fShapeParams[d.param] = std::to_string(d.dim);
219 }
220 }
221 }
222 }
223}
224
225void RModel::AddOutputTensorNameList(std::vector<std::string> outputtensornames) {
226 fOutputTensorNames.clear();
227 for(auto& it : outputtensornames) {
229 }
230}
231
232void RModel::UpdateOutputTensorList(std::vector<std::string> curr_output_tensors, std::vector<std::string> new_output_tensors) {
233 for(auto& it:curr_output_tensors) {
234 fOutputTensorNames.erase(std::remove(fOutputTensorNames.begin(), fOutputTensorNames.end(), it), fOutputTensorNames.end());
235 }
236 fOutputTensorNames.insert(fOutputTensorNames.end(), new_output_tensors.begin(), new_output_tensors.end());
237}
238
239void RModel::UpdateInitializedTensor(std::string tensor_name, ETensorType type, std::vector<std::size_t> shape, std::shared_ptr<void> data) {
240 tensor_name = UTILITY::Clean_name(tensor_name);
241 if (!CheckIfTensorAlreadyExist(tensor_name)) {
242 throw std::runtime_error("TMVA-SOFIE: tensor " + tensor_name + " not found when trying to update it");
243 }
244 InitializedTensor new_tensor {type, shape, data};
245 fInitializedTensors[tensor_name] = new_tensor;
246}
247
248std::shared_ptr<void> RModel::GetInitializedTensorData(std::string tensor_name) {
249 auto f = fInitializedTensors.find(tensor_name);
250 if (f == fInitializedTensors.end()) {
251 throw std::runtime_error("TMVA-SOFIE: tensor " + tensor_name + " not found when trying to get its data");
252 } else {
253 return f->second.fData;
254 }
255}
256
257void RModel::Initialize(int batchSize, bool verbose) {
258
260 fDynamicTensorInfos.clear();
261
262 // loop on inputs and see if shape can be full specified
263 // if the batch size is provided it can be used to specify the full shape
264 // Add the full specified tensors in fReadyInputTensors collection
265 for (auto &input : fInputTensorInfos) {
266 // if a batch size is provided convert batch size
267 // assume is parametrized as "bs" or "batch_size"
268 if (batchSize > 0) {
269 // std::vector<Dim> shape;
270 // shape.reserve(input.second.shape.size());
271 for (auto &d : input.second.shape) {
272 if (d.isParam && (d.param == "bs" || d.param == "batch_size")) {
273 d = Dim{static_cast<size_t>(batchSize)};
274 }
275 }
276 }
277 auto shape = ConvertShapeToInt(input.second.shape);
278 if (!shape.empty()) {
279 // add to the ready input tensor informations
280 AddInputTensorInfo(input.first, input.second.type, shape);
281 // remove from the tensor info
282 fInputTensorInfos.erase(input.first);
283 }
284 // store the parameters of the input tensors
285 else {
286 // store the found parametric shape parameters
287 for (auto &d : input.second.shape) {
288 if (d.isParam)
289 fShapeParams[d.param] = std::to_string(d.dim);
290 }
291 }
292 }
293
294 if (verbose) {
297 }
298
299 // check if there are initialized tensors to write in a weight file
300 // support for the time being only weight of FLOAT type
301 if (fUseWeightFile) {
302 bool modelHasWeights = false;
303 for (auto &i : fInitializedTensors) {
304 if (i.second.fType == ETensorType::FLOAT) {
305 modelHasWeights = true;
306 break;
307 }
308 }
309 if (!modelHasWeights)
310 fUseWeightFile = false;
311 }
312 // Go through model and initialize each operator
313 int i = 0;
314 for (auto &op : fOperators) {
315 if (verbose) {
316 auto& r = *op.get();
317 std::cout << "Initializing operator " << i << " " << typeid(r).name() << std::endl;
318 }
319 op->Initialize(*this);
320 i++;
321 }
322}
323
325 for (auto& i: fInitializedTensors) {
326 if (i.second.fType == ETensorType::FLOAT) {
327 size_t length = 1;
328 for (auto & dim: i.second.fShape) {
329 length *= dim;
330 }
331 if (!fUseWeightFile) {
332 fGC += "float tensor_" + i.first + "[" + std::to_string(length) + "] = {";
333 std::shared_ptr<float> data = std::static_pointer_cast<float>(i.second.fData);
334 std::stringstream floats;
335 for (size_t idx = 0; idx < length-1; idx++) {
336 floats << std::setprecision(std::numeric_limits<float>::max_digits10) << data.get()[idx] << ", ";
337 }
338 floats << std::setprecision(std::numeric_limits<float>::max_digits10) << data.get()[length-1];
339 fGC += floats.str();
340 fGC += "};\n";
341 }
342 else {
343 fGC += "std::vector<float> fTensor_" + i.first + " = std::vector<float>(" + std::to_string(length) + ");\n";
344 fGC += "float * tensor_" + i.first + " = fTensor_" + i.first + ".data();\n";
345 }
346
347 }
348 }
349}
350
352 if (!fIntermediateTensorInfos.empty()) {
353 fGC += "\n//--- declare and allocate the intermediate tensors\n";
354 for (auto &i : fIntermediateTensorInfos) {
355 size_t length = ConvertShapeToLength(i.second.shape);
356 if (i.second.type == ETensorType::FLOAT) {
357 fGC += "std::vector<float> fTensor_" + i.first + " = std::vector<float>(" + std::to_string(length) + ");\n";
358 fGC += "float * tensor_" + i.first + " = fTensor_" + i.first + ".data();\n";
359 }
360 if (i.second.type == ETensorType::DOUBLE) {
361 fGC += "std::vector<double> fTensor_" + i.first + " = std::vector<double>(" + std::to_string(length) + ");\n";
362 fGC += "double * tensor_" + i.first + " = fTensor_" + i.first + ".data();\n";
363 }
364 if (i.second.type == ETensorType::INT64) {
365 fGC += "std::vector<int64_t> fTensor_" + i.first + " = std::vector<int64_t>(" + std::to_string(length) + ");\n";
366 fGC += "int64_t * tensor_" + i.first + " = fTensor_" + i.first + ".data();\n";
367 }
368 if (i.second.type == ETensorType::BOOL) {
369 fGC += "std::vector<bool> fTensor_" + i.first + " = std::vector<bool>(" + std::to_string(length) + ");\n";
370 // don't allocate pointer since boolean vector don't have the .data() member
371 }
372 }
373 }
374 // add also the dynamic tensors (only declarations, allocation will be done later)
375 if (!fDynamicTensorInfos.empty()) {
376 fGC += "//--- declare the dynamic tensors\n";
377 for (auto &i : fDynamicTensorInfos) {
378 if (i.second.type == ETensorType::FLOAT) {
379 fGC += "std::vector<float> fTensor_" + i.first + ";\n";
380 fGC += "float * tensor_" + i.first + " = nullptr;\n";
381 } else if (i.second.type == ETensorType::DOUBLE) {
382 fGC += "std::vector<double> fTensor_" + i.first + ";\n";
383 fGC += "double * tensor_" + i.first + " = nullptr;\n";
384 } else if (i.second.type == ETensorType::INT64) {
385 fGC += "std::vector<int64_t> fTensor_" + i.first + ";\n";
386 fGC += "int64_t * tensor_" + i.first + " = nullptr;\n";
387 }
388 }
389 }
390}
391
393 fGC += "//---- allocate the intermediate dynamic tensors\n";
394 std::stringstream out;
395 for (auto & i: fDynamicTensorInfos) {
396 auto length = ConvertDynamicShapeToLength(i.second.shape);
397 out << SP << "if (" << length << " > 0) {\n";
398 out << SP << SP << "fTensor_" << i.first << ".resize(" << length << ");\n";
399 out << SP << SP << "tensor_" << i.first << " = fTensor_" << i.first << ".data();\n";
400 out << SP << "}\n";
401 }
402 fGC += out.str();
403}
404
406
407 size_t outputSize = fOutputTensorNames.size();
408 // assume output types are all the same
409 if (outputSize == 0)
410 throw std::runtime_error("TMVA-SOFIE: output size=0 are not supported");
411
412 std::string outputType;
413 ETensorType eOutputType;
414 eOutputType = GetTensorType(fOutputTensorNames[0]);
415 outputType = ConvertTypeToString(eOutputType);
416 if (outputSize == 1) {
417 fGC += "std::vector<" + outputType + "> ";
418 } else {
419 // we assume all output types are the same
420 for (size_t i = 1; i < outputSize; i++) {
421 if (GetTensorType(fOutputTensorNames[i]) != eOutputType)
422 throw std::runtime_error("TMVA-SOFIE: different output tensor types are not supported");
423 }
424 fGC += "std::vector<std::vector<" + outputType + ">> ";
425 }
426
427 fGC += "infer(";
428
429 std::unordered_map<std::string, int> inputParams;
430 int i_input = 0;
431 for (auto &name : fInputTensorNames) {
432 // if is a dynamic tensor pass initial parameters
433 if (IsInputTensor(name)) {
434 auto shape = GetDynamicTensorShape(name);
435 for (auto &d : shape) {
436 std::string pName = d.param;
437 // need to check if the input parameters is already existing in another input tensor
438 if (d.isParam && inputParams.count(pName) == 0) {
439 fGC += "size_t " + d.param + ",";
440 inputParams[pName] = i_input;
441 }
442 }
443 }
444 switch (GetTensorType(name)) {
445 case ETensorType::FLOAT: {
446 fGC += "float* tensor_" + name + ",";
447 break;
448 }
449 case ETensorType::INT32: {
450 fGC += "int32_t* tensor_" + name + ",";
451 break;
452 }
453 case ETensorType::INT64: {
454 fGC += "int64_t* tensor_" + name + ",";
455 break;
456 }
457 case ETensorType::DOUBLE: {
458 fGC += "double* tensor_" + name + ",";
459 break;
460 }
461 case ETensorType::BOOL: {
462 fGC += "bool* tensor_" + name + ",";
463 break;
464 }
465 default: {
466 throw std::runtime_error("TMVA-SOFIE: input tensor " + name +
467 " is of a data type which is not yet supported.");
468 }
469 }
470 i_input++;
471 }
472
473 fGC.pop_back(); // remove last ","
474 fGC += "){\n";
475
476 for (size_t id = 0; id < fOperators.size(); id++) {
477 fGC += (fOperators[id]->Generate(std::to_string(id)));
478 }
479
480 if (outputSize == 1) {
481 std::string tensorName = fOutputTensorNames[0];
482 if (fIntermediateTensorInfos.count(tensorName) > 0) {
483 // need to check is size is the same(don't want to return a vector with larger size)
484 // in that case better to copy
485 fGC += SP + "return fTensor_" + tensorName + ";\n";
486 } else {
487 // include also dynamic tensors since the vectors can be allocated with a size larger than their output
488 // we need a special handling for bool type allocated as vector<bool>
489 auto outputLength = ConvertDynamicShapeToLength(GetDynamicTensorShape(tensorName));
490 if (IsDynamicTensor(tensorName) && eOutputType == ETensorType::BOOL) {
491 fGC += SP + "std::vector<bool> ret (fTensor_" + tensorName + ".begin(), fTensor_" + tensorName +
492 ".begin() + " + outputLength + ");\n";
493 } else {
494 fGC += SP + "std::vector<" + outputType + "> ret (tensor_" + tensorName + ", tensor_" + tensorName + " + " +
495 outputLength + ");\n";
496 }
497 fGC += SP + "return ret;\n";
498 }
499 } else {
500 // here we assume all outputs have same type
501 fGC += SP + "std::vector<std::vector<" + outputType + ">> ret({";
502 for (size_t i = 0; i < outputSize; i++) {
503 std::string tensorName = fOutputTensorNames[i];
504 if (!tensorName.empty()) {
505 if (fIntermediateTensorInfos.count(tensorName) > 0) {
506 fGC += "fTensor_" + tensorName;
507 } else {
508 auto outputLength = ConvertDynamicShapeToLength(GetDynamicTensorShape(tensorName));
509 if (IsDynamicTensor(tensorName) && eOutputType == ETensorType::BOOL) {
510 fGC += "std::vector<bool>(fTensor_" + tensorName + ".begin(), fTensor_" + tensorName + ".begin() + " +
511 outputLength + ");\n";
512 } else {
513 fGC += "std::vector<" + outputType + ">(tensor_" + tensorName + ", tensor_" + tensorName + " + " +
514 outputLength + ")";
515 }
516 }
517 if (i < outputSize - 1)
518 fGC += ",";
519 } else {
520 fGC += "{}";
521 }
522 }
523 fGC += "});\n";
524 fGC += SP + "return ret;\n";
525 }
526 fGC += "}\n";
527}
528
529void RModel::Generate(std::underlying_type_t<Options> options, int batchSize, long pos) {
530 // session flag is used in operator initialize
531 if (static_cast<std::underlying_type_t<Options>>(Options::kNoSession) & options) {
532 fUseSession = false;
534 }
535 if (static_cast<std::underlying_type_t<Options>>(Options::kNoWeightFile) & options) {
536 fUseWeightFile = false;
538 }
539 if (static_cast<std::underlying_type_t<Options>>(Options::kRootBinaryWeightFile) & options) {
540 fUseWeightFile = true;
542 }
543 if (fUseWeightFile && !fUseSession) {
544 throw
545 std::runtime_error("TMVA-SOFIE: RModel::Generate: cannot use a separate weight file without generating a Session class");
546 }
547
548 if (static_cast<std::underlying_type_t<Options>>(Options::kGNN) & options)
549 fIsGNN = true;
550 if (static_cast<std::underlying_type_t<Options>>(Options::kGNNComponent) & options)
551 fIsGNNComponent = true;
552
553 Initialize(batchSize);
554 std::string hgname;
555 if(!fIsGNNComponent) {
556 fGC.clear();
557 GenerateHeaderInfo(hgname);
558 if (fUseSession) {
559 fGC += "struct Session {\n";
560 }
561 }
562
565
566 if (fUseSession) {
567 // add here specific operator code that needs to define session data members
568 fGC += "\n";
569 for (size_t id = 0; id < fOperators.size(); id++) {
570 std::string opName = std::to_string(id);
571 fGC += fOperators[id]->GenerateSessionMembersCode(opName);
572 }
573 fGC += "\n";
574 // here add initialization and reading of weight tensors
575 if (fUseWeightFile) {
576 std::string fileName = fName;
578 fileName += ".dat";
579 }
581 fileName += ".root";
582 }
583 fGC += "Session(std::string filename =\"" + fileName + "\"";
584 } else {
585 // no need to pass weight file since it is not used
586 // keep passing a string for compatibility
587 fGC += "Session(std::string = \"\"";
588 }
589 // add initialization of shape parameters
590 // assume all parameters are of type size_t
591 if (!fShapeParams.empty()) {
592 for (auto & p : fShapeParams) {
593 fGC += ",\n";
594 fGC += " size_t " + p.first + " = " + p.second;
595 }
596 }
597 fGC += ") {\n";
598
599 if (fUseWeightFile) {
600 fGC += "\n//--- reading weights from file\n";
602 fGC += "\n";
603 //fUseWeightFile = fUseWeightFile;
604 }
605
606 // now we have passed the parameters we can allocate the dynamic tensors
608
609 // add here initialization code for operator
610 for (size_t id = 0; id < fOperators.size() ; id++) {
611 fGC += fOperators[id]->GenerateInitCode();
612 }
613
614 fGC += "}\n\n";
615 }
616
618
619 if(!fIsGNNComponent) {
620 if (fUseSession) {
621 fGC += "};\n";
622 }
623 fGC += ("} //TMVA_SOFIE_" + fName + "\n");
624 fGC += "\n#endif // " + hgname + "\n";
625 }
626}
627
629 // generate the code to read initialized tensors from a text data file
631 if (fInitializedTensors.empty()) return;
632
633 fGC += " std::ifstream f;\n";
634 fGC += " f.open(filename);\n";
635 fGC += " if (!f.is_open()) {\n";
636 fGC += " throw std::runtime_error(\"tmva-sofie failed to open file for input weights\");\n";
637 fGC += " }\n";
638
639 if(fIsGNNComponent) {
640 fGC += " f.seekg(" + std::to_string(pos) + ");\n";
641 }
642
643 fGC += " std::string tensor_name;\n";
644 fGC += " size_t length;\n";
645
646 // loop on tensors and parse the file
647 for (auto& i: fInitializedTensors) {
648 if (i.second.fType == ETensorType::FLOAT) {
649 size_t length = 1;
650 length = ConvertShapeToLength(i.second.fShape);
651 std::string tensor_name = "tensor_" + i.first;
652 std::string slength = std::to_string(length);
653 fGC += " f >> tensor_name >> length;\n";
654 fGC += " if (tensor_name != \"" + tensor_name + "\" ) {\n";
655 fGC += " std::string err_msg = \"TMVA-SOFIE failed to read the correct tensor name; expected name is " +
656 tensor_name + " , read \" + tensor_name;\n";
657 fGC += " throw std::runtime_error(err_msg);\n";
658 fGC += " }\n";
659 fGC += " if (length != " + slength + ") {\n";
660 fGC += " std::string err_msg = \"TMVA-SOFIE failed to read the correct tensor size; expected size is " +
661 slength + " , read \" + std::to_string(length) ;\n";
662 fGC += " throw std::runtime_error(err_msg);\n";
663 fGC += " }\n";
664 fGC += " for (size_t i = 0; i < length; ++i)\n";
665 fGC += " f >> " + tensor_name + "[i];\n";
666 }
667 }
668 fGC += " f.close();\n";
669 }
670
671 // generate the code to read initialized tensors from a ROOT data file
673 fGC += " {\n";
674 fGC += " std::unique_ptr<TFile> rootFile(TFile::Open(filename.c_str(), \"READ\"));\n";
675 fGC += " if (!rootFile->IsOpen()) {\n";
676 fGC += " throw std::runtime_error(\"tmva-sofie failed to open ROOT file for input weights\");\n";
677 fGC += " }\n";
678
679 std::string dirName = fName + "_weights";
680 fGC += " if (!rootFile->GetKey(\"" + dirName + "\")) {\n";
681 fGC += " throw std::runtime_error(\"tmva-sofie failed to open ROOT directory for input weights\");\n";
682 fGC += " }\n";
683
684 for (auto &i : fInitializedTensors) {
685 fGC += " {\n";
686 std::string tensor_name = "tensor_" + i.first;
687 if (i.second.fType == ETensorType::FLOAT) {
688 fGC += " fTensor_" + i.first + " = *reinterpret_cast<std::vector<float>*>(rootFile->Get(\"";
689 fGC += dirName + "/" + tensor_name + "\"));\n";
690 } else if (i.second.fType == ETensorType::DOUBLE) {
691 fGC += " fTensor_" + i.first + " = *reinterpret_cast<std::vector<double>*>(rootFile->Get(\"";
692 fGC += dirName + + "/" + tensor_name + "\"));\n";
693 } else if (i.second.fType == ETensorType::INT64) {
694 fGC += " fTensor_" + i.first + " = *reinterpret_cast<std::vector<int64_t>*>(rootFile->Get(\"";
695 fGC += dirName + "/" + tensor_name + "\"));\n";
696 }
697 fGC += " }\n";
698 }
699 fGC += " }\n";
700 }
701}
702
704 // Determine the file extension based on the weight file type
705 std::string fileExtension;
706 switch (fWeightFile) {
708 fileExtension = ".dat";
709 break;
711 fileExtension = ".root";
712 break;
714 fileExtension = ".dat";
715 break;
716 }
717
718 // If filename is empty, use the model name as the base filename
719 if (filename.empty()) {
720 filename = fFileName + fileExtension;
721 }
722
723 // Write the initialized tensors to the file
725 if(fIsGNNComponent || fIsGNN) {
726 throw std::runtime_error("SOFIE-GNN yet not supports writing to a ROOT file.");
727 }
728 std::unique_ptr<TFile> outputFile(TFile::Open(filename.c_str(), "UPDATE"));
729
730 std::string dirName = fName + "_weights";
731 // check if directory exists, in case delete to replace with new one
732 if (outputFile->GetKey(dirName.c_str()))
733 outputFile->rmdir(dirName.c_str());
734
735 auto outputDir = outputFile->mkdir(dirName.c_str());
736
737 for (const auto& item : fInitializedTensors) {
738 std::string tensorName = "tensor_" + item.first;
739 size_t length = 1;
740 length = ConvertShapeToLength(item.second.fShape);
741 if(item.second.fType == ETensorType::FLOAT) {
742 const std::shared_ptr<void> ptr = item.second.fData; // shared_ptr<void> instance
743 const float* data = (std::static_pointer_cast<float>(item.second.fData)).get();
744 std::vector<float> tensorDataVector(data, data + length);
745 outputDir->WriteObjectAny(&tensorDataVector, "std::vector<float>", tensorName.c_str());
746 }
747 else if(item.second.fType == ETensorType::DOUBLE) {
748 const std::shared_ptr<void> ptr = item.second.fData; // shared_ptr<void> instance
749 const double* data = (std::static_pointer_cast<double>(item.second.fData)).get();
750 std::vector<double> tensorDataVector(data, data + length);
751 outputDir->WriteObjectAny(&tensorDataVector, "std::vector<double>", tensorName.c_str());
752 }
753 else if(item.second.fType == ETensorType::INT64) {
754 const std::shared_ptr<void> ptr = item.second.fData; // shared_ptr<void> instance
755 const int64_t* data = (std::static_pointer_cast<int64_t>(item.second.fData)).get();
756 std::vector<int64_t> tensorDataVector(data, data + length);
757 outputDir->WriteObjectAny(&tensorDataVector, "std::vector<int64_t>", tensorName.c_str());
758 }
759 }
760 outputFile->Write(filename.c_str());
761
762 // this needs to be changed, similar to the text file
763 return -1;
764
765 } else if (fWeightFile == WeightFileType::Text) {
766 std::ofstream f;
767 if(fIsGNNComponent) {
768 // appending all GNN components into the same file
769 f.open(filename, std::ios::app);
770 } else {
771 f.open(filename);
772 }
773 if (!f.is_open())
774 throw
775 std::runtime_error("tmva-sofie failed to open file for tensor weight data");
776 for (auto& i: fInitializedTensors) {
777 if (i.second.fType == ETensorType::FLOAT) {
778 size_t length = 1;
779 for (auto &dim : i.second.fShape) {
780 length *= dim;
781 }
782 std::string tensor_name = "tensor_" + i.first;
783 f << tensor_name << " " << length << "\n";
784 const float * data = (std::static_pointer_cast<float>(i.second.fData)).get();
785 for (size_t idx = 0; idx < length - 1; idx++) {
786 f << std::setprecision(std::numeric_limits<float>::max_digits10) << data[idx] << " ";
787 }
788 f << std::setprecision(std::numeric_limits<float>::max_digits10) << data[length - 1];
789 f << "\n";
790 }
791 }
792 long curr_pos = f.tellp();
793 f.close();
794 return curr_pos;
795 } else {
796 return -1;
797 }
798}
799
801 std::cout << "Model requires following inputs:\n";
802 for (auto& inputInfo: fInputTensorInfos) {
803 std::cout << "Parameterised Tensor name: " << inputInfo.first << "\t";
804 std::cout << "type: " << ConvertTypeToString(inputInfo.second.type) << "\t";
805 std::cout << "shape: [";
806 for (size_t i = 0; i < inputInfo.second.shape.size(); i++) {
807 if (inputInfo.second.shape[i].isParam) {
808 std::cout << inputInfo.second.shape[i].param;
809 } else {
810 std::cout << inputInfo.second.shape[i].dim ;
811 }
812 if (i < inputInfo.second.shape.size() - 1) std::cout << ",";
813 }
814 std::cout << "]" << std::endl;
815 }
816
817 for (auto& inputInfo: fReadyInputTensorInfos) {
818 std::cout << "Fully Specified Tensor name: " << inputInfo.first << "\t";
819 std::cout << "type: " << ConvertTypeToString(inputInfo.second.type) << "\t";
820 std::cout << "shape: [";
821 for (size_t i = 0; i < inputInfo.second.shape.size(); i++) {
822 std::cout << inputInfo.second.shape[i];
823 if (i < inputInfo.second.shape.size() - 1) std::cout << ",";
824 }
825 std::cout << "]" << std::endl;
826 }
827 std::cout << "\n";
828}
829
831 std::cout << "Model initialized the following tensors:\n";
832 for (auto& it: fInitializedTensors) {
833 std::cout << "Tensor name: \"" << it.first << "\"\t";
834 std::cout << "type: " << ConvertTypeToString(it.second.fType) << "\t";
835 std::cout << "shape: [";
836 for (size_t i = 0; i < it.second.fShape.size(); i++) {
837 std::cout << it.second.fShape[i];
838 if (i < it.second.fShape.size() - 1) std::cout << ",";
839 }
840 std::cout << "]" << std::endl;
841 }
842 std::cout << "\n";
843}
844
846 std::cout << "Model specify the following intermediate tensors:\n";
847 for (auto& it: fIntermediateTensorInfos) {
848 std::cout << "Tensor name: \"" << it.first << "\"\t";
849 std::cout << "type: " << ConvertTypeToString(it.second.type) << "\t";
850 std::cout << "shape: [";
851 for (size_t i = 0; i < it.second.shape.size(); i++) {
852 std::cout << it.second.shape[i];
853 if (i < it.second.shape.size() - 1) std::cout << ",";
854 }
855 std::cout << "]" << std::endl;
856 }
857 std::cout << "\n";
858}
859
861 std::cout << "Model specify the following dynamic tensors:\n";
862 for (auto& it: fDynamicTensorInfos) {
863 std::cout << "Tensor name: \"" << it.first << "\"\t";
864 std::cout << "type: " << ConvertTypeToString(it.second.type) << "\t";
865 std::cout << "shape: [";
866 for (size_t i = 0; i < it.second.shape.size(); i++) {
867 std::cout << it.second.shape[i].GetVal();
868 if (i < it.second.shape.size() - 1) std::cout << ",";
869 }
870 std::cout << "]" << std::endl;
871 }
872 std::cout << "\n";
873}
874
876 std::cout << "Model specify the following output tensors:\n";
877 for (auto& it: fOutputTensorNames) {
878 std::cout << "Tensor name: \"" << it << "\"\t";
879 if (!IsDynamicTensor(it))
880 std::cout << "shape: " << ConvertShapeToString(GetTensorShape(it)) << std::endl;
881 else
882 std::cout << "shape: " << ConvertDynamicShapeToString(GetDynamicTensorShape(it)) << std::endl;
883 }
884 std::cout << "\n";
885}
886
887void RModel::HeadInitializedTensors(std::string name, int n_print) {
888 auto it = fInitializedTensors.find(name);
889 if (it == fInitializedTensors.end()) {
890 std::cout << "Tensor " << name << " not found in model's initialized tensor list" << std::endl;
891 return;
892 }
893
894 std::cout << "Tensor name: " << it->first << "\t";
895 std::cout << "type: " << ConvertTypeToString(it->second.fType) << "\t";
896 int length =1;
897 std::cout << "shape: [";
898 for (size_t i = 0; i < it->second.fShape.size(); i++) {
899 std::cout << it->second.fShape[i];
900 length *= it->second.fShape[i];
901 if (i < it->second.fShape.size() - 1) std::cout << ",";
902 }
903 std::cout << "]" << std::endl;
904 bool ellipsis = true;
905 if (n_print > length) {
906 n_print = length;
907 ellipsis = false;
908 }
909
910 std::cout << "data: [" << std::endl;
911 if (it->second.fType == ETensorType::FLOAT) {
912 auto converted_data = std::static_pointer_cast<float>(it->second.fData).get();
913 for (int i =0; i < n_print; i++) {
914 std::cout << converted_data[i];
915 if (i < n_print - 1) std::cout << " ,";
916 }
917 }
918 if (ellipsis) std::cout << ", ...";
919 std::cout << "]" << std::endl;
920
921}
922
923void RModel::OutputGenerated(std::string filename, bool append) {
924
926
927 // write weights in a text file
928 if (fUseWeightFile) {
929 if (!filename.empty()) {
930 size_t pos = filename.find(".hxx");
932 filename.replace(pos, 4, ".dat");
934 filename = filename.erase(pos, 4);
935 filename += ".root";
936 }
937 } else {
938 filename = fName;
939 filename += fWeightFile == WeightFileType::Text ? ".dat" : ".root";
940 }
942 }
943}
944
945void RModel::Streamer(TBuffer &R__b) {
946 if (R__b.IsReading()) {
947 RModel::Class()->ReadBuffer(R__b, this);
948 for(auto i=RModel::fInitializedTensors.begin(); i!=RModel::fInitializedTensors.end(); ++i) {
949 i->second.CastPersistentToShared();
950 }
951 }
952 else {
953 for(auto i=RModel::fInitializedTensors.begin(); i!=RModel::fInitializedTensors.end(); ++i) {
954 i->second.CastSharedToPersistent();
955 }
956 RModel::Class()->WriteBuffer(R__b, this);
957 }
958}
959
960}//SOFIE
961}//Experimental
962}//TMVA
#define d(i)
Definition RSha256.hxx:102
#define f(i)
Definition RSha256.hxx:104
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 filename
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void data
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
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 length
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize id
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 Atom_t Time_t type
char name[80]
Definition TGX11.cxx:110
Buffer base class used for serializing objects.
Definition TBuffer.h:43
Bool_t IsReading() const
Definition TBuffer.h:86
Int_t ReadBuffer(TBuffer &b, void *pointer, Int_t version, UInt_t start, UInt_t count)
Function called by the Streamer functions to deserialize information from buffer b into object at p.
Definition TClass.cxx:6758
Int_t WriteBuffer(TBuffer &b, void *pointer, const char *info="")
Function called by the Streamer functions to serialize object at p to buffer b.
Definition TClass.cxx:6779
static TFile * Open(const char *name, Option_t *option="", const char *ftitle="", Int_t compress=ROOT::RCompressionSetting::EDefaults::kUseCompiledDefault, Int_t netopt=0)
Create / open a file.
Definition TFile.cxx:4067
void GenerateHeaderInfo(std::string &hgname)
std::unordered_set< std::string > fNeededBlasRoutines
void OutputGenerated(std::string filename="", bool append=false)
std::unordered_set< std::string > fNeededStdLib
void AddBlasRoutines(std::vector< std::string > routines)
void AddNeededStdLib(std::string libname)
const ETensorType & GetTensorType(std::string name)
Definition RModel.cxx:91
std::unordered_map< std::string, DynamicTensorInfo > fDynamicTensorInfos
Definition RModel.hxx:20
bool IsDynamicTensor(const std::string &name) const
Definition RModel.cxx:177
void AddIntermediateTensor(std::string tensor_name, ETensorType type, std::vector< Dim > dim_shape)
Definition RModel.cxx:187
std::vector< Dim > GetDynamicTensorShape(std::string name)
Definition RModel.cxx:79
bool CheckIfTensorAlreadyExist(std::string tensor_name)
Definition RModel.cxx:116
std::vector< std::unique_ptr< ROperator > > fOperators
Definition RModel.hxx:25
void OutputGenerated(std::string filename="", bool append=false)
Definition RModel.cxx:923
void AddInputTensorInfo(std::string input_name, ETensorType type, std::vector< Dim > shape)
Definition RModel.cxx:125
std::unordered_map< std::string, TensorInfo > fIntermediateTensorInfos
Definition RModel.hxx:19
void AddOutputTensorNameList(std::vector< std::string > output_tensor_names)
Definition RModel.cxx:225
std::unordered_map< std::string, TensorInfo > fReadyInputTensorInfos
Definition RModel.hxx:17
void AddDynamicTensor(std::string tensor_name, ETensorType type, std::vector< Dim > shape)
Definition RModel.cxx:204
void AddInitializedTensor(std::string tensor_name, ETensorType type, std::vector< std::size_t > shape, std::shared_ptr< void > data)
Definition RModel.cxx:161
RModel & operator=(RModel &&other)
Definition RModel.cxx:39
void AddInputTensorName(std::string name)
Definition RModel.cxx:144
std::vector< std::string > fOutputTensorNames
Definition RModel.hxx:22
bool IsInitializedTensor(const std::string &name) const
Definition RModel.cxx:172
void AddOperator(std::unique_ptr< ROperator > op, int order_execution=-1)
Definition RModel.cxx:148
void HeadInitializedTensors(std::string name, int n_print=50)
Definition RModel.cxx:887
void Initialize(int batchSize=-1, bool verbose=false)
Definition RModel.cxx:257
const std::vector< size_t > & GetTensorShape(std::string name)
Definition RModel.cxx:56
bool IsInputTensor(const std::string &name) const
Definition RModel.cxx:181
long WriteInitializedTensorsToFile(std::string filename="")
Definition RModel.cxx:703
void Generate(std::underlying_type_t< Options > options, int batchSize=-1, long pos=0)
Definition RModel.cxx:529
std::unordered_map< std::string, InputTensorInfo > fInputTensorInfos
Definition RModel.hxx:16
std::shared_ptr< void > GetInitializedTensorData(std::string tensor_name)
Definition RModel.cxx:248
std::unordered_map< std::string, std::string > fShapeParams
Definition RModel.hxx:21
std::vector< std::string > fInputTensorNames
Definition RModel.hxx:23
std::unordered_map< std::string, InitializedTensor > fInitializedTensors
Definition RModel.hxx:18
void UpdateInitializedTensor(std::string tensor_name, ETensorType type, std::vector< std::size_t > shape, std::shared_ptr< void > data)
Definition RModel.cxx:239
void UpdateOutputTensorList(std::vector< std::string > curr_output_tensor, std::vector< std::string > modify_output_tensor)
Definition RModel.cxx:232
virtual void Streamer(TBuffer &)
Stream an object of class TObject.
Definition TObject.cxx:888
static TClass * Class()
std::string Clean_name(std::string input_tensor_name)
std::vector< Dim > ConvertShapeToDim(std::vector< size_t > shape)
Convert shape from integer format to dynamic one (based on Dim)
std::string ConvertDynamicShapeToLength(std::vector< Dim > shape)
std::string ConvertShapeToString(std::vector< size_t > shape)
std::string ConvertTypeToString(ETensorType type)
std::string ConvertDynamicShapeToString(std::vector< Dim > shape)
std::underlying_type_t< Options > operator|(Options opA, Options opB)
Definition RModel.cxx:16
std::vector< size_t > ConvertShapeToInt(std::vector< Dim > shape)
Convert shape based on Dim to integer format.
std::size_t ConvertShapeToLength(std::vector< size_t > shape)
create variable transformations