Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:27:47

0001 /*
0002  * \class DeepTauId
0003  *
0004  * Tau identification using Deep NN.
0005  *
0006  * \author Konstantin Androsov, INFN Pisa
0007  *         Christian Veelken, Tallinn
0008  */
0009 
0010 #include "FWCore/Framework/interface/stream/EDProducer.h"
0011 #include "RecoTauTag/RecoTau/interface/DeepTauIdBase.h"
0012 #include "FWCore/Utilities/interface/isFinite.h"
0013 
0014 namespace deep_tau {
0015   class DeepTauCache {
0016   public:
0017     using GraphPtr = std::shared_ptr<tensorflow::GraphDef>;
0018 
0019     DeepTauCache(const std::map<std::string, std::string>& graph_names, bool mem_mapped) {
0020       for (const auto& graph_entry : graph_names) {
0021         // Backend : to be parametrized from the python config
0022         tensorflow::Options options{tensorflow::Backend::cpu};
0023 
0024         const std::string& entry_name = graph_entry.first;
0025         const std::string& graph_file = graph_entry.second;
0026         if (mem_mapped) {
0027           memmappedEnv_[entry_name] = std::make_unique<tensorflow::MemmappedEnv>(tensorflow::Env::Default());
0028           const tensorflow::Status mmap_status = memmappedEnv_.at(entry_name)->InitializeFromFile(graph_file);
0029           if (!mmap_status.ok()) {
0030             throw cms::Exception("DeepTauCache: unable to initalize memmapped environment for ")
0031                 << graph_file << ". \n"
0032                 << mmap_status.ToString();
0033           }
0034 
0035           graphs_[entry_name] = std::make_unique<tensorflow::GraphDef>();
0036           const tensorflow::Status load_graph_status =
0037               ReadBinaryProto(memmappedEnv_.at(entry_name).get(),
0038                               tensorflow::MemmappedFileSystem::kMemmappedPackageDefaultGraphDef,
0039                               graphs_.at(entry_name).get());
0040           if (!load_graph_status.ok())
0041             throw cms::Exception("DeepTauCache: unable to load graph from ") << graph_file << ". \n"
0042                                                                              << load_graph_status.ToString();
0043 
0044           options.getSessionOptions().config.mutable_graph_options()->mutable_optimizer_options()->set_opt_level(
0045               ::tensorflow::OptimizerOptions::L0);
0046           options.getSessionOptions().env = memmappedEnv_.at(entry_name).get();
0047 
0048           sessions_[entry_name] = tensorflow::createSession(graphs_.at(entry_name).get(), options);
0049 
0050         } else {
0051           graphs_[entry_name].reset(tensorflow::loadGraphDef(graph_file));
0052           sessions_[entry_name] = tensorflow::createSession(graphs_.at(entry_name).get(), options);
0053         }
0054       }
0055     };
0056     ~DeepTauCache() {
0057       for (auto& session_entry : sessions_)
0058         tensorflow::closeSession(session_entry.second);
0059     }
0060 
0061     // A Session allows concurrent calls to Run(), though a Session must
0062     // be created / extended by a single thread.
0063     tensorflow::Session& getSession(const std::string& name = "") const { return *sessions_.at(name); }
0064     const tensorflow::GraphDef& getGraph(const std::string& name = "") const { return *graphs_.at(name); }
0065 
0066   private:
0067     std::map<std::string, GraphPtr> graphs_;
0068     std::map<std::string, tensorflow::Session*> sessions_;
0069     std::map<std::string, std::unique_ptr<tensorflow::MemmappedEnv>> memmappedEnv_;
0070   };
0071 }  // namespace deep_tau
0072 
0073 class DeepTauIdWrapper : public edm::stream::EDProducer<edm::GlobalCache<deep_tau::DeepTauCache>> {
0074 public:
0075   DeepTauIdWrapper(const edm::ParameterSet& cfg) {}
0076 };
0077 
0078 class DeepTauId : public DeepTauIdBase<DeepTauIdWrapper> {
0079 public:
0080   static void fillDescriptions(edm::ConfigurationDescriptions& descriptions) {
0081     edm::ParameterSetDescription desc;
0082     fillDescriptionsHelper(desc);
0083     desc.add<std::vector<std::string>>("graph_file",
0084                                        {"RecoTauTag/TrainingFiles/data/DeepTauId/deepTau_2017v2p6_e6.pb"});
0085     descriptions.add("DeepTau", desc);
0086   }
0087 
0088 public:
0089   explicit DeepTauId(const edm::ParameterSet& cfg, const deep_tau::DeepTauCache* cache)
0090       : DeepTauIdBase<DeepTauIdWrapper>(cfg), cache_(cache) {
0091     if (version_ == 2) {
0092       using namespace dnn_inputs_v2;
0093       if (sub_version_ == 1) {
0094         tauBlockTensor_ = std::make_unique<tensorflow::Tensor>(
0095             tensorflow::DT_FLOAT, tensorflow::TensorShape{1, TauBlockInputs::NumberOfInputs});
0096       } else if (sub_version_ == 5) {
0097         tauBlockTensor_ = std::make_unique<tensorflow::Tensor>(
0098             tensorflow::DT_FLOAT,
0099             tensorflow::TensorShape{1,
0100                                     static_cast<int>(TauBlockInputs::NumberOfInputs) -
0101                                         static_cast<int>(TauBlockInputs::varsToDrop.size())});
0102       }
0103 
0104       for (size_t n = 0; n < 2; ++n) {
0105         const bool is_inner = n == 0;
0106         const auto n_cells = is_inner ? number_of_inner_cell : number_of_outer_cell;
0107         eGammaTensor_[is_inner] = std::make_unique<tensorflow::Tensor>(
0108             tensorflow::DT_FLOAT, tensorflow::TensorShape{1, 1, 1, EgammaBlockInputs::NumberOfInputs});
0109         muonTensor_[is_inner] = std::make_unique<tensorflow::Tensor>(
0110             tensorflow::DT_FLOAT, tensorflow::TensorShape{1, 1, 1, MuonBlockInputs::NumberOfInputs});
0111         hadronsTensor_[is_inner] = std::make_unique<tensorflow::Tensor>(
0112             tensorflow::DT_FLOAT, tensorflow::TensorShape{1, 1, 1, HadronBlockInputs::NumberOfInputs});
0113         convTensor_[is_inner] = std::make_unique<tensorflow::Tensor>(
0114             tensorflow::DT_FLOAT, tensorflow::TensorShape{1, n_cells, n_cells, number_of_conv_features});
0115         zeroOutputTensor_[is_inner] = std::make_unique<tensorflow::Tensor>(
0116             tensorflow::DT_FLOAT, tensorflow::TensorShape{1, 1, 1, number_of_conv_features});
0117 
0118         eGammaTensor_[is_inner]->flat<float>().setZero();
0119         muonTensor_[is_inner]->flat<float>().setZero();
0120         hadronsTensor_[is_inner]->flat<float>().setZero();
0121 
0122         setCellConvFeatures(*zeroOutputTensor_[is_inner], getPartialPredictions(is_inner), 0, 0, 0);
0123       }
0124     }
0125   }
0126 
0127   void produce(edm::Event& event, const edm::EventSetup& es) override {
0128     edm::Handle<TauCollection> taus;
0129     event.getByToken(tausToken_, taus);
0130 
0131     // store empty output collection(s) if tau collection is empty
0132     if (taus->empty()) {
0133       const tensorflow::Tensor emptyPrediction(tensorflow::DT_FLOAT, {0, deep_tau::NumberOfOutputs});
0134       createOutputs(event, emptyPrediction, taus);
0135       return;
0136     }
0137 
0138     loadPrediscriminants(event, taus);
0139 
0140     const tensorflow::Tensor& pred = getPredictions(event, taus);
0141     createOutputs(event, pred, taus);
0142   }
0143 
0144   static std::unique_ptr<deep_tau::DeepTauCache> initializeGlobalCache(const edm::ParameterSet& cfg) {
0145     const auto graph_name_vector = cfg.getParameter<std::vector<std::string>>("graph_file");
0146     std::map<std::string, std::string> graph_names;
0147     for (const auto& entry : graph_name_vector) {
0148       const size_t sep_pos = entry.find(':');
0149       std::string entry_name, graph_file;
0150       if (sep_pos != std::string::npos) {
0151         entry_name = entry.substr(0, sep_pos);
0152         graph_file = entry.substr(sep_pos + 1);
0153       } else {
0154         entry_name = "";
0155         graph_file = entry;
0156       }
0157       graph_file = edm::FileInPath(graph_file).fullPath();
0158       if (graph_names.count(entry_name))
0159         throw cms::Exception("DeepTauCache") << "Duplicated graph entries";
0160       graph_names[entry_name] = graph_file;
0161     }
0162     bool mem_mapped = cfg.getParameter<bool>("mem_mapped");
0163     return std::make_unique<deep_tau::DeepTauCache>(graph_names, mem_mapped);
0164   }
0165 
0166   static void globalEndJob(const deep_tau::DeepTauCache* cache_) {}
0167 
0168 private:
0169   inline void checkInputs(const tensorflow::Tensor& inputs,
0170                           const std::string& block_name,
0171                           int n_inputs,
0172                           const CellGrid* grid = nullptr) const {
0173     if (debug_level >= 1) {
0174       std::cout << "<checkInputs>: block_name = " << block_name << std::endl;
0175       if (block_name == "input_tau") {
0176         for (int input_index = 0; input_index < n_inputs; ++input_index) {
0177           float input = inputs.matrix<float>()(0, input_index);
0178           if (edm::isNotFinite(input)) {
0179             throw cms::Exception("DeepTauId")
0180                 << "in the " << block_name
0181                 << ", input is not finite, i.e. infinite or NaN, for input_index = " << input_index;
0182           }
0183           if (debug_level >= 2) {
0184             std::cout << block_name << "[var = " << input_index << "] = " << std::setprecision(5) << std::fixed << input
0185                       << std::endl;
0186           }
0187         }
0188       } else {
0189         assert(grid);
0190         int n_eta, n_phi;
0191         if (block_name.find("input_inner") != std::string::npos) {
0192           n_eta = 5;
0193           n_phi = 5;
0194         } else if (block_name.find("input_outer") != std::string::npos) {
0195           n_eta = 10;
0196           n_phi = 10;
0197         } else
0198           assert(0);
0199         int eta_phi_index = 0;
0200         for (int eta = -n_eta; eta <= n_eta; ++eta) {
0201           for (int phi = -n_phi; phi <= n_phi; ++phi) {
0202             const CellIndex cell_index{eta, phi};
0203             const auto cell_iter = grid->find(cell_index);
0204             if (cell_iter != grid->end()) {
0205               for (int input_index = 0; input_index < n_inputs; ++input_index) {
0206                 float input = inputs.tensor<float, 4>()(eta_phi_index, 0, 0, input_index);
0207                 if (edm::isNotFinite(input)) {
0208                   throw cms::Exception("DeepTauId")
0209                       << "in the " << block_name << ", input is not finite, i.e. infinite or NaN, for eta = " << eta
0210                       << ", phi = " << phi << ", input_index = " << input_index;
0211                 }
0212                 if (debug_level >= 2) {
0213                   std::cout << block_name << "[eta = " << eta << "][phi = " << phi << "][var = " << input_index
0214                             << "] = " << std::setprecision(5) << std::fixed << input << std::endl;
0215                 }
0216               }
0217               eta_phi_index += 1;
0218             }
0219           }
0220         }
0221       }
0222     }
0223   }
0224 
0225   inline void saveInputs(const tensorflow::Tensor& inputs,
0226                          const std::string& block_name,
0227                          int n_inputs,
0228                          const CellGrid* grid = nullptr) {
0229     if (debug_level >= 1) {
0230       std::cout << "<saveInputs>: block_name = " << block_name << std::endl;
0231     }
0232     if (!is_first_block_)
0233       (*json_file_) << ", ";
0234     (*json_file_) << "\"" << block_name << "\": [";
0235     if (block_name == "input_tau") {
0236       for (int input_index = 0; input_index < n_inputs; ++input_index) {
0237         float input = inputs.matrix<float>()(0, input_index);
0238         if (input_index != 0)
0239           (*json_file_) << ", ";
0240         (*json_file_) << input;
0241       }
0242     } else {
0243       assert(grid);
0244       int n_eta, n_phi;
0245       if (block_name.find("input_inner") != std::string::npos) {
0246         n_eta = 5;
0247         n_phi = 5;
0248       } else if (block_name.find("input_outer") != std::string::npos) {
0249         n_eta = 10;
0250         n_phi = 10;
0251       } else
0252         assert(0);
0253       int eta_phi_index = 0;
0254       for (int eta = -n_eta; eta <= n_eta; ++eta) {
0255         if (eta != -n_eta)
0256           (*json_file_) << ", ";
0257         (*json_file_) << "[";
0258         for (int phi = -n_phi; phi <= n_phi; ++phi) {
0259           if (phi != -n_phi)
0260             (*json_file_) << ", ";
0261           (*json_file_) << "[";
0262           const CellIndex cell_index{eta, phi};
0263           const auto cell_iter = grid->find(cell_index);
0264           for (int input_index = 0; input_index < n_inputs; ++input_index) {
0265             float input = 0.;
0266             if (cell_iter != grid->end()) {
0267               input = inputs.tensor<float, 4>()(eta_phi_index, 0, 0, input_index);
0268             }
0269             if (input_index != 0)
0270               (*json_file_) << ", ";
0271             (*json_file_) << input;
0272           }
0273           if (cell_iter != grid->end()) {
0274             eta_phi_index += 1;
0275           }
0276           (*json_file_) << "]";
0277         }
0278         (*json_file_) << "]";
0279       }
0280     }
0281     (*json_file_) << "]";
0282     is_first_block_ = false;
0283   }
0284 
0285 private:
0286   tensorflow::Tensor getPredictions(edm::Event& event, edm::Handle<TauCollection> taus) {
0287     // Empty dummy vectors
0288     const std::vector<pat::Electron> electron_collection_default;
0289     const std::vector<pat::Muon> muon_collection_default;
0290     const reco::TauDiscriminatorContainer basicTauDiscriminators_default;
0291     const reco::TauDiscriminatorContainer basicTauDiscriminatorsdR03_default;
0292     const edm::AssociationVector<reco::PFTauRefProd, std::vector<reco::PFTauTransverseImpactParameterRef>>
0293         pfTauTransverseImpactParameters_default;
0294 
0295     const std::vector<pat::Electron>* electron_collection;
0296     const std::vector<pat::Muon>* muon_collection;
0297     const reco::TauDiscriminatorContainer* basicTauDiscriminators;
0298     const reco::TauDiscriminatorContainer* basicTauDiscriminatorsdR03;
0299     const edm::AssociationVector<reco::PFTauRefProd, std::vector<reco::PFTauTransverseImpactParameterRef>>*
0300         pfTauTransverseImpactParameters;
0301 
0302     if (!is_online_) {
0303       electron_collection = &event.get(electrons_token_);
0304       muon_collection = &event.get(muons_token_);
0305       pfTauTransverseImpactParameters = &pfTauTransverseImpactParameters_default;
0306       basicTauDiscriminators = &basicTauDiscriminators_default;
0307       basicTauDiscriminatorsdR03 = &basicTauDiscriminatorsdR03_default;
0308     } else {
0309       electron_collection = &electron_collection_default;
0310       muon_collection = &muon_collection_default;
0311       pfTauTransverseImpactParameters = &event.get(pfTauTransverseImpactParameters_token_);
0312       basicTauDiscriminators = &event.get(basicTauDiscriminators_inputToken_);
0313       basicTauDiscriminatorsdR03 = &event.get(basicTauDiscriminatorsdR03_inputToken_);
0314 
0315       // Get indices for discriminators
0316       if (!discrIndicesMapped_) {
0317         basicDiscrIndexMap_ =
0318             matchDiscriminatorIndices(event, basicTauDiscriminators_inputToken_, requiredBasicDiscriminators_);
0319         basicDiscrdR03IndexMap_ =
0320             matchDiscriminatorIndices(event, basicTauDiscriminatorsdR03_inputToken_, requiredBasicDiscriminatorsdR03_);
0321         discrIndicesMapped_ = true;
0322       }
0323     }
0324 
0325     TauFunc tauIDs = {basicTauDiscriminators,
0326                       basicTauDiscriminatorsdR03,
0327                       pfTauTransverseImpactParameters,
0328                       basicDiscrIndexMap_,
0329                       basicDiscrdR03IndexMap_};
0330 
0331     edm::Handle<edm::View<reco::Candidate>> pfCands;
0332     event.getByToken(pfcandToken_, pfCands);
0333 
0334     edm::Handle<reco::VertexCollection> vertices;
0335     event.getByToken(vtxToken_, vertices);
0336 
0337     edm::Handle<double> rho;
0338     event.getByToken(rho_token_, rho);
0339 
0340     auto const& eventnr = event.id().event();
0341 
0342     tensorflow::Tensor predictions(tensorflow::DT_FLOAT, {static_cast<int>(taus->size()), deep_tau::NumberOfOutputs});
0343 
0344     for (size_t tau_index = 0; tau_index < taus->size(); ++tau_index) {
0345       const edm::RefToBase<reco::BaseTau> tauRef = taus->refAt(tau_index);
0346 
0347       std::vector<tensorflow::Tensor> pred_vector;
0348 
0349       bool passesPrediscriminants;
0350       if (is_online_) {
0351         passesPrediscriminants = tauIDs.passPrediscriminants<std::vector<TauDiscInfo<reco::PFTauDiscriminator>>>(
0352             recoPrediscriminants_, andPrediscriminants_, tauRef);
0353       } else {
0354         passesPrediscriminants = tauIDs.passPrediscriminants<std::vector<TauDiscInfo<pat::PATTauDiscriminator>>>(
0355             patPrediscriminants_, andPrediscriminants_, tauRef);
0356       }
0357 
0358       if (passesPrediscriminants) {
0359         if (version_ == 2) {
0360           if (is_online_) {
0361             getPredictionsV2<reco::PFCandidate, reco::PFTau>(taus->at(tau_index),
0362                                                              tau_index,
0363                                                              tauRef,
0364                                                              electron_collection,
0365                                                              muon_collection,
0366                                                              *pfCands,
0367                                                              vertices->at(0),
0368                                                              *rho,
0369                                                              eventnr,
0370                                                              pred_vector,
0371                                                              tauIDs);
0372           } else
0373             getPredictionsV2<pat::PackedCandidate, pat::Tau>(taus->at(tau_index),
0374                                                              tau_index,
0375                                                              tauRef,
0376                                                              electron_collection,
0377                                                              muon_collection,
0378                                                              *pfCands,
0379                                                              vertices->at(0),
0380                                                              *rho,
0381                                                              eventnr,
0382                                                              pred_vector,
0383                                                              tauIDs);
0384         } else {
0385           throw cms::Exception("DeepTauId") << "version " << version_ << " is not supported.";
0386         }
0387 
0388         for (int k = 0; k < deep_tau::NumberOfOutputs; ++k) {
0389           const float pred = pred_vector[0].flat<float>()(k);
0390           if (!(pred >= 0 && pred <= 1))
0391             throw cms::Exception("DeepTauId")
0392                 << "invalid prediction = " << pred << " for tau_index = " << tau_index << ", pred_index = " << k;
0393           predictions.matrix<float>()(tau_index, k) = pred;
0394         }
0395       } else {
0396         // This else statement was added as a part of the DeepTau@HLT development. It does not affect the current state
0397         // of offline DeepTauId code as there the preselection is not used (it was added in the DeepTau@HLT). It returns
0398         // default values for deepTau score if the preselection failed. Before this statement the values given for this tau
0399         // were random. k == 2 corresponds to the tau score and all other k values to e, mu and jets. By defining in this way
0400         // the final score is -1.
0401         for (int k = 0; k < deep_tau::NumberOfOutputs; ++k) {
0402           predictions.matrix<float>()(tau_index, k) = (k == 2) ? -1.f : 2.f;
0403         }
0404       }
0405     }
0406     return predictions;
0407   }
0408 
0409   template <typename CandidateCastType, typename TauCastType>
0410   void getPredictionsV2(TauCollection::const_reference& tau,
0411                         const size_t tau_index,
0412                         const edm::RefToBase<reco::BaseTau> tau_ref,
0413                         const std::vector<pat::Electron>* electrons,
0414                         const std::vector<pat::Muon>* muons,
0415                         const edm::View<reco::Candidate>& pfCands,
0416                         const reco::Vertex& pv,
0417                         double rho,
0418                         const edm::EventNumber_t& eventnr,
0419                         std::vector<tensorflow::Tensor>& pred_vector,
0420                         TauFunc tau_funcs) {
0421     using namespace dnn_inputs_v2;
0422     if (debug_level >= 2) {
0423       std::cout << "<DeepTauId::getPredictionsV2 (moduleLabel = " << moduleDescription().moduleLabel()
0424                 << ")>:" << std::endl;
0425       std::cout << " tau: pT = " << tau.pt() << ", eta = " << tau.eta() << ", phi = " << tau.phi()
0426                 << ", eventnr = " << eventnr << std::endl;
0427     }
0428     CellGrid inner_grid(number_of_inner_cell, number_of_inner_cell, 0.02, 0.02, disable_CellIndex_workaround_);
0429     CellGrid outer_grid(number_of_outer_cell, number_of_outer_cell, 0.05, 0.05, disable_CellIndex_workaround_);
0430     fillGrids(dynamic_cast<const TauCastType&>(tau), *electrons, inner_grid, outer_grid);
0431     fillGrids(dynamic_cast<const TauCastType&>(tau), *muons, inner_grid, outer_grid);
0432     fillGrids(dynamic_cast<const TauCastType&>(tau), pfCands, inner_grid, outer_grid);
0433 
0434     tauBlockTensor_->flat<float>().setZero();
0435     createTauBlockInputs<CandidateCastType>(
0436         dynamic_cast<const TauCastType&>(tau), tau_index, tau_ref, pv, rho, tau_funcs, *tauBlockTensor_);
0437     checkInputs(*tauBlockTensor_, "input_tau", static_cast<int>(tauBlockTensor_->shape().dim_size(1)));
0438     createConvFeatures<CandidateCastType>(dynamic_cast<const TauCastType&>(tau),
0439                                           tau_index,
0440                                           tau_ref,
0441                                           pv,
0442                                           rho,
0443                                           electrons,
0444                                           muons,
0445                                           pfCands,
0446                                           inner_grid,
0447                                           tau_funcs,
0448                                           true);
0449     checkInputs(*eGammaTensor_[true], "input_inner_egamma", EgammaBlockInputs::NumberOfInputs, &inner_grid);
0450     checkInputs(*muonTensor_[true], "input_inner_muon", MuonBlockInputs::NumberOfInputs, &inner_grid);
0451     checkInputs(*hadronsTensor_[true], "input_inner_hadrons", HadronBlockInputs::NumberOfInputs, &inner_grid);
0452     createConvFeatures<CandidateCastType>(dynamic_cast<const TauCastType&>(tau),
0453                                           tau_index,
0454                                           tau_ref,
0455                                           pv,
0456                                           rho,
0457                                           electrons,
0458                                           muons,
0459                                           pfCands,
0460                                           outer_grid,
0461                                           tau_funcs,
0462                                           false);
0463     checkInputs(*eGammaTensor_[false], "input_outer_egamma", EgammaBlockInputs::NumberOfInputs, &outer_grid);
0464     checkInputs(*muonTensor_[false], "input_outer_muon", MuonBlockInputs::NumberOfInputs, &outer_grid);
0465     checkInputs(*hadronsTensor_[false], "input_outer_hadrons", HadronBlockInputs::NumberOfInputs, &outer_grid);
0466 
0467     if (save_inputs_) {
0468       std::string json_file_name = "DeepTauId_" + std::to_string(eventnr) + "_" + std::to_string(tau_index) + ".json";
0469       json_file_ = new std::ofstream(json_file_name.data());
0470       is_first_block_ = true;
0471       (*json_file_) << "{";
0472       saveInputs(*tauBlockTensor_, "input_tau", static_cast<int>(tauBlockTensor_->shape().dim_size(1)));
0473       saveInputs(*eGammaTensor_[true], "input_inner_egamma", EgammaBlockInputs::NumberOfInputs, &inner_grid);
0474       saveInputs(*muonTensor_[true], "input_inner_muon", MuonBlockInputs::NumberOfInputs, &inner_grid);
0475       saveInputs(*hadronsTensor_[true], "input_inner_hadrons", HadronBlockInputs::NumberOfInputs, &inner_grid);
0476       saveInputs(*eGammaTensor_[false], "input_outer_egamma", EgammaBlockInputs::NumberOfInputs, &outer_grid);
0477       saveInputs(*muonTensor_[false], "input_outer_muon", MuonBlockInputs::NumberOfInputs, &outer_grid);
0478       saveInputs(*hadronsTensor_[false], "input_outer_hadrons", HadronBlockInputs::NumberOfInputs, &outer_grid);
0479       (*json_file_) << "}";
0480       delete json_file_;
0481       ++file_counter_;
0482     }
0483 
0484     tensorflow::run(&(cache_->getSession("core")),
0485                     {{"input_tau", *tauBlockTensor_},
0486                      {"input_inner", *convTensor_.at(true)},
0487                      {"input_outer", *convTensor_.at(false)}},
0488                     {"main_output/Softmax"},
0489                     &pred_vector);
0490     if (debug_level >= 1) {
0491       std::cout << "output = { ";
0492       for (int idx = 0; idx < deep_tau::NumberOfOutputs; ++idx) {
0493         if (idx > 0)
0494           std::cout << ", ";
0495         std::string label;
0496         if (idx == 0)
0497           label = "e";
0498         else if (idx == 1)
0499           label = "mu";
0500         else if (idx == 2)
0501           label = "tau";
0502         else if (idx == 3)
0503           label = "jet";
0504         else
0505           assert(0);
0506         std::cout << label << " = " << pred_vector[0].flat<float>()(idx);
0507       }
0508       std::cout << " }" << std::endl;
0509     }
0510   }
0511 
0512   tensorflow::Tensor getPartialPredictions(bool is_inner) {
0513     std::vector<tensorflow::Tensor> pred_vector;
0514     if (is_inner) {
0515       tensorflow::run(&(cache_->getSession("inner")),
0516                       {
0517                           {"input_inner_egamma", *eGammaTensor_.at(is_inner)},
0518                           {"input_inner_muon", *muonTensor_.at(is_inner)},
0519                           {"input_inner_hadrons", *hadronsTensor_.at(is_inner)},
0520                       },
0521                       {"inner_all_dropout_4/Identity"},
0522                       &pred_vector);
0523     } else {
0524       tensorflow::run(&(cache_->getSession("outer")),
0525                       {
0526                           {"input_outer_egamma", *eGammaTensor_.at(is_inner)},
0527                           {"input_outer_muon", *muonTensor_.at(is_inner)},
0528                           {"input_outer_hadrons", *hadronsTensor_.at(is_inner)},
0529                       },
0530                       {"outer_all_dropout_4/Identity"},
0531                       &pred_vector);
0532     }
0533 
0534     return pred_vector.at(0);
0535   }
0536 
0537   template <typename CandidateCastType, typename TauCastType>
0538   void createConvFeatures(const TauCastType& tau,
0539                           const size_t tau_index,
0540                           const edm::RefToBase<reco::BaseTau> tau_ref,
0541                           const reco::Vertex& pv,
0542                           double rho,
0543                           const std::vector<pat::Electron>* electrons,
0544                           const std::vector<pat::Muon>* muons,
0545                           const edm::View<reco::Candidate>& pfCands,
0546                           const CellGrid& grid,
0547                           TauFunc tau_funcs,
0548                           bool is_inner) {
0549     if (debug_level >= 2) {
0550       std::cout << "<DeepTauId::createConvFeatures (is_inner = " << is_inner << ")>:" << std::endl;
0551       std::cout << "number of valid cells = " << grid.num_valid_cells() << std::endl;
0552     }
0553 
0554     const size_t n_valid_cells = grid.num_valid_cells();
0555     tensorflow::Tensor predTensor;
0556     tensorflow::Tensor& convTensor = *convTensor_.at(is_inner);
0557 
0558     //check if at least one input is there to
0559     //avoid calling TF with empty grid #TODO understand why the grid is empty
0560     if (n_valid_cells > 0) {
0561       eGammaTensor_[is_inner] = std::make_unique<tensorflow::Tensor>(
0562           tensorflow::DT_FLOAT,
0563           tensorflow::TensorShape{
0564               (long long int)grid.num_valid_cells(), 1, 1, dnn_inputs_v2::EgammaBlockInputs::NumberOfInputs});
0565       muonTensor_[is_inner] = std::make_unique<tensorflow::Tensor>(
0566           tensorflow::DT_FLOAT,
0567           tensorflow::TensorShape{
0568               (long long int)grid.num_valid_cells(), 1, 1, dnn_inputs_v2::MuonBlockInputs::NumberOfInputs});
0569       hadronsTensor_[is_inner] = std::make_unique<tensorflow::Tensor>(
0570           tensorflow::DT_FLOAT,
0571           tensorflow::TensorShape{
0572               (long long int)grid.num_valid_cells(), 1, 1, dnn_inputs_v2::HadronBlockInputs::NumberOfInputs});
0573 
0574       eGammaTensor_[is_inner]->flat<float>().setZero();
0575       muonTensor_[is_inner]->flat<float>().setZero();
0576       hadronsTensor_[is_inner]->flat<float>().setZero();
0577 
0578       unsigned idx = 0;
0579       for (int eta = -grid.maxEtaIndex(); eta <= grid.maxEtaIndex(); ++eta) {
0580         for (int phi = -grid.maxPhiIndex(); phi <= grid.maxPhiIndex(); ++phi) {
0581           if (debug_level >= 2) {
0582             std::cout << "processing ( eta = " << eta << ", phi = " << phi << " )" << std::endl;
0583           }
0584           const CellIndex cell_index{eta, phi};
0585           const auto cell_iter = grid.find(cell_index);
0586           if (cell_iter != grid.end()) {
0587             if (debug_level >= 2) {
0588               std::cout << " creating inputs for ( eta = " << eta << ", phi = " << phi << " ): idx = " << idx
0589                         << std::endl;
0590             }
0591             const Cell& cell = cell_iter->second;
0592             createEgammaBlockInputs<CandidateCastType>(idx,
0593                                                        tau,
0594                                                        tau_index,
0595                                                        tau_ref,
0596                                                        pv,
0597                                                        rho,
0598                                                        electrons,
0599                                                        pfCands,
0600                                                        cell,
0601                                                        tau_funcs,
0602                                                        is_inner,
0603                                                        *eGammaTensor_[is_inner]);
0604             createMuonBlockInputs<CandidateCastType>(
0605                 idx, tau, tau_index, tau_ref, pv, rho, muons, pfCands, cell, tau_funcs, is_inner, *muonTensor_[is_inner]);
0606             createHadronsBlockInputs<CandidateCastType>(
0607                 idx, tau, tau_index, tau_ref, pv, rho, pfCands, cell, tau_funcs, is_inner, *hadronsTensor_[is_inner]);
0608             idx += 1;
0609           } else {
0610             if (debug_level >= 2) {
0611               std::cout << " skipping creation of inputs, because ( eta = " << eta << ", phi = " << phi
0612                         << " ) is not in the grid !!" << std::endl;
0613             }
0614           }
0615         }
0616       }
0617       // Calling TF prediction only if n_valid_cells > 0
0618       predTensor = getPartialPredictions(is_inner);
0619     }
0620 
0621     unsigned idx = 0;
0622     for (int eta = -grid.maxEtaIndex(); eta <= grid.maxEtaIndex(); ++eta) {
0623       for (int phi = -grid.maxPhiIndex(); phi <= grid.maxPhiIndex(); ++phi) {
0624         const CellIndex cell_index{eta, phi};
0625         const int eta_index = grid.getEtaTensorIndex(cell_index);
0626         const int phi_index = grid.getPhiTensorIndex(cell_index);
0627 
0628         const auto cell_iter = grid.find(cell_index);
0629         if (cell_iter != grid.end()) {
0630           setCellConvFeatures(convTensor, predTensor, idx, eta_index, phi_index);
0631           idx += 1;
0632         } else {
0633           setCellConvFeatures(convTensor, *zeroOutputTensor_[is_inner], 0, eta_index, phi_index);
0634         }
0635       }
0636     }
0637   }
0638 
0639   void setCellConvFeatures(tensorflow::Tensor& convTensor,
0640                            const tensorflow::Tensor& features,
0641                            unsigned batch_idx,
0642                            int eta_index,
0643                            int phi_index) {
0644     for (int n = 0; n < dnn_inputs_v2::number_of_conv_features; ++n) {
0645       convTensor.tensor<float, 4>()(0, eta_index, phi_index, n) = features.tensor<float, 4>()(batch_idx, 0, 0, n);
0646     }
0647   }
0648 
0649 private:
0650   const deep_tau::DeepTauCache* cache_;
0651 
0652   std::unique_ptr<tensorflow::Tensor> tauBlockTensor_;
0653   std::array<std::unique_ptr<tensorflow::Tensor>, 2> eGammaTensor_, muonTensor_, hadronsTensor_, convTensor_,
0654       zeroOutputTensor_;
0655 };
0656 
0657 #include "FWCore/Framework/interface/MakerMacros.h"
0658 DEFINE_FWK_MODULE(DeepTauId);