Skip to content

Commit da5fba1

Browse files
committed
[tmva][sofie] Migrate SOFIE tutorials from Keras to PyTorch and ONNX
PyTorch has become the dominant training framework in the particle physics community, and it comes with better ONNX support than Keras. Since ONNX is the primary input format for SOFIE, the SOFIE tutorials based on the Higgs dataset are migrated from Keras to PyTorch with ONNX export. Replace TMVA_SOFIE_Keras_HiggsModel.py with TMVA_SOFIE_PyTorch_HiggsModel.py, which trains the same architecture (7 -> 64 -> 64 -> 1 with sigmoid output, binary cross-entropy, Adam, 5 epochs) with PyTorch, exports it to HiggsModel.onnx and generates the inference code with RModelParser_ONNX. The generated code is validated against the PyTorch predictions, and the trained model was checked to be roughly equivalent to the Keras one (test AUC 0.712 vs. 0.720 on an identical data split). Adapt the downstream tutorials that consume the trained Higgs model (TMVA_SOFIE_RDataFrame.C/.py, TMVA_SOFIE_RDataFrame_JIT.C, TMVA_SOFIE_RSofieReader.C, TMVA_SOFIE_Inference.py) to use HiggsModel.onnx instead of HiggsModel.keras. Also migrate TMVA_SOFIE_Models.py, which demonstrates storing several models in a single generated header with weights in one ROOT binary file: this feature is independent of the training framework. The PyTorch ONNX export and ROOT's SOFIE parser are usually linked against different protobuf versions, so the training and export run in a separate Python process, following the pattern established in TMVA_SOFIE_ONNX.py. The CMake test dependencies are updated accordingly, and the migrated tutorials are now gated on tmva-sofie plus the torch and onnx Python modules instead of keras. 🤖 Done with the help of AI.
1 parent 39e4fb2 commit da5fba1

11 files changed

Lines changed: 442 additions & 270 deletions

tmva/sofie/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,9 +176,9 @@ parser.CheckModel("example_model.ONNX");
176176
- **Tutorials**
177177
- [TMVA_SOFIE_Inference](https://github.com/root-project/root/blob/master/tutorials/machine_learning/TMVA_SOFIE_Inference.py)
178178
- [TMVA_SOFIE_Keras](https://github.com/root-project/root/blob/master/tutorials/machine_learning/TMVA_SOFIE_Keras.C)
179-
- [TMVA_SOFIE_Keras_HiggsModel](https://github.com/root-project/root/blob/master/tutorials/machine_learning/TMVA_SOFIE_Keras_HiggsModel.C)
180179
- [TMVA_SOFIE_ONNX](https://github.com/root-project/root/blob/master/tutorials/machine_learning/TMVA_SOFIE_ONNX.C)
181180
- [TMVA_SOFIE_PyTorch](https://github.com/root-project/root/blob/master/tutorials/machine_learning/TMVA_SOFIE_PyTorch.py)
181+
- [TMVA_SOFIE_PyTorch_HiggsModel](https://github.com/root-project/root/blob/master/tutorials/machine_learning/TMVA_SOFIE_PyTorch_HiggsModel.py)
182182
- [TMVA_SOFIE_RDataFrame](https://github.com/root-project/root/blob/master/tutorials/machine_learning/TMVA_SOFIE_RDataFrame.C)
183183
- [TMVA_SOFIE_RDataFrame](https://github.com/root-project/root/blob/master/tutorials/machine_learning/TMVA_SOFIE_RDataFrame.py)
184184
- [TMVA_SOFIE_RDataFrame_JIT](https://github.com/root-project/root/blob/master/tutorials/machine_learning/TMVA_SOFIE_RDataFrame_JIT.C)

tutorials/CMakeLists.txt

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -370,20 +370,20 @@ else()
370370
# These SOFIE tutorials take models trained via PyMVA-PyKeras as input
371371
if (NOT tmva-sofie OR NOT ROOT_KERAS_FOUND)
372372
list(APPEND tmva_veto machine_learning/TMVA_SOFIE_Keras.py)
373-
list(APPEND tmva_veto machine_learning/TMVA_SOFIE_Models.py)
374-
list(APPEND tmva_veto machine_learning/TMVA_SOFIE_Keras_HiggsModel.py)
375-
list(APPEND tmva_veto machine_learning/TMVA_SOFIE_RDataFrame.C)
376-
list(APPEND tmva_veto machine_learning/TMVA_SOFIE_RDataFrame_JIT.C)
377-
list(APPEND tmva_veto machine_learning/TMVA_SOFIE_RSofieReader.C)
378-
list(APPEND tmva_veto machine_learning/TMVA_SOFIE_RDataFrame.py)
379-
list(APPEND tmva_veto machine_learning/TMVA_SOFIE_RSofieReader.C)
380-
list(APPEND tmva_veto machine_learning/TMVA_SOFIE_Inference.py)
381373
endif()
382374
if (NOT tmva-sofie OR NOT ROOT_TORCH_FOUND)
383375
list(APPEND tmva_veto machine_learning/TMVA_SOFIE_PyTorch.py)
384376
endif()
377+
# These SOFIE tutorials take the ONNX HiggsModel trained with PyTorch as input
385378
if (NOT tmva-sofie OR NOT ROOT_TORCH_FOUND OR NOT ROOT_ONNX_FOUND)
386379
list(APPEND tmva_veto machine_learning/TMVA_SOFIE_ONNX.py)
380+
list(APPEND tmva_veto machine_learning/TMVA_SOFIE_Models.py)
381+
list(APPEND tmva_veto machine_learning/TMVA_SOFIE_PyTorch_HiggsModel.py)
382+
list(APPEND tmva_veto machine_learning/TMVA_SOFIE_RDataFrame.C)
383+
list(APPEND tmva_veto machine_learning/TMVA_SOFIE_RDataFrame_JIT.C)
384+
list(APPEND tmva_veto machine_learning/TMVA_SOFIE_RSofieReader.C)
385+
list(APPEND tmva_veto machine_learning/TMVA_SOFIE_RDataFrame.py)
386+
list(APPEND tmva_veto machine_learning/TMVA_SOFIE_Inference.py)
387387
endif()
388388
#veto this tutorial since it is added directly
389389
list(APPEND tmva_veto machine_learning/TMVA_SOFIE_GNN_Parser.py)
@@ -655,7 +655,7 @@ set (machine_learning-tmva004_RStandardScaler-depends tutorial-machine_learning-
655655
set (machine_learning-pytorch-ApplicationClassificationPyTorch-depends tutorial-machine_learning-pytorch-ClassificationPyTorch-py)
656656
set (machine_learning-pytorch-RegressionPyTorch-depends tutorial-machine_learning-pytorch-ApplicationClassificationPyTorch-py)
657657
set (machine_learning-pytorch-ApplicationRegressionPyTorch-depends tutorial-machine_learning-pytorch-RegressionPyTorch-py)
658-
set (machine_learning-TMVA_SOFIE_RDataFrame-depends tutorial-machine_learning-TMVA_SOFIE_Keras_HiggsModel-py)
658+
set (machine_learning-TMVA_SOFIE_RDataFrame-depends tutorial-machine_learning-TMVA_SOFIE_PyTorch_HiggsModel-py)
659659
set (machine_learning-TMVA_SOFIE_RDataFrame_JIT-depends tutorial-machine_learning-TMVA_SOFIE_RDataFrame)
660660
set (machine_learning-TMVA_SOFIE_RSofieReader-depends tutorial-machine_learning-TMVA_SOFIE_RDataFrame_JIT)
661661
set (machine_learning-TMVA_SOFIE_Inference-depends tutorial-machine_learning-TMVA_SOFIE_RSofieReader)
@@ -848,8 +848,8 @@ if(pyroot)
848848
list(APPEND pyveto ${tmva_veto_py})
849849
endif()
850850

851-
if (ROOT_KERAS_FOUND)
852-
set (machine_learning-TMVA_SOFIE_RDataFrame-py-depends tutorial-machine_learning-TMVA_SOFIE_Keras_HiggsModel)
851+
if (ROOT_TORCH_FOUND AND ROOT_ONNX_FOUND)
852+
set (machine_learning-TMVA_SOFIE_RDataFrame-py-depends tutorial-machine_learning-TMVA_SOFIE_PyTorch_HiggsModel)
853853
endif()
854854

855855
if(NOT tmva-pymva)
@@ -947,17 +947,16 @@ if(pyroot)
947947
roofit/roofit/rf409_NumPyPandasToRooFit.py)
948948

949949
file(GLOB requires_keras RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
950-
machine_learning/TMVA_SOFIE_Inference.py
951-
machine_learning/TMVA_SOFIE_Models.py
952-
machine_learning/TMVA_SOFIE_RDataFrame.py
953950
machine_learning/keras/*.py
954951
)
955952
file(GLOB requires_torch RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
956953
machine_learning/pytorch/*.py
957954
machine_learning/ml_dataloader_PyTorch.py
958955
machine_learning/ml_dataloader_resampling.py
959956
machine_learning/ml_dataloader_Higgs_Classification.py
957+
machine_learning/TMVA_SOFIE_Models.py
960958
machine_learning/TMVA_SOFIE_PyTorch.py
959+
machine_learning/TMVA_SOFIE_PyTorch_HiggsModel.py
961960
)
962961
file(GLOB requires_xgboost RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
963962
machine_learning/tmva101_Training.py
@@ -966,7 +965,6 @@ if(pyroot)
966965
roofit/roofit/rf618_mixture_models.py
967966
)
968967
file(GLOB requires_sklearn RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
969-
machine_learning/TMVA_SOFIE_Models.py
970968
machine_learning/tmva101_Training.py # uses the xgboost sklearn plugin
971969
machine_learning/tmva102_Testing.py # requires tmva101_Training.py
972970
machine_learning/ml_dataloader_XGBoost.py

tutorials/machine_learning/TMVA_SOFIE_Inference.py

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
### \file
22
### \ingroup tutorial_ml
33
### \notebook -nodraw
4-
### This macro provides an example of using a trained model with Keras
4+
### This macro provides an example of using a trained model with PyTorch
55
### and make inference using SOFIE directly from Numpy
6-
### This macro uses as input a Keras model generated with the
7-
### TMVA_Higgs_Classification.C tutorial
6+
### This macro uses as input an ONNX model generated with the
7+
### TMVA_SOFIE_PyTorch_HiggsModel.py tutorial
88
### You need to run that macro before this one.
99
### In this case we are parsing the input file and then run the inference in the same
1010
### macro making use of the ROOT JITing capability
@@ -20,32 +20,28 @@
2020
import ROOT
2121

2222
# check if the input file exists
23-
modelFile = "HiggsModel.keras"
23+
modelFile = "HiggsModel.onnx"
2424

2525
if not exists(modelFile):
26-
raise FileNotFoundError("You need to run TMVA_Higgs_Classification.C to generate the Keras trained model")
26+
raise FileNotFoundError("You need to run TMVA_SOFIE_PyTorch_HiggsModel.py to generate the ONNX trained model")
2727

2828

29-
# parse the input Keras model into RModel object
30-
model = ROOT.TMVA.Experimental.SOFIE.PyKeras.Parse(modelFile)
29+
# parse the input ONNX model into RModel object
30+
parser = ROOT.TMVA.Experimental.SOFIE.RModelParser_ONNX()
31+
model = parser.Parse(modelFile)
3132

32-
generatedHeaderFile = modelFile.replace(".keras",".hxx")
33-
print("Generating inference code for the Keras model from ",modelFile,"in the header ", generatedHeaderFile)
33+
generatedHeaderFile = modelFile.replace(".onnx", ".hxx")
34+
print("Generating inference code for the ONNX model from ", modelFile, "in the header ", generatedHeaderFile)
3435
#Generating inference code
3536
model.Generate()
3637
model.OutputGenerated(generatedHeaderFile)
3738
model.PrintGenerated()
3839

3940
# now compile using ROOT JIT trained model
40-
modelName = modelFile.replace(".keras","")
41+
modelName = modelFile.replace(".onnx", "")
4142
print("compiling SOFIE model ", modelName)
4243
ROOT.gInterpreter.Declare('#include "' + generatedHeaderFile + '"')
4344

44-
45-
generatedHeaderFile = modelFile.replace(".keras",".hxx")
46-
print("Generating inference code for the Keras model from ",modelFile,"in the header ", generatedHeaderFile)
47-
#Generating inference
48-
4945
inputFileName = "Higgs_data.root"
5046
inputFile = str(ROOT.gROOT.GetTutorialDir()) + "/machine_learning/data/" + inputFileName
5147

tutorials/machine_learning/TMVA_SOFIE_Keras_HiggsModel.py

Lines changed: 0 additions & 164 deletions
This file was deleted.

0 commit comments

Comments
 (0)