Belle II Software development
PIDNeuralNetwork.cc
1/**************************************************************************
2 * basf2 (Belle II Analysis Software Framework) *
3 * Author: The Belle II Collaboration *
4 * *
5 * See git log for contributors and copyright holders. *
6 * This file is licensed under LGPL-3.0, see LICENSE.md. *
7 **************************************************************************/
8
9#include <analysis/utility/PIDNeuralNetwork.h>
10
11#include <framework/gearbox/Const.h>
12
13#include <cmath>
14
15using namespace Belle2;
16
17
19{
20 m_pidNeuralNetworkParametersDB = std::make_unique<DBObjPtr<PIDNeuralNetworkParameters>>(m_pidNeuralNetworkParametersName);
21
23 B2FATAL("The dbobject PIDNeuralNetworkParameters, " << m_pidNeuralNetworkParametersName <<
24 ", could not be found! It is necessary for the neural network based PID variables.");
25
26 m_model = std::make_unique<fdeep::model>(fdeep::read_model_from_string((*m_pidNeuralNetworkParametersDB)->getModelDefinition(),
27 false,
28 [](const std::string&) {} // disable logger
29 ));
30
31 // Rename some of the input variables such that they match the basf2 internal names
32 // This is needed for backwards compatibility with older payloads where the input variable names are different from the basf2 internal names
33 std::map<std::string, std::string> inputNameMap; // maps old -> new names
34 for (const Const::EDetector& detector : Const::PIDDetectorSet::set()) {
35 for (const auto& hypeType : Const::chargedStableSet) {
36 const auto oldName = "pidLogLikelihood_Of_" + std::to_string(abs(hypeType.getPDGCode())) + "_From_" + Const::parseDetectors(
37 detector);
38 const auto newName = "pidLogLikelihoodValueExpert(" + std::to_string(abs(hypeType.getPDGCode())) + ',' + Const::parseDetectors(
39 detector) + ")";
40 inputNameMap[oldName] = newName;
41 }
42 }
43 inputNameMap["momentum"] = "p";
44
45 // Build list of input variable names in Basf2 naming scheme
47 for (std::string name : (*m_pidNeuralNetworkParametersDB)->getInputNames()) {
48 const auto itr = inputNameMap.find(name);
49 if (itr != inputNameMap.end()) name = itr->second;
50 m_inputBasf2Names.push_back(name);
51 }
52
53 // Build extraInfo names for this network for all predicted PDG codes
54 for (const auto outputPdgCode : getOutputSpeciesPdg()) {
55 m_extraInfoNames[outputPdgCode] = "pidNeuralNetworkValueExpert(" + std::to_string(outputPdgCode) \
57 }
58}
59
60
61std::map<int, double> PIDNeuralNetwork::predict(std::vector<float> input) const
62{
63
64 // apply cuts, ie. overwrite certain input values with index `inputSetIndex` with the value `setValue`
65 // if the input with index `inputCutIndex` is in the range (`rangeStart`, `rangeEnd`)
66 for (auto const& inputToCut : (*m_pidNeuralNetworkParametersDB)->getInputsToCut()) {
67 const auto [inputSetIndex, inputCutIndex, rangeStart, rangeEnd, setValue] = inputToCut;
68 if (!std::isnan(rangeStart) and !std::isnan(rangeEnd)) {
69 if (input[inputCutIndex] >= rangeStart and input[inputCutIndex] <= rangeEnd)
70 input[inputSetIndex] = setValue;
71 } else if (!std::isnan(rangeStart)) {
72 if (input[inputCutIndex] >= rangeStart)
73 input[inputSetIndex] = setValue;
74 } else if (!std::isnan(rangeEnd)) {
75 if (input[inputCutIndex] <= rangeEnd)
76 input[inputSetIndex] = setValue;
77 }
78 }
79
80 // Normalize inputs
81 // By definition, this has to be done after applying the cuts and before handling missing information
82 for (size_t i = 0; i < input.size(); ++i) {
83 input[i] = (input[i] - (*m_pidNeuralNetworkParametersDB)->getMeanValues()[i]) /
84 (*m_pidNeuralNetworkParametersDB)->getStandardDeviations()[i];
85 }
86
87 // handle missing information
88 for (auto const& index_value : (*m_pidNeuralNetworkParametersDB)->getHandleMissingInputs()) {
89 const auto [index, value] = index_value;
90 if (std::isnan(input[index])) input[index] = value;
91 }
92
93 // apply neural network
94 const auto inputFdeep = fdeep::tensor(fdeep::tensor_shape(input.size()), input);
95 const auto result = m_model->predict({inputFdeep});
96
97 std::map<int, double> probabilities;
98 for (const auto pdgCode : getOutputSpeciesPdg()) {
99 const int outputIndex = (*m_pidNeuralNetworkParametersDB)->pdg2OutputIndex(pdgCode);
100 probabilities[pdgCode] = result.front().get(fdeep::tensor_pos(outputIndex));
101 }
102 return probabilities;
103}
static DetectorSet set()
Accessor for the set of valid detector IDs.
Definition: Const.h:333
static const ParticleSet chargedStableSet
set of charged stable particles
Definition: Const.h:618
EDetector
Enum for identifying the detector components (detector and subdetector).
Definition: Const.h:42
static std::string parseDetectors(EDetector det)
Converts Const::EDetector object to string.
Definition: UnitConst.cc:161
size_t getInputSize() const
Get number of inputs.
std::vector< std::string > m_inputBasf2Names
list of input names of input variables in the basf2 naming scheme
std::string m_pidNeuralNetworkParametersName
name of the parameter set
void loadParametersFromDB()
Load neural-network parameters with name m_pidNeuralNetworkParametersName from the conditions data ba...
std::map< int, double > predict(std::vector< float > inputs) const
Predict neural-network output for all implemented hypotheses using the given inputs.
std::unique_ptr< const fdeep::model > m_model
frugally-deep neural network
const std::vector< int > & getOutputSpeciesPdg() const
Get the list of pdg codes of species hypotheses, for which the network predicts the probability in th...
std::map< int, std::string > m_extraInfoNames
map from PDG code to extraInfo name that stores the output of this network
std::unique_ptr< DBObjPtr< PIDNeuralNetworkParameters > > m_pidNeuralNetworkParametersDB
db object for the parameter set
Abstract base class for different kinds of events.