From d8951bbd2766485a7845a36b120d61156b144ed9 Mon Sep 17 00:00:00 2001 From: Huilin Qu Date: Sun, 8 Mar 2020 02:34:58 +0100 Subject: [PATCH] Restore TF and MXNet-based inference. And enable ONNXRuntime for x86/arm only. --- .../ONNXRuntime/interface/ONNXRuntime.h | 13 + PhysicsTools/ONNXRuntime/src/ONNXRuntime.cc | 18 +- .../ONNXRuntime/test/testONNXRuntime.cc | 5 + .../PatAlgos/python/tools/jetTools.py | 10 + .../TensorFlow/interface/TensorFlow.h | 4 +- PhysicsTools/TensorFlow/src/TensorFlow.cc | 4 +- .../FeatureTools/interface/tensor_fillers.h | 48 ++++ RecoBTag/FeatureTools/src/tensor_fillers.cc | 256 ++++++++++++++++++ RecoBTag/ONNXRuntime/plugins/BuildFile.xml | 1 + .../DeepBoostedJetONNXJetTagsProducer.cc | 2 +- .../plugins/DeepDoubleXONNXJetTagsProducer.cc | 72 +---- .../plugins/DeepFlavourONNXJetTagsProducer.cc | 95 +------ .../ONNXRuntime/python/SwitchProducerONNX.py | 39 +++ .../python/pfDeepBoostedJetTags_cfi.py | 40 +++ .../python/pfDeepBoostedJet_cff.py | 24 +- .../python/pfDeepDoubleXJetTags_cfi.py | 49 ++++ .../ONNXRuntime/python/pfDeepDoubleX_cff.py | 8 +- .../python/pfDeepFlavourJetTags_cfi.py | 8 + .../ONNXRuntime/python/pfDeepFlavour_cff.py | 1 - ...pfMassIndependentDeepDoubleXJetTags_cff.py | 12 - .../pfNegativeDeepFlavourJetTags_cfi.py | 6 +- RecoBTag/TensorFlow/BuildFile.xml | 5 - .../TensorFlow/interface/tensor_fillers.h | 66 ----- RecoBTag/TensorFlow/plugins/BuildFile.xml | 2 +- .../plugins/DeepDoubleXTFJetTagsProducer.cc | 230 ++++++++++++++++ .../plugins/DeepFlavourTFJetTagsProducer.cc | 213 +++++++++++++++ .../plugins/DeepVertexTFJetTagsProducer.cc | 9 +- RecoBTag/TensorFlow/src/tensor_fillers.cc | 251 ----------------- 28 files changed, 971 insertions(+), 520 deletions(-) create mode 100644 RecoBTag/FeatureTools/interface/tensor_fillers.h create mode 100644 RecoBTag/FeatureTools/src/tensor_fillers.cc create mode 100644 RecoBTag/ONNXRuntime/python/SwitchProducerONNX.py create mode 100644 RecoBTag/ONNXRuntime/python/pfDeepBoostedJetTags_cfi.py create mode 100644 RecoBTag/ONNXRuntime/python/pfDeepDoubleXJetTags_cfi.py create mode 100644 RecoBTag/ONNXRuntime/python/pfDeepFlavourJetTags_cfi.py delete mode 100644 RecoBTag/ONNXRuntime/python/pfMassIndependentDeepDoubleXJetTags_cff.py delete mode 100644 RecoBTag/TensorFlow/BuildFile.xml delete mode 100644 RecoBTag/TensorFlow/interface/tensor_fillers.h create mode 100644 RecoBTag/TensorFlow/plugins/DeepDoubleXTFJetTagsProducer.cc create mode 100644 RecoBTag/TensorFlow/plugins/DeepFlavourTFJetTagsProducer.cc delete mode 100644 RecoBTag/TensorFlow/src/tensor_fillers.cc diff --git a/PhysicsTools/ONNXRuntime/interface/ONNXRuntime.h b/PhysicsTools/ONNXRuntime/interface/ONNXRuntime.h index c8411e2eeb5fe..52f378c53acb2 100644 --- a/PhysicsTools/ONNXRuntime/interface/ONNXRuntime.h +++ b/PhysicsTools/ONNXRuntime/interface/ONNXRuntime.h @@ -16,7 +16,18 @@ #include #include +// currently ONNXRUNTIME only supports x86 and ARM +#if defined(__arm__) || defined(__aarch64__) || defined(__x86_64__) || defined(__i386__) +#define CMS_USE_ONNXRUNTIME +#endif + +#ifdef CMS_USE_ONNXRUNTIME #include "onnxruntime/core/session/onnxruntime_cxx_api.h" +#else +namespace Ort { + struct SessionOptions {}; +} // namespace Ort +#endif namespace cms::Ort { @@ -48,6 +59,7 @@ namespace cms::Ort { // The 0th dim depends on the batch size, therefore is set to -1 const std::vector& getOutputShape(const std::string& output_name) const; +#ifdef CMS_USE_ONNXRUNTIME private: static const ::Ort::Env env_; std::unique_ptr<::Ort::Session> session_; @@ -59,6 +71,7 @@ namespace cms::Ort { std::vector output_node_strings_; std::vector output_node_names_; std::map> output_node_dims_; +#endif }; } // namespace cms::Ort diff --git a/PhysicsTools/ONNXRuntime/src/ONNXRuntime.cc b/PhysicsTools/ONNXRuntime/src/ONNXRuntime.cc index 124155e9cbac0..7ca76762a1024 100644 --- a/PhysicsTools/ONNXRuntime/src/ONNXRuntime.cc +++ b/PhysicsTools/ONNXRuntime/src/ONNXRuntime.cc @@ -19,9 +19,12 @@ namespace cms::Ort { using namespace ::Ort; +#ifdef CMS_USE_ONNXRUNTIME const Env ONNXRuntime::env_(ORT_LOGGING_LEVEL_WARNING, ""); +#endif ONNXRuntime::ONNXRuntime(const std::string& model_path, const SessionOptions* session_options) { +#ifdef CMS_USE_ONNXRUNTIME // create session if (session_options) { session_.reset(new Session(env_, model_path.c_str(), *session_options)); @@ -76,6 +79,7 @@ namespace cms::Ort { // the 0th dim depends on the batch size output_node_dims_[output_name].at(0) = -1; } +#endif } ONNXRuntime::~ONNXRuntime() {} @@ -84,6 +88,7 @@ namespace cms::Ort { FloatArrays& input_values, const std::vector& output_names, int64_t batch_size) const { +#ifdef CMS_USE_ONNXRUNTIME assert(input_names.size() == input_values.size()); assert(batch_size > 0); @@ -142,23 +147,34 @@ namespace cms::Ort { assert(outputs.size() == run_output_node_names.size()); return outputs; +#else + throw cms::Exception("RuntimeError") << "ONNXRuntime does not support the current architecture"; +#endif } const std::vector& ONNXRuntime::getOutputNames() const { +#ifdef CMS_USE_ONNXRUNTIME if (session_) { return output_node_strings_; } else { - throw cms::Exception("RuntimeError") << "Needs to call createSession() first before getting the output names!"; + throw cms::Exception("RuntimeError") << "ONNXRuntime session is not initialized!"; } +#else + throw cms::Exception("RuntimeError") << "ONNXRuntime does not support the current architecture"; +#endif } const std::vector& ONNXRuntime::getOutputShape(const std::string& output_name) const { +#ifdef CMS_USE_ONNXRUNTIME auto iter = output_node_dims_.find(output_name); if (iter == output_node_dims_.end()) { throw cms::Exception("RuntimeError") << "Output name " << output_name << " is invalid!"; } else { return iter->second; } +#else + throw cms::Exception("RuntimeError") << "ONNXRuntime does not support the current architecture"; +#endif } } /* namespace cms::Ort */ diff --git a/PhysicsTools/ONNXRuntime/test/testONNXRuntime.cc b/PhysicsTools/ONNXRuntime/test/testONNXRuntime.cc index 1aac5bbcb4dde..2226fa3c30bb2 100644 --- a/PhysicsTools/ONNXRuntime/test/testONNXRuntime.cc +++ b/PhysicsTools/ONNXRuntime/test/testONNXRuntime.cc @@ -2,6 +2,7 @@ #include "PhysicsTools/ONNXRuntime/interface/ONNXRuntime.h" #include "FWCore/ParameterSet/interface/FileInPath.h" +#include "FWCore/Utilities/interface/Exception.h" #include #include @@ -27,11 +28,15 @@ void testONNXRuntime::checkAll() { std::vector(batch_size * 2, 1), }; FloatArrays outputs; +#ifdef CMS_USE_ONNXRUNTIME CPPUNIT_ASSERT_NO_THROW(outputs = rt.run({"X"}, input_values, {"Y"}, batch_size)); CPPUNIT_ASSERT(outputs.size() == 1); CPPUNIT_ASSERT(outputs[0].size() == batch_size); for (const auto &v : outputs[0]) { CPPUNIT_ASSERT(v == 3); } +#else + CPPUNIT_ASSERT_THROW(rt.run({"X"}, input_values, {"Y"}, batch_size), cms::Exception); +#endif } } diff --git a/PhysicsTools/PatAlgos/python/tools/jetTools.py b/PhysicsTools/PatAlgos/python/tools/jetTools.py index 19bf211c46459..0a521ce4b1a77 100644 --- a/PhysicsTools/PatAlgos/python/tools/jetTools.py +++ b/PhysicsTools/PatAlgos/python/tools/jetTools.py @@ -281,6 +281,7 @@ def setupBTagging(process, jetSource, pfCandidates, explicitJTA, pvSource, svSou process.load("RecoBTag.CTagging.cTagging_EventSetup_cff") import RecoBTag.Configuration.RecoBTag_cff as btag import RecoJets.JetProducers.caTopTaggers_cff as toptag + from RecoBTag.ONNXRuntime.SwitchProducerONNX import SwitchProducerONNX if tightBTagNTkHits: if not runIVF: @@ -720,6 +721,15 @@ def setupBTagging(process, jetSource, pfCandidates, explicitJTA, pvSource, svSou process, task ) + elif isinstance(getattr(btag, btagDiscr), SwitchProducerONNX): + addToProcessAndTask( + newDiscr, + getattr(btag, btagDiscr).cloneAll( + src = btagPrefix + supportedBtagDiscr[discriminator_name][0][0] + labelName + postfix + ), + process, + task + ) else: raise ValueError('I do not know how to update %s it does not have neither "tagInfos" nor "src" attributes' % btagDiscr) acceptedBtagDiscriminators.append(discriminator_name) diff --git a/PhysicsTools/TensorFlow/interface/TensorFlow.h b/PhysicsTools/TensorFlow/interface/TensorFlow.h index b43a1cd8bc578..b5ebf2f79b166 100644 --- a/PhysicsTools/TensorFlow/interface/TensorFlow.h +++ b/PhysicsTools/TensorFlow/interface/TensorFlow.h @@ -87,13 +87,13 @@ namespace tensorflow { // return a new session that will contain an already loaded graph def, sessionOptions are predefined // an error is thrown when graphDef is a nullptr or when the grah has no nodes // transfers ownership - Session* createSession(GraphDef* graphDef, SessionOptions& sessionOptions); + Session* createSession(const GraphDef* graphDef, SessionOptions& sessionOptions); // return a new session that will contain an already loaded graph def, threading options are // inferred from nThreads // an error is thrown when graphDef is a nullptr or when the grah has no nodes // transfers ownership - Session* createSession(GraphDef* graphDef, int nThreads = 1); + Session* createSession(const GraphDef* graphDef, int nThreads = 1); // closes a session, calls its destructor, resets the pointer, and returns true on success bool closeSession(Session*& session); diff --git a/PhysicsTools/TensorFlow/src/TensorFlow.cc b/PhysicsTools/TensorFlow/src/TensorFlow.cc index c0c5d5630f985..488eb736b1d7a 100644 --- a/PhysicsTools/TensorFlow/src/TensorFlow.cc +++ b/PhysicsTools/TensorFlow/src/TensorFlow.cc @@ -159,7 +159,7 @@ namespace tensorflow { return createSession(metaGraphDef, exportDir, sessionOptions); } - Session* createSession(GraphDef* graphDef, SessionOptions& sessionOptions) { + Session* createSession(const GraphDef* graphDef, SessionOptions& sessionOptions) { // check for valid pointer if (graphDef == nullptr) { throw cms::Exception("InvalidGraphDef") << "error while creating session: graphDef is nullptr"; @@ -185,7 +185,7 @@ namespace tensorflow { return session; } - Session* createSession(GraphDef* graphDef, int nThreads) { + Session* createSession(const GraphDef* graphDef, int nThreads) { // create session options and set thread options SessionOptions sessionOptions; setThreading(sessionOptions, nThreads); diff --git a/RecoBTag/FeatureTools/interface/tensor_fillers.h b/RecoBTag/FeatureTools/interface/tensor_fillers.h new file mode 100644 index 0000000000000..253c90b63e3a9 --- /dev/null +++ b/RecoBTag/FeatureTools/interface/tensor_fillers.h @@ -0,0 +1,48 @@ +#ifndef RecoBTag_FeatureTools_tensor_fillers_h +#define RecoBTag_FeatureTools_tensor_fillers_h + +#include "DataFormats/BTauReco/interface/DeepFlavourTagInfo.h" +#include "DataFormats/BTauReco/interface/DeepDoubleXTagInfo.h" + +namespace btagbtvdeep { + + void jet_tensor_filler(float* ptr, const btagbtvdeep::DeepFlavourFeatures& features, unsigned feature_dims); + + void jet4vec_tensor_filler(float* ptr, const btagbtvdeep::DeepFlavourFeatures& features, unsigned feature_dims); + + void db_tensor_filler(float* ptr, const btagbtvdeep::DeepDoubleXFeatures& features, unsigned feature_dims); + + void c_pf_tensor_filler(float* ptr, + std::size_t max_c_pf_n, + const std::vector& c_pf_features_vec, + unsigned feature_dims); + + void c_pf_reduced_tensor_filler(float* ptr, + std::size_t max_c_pf_n, + const std::vector& c_pf_features_vec, + unsigned feature_dims); + + void n_pf_tensor_filler(float* ptr, + std::size_t max_n_pf_n, + const std::vector& n_pf_features_vec, + unsigned feature_dims); + + void sv_tensor_filler(float* ptr, + std::size_t max_sv_n, + const std::vector& sv_features_vec, + unsigned feature_dims); + + void sv_reduced_tensor_filler(float* ptr, + std::size_t max_sv_n, + const std::vector& sv_features_vec, + unsigned feature_dims); + + void seed_tensor_filler(float* ptr, const btagbtvdeep::SeedingTrackFeatures& seed_features, unsigned feature_dims); + + void neighbourTracks_tensor_filler(float* ptr, + const btagbtvdeep::SeedingTrackFeatures& seed_features, + unsigned feature_dims); + +} // namespace btagbtvdeep + +#endif diff --git a/RecoBTag/FeatureTools/src/tensor_fillers.cc b/RecoBTag/FeatureTools/src/tensor_fillers.cc new file mode 100644 index 0000000000000..11288cdc1dbbc --- /dev/null +++ b/RecoBTag/FeatureTools/src/tensor_fillers.cc @@ -0,0 +1,256 @@ +#include "RecoBTag/FeatureTools/interface/tensor_fillers.h" +#include + +namespace btagbtvdeep { + + // Note on setting tensor values: + // Instead of using the more convenient tensor.matrix (etc) methods, + // we can exploit that in the following methods values are set along + // the innermost (= last) axis. Those values are stored contiguously in + // the memory, so it is most performant to get the pointer to the first + // value and use pointer arithmetic to iterate through the next pointers. + + void jet_tensor_filler(float *ptr, const btagbtvdeep::DeepFlavourFeatures &features, unsigned feature_dims) { + // jet variables + const float *start = ptr; + const auto &jet_features = features.jet_features; + *(ptr++) = jet_features.pt; + *(ptr++) = jet_features.eta; + // number of elements in different collections + *(ptr++) = features.c_pf_features.size(); + *(ptr++) = features.n_pf_features.size(); + *(ptr++) = features.sv_features.size(); + *(ptr++) = features.npv; + // variables from ShallowTagInfo + const auto &tag_info_features = features.tag_info_features; + *(ptr++) = tag_info_features.trackSumJetEtRatio; + *(ptr++) = tag_info_features.trackSumJetDeltaR; + *(ptr++) = tag_info_features.vertexCategory; + *(ptr++) = tag_info_features.trackSip2dValAboveCharm; + *(ptr++) = tag_info_features.trackSip2dSigAboveCharm; + *(ptr++) = tag_info_features.trackSip3dValAboveCharm; + *(ptr++) = tag_info_features.trackSip3dSigAboveCharm; + *(ptr++) = tag_info_features.jetNSelectedTracks; + *(ptr++) = tag_info_features.jetNTracksEtaRel; + assert(start + feature_dims == ptr); + } + + void jet4vec_tensor_filler(float *ptr, const btagbtvdeep::DeepFlavourFeatures &features, unsigned feature_dims) { + // jet 4 vector variables + const float *start = ptr; + const auto &jet_features = features.jet_features; + *(ptr++) = jet_features.pt; + *(ptr++) = jet_features.eta; + *(ptr++) = jet_features.phi; + *(ptr++) = jet_features.mass; + assert(start + feature_dims == ptr); + } + + void db_tensor_filler(float *ptr, const btagbtvdeep::DeepDoubleXFeatures &features, unsigned feature_dims) { + // variables from BoostedDoubleSVTagInfo + const float *start = ptr; + const auto &tag_info_features = features.tag_info_features; + *(ptr++) = tag_info_features.jetNTracks; + *(ptr++) = tag_info_features.jetNSecondaryVertices; + *(ptr++) = tag_info_features.tau1_trackEtaRel_0; + *(ptr++) = tag_info_features.tau1_trackEtaRel_1; + *(ptr++) = tag_info_features.tau1_trackEtaRel_2; + *(ptr++) = tag_info_features.tau2_trackEtaRel_0; + *(ptr++) = tag_info_features.tau2_trackEtaRel_1; + *(ptr++) = tag_info_features.tau2_trackEtaRel_2; + *(ptr++) = tag_info_features.tau1_flightDistance2dSig; + *(ptr++) = tag_info_features.tau2_flightDistance2dSig; + *(ptr++) = tag_info_features.tau1_vertexDeltaR; + // Note: this variable is not used in the 27-input BDT + // *(ptr++) = tag_info_features.tau2_vertexDeltaR; + *(ptr++) = tag_info_features.tau1_vertexEnergyRatio; + *(ptr++) = tag_info_features.tau2_vertexEnergyRatio; + *(ptr++) = tag_info_features.tau1_vertexMass; + *(ptr++) = tag_info_features.tau2_vertexMass; + *(ptr++) = tag_info_features.trackSip2dSigAboveBottom_0; + *(ptr++) = tag_info_features.trackSip2dSigAboveBottom_1; + *(ptr++) = tag_info_features.trackSip2dSigAboveCharm; + *(ptr++) = tag_info_features.trackSip3dSig_0; + *(ptr++) = tag_info_features.tau1_trackSip3dSig_0; + *(ptr++) = tag_info_features.tau1_trackSip3dSig_1; + *(ptr++) = tag_info_features.trackSip3dSig_1; + *(ptr++) = tag_info_features.tau2_trackSip3dSig_0; + *(ptr++) = tag_info_features.tau2_trackSip3dSig_1; + *(ptr++) = tag_info_features.trackSip3dSig_2; + *(ptr++) = tag_info_features.trackSip3dSig_3; + *(ptr++) = tag_info_features.z_ratio; + assert(start + feature_dims == ptr); + } + + void c_pf_tensor_filler(float *ptr, + std::size_t max_c_pf_n, + const std::vector &c_pf_features_vec, + unsigned feature_dims) { + for (std::size_t i = 0; i < max_c_pf_n; ++i) { + const auto &c_pf_features = c_pf_features_vec.at(i); + const float *start = ptr; + *(ptr++) = c_pf_features.btagPf_trackEtaRel; + *(ptr++) = c_pf_features.btagPf_trackPtRel; + *(ptr++) = c_pf_features.btagPf_trackPPar; + *(ptr++) = c_pf_features.btagPf_trackDeltaR; + *(ptr++) = c_pf_features.btagPf_trackPParRatio; + *(ptr++) = c_pf_features.btagPf_trackSip2dVal; + *(ptr++) = c_pf_features.btagPf_trackSip2dSig; + *(ptr++) = c_pf_features.btagPf_trackSip3dVal; + *(ptr++) = c_pf_features.btagPf_trackSip3dSig; + *(ptr++) = c_pf_features.btagPf_trackJetDistVal; + *(ptr++) = c_pf_features.ptrel; + *(ptr++) = c_pf_features.drminsv; + *(ptr++) = c_pf_features.vtx_ass; + *(ptr++) = c_pf_features.puppiw; + *(ptr++) = c_pf_features.chi2; + *(ptr++) = c_pf_features.quality; + assert(start + feature_dims == ptr); + } + } + + void c_pf_reduced_tensor_filler(float *ptr, + std::size_t max_c_pf_n, + const std::vector &c_pf_features_vec, + unsigned feature_dims) { + for (std::size_t i = 0; i < max_c_pf_n; ++i) { + const auto &c_pf_features = c_pf_features_vec.at(i); + const float *start = ptr; + *(ptr++) = c_pf_features.btagPf_trackEtaRel; + *(ptr++) = c_pf_features.btagPf_trackPtRatio; + *(ptr++) = c_pf_features.btagPf_trackPParRatio; + *(ptr++) = c_pf_features.btagPf_trackSip2dVal; + *(ptr++) = c_pf_features.btagPf_trackSip2dSig; + *(ptr++) = c_pf_features.btagPf_trackSip3dVal; + *(ptr++) = c_pf_features.btagPf_trackSip3dSig; + *(ptr++) = c_pf_features.btagPf_trackJetDistVal; + assert(start + feature_dims == ptr); + } + } + + void n_pf_tensor_filler(float *ptr, + std::size_t max_n_pf_n, + const std::vector &n_pf_features_vec, + unsigned feature_dims) { + for (std::size_t i = 0; i < max_n_pf_n; ++i) { + const auto &n_pf_features = n_pf_features_vec.at(i); + const float *start = ptr; + *(ptr++) = n_pf_features.ptrel; + *(ptr++) = n_pf_features.deltaR; + *(ptr++) = n_pf_features.isGamma; + *(ptr++) = n_pf_features.hadFrac; + *(ptr++) = n_pf_features.drminsv; + *(ptr++) = n_pf_features.puppiw; + assert(start + feature_dims == ptr); + } + } + + void sv_tensor_filler(float *ptr, + std::size_t max_sv_n, + const std::vector &sv_features_vec, + unsigned feature_dims) { + for (std::size_t i = 0; i < max_sv_n; ++i) { + const auto &sv_features = sv_features_vec.at(i); + const float *start = ptr; + *(ptr++) = sv_features.pt; + *(ptr++) = sv_features.deltaR; + *(ptr++) = sv_features.mass; + *(ptr++) = sv_features.ntracks; + *(ptr++) = sv_features.chi2; + *(ptr++) = sv_features.normchi2; + *(ptr++) = sv_features.dxy; + *(ptr++) = sv_features.dxysig; + *(ptr++) = sv_features.d3d; + *(ptr++) = sv_features.d3dsig; + *(ptr++) = sv_features.costhetasvpv; + *(ptr++) = sv_features.enratio; + assert(start + feature_dims == ptr); + } + } + + void sv_reduced_tensor_filler(float *ptr, + std::size_t max_sv_n, + const std::vector &sv_features_vec, + unsigned feature_dims) { + for (std::size_t i = 0; i < max_sv_n; ++i) { + const auto &sv_features = sv_features_vec.at(i); + const float *start = ptr; + *(ptr++) = sv_features.d3d; + *(ptr++) = sv_features.d3dsig; + assert(start + feature_dims == ptr); + } + } + + void seed_tensor_filler(float *ptr, const btagbtvdeep::SeedingTrackFeatures &seed_features, unsigned feature_dims) { + const float *start = ptr; + *(ptr++) = seed_features.pt; + *(ptr++) = seed_features.eta; + *(ptr++) = seed_features.phi; + *(ptr++) = seed_features.mass; + *(ptr++) = seed_features.dz; + *(ptr++) = seed_features.dxy; + *(ptr++) = seed_features.ip3D; + *(ptr++) = seed_features.sip3D; + *(ptr++) = seed_features.ip2D; + *(ptr++) = seed_features.sip2D; + *(ptr++) = seed_features.signedIp3D; + *(ptr++) = seed_features.signedSip3D; + *(ptr++) = seed_features.signedIp2D; + *(ptr++) = seed_features.signedSip2D; + *(ptr++) = seed_features.trackProbability3D; + *(ptr++) = seed_features.trackProbability2D; + *(ptr++) = seed_features.chi2reduced; + *(ptr++) = seed_features.nPixelHits; + *(ptr++) = seed_features.nHits; + *(ptr++) = seed_features.jetAxisDistance; + *(ptr++) = seed_features.jetAxisDlength; + assert(start + feature_dims == ptr); + } + + void neighbourTracks_tensor_filler(float *ptr, + const btagbtvdeep::SeedingTrackFeatures &seed_features, + unsigned feature_dims) { + const auto &neighbourTracks_features = seed_features.nearTracks; + for (unsigned int t_i = 0; t_i < neighbourTracks_features.size(); t_i++) { + const float *start = ptr; + *(ptr++) = neighbourTracks_features[t_i].pt; + *(ptr++) = neighbourTracks_features[t_i].eta; + *(ptr++) = neighbourTracks_features[t_i].phi; + *(ptr++) = neighbourTracks_features[t_i].dz; + *(ptr++) = neighbourTracks_features[t_i].dxy; + *(ptr++) = neighbourTracks_features[t_i].mass; + *(ptr++) = neighbourTracks_features[t_i].ip3D; + *(ptr++) = neighbourTracks_features[t_i].sip3D; + *(ptr++) = neighbourTracks_features[t_i].ip2D; + *(ptr++) = neighbourTracks_features[t_i].sip2D; + *(ptr++) = neighbourTracks_features[t_i].distPCA; + *(ptr++) = neighbourTracks_features[t_i].dsigPCA; + *(ptr++) = neighbourTracks_features[t_i].x_PCAonSeed; + *(ptr++) = neighbourTracks_features[t_i].y_PCAonSeed; + *(ptr++) = neighbourTracks_features[t_i].z_PCAonSeed; + *(ptr++) = neighbourTracks_features[t_i].xerr_PCAonSeed; + *(ptr++) = neighbourTracks_features[t_i].yerr_PCAonSeed; + *(ptr++) = neighbourTracks_features[t_i].zerr_PCAonSeed; + *(ptr++) = neighbourTracks_features[t_i].x_PCAonTrack; + *(ptr++) = neighbourTracks_features[t_i].y_PCAonTrack; + *(ptr++) = neighbourTracks_features[t_i].z_PCAonTrack; + *(ptr++) = neighbourTracks_features[t_i].xerr_PCAonTrack; + *(ptr++) = neighbourTracks_features[t_i].yerr_PCAonTrack; + *(ptr++) = neighbourTracks_features[t_i].zerr_PCAonTrack; + *(ptr++) = neighbourTracks_features[t_i].dotprodTrack; + *(ptr++) = neighbourTracks_features[t_i].dotprodSeed; + *(ptr++) = neighbourTracks_features[t_i].dotprodTrackSeed2D; + *(ptr++) = neighbourTracks_features[t_i].dotprodTrackSeed3D; + *(ptr++) = neighbourTracks_features[t_i].dotprodTrackSeedVectors2D; + *(ptr++) = neighbourTracks_features[t_i].dotprodTrackSeedVectors3D; + *(ptr++) = neighbourTracks_features[t_i].pvd_PCAonSeed; + *(ptr++) = neighbourTracks_features[t_i].pvd_PCAonTrack; + *(ptr++) = neighbourTracks_features[t_i].dist_PCAjetAxis; + *(ptr++) = neighbourTracks_features[t_i].dotprod_PCAjetMomenta; + *(ptr++) = neighbourTracks_features[t_i].deta_PCAjetDirs; + *(ptr++) = neighbourTracks_features[t_i].dphi_PCAjetDirs; + assert(start + feature_dims == ptr); + } + } + +} // namespace btagbtvdeep diff --git a/RecoBTag/ONNXRuntime/plugins/BuildFile.xml b/RecoBTag/ONNXRuntime/plugins/BuildFile.xml index 067eae1ac3715..e0566fc83fe60 100644 --- a/RecoBTag/ONNXRuntime/plugins/BuildFile.xml +++ b/RecoBTag/ONNXRuntime/plugins/BuildFile.xml @@ -2,6 +2,7 @@ + diff --git a/RecoBTag/ONNXRuntime/plugins/DeepBoostedJetONNXJetTagsProducer.cc b/RecoBTag/ONNXRuntime/plugins/DeepBoostedJetONNXJetTagsProducer.cc index 90a0151fe1c33..be873318c49c0 100644 --- a/RecoBTag/ONNXRuntime/plugins/DeepBoostedJetONNXJetTagsProducer.cc +++ b/RecoBTag/ONNXRuntime/plugins/DeepBoostedJetONNXJetTagsProducer.cc @@ -162,7 +162,7 @@ void DeepBoostedJetONNXJetTagsProducer::fillDescriptions(edm::ConfigurationDescr }); desc.addOptionalUntracked("debugMode", false); - descriptions.add("pfDeepBoostedJetTags", desc); + descriptions.addWithDefaultLabel(desc); } std::unique_ptr DeepBoostedJetONNXJetTagsProducer::initializeGlobalCache(const edm::ParameterSet &iConfig) { diff --git a/RecoBTag/ONNXRuntime/plugins/DeepDoubleXONNXJetTagsProducer.cc b/RecoBTag/ONNXRuntime/plugins/DeepDoubleXONNXJetTagsProducer.cc index f7c5176b199c9..5a6b21ed5cc12 100644 --- a/RecoBTag/ONNXRuntime/plugins/DeepDoubleXONNXJetTagsProducer.cc +++ b/RecoBTag/ONNXRuntime/plugins/DeepDoubleXONNXJetTagsProducer.cc @@ -12,6 +12,7 @@ #include "DataFormats/BTauReco/interface/JetTag.h" #include "DataFormats/BTauReco/interface/DeepDoubleXTagInfo.h" +#include "RecoBTag/FeatureTools/interface/tensor_fillers.h" #include "PhysicsTools/ONNXRuntime/interface/ONNXRuntime.h" @@ -94,15 +95,15 @@ void DeepDoubleXONNXJetTagsProducer::fillDescriptions(edm::ConfigurationDescript }; auto descBvL(desc); descBvL.ifValue(edm::ParameterDescription("flavor", "BvL", true), flavorCases()); - descriptions.add("pfDeepDoubleBvLJetTags", descBvL); + descriptions.add("pfDeepDoubleBvLONNXJetTags", descBvL); auto descCvL(desc); descCvL.ifValue(edm::ParameterDescription("flavor", "CvL", true), flavorCases()); - descriptions.add("pfDeepDoubleCvLJetTags", descCvL); + descriptions.add("pfDeepDoubleCvLONNXJetTags", descCvL); auto descCvB(desc); descCvB.ifValue(edm::ParameterDescription("flavor", "CvB", true), flavorCases()); - descriptions.add("pfDeepDoubleCvBJetTags", descCvB); + descriptions.add("pfDeepDoubleCvBONNXJetTags", descCvB); } std::unique_ptr DeepDoubleXONNXJetTagsProducer::initializeGlobalCache(const edm::ParameterSet& iConfig) { @@ -179,75 +180,22 @@ void DeepDoubleXONNXJetTagsProducer::produce(edm::Event& iEvent, const edm::Even void DeepDoubleXONNXJetTagsProducer::make_inputs(unsigned i_jet, const reco::DeepDoubleXTagInfo& taginfo) { const auto& features = taginfo.features(); - float* ptr = nullptr; - const float* start = nullptr; unsigned offset = 0; // DoubleB features offset = i_jet * input_sizes_[kGlobal]; - ptr = &data_[kGlobal][offset]; - start = ptr; - const auto& tag_info_features = features.tag_info_features; - *ptr = tag_info_features.jetNTracks; - *(++ptr) = tag_info_features.jetNSecondaryVertices; - *(++ptr) = tag_info_features.tau1_trackEtaRel_0; - *(++ptr) = tag_info_features.tau1_trackEtaRel_1; - *(++ptr) = tag_info_features.tau1_trackEtaRel_2; - *(++ptr) = tag_info_features.tau2_trackEtaRel_0; - *(++ptr) = tag_info_features.tau2_trackEtaRel_1; - *(++ptr) = tag_info_features.tau2_trackEtaRel_2; - *(++ptr) = tag_info_features.tau1_flightDistance2dSig; - *(++ptr) = tag_info_features.tau2_flightDistance2dSig; - *(++ptr) = tag_info_features.tau1_vertexDeltaR; - // Note: this variable is not used in the 27-input BDT - // *(++ptr) = tag_info_features.tau2_vertexDeltaR; - *(++ptr) = tag_info_features.tau1_vertexEnergyRatio; - *(++ptr) = tag_info_features.tau2_vertexEnergyRatio; - *(++ptr) = tag_info_features.tau1_vertexMass; - *(++ptr) = tag_info_features.tau2_vertexMass; - *(++ptr) = tag_info_features.trackSip2dSigAboveBottom_0; - *(++ptr) = tag_info_features.trackSip2dSigAboveBottom_1; - *(++ptr) = tag_info_features.trackSip2dSigAboveCharm; - *(++ptr) = tag_info_features.trackSip3dSig_0; - *(++ptr) = tag_info_features.tau1_trackSip3dSig_0; - *(++ptr) = tag_info_features.tau1_trackSip3dSig_1; - *(++ptr) = tag_info_features.trackSip3dSig_1; - *(++ptr) = tag_info_features.tau2_trackSip3dSig_0; - *(++ptr) = tag_info_features.tau2_trackSip3dSig_1; - *(++ptr) = tag_info_features.trackSip3dSig_2; - *(++ptr) = tag_info_features.trackSip3dSig_3; - *(++ptr) = tag_info_features.z_ratio; - assert(start + n_features_global_ - 1 == ptr); + btagbtvdeep::db_tensor_filler(&data_[kGlobal][offset], features, n_features_global_); // c_pf candidates - auto max_c_pf_n = std::min(features.c_pf_features.size(), (std::size_t)n_cpf_); offset = i_jet * input_sizes_[kChargedCandidates]; - for (std::size_t c_pf_n = 0; c_pf_n < max_c_pf_n; c_pf_n++) { - const auto& c_pf_features = features.c_pf_features.at(c_pf_n); - ptr = &data_[kChargedCandidates][offset + c_pf_n * n_features_cpf_]; - start = ptr; - *ptr = c_pf_features.btagPf_trackEtaRel; - *(++ptr) = c_pf_features.btagPf_trackPtRatio; - *(++ptr) = c_pf_features.btagPf_trackPParRatio; - *(++ptr) = c_pf_features.btagPf_trackSip2dVal; - *(++ptr) = c_pf_features.btagPf_trackSip2dSig; - *(++ptr) = c_pf_features.btagPf_trackSip3dVal; - *(++ptr) = c_pf_features.btagPf_trackSip3dSig; - *(++ptr) = c_pf_features.btagPf_trackJetDistVal; - assert(start + n_features_cpf_ - 1 == ptr); - } + auto max_c_pf_n = std::min(features.c_pf_features.size(), (std::size_t)n_cpf_); + btagbtvdeep::c_pf_reduced_tensor_filler( + &data_[kChargedCandidates][offset], max_c_pf_n, features.c_pf_features, n_features_cpf_); // sv candidates - auto max_sv_n = std::min(features.sv_features.size(), (std::size_t)n_sv_); offset = i_jet * input_sizes_[kVertices]; - for (std::size_t sv_n = 0; sv_n < max_sv_n; sv_n++) { - const auto& sv_features = features.sv_features.at(sv_n); - ptr = &data_[kVertices][offset + sv_n * n_features_sv_]; - start = ptr; - *ptr = sv_features.d3d; - *(++ptr) = sv_features.d3dsig; - assert(start + n_features_sv_ - 1 == ptr); - } + auto max_sv_n = std::min(features.sv_features.size(), (std::size_t)n_sv_); + btagbtvdeep::sv_reduced_tensor_filler(&data_[kVertices][offset], max_sv_n, features.sv_features, n_features_sv_); } //define this as a plug-in diff --git a/RecoBTag/ONNXRuntime/plugins/DeepFlavourONNXJetTagsProducer.cc b/RecoBTag/ONNXRuntime/plugins/DeepFlavourONNXJetTagsProducer.cc index 8e1c91c7fe9c7..9fd397f99b041 100644 --- a/RecoBTag/ONNXRuntime/plugins/DeepFlavourONNXJetTagsProducer.cc +++ b/RecoBTag/ONNXRuntime/plugins/DeepFlavourONNXJetTagsProducer.cc @@ -12,6 +12,7 @@ #include "DataFormats/BTauReco/interface/JetTag.h" #include "DataFormats/BTauReco/interface/DeepFlavourTagInfo.h" +#include "RecoBTag/FeatureTools/interface/tensor_fillers.h" #include "PhysicsTools/ONNXRuntime/interface/ONNXRuntime.h" @@ -64,12 +65,11 @@ DeepFlavourONNXJetTagsProducer::DeepFlavourONNXJetTagsProducer(const edm::Parame flav_names_(iConfig.getParameter>("flav_names")), input_names_(iConfig.getParameter>("input_names")), output_names_(iConfig.getParameter>("output_names")) { + assert(input_names_.size() == input_sizes_.size()); // get output names from flav_names for (const auto& flav_name : flav_names_) { produces(flav_name); } - - assert(input_names_.size() == input_sizes_.size()); } DeepFlavourONNXJetTagsProducer::~DeepFlavourONNXJetTagsProducer() {} @@ -85,7 +85,7 @@ void DeepFlavourONNXJetTagsProducer::fillDescriptions(edm::ConfigurationDescript desc.add>( "flav_names", std::vector{"probb", "probbb", "problepb", "probc", "probuds", "probg"}); - descriptions.add("pfDeepFlavourJetTags", desc); + descriptions.add("pfDeepFlavourONNXJetTags", desc); } std::unique_ptr DeepFlavourONNXJetTagsProducer::initializeGlobalCache(const edm::ParameterSet& iConfig) { @@ -147,99 +147,28 @@ void DeepFlavourONNXJetTagsProducer::produce(edm::Event& iEvent, const edm::Even void DeepFlavourONNXJetTagsProducer::make_inputs(unsigned i_jet, const reco::DeepFlavourTagInfo& taginfo) { const auto& features = taginfo.features(); - float* ptr = nullptr; - const float* start = nullptr; unsigned offset = 0; // jet and other global features offset = i_jet * input_sizes_[kGlobal]; - ptr = &data_[kGlobal][offset]; - // jet variables - const auto& jet_features = features.jet_features; - start = ptr; - *ptr = jet_features.pt; - *(++ptr) = jet_features.eta; - // number of elements in different collections - *(++ptr) = features.c_pf_features.size(); - *(++ptr) = features.n_pf_features.size(); - *(++ptr) = features.sv_features.size(); - *(++ptr) = features.npv; - // variables from ShallowTagInfo - const auto& tag_info_features = features.tag_info_features; - *(++ptr) = tag_info_features.trackSumJetEtRatio; - *(++ptr) = tag_info_features.trackSumJetDeltaR; - *(++ptr) = tag_info_features.vertexCategory; - *(++ptr) = tag_info_features.trackSip2dValAboveCharm; - *(++ptr) = tag_info_features.trackSip2dSigAboveCharm; - *(++ptr) = tag_info_features.trackSip3dValAboveCharm; - *(++ptr) = tag_info_features.trackSip3dSigAboveCharm; - *(++ptr) = tag_info_features.jetNSelectedTracks; - *(++ptr) = tag_info_features.jetNTracksEtaRel; - assert(start + n_features_global_ - 1 == ptr); + btagbtvdeep::jet_tensor_filler(&data_[kGlobal][offset], features, n_features_global_); // c_pf candidates - auto max_c_pf_n = std::min(features.c_pf_features.size(), (std::size_t)25); offset = i_jet * input_sizes_[kChargedCandidates]; - for (std::size_t c_pf_n = 0; c_pf_n < max_c_pf_n; c_pf_n++) { - const auto& c_pf_features = features.c_pf_features.at(c_pf_n); - ptr = &data_[kChargedCandidates][offset + c_pf_n * n_features_cpf_]; - start = ptr; - *ptr = c_pf_features.btagPf_trackEtaRel; - *(++ptr) = c_pf_features.btagPf_trackPtRel; - *(++ptr) = c_pf_features.btagPf_trackPPar; - *(++ptr) = c_pf_features.btagPf_trackDeltaR; - *(++ptr) = c_pf_features.btagPf_trackPParRatio; - *(++ptr) = c_pf_features.btagPf_trackSip2dVal; - *(++ptr) = c_pf_features.btagPf_trackSip2dSig; - *(++ptr) = c_pf_features.btagPf_trackSip3dVal; - *(++ptr) = c_pf_features.btagPf_trackSip3dSig; - *(++ptr) = c_pf_features.btagPf_trackJetDistVal; - *(++ptr) = c_pf_features.ptrel; - *(++ptr) = c_pf_features.drminsv; - *(++ptr) = c_pf_features.vtx_ass; - *(++ptr) = c_pf_features.puppiw; - *(++ptr) = c_pf_features.chi2; - *(++ptr) = c_pf_features.quality; - assert(start + n_features_cpf_ - 1 == ptr); - } + auto max_c_pf_n = std::min(features.c_pf_features.size(), (std::size_t)n_cpf_); + btagbtvdeep::c_pf_tensor_filler( + &data_[kChargedCandidates][offset], max_c_pf_n, features.c_pf_features, n_features_cpf_); // n_pf candidates - auto max_n_pf_n = std::min(features.n_pf_features.size(), (std::size_t)25); offset = i_jet * input_sizes_[kNeutralCandidates]; - for (std::size_t n_pf_n = 0; n_pf_n < max_n_pf_n; n_pf_n++) { - const auto& n_pf_features = features.n_pf_features.at(n_pf_n); - ptr = &data_[kNeutralCandidates][offset + n_pf_n * n_features_npf_]; - start = ptr; - *ptr = n_pf_features.ptrel; - *(++ptr) = n_pf_features.deltaR; - *(++ptr) = n_pf_features.isGamma; - *(++ptr) = n_pf_features.hadFrac; - *(++ptr) = n_pf_features.drminsv; - *(++ptr) = n_pf_features.puppiw; - assert(start + n_features_npf_ - 1 == ptr); - } + auto max_n_pf_n = std::min(features.n_pf_features.size(), (std::size_t)n_npf_); + btagbtvdeep::n_pf_tensor_filler( + &data_[kNeutralCandidates][offset], max_n_pf_n, features.n_pf_features, n_features_npf_); // sv candidates - auto max_sv_n = std::min(features.sv_features.size(), (std::size_t)4); offset = i_jet * input_sizes_[kVertices]; - for (std::size_t sv_n = 0; sv_n < max_sv_n; sv_n++) { - const auto& sv_features = features.sv_features.at(sv_n); - ptr = &data_[kVertices][offset + sv_n * n_features_sv_]; - start = ptr; - *ptr = sv_features.pt; - *(++ptr) = sv_features.deltaR; - *(++ptr) = sv_features.mass; - *(++ptr) = sv_features.ntracks; - *(++ptr) = sv_features.chi2; - *(++ptr) = sv_features.normchi2; - *(++ptr) = sv_features.dxy; - *(++ptr) = sv_features.dxysig; - *(++ptr) = sv_features.d3d; - *(++ptr) = sv_features.d3dsig; - *(++ptr) = sv_features.costhetasvpv; - *(++ptr) = sv_features.enratio; - assert(start + n_features_sv_ - 1 == ptr); - } + auto max_sv_n = std::min(features.sv_features.size(), (std::size_t)n_sv_); + btagbtvdeep::sv_tensor_filler(&data_[kVertices][offset], max_sv_n, features.sv_features, n_features_sv_); // last input: jet pt offset = i_jet * input_sizes_[kJetPt]; diff --git a/RecoBTag/ONNXRuntime/python/SwitchProducerONNX.py b/RecoBTag/ONNXRuntime/python/SwitchProducerONNX.py new file mode 100644 index 0000000000000..1d91efac91d91 --- /dev/null +++ b/RecoBTag/ONNXRuntime/python/SwitchProducerONNX.py @@ -0,0 +1,39 @@ +import FWCore.ParameterSet.Config as cms + +_tf_enabled_cached = None +_onnxrt_enabled_cached = None + + +def _switch_native(): + global _tf_enabled_cached + if _tf_enabled_cached is None: + import os + _tf_enabled_cached = ('CMS_DISABLE_TENSORFLOW' not in os.environ) + return (_tf_enabled_cached, 1) + + +def _switch_onnxruntime(): + global _onnxrt_enabled_cached + if _onnxrt_enabled_cached is None: + import os + _onnxrt_enabled_cached = ('amd64' in os.environ['SCRAM_ARCH'] or 'aarch64' in os.environ['SCRAM_ARCH']) and ('CMS_DISABLE_ONNXRUNTIME' not in os.environ) + return (_onnxrt_enabled_cached, 2) + + +class SwitchProducerONNX(cms.SwitchProducer): + + def __init__(self, **kwargs): + super(SwitchProducerONNX, self).__init__( + dict(native = _switch_native, + onnx = _switch_onnxruntime), + **kwargs + ) + + def cloneAll(self, **params): + return super(SwitchProducerONNX, self).clone( + native = self.native.clone(**params), + onnx = self.onnx.clone(**params), + ) + + +cms.specialImportRegistry.registerSpecialImportForType(SwitchProducerONNX, "from RecoBTag.ONNXRuntime.SwitchProducerONNX import SwitchProducerONNX") diff --git a/RecoBTag/ONNXRuntime/python/pfDeepBoostedJetTags_cfi.py b/RecoBTag/ONNXRuntime/python/pfDeepBoostedJetTags_cfi.py new file mode 100644 index 0000000000000..aa50795b9071e --- /dev/null +++ b/RecoBTag/ONNXRuntime/python/pfDeepBoostedJetTags_cfi.py @@ -0,0 +1,40 @@ +from RecoBTag.ONNXRuntime.SwitchProducerONNX import SwitchProducerONNX +from RecoBTag.ONNXRuntime.deepBoostedJetONNXJetTagsProducer_cfi import deepBoostedJetONNXJetTagsProducer +from RecoBTag.MXNet.boostedJetMXNetJetTagsProducer_cfi import boostedJetMXNetJetTagsProducer +from RecoBTag.ONNXRuntime.Parameters.DeepBoostedJet.V02.pfDeepBoostedJetPreprocessParams_cfi import pfDeepBoostedJetPreprocessParams +from RecoBTag.ONNXRuntime.Parameters.DeepBoostedJet.V02.pfMassDecorrelatedDeepBoostedJetPreprocessParams_cfi import pfMassDecorrelatedDeepBoostedJetPreprocessParams + +_flav_names = ['probTbcq', 'probTbqq', 'probTbc', 'probTbq', 'probWcq', 'probWqq', + 'probZbb', 'probZcc', 'probZqq', 'probHbb', 'probHcc', 'probHqqqq', + 'probQCDbb', 'probQCDcc', 'probQCDb', 'probQCDc', 'probQCDothers'] + +# nominal DeepAK8 +pfDeepBoostedJetTags = SwitchProducerONNX( + native = boostedJetMXNetJetTagsProducer.clone( + flav_names = _flav_names, + preprocessParams = pfDeepBoostedJetPreprocessParams, + model_path = 'RecoBTag/Combined/data/DeepBoostedJet/V02/full/resnet-symbol.json', + param_path = 'RecoBTag/Combined/data/DeepBoostedJet/V02/full/resnet-0000.params', + ), + onnx = deepBoostedJetONNXJetTagsProducer.clone( + flav_names = _flav_names, + preprocessParams = pfDeepBoostedJetPreprocessParams, + model_path = 'RecoBTag/Combined/data/DeepBoostedJet/V02/full/resnet.onnx', + ), + ) + +# mass-decorrelated DeepAK8 +pfMassDecorrelatedDeepBoostedJetTags = SwitchProducerONNX( + native = boostedJetMXNetJetTagsProducer.clone( + flav_names = _flav_names, + preprocessParams = pfMassDecorrelatedDeepBoostedJetPreprocessParams, + model_path = 'RecoBTag/Combined/data/DeepBoostedJet/V02/decorrelated/resnet-symbol.json', + param_path = 'RecoBTag/Combined/data/DeepBoostedJet/V02/decorrelated/resnet-0000.params', + ), + onnx = deepBoostedJetONNXJetTagsProducer.clone( + flav_names = _flav_names, + preprocessParams = pfMassDecorrelatedDeepBoostedJetPreprocessParams, + model_path = 'RecoBTag/Combined/data/DeepBoostedJet/V02/decorrelated/resnet.onnx', + ), + ) + diff --git a/RecoBTag/ONNXRuntime/python/pfDeepBoostedJet_cff.py b/RecoBTag/ONNXRuntime/python/pfDeepBoostedJet_cff.py index f6592696e4059..0c0b1421e09c2 100644 --- a/RecoBTag/ONNXRuntime/python/pfDeepBoostedJet_cff.py +++ b/RecoBTag/ONNXRuntime/python/pfDeepBoostedJet_cff.py @@ -1,26 +1,10 @@ import FWCore.ParameterSet.Config as cms from RecoBTag.FeatureTools.pfDeepBoostedJetTagInfos_cfi import pfDeepBoostedJetTagInfos -from RecoBTag.ONNXRuntime.pfDeepBoostedJetTags_cfi import pfDeepBoostedJetTags as _pfDeepBoostedJetTags -from RecoBTag.ONNXRuntime.Parameters.DeepBoostedJet.V02.pfDeepBoostedJetPreprocessParams_cfi import pfDeepBoostedJetPreprocessParams -from RecoBTag.ONNXRuntime.Parameters.DeepBoostedJet.V02.pfMassDecorrelatedDeepBoostedJetPreprocessParams_cfi import pfMassDecorrelatedDeepBoostedJetPreprocessParams +from RecoBTag.ONNXRuntime.pfDeepBoostedJetTags_cfi import pfDeepBoostedJetTags, pfMassDecorrelatedDeepBoostedJetTags, _flav_names from RecoBTag.ONNXRuntime.pfDeepBoostedDiscriminatorsJetTags_cfi import pfDeepBoostedDiscriminatorsJetTags from RecoBTag.ONNXRuntime.pfMassDecorrelatedDeepBoostedDiscriminatorsJetTags_cfi import pfMassDecorrelatedDeepBoostedDiscriminatorsJetTags -# nominal DeepAK8 -pfDeepBoostedJetTags = _pfDeepBoostedJetTags.clone( - preprocessParams = pfDeepBoostedJetPreprocessParams, - model_path = 'RecoBTag/Combined/data/DeepBoostedJet/V02/full/resnet.onnx', - debugMode = False, # debug -) - -# mass-decorrelated DeepAK8 -pfMassDecorrelatedDeepBoostedJetTags = _pfDeepBoostedJetTags.clone( - preprocessParams = pfMassDecorrelatedDeepBoostedJetPreprocessParams, - model_path = 'RecoBTag/Combined/data/DeepBoostedJet/V02/decorrelated/resnet.onnx', - debugMode = False, # debug -) - from CommonTools.PileupAlgos.Puppi_cff import puppi from PhysicsTools.PatAlgos.slimming.primaryVertexAssociation_cfi import primaryVertexAssociation @@ -32,15 +16,13 @@ # declare all the discriminators # nominal: probs -_pfDeepBoostedJetTagsProbs = ['pfDeepBoostedJetTags:' + flav_name - for flav_name in pfDeepBoostedJetTags.flav_names] +_pfDeepBoostedJetTagsProbs = ['pfDeepBoostedJetTags:' + flav_name for flav_name in _flav_names] # nominal: meta-taggers _pfDeepBoostedJetTagsMetaDiscrs = ['pfDeepBoostedDiscriminatorsJetTags:' + disc.name.value() for disc in pfDeepBoostedDiscriminatorsJetTags.discriminators] # mass-decorrelated: probs -_pfMassDecorrelatedDeepBoostedJetTagsProbs = ['pfMassDecorrelatedDeepBoostedJetTags:' + flav_name - for flav_name in pfMassDecorrelatedDeepBoostedJetTags.flav_names] +_pfMassDecorrelatedDeepBoostedJetTagsProbs = ['pfMassDecorrelatedDeepBoostedJetTags:' + flav_name for flav_name in _flav_names] # mass-decorrelated: meta-taggers _pfMassDecorrelatedDeepBoostedJetTagsMetaDiscrs = ['pfMassDecorrelatedDeepBoostedDiscriminatorsJetTags:' + disc.name.value() for disc in pfMassDecorrelatedDeepBoostedDiscriminatorsJetTags.discriminators] diff --git a/RecoBTag/ONNXRuntime/python/pfDeepDoubleXJetTags_cfi.py b/RecoBTag/ONNXRuntime/python/pfDeepDoubleXJetTags_cfi.py new file mode 100644 index 0000000000000..7ea9915e22271 --- /dev/null +++ b/RecoBTag/ONNXRuntime/python/pfDeepDoubleXJetTags_cfi.py @@ -0,0 +1,49 @@ +from RecoBTag.ONNXRuntime.SwitchProducerONNX import SwitchProducerONNX +from RecoBTag.ONNXRuntime.pfDeepDoubleBvLONNXJetTags_cfi import pfDeepDoubleBvLONNXJetTags +from RecoBTag.ONNXRuntime.pfDeepDoubleCvLONNXJetTags_cfi import pfDeepDoubleCvLONNXJetTags +from RecoBTag.ONNXRuntime.pfDeepDoubleCvBONNXJetTags_cfi import pfDeepDoubleCvBONNXJetTags +from RecoBTag.TensorFlow.pfDeepDoubleBvLTFJetTags_cfi import pfDeepDoubleBvLTFJetTags +from RecoBTag.TensorFlow.pfDeepDoubleCvLTFJetTags_cfi import pfDeepDoubleCvLTFJetTags +from RecoBTag.TensorFlow.pfDeepDoubleCvBTFJetTags_cfi import pfDeepDoubleCvBTFJetTags + +pfDeepDoubleBvLJetTags = SwitchProducerONNX( + native = pfDeepDoubleBvLTFJetTags.clone(), + onnx = pfDeepDoubleBvLONNXJetTags.clone(), +) + +pfDeepDoubleCvLJetTags = SwitchProducerONNX( + native = pfDeepDoubleCvLTFJetTags.clone(), + onnx = pfDeepDoubleCvLONNXJetTags.clone(), +) + +pfDeepDoubleCvBJetTags = SwitchProducerONNX( + native = pfDeepDoubleCvBTFJetTags.clone(), + onnx = pfDeepDoubleCvBONNXJetTags.clone(), +) + +pfMassIndependentDeepDoubleBvLJetTags = SwitchProducerONNX( + native = pfDeepDoubleBvLTFJetTags.clone( + model_path = 'RecoBTag/Combined/data/DeepDoubleX/94X/V01/DDB_mass_independent.pb' + ), + onnx = pfDeepDoubleBvLONNXJetTags.clone( + model_path = 'RecoBTag/Combined/data/DeepDoubleX/94X/V01/DDB_mass_independent.onnx' + ), +) + +pfMassIndependentDeepDoubleCvLJetTags = SwitchProducerONNX( + native = pfDeepDoubleCvLTFJetTags.clone( + model_path = 'RecoBTag/Combined/data/DeepDoubleX/94X/V01/DDC_mass_independent.pb' + ), + onnx = pfDeepDoubleCvLONNXJetTags.clone( + model_path = 'RecoBTag/Combined/data/DeepDoubleX/94X/V01/DDC_mass_independent.onnx' + ), +) + +pfMassIndependentDeepDoubleCvBJetTags = SwitchProducerONNX( + native = pfDeepDoubleCvBTFJetTags.clone( + model_path = 'RecoBTag/Combined/data/DeepDoubleX/94X/V01/DDCvB_mass_independent.pb' + ), + onnx = pfDeepDoubleCvBONNXJetTags.clone( + model_path = 'RecoBTag/Combined/data/DeepDoubleX/94X/V01/DDCvB_mass_independent.onnx' + ), +) diff --git a/RecoBTag/ONNXRuntime/python/pfDeepDoubleX_cff.py b/RecoBTag/ONNXRuntime/python/pfDeepDoubleX_cff.py index 4c8ea8d8b67d1..ed880de9098bd 100644 --- a/RecoBTag/ONNXRuntime/python/pfDeepDoubleX_cff.py +++ b/RecoBTag/ONNXRuntime/python/pfDeepDoubleX_cff.py @@ -1,6 +1,4 @@ -from RecoBTag.ONNXRuntime.pfDeepDoubleBvLJetTags_cfi import pfDeepDoubleBvLJetTags -from RecoBTag.ONNXRuntime.pfDeepDoubleCvBJetTags_cfi import pfDeepDoubleCvBJetTags -from RecoBTag.ONNXRuntime.pfDeepDoubleCvLJetTags_cfi import pfDeepDoubleCvLJetTags - -from RecoBTag.ONNXRuntime.pfMassIndependentDeepDoubleXJetTags_cff import * +from RecoBTag.FeatureTools.pfDeepDoubleXTagInfos_cfi import pfDeepDoubleXTagInfos +from RecoBTag.ONNXRuntime.pfDeepDoubleXJetTags_cfi import pfDeepDoubleBvLJetTags, pfDeepDoubleCvBJetTags, pfDeepDoubleCvLJetTags, \ + pfMassIndependentDeepDoubleBvLJetTags, pfMassIndependentDeepDoubleCvLJetTags, pfMassIndependentDeepDoubleCvBJetTags diff --git a/RecoBTag/ONNXRuntime/python/pfDeepFlavourJetTags_cfi.py b/RecoBTag/ONNXRuntime/python/pfDeepFlavourJetTags_cfi.py new file mode 100644 index 0000000000000..f6a51bb2e81ab --- /dev/null +++ b/RecoBTag/ONNXRuntime/python/pfDeepFlavourJetTags_cfi.py @@ -0,0 +1,8 @@ +from RecoBTag.ONNXRuntime.SwitchProducerONNX import SwitchProducerONNX +from RecoBTag.ONNXRuntime.pfDeepFlavourONNXJetTags_cfi import pfDeepFlavourONNXJetTags +from RecoBTag.TensorFlow.pfDeepFlavourTFJetTags_cfi import pfDeepFlavourTFJetTags + +pfDeepFlavourJetTags = SwitchProducerONNX( + native = pfDeepFlavourTFJetTags.clone(), + onnx = pfDeepFlavourONNXJetTags.clone(), +) diff --git a/RecoBTag/ONNXRuntime/python/pfDeepFlavour_cff.py b/RecoBTag/ONNXRuntime/python/pfDeepFlavour_cff.py index a68d2585bad19..9b9c2b2be2378 100644 --- a/RecoBTag/ONNXRuntime/python/pfDeepFlavour_cff.py +++ b/RecoBTag/ONNXRuntime/python/pfDeepFlavour_cff.py @@ -2,7 +2,6 @@ from RecoBTag.FeatureTools.pfDeepFlavourTagInfos_cfi import pfDeepFlavourTagInfos from RecoBTag.FeatureTools.pfNegativeDeepFlavourTagInfos_cfi import pfNegativeDeepFlavourTagInfos -from RecoBTag.FeatureTools.pfDeepDoubleXTagInfos_cfi import pfDeepDoubleXTagInfos from RecoBTag.ONNXRuntime.pfDeepFlavourJetTags_cfi import pfDeepFlavourJetTags from RecoBTag.TensorFlow.pfDeepVertexJetTags_cfi import pfDeepVertexJetTags diff --git a/RecoBTag/ONNXRuntime/python/pfMassIndependentDeepDoubleXJetTags_cff.py b/RecoBTag/ONNXRuntime/python/pfMassIndependentDeepDoubleXJetTags_cff.py deleted file mode 100644 index d2e9d544b018b..0000000000000 --- a/RecoBTag/ONNXRuntime/python/pfMassIndependentDeepDoubleXJetTags_cff.py +++ /dev/null @@ -1,12 +0,0 @@ -from __future__ import absolute_import -import FWCore.ParameterSet.Config as cms -from .pfDeepDoubleBvLJetTags_cfi import pfDeepDoubleBvLJetTags -from .pfDeepDoubleCvLJetTags_cfi import pfDeepDoubleCvLJetTags -from .pfDeepDoubleCvBJetTags_cfi import pfDeepDoubleCvBJetTags - -pfMassIndependentDeepDoubleBvLJetTags = pfDeepDoubleBvLJetTags.clone( - model_path = 'RecoBTag/Combined/data/DeepDoubleX/94X/V01/DDB_mass_independent.onnx') -pfMassIndependentDeepDoubleCvLJetTags = pfDeepDoubleCvLJetTags.clone( - model_path = 'RecoBTag/Combined/data/DeepDoubleX/94X/V01/DDC_mass_independent.onnx') -pfMassIndependentDeepDoubleCvBJetTags = pfDeepDoubleCvBJetTags.clone( - model_path = 'RecoBTag/Combined/data/DeepDoubleX/94X/V01/DDCvB_mass_independent.onnx') diff --git a/RecoBTag/ONNXRuntime/python/pfNegativeDeepFlavourJetTags_cfi.py b/RecoBTag/ONNXRuntime/python/pfNegativeDeepFlavourJetTags_cfi.py index c5efa8035a310..ba6d889751090 100644 --- a/RecoBTag/ONNXRuntime/python/pfNegativeDeepFlavourJetTags_cfi.py +++ b/RecoBTag/ONNXRuntime/python/pfNegativeDeepFlavourJetTags_cfi.py @@ -2,6 +2,6 @@ from RecoBTag.ONNXRuntime.pfDeepFlavourJetTags_cfi import pfDeepFlavourJetTags -pfNegativeDeepFlavourJetTags = pfDeepFlavourJetTags.clone( - src = cms.InputTag('pfNegativeDeepFlavourTagInfos') - ) +pfNegativeDeepFlavourJetTags = pfDeepFlavourJetTags.cloneAll( + src = 'pfNegativeDeepFlavourTagInfos' + ) diff --git a/RecoBTag/TensorFlow/BuildFile.xml b/RecoBTag/TensorFlow/BuildFile.xml deleted file mode 100644 index 12e3ac6997187..0000000000000 --- a/RecoBTag/TensorFlow/BuildFile.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/RecoBTag/TensorFlow/interface/tensor_fillers.h b/RecoBTag/TensorFlow/interface/tensor_fillers.h deleted file mode 100644 index bdc9bcf995489..0000000000000 --- a/RecoBTag/TensorFlow/interface/tensor_fillers.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef RecoBTag_TensorFlow_tensor_fillers_h -#define RecoBTag_TensorFlow_tensor_fillers_h - -#include "PhysicsTools/TensorFlow/interface/TensorFlow.h" -#include "DataFormats/BTauReco/interface/DeepFlavourTagInfo.h" -#include "DataFormats/BTauReco/interface/DeepDoubleXTagInfo.h" - -namespace btagbtvdeep { - - // Note on setting tensor values: - // Instead of using the more convenient tensor.matrix (etc) methods, - // we can exploit that in the following methods values are set along - // the innermost (= last) axis. Those values are stored contiguously in - // the memory, so it is most performant to get the pointer to the first - // value and use pointer arithmetic to iterate through the next pointers. - - void jet_tensor_filler(tensorflow::Tensor& tensor, - std::size_t jet_n, - const btagbtvdeep::DeepFlavourFeatures& features); - - void jet4vec_tensor_filler(tensorflow::Tensor& tensor, - std::size_t jet_n, - const btagbtvdeep::DeepFlavourFeatures& features); - - void db_tensor_filler(tensorflow::Tensor& tensor, - std::size_t jet_n, - const btagbtvdeep::DeepDoubleXFeatures& features); - - void c_pf_tensor_filler(tensorflow::Tensor& tensor, - std::size_t jet_n, - std::size_t c_pf_n, - const btagbtvdeep::ChargedCandidateFeatures& c_pf_features); - - void c_pf_reduced_tensor_filler(tensorflow::Tensor& tensor, - std::size_t jet_n, - std::size_t c_pf_n, - const btagbtvdeep::ChargedCandidateFeatures& c_pf_features); - - void n_pf_tensor_filler(tensorflow::Tensor& tensor, - std::size_t jet_n, - std::size_t n_pf_n, - const btagbtvdeep::NeutralCandidateFeatures& n_pf_features); - - void sv_tensor_filler(tensorflow::Tensor& tensor, - std::size_t jet_n, - std::size_t sv_n, - const btagbtvdeep::SecondaryVertexFeatures& sv_features); - - void sv_reduced_tensor_filler(tensorflow::Tensor& tensor, - std::size_t jet_n, - std::size_t sv_n, - const btagbtvdeep::SecondaryVertexFeatures& sv_features); - - void seed_tensor_filler(tensorflow::Tensor& tensor, - std::size_t jet_n, - std::size_t seed_n, - const btagbtvdeep::SeedingTrackFeatures& seed_features); - - void neighbourTracks_tensor_filler(tensorflow::Tensor& tensor, - std::size_t jet_n, - std::size_t seed_n, - const btagbtvdeep::SeedingTrackFeatures& seed_features); - -} // namespace btagbtvdeep - -#endif diff --git a/RecoBTag/TensorFlow/plugins/BuildFile.xml b/RecoBTag/TensorFlow/plugins/BuildFile.xml index 84335c68879f2..d5cd47b2b037b 100644 --- a/RecoBTag/TensorFlow/plugins/BuildFile.xml +++ b/RecoBTag/TensorFlow/plugins/BuildFile.xml @@ -2,7 +2,7 @@ - + diff --git a/RecoBTag/TensorFlow/plugins/DeepDoubleXTFJetTagsProducer.cc b/RecoBTag/TensorFlow/plugins/DeepDoubleXTFJetTagsProducer.cc new file mode 100644 index 0000000000000..cab981ac35329 --- /dev/null +++ b/RecoBTag/TensorFlow/plugins/DeepDoubleXTFJetTagsProducer.cc @@ -0,0 +1,230 @@ +#include "FWCore/Framework/interface/Frameworkfwd.h" +#include "FWCore/Framework/interface/stream/EDProducer.h" + +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/MakerMacros.h" + +#include "FWCore/Framework/interface/makeRefToBaseProdFrom.h" + +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/Utilities/interface/StreamID.h" + +#include "DataFormats/BTauReco/interface/JetTag.h" + +#include "DataFormats/BTauReco/interface/DeepDoubleXTagInfo.h" +#include "RecoBTag/FeatureTools/interface/tensor_fillers.h" + +#include "PhysicsTools/TensorFlow/interface/TensorFlow.h" + +#include + +class DeepDoubleXTFJetTagsProducer : public edm::stream::EDProducer> { +public: + explicit DeepDoubleXTFJetTagsProducer(const edm::ParameterSet&, const tensorflow::GraphDef*); + ~DeepDoubleXTFJetTagsProducer() override; + + static void fillDescriptions(edm::ConfigurationDescriptions&); + + static std::unique_ptr initializeGlobalCache(const edm::ParameterSet&); + static void globalEndJob(const tensorflow::GraphDef*); + +private: + typedef std::vector TagInfoCollection; + typedef reco::JetTagCollection JetTagCollection; + + void produce(edm::Event&, const edm::EventSetup&) override; + + void make_inputs(unsigned i_jet, const reco::DeepDoubleXTagInfo& taginfo); + + const edm::EDGetTokenT src_; + std::vector flav_names_; + std::vector input_names_; + std::vector output_names_; + + enum InputIndexes { kGlobal = 0, kChargedCandidates = 1, kVertices = 2 }; + constexpr static unsigned n_features_global_ = 27; + constexpr static unsigned n_cpf_ = 60; + constexpr static unsigned n_features_cpf_ = 8; + constexpr static unsigned n_sv_ = 5; + constexpr static unsigned n_features_sv_ = 2; + const static std::vector input_shapes_; + + // hold the input data + tensorflow::NamedTensorList data_; + // session for TF evaluation + tensorflow::Session* session_ = nullptr; +}; + +const std::vector DeepDoubleXTFJetTagsProducer::input_shapes_{ + {1, n_features_global_}, + {1, n_cpf_, n_features_cpf_}, + {1, n_sv_, n_features_sv_}, +}; + +DeepDoubleXTFJetTagsProducer::DeepDoubleXTFJetTagsProducer(const edm::ParameterSet& iConfig, + const tensorflow::GraphDef* cache) + : src_(consumes(iConfig.getParameter("src"))), + flav_names_(iConfig.getParameter>("flav_names")), + input_names_(iConfig.getParameter>("input_names")), + output_names_(iConfig.getParameter>("output_names")) { + assert(input_names_.size() == input_shapes_.size()); + for (const auto& name : input_names_) { + data_.emplace_back(name, tensorflow::Tensor()); + } + + // get threading config and build session options + size_t nThreads = iConfig.getParameter("nThreads"); + std::string singleThreadPool = iConfig.getParameter("singleThreadPool"); + tensorflow::SessionOptions sessionOptions; + tensorflow::setThreading(sessionOptions, nThreads, singleThreadPool); + + // create the session using the meta graph from the cache + session_ = tensorflow::createSession(cache, sessionOptions); + + // get output names from flav_names + for (const auto& flav_name : flav_names_) { + produces(flav_name); + } +} + +DeepDoubleXTFJetTagsProducer::~DeepDoubleXTFJetTagsProducer() { + // close and delete the session + if (session_ != nullptr) { + tensorflow::closeSession(session_); + } +} + +void DeepDoubleXTFJetTagsProducer::fillDescriptions(edm::ConfigurationDescriptions& descriptions) { + // pfDeepDoubleBvLJetTags + edm::ParameterSetDescription desc; + desc.add("src", edm::InputTag("pfDeepDoubleXTagInfos")); + desc.add>("input_names", {"input_1", "input_2", "input_3"}); + desc.add>("output_names", {"ID_pred/Softmax"}); + desc.add("nThreads", 1); + desc.add("singleThreadPool", "no_threads"); + + using FIP = edm::FileInPath; + using PDFIP = edm::ParameterDescription; + using PDPSD = edm::ParameterDescription>; + using PDCases = edm::ParameterDescriptionCases; + auto flavorCases = [&]() { + return "BvL" >> (PDPSD("flav_names", std::vector{"probQCD", "probHbb"}, true) and + PDFIP("model_path", FIP("RecoBTag/Combined/data/DeepDoubleX/94X/V01/DDB.pb"), true)) or + "CvL" >> (PDPSD("flav_names", std::vector{"probQCD", "probHcc"}, true) and + PDFIP("model_path", FIP("RecoBTag/Combined/data/DeepDoubleX/94X/V01/DDC.pb"), true)) or + "CvB" >> (PDPSD("flav_names", std::vector{"probHbb", "probHcc"}, true) and + PDFIP("model_path", FIP("RecoBTag/Combined/data/DeepDoubleX/94X/V01/DDCvB.pb"), true)); + }; + auto descBvL(desc); + descBvL.ifValue(edm::ParameterDescription("flavor", "BvL", true), flavorCases()); + descriptions.add("pfDeepDoubleBvLTFJetTags", descBvL); + + auto descCvL(desc); + descCvL.ifValue(edm::ParameterDescription("flavor", "CvL", true), flavorCases()); + descriptions.add("pfDeepDoubleCvLTFJetTags", descCvL); + + auto descCvB(desc); + descCvB.ifValue(edm::ParameterDescription("flavor", "CvB", true), flavorCases()); + descriptions.add("pfDeepDoubleCvBTFJetTags", descCvB); +} + +std::unique_ptr DeepDoubleXTFJetTagsProducer::initializeGlobalCache( + const edm::ParameterSet& iConfig) { + // set the tensorflow log level to error + tensorflow::setLogging("3"); + return std::unique_ptr( + tensorflow::loadGraphDef(iConfig.getParameter("model_path").fullPath())); +} + +void DeepDoubleXTFJetTagsProducer::globalEndJob(const tensorflow::GraphDef* cache) {} + +void DeepDoubleXTFJetTagsProducer::produce(edm::Event& iEvent, const edm::EventSetup& iSetup) { + edm::Handle tag_infos; + iEvent.getByToken(src_, tag_infos); + + std::vector> output_tags; + if (!tag_infos->empty()) { + // initialize output collection + auto jet_ref = tag_infos->begin()->jet(); + auto ref2prod = edm::makeRefToBaseProdFrom(jet_ref, iEvent); + for (std::size_t i = 0; i < flav_names_.size(); i++) { + output_tags.emplace_back(std::make_unique(ref2prod)); + } + + // only need to run on jets with non-empty features + auto batch_size = std::count_if( + tag_infos->begin(), tag_infos->end(), [](const auto& taginfo) { return !taginfo.features().empty(); }); + + std::vector outputs; + if (batch_size > 0) { + // init data storage + for (unsigned i = 0; i < input_names_.size(); ++i) { + auto shape = input_shapes_[i]; + shape.set_dim(0, batch_size); + data_[i].second = tensorflow::Tensor(tensorflow::DT_FLOAT, shape); + data_[i].second.flat().setZero(); + } + + // convert inputs + unsigned idx = 0; + for (const auto& taginfo : *tag_infos) { + if (!taginfo.features().empty()) { + make_inputs(idx, taginfo); + ++idx; + } + } + + // run prediction + tensorflow::run(session_, data_, output_names_, &outputs); + } + + // get the outputs + unsigned idx = 0; + for (unsigned jet_n = 0; jet_n < tag_infos->size(); ++jet_n) { + const auto& taginfo = tag_infos->at(jet_n); + const auto& jet_ref = taginfo.jet(); + if (!taginfo.features().empty()) { + for (std::size_t flav_n = 0; flav_n < flav_names_.size(); flav_n++) { + (*(output_tags[flav_n]))[jet_ref] = outputs.at(0).matrix()(idx, flav_n); + } + ++idx; + } else { + for (std::size_t flav_n = 0; flav_n < flav_names_.size(); flav_n++) { + (*(output_tags[flav_n]))[jet_ref] = -1.; + } + } + } + } else { + // create empty output collection + for (std::size_t i = 0; i < flav_names_.size(); i++) { + output_tags.emplace_back(std::make_unique()); + } + } + + // put into the event + for (std::size_t flav_n = 0; flav_n < flav_names_.size(); ++flav_n) { + iEvent.put(std::move(output_tags[flav_n]), flav_names_[flav_n]); + } +} + +void DeepDoubleXTFJetTagsProducer::make_inputs(unsigned i_jet, const reco::DeepDoubleXTagInfo& taginfo) { + const auto& features = taginfo.features(); + + // DoubleB features + btagbtvdeep::db_tensor_filler(&data_[kGlobal].second.matrix()(i_jet, 0), features, n_features_global_); + + // c_pf candidates + auto max_c_pf_n = std::min(features.c_pf_features.size(), (std::size_t)n_cpf_); + btagbtvdeep::c_pf_reduced_tensor_filler(&data_[kChargedCandidates].second.tensor()(i_jet, 0, 0), + max_c_pf_n, + features.c_pf_features, + n_features_cpf_); + + // sv candidates + auto max_sv_n = std::min(features.sv_features.size(), (std::size_t)n_sv_); + btagbtvdeep::sv_reduced_tensor_filler( + &data_[kVertices].second.tensor()(i_jet, 0, 0), max_sv_n, features.sv_features, n_features_sv_); +} + +//define this as a plug-in +DEFINE_FWK_MODULE(DeepDoubleXTFJetTagsProducer); diff --git a/RecoBTag/TensorFlow/plugins/DeepFlavourTFJetTagsProducer.cc b/RecoBTag/TensorFlow/plugins/DeepFlavourTFJetTagsProducer.cc new file mode 100644 index 0000000000000..306938e64d072 --- /dev/null +++ b/RecoBTag/TensorFlow/plugins/DeepFlavourTFJetTagsProducer.cc @@ -0,0 +1,213 @@ +#include "FWCore/Framework/interface/Frameworkfwd.h" +#include "FWCore/Framework/interface/stream/EDProducer.h" + +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/MakerMacros.h" + +#include "FWCore/Framework/interface/makeRefToBaseProdFrom.h" + +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/Utilities/interface/StreamID.h" + +#include "DataFormats/BTauReco/interface/JetTag.h" + +#include "DataFormats/BTauReco/interface/DeepFlavourTagInfo.h" +#include "RecoBTag/FeatureTools/interface/tensor_fillers.h" + +#include "PhysicsTools/TensorFlow/interface/TensorFlow.h" + +class DeepFlavourTFJetTagsProducer : public edm::stream::EDProducer> { +public: + explicit DeepFlavourTFJetTagsProducer(const edm::ParameterSet&, const tensorflow::GraphDef*); + ~DeepFlavourTFJetTagsProducer() override; + + static void fillDescriptions(edm::ConfigurationDescriptions&); + + static std::unique_ptr initializeGlobalCache(const edm::ParameterSet&); + static void globalEndJob(const tensorflow::GraphDef*); + +private: + typedef std::vector TagInfoCollection; + typedef reco::JetTagCollection JetTagCollection; + + void produce(edm::Event&, const edm::EventSetup&) override; + + void make_inputs(unsigned i_jet, const reco::DeepFlavourTagInfo& taginfo); + + const edm::EDGetTokenT src_; + std::vector flav_names_; + std::vector input_names_; + std::vector output_names_; + + enum InputIndexes { kGlobal = 0, kChargedCandidates = 1, kNeutralCandidates = 2, kVertices = 3, kJetPt = 4 }; + constexpr static unsigned n_features_global_ = 15; + constexpr static unsigned n_cpf_ = 25; + constexpr static unsigned n_features_cpf_ = 16; + constexpr static unsigned n_npf_ = 25; + constexpr static unsigned n_features_npf_ = 6; + constexpr static unsigned n_sv_ = 4; + constexpr static unsigned n_features_sv_ = 12; + constexpr static unsigned n_features_jetpt_ = 1; + const static std::vector input_shapes_; + + // hold the input data + tensorflow::NamedTensorList data_; + // session for TF evaluation + tensorflow::Session* session_ = nullptr; +}; + +const std::vector DeepFlavourTFJetTagsProducer::input_shapes_{ + {1, n_features_global_}, + {1, n_cpf_, n_features_cpf_}, + {1, n_npf_, n_features_npf_}, + {1, n_sv_, n_features_sv_}, + {1, n_features_jetpt_}, +}; + +DeepFlavourTFJetTagsProducer::DeepFlavourTFJetTagsProducer(const edm::ParameterSet& iConfig, + const tensorflow::GraphDef* cache) + : src_(consumes(iConfig.getParameter("src"))), + flav_names_(iConfig.getParameter>("flav_names")), + input_names_(iConfig.getParameter>("input_names")), + output_names_(iConfig.getParameter>("output_names")) { + assert(input_names_.size() == input_shapes_.size()); + for (const auto& name : input_names_) { + data_.emplace_back(name, tensorflow::Tensor()); + } + + for (const auto& name : iConfig.getParameter>("lp_names")) { + data_.emplace_back(name, tensorflow::Tensor(tensorflow::DT_BOOL, {})); + data_.back().second.scalar()() = false; + } + + // get threading config and build session options + size_t nThreads = iConfig.getParameter("nThreads"); + std::string singleThreadPool = iConfig.getParameter("singleThreadPool"); + tensorflow::SessionOptions sessionOptions; + tensorflow::setThreading(sessionOptions, nThreads, singleThreadPool); + + // create the session using the meta graph from the cache + session_ = tensorflow::createSession(cache, sessionOptions); + + // get output names from flav_names + for (const auto& flav_name : flav_names_) { + produces(flav_name); + } +} + +DeepFlavourTFJetTagsProducer::~DeepFlavourTFJetTagsProducer() { + // close and delete the session + if (session_ != nullptr) { + tensorflow::closeSession(session_); + } +} + +void DeepFlavourTFJetTagsProducer::fillDescriptions(edm::ConfigurationDescriptions& descriptions) { + // pfDeepFlavourJetTags + edm::ParameterSetDescription desc; + desc.add("src", edm::InputTag("pfDeepFlavourTagInfos")); + desc.add>("input_names", {"input_1", "input_2", "input_3", "input_4", "input_5"}); + desc.add>("lp_names", {}); + desc.add("model_path", + edm::FileInPath("RecoBTag/Combined/data/DeepFlavourV03_10X_training/constant_graph.pb")); + desc.add>("output_names", {"ID_pred/Softmax"}); + desc.add>( + "flav_names", std::vector{"probb", "probbb", "problepb", "probc", "probuds", "probg"}); + desc.add("nThreads", 1); + desc.add("singleThreadPool", "no_threads"); + + descriptions.add("pfDeepFlavourTFJetTags", desc); +} + +std::unique_ptr DeepFlavourTFJetTagsProducer::initializeGlobalCache( + const edm::ParameterSet& iConfig) { + // set the tensorflow log level to error + tensorflow::setLogging("3"); + return std::unique_ptr( + tensorflow::loadGraphDef(iConfig.getParameter("model_path").fullPath())); +} + +void DeepFlavourTFJetTagsProducer::globalEndJob(const tensorflow::GraphDef* cache) {} + +void DeepFlavourTFJetTagsProducer::produce(edm::Event& iEvent, const edm::EventSetup& iSetup) { + edm::Handle tag_infos; + iEvent.getByToken(src_, tag_infos); + + std::vector> output_tags; + if (!tag_infos->empty()) { + // initialize output collection + auto jet_ref = tag_infos->begin()->jet(); + auto ref2prod = edm::makeRefToBaseProdFrom(jet_ref, iEvent); + for (std::size_t i = 0; i < flav_names_.size(); i++) { + output_tags.emplace_back(std::make_unique(ref2prod)); + } + + // init data storage + for (unsigned i = 0; i < input_names_.size(); ++i) { + auto shape = input_shapes_[i]; + shape.set_dim(0, tag_infos->size()); + data_[i].second = tensorflow::Tensor(tensorflow::DT_FLOAT, shape); + data_[i].second.flat().setZero(); + } + + // convert inputs + for (unsigned jet_n = 0; jet_n < tag_infos->size(); ++jet_n) { + const auto& taginfo = (*tag_infos)[jet_n]; + make_inputs(jet_n, taginfo); + } + + // run prediction + std::vector outputs; + tensorflow::run(session_, data_, output_names_, &outputs); + + // get the outputs + for (unsigned jet_n = 0; jet_n < tag_infos->size(); ++jet_n) { + const auto& jet_ref = tag_infos->at(jet_n).jet(); + for (std::size_t flav_n = 0; flav_n < flav_names_.size(); flav_n++) { + (*(output_tags[flav_n]))[jet_ref] = outputs.at(0).matrix()(jet_n, flav_n); + } + } + } else { + // create empty output collection + for (std::size_t i = 0; i < flav_names_.size(); i++) { + output_tags.emplace_back(std::make_unique()); + } + } + + // put into the event + for (std::size_t flav_n = 0; flav_n < flav_names_.size(); ++flav_n) { + iEvent.put(std::move(output_tags[flav_n]), flav_names_[flav_n]); + } +} + +void DeepFlavourTFJetTagsProducer::make_inputs(unsigned i_jet, const reco::DeepFlavourTagInfo& taginfo) { + const auto& features = taginfo.features(); + + // jet and other global features + btagbtvdeep::jet_tensor_filler(&data_[kGlobal].second.matrix()(i_jet, 0), features, n_features_global_); + + // c_pf candidates + auto max_c_pf_n = std::min(features.c_pf_features.size(), (std::size_t)n_cpf_); + btagbtvdeep::c_pf_tensor_filler(&data_[kChargedCandidates].second.tensor()(i_jet, 0, 0), + max_c_pf_n, + features.c_pf_features, + n_features_cpf_); + + // n_pf candidates + auto max_n_pf_n = std::min(features.n_pf_features.size(), (std::size_t)n_npf_); + btagbtvdeep::n_pf_tensor_filler(&data_[kNeutralCandidates].second.tensor()(i_jet, 0, 0), + max_n_pf_n, + features.n_pf_features, + n_features_npf_); + + // sv candidates + auto max_sv_n = std::min(features.sv_features.size(), (std::size_t)n_sv_); + btagbtvdeep::sv_tensor_filler( + &data_[kVertices].second.tensor()(i_jet, 0, 0), max_sv_n, features.sv_features, n_features_sv_); + + // last input: jet pt + data_[kJetPt].second.matrix()(i_jet, 0) = features.jet_features.pt; +} + +//define this as a plug-in +DEFINE_FWK_MODULE(DeepFlavourTFJetTagsProducer); diff --git a/RecoBTag/TensorFlow/plugins/DeepVertexTFJetTagsProducer.cc b/RecoBTag/TensorFlow/plugins/DeepVertexTFJetTagsProducer.cc index 094048594637b..6839880c4748c 100644 --- a/RecoBTag/TensorFlow/plugins/DeepVertexTFJetTagsProducer.cc +++ b/RecoBTag/TensorFlow/plugins/DeepVertexTFJetTagsProducer.cc @@ -16,7 +16,7 @@ #include "PhysicsTools/TensorFlow/interface/TensorFlow.h" -#include "RecoBTag/TensorFlow/interface/tensor_fillers.h" +#include "RecoBTag/FeatureTools/interface/tensor_fillers.h" // Declaration of the data structure that is hold by the edm::GlobalCache. // In TensorFlow, the computational graph is stored in a stateless graph object which can be shared @@ -265,7 +265,7 @@ void DeepVertexTFJetTagsProducer::produce(edm::Event& iEvent, const edm::EventSe continue; } - jet4vec_tensor_filler(input_tensors.at(kGlobal).second, jet_bn, features); + jet4vec_tensor_filler(&input_tensors.at(kGlobal).second.matrix()(jet_bn, 0), features, 4); // seed features auto max_seed_n = @@ -274,9 +274,10 @@ void DeepVertexTFJetTagsProducer::produce(edm::Event& iEvent, const edm::EventSe for (std::size_t seed_n = 0; seed_n < max_seed_n; seed_n++) { const auto& seed_features = features.seed_features.at(seed_n); - seed_tensor_filler(input_tensors.at(kSeedingTracks).second, jet_bn, seed_n, seed_features); + seed_tensor_filler( + &input_tensors.at(kSeedingTracks).second.tensor()(jet_bn, seed_n, 0), seed_features, 21); neighbourTracks_tensor_filler( - input_tensors.at(kNeighbourTracks + seed_n).second, jet_bn, seed_n, seed_features); + &input_tensors.at(kNeighbourTracks + seed_n).second.tensor()(jet_n, 0, 0), seed_features, 36); } } //different block diff --git a/RecoBTag/TensorFlow/src/tensor_fillers.cc b/RecoBTag/TensorFlow/src/tensor_fillers.cc deleted file mode 100644 index 4eec2671939c9..0000000000000 --- a/RecoBTag/TensorFlow/src/tensor_fillers.cc +++ /dev/null @@ -1,251 +0,0 @@ -#include "RecoBTag/TensorFlow/interface/tensor_fillers.h" - -namespace btagbtvdeep { - - // Note on setting tensor values: - // Instead of using the more convenient tensor.matrix (etc) methods, - // we can exploit that in the following methods values are set along - // the innermost (= last) axis. Those values are stored contiguously in - // the memory, so it is most performant to get the pointer to the first - // value and use pointer arithmetic to iterate through the next pointers. - - void jet_tensor_filler(tensorflow::Tensor& tensor, - std::size_t jet_n, - const btagbtvdeep::DeepFlavourFeatures& features) { - float* ptr = &tensor.matrix()(jet_n, 0); - - // jet variables - const auto& jet_features = features.jet_features; - *ptr = jet_features.pt; - *(++ptr) = jet_features.eta; - // number of elements in different collections - *(++ptr) = features.c_pf_features.size(); - *(++ptr) = features.n_pf_features.size(); - *(++ptr) = features.sv_features.size(); - *(++ptr) = features.npv; - // variables from ShallowTagInfo - const auto& tag_info_features = features.tag_info_features; - *(++ptr) = tag_info_features.trackSumJetEtRatio; - *(++ptr) = tag_info_features.trackSumJetDeltaR; - *(++ptr) = tag_info_features.vertexCategory; - *(++ptr) = tag_info_features.trackSip2dValAboveCharm; - *(++ptr) = tag_info_features.trackSip2dSigAboveCharm; - *(++ptr) = tag_info_features.trackSip3dValAboveCharm; - *(++ptr) = tag_info_features.trackSip3dSigAboveCharm; - *(++ptr) = tag_info_features.jetNSelectedTracks; - *(++ptr) = tag_info_features.jetNTracksEtaRel; - } - - void jet4vec_tensor_filler(tensorflow::Tensor& tensor, - std::size_t jet_n, - const btagbtvdeep::DeepFlavourFeatures& features) { - float* ptr = &tensor.matrix()(jet_n, 0); - - // jet 4 vector variables - const auto& jet_features = features.jet_features; - *ptr = jet_features.pt; - *(++ptr) = jet_features.eta; - *(++ptr) = jet_features.phi; - *(++ptr) = jet_features.mass; - } - - void db_tensor_filler(tensorflow::Tensor& tensor, - std::size_t jet_n, - const btagbtvdeep::DeepDoubleXFeatures& features) { - float* ptr = &tensor.tensor()(jet_n, 0, 0); - - // variables from BoostedDoubleSVTagInfo - const auto& tag_info_features = features.tag_info_features; - *ptr = tag_info_features.jetNTracks; - *(++ptr) = tag_info_features.jetNSecondaryVertices; - *(++ptr) = tag_info_features.tau1_trackEtaRel_0; - *(++ptr) = tag_info_features.tau1_trackEtaRel_1; - *(++ptr) = tag_info_features.tau1_trackEtaRel_2; - *(++ptr) = tag_info_features.tau2_trackEtaRel_0; - *(++ptr) = tag_info_features.tau2_trackEtaRel_1; - *(++ptr) = tag_info_features.tau2_trackEtaRel_2; - *(++ptr) = tag_info_features.tau1_flightDistance2dSig; - *(++ptr) = tag_info_features.tau2_flightDistance2dSig; - *(++ptr) = tag_info_features.tau1_vertexDeltaR; - // Note: this variable is not used in the 27-input BDT - // *(++ptr) = tag_info_features.tau2_vertexDeltaR; - *(++ptr) = tag_info_features.tau1_vertexEnergyRatio; - *(++ptr) = tag_info_features.tau2_vertexEnergyRatio; - *(++ptr) = tag_info_features.tau1_vertexMass; - *(++ptr) = tag_info_features.tau2_vertexMass; - *(++ptr) = tag_info_features.trackSip2dSigAboveBottom_0; - *(++ptr) = tag_info_features.trackSip2dSigAboveBottom_1; - *(++ptr) = tag_info_features.trackSip2dSigAboveCharm; - *(++ptr) = tag_info_features.trackSip3dSig_0; - *(++ptr) = tag_info_features.tau1_trackSip3dSig_0; - *(++ptr) = tag_info_features.tau1_trackSip3dSig_1; - *(++ptr) = tag_info_features.trackSip3dSig_1; - *(++ptr) = tag_info_features.tau2_trackSip3dSig_0; - *(++ptr) = tag_info_features.tau2_trackSip3dSig_1; - *(++ptr) = tag_info_features.trackSip3dSig_2; - *(++ptr) = tag_info_features.trackSip3dSig_3; - *(++ptr) = tag_info_features.z_ratio; - } - - void c_pf_tensor_filler(tensorflow::Tensor& tensor, - std::size_t jet_n, - std::size_t c_pf_n, - const btagbtvdeep::ChargedCandidateFeatures& c_pf_features) { - float* ptr = &tensor.tensor()(jet_n, c_pf_n, 0); - - *ptr = c_pf_features.btagPf_trackEtaRel; - *(++ptr) = c_pf_features.btagPf_trackPtRel; - *(++ptr) = c_pf_features.btagPf_trackPPar; - *(++ptr) = c_pf_features.btagPf_trackDeltaR; - *(++ptr) = c_pf_features.btagPf_trackPParRatio; - *(++ptr) = c_pf_features.btagPf_trackSip2dVal; - *(++ptr) = c_pf_features.btagPf_trackSip2dSig; - *(++ptr) = c_pf_features.btagPf_trackSip3dVal; - *(++ptr) = c_pf_features.btagPf_trackSip3dSig; - *(++ptr) = c_pf_features.btagPf_trackJetDistVal; - *(++ptr) = c_pf_features.ptrel; - *(++ptr) = c_pf_features.drminsv; - *(++ptr) = c_pf_features.vtx_ass; - *(++ptr) = c_pf_features.puppiw; - *(++ptr) = c_pf_features.chi2; - *(++ptr) = c_pf_features.quality; - } - - void c_pf_reduced_tensor_filler(tensorflow::Tensor& tensor, - std::size_t jet_n, - std::size_t c_pf_n, - const btagbtvdeep::ChargedCandidateFeatures& c_pf_features) { - float* ptr = &tensor.tensor()(jet_n, c_pf_n, 0); - - *ptr = c_pf_features.btagPf_trackEtaRel; - *(++ptr) = c_pf_features.btagPf_trackPtRatio; - *(++ptr) = c_pf_features.btagPf_trackPParRatio; - *(++ptr) = c_pf_features.btagPf_trackSip2dVal; - *(++ptr) = c_pf_features.btagPf_trackSip2dSig; - *(++ptr) = c_pf_features.btagPf_trackSip3dVal; - *(++ptr) = c_pf_features.btagPf_trackSip3dSig; - *(++ptr) = c_pf_features.btagPf_trackJetDistVal; - } - - void n_pf_tensor_filler(tensorflow::Tensor& tensor, - std::size_t jet_n, - std::size_t n_pf_n, - const btagbtvdeep::NeutralCandidateFeatures& n_pf_features) { - float* ptr = &tensor.tensor()(jet_n, n_pf_n, 0); - - *ptr = n_pf_features.ptrel; - *(++ptr) = n_pf_features.deltaR; - *(++ptr) = n_pf_features.isGamma; - *(++ptr) = n_pf_features.hadFrac; - *(++ptr) = n_pf_features.drminsv; - *(++ptr) = n_pf_features.puppiw; - } - - void sv_tensor_filler(tensorflow::Tensor& tensor, - std::size_t jet_n, - std::size_t sv_n, - const btagbtvdeep::SecondaryVertexFeatures& sv_features) { - float* ptr = &tensor.tensor()(jet_n, sv_n, 0); - - *ptr = sv_features.pt; - *(++ptr) = sv_features.deltaR; - *(++ptr) = sv_features.mass; - *(++ptr) = sv_features.ntracks; - *(++ptr) = sv_features.chi2; - *(++ptr) = sv_features.normchi2; - *(++ptr) = sv_features.dxy; - *(++ptr) = sv_features.dxysig; - *(++ptr) = sv_features.d3d; - *(++ptr) = sv_features.d3dsig; - *(++ptr) = sv_features.costhetasvpv; - *(++ptr) = sv_features.enratio; - } - - void sv_reduced_tensor_filler(tensorflow::Tensor& tensor, - std::size_t jet_n, - std::size_t sv_n, - const btagbtvdeep::SecondaryVertexFeatures& sv_features) { - float* ptr = &tensor.tensor()(jet_n, sv_n, 0); - - *ptr = sv_features.d3d; - *(++ptr) = sv_features.d3dsig; - } - - void seed_tensor_filler(tensorflow::Tensor& tensor, - std::size_t jet_n, - std::size_t seed_n, - const btagbtvdeep::SeedingTrackFeatures& seed_features) { - float* ptr = &tensor.tensor()(jet_n, seed_n, 0); - - *ptr = seed_features.pt; - *(++ptr) = seed_features.eta; - *(++ptr) = seed_features.phi; - *(++ptr) = seed_features.mass; - *(++ptr) = seed_features.dz; - *(++ptr) = seed_features.dxy; - *(++ptr) = seed_features.ip3D; - *(++ptr) = seed_features.sip3D; - *(++ptr) = seed_features.ip2D; - *(++ptr) = seed_features.sip2D; - *(++ptr) = seed_features.signedIp3D; - *(++ptr) = seed_features.signedSip3D; - *(++ptr) = seed_features.signedIp2D; - *(++ptr) = seed_features.signedSip2D; - *(++ptr) = seed_features.trackProbability3D; - *(++ptr) = seed_features.trackProbability2D; - *(++ptr) = seed_features.chi2reduced; - *(++ptr) = seed_features.nPixelHits; - *(++ptr) = seed_features.nHits; - *(++ptr) = seed_features.jetAxisDistance; - *(++ptr) = seed_features.jetAxisDlength; - } - - void neighbourTracks_tensor_filler(tensorflow::Tensor& tensor, - std::size_t jet_n, - std::size_t seed_n, - const btagbtvdeep::SeedingTrackFeatures& seed_features) { - std::vector neighbourTracks_features = seed_features.nearTracks; - - for (unsigned int t_i = 0; t_i < neighbourTracks_features.size(); t_i++) { - float* ptr = &tensor.tensor()(jet_n, t_i, 0); - - *ptr = neighbourTracks_features[t_i].pt; - *(++ptr) = neighbourTracks_features[t_i].eta; - *(++ptr) = neighbourTracks_features[t_i].phi; - *(++ptr) = neighbourTracks_features[t_i].dz; - *(++ptr) = neighbourTracks_features[t_i].dxy; - *(++ptr) = neighbourTracks_features[t_i].mass; - *(++ptr) = neighbourTracks_features[t_i].ip3D; - *(++ptr) = neighbourTracks_features[t_i].sip3D; - *(++ptr) = neighbourTracks_features[t_i].ip2D; - *(++ptr) = neighbourTracks_features[t_i].sip2D; - *(++ptr) = neighbourTracks_features[t_i].distPCA; - *(++ptr) = neighbourTracks_features[t_i].dsigPCA; - *(++ptr) = neighbourTracks_features[t_i].x_PCAonSeed; - *(++ptr) = neighbourTracks_features[t_i].y_PCAonSeed; - *(++ptr) = neighbourTracks_features[t_i].z_PCAonSeed; - *(++ptr) = neighbourTracks_features[t_i].xerr_PCAonSeed; - *(++ptr) = neighbourTracks_features[t_i].yerr_PCAonSeed; - *(++ptr) = neighbourTracks_features[t_i].zerr_PCAonSeed; - *(++ptr) = neighbourTracks_features[t_i].x_PCAonTrack; - *(++ptr) = neighbourTracks_features[t_i].y_PCAonTrack; - *(++ptr) = neighbourTracks_features[t_i].z_PCAonTrack; - *(++ptr) = neighbourTracks_features[t_i].xerr_PCAonTrack; - *(++ptr) = neighbourTracks_features[t_i].yerr_PCAonTrack; - *(++ptr) = neighbourTracks_features[t_i].zerr_PCAonTrack; - *(++ptr) = neighbourTracks_features[t_i].dotprodTrack; - *(++ptr) = neighbourTracks_features[t_i].dotprodSeed; - *(++ptr) = neighbourTracks_features[t_i].dotprodTrackSeed2D; - *(++ptr) = neighbourTracks_features[t_i].dotprodTrackSeed3D; - *(++ptr) = neighbourTracks_features[t_i].dotprodTrackSeedVectors2D; - *(++ptr) = neighbourTracks_features[t_i].dotprodTrackSeedVectors3D; - *(++ptr) = neighbourTracks_features[t_i].pvd_PCAonSeed; - *(++ptr) = neighbourTracks_features[t_i].pvd_PCAonTrack; - *(++ptr) = neighbourTracks_features[t_i].dist_PCAjetAxis; - *(++ptr) = neighbourTracks_features[t_i].dotprod_PCAjetMomenta; - *(++ptr) = neighbourTracks_features[t_i].deta_PCAjetDirs; - *(++ptr) = neighbourTracks_features[t_i].dphi_PCAjetDirs; - } - } - -} // namespace btagbtvdeep