diff --git a/PhysicsTools/NanoAOD/python/nano_cff.py b/PhysicsTools/NanoAOD/python/nano_cff.py index d280b50fa5da0..412da86412d9d 100644 --- a/PhysicsTools/NanoAOD/python/nano_cff.py +++ b/PhysicsTools/NanoAOD/python/nano_cff.py @@ -176,9 +176,6 @@ def nanoAOD_addDeepInfo(process,addDeepBTag,addDeepFlavour): process.load("Configuration.StandardSequences.MagneticField_cff") process.jetCorrFactorsNano.src="selectedUpdatedPatJetsWithDeepInfo" process.updatedJets.jetSource="selectedUpdatedPatJetsWithDeepInfo" - if addDeepFlavour: - process.pfDeepFlavourJetTagsWithDeepInfo.graph_path = 'RecoBTag/Combined/data/DeepFlavourV03_10X_training/constant_graph.pb' - process.pfDeepFlavourJetTagsWithDeepInfo.lp_names = ["cpf_input_batchnorm/keras_learning_phase"] return process from PhysicsTools.PatUtils.tools.runMETCorrectionsAndUncertainties import runMetCorAndUncFromMiniAOD @@ -237,7 +234,7 @@ def nanoAOD_addDeepInfoAK8(process,addDeepBTag,addDeepBoostedJet, addDeepDoubleX _btagDiscriminators += ['pfDeepCSVJetTags:probb','pfDeepCSVJetTags:probbb'] if addDeepBoostedJet: print("Updating process to run DeepBoostedJet on datasets before 103X") - from RecoBTag.MXNet.pfDeepBoostedJet_cff import _pfDeepBoostedJetTagsAll as pfDeepBoostedJetTagsAll + from RecoBTag.ONNXRuntime.pfDeepBoostedJet_cff import _pfDeepBoostedJetTagsAll as pfDeepBoostedJetTagsAll _btagDiscriminators += pfDeepBoostedJetTagsAll if addDeepDoubleX: print("Updating process to run DeepDoubleX on datasets before 104X") diff --git a/PhysicsTools/ONNXRuntime/BuildFile.xml b/PhysicsTools/ONNXRuntime/BuildFile.xml new file mode 100644 index 0000000000000..74335c38157af --- /dev/null +++ b/PhysicsTools/ONNXRuntime/BuildFile.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/PhysicsTools/ONNXRuntime/interface/ONNXRuntime.h b/PhysicsTools/ONNXRuntime/interface/ONNXRuntime.h new file mode 100644 index 0000000000000..c8411e2eeb5fe --- /dev/null +++ b/PhysicsTools/ONNXRuntime/interface/ONNXRuntime.h @@ -0,0 +1,66 @@ +/* + * ONNXRuntime.h + * + * A convenience wrapper of the ONNXRuntime C++ API. + * Based on https://github.com/microsoft/onnxruntime/blob/master/csharp/test/Microsoft.ML.OnnxRuntime.EndToEndTests.Capi/CXX_Api_Sample.cpp. + * + * Created on: Jun 28, 2019 + * Author: hqu + */ + +#ifndef PHYSICSTOOLS_ONNXRUNTIME_INTERFACE_ONNXRUNTIME_H_ +#define PHYSICSTOOLS_ONNXRUNTIME_INTERFACE_ONNXRUNTIME_H_ + +#include +#include +#include +#include + +#include "onnxruntime/core/session/onnxruntime_cxx_api.h" + +namespace cms::Ort { + + typedef std::vector> FloatArrays; + + class ONNXRuntime { + public: + ONNXRuntime(const std::string& model_path, const ::Ort::SessionOptions* session_options = nullptr); + ONNXRuntime(const ONNXRuntime&) = delete; + ONNXRuntime& operator=(const ONNXRuntime&) = delete; + ~ONNXRuntime(); + + // Run inference and get outputs + // input_names: list of the names of the input nodes. + // input_values: list of input arrays for each input node. The order of `input_values` must match `input_names`. + // output_names: names of the output nodes to get outputs from. Empty list means all output nodes. + // batch_size: number of samples in the batch. Each array in `input_values` must have a shape layout of (batch_size, ...). + // Returns: a std::vector>, with the order matched to `output_names`. + // When `output_names` is empty, will return all outputs ordered as in `getOutputNames()`. + FloatArrays run(const std::vector& input_names, + FloatArrays& input_values, + const std::vector& output_names = {}, + int64_t batch_size = 1) const; + + // Get a list of names of all the output nodes + const std::vector& getOutputNames() const; + + // Get the shape of a output node + // The 0th dim depends on the batch size, therefore is set to -1 + const std::vector& getOutputShape(const std::string& output_name) const; + + private: + static const ::Ort::Env env_; + std::unique_ptr<::Ort::Session> session_; + + std::vector input_node_strings_; + std::vector input_node_names_; + std::map> input_node_dims_; + + std::vector output_node_strings_; + std::vector output_node_names_; + std::map> output_node_dims_; + }; + +} // namespace cms::Ort + +#endif /* PHYSICSTOOLS_ONNXRUNTIME_INTERFACE_ONNXRUNTIME_H_ */ diff --git a/PhysicsTools/ONNXRuntime/src/ONNXRuntime.cc b/PhysicsTools/ONNXRuntime/src/ONNXRuntime.cc new file mode 100644 index 0000000000000..8744b6411fe73 --- /dev/null +++ b/PhysicsTools/ONNXRuntime/src/ONNXRuntime.cc @@ -0,0 +1,164 @@ +/* + * ONNXRuntime.cc + * + * Created on: Jun 28, 2019 + * Author: hqu + */ + +#include "PhysicsTools/ONNXRuntime/interface/ONNXRuntime.h" + +#include +#include +#include +#include +#include +#include "FWCore/Utilities/interface/Exception.h" +#include "FWCore/Utilities/interface/thread_safety_macros.h" + +namespace cms::Ort { + + using namespace ::Ort; + + const Env ONNXRuntime::env_(ORT_LOGGING_LEVEL_ERROR, ""); + + ONNXRuntime::ONNXRuntime(const std::string& model_path, const SessionOptions* session_options) { + // create session + if (session_options) { + session_.reset(new Session(env_, model_path.c_str(), *session_options)); + } else { + SessionOptions sess_opts; + sess_opts.SetIntraOpNumThreads(1); + session_.reset(new Session(env_, model_path.c_str(), sess_opts)); + } + AllocatorWithDefaultOptions allocator; + + // get input names and shapes + size_t num_input_nodes = session_->GetInputCount(); + input_node_strings_.resize(num_input_nodes); + input_node_names_.resize(num_input_nodes); + input_node_dims_.clear(); + + for (size_t i = 0; i < num_input_nodes; i++) { + // get input node names + std::string input_name(session_->GetInputName(i, allocator)); + input_node_strings_[i] = input_name; + input_node_names_[i] = input_node_strings_[i].c_str(); + + // get input shapes + auto type_info = session_->GetInputTypeInfo(i); + auto tensor_info = type_info.GetTensorTypeAndShapeInfo(); + size_t num_dims = tensor_info.GetDimensionsCount(); + input_node_dims_[input_name].resize(num_dims); + tensor_info.GetDimensions(input_node_dims_[input_name].data(), num_dims); + + // set the batch size to 1 by default + input_node_dims_[input_name].at(0) = 1; + } + + size_t num_output_nodes = session_->GetOutputCount(); + output_node_strings_.resize(num_output_nodes); + output_node_names_.resize(num_output_nodes); + output_node_dims_.clear(); + + for (size_t i = 0; i < num_output_nodes; i++) { + // get output node names + std::string output_name(session_->GetOutputName(i, allocator)); + output_node_strings_[i] = output_name; + output_node_names_[i] = output_node_strings_[i].c_str(); + + // get output node types + auto type_info = session_->GetOutputTypeInfo(i); + auto tensor_info = type_info.GetTensorTypeAndShapeInfo(); + size_t num_dims = tensor_info.GetDimensionsCount(); + output_node_dims_[output_name].resize(num_dims); + tensor_info.GetDimensions(output_node_dims_[output_name].data(), num_dims); + + // the 0th dim depends on the batch size + output_node_dims_[output_name].at(0) = -1; + } + } + + ONNXRuntime::~ONNXRuntime() {} + + FloatArrays ONNXRuntime::run(const std::vector& input_names, + FloatArrays& input_values, + const std::vector& output_names, + int64_t batch_size) const { + assert(input_names.size() == input_values.size()); + assert(batch_size > 0); + + // create input tensor objects from data values + std::vector input_tensors; + auto memory_info = MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault); + for (const auto& name : input_node_strings_) { + auto iter = std::find(input_names.begin(), input_names.end(), name); + if (iter == input_names.end()) { + throw cms::Exception("RuntimeError") << "Input " << name << " is not provided!"; + } + auto value = input_values.begin() + (iter - input_names.begin()); + auto input_dims = input_node_dims_.at(name); + input_dims[0] = batch_size; + auto expected_len = std::accumulate(input_dims.begin(), input_dims.end(), 1, std::multiplies()); + if (expected_len != (int64_t)value->size()) { + throw cms::Exception("RuntimeError") + << "Input array " << name << " has a wrong size of " << value->size() << ", expected " << expected_len; + } + auto input_tensor = + Value::CreateTensor(memory_info, value->data(), value->size(), input_dims.data(), input_dims.size()); + assert(input_tensor.IsTensor()); + input_tensors.emplace_back(std::move(input_tensor)); + } + + // set output node names; will get all outputs if `output_names` is not provided + std::vector run_output_node_names; + if (output_names.empty()) { + run_output_node_names = output_node_names_; + } else { + for (const auto& name : output_names) { + run_output_node_names.push_back(name.c_str()); + } + } + + // run + auto output_tensors = session_->Run(RunOptions{nullptr}, + input_node_names_.data(), + input_tensors.data(), + input_tensors.size(), + run_output_node_names.data(), + run_output_node_names.size()); + + // convert output to floats + FloatArrays outputs; + for (auto& output_tensor : output_tensors) { + assert(output_tensor.IsTensor()); + + // get output shape + auto tensor_info = output_tensor.GetTensorTypeAndShapeInfo(); + auto length = tensor_info.GetElementCount(); + + auto floatarr = output_tensor.GetTensorMutableData(); + outputs.emplace_back(floatarr, floatarr + length); + } + assert(outputs.size() == run_output_node_names.size()); + + return outputs; + } + + const std::vector& ONNXRuntime::getOutputNames() const { + if (session_) { + return output_node_strings_; + } else { + throw cms::Exception("RuntimeError") << "Needs to call createSession() first before getting the output names!"; + } + } + + const std::vector& ONNXRuntime::getOutputShape(const std::string& output_name) const { + 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; + } + } + +} /* namespace cms::Ort */ diff --git a/PhysicsTools/ONNXRuntime/test/BuildFile.xml b/PhysicsTools/ONNXRuntime/test/BuildFile.xml new file mode 100644 index 0000000000000..034a96daf6af7 --- /dev/null +++ b/PhysicsTools/ONNXRuntime/test/BuildFile.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/PhysicsTools/ONNXRuntime/test/data/model.onnx b/PhysicsTools/ONNXRuntime/test/data/model.onnx new file mode 100644 index 0000000000000..7b28419426960 Binary files /dev/null and b/PhysicsTools/ONNXRuntime/test/data/model.onnx differ diff --git a/PhysicsTools/ONNXRuntime/test/testONNXRuntime.cc b/PhysicsTools/ONNXRuntime/test/testONNXRuntime.cc new file mode 100644 index 0000000000000..8e0df6e5df501 --- /dev/null +++ b/PhysicsTools/ONNXRuntime/test/testONNXRuntime.cc @@ -0,0 +1,37 @@ +#include + +#include "PhysicsTools/ONNXRuntime/interface/ONNXRuntime.h" +#include "FWCore/ParameterSet/interface/FileInPath.h" + +#include +#include + +using namespace cms::Ort; + +class testONNXRuntime : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(testONNXRuntime); + CPPUNIT_TEST(checkAll); + CPPUNIT_TEST_SUITE_END(); + +public: + void checkAll(); +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(testONNXRuntime); + +void testONNXRuntime::checkAll() { + std::string model_path = edm::FileInPath("PhysicsTools/ONNXRuntime/test/data/model.onnx").fullPath(); + ONNXRuntime rt(model_path); + for (const unsigned batch_size : {1, 2, 4}) { + FloatArrays input_values{ + std::vector(batch_size * 2, 1), + }; + FloatArrays outputs; + 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); + } + } +} diff --git a/PhysicsTools/ONNXRuntime/test/testRunner.cpp b/PhysicsTools/ONNXRuntime/test/testRunner.cpp new file mode 100644 index 0000000000000..1482cf9a9ce85 --- /dev/null +++ b/PhysicsTools/ONNXRuntime/test/testRunner.cpp @@ -0,0 +1 @@ +#include diff --git a/PhysicsTools/PatAlgos/python/recoLayer0/bTagging_cff.py b/PhysicsTools/PatAlgos/python/recoLayer0/bTagging_cff.py index f1585f95224e3..f63f9ad4589db 100644 --- a/PhysicsTools/PatAlgos/python/recoLayer0/bTagging_cff.py +++ b/PhysicsTools/PatAlgos/python/recoLayer0/bTagging_cff.py @@ -219,7 +219,7 @@ # ----------------------------------- # setup DeepBoostedJet -from RecoBTag.MXNet.pfDeepBoostedJet_cff import _pfDeepBoostedJetTagsProbs, _pfDeepBoostedJetTagsMetaDiscrs, \ +from RecoBTag.ONNXRuntime.pfDeepBoostedJet_cff import _pfDeepBoostedJetTagsProbs, _pfDeepBoostedJetTagsMetaDiscrs, \ _pfMassDecorrelatedDeepBoostedJetTagsProbs, _pfMassDecorrelatedDeepBoostedJetTagsMetaDiscrs # update supportedBtagDiscr for disc in _pfDeepBoostedJetTagsProbs + _pfMassDecorrelatedDeepBoostedJetTagsProbs: diff --git a/PhysicsTools/PatAlgos/python/slimming/applyDeepBtagging_cff.py b/PhysicsTools/PatAlgos/python/slimming/applyDeepBtagging_cff.py index 02b36bc7c4586..ce546fdcd3dfa 100644 --- a/PhysicsTools/PatAlgos/python/slimming/applyDeepBtagging_cff.py +++ b/PhysicsTools/PatAlgos/python/slimming/applyDeepBtagging_cff.py @@ -42,7 +42,7 @@ def applyDeepBtagging( process, postfix="" ) : # delete module not used anymore (slimmedJets substitutes) delattr(process, 'selectedUpdatedPatJetsSlimmedDeepFlavour'+postfix) - from RecoBTag.MXNet.pfDeepBoostedJet_cff import _pfDeepBoostedJetTagsAll as pfDeepBoostedJetTagsAll + from RecoBTag.ONNXRuntime.pfDeepBoostedJet_cff import _pfDeepBoostedJetTagsAll as pfDeepBoostedJetTagsAll from RecoBTag.MXNet.pfParticleNet_cff import _pfParticleNetJetTagsAll as pfParticleNetJetTagsAll # update slimmed jets to include particle-based deep taggers (keep same name) diff --git a/RecoBTag/Configuration/python/RecoBTag_cff.py b/RecoBTag/Configuration/python/RecoBTag_cff.py index 8c03e0bf2bcfd..29e82b2f5d8c4 100644 --- a/RecoBTag/Configuration/python/RecoBTag_cff.py +++ b/RecoBTag/Configuration/python/RecoBTag_cff.py @@ -7,9 +7,9 @@ from RecoBTag.Combined.combinedMVA_cff import * from RecoBTag.CTagging.RecoCTagging_cff import * from RecoBTag.Combined.deepFlavour_cff import * -from RecoBTag.TensorFlow.pfDeepFlavour_cff import * -from RecoBTag.TensorFlow.pfDeepDoubleX_cff import * -from RecoBTag.MXNet.pfDeepBoostedJet_cff import * +from RecoBTag.ONNXRuntime.pfDeepFlavour_cff import * +from RecoBTag.ONNXRuntime.pfDeepDoubleX_cff import * +from RecoBTag.ONNXRuntime.pfDeepBoostedJet_cff import * from RecoBTag.MXNet.pfParticleNet_cff import * from RecoVertex.AdaptiveVertexFinder.inclusiveVertexing_cff import * diff --git a/RecoBTag/MXNet/plugins/BoostedJetMXNetJetTagsProducer.cc b/RecoBTag/MXNet/plugins/BoostedJetMXNetJetTagsProducer.cc index 25638da86bedd..64d116103c760 100644 --- a/RecoBTag/MXNet/plugins/BoostedJetMXNetJetTagsProducer.cc +++ b/RecoBTag/MXNet/plugins/BoostedJetMXNetJetTagsProducer.cc @@ -141,36 +141,23 @@ BoostedJetMXNetJetTagsProducer::BoostedJetMXNetJetTagsProducer(const edm::Parame BoostedJetMXNetJetTagsProducer::~BoostedJetMXNetJetTagsProducer() {} void BoostedJetMXNetJetTagsProducer::fillDescriptions(edm::ConfigurationDescriptions &descriptions) { - // pfDeepBoostedJetTags + // pfParticleNetJetTags edm::ParameterSetDescription desc; - desc.add("src", edm::InputTag("pfDeepBoostedJetTagInfos")); + desc.add("src", edm::InputTag("pfParticleNetTagInfos")); edm::ParameterSetDescription preprocessParams; preprocessParams.setAllowAnything(); desc.add("preprocessParams", preprocessParams); - desc.add("model_path", - edm::FileInPath("RecoBTag/Combined/data/DeepBoostedJet/V01/full/resnet-symbol.json")); - desc.add("param_path", - edm::FileInPath("RecoBTag/Combined/data/DeepBoostedJet/V01/full/resnet-0000.params")); - desc.add>("flav_names", - std::vector{ - "probTbcq", - "probTbqq", - "probTbc", - "probTbq", - "probWcq", - "probWqq", - "probZbb", - "probZcc", - "probZqq", - "probHbb", - "probHcc", - "probHqqqq", - "probQCDbb", - "probQCDcc", - "probQCDb", - "probQCDc", - "probQCDothers", - }); + desc.add( + "model_path", edm::FileInPath("RecoBTag/Combined/data/ParticleNetAK8/General/V00/ParticleNet-symbol.json")); + desc.add( + "param_path", edm::FileInPath("RecoBTag/Combined/data/ParticleNetAK8/General/V00/ParticleNet-0000.params")); + desc.add>( + "flav_names", + std::vector{ + "probTbcq", "probTbqq", "probTbc", "probTbq", "probTbel", "probTbmu", "probTbta", + "probWcq", "probWqq", "probZbb", "probZcc", "probZqq", "probHbb", "probHcc", + "probHqqqq", "probQCDbb", "probQCDcc", "probQCDb", "probQCDc", "probQCDothers", + }); desc.addOptionalUntracked("debugMode", false); descriptions.addWithDefaultLabel(desc); diff --git a/RecoBTag/MXNet/plugins/BuildFile.xml b/RecoBTag/MXNet/plugins/BuildFile.xml index b6d6eaed37b09..e64a37659f9a9 100644 --- a/RecoBTag/MXNet/plugins/BuildFile.xml +++ b/RecoBTag/MXNet/plugins/BuildFile.xml @@ -1,5 +1,4 @@ - diff --git a/RecoBTag/MXNet/python/pfParticleNet_cff.py b/RecoBTag/MXNet/python/pfParticleNet_cff.py index e02d257f6ecb3..b97d1fb164a02 100644 --- a/RecoBTag/MXNet/python/pfParticleNet_cff.py +++ b/RecoBTag/MXNet/python/pfParticleNet_cff.py @@ -14,9 +14,6 @@ preprocessParams = pfParticleNetPreprocessParams, model_path = 'RecoBTag/Combined/data/ParticleNetAK8/General/V00/ParticleNet-symbol.json', param_path = 'RecoBTag/Combined/data/ParticleNetAK8/General/V00/ParticleNet-0000.params', - flav_names = ["probTbcq", "probTbqq", "probTbc", "probTbq", "probTbel", "probTbmu", "probTbta", - "probWcq", "probWqq", "probZbb", "probZcc", "probZqq", "probHbb", "probHcc", - "probHqqqq", "probQCDbb", "probQCDcc", "probQCDb", "probQCDc", "probQCDothers"], ) pfMassDecorrelatedParticleNetJetTags = boostedJetMXNetJetTagsProducer.clone( diff --git a/RecoBTag/ONNXRuntime/plugins/BuildFile.xml b/RecoBTag/ONNXRuntime/plugins/BuildFile.xml new file mode 100644 index 0000000000000..8deb93e335e1b --- /dev/null +++ b/RecoBTag/ONNXRuntime/plugins/BuildFile.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/RecoBTag/ONNXRuntime/plugins/DeepBoostedJetONNXJetTagsProducer.cc b/RecoBTag/ONNXRuntime/plugins/DeepBoostedJetONNXJetTagsProducer.cc new file mode 100644 index 0000000000000..90a0151fe1c33 --- /dev/null +++ b/RecoBTag/ONNXRuntime/plugins/DeepBoostedJetONNXJetTagsProducer.cc @@ -0,0 +1,277 @@ +#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/DeepBoostedJetTagInfo.h" + +#include "PhysicsTools/ONNXRuntime/interface/ONNXRuntime.h" + +#include +#include +#include +#include + +using namespace cms::Ort; + +// struct to hold preprocessing parameters +struct PreprocessParams { + struct VarInfo { + VarInfo() {} + VarInfo(float median, float norm_factor) : center(median), norm_factor(norm_factor) {} + float center = 0; + float norm_factor = 1; + }; + + unsigned var_length = 0; + std::vector var_names; + std::unordered_map var_info_map; + + VarInfo get_info(const std::string &name) const { + auto item = var_info_map.find(name); + if (item != var_info_map.end()) { + return item->second; + } else { + throw cms::Exception("InvalidArgument") << "Cannot find variable info for " << name; + } + } +}; + +class DeepBoostedJetONNXJetTagsProducer : public edm::stream::EDProducer> { +public: + explicit DeepBoostedJetONNXJetTagsProducer(const edm::ParameterSet &, const ONNXRuntime *); + ~DeepBoostedJetONNXJetTagsProducer() override; + + static void fillDescriptions(edm::ConfigurationDescriptions &); + + static std::unique_ptr initializeGlobalCache(const edm::ParameterSet &); + static void globalEndJob(const ONNXRuntime *); + +private: + typedef std::vector TagInfoCollection; + typedef reco::JetTagCollection JetTagCollection; + + void produce(edm::Event &, const edm::EventSetup &) override; + + std::vector center_norm_pad(const std::vector &input, + float center, + float scale, + unsigned target_length, + float pad_value = 0, + float min = 0, + float max = -1); + void make_inputs(const reco::DeepBoostedJetTagInfo &taginfo); + + const edm::EDGetTokenT src_; + std::vector flav_names_; // names of the output scores + std::vector input_names_; // names of each input group - the ordering is important! + std::vector> input_shapes_; // shapes of each input group + std::unordered_map prep_info_map_; // preprocessing info for each input group + + FloatArrays data_; + + bool debug_ = false; +}; + +DeepBoostedJetONNXJetTagsProducer::DeepBoostedJetONNXJetTagsProducer(const edm::ParameterSet &iConfig, + const ONNXRuntime *cache) + : src_(consumes(iConfig.getParameter("src"))), + flav_names_(iConfig.getParameter>("flav_names")), + debug_(iConfig.getUntrackedParameter("debugMode", false)) { + // load preprocessing info + const auto &prep_pset = iConfig.getParameterSet("preprocessParams"); + input_names_ = prep_pset.getParameter>("input_names"); + for (const auto &group_name : input_names_) { + const auto &group_pset = prep_pset.getParameterSet(group_name); + input_shapes_.push_back(group_pset.getParameter>("input_shape")); + auto &prep_params = prep_info_map_[group_name]; + prep_params.var_length = group_pset.getParameter("var_length"); + prep_params.var_names = group_pset.getParameter>("var_names"); + const auto &var_info_pset = group_pset.getParameterSet("var_infos"); + for (const auto &var_name : prep_params.var_names) { + const auto &var_pset = var_info_pset.getParameterSet(var_name); + double median = var_pset.getParameter("median"); + double norm_factor = var_pset.getParameter("norm_factor"); + prep_params.var_info_map[var_name] = PreprocessParams::VarInfo(median, norm_factor); + } + + // create data storage with a fixed size vector initilized w/ 0 + unsigned len = prep_params.var_length * prep_params.var_names.size(); + data_.emplace_back(len, 0); + } + + if (debug_) { + for (unsigned i = 0; i < input_names_.size(); ++i) { + const auto &group_name = input_names_.at(i); + std::cout << group_name << "\nshapes: "; + for (const auto &x : input_shapes_.at(i)) { + std::cout << x << ", "; + } + std::cout << "\nvariables: "; + for (const auto &x : prep_info_map_.at(group_name).var_names) { + std::cout << x << ", "; + } + std::cout << "\n"; + } + } + + // get output names from flav_names + for (const auto &flav_name : flav_names_) { + produces(flav_name); + } +} + +DeepBoostedJetONNXJetTagsProducer::~DeepBoostedJetONNXJetTagsProducer() {} + +void DeepBoostedJetONNXJetTagsProducer::fillDescriptions(edm::ConfigurationDescriptions &descriptions) { + // pfDeepBoostedJetTags + edm::ParameterSetDescription desc; + desc.add("src", edm::InputTag("pfDeepBoostedJetTagInfos")); + edm::ParameterSetDescription preprocessParams; + preprocessParams.setAllowAnything(); + desc.add("preprocessParams", preprocessParams); + desc.add("model_path", + edm::FileInPath("RecoBTag/Combined/data/DeepBoostedJet/V02/full/resnet.onnx")); + desc.add>("flav_names", + std::vector{ + "probTbcq", + "probTbqq", + "probTbc", + "probTbq", + "probWcq", + "probWqq", + "probZbb", + "probZcc", + "probZqq", + "probHbb", + "probHcc", + "probHqqqq", + "probQCDbb", + "probQCDcc", + "probQCDb", + "probQCDc", + "probQCDothers", + }); + desc.addOptionalUntracked("debugMode", false); + + descriptions.add("pfDeepBoostedJetTags", desc); +} + +std::unique_ptr DeepBoostedJetONNXJetTagsProducer::initializeGlobalCache(const edm::ParameterSet &iConfig) { + return std::make_unique(iConfig.getParameter("model_path").fullPath()); +} + +void DeepBoostedJetONNXJetTagsProducer::globalEndJob(const ONNXRuntime *cache) {} + +void DeepBoostedJetONNXJetTagsProducer::produce(edm::Event &iEvent, const edm::EventSetup &iSetup) { + edm::Handle tag_infos; + iEvent.getByToken(src_, tag_infos); + + // initialize output collection + std::vector> output_tags; + if (!tag_infos->empty()) { + 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)); + } + } else { + for (std::size_t i = 0; i < flav_names_.size(); i++) { + output_tags.emplace_back(std::make_unique()); + } + } + + for (unsigned jet_n = 0; jet_n < tag_infos->size(); ++jet_n) { + const auto &taginfo = (*tag_infos)[jet_n]; + std::vector outputs(flav_names_.size(), 0); // init as all zeros + + if (!taginfo.features().empty()) { + // convert inputs + make_inputs(taginfo); + // run prediction and get outputs + outputs = globalCache()->run(input_names_, data_)[0]; + assert(outputs.size() == flav_names_.size()); + } + + 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[flav_n]; + } + } + + if (debug_) { + std::cout << "=== " << iEvent.id().run() << ":" << iEvent.id().luminosityBlock() << ":" << iEvent.id().event() + << " ===" << std::endl; + for (unsigned jet_n = 0; jet_n < tag_infos->size(); ++jet_n) { + const auto &jet_ref = tag_infos->at(jet_n).jet(); + std::cout << " - Jet #" << jet_n << ", pt=" << jet_ref->pt() << ", eta=" << jet_ref->eta() + << ", phi=" << jet_ref->phi() << std::endl; + for (std::size_t flav_n = 0; flav_n < flav_names_.size(); ++flav_n) { + std::cout << " " << flav_names_.at(flav_n) << " = " << (*(output_tags.at(flav_n)))[jet_ref] << std::endl; + } + } + } + + // 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]); + } +} + +std::vector DeepBoostedJetONNXJetTagsProducer::center_norm_pad(const std::vector &input, + float center, + float norm_factor, + unsigned target_length, + float pad_value, + float min, + float max) { + // do variable shifting/scaling/padding/clipping in one go + + assert(min <= pad_value && pad_value <= max); + + std::vector out(target_length, pad_value); + for (unsigned i = 0; i < input.size() && i < target_length; ++i) { + out[i] = std::clamp((input[i] - center) * norm_factor, min, max); + } + return out; +} + +void DeepBoostedJetONNXJetTagsProducer::make_inputs(const reco::DeepBoostedJetTagInfo &taginfo) { + for (unsigned igroup = 0; igroup < input_names_.size(); ++igroup) { + const auto &group_name = input_names_[igroup]; + auto &group_values = data_[igroup]; + const auto &prep_params = prep_info_map_.at(group_name); + // first reset group_values to 0 + std::fill(group_values.begin(), group_values.end(), 0); + unsigned curr_pos = 0; + // transform/pad + for (const auto &varname : prep_params.var_names) { + const auto &raw_value = taginfo.features().get(varname); + const auto &info = prep_params.get_info(varname); + const float pad = 0; // pad w/ zero + auto val = center_norm_pad(raw_value, info.center, info.norm_factor, prep_params.var_length, pad, -5, 5); + std::copy(val.begin(), val.end(), group_values.begin() + curr_pos); + curr_pos += prep_params.var_length; + + if (debug_) { + std::cout << " -- var=" << varname << ", center=" << info.center << ", scale=" << info.norm_factor + << ", pad=" << pad << std::endl; + std::cout << "values (first 7 and last 3): " << val.at(0) << ", " << val.at(1) << ", " << val.at(2) << ", " + << val.at(3) << ", " << val.at(4) << ", " << val.at(5) << ", " << val.at(6) << " ... " + << val.at(prep_params.var_length - 3) << ", " << val.at(prep_params.var_length - 2) << ", " + << val.at(prep_params.var_length - 1) << std::endl; + } + } + } +} + +//define this as a plug-in +DEFINE_FWK_MODULE(DeepBoostedJetONNXJetTagsProducer); diff --git a/RecoBTag/ONNXRuntime/plugins/DeepDoubleXONNXJetTagsProducer.cc b/RecoBTag/ONNXRuntime/plugins/DeepDoubleXONNXJetTagsProducer.cc new file mode 100644 index 0000000000000..f7c5176b199c9 --- /dev/null +++ b/RecoBTag/ONNXRuntime/plugins/DeepDoubleXONNXJetTagsProducer.cc @@ -0,0 +1,254 @@ +#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 "PhysicsTools/ONNXRuntime/interface/ONNXRuntime.h" + +#include + +using namespace cms::Ort; + +class DeepDoubleXONNXJetTagsProducer : public edm::stream::EDProducer> { +public: + explicit DeepDoubleXONNXJetTagsProducer(const edm::ParameterSet&, const ONNXRuntime*); + ~DeepDoubleXONNXJetTagsProducer() override; + + static void fillDescriptions(edm::ConfigurationDescriptions&); + + static std::unique_ptr initializeGlobalCache(const edm::ParameterSet&); + static void globalEndJob(const ONNXRuntime*); + +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_sizes_; + + // hold the input data + FloatArrays data_; +}; + +const std::vector DeepDoubleXONNXJetTagsProducer::input_sizes_{ + n_features_global_, n_cpf_* n_features_cpf_, n_sv_* n_features_sv_}; + +DeepDoubleXONNXJetTagsProducer::DeepDoubleXONNXJetTagsProducer(const edm::ParameterSet& iConfig, + const ONNXRuntime* cache) + : src_(consumes(iConfig.getParameter("src"))), + flav_names_(iConfig.getParameter>("flav_names")), + input_names_(iConfig.getParameter>("input_names")), + output_names_(iConfig.getParameter>("output_names")) { + // get output names from flav_names + for (const auto& flav_name : flav_names_) { + produces(flav_name); + } + + assert(input_names_.size() == input_sizes_.size()); +} + +DeepDoubleXONNXJetTagsProducer::~DeepDoubleXONNXJetTagsProducer() {} + +void DeepDoubleXONNXJetTagsProducer::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", {}); + + 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.onnx"), true)) or + "CvL" >> (PDPSD("flav_names", std::vector{"probQCD", "probHcc"}, true) and + PDFIP("model_path", FIP("RecoBTag/Combined/data/DeepDoubleX/94X/V01/DDC.onnx"), true)) or + "CvB" >> (PDPSD("flav_names", std::vector{"probHbb", "probHcc"}, true) and + PDFIP("model_path", FIP("RecoBTag/Combined/data/DeepDoubleX/94X/V01/DDCvB.onnx"), true)); + }; + auto descBvL(desc); + descBvL.ifValue(edm::ParameterDescription("flavor", "BvL", true), flavorCases()); + descriptions.add("pfDeepDoubleBvLJetTags", descBvL); + + auto descCvL(desc); + descCvL.ifValue(edm::ParameterDescription("flavor", "CvL", true), flavorCases()); + descriptions.add("pfDeepDoubleCvLJetTags", descCvL); + + auto descCvB(desc); + descCvB.ifValue(edm::ParameterDescription("flavor", "CvB", true), flavorCases()); + descriptions.add("pfDeepDoubleCvBJetTags", descCvB); +} + +std::unique_ptr DeepDoubleXONNXJetTagsProducer::initializeGlobalCache(const edm::ParameterSet& iConfig) { + return std::make_unique(iConfig.getParameter("model_path").fullPath()); +} + +void DeepDoubleXONNXJetTagsProducer::globalEndJob(const ONNXRuntime* cache) {} + +void DeepDoubleXONNXJetTagsProducer::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 + data_.clear(); + for (const auto& len : input_sizes_) { + data_.emplace_back(batch_size * len, 0); + } + + // convert inputs + unsigned idx = 0; + for (const auto& taginfo : *tag_infos) { + if (!taginfo.features().empty()) { + make_inputs(idx, taginfo); + ++idx; + } + } + + // run prediction + outputs = globalCache()->run(input_names_, data_, output_names_, batch_size)[0]; + assert(outputs.size() == flav_names_.size() * batch_size); + } + + // get the outputs + unsigned i_output = 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(); + for (std::size_t flav_n = 0; flav_n < flav_names_.size(); flav_n++) { + if (!taginfo.features().empty()) { + (*(output_tags[flav_n]))[jet_ref] = outputs[i_output]; + ++i_output; + } else { + (*(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 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); + + // 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); + } + + // 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); + } +} + +//define this as a plug-in +DEFINE_FWK_MODULE(DeepDoubleXONNXJetTagsProducer); diff --git a/RecoBTag/ONNXRuntime/plugins/DeepFlavourONNXJetTagsProducer.cc b/RecoBTag/ONNXRuntime/plugins/DeepFlavourONNXJetTagsProducer.cc new file mode 100644 index 0000000000000..8e1c91c7fe9c7 --- /dev/null +++ b/RecoBTag/ONNXRuntime/plugins/DeepFlavourONNXJetTagsProducer.cc @@ -0,0 +1,250 @@ +#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 "PhysicsTools/ONNXRuntime/interface/ONNXRuntime.h" + +using namespace cms::Ort; + +class DeepFlavourONNXJetTagsProducer : public edm::stream::EDProducer> { +public: + explicit DeepFlavourONNXJetTagsProducer(const edm::ParameterSet&, const ONNXRuntime*); + ~DeepFlavourONNXJetTagsProducer() override; + + static void fillDescriptions(edm::ConfigurationDescriptions&); + + static std::unique_ptr initializeGlobalCache(const edm::ParameterSet&); + static void globalEndJob(const ONNXRuntime*); + +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_sizes_; + + // hold the input data + FloatArrays data_; +}; + +const std::vector DeepFlavourONNXJetTagsProducer::input_sizes_{ + n_features_global_, n_cpf_* n_features_cpf_, n_npf_* n_features_npf_, n_sv_* n_features_sv_, n_features_jetpt_}; + +DeepFlavourONNXJetTagsProducer::DeepFlavourONNXJetTagsProducer(const edm::ParameterSet& iConfig, + const ONNXRuntime* cache) + : src_(consumes(iConfig.getParameter("src"))), + flav_names_(iConfig.getParameter>("flav_names")), + input_names_(iConfig.getParameter>("input_names")), + output_names_(iConfig.getParameter>("output_names")) { + // 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() {} + +void DeepFlavourONNXJetTagsProducer::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("model_path", + edm::FileInPath("RecoBTag/Combined/data/DeepFlavourV03_10X_training/model.onnx")); + desc.add>("output_names", {"ID_pred/Softmax:0"}); + desc.add>( + "flav_names", std::vector{"probb", "probbb", "problepb", "probc", "probuds", "probg"}); + + descriptions.add("pfDeepFlavourJetTags", desc); +} + +std::unique_ptr DeepFlavourONNXJetTagsProducer::initializeGlobalCache(const edm::ParameterSet& iConfig) { + return std::make_unique(iConfig.getParameter("model_path").fullPath()); +} + +void DeepFlavourONNXJetTagsProducer::globalEndJob(const ONNXRuntime* cache) {} + +void DeepFlavourONNXJetTagsProducer::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 + data_.clear(); + for (const auto& len : input_sizes_) { + data_.emplace_back(tag_infos->size() * len, 0); + } + + // 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 + auto outputs = globalCache()->run(input_names_, data_, output_names_, tag_infos->size())[0]; + assert(outputs.size() == flav_names_.size() * tag_infos->size()); + + // get the outputs + unsigned i_output = 0; + 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[i_output]; + ++i_output; + } + } + } 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 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); + + // 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); + } + + // 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); + } + + // 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); + } + + // last input: jet pt + offset = i_jet * input_sizes_[kJetPt]; + data_[kJetPt][offset] = features.jet_features.pt; +} + +//define this as a plug-in +DEFINE_FWK_MODULE(DeepFlavourONNXJetTagsProducer); diff --git a/RecoBTag/MXNet/python/Parameters/V01/pfDeepBoostedJetPreprocessParams_cfi.py b/RecoBTag/ONNXRuntime/python/Parameters/DeepBoostedJet/V01/pfDeepBoostedJetPreprocessParams_cfi.py similarity index 100% rename from RecoBTag/MXNet/python/Parameters/V01/pfDeepBoostedJetPreprocessParams_cfi.py rename to RecoBTag/ONNXRuntime/python/Parameters/DeepBoostedJet/V01/pfDeepBoostedJetPreprocessParams_cfi.py diff --git a/RecoBTag/MXNet/python/Parameters/V02/pfDeepBoostedJetPreprocessParams_cfi.py b/RecoBTag/ONNXRuntime/python/Parameters/DeepBoostedJet/V02/pfDeepBoostedJetPreprocessParams_cfi.py similarity index 100% rename from RecoBTag/MXNet/python/Parameters/V02/pfDeepBoostedJetPreprocessParams_cfi.py rename to RecoBTag/ONNXRuntime/python/Parameters/DeepBoostedJet/V02/pfDeepBoostedJetPreprocessParams_cfi.py diff --git a/RecoBTag/MXNet/python/Parameters/V02/pfMassDecorrelatedDeepBoostedJetPreprocessParams_cfi.py b/RecoBTag/ONNXRuntime/python/Parameters/DeepBoostedJet/V02/pfMassDecorrelatedDeepBoostedJetPreprocessParams_cfi.py similarity index 100% rename from RecoBTag/MXNet/python/Parameters/V02/pfMassDecorrelatedDeepBoostedJetPreprocessParams_cfi.py rename to RecoBTag/ONNXRuntime/python/Parameters/DeepBoostedJet/V02/pfMassDecorrelatedDeepBoostedJetPreprocessParams_cfi.py diff --git a/RecoBTag/MXNet/python/pfDeepBoostedDiscriminatorsJetTags_cfi.py b/RecoBTag/ONNXRuntime/python/pfDeepBoostedDiscriminatorsJetTags_cfi.py similarity index 100% rename from RecoBTag/MXNet/python/pfDeepBoostedDiscriminatorsJetTags_cfi.py rename to RecoBTag/ONNXRuntime/python/pfDeepBoostedDiscriminatorsJetTags_cfi.py diff --git a/RecoBTag/MXNet/python/pfDeepBoostedJet_cff.py b/RecoBTag/ONNXRuntime/python/pfDeepBoostedJet_cff.py similarity index 69% rename from RecoBTag/MXNet/python/pfDeepBoostedJet_cff.py rename to RecoBTag/ONNXRuntime/python/pfDeepBoostedJet_cff.py index 375fef2de40f0..f6592696e4059 100644 --- a/RecoBTag/MXNet/python/pfDeepBoostedJet_cff.py +++ b/RecoBTag/ONNXRuntime/python/pfDeepBoostedJet_cff.py @@ -1,25 +1,23 @@ import FWCore.ParameterSet.Config as cms from RecoBTag.FeatureTools.pfDeepBoostedJetTagInfos_cfi import pfDeepBoostedJetTagInfos -from RecoBTag.MXNet.boostedJetMXNetJetTagsProducer_cfi import boostedJetMXNetJetTagsProducer -from RecoBTag.MXNet.Parameters.V02.pfDeepBoostedJetPreprocessParams_cfi import pfDeepBoostedJetPreprocessParams -from RecoBTag.MXNet.Parameters.V02.pfMassDecorrelatedDeepBoostedJetPreprocessParams_cfi import pfMassDecorrelatedDeepBoostedJetPreprocessParams -from RecoBTag.MXNet.pfDeepBoostedDiscriminatorsJetTags_cfi import pfDeepBoostedDiscriminatorsJetTags -from RecoBTag.MXNet.pfMassDecorrelatedDeepBoostedDiscriminatorsJetTags_cfi import pfMassDecorrelatedDeepBoostedDiscriminatorsJetTags +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.pfDeepBoostedDiscriminatorsJetTags_cfi import pfDeepBoostedDiscriminatorsJetTags +from RecoBTag.ONNXRuntime.pfMassDecorrelatedDeepBoostedDiscriminatorsJetTags_cfi import pfMassDecorrelatedDeepBoostedDiscriminatorsJetTags # nominal DeepAK8 -pfDeepBoostedJetTags = boostedJetMXNetJetTagsProducer.clone( +pfDeepBoostedJetTags = _pfDeepBoostedJetTags.clone( preprocessParams = pfDeepBoostedJetPreprocessParams, - model_path = 'RecoBTag/Combined/data/DeepBoostedJet/V02/full/resnet-symbol.json', - param_path = 'RecoBTag/Combined/data/DeepBoostedJet/V02/full/resnet-0000.params', + model_path = 'RecoBTag/Combined/data/DeepBoostedJet/V02/full/resnet.onnx', debugMode = False, # debug ) # mass-decorrelated DeepAK8 -pfMassDecorrelatedDeepBoostedJetTags = boostedJetMXNetJetTagsProducer.clone( +pfMassDecorrelatedDeepBoostedJetTags = _pfDeepBoostedJetTags.clone( preprocessParams = pfMassDecorrelatedDeepBoostedJetPreprocessParams, - model_path = 'RecoBTag/Combined/data/DeepBoostedJet/V02/decorrelated/resnet-symbol.json', - param_path = 'RecoBTag/Combined/data/DeepBoostedJet/V02/decorrelated/resnet-0000.params', + model_path = 'RecoBTag/Combined/data/DeepBoostedJet/V02/decorrelated/resnet.onnx', debugMode = False, # debug ) diff --git a/RecoBTag/ONNXRuntime/python/pfDeepDoubleX_cff.py b/RecoBTag/ONNXRuntime/python/pfDeepDoubleX_cff.py new file mode 100644 index 0000000000000..4c8ea8d8b67d1 --- /dev/null +++ b/RecoBTag/ONNXRuntime/python/pfDeepDoubleX_cff.py @@ -0,0 +1,6 @@ +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 * + diff --git a/RecoBTag/TensorFlow/python/pfDeepFlavour_cff.py b/RecoBTag/ONNXRuntime/python/pfDeepFlavour_cff.py similarity index 79% rename from RecoBTag/TensorFlow/python/pfDeepFlavour_cff.py rename to RecoBTag/ONNXRuntime/python/pfDeepFlavour_cff.py index 481b0efa90f7e..4e66360a21ae3 100644 --- a/RecoBTag/TensorFlow/python/pfDeepFlavour_cff.py +++ b/RecoBTag/ONNXRuntime/python/pfDeepFlavour_cff.py @@ -4,8 +4,8 @@ from RecoBTag.FeatureTools.pfNegativeDeepFlavourTagInfos_cfi import pfNegativeDeepFlavourTagInfos from RecoBTag.FeatureTools.pfDeepDoubleXTagInfos_cfi import pfDeepDoubleXTagInfos -from RecoBTag.TensorFlow.pfDeepFlavourJetTags_cfi import pfDeepFlavourJetTags -from RecoBTag.TensorFlow.pfNegativeDeepFlavourJetTags_cfi import pfNegativeDeepFlavourJetTags +from RecoBTag.ONNXRuntime.pfDeepFlavourJetTags_cfi import pfDeepFlavourJetTags +from RecoBTag.ONNXRuntime.pfNegativeDeepFlavourJetTags_cfi import pfNegativeDeepFlavourJetTags from CommonTools.PileupAlgos.Puppi_cff import puppi from PhysicsTools.PatAlgos.slimming.primaryVertexAssociation_cfi import primaryVertexAssociation diff --git a/RecoBTag/MXNet/python/pfMassDecorrelatedDeepBoostedDiscriminatorsJetTags_cfi.py b/RecoBTag/ONNXRuntime/python/pfMassDecorrelatedDeepBoostedDiscriminatorsJetTags_cfi.py similarity index 100% rename from RecoBTag/MXNet/python/pfMassDecorrelatedDeepBoostedDiscriminatorsJetTags_cfi.py rename to RecoBTag/ONNXRuntime/python/pfMassDecorrelatedDeepBoostedDiscriminatorsJetTags_cfi.py diff --git a/RecoBTag/TensorFlow/python/pfMassIndependentDeepDoubleXJetTags_cff.py b/RecoBTag/ONNXRuntime/python/pfMassIndependentDeepDoubleXJetTags_cff.py similarity index 64% rename from RecoBTag/TensorFlow/python/pfMassIndependentDeepDoubleXJetTags_cff.py rename to RecoBTag/ONNXRuntime/python/pfMassIndependentDeepDoubleXJetTags_cff.py index c058d6ffe1084..d2e9d544b018b 100644 --- a/RecoBTag/TensorFlow/python/pfMassIndependentDeepDoubleXJetTags_cff.py +++ b/RecoBTag/ONNXRuntime/python/pfMassIndependentDeepDoubleXJetTags_cff.py @@ -5,10 +5,8 @@ from .pfDeepDoubleCvBJetTags_cfi import pfDeepDoubleCvBJetTags pfMassIndependentDeepDoubleBvLJetTags = pfDeepDoubleBvLJetTags.clone( - graph_path = 'RecoBTag/Combined/data/DeepDoubleX/94X/V01/DDB_mass_independent.pb') + model_path = 'RecoBTag/Combined/data/DeepDoubleX/94X/V01/DDB_mass_independent.onnx') pfMassIndependentDeepDoubleCvLJetTags = pfDeepDoubleCvLJetTags.clone( - graph_path = 'RecoBTag/Combined/data/DeepDoubleX/94X/V01/DDC_mass_independent.pb') + model_path = 'RecoBTag/Combined/data/DeepDoubleX/94X/V01/DDC_mass_independent.onnx') pfMassIndependentDeepDoubleCvBJetTags = pfDeepDoubleCvBJetTags.clone( - graph_path = 'RecoBTag/Combined/data/DeepDoubleX/94X/V01/DDCvB_mass_independent.pb') - - + model_path = 'RecoBTag/Combined/data/DeepDoubleX/94X/V01/DDCvB_mass_independent.onnx') diff --git a/RecoBTag/TensorFlow/python/pfNegativeDeepFlavourJetTags_cfi.py b/RecoBTag/ONNXRuntime/python/pfNegativeDeepFlavourJetTags_cfi.py similarity index 68% rename from RecoBTag/TensorFlow/python/pfNegativeDeepFlavourJetTags_cfi.py rename to RecoBTag/ONNXRuntime/python/pfNegativeDeepFlavourJetTags_cfi.py index a9e6273f2368c..c5efa8035a310 100644 --- a/RecoBTag/TensorFlow/python/pfNegativeDeepFlavourJetTags_cfi.py +++ b/RecoBTag/ONNXRuntime/python/pfNegativeDeepFlavourJetTags_cfi.py @@ -1,6 +1,6 @@ import FWCore.ParameterSet.Config as cms -from RecoBTag.TensorFlow.pfDeepFlavourJetTags_cfi import pfDeepFlavourJetTags +from RecoBTag.ONNXRuntime.pfDeepFlavourJetTags_cfi import pfDeepFlavourJetTags pfNegativeDeepFlavourJetTags = pfDeepFlavourJetTags.clone( src = cms.InputTag('pfNegativeDeepFlavourTagInfos') diff --git a/RecoBTag/TensorFlow/test/plotDDX.py b/RecoBTag/ONNXRuntime/test/plotDDX.py similarity index 100% rename from RecoBTag/TensorFlow/test/plotDDX.py rename to RecoBTag/ONNXRuntime/test/plotDDX.py diff --git a/RecoBTag/MXNet/test/test_deep_boosted_jet_cfg.py b/RecoBTag/ONNXRuntime/test/test_deep_boosted_jet_cfg.py similarity index 97% rename from RecoBTag/MXNet/test/test_deep_boosted_jet_cfg.py rename to RecoBTag/ONNXRuntime/test/test_deep_boosted_jet_cfg.py index b28dcae0a65eb..e805da23b39d6 100644 --- a/RecoBTag/MXNet/test/test_deep_boosted_jet_cfg.py +++ b/RecoBTag/ONNXRuntime/test/test_deep_boosted_jet_cfg.py @@ -48,7 +48,7 @@ ## and add them to the event content from PhysicsTools.PatAlgos.tools.jetTools import updateJetCollection -from RecoBTag.MXNet.pfDeepBoostedJet_cff import _pfDeepBoostedJetTagsAll as pfDeepBoostedJetTagsAll +from RecoBTag.ONNXRuntime.pfDeepBoostedJet_cff import _pfDeepBoostedJetTagsAll as pfDeepBoostedJetTagsAll updateJetCollection( process, diff --git a/RecoBTag/TensorFlow/test/test_deep_doubleb_cfg_AOD.py b/RecoBTag/ONNXRuntime/test/test_deep_doubleb_cfg_AOD.py similarity index 98% rename from RecoBTag/TensorFlow/test/test_deep_doubleb_cfg_AOD.py rename to RecoBTag/ONNXRuntime/test/test_deep_doubleb_cfg_AOD.py index 7ad0824949662..8c82f56a62006 100644 --- a/RecoBTag/TensorFlow/test/test_deep_doubleb_cfg_AOD.py +++ b/RecoBTag/ONNXRuntime/test/test_deep_doubleb_cfg_AOD.py @@ -62,7 +62,7 @@ process, #labelName = 'AK8PFCHS', labelName = 'AK8PFPuppi', - #jetSource = cms.InputTag('ak8PFJetsCHS'), + #jetSource = cms.InputTag('ak8PFJetsPuppi'), jetSource = cms.InputTag('ak8PFJetsPuppi'), #pvSource = cms.InputTag('offlinePrimaryVertices'), #svSource = cms.InputTag('inclusiveCandidateSecondaryVertices'), @@ -105,7 +105,7 @@ from Configuration.EventContent.EventContent_cff import MINIAODSIMEventContent #process.out.outputCommands = MINIAODSIMEventContent.outputCommands process.out.outputCommands = patEventContentNoCleaning -process.out.outputCommands.append('keep *_ak8PFJetsCHS*_*_*') +process.out.outputCommands.append('keep *_ak8PFJetsPuppi*_*_*') process.out.outputCommands.append('keep *_offlinePrimaryVertices*_*_*') process.out.outputCommands.append('keep *_inclusiveCandidateSecondaryVertices*_*_*') process.out.outputCommands.append('keep *_selectedPatJets*_*_*') diff --git a/RecoBTag/TensorFlow/test/test_deep_doublex_cfg.py b/RecoBTag/ONNXRuntime/test/test_deep_doublex_cfg.py similarity index 100% rename from RecoBTag/TensorFlow/test/test_deep_doublex_cfg.py rename to RecoBTag/ONNXRuntime/test/test_deep_doublex_cfg.py diff --git a/RecoBTag/TensorFlow/test/test_deep_flavour_cfg.py b/RecoBTag/ONNXRuntime/test/test_deep_flavour_cfg.py similarity index 100% rename from RecoBTag/TensorFlow/test/test_deep_flavour_cfg.py rename to RecoBTag/ONNXRuntime/test/test_deep_flavour_cfg.py diff --git a/RecoBTag/TensorFlow/plugins/BuildFile.xml b/RecoBTag/TensorFlow/plugins/BuildFile.xml deleted file mode 100644 index 84335c68879f2..0000000000000 --- a/RecoBTag/TensorFlow/plugins/BuildFile.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/RecoBTag/TensorFlow/plugins/DeepDoubleXTFJetTagsProducer.cc b/RecoBTag/TensorFlow/plugins/DeepDoubleXTFJetTagsProducer.cc deleted file mode 100644 index 4c9b595e342f6..0000000000000 --- a/RecoBTag/TensorFlow/plugins/DeepDoubleXTFJetTagsProducer.cc +++ /dev/null @@ -1,332 +0,0 @@ - -#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 "PhysicsTools/TensorFlow/interface/TensorFlow.h" - -#include "RecoBTag/TensorFlow/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 -// by multiple session instances which handle the initialization of variables related to the graph. -// Following this approach in CMSSW, a graph should be stored in a GlobalCache which can be accessed -// by sessions owned by multiple stream module copies. Instead of using only the plain graph, we -// make use of a cache struct that can be extended in the future if nedded. In addition, the graph -// is protected via std::atomic, which should not affect the performance as it is only accessed in -// the module constructor and not in the actual produce loop. -struct DeepDoubleXTFCache { - DeepDoubleXTFCache() : graphDef(nullptr) { - } - - std::atomic graphDef; -}; - -class DeepDoubleXTFJetTagsProducer : public edm::stream::EDProducer> { - - public: - explicit DeepDoubleXTFJetTagsProducer(const edm::ParameterSet&, const DeepDoubleXTFCache*); - ~DeepDoubleXTFJetTagsProducer() override; - - static void fillDescriptions(edm::ConfigurationDescriptions&); - - static std::unique_ptr initializeGlobalCache(const edm::ParameterSet&); - static void globalEndJob(const DeepDoubleXTFCache*); - - enum InputIndexes { - kGlobal = 0, - kChargedCandidates = 1, - kVertices = 2 - }; - - enum OutputIndexes { - kJetFlavour = 0 - }; - - private: - typedef std::vector TagInfoCollection; - typedef reco::JetTagCollection JetTagCollection; - - void beginStream(edm::StreamID) override {} - void produce(edm::Event&, const edm::EventSetup&) override; - void endStream() override {} - - const edm::EDGetTokenT< TagInfoCollection > src_; - std::vector>> flav_pairs_; - std::vector input_names_; - std::vector output_names_; - std::vector lp_names_; - - // session for TF evaluation - tensorflow::Session* session_; - // vector of learning phase tensors, i.e., boolean scalar tensors pointing to false - std::vector lp_tensors_; - // flag to evaluate model batch or jet by jet - bool batch_eval_; -}; - -DeepDoubleXTFJetTagsProducer::DeepDoubleXTFJetTagsProducer(const edm::ParameterSet& iConfig, - const DeepDoubleXTFCache* cache) : - src_(consumes(iConfig.getParameter("src"))), - input_names_(iConfig.getParameter>("input_names")), - output_names_(iConfig.getParameter>("output_names")), - lp_names_(iConfig.getParameter>("lp_names")), - session_(nullptr), - batch_eval_(iConfig.getParameter("batch_eval")) -{ - // 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->graphDef, sessionOptions); - - // get output names from flav_table - const auto & flav_pset = iConfig.getParameter("flav_table"); - for (const auto flav_pair : flav_pset.tbl()) { - const auto & flav_name = flav_pair.first; - flav_pairs_.emplace_back(flav_name, - flav_pset.getParameter>(flav_name)); - } - - for (const auto & flav_pair : flav_pairs_) { - produces(flav_pair.first); - } - - // flag inputs (required because of batch norm) - // names for the learing phase placeholders (to init and set as false) - for (size_t i = 0; i < lp_names_.size(); i++) { - // create a bool tensor, set its value to false and store it - tensorflow::Tensor t(tensorflow::DT_BOOL, {}); - t.scalar()() = false; - lp_tensors_.push_back(t); - } -} - -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>("lp_names", - { "db_input_batchnorm/keras_learning_phase" }); - desc.add>("output_names", - { "ID_pred/Softmax" }); - - desc.add("batch_eval", false); - - desc.add("nThreads", 1); - desc.add("singleThreadPool", "no_threads"); - - edm::ParameterSetDescription psBvL; - psBvL.add>("probQCD", {0}); - psBvL.add>("probHbb", {1}); - - edm::ParameterSetDescription psCvL; - psCvL.add>("probQCD", {0}); - psCvL.add>("probHcc", {1}); - - edm::ParameterSetDescription psCvB; - psCvB.add>("probHbb", {0}); - psCvB.add>("probHcc", {1}); - - using FIP = edm::FileInPath; - using PDFIP = edm::ParameterDescription; - using PDPSD = edm::ParameterDescription; - using PDCases = edm::ParameterDescriptionCases; - auto flavorCases = [&](){ return - "BvL" >> (PDPSD("flav_table", psBvL, true) and - PDFIP("graph_path", FIP("RecoBTag/Combined/data/DeepDoubleX/94X/V01/DDB.pb"), true) ) or - "CvL" >> (PDPSD("flav_table", psCvL, true) and - PDFIP("graph_path", FIP("RecoBTag/Combined/data/DeepDoubleX/94X/V01/DDC.pb"), true) ) or - "CvB" >> (PDPSD("flav_table", psCvB, true) and - PDFIP("graph_path", FIP("RecoBTag/Combined/data/DeepDoubleX/94X/V01/DDCvB.pb"), true)); - }; - auto descBvL(desc); - descBvL.ifValue( edm::ParameterDescription("flavor", "BvL", true), flavorCases()); - descriptions.add("pfDeepDoubleBvLJetTags", descBvL); - - auto descCvL(desc); - descCvL.ifValue( edm::ParameterDescription("flavor", "CvL", true), flavorCases()); - descriptions.add("pfDeepDoubleCvLJetTags", descCvL); - - auto descCvB(desc); - descCvB.ifValue( edm::ParameterDescription("flavor", "CvB", true), flavorCases()); - descriptions.add("pfDeepDoubleCvBJetTags", descCvB); - -} - -std::unique_ptr DeepDoubleXTFJetTagsProducer::initializeGlobalCache( - const edm::ParameterSet& iConfig) -{ - // set the tensorflow log level to error - tensorflow::setLogging("3"); - - // get the pb file - std::string pbFile = iConfig.getParameter("graph_path").fullPath(); - - // load the graph def and save it in the cache - DeepDoubleXTFCache* cache = new DeepDoubleXTFCache(); - cache->graphDef = tensorflow::loadGraphDef(pbFile); - - return std::unique_ptr(cache); -} - -void DeepDoubleXTFJetTagsProducer::globalEndJob(const DeepDoubleXTFCache* cache) -{ - if (cache->graphDef != nullptr) { - delete cache->graphDef; - } -} - -void DeepDoubleXTFJetTagsProducer::produce(edm::Event& iEvent, const edm::EventSetup& iSetup) -{ - - edm::Handle tag_infos; - iEvent.getByToken(src_, tag_infos); - - // initialize output collection - std::vector> output_tags; - for (std::size_t i=0; i < flav_pairs_.size(); i++) { - if (!tag_infos->empty()) { - auto jet_ref = tag_infos->begin()->jet(); - output_tags.emplace_back(std::make_unique( - edm::makeRefToBaseProdFrom(jet_ref, iEvent))); - } else { - output_tags.emplace_back(std::make_unique()); - } - } - - // count jets to actually run inference on - int64_t n_jets = 0; - for (std::size_t i=0; i < tag_infos->size(); i++){ - const auto & features = tag_infos->at(i).features(); - if (!features.empty()) n_jets += 1 ; - } - // count all jets to generate output_tags for each and set to default (-1) - const int64_t n_jets_all = tag_infos->size(); - // either all jets or one per batch for the time being - const int64_t n_batch_jets = batch_eval_ ? n_jets_all : 1; - - std::vector input_sizes { - {n_batch_jets, 1, 27}, // input_1 - global double-b features - {n_batch_jets, 60, 8}, // input_2 - charged pf - {n_batch_jets, 5, 2}, // input_3 - vertices - }; - - // create a list of named tensors, i.e. a vector of (string, Tensor) pairs, with proper size to - // prevent element copying that would occur via push_back's - // the default Tensor constructor creates a scalar so this should be fine w.r.t. to memory - tensorflow::NamedTensorList input_tensors; - input_tensors.resize(input_sizes.size() + lp_tensors_.size()); - - // add actual input tensors that hold physics information - for (std::size_t i=0; i < input_sizes.size(); i++) { - input_tensors[i] = tensorflow::NamedTensor( - input_names_[i], tensorflow::Tensor(tensorflow::DT_FLOAT, input_sizes.at(i))); - } - - // add learning-phase tensors behind them - for (std::size_t i=0; i < lp_tensors_.size(); i++) { - input_tensors[input_sizes.size() + i] = tensorflow::NamedTensor(lp_names_[i], lp_tensors_[i]); - } - - std::size_t n_batches = n_jets_all/n_batch_jets; // either 1 or n_jets - for (std::size_t batch_n=0; batch_n < n_batches; batch_n++) { - // tensors have to be zeroed before filling per batch - for (std::size_t i=0; i < input_sizes.size(); i++) { - input_tensors[i].second.flat().setZero(); - } - // don't run batch unless filled - bool run_this_batch = false; - // fill values of the input tensors - for (std::size_t jet_bn=0; jet_bn < (std::size_t) n_batch_jets; jet_bn++) { - - // global jet index (jet_bn is the jet batch index) - std::size_t jet_n = batch_n*n_batch_jets + jet_bn; - // only fill if features not empty - const auto & features = tag_infos->at(jet_n).features(); - if (features.empty()) continue ; - // if at least one jet has features, run inferences - run_this_batch = true; - // jet and other global features - db_tensor_filler(input_tensors.at(kGlobal).second, jet_bn, features); - - // c_pf candidates - auto max_c_pf_n = std::min(features.c_pf_features.size(), - (std::size_t) input_sizes.at(kChargedCandidates).dim_size(1)); - 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); - c_pf_reduced_tensor_filler(input_tensors.at(kChargedCandidates).second, - jet_bn, c_pf_n, c_pf_features); - } - - // sv candidates - auto max_sv_n = std::min(features.sv_features.size(), - (std::size_t) input_sizes.at(kVertices).dim_size(1)); - for (std::size_t sv_n=0; sv_n < max_sv_n; sv_n++) { - const auto & sv_features = features.sv_features.at(sv_n); - sv_reduced_tensor_filler(input_tensors.at(kVertices).second, - jet_bn, sv_n, sv_features); - } - - } - // run the session - std::vector outputs; - if (run_this_batch){ - tensorflow::run(session_, input_tensors, output_names_, &outputs); - } - // set output values for flavour probs - for (std::size_t jet_bn=0; jet_bn < (std::size_t) n_batch_jets; jet_bn++) { - - // global jet index (jet_bn is the jet batch index) - std::size_t jet_n = batch_n*n_batch_jets + jet_bn; - - const auto & features = tag_infos->at(jet_n).features(); - const auto & jet_ref = tag_infos->at(jet_n).jet(); - for (std::size_t flav_n=0; flav_n < flav_pairs_.size(); flav_n++) { - const auto & flav_pair = flav_pairs_.at(flav_n); - float o_sum = 0.; - if (!features.empty()) { - for (const unsigned int & ind : flav_pair.second) { - o_sum += outputs.at(kJetFlavour).matrix()(jet_bn, ind); - } - (*(output_tags.at(flav_n)))[jet_ref] = o_sum; - } else { - (*(output_tags.at(flav_n)))[jet_ref] = -1.; - } - } - } - } - - for (std::size_t i=0; i < flav_pairs_.size(); i++) { - iEvent.put(std::move(output_tags[i]), flav_pairs_.at(i).first); - } -} - -//define this as a plug-in -DEFINE_FWK_MODULE(DeepDoubleXTFJetTagsProducer); diff --git a/RecoBTag/TensorFlow/plugins/DeepFlavourTFJetTagsProducer.cc b/RecoBTag/TensorFlow/plugins/DeepFlavourTFJetTagsProducer.cc deleted file mode 100644 index d6327992f38ac..0000000000000 --- a/RecoBTag/TensorFlow/plugins/DeepFlavourTFJetTagsProducer.cc +++ /dev/null @@ -1,311 +0,0 @@ - -#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 "PhysicsTools/TensorFlow/interface/TensorFlow.h" - -#include "RecoBTag/TensorFlow/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 -// by multiple session instances which handle the initialization of variables related to the graph. -// Following this approach in CMSSW, a graph should be stored in a GlobalCache which can be accessed -// by sessions owned by multiple stream module copies. Instead of using only the plain graph, we -// make use of a cache struct that can be extended in the future if nedded. In addition, the graph -// is protected via std::atomic, which should not affect the performance as it is only accessed in -// the module constructor and not in the actual produce loop. -struct DeepFlavourTFCache { - DeepFlavourTFCache() : graphDef(nullptr) { - } - - std::atomic graphDef; -}; - -class DeepFlavourTFJetTagsProducer : public edm::stream::EDProducer> { - - public: - explicit DeepFlavourTFJetTagsProducer(const edm::ParameterSet&, const DeepFlavourTFCache*); - ~DeepFlavourTFJetTagsProducer() override; - - static void fillDescriptions(edm::ConfigurationDescriptions&); - - static std::unique_ptr initializeGlobalCache(const edm::ParameterSet&); - static void globalEndJob(const DeepFlavourTFCache*); - - enum InputIndexes { - kGlobal = 0, - kChargedCandidates = 1, - kNeutralCandidates = 2, - kVertices = 3, - kJetPt = 4 - }; - - enum OutputIndexes { - kJetFlavour = 0, - kRegJetPt = 1, - }; - - private: - typedef std::vector TagInfoCollection; - typedef reco::JetTagCollection JetTagCollection; - - void beginStream(edm::StreamID) override {} - void produce(edm::Event&, const edm::EventSetup&) override; - void endStream() override {} - - const edm::EDGetTokenT< TagInfoCollection > src_; - std::vector>> flav_pairs_; - std::vector input_names_; - std::vector output_names_; - std::vector lp_names_; - - // session for TF evaluation - tensorflow::Session* session_; - // vector of learning phase tensors, i.e., boolean scalar tensors pointing to false - std::vector lp_tensors_; - // flag to evaluate model batch or jet by jet - bool batch_eval_; -}; - -DeepFlavourTFJetTagsProducer::DeepFlavourTFJetTagsProducer(const edm::ParameterSet& iConfig, - const DeepFlavourTFCache* cache) : - src_(consumes(iConfig.getParameter("src"))), - input_names_(iConfig.getParameter>("input_names")), - output_names_(iConfig.getParameter>("output_names")), - lp_names_(iConfig.getParameter>("lp_names")), - session_(nullptr), - batch_eval_(iConfig.getParameter("batch_eval")) -{ - // 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->graphDef, sessionOptions); - - // get output names from flav_table - const auto & flav_pset = iConfig.getParameter("flav_table"); - for (const auto flav_pair : flav_pset.tbl()) { - const auto & flav_name = flav_pair.first; - flav_pairs_.emplace_back(flav_name, - flav_pset.getParameter>(flav_name)); - } - - for (const auto & flav_pair : flav_pairs_) { - produces(flav_pair.first); - } - - // flag inputs (required because of batch norm) - // names for the learing phase placeholders (to init and set as false) - for (size_t i = 0; i < lp_names_.size(); i++) { - // create a bool tensor, set its value to false and store it - tensorflow::Tensor t(tensorflow::DT_BOOL, {}); - t.scalar()() = false; - lp_tensors_.push_back(t); - } -} - -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("graph_path", - edm::FileInPath("RecoBTag/Combined/data/DeepFlavourV03_10X_training/constant_graph.pb")); - desc.add>("lp_names", - { "cpf_input_batchnorm/keras_learning_phase" }); - desc.add>("output_names", - { "ID_pred/Softmax", "regression_pred/BiasAdd" }); - { - edm::ParameterSetDescription psd0; - psd0.add>("probb", {0}); - psd0.add>("probbb", {1}); - psd0.add>("problepb", {2}); - psd0.add>("probc", {3}); - psd0.add>("probuds", {4}); - psd0.add>("probg", {5}); - desc.add("flav_table", psd0); - } - - desc.add("batch_eval", false); - - desc.add("nThreads", 1); - desc.add("singleThreadPool", "no_threads"); - - descriptions.add("pfDeepFlavourJetTags", desc); -} - -std::unique_ptr DeepFlavourTFJetTagsProducer::initializeGlobalCache( - const edm::ParameterSet& iConfig) -{ - // set the tensorflow log level to error - tensorflow::setLogging("3"); - - // get the pb file - std::string pbFile = iConfig.getParameter("graph_path").fullPath(); - - // load the graph def and save it in the cache - DeepFlavourTFCache* cache = new DeepFlavourTFCache(); - cache->graphDef = tensorflow::loadGraphDef(pbFile); - - return std::unique_ptr(cache); -} - -void DeepFlavourTFJetTagsProducer::globalEndJob(const DeepFlavourTFCache* cache) -{ - if (cache->graphDef != nullptr) { - delete cache->graphDef; - } -} - -void DeepFlavourTFJetTagsProducer::produce(edm::Event& iEvent, const edm::EventSetup& iSetup) -{ - - edm::Handle tag_infos; - iEvent.getByToken(src_, tag_infos); - - // initialize output collection - std::vector> output_tags; - for (std::size_t i=0; i < flav_pairs_.size(); i++) { - if (!tag_infos->empty()) { - auto jet_ref = tag_infos->begin()->jet(); - output_tags.emplace_back(std::make_unique( - edm::makeRefToBaseProdFrom(jet_ref, iEvent))); - } else { - output_tags.emplace_back(std::make_unique()); - } - } - - const int64_t n_jets = tag_infos->size(); - // either all jets or one per batch for the time being - const int64_t n_batch_jets = batch_eval_ ? n_jets : 1; - - std::vector input_sizes { - {n_batch_jets, 15}, // input_1 - global jet features - {n_batch_jets, 25, 16}, // input_2 - charged pf - {n_batch_jets, 25, 6}, // input_3 - neutral pf - {n_batch_jets, 4, 12}, // input_4 - vertices - {n_batch_jets, 1} // input_5 - jet pt for reg - }; - - // create a list of named tensors, i.e. a vector of (string, Tensor) pairs, with proper size to - // prevent element copying that would occur via push_back's - // the default Tensor constructor creates a scalar so this should be fine w.r.t. to memory - tensorflow::NamedTensorList input_tensors; - input_tensors.resize(input_sizes.size() + lp_tensors_.size()); - - // add actual input tensors that hold physics information - for (std::size_t i=0; i < input_sizes.size(); i++) { - input_tensors[i] = tensorflow::NamedTensor( - input_names_[i], tensorflow::Tensor(tensorflow::DT_FLOAT, input_sizes.at(i))); - } - - // add learning-phase tensors behind them - for (std::size_t i=0; i < lp_tensors_.size(); i++) { - input_tensors[input_sizes.size() + i] = tensorflow::NamedTensor(lp_names_[i], lp_tensors_[i]); - } - - std::size_t n_batches = n_jets/n_batch_jets; // either 1 or n_jets - for (std::size_t batch_n=0; batch_n < n_batches; batch_n++) { - - // tensors have to be zeroed before filling per batch - for (std::size_t i=0; i < input_sizes.size(); i++) { - input_tensors[i].second.flat().setZero(); - } - - // fill values of the input tensors - for (std::size_t jet_bn=0; jet_bn < (std::size_t) n_batch_jets; jet_bn++) { - - // global jet index (jet_bn is the jet batch index) - std::size_t jet_n = batch_n*n_batch_jets + jet_bn; - - // jet and other global features - const auto & features = tag_infos->at(jet_n).features(); - jet_tensor_filler(input_tensors.at(kGlobal).second, jet_bn, features); - - // c_pf candidates - auto max_c_pf_n = std::min(features.c_pf_features.size(), - (std::size_t) input_sizes.at(kChargedCandidates).dim_size(1)); - 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); - c_pf_tensor_filler(input_tensors.at(kChargedCandidates).second, - jet_bn, c_pf_n, c_pf_features); - } - - // n_pf candidates - auto max_n_pf_n = std::min(features.n_pf_features.size(), - (std::size_t) input_sizes.at(kNeutralCandidates).dim_size(1)); - 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); - n_pf_tensor_filler(input_tensors.at(kNeutralCandidates).second, - jet_bn, n_pf_n, n_pf_features); - } - - // sv candidates - auto max_sv_n = std::min(features.sv_features.size(), - (std::size_t) input_sizes.at(kVertices).dim_size(1)); - for (std::size_t sv_n=0; sv_n < max_sv_n; sv_n++) { - const auto & sv_features = features.sv_features.at(sv_n); - sv_tensor_filler(input_tensors.at(kVertices).second, - jet_bn, sv_n, sv_features); - } - - // last input: jet pt - input_tensors.at(kJetPt).second.matrix()(jet_bn, 0) = features.jet_features.pt; - } - - // run the session - std::vector outputs; - tensorflow::run(session_, input_tensors, output_names_, &outputs); - - // set output values for flavour probs - for (std::size_t jet_bn=0; jet_bn < (std::size_t) n_batch_jets; jet_bn++) { - - // global jet index (jet_bn is the jet batch index) - std::size_t jet_n = batch_n*n_batch_jets + jet_bn; - - const auto & jet_ref = tag_infos->at(jet_n).jet(); - for (std::size_t flav_n=0; flav_n < flav_pairs_.size(); flav_n++) { - const auto & flav_pair = flav_pairs_.at(flav_n); - float o_sum = 0.; - for (const unsigned int & ind : flav_pair.second) { - o_sum += outputs.at(kJetFlavour).matrix()(jet_bn, ind); - } - (*(output_tags.at(flav_n)))[jet_ref] = o_sum; - } - } - } - - for (std::size_t i=0; i < flav_pairs_.size(); i++) { - iEvent.put(std::move(output_tags[i]), flav_pairs_.at(i).first); - } - -} - -//define this as a plug-in -DEFINE_FWK_MODULE(DeepFlavourTFJetTagsProducer); diff --git a/RecoBTag/TensorFlow/python/pfDeepDoubleX_cff.py b/RecoBTag/TensorFlow/python/pfDeepDoubleX_cff.py deleted file mode 100644 index 32331fc050bd2..0000000000000 --- a/RecoBTag/TensorFlow/python/pfDeepDoubleX_cff.py +++ /dev/null @@ -1,6 +0,0 @@ -from RecoBTag.TensorFlow.pfDeepDoubleBvLJetTags_cfi import pfDeepDoubleBvLJetTags -from RecoBTag.TensorFlow.pfDeepDoubleCvBJetTags_cfi import pfDeepDoubleCvBJetTags -from RecoBTag.TensorFlow.pfDeepDoubleCvLJetTags_cfi import pfDeepDoubleCvLJetTags - -from RecoBTag.TensorFlow.pfMassIndependentDeepDoubleXJetTags_cff import * -