Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RModelParser_Keras.cxx
Go to the documentation of this file.
1// @(#)root/tmva/pymva $Id$
2// Author: Sanjiban Sengupta 2021
3
4/**********************************************************************************
5 * Project : TMVA - a Root-integrated toolkit for multivariate data analysis *
6 * Package : TMVA *
7 * Function: TMVA::Experimental::SOFIE::PyKeras::Parse *
8 * *
9 * Description: *
10 * Parser function for translating Keras .h5 model to RModel object *
11 * *
12 * Example Usage: *
13 * ~~~ {.cpp} *
14 * using TMVA::Experimental::SOFIE; *
15 * RModel model = PyKeras::Parse("trained_model_dense.h5"); *
16 * ~~~ *
17 * *
18 **********************************************************************************/
19
21
22#include <Python.h>
23
24#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
25#include <numpy/arrayobject.h>
26
27
29
30namespace {
31
32// Utility functions (taken from PyMethodBase in PyMVA)
33
34void PyRunString(TString code, PyObject *globalNS, PyObject *localNS)
35{
37 if (!fPyReturn) {
38 std::cout << "\nPython error message:\n";
40 throw std::runtime_error("\nFailed to run python code: " + code);
41 }
42}
43
44const char *PyStringAsString(PyObject *string)
45{
48 return cstring;
49}
50
51std::vector<size_t> GetDataFromTuple(PyObject *tupleObject)
52{
53 std::vector<size_t> tupleVec;
56 if (itemObj == Py_None)
57 tupleVec.push_back(0); // case shape is for example (None,2,3)
58 else
59 tupleVec.push_back((size_t)PyLong_AsLong(itemObj));
60 }
61 return tupleVec;
62}
63
64PyObject *GetValueFromDict(PyObject *dict, const char *key)
65{
67}
68
69} // namespace
70
71namespace INTERNAL{
72
73// For adding Keras layer into RModel object
74void AddKerasLayer(RModel &rmodel, PyObject *fLayer);
75
76// Declaring Internal Functions for Keras layers which don't have activation as an additional attribute
77std::unique_ptr<ROperator> MakeKerasActivation(PyObject *fLayer); // For instantiating ROperator for Keras Activation Layer
78std::unique_ptr<ROperator> MakeKerasReLU(PyObject *fLayer); // For instantiating ROperator for Keras ReLU layer
79std::unique_ptr<ROperator> MakeKerasSelu(PyObject *fLayer); // For instantiating ROperator for Keras Selu layer
80std::unique_ptr<ROperator> MakeKerasSigmoid(PyObject *fLayer); // For instantiating ROperator for Keras Sigmoid layer
81std::unique_ptr<ROperator> MakeKerasSwish(PyObject *fLayer); // For instantiating ROperator for Keras Swish layer
82std::unique_ptr<ROperator> MakeKerasPermute(PyObject *fLayer); // For instantiating ROperator for Keras Permute Layer
83std::unique_ptr<ROperator> MakeKerasBatchNorm(PyObject *fLayer); // For instantiating ROperator for Keras Batch Normalization Layer
84std::unique_ptr<ROperator> MakeKerasReshape(PyObject *fLayer); // For instantiating ROperator for Keras Reshape Layer
85std::unique_ptr<ROperator> MakeKerasConcat(PyObject *fLayer); // For instantiating ROperator for Keras Concat Layer
86std::unique_ptr<ROperator> MakeKerasBinary(PyObject *fLayer); // For instantiating ROperator for Keras binary operations: Add, Subtract & Multiply.
87std::unique_ptr<ROperator> MakeKerasSoftmax(PyObject *fLayer); // For instantiating ROperator for Keras Softmax Layer
88std::unique_ptr<ROperator> MakeKerasTanh(PyObject *fLayer); // For instantiating ROperator for Keras Tanh Layer
89std::unique_ptr<ROperator> MakeKerasLeakyRelu(PyObject *fLayer); // For instantiating ROperator for Keras LeakyRelu Layer
90std::unique_ptr<ROperator> MakeKerasIdentity(PyObject *fLayer); // For instantiating ROperator for Keras Identity Layer
91
92
93// Declaring Internal function for Keras layers which have additional activation attribute
94std::unique_ptr<ROperator> MakeKerasDense(PyObject *fLayer); // For instantiating ROperator for Keras Dense Layer
95std::unique_ptr<ROperator> MakeKerasConv(PyObject *fLayer); // For instantiating ROperator for Keras Conv Layer
96
97// For mapping Keras layer with the preparatory functions for ROperators
98using KerasMethodMap = std::unordered_map<std::string, std::unique_ptr<ROperator> (*)(PyObject *fLayer)>;
99using KerasMethodMapWithActivation = std::unordered_map<std::string, std::unique_ptr<ROperator> (*)(PyObject *fLayer)>;
100
102 {"Activation", &MakeKerasActivation},
103 {"Permute", &MakeKerasPermute},
104 {"BatchNormalization", &MakeKerasBatchNorm},
105 {"Reshape", &MakeKerasReshape},
106 {"Concatenate", &MakeKerasConcat},
107 {"swish", &MakeKerasSwish},
108 {"Add", &MakeKerasBinary},
109 {"Subtract", &MakeKerasBinary},
110 {"Multiply", &MakeKerasBinary},
111 {"Softmax", &MakeKerasSoftmax},
112 {"tanh", &MakeKerasTanh},
113 {"LeakyReLU", &MakeKerasLeakyRelu},
114 {"Identity", &MakeKerasIdentity},
115 {"Dropout", &MakeKerasIdentity},
116
117 // For activation layers
118 {"ReLU", &MakeKerasReLU},
119
120 // For layers with activation attributes
121 {"relu", &MakeKerasReLU},
122 {"selu", &MakeKerasSelu},
123 {"sigmoid", &MakeKerasSigmoid},
124 {"softmax", &MakeKerasSoftmax}
125};
126
131
132
133//////////////////////////////////////////////////////////////////////////////////
134/// \brief Adds equivalent ROperator with respect to Keras model layer
135/// into the referenced RModel object
136///
137/// \param[in] rmodel RModel object
138/// \param[in] fLayer Python Keras layer as a Dictionary object
139/// \param[out] RModel object with the added ROperator
140///
141/// Function adds equivalent ROperator into the referenced RModel object.
142/// Keras models can have layers like Dense and Conv which have activation
143/// function as an attribute. Function first searches if layer object is among
144/// the ones which don't have activation attribute and then calls the respective
145/// preparation function to get the ROperator object, which is then added
146/// into the RModel object. If passed layer is among the ones which may have activation
147/// attribute, then it checks for the activation attribute, if present then first adds
148/// the primary operator into the RModel object, and then adds the operator for the
149/// activation function with appropriate changes in the names of input and output
150/// tensors for both of them.
151/// Example of such layers is the Dense Layer. For a dense layer with input tensor name
152/// dense2BiasAdd0 and output tensor name dense3Relu0 with relu as activation attribute
153/// will be transformed into a ROperator_Gemm with input tensor name dense2BiasAdd0
154/// & output tensor name dense3Dense (layerName+layerType), and a subsequent
155/// ROperator_Relu with input tensor name as dense3Dense and output tensor name
156/// as dense3Relu0.
157///
158/// For developing new preparatory functions for supporting Keras layers in future,
159/// all one needs is to extract the required properties and attributes from the fLayer
160/// dictionary which contains all the information about any Keras layer and after
161/// any required transformations, these are passed for instantiating the ROperator
162/// object.
163///
164/// The fLayer dictionary which holds all the information about a Keras layer has
165/// following structure:-
166///
167/// dict fLayer { 'layerType' : Type of the Keras layer
168/// 'layerAttributes' : Attributes of the keras layer as returned by layer.get_config()
169/// 'layerInput' : List of names of input tensors
170/// 'layerOutput' : List of names of output tensors
171/// 'layerDType' : Data-type of the Keras layer
172/// 'layerWeight' : List of weight tensor names of Keras layers
173/// }
175 std::string fLayerType = PyStringAsString(GetValueFromDict(fLayer,"layerType"));
176
177 if(fLayerType == "Reshape"){
178 PyObject* fAttributes=GetValueFromDict(fLayer,"layerAttributes");
179 std::string fLayerName = PyStringAsString(GetValueFromDict(fAttributes,"_name"));
180 PyObject* fPTargetShape = GetValueFromDict(fAttributes,"target_shape");
181 std::vector<size_t>fTargetShape = GetDataFromTuple(fPTargetShape);
182 std::shared_ptr<void> fData(malloc(fTargetShape.size() * sizeof(int64_t)), free);
183 std::copy(fTargetShape.begin(),fTargetShape.end(),(int64_t*)fData.get());
184 rmodel.AddInitializedTensor(fLayerName+"ReshapeAxes",ETensorType::INT64,{fTargetShape.size()},fData);
185 }
186
187 //For layers without additional activation attribute
189 if(findLayer != mapKerasLayer.end()){
190 rmodel.AddOperator((findLayer->second)(fLayer));
191 return;
192 }
193
194 //For layers like Dense & Conv which has additional activation attribute
197 PyObject* fAttributes=GetValueFromDict(fLayer,"layerAttributes");
198
199 std::string fLayerName = PyStringAsString(GetValueFromDict(fAttributes,"_name"));
200
201 PyObject* fPActivation = GetValueFromDict(fAttributes,"activation");
202 std::string fLayerActivation = PyStringAsString(PyObject_GetAttrString(fPActivation,"__name__"));
203
204 if(fLayerActivation == "selu" || fLayerActivation == "sigmoid")
205 rmodel.AddNeededStdLib("cmath");
206
207
208 //Checking if additional attribute exixts
209 if(fLayerActivation != "linear"){
210 PyObject* fOutputs = GetValueFromDict(fLayer,"layerOutput");
211 PyObject* fInputs = GetValueFromDict(fLayer,"layerInput");
212 std::string fActivationLayerOutput = PyStringAsString(PyList_GetItem(fOutputs,0));
213
214 if(fLayerType == "Conv2D"){
215 std::unique_ptr<ROperator> op_pre_transpose;
216 op_pre_transpose.reset(new ROperator_Transpose<float>({0,3,1,2}, PyStringAsString(PyList_GetItem(fInputs,0)), fLayerName+"PreTrans"));
217 rmodel.AddOperator(std::move(op_pre_transpose));
218
219 PyList_SetItem(fInputs,0,PyUnicode_FromString((fLayerName+"PreTrans").c_str()));
220 PyDict_SetItemString(fLayer,"layerInput",fInputs);
221 }
222
223 // Making changes in the names of the input and output tensor names
225 PyDict_SetItemString(fLayer,"layerOutput",fOutputs);
226 rmodel.AddOperator((findLayer->second)(fLayer));
227
229 if(fLayerType == "Conv2D"){
230 std::unique_ptr<ROperator> op_post_transpose;
232 rmodel.AddOperator(std::move(op_post_transpose));
233 fActivationLayerInput = fLayerName+"PostTrans";
234 }
235
238 PyDict_SetItemString(fLayer,"layerInput",fInputs);
239 PyDict_SetItemString(fLayer,"layerOutput",fOutputs);
240
243 throw std::runtime_error("TMVA::SOFIE - Parsing Keras Activation layer " + fLayerActivation + " is not yet supported");
244 }
245 rmodel.AddOperator((findActivationLayer->second)(fLayer));
246
247 }
248 else{
249 rmodel.AddOperator((findLayer->second)(fLayer));
250 }
251 return;
252 }
253
254 else{
255 throw std::runtime_error("TMVA::SOFIE - Parsing Keras layer " + fLayerType + " is not yet supported");
256 }
257
258}
259
260//////////////////////////////////////////////////////////////////////////////////
261/// \brief Prepares a ROperator object for Keras Dense Layer
262///
263/// \param[in] fLayer Python Keras layer as a Dictionary object
264/// \return Unique pointer to ROperator object
265///
266/// For Keras's Dense layer, the names of the input tensor, output tensor, and
267/// weight tensors are extracted, and then are passed to instantiate a
268/// ROperator_Gemm object using the required attributes.
269std::unique_ptr<ROperator> MakeKerasDense(PyObject* fLayer){
270 PyObject* fInputs = GetValueFromDict(fLayer,"layerInput");
271 PyObject* fOutputs = GetValueFromDict(fLayer,"layerOutput");
272 std::string fLayerDType = PyStringAsString(GetValueFromDict(fLayer,"layerDType"));
273
274 std::string fLayerInputName = PyStringAsString(PyList_GetItem(fInputs,0));
275 std::string fLayerOutputName = PyStringAsString(PyList_GetItem(fOutputs,0));
276
277 // Extracting names of weight tensors
278 // The names of Kernel weights and bias weights are found in the list
279 // of weight tensors from fLayer.
280 PyObject* fWeightNames = GetValueFromDict(fLayer,"layerWeight");
281 std::string fKernelName = PyStringAsString(PyList_GetItem(fWeightNames,0));
282 std::string fBiasName = PyStringAsString(PyList_GetItem(fWeightNames,1));
283
284 std::unique_ptr<ROperator> op;
285
286 float attr_alpha = 1.0;
287 float attr_beta = 1.0;
288 int_t attr_transA = 0;
289 int_t attr_transB = 0;
290
294 break;
295
296 default:
297 throw std::runtime_error("TMVA::SOFIE - Unsupported - Operator Gemm does not yet support input type " + fLayerDType);
298 }
299 return op;
300}
301
302
303
304//////////////////////////////////////////////////////////////////////////////////
305/// \brief Prepares a ROperator object for Keras Conv Layer
306///
307/// \param[in] fLayer Python Keras layer as a Dictionary object
308/// \return Unique pointer to ROperator object
309///
310/// For Keras's Conv layer, the names of the input tensor, output tensor, and
311/// weight tensors are extracted, along with attributes like dilation_rate,
312/// groups, kernel size, padding, strides. Padding attribute is then
313/// computed for ROperator depending on Keras' attribute parameter.
314std::unique_ptr<ROperator> MakeKerasConv(PyObject* fLayer){
315 PyObject* fAttributes = GetValueFromDict(fLayer,"layerAttributes");
316 PyObject* fInputs = GetValueFromDict(fLayer,"layerInput");
317 PyObject* fOutputs = GetValueFromDict(fLayer,"layerOutput");
318 std::string fLayerDType = PyStringAsString(GetValueFromDict(fLayer,"layerDType"));
319
320 std::string fLayerInputName = PyStringAsString(PyList_GetItem(fInputs,0));
321 std::string fLayerOutputName = PyStringAsString(PyList_GetItem(fOutputs,0));
322
323 // Extracting names of weight tensors
324 // The names of Kernel weights and bias weights are found in the list
325 // of weight tensors from fLayer.
326 PyObject* fWeightNames = GetValueFromDict(fLayer,"layerWeight");
327 std::string fKernelName = PyStringAsString(PyList_GetItem(fWeightNames,0));
328 std::string fBiasName = PyStringAsString(PyList_GetItem(fWeightNames,1));
329
330 // Extracting the Conv Node Attributes
331 PyObject* fDilations = GetValueFromDict(fAttributes,"dilation_rate");
332 PyObject* fGroup = GetValueFromDict(fAttributes,"groups");
333 PyObject* fKernelShape = GetValueFromDict(fAttributes,"kernel_size");
334 PyObject* fPads = GetValueFromDict(fAttributes,"padding");
335 PyObject* fStrides = GetValueFromDict(fAttributes,"strides");
336
337 std::vector<size_t> fAttrDilations = GetDataFromTuple(fDilations);
338
339
340 size_t fAttrGroup = PyLong_AsLong(fGroup);
341 std::vector<size_t> fAttrKernelShape = GetDataFromTuple(fKernelShape);
342 std::vector<size_t> fAttrStrides = GetDataFromTuple(fStrides);
343 std::string fAttrAutopad;
344 std::vector<size_t>fAttrPads;
345
346 //Seting the layer padding
347 std::string fKerasPadding = PyStringAsString(fPads);
348 if(fKerasPadding == "valid"){
349 fAttrAutopad = "VALID";
350 }
351 else if(fKerasPadding == "same"){
352 fAttrAutopad="NOTSET";
353 PyObject* fInputShape = GetValueFromDict(fAttributes,"_batch_input_shape");
354 long inputHeight = PyLong_AsLong(PyTuple_GetItem(fInputShape,1));
355 long inputWidth = PyLong_AsLong(PyTuple_GetItem(fInputShape,2));
356
357 long outputHeight = std::ceil(float(inputHeight) / float(fAttrStrides[0]));
358 long outputWidth = std::ceil(float(inputWidth) / float(fAttrStrides[1]));
359
360 long padding_height = std::max(long((outputHeight - 1) * fAttrStrides[0] + fAttrKernelShape[0] - inputHeight),0L);
361 long padding_width = std::max(long((outputWidth - 1) * fAttrStrides[1] + fAttrKernelShape[1] - inputWidth),0L);
362
363 size_t padding_top = std::floor(padding_height/2);
365 size_t padding_left = std::floor(padding_width/2);
368 }
369 else{
370 throw std::runtime_error("TMVA::SOFIE - RModel Keras Parser doesn't yet supports Convolution layer with padding " + fKerasPadding);
371 }
372
373 std::unique_ptr<ROperator> op;
374
377 op.reset(new ROperator_Conv<float>(fAttrAutopad, fAttrDilations, fAttrGroup, fAttrKernelShape, fAttrPads, fAttrStrides, fLayerInputName, fKernelName, fBiasName, fLayerOutputName));
378 break;
379
380 default:
381 throw std::runtime_error("TMVA::SOFIE - Unsupported - Operator Conv does not yet support input type " + fLayerDType);
382 }
383 return op;
384}
385
386
387//////////////////////////////////////////////////////////////////////////////////
388/// \brief Prepares a ROperator object for Keras activation layer
389///
390/// \param[in] fLayer Python Keras layer as a Dictionary object
391/// \return Unique pointer to ROperator object
392///
393/// For Keras's keras.layers.Activation layer, the activation attribute is
394/// extracted and appropriate function for adding the function is called.
395std::unique_ptr<ROperator> MakeKerasActivation(PyObject* fLayer){
396 PyObject* fAttributes=GetValueFromDict(fLayer,"layerAttributes");
397 PyObject* fPActivation = GetValueFromDict(fAttributes,"activation");
398 std::string fLayerActivation = PyStringAsString(PyObject_GetAttrString(fPActivation,"__name__"));
399
401 if(findLayer == mapKerasLayer.end()){
402 throw std::runtime_error("TMVA::SOFIE - Parsing Keras Activation layer " + fLayerActivation + " is not yet supported");
403 }
404 return (findLayer->second)(fLayer);
405}
406
407
408//////////////////////////////////////////////////////////////////////////////////
409/// \brief Prepares a ROperator object for Keras ReLU activation
410///
411/// \param[in] fLayer Python Keras layer as a Dictionary object
412/// \return Unique pointer to ROperator object
413///
414/// For instantiating a ROperator_Relu object, the names of
415/// input & output tensors and the data-type of the layer are extracted.
416std::unique_ptr<ROperator> MakeKerasReLU(PyObject* fLayer)
417{
418 PyObject* fInputs=GetValueFromDict(fLayer,"layerInput");
419 PyObject* fOutputs=GetValueFromDict(fLayer,"layerOutput");
420
421 std::string fLayerDType = PyStringAsString(GetValueFromDict(fLayer,"layerDType"));
422 std::string fLayerInputName = PyStringAsString(PyList_GetItem(fInputs,0));
423 std::string fLayerOutputName = PyStringAsString(PyList_GetItem(fOutputs,0));
424
425 std::unique_ptr<ROperator> op;
429 break;
430 default:
431 throw std::runtime_error("TMVA::SOFIE - Unsupported - Operator Relu does not yet support input type " + fLayerDType);
432 }
433 return op;
434}
435
436
437//////////////////////////////////////////////////////////////////////////////////
438/// \brief Prepares a ROperator object for Keras Selu activation
439///
440/// \param[in] fLayer Python Keras layer as a Dictionary object
441/// \return Unique pointer to ROperator object
442///
443/// For instantiating a ROperator_Selu object, the names of
444/// input & output tensors and the data-type of the layer are extracted.
445std::unique_ptr<ROperator> MakeKerasSelu(PyObject* fLayer){
446 PyObject* fInputs = GetValueFromDict(fLayer,"layerInput");
447 PyObject* fOutputs = GetValueFromDict(fLayer,"layerOutput");
448
449 std::string fLayerDType = PyStringAsString(GetValueFromDict(fLayer,"layerDType"));
450 std::string fLayerInputName = PyStringAsString(PyList_GetItem(fInputs,0));
451 std::string fLayerOutputName = PyStringAsString(PyList_GetItem(fOutputs,0));
452
453 std::unique_ptr<ROperator> op;
457 break;
458 default:
459 throw std::runtime_error("TMVA::SOFIE - Unsupported - Operator Selu does not yet support input type " + fLayerDType);
460 }
461 return op;
462}
463
464
465//////////////////////////////////////////////////////////////////////////////////
466/// \brief Prepares a ROperator object for Keras Sigmoid activation
467///
468/// \param[in] fLayer Python Keras layer as a Dictionary object
469/// \return Unique pointer to ROperator object
470///
471/// For instantiating a ROperator_Sigmoid object, the names of
472/// input & output tensors and the data-type of the layer are extracted.
473std::unique_ptr<ROperator> MakeKerasSigmoid(PyObject* fLayer){
474 PyObject* fInputs = GetValueFromDict(fLayer,"layerInput");
475 PyObject* fOutputs = GetValueFromDict(fLayer,"layerOutput");
476
477 std::string fLayerDType = PyStringAsString(GetValueFromDict(fLayer,"layerDType"));
478 std::string fLayerInputName = PyStringAsString(PyList_GetItem(fInputs,0));
479 std::string fLayerOutputName = PyStringAsString(PyList_GetItem(fOutputs,0));
480
481 std::unique_ptr<ROperator> op;
485 break;
486 default:
487 throw std::runtime_error("TMVA::SOFIE - Unsupported - Operator Sigmoid does not yet support input type " + fLayerDType);
488 }
489 return op;
490}
491
492//////////////////////////////////////////////////////////////////////////////////
493/// \brief Prepares a ROperator object for Keras Softmax activation
494///
495/// \param[in] fLayer Python Keras layer as a Dictionary object
496/// \return Unique pointer to ROperator object
497///
498/// For instantiating a ROperator_Softmax object, the names of
499/// input & output tensors and the data-type of the layer are extracted.
500std::unique_ptr<ROperator> MakeKerasSoftmax(PyObject* fLayer){
501 PyObject* fInputs = GetValueFromDict(fLayer,"layerInput");
502 PyObject* fOutputs = GetValueFromDict(fLayer,"layerOutput");
503
504 std::string fLayerDType = PyStringAsString(GetValueFromDict(fLayer,"layerDType"));
505 std::string fLayerInputName = PyStringAsString(PyList_GetItem(fInputs,0));
506 std::string fLayerOutputName = PyStringAsString(PyList_GetItem(fOutputs,0));
507
508 std::unique_ptr<ROperator> op;
511 op.reset(new ROperator_Softmax<float>(/*default axis is -1*/-1,fLayerInputName, fLayerOutputName));
512 break;
513 default:
514 throw std::runtime_error("TMVA::SOFIE - Unsupported - Operator Sigmoid does not yet support input type " + fLayerDType);
515 }
516 return op;
517}
518
519//////////////////////////////////////////////////////////////////////////////////
520/// \brief Prepares a ROperator object for Keras Leaky Relu activation
521///
522/// \param[in] fLayer Python Keras layer as a Dictionary object
523/// \return Unique pointer to ROperator object
524///
525/// For instantiating a ROperator_LeakyRelu object, the names of
526/// input & output tensors, the data-type and the alpha attribute of the layer
527/// are extracted.
528std::unique_ptr<ROperator> MakeKerasLeakyRelu(PyObject* fLayer){
529 PyObject* fInputs = GetValueFromDict(fLayer,"layerInput");
530 PyObject* fOutputs = GetValueFromDict(fLayer,"layerOutput");
531 PyObject* fAttributes=GetValueFromDict(fLayer,"layerAttributes");
532
533 std::string fLayerDType = PyStringAsString(GetValueFromDict(fLayer,"layerDType"));
534 std::string fLayerInputName = PyStringAsString(PyList_GetItem(fInputs,0));
535 std::string fLayerOutputName = PyStringAsString(PyList_GetItem(fOutputs,0));
536 float fAlpha = (float)PyFloat_AsDouble(GetValueFromDict(fAttributes,"alpha"));
537 std::unique_ptr<ROperator> op;
541 break;
542 default:
543 throw std::runtime_error("TMVA::SOFIE - Unsupported - Operator Sigmoid does not yet support input type " + fLayerDType);
544 }
545 return op;
546}
547
548//////////////////////////////////////////////////////////////////////////////////
549/// \brief Prepares a ROperator object for Keras Tanh activation
550///
551/// \param[in] fLayer Python Keras layer as a Dictionary object
552/// \return Unique pointer to ROperator object
553///
554/// For instantiating a ROperator_Tanh object, the names of
555/// input & output tensors and the data-type of the layer are extracted.
556std::unique_ptr<ROperator> MakeKerasTanh(PyObject* fLayer){
557 PyObject* fInputs = GetValueFromDict(fLayer,"layerInput");
558 PyObject* fOutputs = GetValueFromDict(fLayer,"layerOutput");
559
560 std::string fLayerDType = PyStringAsString(GetValueFromDict(fLayer,"layerDType"));
561 std::string fLayerInputName = PyStringAsString(PyList_GetItem(fInputs,0));
562 std::string fLayerOutputName = PyStringAsString(PyList_GetItem(fOutputs,0));
563
564 std::unique_ptr<ROperator> op;
568 break;
569 default:
570 throw std::runtime_error("TMVA::SOFIE - Unsupported - Operator Tanh does not yet support input type " + fLayerDType);
571 }
572 return op;
573}
574
575//////////////////////////////////////////////////////////////////////////////////
576/// \brief Prepares a ROperator object for Keras Swish activation
577///
578/// \param[in] fLayer Python Keras layer as a Dictionary object
579/// \return Unique pointer to ROperator object
580///
581/// For instantiating a ROperator_Swish object, the names of
582/// input & output tensors and the data-type of the layer are extracted.
583std::unique_ptr<ROperator> MakeKerasSwish(PyObject* fLayer){
584 PyObject* fInputs = GetValueFromDict(fLayer,"layerInput");
585 PyObject* fOutputs = GetValueFromDict(fLayer,"layerOutput");
586
587 std::string fLayerDType = PyStringAsString(GetValueFromDict(fLayer,"layerDType"));
588 std::string fLayerInputName = PyStringAsString(PyList_GetItem(fInputs,0));
589 std::string fLayerOutputName = PyStringAsString(PyList_GetItem(fOutputs,0));
590
591 std::unique_ptr<ROperator> op;
595 break;
596 default:
597 throw std::runtime_error("TMVA::SOFIE - Unsupported - Operator Swish does not yet support input type " + fLayerDType);
598 }
599 return op;
600}
601
602//////////////////////////////////////////////////////////////////////////////////
603/// \brief Prepares a ROperator object for Keras Permute layer
604///
605/// \param[in] fLayer Python Keras layer as a Dictionary object
606/// \return Unique pointer to ROperator object
607///
608/// The Permute layer in Keras has an equivalent Tranpose operator in ONNX.
609/// For adding a Transpose operator, the permute dimensions are found, if they
610/// exist are passed in instantiating the ROperator, else default values are used.
611std::unique_ptr<ROperator> MakeKerasPermute(PyObject* fLayer)
612{
613 // Extracting required layer information
614 PyObject* fAttributes=GetValueFromDict(fLayer,"layerAttributes");
615 PyObject* fInputs=GetValueFromDict(fLayer,"layerInput");
616 PyObject* fOutputs=GetValueFromDict(fLayer,"layerOutput");
617
618 std::string fLayerDType = PyStringAsString(GetValueFromDict(fLayer,"layerDType"));
619 std::string fLayerInputName = PyStringAsString(PyList_GetItem(fInputs,0));
620 std::string fLayerOutputName = PyStringAsString(PyList_GetItem(fOutputs,0));
621
622 // Extracting the permute dimensions present in Attributes of the Keras layer
623 PyObject* fAttributePermute = GetValueFromDict(fAttributes,"dims");
624 std::vector<int_t>fPermuteDims;
625
626 // Building vector of permute dimensions from the Tuple object.
628
630 }
631 std::unique_ptr<ROperator> op;
633 case ETensorType::FLOAT:{
634
635 // Adding the permute dimensions if present, else are avoided to use default values.
636 if (!fPermuteDims.empty()){
638 }
639 else{
641 }
642 break;
643 }
644 default:
645 throw std::runtime_error("TMVA::SOFIE - Unsupported - Operator Transpose does not yet support input type " + fLayerDType);
646 }
647 return op;
648}
649
650//////////////////////////////////////////////////////////////////////////////////
651/// \brief Prepares a ROperator object for Keras BatchNorm layer
652///
653/// \param[in] fLayer Python Keras layer as a Dictionary object
654/// \return Unique pointer to ROperator object
655std::unique_ptr<ROperator> MakeKerasBatchNorm(PyObject* fLayer)
656{
657 // Extracting required layer information
658 PyObject* fAttributes = GetValueFromDict(fLayer,"layerAttributes");
659 PyObject* fInputs = GetValueFromDict(fLayer,"layerInput");
660 PyObject* fOutputs = GetValueFromDict(fLayer,"layerOutput");
661 PyObject* fGamma = GetValueFromDict(fAttributes,"gamma");
662 PyObject* fBeta = GetValueFromDict(fAttributes,"beta");
663 PyObject* fMoving_Mean = GetValueFromDict(fAttributes,"moving_mean");
664 PyObject* fMoving_Var = GetValueFromDict(fAttributes,"moving_variance");
665
666 std::string fLayerDType = PyStringAsString(GetValueFromDict(fLayer,"layerDType"));
667 std::string fNX = PyStringAsString(PyList_GetItem(fInputs,0));
668 std::string fNY = PyStringAsString(PyList_GetItem(fOutputs,0));
669 std::string fNScale = PyStringAsString(PyObject_GetAttrString(fGamma,"name"));
670 std::string fNB = PyStringAsString(PyObject_GetAttrString(fBeta,"name"));
671 std::string fNMean = PyStringAsString(PyObject_GetAttrString(fMoving_Mean,"name"));
672 std::string fNVar = PyStringAsString(PyObject_GetAttrString(fMoving_Var,"name"));
673 float fEpsilon = (float)PyFloat_AsDouble(GetValueFromDict(fAttributes,"epsilon"));
674 float fMomentum = (float)PyFloat_AsDouble(GetValueFromDict(fAttributes,"momentum"));
675
676 std::unique_ptr<ROperator> op;
677 op.reset(new ROperator_BatchNormalization<float>(fEpsilon, fMomentum, /* training mode */ 0, fNX, fNScale, fNB, fNMean, fNVar, fNY));
678 return op;
679}
680
681//////////////////////////////////////////////////////////////////////////////////
682/// \brief Prepares a ROperator object for Keras Reshape layer
683///
684/// \param[in] fLayer Python Keras layer as a Dictionary object
685/// \return Unique pointer to ROperator object
686std::unique_ptr<ROperator> MakeKerasReshape(PyObject* fLayer)
687{
688 // Extracting required layer information
689 PyObject* fAttributes = GetValueFromDict(fLayer,"layerAttributes");
690 PyObject* fInputs = GetValueFromDict(fLayer,"layerInput");
691 PyObject* fOutputs = GetValueFromDict(fLayer,"layerOutput");
692
693 std::string fLayerName = PyStringAsString(GetValueFromDict(fAttributes,"_name"));
694
695 ReshapeOpMode fOpMode = Reshape;
696 std::string fLayerDType = PyStringAsString(GetValueFromDict(fLayer,"layerDType"));
697 std::string fNameData = PyStringAsString(PyList_GetItem(fInputs,0));
698 std::string fNameOutput = PyStringAsString(PyList_GetItem(fOutputs,0));
699 std::string fNameShape = fLayerName + "ReshapeAxes";
700 std::unique_ptr<ROperator> op;
701 op.reset(new ROperator_Reshape(fOpMode, /*allow zero*/0, fNameData, fNameShape, fNameOutput));
702 return op;
703}
704
705//////////////////////////////////////////////////////////////////////////////////
706/// \brief Prepares a ROperator object for Keras Concat layer
707///
708/// \param[in] fLayer Python Keras layer as a Dictionary object
709/// \return Unique pointer to ROperator object
710std::unique_ptr<ROperator> MakeKerasConcat(PyObject* fLayer)
711{
712 PyObject* fAttributes = GetValueFromDict(fLayer,"layerAttributes");
713 PyObject* fInputs = GetValueFromDict(fLayer,"layerInput");
714 PyObject* fOutputs = GetValueFromDict(fLayer,"layerOutput");
715
716 std::vector<std::string> inputs;
717 for(Py_ssize_t i=0; i<PyList_Size(fInputs); ++i){
718 inputs.emplace_back(PyStringAsString(PyList_GetItem(fInputs,i)));
719 }
720 std::string output = PyStringAsString(PyList_GetItem(fOutputs,0));
721
722 int axis = (int)PyLong_AsLong(GetValueFromDict(fAttributes,"axis"));
723 std::unique_ptr<ROperator> op;
724 op.reset(new ROperator_Concat(inputs, axis, 0, output));
725 return op;
726}
727
728//////////////////////////////////////////////////////////////////////////////////
729/// \brief Prepares a ROperator object for Keras binary operations like Add,
730/// subtract, and multiply.
731///
732/// \param[in] fLayer Python Keras layer as a Dictionary object
733/// \return Unique pointer to ROperator object
734///
735/// For instantiating a ROperator_BasicBinary object, the names of
736/// input & output tensors, the data-type of the layer and the operation type
737/// are extracted.
738std::unique_ptr<ROperator> MakeKerasBinary(PyObject* fLayer){
739 PyObject* fInputs = GetValueFromDict(fLayer,"layerInput");
740 PyObject* fOutputs = GetValueFromDict(fLayer,"layerOutput");
741
742 std::string fLayerType = PyStringAsString(GetValueFromDict(fLayer,"layerType"));
743 std::string fLayerDType = PyStringAsString(GetValueFromDict(fLayer,"layerDType"));
744 std::string fX1 = PyStringAsString(PyList_GetItem(fInputs,0));
745 std::string fX2 = PyStringAsString(PyList_GetItem(fInputs,1));
746 std::string fY = PyStringAsString(PyList_GetItem(fOutputs,0));
747
748 std::unique_ptr<ROperator> op;
750 case ETensorType::FLOAT:{
751 if(fLayerType == "Add")
752 op.reset(new ROperator_BasicBinary<float, Add> (fX1, fX2, fY));
753 else if(fLayerType == "Subtract")
754 op.reset(new ROperator_BasicBinary<float, Sub> (fX1, fX2, fY));
755 else
756 op.reset(new ROperator_BasicBinary<float, Mul> (fX1, fX2, fY));
757 break;
758 }
759 default:
760 throw std::runtime_error("TMVA::SOFIE - Unsupported - Operator Sigmoid does not yet support input type " + fLayerDType);
761 }
762 return op;
763}
764
765//////////////////////////////////////////////////////////////////////////////////
766/// \brief Prepares a ROperator object for Keras Identity and Dropout Layer
767///
768/// \param[in] fLayer Python Keras layer as a Dictionary object
769/// \return Unique pointer to ROperator object
770///
771/// Dropout will have no effect in inference, so instead an Identity operator
772/// is added to mimic its presence in the Keras model
773std::unique_ptr<ROperator> MakeKerasIdentity(PyObject* fLayer)
774{
775 PyObject* fInputs=GetValueFromDict(fLayer,"layerInput");
776 PyObject* fOutputs=GetValueFromDict(fLayer,"layerOutput");
777
778 std::string fLayerDType = PyStringAsString(GetValueFromDict(fLayer,"layerDType"));
779 std::string fLayerInputName = PyStringAsString(PyList_GetItem(fInputs,0));
780 std::string fLayerOutputName = PyStringAsString(PyList_GetItem(fOutputs,0));
781
782 std::unique_ptr<ROperator> op;
786 break;
787 default:
788 throw std::runtime_error("TMVA::SOFIE - Unsupported - Operator Identity does not yet support input type " + fLayerDType);
789 }
790 return op;
791}
792
793}//INTERNAL
794
795
796//////////////////////////////////////////////////////////////////////////////////
797/// \param[in] filename file location of Keras .h5
798/// \param[in] batch_size if not given, 1 is used if the model does not provide it
799/// \return Parsed RModel object
800///
801/// The `Parse()` function defined in `TMVA::Experimental::SOFIE::PyKeras` will
802/// parse a trained Keras .h5 model into a RModel Object. After loading the model
803/// in a Python Session, the included layers are extracted with properties
804/// like Layer type, Attributes, Input tensor names, Output tensor names, data-type
805/// and names of the weight/initialized tensors.
806/// The extracted layers from the model are then passed into `AddKerasLayer()`
807/// which prepares the specific ROperator and adds them into the RModel object.
808/// The layers are also checked for adding any required routines for executing
809/// the generated Inference code.
810///
811/// For adding the Initialized tensors into the RModel object, the weights are
812/// extracted from the Keras model in the form of NumPy arrays, which are then
813/// passed into `AddInitializedTensor()` after appropriate casting.
814///
815/// Input tensor infos are required to be added which will contain their names,
816/// shapes and data-types. For keras models with single input tensors, the tensor
817/// shape is returned as a Tuple object, whereas for multi-input models,
818/// the tensor shape is returned as a List of Tuple object containing the shape
819/// of the individual input tensors. SOFIE's RModel also requires that the Keras
820/// models are initialized with Batch Size. The `GetDataFromTuple()` are called
821/// on the Tuple objects, which then returns the shape vector required to call
822/// the `AddInputTensorInfo()`.
823///
824/// For adding the Output Tensor infos, only the names of the model's output
825/// tensors are extracted and are then passed into `AddOutputTensorNameList()`.
826///
827/// Provide optionally a batch size that can be used to overwrite the one given by the
828/// model. If a batch size is not given 1 is used if the model does not provide a batch size
829///
830/// Example Usage:
831/// ~~~ {.cpp}
832/// using TMVA::Experimental::SOFIE;
833/// RModel model = PyKeras::Parse("trained_model_dense.h5");
834/// ~~~
835RModel Parse(std::string filename, int batch_size){
836
837 char sep = '/';
838 #ifdef _WIN32
839 sep = '\\';
840 #endif
841
842 size_t isep = filename.rfind(sep, filename.length());
843 std::string filename_nodir = filename;
844 if (isep != std::string::npos){
845 filename_nodir = (filename.substr(isep+1, filename.length() - isep));
846 }
847
848 //Check on whether the Keras .h5 file exists
849 if(!std::ifstream(filename).good()){
850 throw std::runtime_error("Model file "+filename_nodir+" not found!");
851 }
852
853
854 std::time_t ttime = std::time(0);
855 std::tm* gmt_time = std::gmtime(&ttime);
856 std::string parsetime (std::asctime(gmt_time));
857
859
860 //Intializing Python Interpreter and scope dictionaries
862 PyObject* main = PyImport_AddModule("__main__");
863 PyObject* fGlobalNS = PyModule_GetDict(main);
864 PyObject* fLocalNS = PyDict_New();
865 if (!fGlobalNS) {
866 throw std::runtime_error("Can't init global namespace for Python");
867 }
868 if (!fLocalNS) {
869 throw std::runtime_error("Can't init local namespace for Python");
870 }
871
872 // Extracting model information
873 // For each layer: type,name,activation,dtype,input tensor's name,
874 // output tensor's name, kernel's name, bias's name
875 // None object is returned for if property doesn't belong to layer
876 PyRunString("import tensorflow",fGlobalNS,fLocalNS);
877 PyRunString("import tensorflow.keras as keras",fGlobalNS,fLocalNS);
878 PyRunString("from tensorflow.keras.models import load_model",fGlobalNS,fLocalNS);
879 PyRunString("print('TF/Keras Version: '+ tensorflow.__version__)",fGlobalNS,fLocalNS);
880 PyRunString(TString::Format("model=load_model('%s')",filename.c_str()),fGlobalNS,fLocalNS);
881 PyRunString(TString::Format("model.load_weights('%s')",filename.c_str()),fGlobalNS,fLocalNS);
882 PyRunString("globals().update(locals())",fGlobalNS,fLocalNS);
883 PyRunString("modelData=[]",fGlobalNS,fLocalNS);
884 PyRunString("for idx in range(len(model.layers)):\n"
885 " layer=model.get_layer(index=idx)\n"
886 " layerData={}\n"
887 " layerData['layerType']=layer.__class__.__name__\n"
888 " layerData['layerAttributes']=layer.__dict__\n"
889 " layerData['layerInput']=[x.name for x in layer.input] if isinstance(layer.input,list) else [layer.input.name]\n"
890 " layerData['layerOutput']=[x.name for x in layer.output] if isinstance(layer.output,list) else [layer.output.name]\n"
891 " layerData['layerDType']=layer.dtype\n"
892 " layerData['layerWeight']=[x.name for x in layer.weights]\n"
893 " modelData.append(layerData)",fGlobalNS,fLocalNS);
894
895
896 PyObject* fPModel = GetValueFromDict(fLocalNS,"modelData");
897 PyObject *fLayer;
899 std::string fLayerType;
900
901 // Traversing through all the layers and passing the Layer object to `AddKerasLayer()`
902 // for adding the equivalent ROperators into the RModel object.
905 fLayerType = PyStringAsString(GetValueFromDict(fLayer,"layerType"));
906
907 // Ignoring the input layer for models built using Keras Functional API
908 if(fLayerType == "InputLayer")
909 continue;
910
911 // Adding any required routines depending on the Layer types for generating
912 // inference code.
913 else if(fLayerType == "Dense")
914 rmodel.AddBlasRoutines({"Gemm", "Gemv"});
915 else if (fLayerType == "BatchNormalization")
916 rmodel.AddBlasRoutines({"Copy", "Axpy"});
917 else if(fLayerType == "Conv1D" || fLayerType == "Conv2D" || fLayerType == "Conv3D")
918 rmodel.AddBlasRoutines({"Gemm", "Axpy"});
919
921
922 }
923
924 //Extracting model's weights
925 //For every initialized tensor, weightProp will have its name and dtype in string
926 //and value in numpy array
927 PyRunString("weight=[]",fGlobalNS,fLocalNS);
928 PyRunString("for idx in range(len(model.get_weights())):\n"
929 " weightProp={}\n"
930 " weightProp['name']=model.weights[idx].name\n"
931 " weightProp['dtype']=(model.get_weights())[idx].dtype.name\n"
932 " weightProp['value']=(model.get_weights())[idx].transpose((3,2,0,1)).copy() if ('conv' in model.weights[idx].name and model.weights[idx].shape.ndims == 4) else (model.get_weights())[idx]\n"
933 " weight.append(weightProp)",fGlobalNS,fLocalNS);
934
937 std::string fWeightName;
939 fPWeight = GetValueFromDict(fLocalNS,"weight");
940 std::vector<std::size_t> fWeightTensorShape;
941 std::size_t fWeightTensorSize;
942
943 // Traversing through all the Weight tensors
946 fWeightName = PyStringAsString(GetValueFromDict(fWeightTensor,"name"));
947 fWeightDType = ConvertStringToType(PyStringAsString(GetValueFromDict(fWeightTensor,"dtype")));
948
949 fWeightTensorValue = (PyArrayObject*)GetValueFromDict(fWeightTensor,"value");
951 fWeightTensorShape.clear();
952
953 // Building the shape vector and finding the tensor size
954 for(int j=0; j<PyArray_NDIM(fWeightTensorValue); ++j){
955 fWeightTensorShape.push_back((std::size_t)(PyArray_DIM(fWeightTensorValue,j)));
957 }
958
959 switch(fWeightDType){
960 case ETensorType::FLOAT : {
962 std::shared_ptr<void> fData(malloc(fWeightTensorSize * sizeof(float)), free);
963 std::memcpy(fData.get(),fWeightArray, fWeightTensorSize * sizeof(float));
964 rmodel.AddInitializedTensor(fWeightName,ETensorType::FLOAT,fWeightTensorShape,fData);
965 break;
966 }
967 default:
968 throw std::runtime_error("Type error: TMVA SOFIE does not yet weight data layer type"+ConvertTypeToString(fWeightDType));
969 }
970 }
971
972
973 // Extracting input tensor info
974 // For every input tensor inputNames will have their names as string,
975 // inputShapes will have their shape as Python Tuple, and inputTypes
976 // will have their dtype as string
977 PyRunString("inputNames=model.input_names",fGlobalNS,fLocalNS);
978 PyRunString("inputShapes=model.input_shape if type(model.input_shape)==list else [model.input_shape]",fGlobalNS,fLocalNS);
979 PyRunString("inputTypes=[]",fGlobalNS,fLocalNS);
980 PyRunString("for idx in range(len(model.inputs)):\n"
981 " inputTypes.append(model.inputs[idx].dtype.__str__()[9:-2])",fGlobalNS,fLocalNS);
982
983 PyObject* fPInputs = GetValueFromDict(fLocalNS,"inputNames");
984 PyObject* fPInputShapes = GetValueFromDict(fLocalNS,"inputShapes");
985 PyObject* fPInputTypes = GetValueFromDict(fLocalNS,"inputTypes");
986
987 std::string fInputName;
989
990 // For single input models, the model.input_shape will return a tuple
991 // describing the input tensor shape. For multiple inputs models,
992 // the model.input_shape will return a list of tuple, each describing
993 // the input tensor shape.
995 fInputName = PyStringAsString(PyList_GetItem(fPInputs,0));
997
998 switch(fInputDType){
999
1000 case ETensorType::FLOAT : {
1001
1002 // Getting the shape vector from the Tuple object
1003 std::vector<size_t>fInputShape = GetDataFromTuple(fPInputShapes);
1004 if (static_cast<int>(fInputShape[0]) <= 0){
1005 fInputShape[0] = std::max(batch_size,1);
1006 std::cout << "Model has not a defined batch size ";
1007 if (batch_size <=0) std::cout << " assume is 1 ";
1008 else std::cout << " use given value of " << batch_size;
1009 std::cout << " - input shape for tensor " << fInputName << " : "
1010 << TMVA::Experimental::SOFIE::ConvertShapeToString(fInputShape) << std::endl;
1011 }
1012 rmodel.AddInputTensorInfo(fInputName, ETensorType::FLOAT, fInputShape);
1013 rmodel.AddInputTensorName(fInputName);
1014 break;
1015 }
1016
1017 default:
1018 throw std::runtime_error("Type error: TMVA SOFIE does not yet support data type"+ConvertTypeToString(fInputDType));
1019 }
1020
1021 }
1022
1023 else{
1024
1025 // Iterating through multiple input tensors
1027
1028 fInputName = PyStringAsString(PyList_GetItem(fPInputs,inputIter));
1030
1031 switch(fInputDType){
1032 case ETensorType::FLOAT : {
1034
1035 std::vector<size_t>fInputShape = GetDataFromTuple(fInputShapeTuple);
1036 if (static_cast<int>(fInputShape[0]) <= 0){
1037 fInputShape[0] = std::max(batch_size,1);
1038 std::cout << "Model has not a defined batch size ";
1039 if (batch_size <=0) std::cout << " assume is 1 ";
1040 else std::cout << " use given value of " << batch_size;
1041 std::cout << " - input shape for tensor "
1042 << fInputName << " : " << TMVA::Experimental::SOFIE::ConvertShapeToString(fInputShape) << std::endl;
1043 }
1044 rmodel.AddInputTensorInfo(fInputName, ETensorType::FLOAT, fInputShape);
1045 rmodel.AddInputTensorName(fInputName);
1046 break;
1047 }
1048
1049 default:
1050 throw std::runtime_error("Type error: TMVA SOFIE does not yet support data type"+ConvertTypeToString(fInputDType));
1051
1052 }
1053 }
1054 }
1055
1056
1057 // For adding OutputTensorInfos, the names of the output
1058 // tensors are extracted from the Keras model
1059 PyRunString("outputNames=[]",fGlobalNS,fLocalNS);
1060 PyRunString("for layerName in model.output_names:\n"
1061 " outputNames.append(model.get_layer(layerName).output.name)",fGlobalNS,fLocalNS);
1062 PyObject* fPOutputs = GetValueFromDict(fLocalNS,"outputNames");
1063 std::vector<std::string> fOutputNames;
1065 fOutputNames.push_back(PyStringAsString(PyList_GetItem(fPOutputs,outputIter)));
1066 }
1067 rmodel.AddOutputTensorNameList(fOutputNames);
1068
1069 return rmodel;
1070}
1071
1072} // namespace TMVA::Experimental::SOFIE::PyKeras
int Py_ssize_t
Definition CPyCppyy.h:215
#define PyBytes_AsString
Definition CPyCppyy.h:64
int main()
Definition Prototype.cxx:12
_object PyObject
#define Py_single_input
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
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
#define malloc
Definition civetweb.c:1575
const_iterator begin() const
const_iterator end() const
Basic string class.
Definition TString.h:138
static TString Format(const char *fmt,...)
Static method which formats a string using a printf style format descriptor and return a TString.
Definition TString.cxx:2384
std::unique_ptr< ROperator > MakeKerasConv(PyObject *fLayer)
Prepares a ROperator object for Keras Conv Layer.
std::unordered_map< std::string, std::unique_ptr< ROperator >(*)(PyObject *fLayer)> KerasMethodMap
std::unique_ptr< ROperator > MakeKerasPermute(PyObject *fLayer)
Prepares a ROperator object for Keras Permute layer.
std::unique_ptr< ROperator > MakeKerasBatchNorm(PyObject *fLayer)
Prepares a ROperator object for Keras BatchNorm layer.
std::unique_ptr< ROperator > MakeKerasSwish(PyObject *fLayer)
Prepares a ROperator object for Keras Swish activation.
void AddKerasLayer(RModel &rmodel, PyObject *fLayer)
Adds equivalent ROperator with respect to Keras model layer into the referenced RModel object.
std::unique_ptr< ROperator > MakeKerasConcat(PyObject *fLayer)
Prepares a ROperator object for Keras Concat layer.
std::unique_ptr< ROperator > MakeKerasLeakyRelu(PyObject *fLayer)
Prepares a ROperator object for Keras Leaky Relu activation.
std::unique_ptr< ROperator > MakeKerasDense(PyObject *fLayer)
Prepares a ROperator object for Keras Dense Layer.
std::unique_ptr< ROperator > MakeKerasBinary(PyObject *fLayer)
Prepares a ROperator object for Keras binary operations like Add, subtract, and multiply.
std::unique_ptr< ROperator > MakeKerasTanh(PyObject *fLayer)
Prepares a ROperator object for Keras Tanh activation.
std::unique_ptr< ROperator > MakeKerasSoftmax(PyObject *fLayer)
Prepares a ROperator object for Keras Softmax activation.
std::unique_ptr< ROperator > MakeKerasReshape(PyObject *fLayer)
Prepares a ROperator object for Keras Reshape layer.
std::unique_ptr< ROperator > MakeKerasReLU(PyObject *fLayer)
Prepares a ROperator object for Keras ReLU activation.
const KerasMethodMapWithActivation mapKerasLayerWithActivation
std::unique_ptr< ROperator > MakeKerasIdentity(PyObject *fLayer)
Prepares a ROperator object for Keras Identity and Dropout Layer.
std::unique_ptr< ROperator > MakeKerasSigmoid(PyObject *fLayer)
Prepares a ROperator object for Keras Sigmoid activation.
std::unique_ptr< ROperator > MakeKerasSelu(PyObject *fLayer)
Prepares a ROperator object for Keras Selu activation.
std::unordered_map< std::string, std::unique_ptr< ROperator >(*)(PyObject *fLayer)> KerasMethodMapWithActivation
std::unique_ptr< ROperator > MakeKerasActivation(PyObject *fLayer)
Prepares a ROperator object for Keras activation layer.
RModel Parse(std::string filename, int batch_size=-1)
Parser function for translatng Keras .h5 model into a RModel object.
std::string ConvertTypeToString(ETensorType type)
ETensorType ConvertStringToType(std::string type)
std::string ConvertShapeToString(const std::vector< size_t > &shape)
static void output()