diff --git a/RecoTauTag/RecoTau/interface/DeepTauBase.h b/RecoTauTag/RecoTau/interface/DeepTauBase.h index 031ebfd90021a..11b79a85f6a3d 100644 --- a/RecoTauTag/RecoTau/interface/DeepTauBase.h +++ b/RecoTauTag/RecoTau/interface/DeepTauBase.h @@ -14,6 +14,7 @@ #include "FWCore/Framework/interface/stream/EDProducer.h" #include "FWCore/ParameterSet/interface/ParameterSet.h" #include "PhysicsTools/TensorFlow/interface/TensorFlow.h" +#include "tensorflow/core/util/memmapped_file_system.h" #include "DataFormats/PatCandidates/interface/Electron.h" #include "DataFormats/PatCandidates/interface/Muon.h" #include "DataFormats/PatCandidates/interface/Tau.h" @@ -22,10 +23,39 @@ #include "RecoTauTag/RecoTau/interface/PFRecoTauClusterVariables.h" #include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h" #include "FWCore/ParameterSet/interface/ParameterSetDescription.h" +#include namespace deep_tau { -class DeepTauBase : public edm::stream::EDProducer<> { +class TauWPThreshold { +public: + explicit TauWPThreshold(const std::string& cut_str); + double operator()(const pat::Tau& tau) const; + +private: + std::unique_ptr fn_; + double value_; +}; + +class DeepTauCache { +public: + using GraphPtr = std::shared_ptr; + + DeepTauCache(const std::string& graph_name, bool mem_mapped); + ~DeepTauCache(); + + // A Session allows concurrent calls to Run(), though a Session must + // be created / extended by a single thread. + tensorflow::Session& getSession() const { return *session_; } + const tensorflow::GraphDef& getGraph() const { return *graph_; } + +private: + GraphPtr graph_; + tensorflow::Session* session_; + std::unique_ptr memmappedEnv_; +}; + +class DeepTauBase : public edm::stream::EDProducer> { public: using TauType = pat::Tau; using TauDiscriminator = pat::PATTauDiscriminator; @@ -35,17 +65,15 @@ class DeepTauBase : public edm::stream::EDProducer<> { using ElectronCollection = pat::ElectronCollection; using MuonCollection = pat::MuonCollection; using LorentzVectorXYZ = ROOT::Math::LorentzVector>; - using GraphPtr = std::shared_ptr; - using Cutter = StringObjectFunction; + using Cutter = TauWPThreshold; using CutterPtr = std::unique_ptr; using WPMap = std::map; - struct Output { using ResultMap = std::map>; - std::vector num, den; + std::vector num_, den_; - Output(const std::vector& _num, const std::vector& _den) : num(_num), den(_den) {} + Output(const std::vector& num, const std::vector& den) : num_(num), den_(den) {} ResultMap get_value(const edm::Handle& taus, const tensorflow::Tensor& pred, const WPMap& working_points) const; @@ -54,27 +82,25 @@ class DeepTauBase : public edm::stream::EDProducer<> { using OutputCollection = std::map; - DeepTauBase(const edm::ParameterSet& cfg, const OutputCollection& outputs); - virtual ~DeepTauBase(); + DeepTauBase(const edm::ParameterSet& cfg, const OutputCollection& outputs, const DeepTauCache* cache); + virtual ~DeepTauBase() {} virtual void produce(edm::Event& event, const edm::EventSetup& es) override; + static std::unique_ptr initializeGlobalCache(const edm::ParameterSet& cfg); + static void globalEndJob(const DeepTauCache* cache){ } private: - virtual tensorflow::Tensor GetPredictions(edm::Event& event, const edm::EventSetup& es, + virtual tensorflow::Tensor getPredictions(edm::Event& event, const edm::EventSetup& es, edm::Handle taus) = 0; - virtual void CreateOutputs(edm::Event& event, const tensorflow::Tensor& pred, edm::Handle taus); + virtual void createOutputs(edm::Event& event, const tensorflow::Tensor& pred, edm::Handle taus); protected: - edm::EDGetTokenT taus_token; - std::string graphName; - GraphPtr graph; - tensorflow::Session* session; - std::map working_points; - OutputCollection outputs; + edm::EDGetTokenT tausToken_; + std::map workingPoints_; + OutputCollection outputs_; + const DeepTauCache* cache_; }; } // namespace deep_tau - - #endif diff --git a/RecoTauTag/RecoTau/plugins/DPFIsolation.cc b/RecoTauTag/RecoTau/plugins/DPFIsolation.cc index 8676abbf7e5de..99da6a6c40663 100644 --- a/RecoTauTag/RecoTau/plugins/DPFIsolation.cc +++ b/RecoTauTag/RecoTau/plugins/DPFIsolation.cc @@ -12,29 +12,24 @@ namespace { inline int getPFCandidateIndex(const edm::Handle& pfcands, const reco::CandidatePtr& cptr) { - unsigned int pfInd = -1; for(unsigned int i = 0; i < pfcands->size(); ++i) { - pfInd++; - if(reco::CandidatePtr(pfcands,i) == cptr) { - pfInd = i; - break; - } + if(reco::CandidatePtr(pfcands,i) == cptr) + return i; } - return pfInd; + return -1; } } // anonymous namespace - class DPFIsolation : public deep_tau::DeepTauBase { public: - static OutputCollection& GetOutputs() + static const OutputCollection& GetOutputs() { - static size_t tau_index = 0; - static OutputCollection outputs = { { "VSall", Output({tau_index}, {}) } }; - return outputs; + const size_t tau_index = 0; + static const OutputCollection outputs_ = { { "VSall", Output({tau_index}, {}) } }; + return outputs_; }; - static unsigned GetNumberOfParticles(unsigned graphVersion) + static unsigned getNumberOfParticles(unsigned graphVersion) { static const std::map nparticles { { 0, 60 }, { 1, 36 } }; return nparticles.at(graphVersion); @@ -52,7 +47,9 @@ class DPFIsolation : public deep_tau::DeepTauBase { desc.add("pfcands", edm::InputTag("packedPFCandidates")); desc.add("taus", edm::InputTag("slimmedTaus")); desc.add("vertices", edm::InputTag("offlineSlimmedPrimaryVertices")); - desc.add("graph_file", "RecoTauTag/TrainingFiles/data/DPFTauId/DPFIsolation_2017v0.pb"); + desc.add("graph_file", "RecoTauTag/TrainingFiles/data/DPFTauId/DPFIsolation_2017v0_quantized.pb"); + desc.add("version", 0); + desc.add("mem_mapped", false); edm::ParameterSetDescription descWP; descWP.add("VVVLoose", "0"); @@ -68,21 +65,24 @@ class DPFIsolation : public deep_tau::DeepTauBase { descriptions.add("DPFTau2016v0", desc); } - explicit DPFIsolation(const edm::ParameterSet& cfg) : - DeepTauBase(cfg, GetOutputs()), + explicit DPFIsolation(const edm::ParameterSet& cfg,const deep_tau::DeepTauCache* cache) : + DeepTauBase(cfg, GetOutputs(), cache), pfcand_token(consumes(cfg.getParameter("pfcands"))), - vtx_token(consumes(cfg.getParameter("vertices"))) + vtx_token(consumes(cfg.getParameter("vertices"))), + graphVersion(cfg.getParameter("version")) { - if(graphName.find("v0.pb") != std::string::npos) - graphVersion = 0; - else if(graphName.find("v1.pb") != std::string::npos) - graphVersion = 1; - else - throw cms::Exception("DPFIsolation") << "unknown version of the graph file."; + const auto& shape = cache_->getGraph().node(0).attr().at("shape").shape(); + + if(!(graphVersion == 1 || graphVersion == 0 )) + throw cms::Exception("DPFIsolation") << "unknown version of the graph_ file."; + + if(!(shape.dim(1).size() == getNumberOfParticles(graphVersion) && shape.dim(2).size() == GetNumberOfFeatures(graphVersion))) + throw cms::Exception("DPFIsolation") << "number of inputs does not match the expected inputs for the given version"; + } private: - virtual tensorflow::Tensor GetPredictions(edm::Event& event, const edm::EventSetup& es, + virtual tensorflow::Tensor getPredictions(edm::Event& event, const edm::EventSetup& es, edm::Handle taus) override { edm::Handle pfcands; @@ -92,11 +92,11 @@ class DPFIsolation : public deep_tau::DeepTauBase { event.getByToken(vtx_token, vertices); tensorflow::Tensor tensor(tensorflow::DT_FLOAT, {1, - static_cast(GetNumberOfParticles(graphVersion)), static_cast(GetNumberOfFeatures(graphVersion))}); + static_cast(getNumberOfParticles(graphVersion)), static_cast(GetNumberOfFeatures(graphVersion))}); tensorflow::Tensor predictions(tensorflow::DT_FLOAT, { static_cast(taus->size()), 1}); - std::vector outputs; + std::vector outputs_; float pfCandPt, pfCandPz, pfCandPtRel, pfCandPzRel, pfCandDr, pfCandDEta, pfCandDPhi, pfCandEta, pfCandDz, pfCandDzErr, pfCandD0, pfCandD0D0, pfCandD0Dz, pfCandD0Dphi, pfCandPuppiWeight, @@ -109,10 +109,35 @@ class DPFIsolation : public deep_tau::DeepTauBase { bool pfCandIsBarrel; + // These variables define ranges further used for standardization + static constexpr float pfCandPt_max = 500.f; + static constexpr float pfCandPz_max = 1000.f; + static constexpr float pfCandPtRel_max = 1.f; + static constexpr float pfCandPzRel_max = 100.f; + static constexpr float pfCandPtRelPtRel_max = 1.f; + static constexpr float pfCandD0_max = 5.f; + static constexpr float pfCandDz_max = 5.f; + static constexpr float pfCandDVx_y_z_1_max = 0.05f; + static constexpr float pfCandD_1_max = 0.1f; + static constexpr float pfCandD0_z_Err_max = 1.f; + static constexpr float pfCandDzSig_max = 3.f; + static constexpr float pfCandD0Sig_max = 1.f; + static constexpr float pfCandDr_max = 0.5f; + static constexpr float pfCandEta_max = 2.75f; + static constexpr float pfCandDEta_max = 0.5f; + static constexpr float pfCandDPhi_max = 0.5f; + static constexpr float pfCandPixHits_max = 7.f; + static constexpr float pfCandHits_max = 30.f; + for(size_t tau_index = 0; tau_index < taus->size(); tau_index++) { pat::Tau tau = taus->at(tau_index); bool isGoodTau = false; - if(tau.pt() >= 30 && std::abs(tau.eta()) < 2.3 && tau.isTauIDAvailable("againstMuonLoose3") && + const float lepRecoPt = tau.pt(); + const float lepRecoPz = std::abs(tau.pz()); + const float lepRecoEta = tau.eta(); + const float lepRecoPhi = tau.phi(); + + if(lepRecoPt >= 30 && std::abs(lepRecoEta) < 2.3 && tau.isTauIDAvailable("againstMuonLoose3") && tau.isTauIDAvailable("againstElectronVLooseMVA6")) { isGoodTau = (tau.tauID("againstElectronVLooseMVA6") && tau.tauID("againstMuonLoose3") ); } @@ -124,20 +149,17 @@ class DPFIsolation : public deep_tau::DeepTauBase { std::vector signalCandidateInds; - for(auto c : tau.signalCands()) + for(const auto c : tau.signalCands()) signalCandidateInds.push_back(getPFCandidateIndex(pfcands,c)); - float lepRecoPt = tau.pt(); - float lepRecoPz = std::abs(tau.pz()); - // Use of setZero results in warnings in eigen library during compilation. //tensor.flat().setZero(); - const unsigned n_inputs = GetNumberOfParticles(graphVersion) * GetNumberOfFeatures(graphVersion); + const unsigned n_inputs = getNumberOfParticles(graphVersion) * GetNumberOfFeatures(graphVersion); for(unsigned input_idx = 0; input_idx < n_inputs; ++input_idx) tensor.flat()(input_idx) = 0; unsigned int iPF = 0; - const unsigned max_iPF = GetNumberOfParticles(graphVersion); + const unsigned max_iPF = getNumberOfParticles(graphVersion); std::vector sorted_inds(pfcands->size()); std::size_t n = 0; @@ -153,19 +175,17 @@ class DPFIsolation : public deep_tau::DeepTauBase { if (p.pt() < 0.5) continue; if (p.fromPV() < 0) continue; if (deltaR_tau_p > 0.5) continue; - - if (p.fromPV() < 1 && p.charge() != 0) continue; pfCandPt = p.pt(); pfCandPtRel = p.pt()/lepRecoPt; pfCandDr = deltaR_tau_p; - pfCandDEta = std::abs(tau.eta() - p.eta()); - pfCandDPhi = std::abs(deltaPhi(tau.phi(), p.phi())); + pfCandDEta = std::abs(lepRecoEta - p.eta()); + pfCandDPhi = std::abs(deltaPhi(lepRecoPhi, p.phi())); pfCandEta = p.eta(); pfCandIsBarrel = (std::abs(pfCandEta) < 1.4); pfCandPz = std::abs(std::sinh(pfCandEta)*pfCandPt); - pfCandPzRel = std::abs(std::sinh(pfCandEta)*pfCandPt)/lepRecoPz; + pfCandPzRel = pfCandPz/lepRecoPz; pfCandPdgID = std::abs(p.pdgId()); pfCandCharge = p.charge(); pfCandDVx_1 = p.vx() - pvx; @@ -215,59 +235,52 @@ class DPFIsolation : public deep_tau::DeepTauBase { pfCandTauIndMatch = pfCandTauIndMatch_temp; pfCandPtRelPtRel = pfCandPtRel*pfCandPtRel; - if (pfCandPt > 500) pfCandPt = 500.; - pfCandPt = pfCandPt/500.; - - if (pfCandPz > 1000) pfCandPz = 1000.; - pfCandPz = pfCandPz/1000.; - - if ((pfCandPtRel) > 1 ) pfCandPtRel = 1.; - if ((pfCandPzRel) > 100 ) pfCandPzRel = 100.; - pfCandPzRel = pfCandPzRel/100.; - pfCandDr = pfCandDr/.5; - pfCandEta = pfCandEta/2.75; - pfCandDEta = pfCandDEta/.5; - pfCandDPhi = pfCandDPhi/.5; - pfCandPixHits = pfCandPixHits/7.; - pfCandHits = pfCandHits/30.; - - if (pfCandPtRelPtRel > 1) pfCandPtRelPtRel = 1; - pfCandPtRelPtRel = pfCandPtRelPtRel; - - if (pfCandD0 > 5.) pfCandD0 = 5.; - if (pfCandD0 < -5.) pfCandD0 = -5.; - pfCandD0 = pfCandD0/5.; - - if (pfCandDz > 5.) pfCandDz = 5.; - if (pfCandDz < -5.) pfCandDz = -5.; - pfCandDz = pfCandDz/5.; - - if (pfCandD0Err > 1.) pfCandD0Err = 1.; - if (pfCandDzErr > 1.) pfCandDzErr = 1.; - if (pfCandDzSig > 3) pfCandDzSig = 3.; - pfCandDzSig = pfCandDzSig/3.; - - if (pfCandD0Sig > 1) pfCandD0Sig = 1.; + pfCandPt = std::min(pfCandPt, pfCandPt_max); + pfCandPt = pfCandPt/pfCandPt_max; + + pfCandPz = std::min(pfCandPz, pfCandPz_max); + pfCandPz = pfCandPz/pfCandPz_max; + + pfCandPtRel = std::min(pfCandPtRel, pfCandPtRel_max); + pfCandPzRel = std::min(pfCandPzRel, pfCandPzRel_max); + pfCandPzRel = pfCandPzRel/pfCandPzRel_max; + pfCandDr = pfCandDr/pfCandDr_max; + pfCandEta = pfCandEta/pfCandEta_max; + pfCandDEta = pfCandDEta/pfCandDEta_max; + pfCandDPhi = pfCandDPhi/pfCandDPhi_max; + pfCandPixHits = pfCandPixHits/pfCandPixHits_max; + pfCandHits = pfCandHits/pfCandHits_max; + + pfCandPtRelPtRel = std::min(pfCandPtRelPtRel, pfCandPtRelPtRel_max); + + pfCandD0 = std::clamp(pfCandD0, -pfCandD0_max, pfCandD0_max); + pfCandD0 = pfCandD0/pfCandD0_max; + + pfCandDz = std::clamp(pfCandDz, -pfCandDz_max, pfCandDz_max); + pfCandDz = pfCandDz/pfCandDz_max; + + pfCandD0Err = std::min(pfCandD0Err, pfCandD0_z_Err_max); + pfCandDzErr = std::min(pfCandDzErr, pfCandD0_z_Err_max); + pfCandDzSig = std::min(pfCandDzSig, pfCandDzSig_max); + pfCandDzSig = pfCandDzSig/pfCandDzSig_max; + + pfCandD0Sig = std::min(pfCandD0Sig, pfCandD0Sig_max); pfCandD0D0 = pfCandD0*pfCandD0; pfCandDzDz = pfCandDz*pfCandDz; pfCandD0Dz = pfCandD0*pfCandDz; pfCandD0Dphi = pfCandD0*pfCandDPhi; - if (pfCandDVx_1 > .05) pfCandDVx_1 = .05; - if (pfCandDVx_1 < -.05) pfCandDVx_1 = -.05; - pfCandDVx_1 = pfCandDVx_1/.05; + pfCandDVx_1 = std::clamp(pfCandDVx_1, -pfCandDVx_y_z_1_max, pfCandDVx_y_z_1_max); + pfCandDVx_1 = pfCandDVx_1/pfCandDVx_y_z_1_max; - if (pfCandDVy_1 > 0.05) pfCandDVy_1 = 0.05; - if (pfCandDVy_1 < -0.05) pfCandDVy_1 = -0.05; - pfCandDVy_1 = pfCandDVy_1/0.05; + pfCandDVy_1 = std::clamp(pfCandDVy_1, -pfCandDVx_y_z_1_max, pfCandDVx_y_z_1_max); + pfCandDVy_1 = pfCandDVy_1/pfCandDVx_y_z_1_max; - if (pfCandDVz_1 > 0.05) pfCandDVz_1 = 0.05; - if (pfCandDVz_1 < -0.05) pfCandDVz_1= -0.05; - pfCandDVz_1 = pfCandDVz_1/0.05; + pfCandDVz_1 = std::clamp(pfCandDVz_1, -pfCandDVx_y_z_1_max, pfCandDVx_y_z_1_max); + pfCandDVz_1 = pfCandDVz_1/pfCandDVx_y_z_1_max; - if (pfCandD_1 > 0.1) pfCandD_1 = 0.1; - if (pfCandD_1 < -0.1) pfCandD_1 = -0.1; - pfCandD_1 = pfCandD_1/.1; + pfCandD_1 = std::clamp(pfCandD_1, -pfCandD_1_max, pfCandD_1_max); + pfCandD_1 = pfCandD_1/ pfCandD_1_max; if (graphVersion == 0) { tensor.tensor()( 0, 60-1-iPF, 0) = pfCandPt; @@ -372,12 +385,10 @@ class DPFIsolation : public deep_tau::DeepTauBase { tensor.tensor()( 0, 36-1-iPF, 49) = pfCandPdgID==211; tensor.tensor()( 0, 36-1-iPF, 50) = pfCandTauIndMatch; } - iPF++; } - - tensorflow::Status status = session->Run( { {"input_1", tensor} }, {"output_node0"}, {}, &outputs); - predictions.matrix()(tau_index, 0) = outputs[0].flat()(0); + tensorflow::run(&(cache_->getSession()), { { "input_1", tensor } }, { "output_node0" }, {}, &outputs_); + predictions.matrix()(tau_index, 0) = outputs_[0].flat()(0); } return predictions; } diff --git a/RecoTauTag/RecoTau/plugins/DeepTauId.cc b/RecoTauTag/RecoTau/plugins/DeepTauId.cc index 178f2889c80f0..bd16f901c19f2 100644 --- a/RecoTauTag/RecoTau/plugins/DeepTauId.cc +++ b/RecoTauTag/RecoTau/plugins/DeepTauId.cc @@ -62,6 +62,8 @@ struct dnn_inputs_2017v1 { isolationGammaCands_nTotal, NumberOfInputs }; + + static constexpr int NumberOfOutputs = 4; }; template @@ -98,7 +100,7 @@ struct MuonHitMatch { n_hits[MuonSubdetId::RPC].assign(n_muon_stations, 0); } - void AddMatchedMuon(const pat::Muon& muon, const pat::Tau& tau) + void addMatchedMuon(const pat::Muon& muon, const pat::Tau& tau) { static constexpr int n_stations = 4; @@ -117,8 +119,7 @@ struct MuonHitMatch { if(muon.outerTrack().isNonnull()) { const auto& hit_pattern = muon.outerTrack()->hitPattern(); - for(int hit_index = 0; hit_index < hit_pattern.numberOfAllHits(reco::HitPattern::TRACK_HITS); - ++hit_index) { + for(int hit_index = 0; hit_index < hit_pattern.numberOfAllHits(reco::HitPattern::TRACK_HITS); ++hit_index) { auto hit_id = hit_pattern.getHitPattern(reco::HitPattern::TRACK_HITS, hit_index); if(hit_id == 0) break; if(hit_pattern.muonHitFilter(hit_id) && (hit_pattern.getHitType(hit_id) == TrackingRecHit::valid @@ -141,7 +142,7 @@ struct MuonHitMatch { } } - static std::vector FindMatchedMuons(const pat::Tau& tau, const pat::MuonCollection& muons, + static std::vector findMatchedMuons(const pat::Tau& tau, const pat::MuonCollection& muons, double deltaR, double minPt) { const reco::Muon* hadr_cand_muon = nullptr; @@ -159,9 +160,8 @@ struct MuonHitMatch { return matched_muons; } - template - void FillTensor(const TensorElemGet& get, const pat::Tau& tau, float default_value) const + void fillTensor(const TensorElemGet& get, const pat::Tau& tau, float default_value) const { get(dnn::n_matched_muons) = n_muons; get(dnn::muon_pt) = best_matched_muon != nullptr ? best_matched_muon->p4().pt() : default_value; @@ -186,12 +186,12 @@ struct MuonHitMatch { get(dnn::muon_n_hits_RPC_2) = n_hits.at(MuonSubdetId::RPC).at(1); get(dnn::muon_n_hits_RPC_3) = n_hits.at(MuonSubdetId::RPC).at(2); get(dnn::muon_n_hits_RPC_4) = n_hits.at(MuonSubdetId::RPC).at(3); - get(dnn::muon_n_stations_with_matches_03) = CountMuonStationsWithMatches(0, 3); - get(dnn::muon_n_stations_with_hits_23) = CountMuonStationsWithHits(2, 3); + get(dnn::muon_n_stations_with_matches_03) = countMuonStationsWithMatches(0, 3); + get(dnn::muon_n_stations_with_hits_23) = countMuonStationsWithHits(2, 3); } private: - unsigned CountMuonStationsWithMatches(size_t first_station, size_t last_station) const + unsigned countMuonStationsWithMatches(size_t first_station, size_t last_station) const { static const std::map> masks = { { MuonSubdetId::DT, { false, false, false, false } }, @@ -207,7 +207,7 @@ struct MuonHitMatch { return cnt; } - unsigned CountMuonStationsWithHits(size_t first_station, size_t last_station) const + unsigned countMuonStationsWithHits(size_t first_station, size_t last_station) const { static const std::map> masks = { { MuonSubdetId::DT, { false, false, false, false } }, @@ -235,12 +235,12 @@ class DeepTauId : public deep_tau::DeepTauBase { static const OutputCollection& GetOutputs() { static constexpr size_t e_index = 0, mu_index = 1, tau_index = 2, jet_index = 3; - static const OutputCollection outputs = { + static const OutputCollection outputs_ = { { "VSe", Output({tau_index}, {e_index, tau_index}) }, { "VSmu", Output({tau_index}, {mu_index, tau_index}) }, { "VSjet", Output({tau_index}, {jet_index, tau_index}) }, }; - return outputs; + return outputs_; } static void fillDescriptions(edm::ConfigurationDescriptions& descriptions) @@ -249,7 +249,8 @@ class DeepTauId : public deep_tau::DeepTauBase { desc.add("electrons", edm::InputTag("slimmedElectrons")); desc.add("muons", edm::InputTag("slimmedMuons")); desc.add("taus", edm::InputTag("slimmedTaus")); - desc.add("graph_file", "RecoTauTag/TrainingFiles/data/DeepTauId/deepTau_2017v1_20L1024N.pb"); + desc.add("graph_file", "RecoTauTag/TrainingFiles/data/DeepTauId/deepTau_2017v1_20L1024N_quantized.pb"); + desc.add("mem_mapped", false); edm::ParameterSetDescription descWP; descWP.add("VVVLoose", "0"); @@ -268,17 +269,31 @@ class DeepTauId : public deep_tau::DeepTauBase { } public: - explicit DeepTauId(const edm::ParameterSet& cfg) : - DeepTauBase(cfg, GetOutputs()), + explicit DeepTauId(const edm::ParameterSet& cfg, const deep_tau::DeepTauCache* cache) : + DeepTauBase(cfg, GetOutputs(), cache), electrons_token(consumes(cfg.getParameter("electrons"))), muons_token(consumes(cfg.getParameter("muons"))), - input_layer(graph->node(0).name()), - output_layer(graph->node(graph->node_size() - 1).name()) + input_layer(cache_->getGraph().node(0).name()), + output_layer(cache_->getGraph().node(cache_->getGraph().node_size() - 1).name()) + { + const auto& shape = cache_->getGraph().node(0).attr().at("shape").shape(); + if(shape.dim(1).size() != dnn_inputs_2017v1::NumberOfInputs) + throw cms::Exception("DeepTauId") << "number of inputs does not match the expected inputs for the given version"; + + } + + static std::unique_ptr initializeGlobalCache(const edm::ParameterSet& cfg) { + return DeepTauBase::initializeGlobalCache(cfg); + } + + static void globalEndJob(const deep_tau::DeepTauCache* cache_) + { + return DeepTauBase::globalEndJob(cache_); } private: - virtual tensorflow::Tensor GetPredictions(edm::Event& event, const edm::EventSetup& es, + virtual tensorflow::Tensor getPredictions(edm::Event& event, const edm::EventSetup& es, edm::Handle taus) override { edm::Handle electrons; @@ -287,36 +302,33 @@ class DeepTauId : public deep_tau::DeepTauBase { edm::Handle muons; event.getByToken(muons_token, muons); - const tensorflow::Tensor& inputs = CreateInputs(*taus, *electrons, *muons); - std::vector pred_vector; - tensorflow::run(session, { { input_layer, inputs } }, { output_layer }, &pred_vector); - return pred_vector.at(0); - } - - template - tensorflow::Tensor CreateInputs(const TauCollection& taus, const ElectronCollection& electrons, - const MuonCollection& muons) const - { - tensorflow::Tensor inputs(tensorflow::DT_FLOAT, { static_cast(taus.size()), dnn_inputs::NumberOfInputs}); - for(size_t tau_index = 0; tau_index < taus.size(); ++tau_index) - SetInputs(taus, tau_index, inputs, electrons, muons); - return inputs; + tensorflow::Tensor predictions(tensorflow::DT_FLOAT, { static_cast(taus->size()), + dnn_inputs_2017v1::NumberOfOutputs}); + for(size_t tau_index = 0; tau_index < taus->size(); ++tau_index) { + const tensorflow::Tensor& inputs = createInputs(taus->at(tau_index), *electrons, *muons); + std::vector pred_vector; + tensorflow::run(&(cache_->getSession()), { { input_layer, inputs } }, { output_layer }, &pred_vector); + for(int k = 0; k < dnn_inputs_2017v1::NumberOfOutputs; ++k) + predictions.matrix()(tau_index, k) = pred_vector[0].flat()(k); + } + return predictions; } template - void SetInputs(const TauCollection& taus, size_t tau_index, tensorflow::Tensor& inputs, - const ElectronCollection& electrons, const MuonCollection& muons) const + tensorflow::Tensor createInputs(const TauType& tau, const ElectronCollection& electrons, + const MuonCollection& muons) const { static constexpr bool check_all_set = false; - static constexpr float magic_number = -42; + static constexpr float default_value_for_set_check = -42; static const TauIdMVAAuxiliaries clusterVariables; - const auto& get = [&](int var_index) -> float& { return inputs.matrix()(tau_index, var_index); }; - const TauType& tau = taus.at(tau_index); + + tensorflow::Tensor inputs(tensorflow::DT_FLOAT, { 1, dnn_inputs_2017v1::NumberOfInputs}); + const auto& get = [&](int var_index) -> float& { return inputs.matrix()(0, var_index); }; auto leadChargedHadrCand = dynamic_cast(tau.leadChargedHadrCand().get()); if(check_all_set) { for(int var_index = 0; var_index < dnn::NumberOfInputs; ++var_index) { - get(var_index) = magic_number; + get(var_index) = default_value_for_set_check; } } @@ -352,18 +364,18 @@ class DeepTauId : public deep_tau::DeepTauBase { get(dnn::pt_weighted_dr_iso) = clusterVariables.tau_pt_weighted_dr_iso(tau, tau.decayMode()); get(dnn::leadingTrackNormChi2) = tau.leadingTrackNormChi2(); get(dnn::e_ratio) = clusterVariables.tau_Eratio(tau); - get(dnn::gj_angle_diff) = CalculateGottfriedJacksonAngleDifference(tau); + get(dnn::gj_angle_diff) = calculateGottfriedJacksonAngleDifference(tau); get(dnn::n_photons) = clusterVariables.tau_n_photons_total(tau); get(dnn::emFraction) = tau.emFraction_MVA(); get(dnn::has_gsf_track) = leadChargedHadrCand && std::abs(leadChargedHadrCand->pdgId()) == 11; - get(dnn::inside_ecal_crack) = IsInEcalCrack(tau.p4().Eta()); - auto gsf_ele = FindMatchedElectron(tau, electrons, 0.3); + get(dnn::inside_ecal_crack) = isInEcalCrack(tau.p4().Eta()); + auto gsf_ele = findMatchedElectron(tau, electrons, 0.3); get(dnn::gsf_ele_matched) = gsf_ele != nullptr; get(dnn::gsf_ele_pt) = gsf_ele != nullptr ? gsf_ele->p4().Pt() : default_value; get(dnn::gsf_ele_dEta) = gsf_ele != nullptr ? dEta(gsf_ele->p4(), tau.p4()) : default_value; get(dnn::gsf_ele_dPhi) = gsf_ele != nullptr ? dPhi(gsf_ele->p4(), tau.p4()) : default_value; get(dnn::gsf_ele_mass) = gsf_ele != nullptr ? gsf_ele->p4().mass() : default_value; - CalculateElectronClusterVars(gsf_ele, get(dnn::gsf_ele_Ee), get(dnn::gsf_ele_Egamma)); + calculateElectronClusterVars(gsf_ele, get(dnn::gsf_ele_Ee), get(dnn::gsf_ele_Egamma)); get(dnn::gsf_ele_Pin) = gsf_ele != nullptr ? gsf_ele->trackMomentumAtVtx().R() : default_value; get(dnn::gsf_ele_Pout) = gsf_ele != nullptr ? gsf_ele->trackMomentumOut().R() : default_value; get(dnn::gsf_ele_EtotOverPin) = get(dnn::gsf_ele_Pin) > 0 @@ -412,15 +424,15 @@ class DeepTauId : public deep_tau::DeepTauBase { MuonHitMatch muon_hit_match; if(tau.leadPFChargedHadrCand().isNonnull() && tau.leadPFChargedHadrCand()->muonRef().isNonnull()) - muon_hit_match.AddMatchedMuon(*tau.leadPFChargedHadrCand()->muonRef(), tau); + muon_hit_match.addMatchedMuon(*tau.leadPFChargedHadrCand()->muonRef(), tau); - auto matched_muons = muon_hit_match.FindMatchedMuons(tau, muons, 0.3, 5); + auto matched_muons = muon_hit_match.findMatchedMuons(tau, muons, 0.3, 5); for(auto muon : matched_muons) - muon_hit_match.AddMatchedMuon(*muon, tau); - muon_hit_match.FillTensor(get, tau, default_value); + muon_hit_match.addMatchedMuon(*muon, tau); + muon_hit_match.fillTensor(get, tau, default_value); LorentzVectorXYZ signalChargedHadrCands_sumIn, signalChargedHadrCands_sumOut; - ProcessSignalPFComponents(tau, tau.signalChargedHadrCands(), + processSignalPFComponents(tau, tau.signalChargedHadrCands(), signalChargedHadrCands_sumIn, signalChargedHadrCands_sumOut, get(dnn::signalChargedHadrCands_sum_innerSigCone_pt), get(dnn::signalChargedHadrCands_sum_innerSigCone_dEta), @@ -434,7 +446,7 @@ class DeepTauId : public deep_tau::DeepTauBase { get(dnn::signalChargedHadrCands_nTotal_outerSigCone)); LorentzVectorXYZ signalNeutrHadrCands_sumIn, signalNeutrHadrCands_sumOut; - ProcessSignalPFComponents(tau, tau.signalNeutrHadrCands(), + processSignalPFComponents(tau, tau.signalNeutrHadrCands(), signalNeutrHadrCands_sumIn, signalNeutrHadrCands_sumOut, get(dnn::signalNeutrHadrCands_sum_innerSigCone_pt), get(dnn::signalNeutrHadrCands_sum_innerSigCone_dEta), @@ -449,7 +461,7 @@ class DeepTauId : public deep_tau::DeepTauBase { LorentzVectorXYZ signalGammaCands_sumIn, signalGammaCands_sumOut; - ProcessSignalPFComponents(tau, tau.signalGammaCands(), + processSignalPFComponents(tau, tau.signalGammaCands(), signalGammaCands_sumIn, signalGammaCands_sumOut, get(dnn::signalGammaCands_sum_innerSigCone_pt), get(dnn::signalGammaCands_sum_innerSigCone_dEta), @@ -463,7 +475,7 @@ class DeepTauId : public deep_tau::DeepTauBase { get(dnn::signalGammaCands_nTotal_outerSigCone)); LorentzVectorXYZ isolationChargedHadrCands_sum; - ProcessIsolationPFComponents(tau, tau.isolationChargedHadrCands(), isolationChargedHadrCands_sum, + processIsolationPFComponents(tau, tau.isolationChargedHadrCands(), isolationChargedHadrCands_sum, get(dnn::isolationChargedHadrCands_sum_pt), get(dnn::isolationChargedHadrCands_sum_dEta), get(dnn::isolationChargedHadrCands_sum_dPhi), @@ -471,7 +483,7 @@ class DeepTauId : public deep_tau::DeepTauBase { get(dnn::isolationChargedHadrCands_nTotal)); LorentzVectorXYZ isolationNeutrHadrCands_sum; - ProcessIsolationPFComponents(tau, tau.isolationNeutrHadrCands(), isolationNeutrHadrCands_sum, + processIsolationPFComponents(tau, tau.isolationNeutrHadrCands(), isolationNeutrHadrCands_sum, get(dnn::isolationNeutrHadrCands_sum_pt), get(dnn::isolationNeutrHadrCands_sum_dEta), get(dnn::isolationNeutrHadrCands_sum_dPhi), @@ -479,7 +491,7 @@ class DeepTauId : public deep_tau::DeepTauBase { get(dnn::isolationNeutrHadrCands_nTotal)); LorentzVectorXYZ isolationGammaCands_sum; - ProcessIsolationPFComponents(tau, tau.isolationGammaCands(), isolationGammaCands_sum, + processIsolationPFComponents(tau, tau.isolationGammaCands(), isolationGammaCands_sum, get(dnn::isolationGammaCands_sum_pt), get(dnn::isolationGammaCands_sum_dEta), get(dnn::isolationGammaCands_sum_dPhi), @@ -490,13 +502,15 @@ class DeepTauId : public deep_tau::DeepTauBase { if(check_all_set) { for(int var_index = 0; var_index < dnn::NumberOfInputs; ++var_index) { - if(get(var_index) == magic_number) + if(get(var_index) == default_value_for_set_check) throw cms::Exception("DeepTauId: variable with index = ") << var_index << " is not set."; } } + + return inputs; } - static void CalculateElectronClusterVars(const pat::Electron* ele, float& elecEe, float& elecEgamma) + static void calculateElectronClusterVars(const pat::Electron* ele, float& elecEe, float& elecEgamma) { if(ele) { elecEe = elecEgamma = 0; @@ -515,7 +529,7 @@ class DeepTauId : public deep_tau::DeepTauBase { } template - static void ProcessSignalPFComponents(const pat::Tau& tau, const CandidateCollection& candidates, + static void processSignalPFComponents(const pat::Tau& tau, const CandidateCollection& candidates, LorentzVectorXYZ& p4_inner, LorentzVectorXYZ& p4_outer, float& pt_inner, float& dEta_inner, float& dPhi_inner, float& m_inner, float& pt_outer, float& dEta_outer, float& dPhi_outer, float& m_outer, @@ -526,7 +540,7 @@ class DeepTauId : public deep_tau::DeepTauBase { n_inner = 0; n_outer = 0; - const double innerSigCone_radius = GetInnerSignalConeRadius(tau.pt()); + const double innerSigCone_radius = getInnerSignalConeRadius(tau.pt()); for(const auto& cand : candidates) { const double dR = reco::deltaR(cand->p4(), tau.leadChargedHadrCand()->p4()); const bool isInside_innerSigCone = dR < innerSigCone_radius; @@ -551,7 +565,7 @@ class DeepTauId : public deep_tau::DeepTauBase { } template - static void ProcessIsolationPFComponents(const pat::Tau& tau, const CandidateCollection& candidates, + static void processIsolationPFComponents(const pat::Tau& tau, const CandidateCollection& candidates, LorentzVectorXYZ& p4, float& pt, float& d_eta, float& d_phi, float& m, float& n) { @@ -569,13 +583,15 @@ class DeepTauId : public deep_tau::DeepTauBase { m = n != 0 ? p4.mass() : default_value; } - static double GetInnerSignalConeRadius(double pt) + static double getInnerSignalConeRadius(double pt) { - return std::max(.05, std::min(.1, 3./std::max(1., pt))); + static constexpr double min_pt = 30., min_radius = 0.05, cone_opening_coef = 3.; + // This is equivalent of the original formula (std::max(std::min(0.1, 3.0/pt), 0.05) + return std::max(cone_opening_coef / std::max(pt, min_pt), min_radius); } // Copied from https://github.com/cms-sw/cmssw/blob/CMSSW_9_4_X/RecoTauTag/RecoTau/plugins/PATTauDiscriminationByMVAIsolationRun2.cc#L218 - static float CalculateGottfriedJacksonAngleDifference(const pat::Tau& tau) + static float calculateGottfriedJacksonAngleDifference(const pat::Tau& tau) { if(tau.decayMode() == 10) { static constexpr double mTau = 1.77682; @@ -593,13 +609,13 @@ class DeepTauId : public deep_tau::DeepTauBase { return default_value; } - static bool IsInEcalCrack(double eta) + static bool isInEcalCrack(double eta) { const double abs_eta = std::abs(eta); return abs_eta > 1.46 && abs_eta < 1.558; } - static const pat::Electron* FindMatchedElectron(const pat::Tau& tau, const pat::ElectronCollection& electrons, + static const pat::Electron* findMatchedElectron(const pat::Tau& tau, const pat::ElectronCollection& electrons, double deltaR) { const double dR2 = deltaR*deltaR; diff --git a/RecoTauTag/RecoTau/python/tools/runTauIdMVA.py b/RecoTauTag/RecoTau/python/tools/runTauIdMVA.py index 71d318b0f9bea..147c2c074c8f0 100644 --- a/RecoTauTag/RecoTau/python/tools/runTauIdMVA.py +++ b/RecoTauTag/RecoTau/python/tools/runTauIdMVA.py @@ -1,6 +1,7 @@ from RecoTauTag.RecoTau.TauDiscriminatorTools import noPrediscriminants from RecoTauTag.RecoTau.PATTauDiscriminationByMVAIsolationRun2_cff import patDiscriminationByIsolationMVArun2v1raw, patDiscriminationByIsolationMVArun2v1VLoose import os +import re class TauIDEmbedder(object): """class to rerun the tau seq and acces trainings from the database""" @@ -592,95 +593,106 @@ def runTauID(self): if "deepTau2017v1" in self.toKeep: print "Adding DeepTau IDs" - working_points = { + workingPoints_ = { "e": { - "VVVLoose" : "0.96424", - "VVLoose" : "0.98992", - "VLoose" : "0.99574", - "Loose": "0.99831", - "Medium": "0.99868", - "Tight": "0.99898", - "VTight": "0.99911", - "VVTight": "0.99918" + "VVVLoose" : 0.96424, + "VVLoose" : 0.98992, + "VLoose" : 0.99574, + "Loose": 0.99831, + "Medium": 0.99868, + "Tight": 0.99898, + "VTight": 0.99911, + "VVTight": 0.99918 }, "mu": { - "VVVLoose" : "0.959619", - "VVLoose" : "0.997687", - "VLoose" : "0.999392", - "Loose": "0.999755", - "Medium": "0.999854", - "Tight": "0.999886", - "VTight": "0.999944", - "VVTight": "0.9999971" + "VVVLoose" : 0.959619, + "VVLoose" : 0.997687, + "VLoose" : 0.999392, + "Loose": 0.999755, + "Medium": 0.999854, + "Tight": 0.999886, + "VTight": 0.999944, + "VVTight": 0.9999971 }, "jet": { - "VVVLoose" : "0.5329", - "VVLoose" : "0.7645", - "VLoose" : "0.8623", - "Loose": "0.9140", - "Medium": "0.9464", - "Tight": "0.9635", - "VTight": "0.9760", - "VVTight": "0.9859" + "VVVLoose" : 0.5329, + "VVLoose" : 0.7645, + "VLoose" : 0.8623, + "Loose": 0.9140, + "Medium": 0.9464, + "Tight": 0.9635, + "VTight": 0.9760, + "VVTight": 0.9859 } } + file_name = 'RecoTauTag/TrainingFiles/data/DeepTauId/deepTau_2017v1_20L1024N_quantized.pb' self.process.deepTau2017v1 = self.cms.EDProducer("DeepTauId", - electrons = self.cms.InputTag('slimmedElectrons'), - muons = self.cms.InputTag('slimmedMuons'), - taus = self.cms.InputTag('slimmedTaus'), - graph_file = self.cms.string('RecoTauTag/TrainingFiles/data/DeepTauId/deepTau_2017v1_20L1024N.pb') + electrons = self.cms.InputTag('slimmedElectrons'), + muons = self.cms.InputTag('slimmedMuons'), + taus = self.cms.InputTag('slimmedTaus'), + graph_file = self.cms.string(file_name), + mem_mapped = self.cms.bool(False) ) - self.processDeepProducer('deepTau2017v1', tauIDSources, working_points) + self.processDeepProducer('deepTau2017v1', tauIDSources, workingPoints_) self.process.rerunMvaIsolationTask.add(self.process.deepTau2017v1) self.process.rerunMvaIsolationSequence += self.process.deepTau2017v1 - if "DPFTau_2016_v0" in self.toKeep: + if "DPFTau_2016_v0" in self.toKeep: print "Adding DPFTau isolation (v0)" - working_points = { + workingPoints_ = { "all": { - - "Tight" : "? decayMode == 0 ? (0.898328 - 0.000160992 * pt) : " + - "(? decayMode == 1 ? 0.910138 - 0.000229923 * pt : " + - "(? decayMode == 10 ? (0.873958 - 0.0002328 * pt) : 1))" + "Tight" : "if(decayMode == 0) return (0.898328 - 0.000160992 * pt);" + \ + "if(decayMode == 1) return (0.910138 - 0.000229923 * pt);" + \ + "if(decayMode == 10) return (0.873958 - 0.0002328 * pt);" + \ + "return 99.0;" + #"Tight" : "? decayMode == 0 ? (0.898328 - 0.000160992 * pt) : " + + # "(? decayMode == 1 ? 0.910138 - 0.000229923 * pt : " + + # "(? decayMode == 10 ? (0.873958 - 0.0002328 * pt) : 1))" # "Tight" : "(decayMode == 0) * (0.898328 - 0.000160992 * pt) + \ # (decayMode == 1) * (0.910138 - 0.000229923 * pt) + \ # (decayMode == 10) * (0.873958 - 0.0002328 * pt) " } } - + file_name = 'RecoTauTag/TrainingFiles/data/DPFTauId/DPFIsolation_2017v0_quantized.pb' self.process.dpfTau2016v0 = self.cms.EDProducer("DPFIsolation", pfcands = self.cms.InputTag('packedPFCandidates'), - taus = self.cms.InputTag('slimmedTaus'), + taus = self.cms.InputTag('slimmedTaus'), vertices = self.cms.InputTag('offlineSlimmedPrimaryVertices'), - graph_file = self.cms.string('RecoTauTag/TrainingFiles/data/DPFTauId/DPFIsolation_2017v0.pb') + graph_file = self.cms.string(file_name), + version = self.cms.uint32(self.getDpfTauVersion(file_name)), + mem_mapped = self.cms.bool(False) ) - self.processDeepProducer('dpfTau2016v0', tauIDSources, working_points) + self.processDeepProducer('dpfTau2016v0', tauIDSources, workingPoints_) self.process.rerunMvaIsolationTask.add(self.process.dpfTau2016v0) self.process.rerunMvaIsolationSequence += self.process.dpfTau2016v0 + if "DPFTau_2016_v1" in self.toKeep: print "Adding DPFTau isolation (v1)" print "WARNING: WPs are not defined for DPFTau_2016_v1" print "WARNING: The score of DPFTau_2016_v1 is inverted: i.e. for Sig->0, for Bkg->1 with -1 for undefined input (preselection not passed)." - working_points = { - "all": {"Tight" : "0.123"} #FIXME: define WP + workingPoints_ = { + "all": {"Tight" : 0.123} #FIXME: define WP } + file_name = 'RecoTauTag/TrainingFiles/data/DPFTauId/DPFIsolation_2017v1_quantized.pb' self.process.dpfTau2016v1 = self.cms.EDProducer("DPFIsolation", pfcands = self.cms.InputTag('packedPFCandidates'), - taus = self.cms.InputTag('slimmedTaus'), + taus = self.cms.InputTag('slimmedTaus'), vertices = self.cms.InputTag('offlineSlimmedPrimaryVertices'), - graph_file = self.cms.string('RecoTauTag/TrainingFiles/data/DPFTauId/DPFIsolation_2017v1.pb') + graph_file = self.cms.string(file_name), + version = self.cms.uint32(self.getDpfTauVersion(file_name)), + mem_mapped = self.cms.bool(False) ) - self.processDeepProducer('dpfTau2016v1', tauIDSources, working_points) + self.processDeepProducer('dpfTau2016v1', tauIDSources, workingPoints_) self.process.rerunMvaIsolationTask.add(self.process.dpfTau2016v1) self.process.rerunMvaIsolationSequence += self.process.dpfTau2016v1 @@ -693,15 +705,26 @@ def runTauID(self): setattr(self.process, self.updatedTauName, embedID) - def processDeepProducer(self, producer_name, tauIDSources, working_points): - for target,points in working_points.iteritems(): + def processDeepProducer(self, producer_name, tauIDSources, workingPoints_): + for target,points in workingPoints_.iteritems(): cuts = self.cms.PSet() setattr(tauIDSources, 'by{}VS{}raw'.format(producer_name[0].upper()+producer_name[1:], target), self.cms.InputTag(producer_name, 'VS{}'.format(target))) for point,cut in points.iteritems(): - setattr(cuts, point, self.cms.string(cut)) + setattr(cuts, point, self.cms.string(str(cut))) setattr(tauIDSources, 'by{}{}VS{}'.format(point, producer_name[0].upper()+producer_name[1:], target), self.cms.InputTag(producer_name, 'VS{}{}'.format(target, point))) setattr(getattr(self.process, producer_name), 'VS{}WP'.format(target), cuts) + + + def getDpfTauVersion(self, file_name): + """returns the DNN version. File name should contain a version label with data takig year (2011-2, 2015-8) and \ + version number (vX), e.g. 2017v0, in general the following format: {year}v{version}""" + version_search = re.search('201[125678]v([0-9]+)[\._]', file_name) + if not version_search: + raise RuntimeError('File "{}" has an invalid name pattern, should be in the format "{year}v{version}". \ + Unable to extract version number.'.format(file_name)) + version = version_search.group(1) + return int(version) diff --git a/RecoTauTag/RecoTau/src/DeepTauBase.cc b/RecoTauTag/RecoTau/src/DeepTauBase.cc index d94d6d55ebd01..f6f33877a3789 100644 --- a/RecoTauTag/RecoTau/src/DeepTauBase.cc +++ b/RecoTauTag/RecoTau/src/DeepTauBase.cc @@ -7,10 +7,46 @@ * \author Maria Rosaria Di Domenico, University of Siena & INFN Pisa */ + #include "RecoTauTag/RecoTau/interface/DeepTauBase.h" namespace deep_tau { +TauWPThreshold::TauWPThreshold(const std::string& cut_str) +{ + bool simple_value = false; + try { + size_t pos = 0; + value_ = std::stod(cut_str, &pos); + simple_value = (pos == cut_str.size()); + } catch(std::invalid_argument&) { + } catch(std::out_of_range&) { + } + if(!simple_value) { + static const std::string prefix = "[&](double *x, double *p) { const int decayMode = p[0];" + "const double pt = p[1]; const double eta = p[2];"; + static const int n_params = 3; + static const auto handler = [](int, Bool_t, const char*, const char*) -> void {}; + + const std::string fn_str = prefix + cut_str + "}"; + auto old_handler = SetErrorHandler(handler); + fn_ = std::make_unique("fn_", fn_str.c_str(), 0, 1, n_params); + SetErrorHandler(old_handler); + if(!fn_->IsValid()) + throw cms::Exception("TauWPThreshold: invalid formula") << "Invalid WP cut formula = '" << cut_str << "'."; + } +} + +double TauWPThreshold::operator()(const pat::Tau& tau) const +{ + if(!fn_) + return value_; + fn_->SetParameter(0, tau.decayMode()); + fn_->SetParameter(1, tau.pt()); + fn_->SetParameter(2, tau.eta()); + return fn_->Eval(0); +} + DeepTauBase::Output::ResultMap DeepTauBase::Output::get_value(const edm::Handle& taus, const tensorflow::Tensor& pred, const WPMap& working_points) const @@ -22,11 +58,11 @@ DeepTauBase::Output::ResultMap DeepTauBase::Output::get_value(const edm::Handle< for(size_t tau_index = 0; tau_index < taus->size(); ++tau_index) { float x = 0; - for(size_t num_elem : num) + for(size_t num_elem : num_) x += pred.matrix()(tau_index, num_elem); - if(x != 0 && den.size() > 0) { + if(x != 0 && den_.size() > 0) { float den_val = 0; - for(size_t den_elem : den) + for(size_t den_elem : den_) den_val += pred.matrix()(tau_index, den_elem); x = den_val != 0 ? x / den_val : std::numeric_limits::max(); } @@ -40,45 +76,80 @@ DeepTauBase::Output::ResultMap DeepTauBase::Output::get_value(const edm::Handle< return output; } -DeepTauBase::DeepTauBase(const edm::ParameterSet& cfg, const OutputCollection& outputCollection) : - taus_token(consumes(cfg.getParameter("taus"))), - graphName(edm::FileInPath(cfg.getParameter("graph_file")).fullPath()), - graph(tensorflow::loadGraphDef(graphName)), - session(tensorflow::createSession(graph.get())), - outputs(outputCollection) +DeepTauBase::DeepTauBase(const edm::ParameterSet& cfg, const OutputCollection& outputCollection, const DeepTauCache* cache) : + tausToken_(consumes(cfg.getParameter("taus"))), + outputs_(outputCollection), + cache_(cache) { - for(const auto& output_desc : outputs) { + for(const auto& output_desc : outputs_) { produces(output_desc.first); const auto& cut_pset = cfg.getParameter(output_desc.first + "WP"); for(const std::string& wp_name : cut_pset.getParameterNames()) { const auto& cut_str = cut_pset.getParameter(wp_name); - working_points[output_desc.first][wp_name] = std::make_unique(cut_str); + workingPoints_[output_desc.first][wp_name] = std::make_unique(cut_str); produces(output_desc.first + wp_name); } } } -DeepTauBase::~DeepTauBase() -{ - tensorflow::closeSession(session); -} - void DeepTauBase::produce(edm::Event& event, const edm::EventSetup& es) { edm::Handle taus; - event.getByToken(taus_token, taus); + event.getByToken(tausToken_, taus); - const tensorflow::Tensor& pred = GetPredictions(event, es, taus); - CreateOutputs(event, pred, taus); + const tensorflow::Tensor& pred = getPredictions(event, es, taus); + createOutputs(event, pred, taus); } -void DeepTauBase::CreateOutputs(edm::Event& event, const tensorflow::Tensor& pred, edm::Handle taus) +void DeepTauBase::createOutputs(edm::Event& event, const tensorflow::Tensor& pred, edm::Handle taus) { - for(const auto& output_desc : outputs) { - auto result_map = output_desc.second.get_value(taus, pred, working_points.at(output_desc.first)); + for(const auto& output_desc : outputs_) { + auto result_map = output_desc.second.get_value(taus, pred, workingPoints_.at(output_desc.first)); for(auto& result : result_map) event.put(std::move(result.second), output_desc.first + result.first); } } +std::unique_ptr DeepTauBase::initializeGlobalCache(const edm::ParameterSet& cfg ) +{ + std::string graph_name = edm::FileInPath(cfg.getParameter("graph_file")).fullPath(); + bool mem_mapped = cfg.getParameter("mem_mapped"); + return std::make_unique(graph_name, mem_mapped); +} + +DeepTauCache::DeepTauCache(const std::string& graph_name, bool mem_mapped) +{ + tensorflow::SessionOptions options; + tensorflow::setThreading(options, 1, "no_threads"); + + if(mem_mapped) { + memmappedEnv_ = std::make_unique(tensorflow::Env::Default()); + const tensorflow::Status mmap_status = memmappedEnv_.get()->InitializeFromFile(graph_name); + if(!mmap_status.ok()) + throw cms::Exception("DeepTauCache: unable to initalize memmapped environment for ") << graph_name << ". \n" + << mmap_status.ToString(); + + graph_ = std::make_unique(); + const tensorflow::Status load_graph_status = ReadBinaryProto(memmappedEnv_.get(), + tensorflow::MemmappedFileSystem::kMemmappedPackageDefaultGraphDef, + graph_.get()); + if(!load_graph_status.ok()) + throw cms::Exception("DeepTauCache: unable to load graph_ from ") << graph_name << ". \n" + << mmap_status.ToString(); + options.config.mutable_graph_options()->mutable_optimizer_options()->set_opt_level(::tensorflow::OptimizerOptions::L0); + options.env = memmappedEnv_.get(); + + session_ = tensorflow::createSession(graph_.get(), options); + + } else { + graph_.reset(tensorflow::loadGraphDef(graph_name)); + session_ = tensorflow::createSession(graph_.get(), options); + } +} + +DeepTauCache::~DeepTauCache() +{ + tensorflow::closeSession(session_); +} + } // namespace deep_tau diff --git a/RecoTauTag/RecoTau/test/runDeepTauIDsOnMiniAOD.py b/RecoTauTag/RecoTau/test/runDeepTauIDsOnMiniAOD.py index cf638c302af73..406f2e532d816 100644 --- a/RecoTauTag/RecoTau/test/runDeepTauIDsOnMiniAOD.py +++ b/RecoTauTag/RecoTau/test/runDeepTauIDsOnMiniAOD.py @@ -34,7 +34,7 @@ toKeep = [ "2017v2", "dR0p32017v2", "newDM2017v2", "deepTau2017v1", "DPFTau_2016_v0", - #"DPFTau_2016_v1" + # "DPFTau_2016_v1" ]) tauIdEmbedder.runTauID()