16#ifndef TMVA_RSOFIEREADER
17#define TMVA_RSOFIEREADER
34namespace Experimental {
58 void Load(
const std::string &path, std::vector<std::vector<size_t>>
inputShapes = {},
int verbose = 0)
64 auto pos1 = path.rfind(
"/");
65 auto pos2 = path.find(
".onnx");
66 if (
pos2 != std::string::npos) {
69 pos2 = path.find(
".h5");
70 if (
pos2 != std::string::npos) {
73 pos2 = path.find(
".pt");
74 if (
pos2 != std::string::npos) {
78 pos2 = path.find(
".root");
79 if (
pos2 != std::string::npos) {
86 throw std::runtime_error(
"Input file is not an ONNX or Keras or PyTorch file");
88 if (
pos1 == std::string::npos)
94 if (verbose) std::cout <<
"Parsing SOFIE model " <<
modelName <<
" of type " <<
fileType << std::endl;
102 throw std::runtime_error(
"RSofieReader: cannot use SOFIE with ONNX since libROOTTMVASofieParser is missing");
104 gInterpreter->Declare(
"#include \"TMVA/RModelParser_ONNX.hxx\"");
105 parserCode +=
"{\nTMVA::Experimental::SOFIE::RModelParser_ONNX parser ; \n";
107 parserCode +=
"TMVA::Experimental::SOFIE::RModel model = parser.Parse(\"" + path +
"\",true); \n";
109 parserCode +=
"TMVA::Experimental::SOFIE::RModel model = parser.Parse(\"" + path +
"\"); \n";
114 throw std::runtime_error(
"RSofieReader: cannot use SOFIE with Keras since libPyMVA is missing");
120 parserCode +=
"{\nTMVA::Experimental::SOFIE::RModel model = TMVA::Experimental::SOFIE::PyKeras::Parse(\"" + path +
126 throw std::runtime_error(
"RSofieReader: cannot use SOFIE with PyTorch since libPyMVA is missing");
129 throw std::runtime_error(
"RSofieReader: cannot use SOFIE with PyTorch since the input tensor shape is missing and is needed by the PyTorch parser");
132 for (
unsigned int i = 0; i <
inputShapes.size(); i++) {
142 parserCode +=
"{\nTMVA::Experimental::SOFIE::RModel model = TMVA::Experimental::SOFIE::PyTorch::Parse(\"" + path +
"\", "
145 else if (
type == kROOT) {
147 parserCode +=
"{\nauto fileRead = TFile::Open(\"" + path +
"\",\"READ\");\n";
148 parserCode +=
"TMVA::Experimental::SOFIE::RModel * modelPtr;\n";
149 parserCode +=
"auto keyList = fileRead->GetListOfKeys(); TString name;\n";
150 parserCode +=
"for (const auto&& k : *keyList) { \n";
151 parserCode +=
" TString cname = ((TKey*)k)->GetClassName(); if (cname==\"TMVA::Experimental::SOFIE::RModel\") name = k->GetName(); }\n";
152 parserCode +=
"fileRead->GetObject(name,modelPtr); fileRead->Close(); delete fileRead;\n";
153 parserCode +=
"TMVA::Experimental::SOFIE::RModel & model = *modelPtr;\n";
160 parserCode +=
"{ auto p = new TMVA::Experimental::SOFIE::ROperator_Custom<float>(\""
161 +
op.fOpName +
"\"," +
op.fInputNames +
"," +
op.fOutputNames +
"," +
op.fOutputShapes +
",\"" +
op.fFileName +
"\");\n";
162 parserCode +=
"std::unique_ptr<TMVA::Experimental::SOFIE::ROperator> op(p);\n";
163 parserCode +=
"model.AddOperator(std::move(op));\n}\n";
170 if (batchSize < 1) batchSize = 1;
172 if (verbose) std::cout <<
"generating the code with batch size = " << batchSize <<
" ...\n";
174 parserCode +=
"model.Generate(TMVA::Experimental::SOFIE::Options::kDefault,"
178 parserCode +=
"model.PrintRequiredInputTensors();\n";
179 parserCode +=
"model.PrintIntermediateTensors();\n";
180 parserCode +=
"model.PrintOutputTensors();\n";
187 parserCode +=
"model.PrintRequiredInputTensors();\n";
188 parserCode +=
"model.PrintIntermediateTensors();\n";
189 parserCode +=
"model.PrintOutputTensors();\n";
192 parserCode +=
"{ auto p = new TMVA::Experimental::SOFIE::ROperator_Custom<float>(\""
193 +
op.fOpName +
"\"," +
op.fInputNames +
"," +
op.fOutputNames +
"," +
op.fOutputShapes +
",\"" +
op.fFileName +
"\");\n";
194 parserCode +=
"std::unique_ptr<TMVA::Experimental::SOFIE::ROperator> op(p);\n";
195 parserCode +=
"model.AddOperator(std::move(op));\n}\n";
197 parserCode +=
"model.Generate(TMVA::Experimental::SOFIE::Options::kDefault,"
205 parserCode +=
"int nInputs = model.GetInputTensorNames().size();\n";
212 if (verbose) std::cout <<
"//ParserCode being executed:\n" <<
parserCode << std::endl;
216 std::string
msg =
"RSofieReader: error processing the parser code: \n" +
parserCode;
217 throw std::runtime_error(
msg);
221 throw std::runtime_error(
"RSofieReader does not yet support model with > 3 inputs");
226 if (verbose) std::cout <<
"compile generated code from file " <<
modelHeader << std::endl;
228 std::string
msg =
"RSofieReader: input header file " +
modelHeader +
" is not existing";
229 throw std::runtime_error(
msg);
231 if (verbose) std::cout <<
"Creating Inference function for model " <<
modelName << std::endl;
233 declCode +=
"#pragma cling optimize(2)\n";
240 [](
char const&
c ) ->
bool { return !std::isalnum(c); } ),
uidName.
end());
245 if (verbose) std::cout <<
"//global session declaration\n" <<
declCode << std::endl;
249 std::string
msg =
"RSofieReader: error compiling inference code and creating session class\n" +
declCode;
250 throw std::runtime_error(
msg);
257 std::string funcName =
"SofieInference_" +
uidName;
258 ifuncCode <<
"std::vector<float> " + funcName +
"( void * ptr";
264 for (
int i = 0; i <
fNInputs; i++) {
271 if (verbose) std::cout <<
"//Inference function code using global session instance\n"
276 std::string
msg =
"RSofieReader: error compiling inference function\n" +
ifuncCode.str();
277 throw std::runtime_error(
msg);
286 const std::string &
outputShapes,
const std::string & fileName) {
287 if (
fInitialized) std::cout <<
"WARNING: Model is already loaded and initialised. It must be done after adding the custom operators" << std::endl;
294 std::string
msg =
"Wrong number of inputs - model requires " + std::to_string(
fNInputs);
295 throw std::runtime_error(
msg);
297 auto fptr =
reinterpret_cast<std::vector<float> (*)(
void *,
const float *)
>(
fFuncPtr);
300 std::vector<float>
DoCompute(
const std::vector<float> &
x1,
const std::vector<float> &
x2) {
302 std::string
msg =
"Wrong number of inputs - model requires " + std::to_string(
fNInputs);
303 throw std::runtime_error(
msg);
305 auto fptr =
reinterpret_cast<std::vector<float> (*)(
void *,
const float *,
const float *)
>(
fFuncPtr);
308 std::vector<float>
DoCompute(
const std::vector<float> &
x1,
const std::vector<float> &
x2,
const std::vector<float> &
x3) {
310 std::string
msg =
"Wrong number of inputs - model requires " + std::to_string(
fNInputs);
311 throw std::runtime_error(
msg);
313 auto fptr =
reinterpret_cast<std::vector<float> (*)(
void *,
const float *,
const float *,
const float *)
>(
fFuncPtr);
318 template<
typename... T>
322 return std::vector<float>();
332 std::vector<float>
Compute(
const std::vector<float> &
x) {
334 return std::vector<float>();
352 const auto nrows =
x.GetShape()[0];
353 const auto rowsize =
x.GetStrides()[0];
354 auto fptr =
reinterpret_cast<std::vector<float> (*)(
void *,
const float *)
>(
fFuncPtr);
361 for (
size_t i = 1; i <
nrows; i++) {
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
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 result
Option_t Option_t TPoint TPoint const char x2
Option_t Option_t TPoint TPoint const char x1
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
R__EXTERN TSystem * gSystem
#define R__WRITE_LOCKGUARD(mutex)
const_iterator begin() const
const_iterator end() const
TMVA::RSofieReader class for reading external Machine Learning models in ONNX files,...
RSofieReader(const std::string &path, std::vector< std::vector< size_t > > inputShapes={}, int verbose=0)
Create TMVA model from ONNX file print level can be 0 (minimal) 1 with info , 2 with all ONNX parsing...
RTensor< float > Compute(RTensor< float > &x)
Compute model prediction on input RTensor The shape of the input tensor should be {nevents,...
std::vector< float > Compute(const std::vector< float > &x)
std::vector< float > Compute(T... x)
Compute model prediction on vector.
void Load(const std::string &path, std::vector< std::vector< size_t > > inputShapes={}, int verbose=0)
std::vector< float > DoCompute(const std::vector< float > &x1, const std::vector< float > &x2, const std::vector< float > &x3)
std::vector< CustomOperatorData > fCustomOperators
std::vector< float > DoCompute(const std::vector< float > &x1)
void AddCustomOperator(const std::string &opName, const std::string &inputNames, const std::string &outputNames, const std::string &outputShapes, const std::string &fileName)
std::vector< float > DoCompute(const std::vector< float > &x1, const std::vector< float > &x2)
RSofieReader()
Dummy constructor which needs model loading afterwards.
virtual int Load(const char *module, const char *entry="", Bool_t system=kFALSE)
Load a shared library.
virtual Bool_t AccessPathName(const char *path, EAccessMode mode=kFileExists)
Returns FALSE if one can access a file using the specified access mode.
This class defines a UUID (Universally Unique IDentifier), also known as GUIDs (Globally Unique IDent...
const char * AsString() const
Return UUID as string. Copy string immediately since it will be reused.
std::string ToString(const T &val)
Utility function for conversion to strings.
R__EXTERN TVirtualRWMutex * gCoreMutex
create variable transformations
std::string fOutputShapes