diff --git a/root/tmva/tmva/CMakeLists.txt b/root/tmva/tmva/CMakeLists.txt index e57484a3..7e63feef 100644 --- a/root/tmva/tmva/CMakeLists.txt +++ b/root/tmva/tmva/CMakeLists.txt @@ -15,6 +15,11 @@ if(ROOT_tmva_FOUND AND ROOT_tmva-cpu_FOUND AND ROOT_imt_FOUND) ConvNetCpuBenchmarks.cxx LABEL short LIBRARIES Core Tree MathCore RIO Hist TMVA) + + RB_ADD_GBENCHMARK(RNNCpuBenchmarks + RNNCpuBenchmarks.cxx + LABEL long + LIBRARIES Core Tree MathCore Gpad RIO Hist TMVA) endif() if (ROOT_cuda_FOUND AND ROOT_tmva-gpu_FOUND) @@ -23,4 +28,9 @@ if (ROOT_cuda_FOUND AND ROOT_tmva-gpu_FOUND) ConvNetCudaBenchmarks.cxx LABEL short LIBRARIES Core Tree MathCore RIO Hist TMVA ${DNN_CUDA_LIBRARIES}) + + RB_ADD_GBENCHMARK(RNNCudaBenchmarks + RNNCudaBenchmarks.cxx + LABEL long + LIBRARIES Core Tree MathCore Gpad RIO Hist TMVA ${DNN_CUDA_LIBRARIES}) endif() diff --git a/root/tmva/tmva/ConvNetBenchmarks.h b/root/tmva/tmva/ConvNetBenchmarks.h index 43e367a3..bc790fa6 100644 --- a/root/tmva/tmva/ConvNetBenchmarks.h +++ b/root/tmva/tmva/ConvNetBenchmarks.h @@ -115,4 +115,4 @@ void CNN_benchmark(TString archName) { factory->TestAllMethods(); outputFile->Close(); -} \ No newline at end of file +} diff --git a/root/tmva/tmva/ConvNetCpuBenchmarks.cxx b/root/tmva/tmva/ConvNetCpuBenchmarks.cxx index 26bf94ce..9772b0d2 100644 --- a/root/tmva/tmva/ConvNetCpuBenchmarks.cxx +++ b/root/tmva/tmva/ConvNetCpuBenchmarks.cxx @@ -12,4 +12,4 @@ static void BM_ConvolutionalNetwork_CPU(benchmark::State &state) } BENCHMARK(BM_ConvolutionalNetwork_CPU); -BENCHMARK_MAIN(); \ No newline at end of file +BENCHMARK_MAIN(); diff --git a/root/tmva/tmva/RNNBenchmarks.h b/root/tmva/tmva/RNNBenchmarks.h new file mode 100644 index 00000000..af1e8c6c --- /dev/null +++ b/root/tmva/tmva/RNNBenchmarks.h @@ -0,0 +1,230 @@ +#include "TMVA/Factory.h" +#include "TMVA/DataLoader.h" +#include "TMVA/DataSetInfo.h" +#include "TMVA/Config.h" +#include "TMVA/MethodDL.h" +#include "TROOT.h" +#include "TFile.h" +#include "TTree.h" +#include "TSystem.h" +#include "TH1.h" +#include "TF1.h" +#include "TRandom.h" +#include "TPad.h" +#include "TCanvas.h" + +#include "rootbench/RBConfig.h" + +void MakeTimeData(int n, int ntime, int ndim ){ + TString fname = TString::Format("%s/time_data_t%d_d%d.root", RB::GetTempFs().c_str(), ntime, ndim); + + std::vector v1(ntime); + std::vector v2(ntime); + + int i = 0; + + for (int i = 0; i < ntime; ++i) { + v1[i] = new TH1D(TString::Format("h1_%d", i), "h1", ndim, 0, 10); + v2[i] = new TH1D(TString::Format("h2_%d", i), "h2", ndim, 0, 10); + } + + auto f1 = new TF1("f1", "gaus"); + auto f2 = new TF1("f2", "gaus"); + + TTree sgn("sgn", "sgn"); + TTree bkg("bkg", "bkg"); + TFile f(fname, "RECREATE"); + + std::vector> x1(ntime); + std::vector> x2(ntime); + + for (int i = 0; i < ntime; ++i) { + x1[i] = std::vector(ndim); + x2[i] = std::vector(ndim); + } + + for (auto i = 0; i < ntime; i++) { + bkg.Branch(Form("vars_time%d", i), "std::vector", &x1[i]); + sgn.Branch(Form("vars_time%d", i), "std::vector", &x2[i]); + } + + sgn.SetDirectory(&f); + bkg.SetDirectory(&f); + gRandom->SetSeed(0); + + std::vector mean1(ntime); + std::vector mean2(ntime); + std::vector sigma1(ntime); + std::vector sigma2(ntime); + + for (int j = 0; j < ntime; ++j) { + mean1[j] = 5. + 0.2 * sin(TMath::Pi() * j / double(ntime)); + mean2[j] = 5. + 0.2 * cos(TMath::Pi() * j / double(ntime)); + sigma1[j] = 4 + 0.3 * sin(TMath::Pi() * j / double(ntime)); + sigma2[j] = 4 + 0.3 * cos(TMath::Pi() * j / double(ntime)); + } + + for (int i = 0; i < n; ++i) { + if (i % 1000 == 0) + std::cout << "Generating event ... " << i << std::endl; + + for (int j = 0; j < ntime; ++j) { + auto h1 = v1[j]; + auto h2 = v2[j]; + h1->Reset(); + h2->Reset(); + + f1->SetParameters(1, mean1[j], sigma1[j]); + f2->SetParameters(1, mean2[j], sigma2[j]); + + h1->FillRandom("f1", 1000); + h2->FillRandom("f2", 1000); + + for (int k = 0; k < ndim; ++k) { + x1[j][k] = h1->GetBinContent(k + 1) + gRandom->Gaus(0, 10); + x2[j][k] = h2->GetBinContent(k + 1) + gRandom->Gaus(0, 10); + } + } + + sgn.Fill(); + bkg.Fill(); + + if (n == 1) { + auto c1 = new TCanvas(); + c1->Divide(ntime, 2); + + for (int j = 0; j < ntime; ++j) { + c1->cd(j + 1); + v1[j]->Draw(); + } + + for (int j = 0; j < ntime; ++j) { + c1->cd(ntime + j + 1); + v2[j]->Draw(); + } + + gPad->Update(); + } + } + + if (n > 1) { + sgn.Write(); + bkg.Write(); + sgn.Print(); + bkg.Print(); + f.Close(); + } +} + +void RNN_benchmark(TString archName) { + const int ninput = 30; + const int ntime = 10; + const int batchSize = 100; + const int maxepochs = 20; + + int nTotEvts = 10000; + +#ifndef R__HAS_TMVAGPU + if (archName == "GPU") { + Error("TMVA_RNN_Classification", "Architecture not supported. Cannot use TMVA Deep Learning for RNN."); + return; + } +#endif +#ifndef R__HAS_TMVACPU + if (archName == "CPU") { + Error("TMVA_RNN_Classification", "Architecture not supported. Cannot use TMVA Deep Learning for RNN."); + return; + } +#endif + + int num_threads = 0; + ROOT::EnableImplicitMT(num_threads); + + TMVA::Config::Instance(); + + std::cout << "Running with nthreads = " << ROOT::GetThreadPoolSize() << std::endl; + + TString inputFileName = TString::Format("%s/time_data_t%d_d%d.root", RB::GetTempFs().c_str(), ntime, ninput); + + bool fileExist = !gSystem->AccessPathName(inputFileName); + + if (!fileExist) + MakeTimeData(nTotEvts,ntime, ninput); + + auto inputFile = TFile::Open(inputFileName); + if (!inputFile) { + Error("TMVA_RNN_Classification", "Error opening input file %s - exit", inputFileName.Data()); + return; + } + std::cout << "--- RNNClassification : Using input file: " << inputFile->GetName() << std::endl; + + TString outfileName(TString::Format("%s/data_RNN_%s.root", RB::GetTempFs().c_str(), archName.Data())); + TFile *outputFile = nullptr; + outputFile = TFile::Open(outfileName, "RECREATE"); + + // Creating the factory object + TMVA::Factory *factory = new TMVA::Factory("TMVAClassification", outputFile, + "!V:!Silent:Color:DrawProgressBar:Transformations=None:!Correlations:" + "AnalysisType=Classification:!ModelPersistence"); + TMVA::DataLoader *dataloader = new TMVA::DataLoader("dataset"); + + TTree *signalTree = (TTree *)inputFile->Get("sgn"); + TTree *background = (TTree *)inputFile->Get("bkg"); + + const int nvar = ninput * ntime; + + for (auto i = 0; i < ntime; i++) { + dataloader->AddVariablesArray(Form("vars_time%d", i), ninput); + } + + dataloader->AddSignalTree(signalTree, 1.0); + dataloader->AddBackgroundTree(background, 1.0); + + int nTrainSig = 0.8 * nTotEvts; + int nTrainBkg = 0.8 * nTotEvts; + + TString prepareOptions = TString::Format("nTrain_Signal=%d:nTrain_Background=%d:SplitMode=Random:SplitSeed=100:NormMode=NumEvents:!V:!CalcCorrelations", nTrainSig, nTrainBkg); + + TCut mycuts = ""; + TCut mycutb = ""; + + dataloader->PrepareTrainingAndTestTree(mycuts, mycutb, prepareOptions); + + std::cout << "prepared DATA LOADER " << std::endl; + + const char *rnn_type = "LSTM"; + + TString inputLayoutString = TString::Format("InputLayout=%d|%d", ntime, ninput); + TString rnnLayout = TString::Format("%s|10|%d|%d|0|1", rnn_type, ninput, ntime); + TString layoutString = TString("Layout=") + rnnLayout + TString(",RESHAPE|FLAT,DENSE|64|TANH,LINEAR"); + + TString trainingString1 = TString::Format("LearningRate=1e-3,Momentum=0.0,Repetitions=1," + "ConvergenceSteps=5,BatchSize=%d,TestRepetitions=1," + "WeightDecay=1e-2,Regularization=None,MaxEpochs=%d," + "Optimizer=ADAM,DropConfig=0.0+0.+0.+0.", batchSize, maxepochs); + + TString trainingStrategyString("TrainingStrategy="); + trainingStrategyString += trainingString1; + + TString rnnOptions("!H:V:ErrorStrategy=CROSSENTROPY:VarTransform=None:" + "WeightInitialization=XAVIERUNIFORM:ValidationSize=0.2:RandomSeed=1234"); + + rnnOptions.Append(":"); + rnnOptions.Append(inputLayoutString); + rnnOptions.Append(":"); + rnnOptions.Append(layoutString); + rnnOptions.Append(":"); + rnnOptions.Append(trainingStrategyString); + rnnOptions.Append(":"); + rnnOptions.Append(TString::Format("Architecture=%s", archName.Data())); + + TString rnnName = "TMVA_" + TString(rnn_type); + factory->BookMethod(dataloader, TMVA::Types::kDL, rnnName, rnnOptions); + + factory->TrainAllMethods(); + factory->TestAllMethods(); + factory->EvaluateAllMethods(); + + if (outputFile) + outputFile->Close(); +} diff --git a/root/tmva/tmva/RNNCpuBenchmarks.cxx b/root/tmva/tmva/RNNCpuBenchmarks.cxx new file mode 100644 index 00000000..80ab9d33 --- /dev/null +++ b/root/tmva/tmva/RNNCpuBenchmarks.cxx @@ -0,0 +1,15 @@ +#include "RNNBenchmarks.h" +#include "benchmark/benchmark.h" + +static void BM_RNN_CPU(benchmark::State &state) +{ + TString architecture("CPU"); + + // Benchmarking + for (auto _ : state) { + RNN_benchmark(architecture); + } +} +BENCHMARK(BM_RNN_CPU); + +BENCHMARK_MAIN(); diff --git a/root/tmva/tmva/RNNCudaBenchmarks.cxx b/root/tmva/tmva/RNNCudaBenchmarks.cxx new file mode 100644 index 00000000..cbd45977 --- /dev/null +++ b/root/tmva/tmva/RNNCudaBenchmarks.cxx @@ -0,0 +1,15 @@ +#include "RNNBenchmarks.h" +#include "benchmark/benchmark.h" + +static void BM_RNN_CUDA(benchmark::State &state) +{ + TString architecture("GPU"); + + // Benchmarking + for (auto _ : state) { + RNN_benchmark(architecture); + } +} +BENCHMARK(BM_RNN_CUDA); + +BENCHMARK_MAIN();