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 <cmath>
12
13
14using namespace Belle2;
15
16
18{
19 m_pidNeuralNetworkParametersDB = std::make_unique<DBObjPtr<PIDNeuralNetworkParameters>>(m_pidNeuralNetworkParametersName);
20
22 B2FATAL("The dbobject PIDNeuralNetworkParameters, " << m_pidNeuralNetworkParametersName <<
23 ", could not be found! It is necessary for the neural network based PID variables.");
24
25 m_model = std::make_unique<fdeep::model>(fdeep::read_model_from_string((*m_pidNeuralNetworkParametersDB)->getModelDefinition(),
26 false,
27 [](const std::string&) {} // disable logger
28 ));
29
30 // Rename some of the input variables such that they match the basf2 internal names
31 // This is needed for backwards compatibility with older payloads where the input variable names are different from the basf2 internal names
32 std::map<std::string, std::string> inputNameMap; // maps old -> new names
33 for (const Const::EDetector& detector : Const::PIDDetectorSet::set()) {
34 for (const auto& hypeType : Const::chargedStableSet) {
35 const auto oldName = "pidLogLikelihood_Of_" + std::to_string(abs(hypeType.getPDGCode())) + "_From_" + Const::parseDetectors(
36 detector);
37 const auto newName = "pidLogLikelihoodValueExpert(" + std::to_string(abs(hypeType.getPDGCode())) + ',' + Const::parseDetectors(
38 detector) + ")";
39 inputNameMap[oldName] = newName;
40 }
41 }
42 inputNameMap["momentum"] = "p";
43
44 // Build list of input variable names in Basf2 naming scheme
46 for (std::string name : (*m_pidNeuralNetworkParametersDB)->getInputNames()) {
47 const auto itr = inputNameMap.find(name);
48 if (itr != inputNameMap.end()) name = itr->second;
49 m_inputBasf2Names.push_back(name);
50 }
51
52 // Build extraInfo names for this network for all predicted PDG codes
53 for (const auto outputPdgCode : getOutputSpeciesPdg()) {
54 m_extraInfoNames[outputPdgCode] = "pidNeuralNetworkValueExpert(" + std::to_string(outputPdgCode) \
56 }
57}
58
59
60std::map<int, double> PIDNeuralNetwork::predict(std::vector<float> input) const
61{
62
63 // apply cuts, ie. overwrite certain input values with index `inputSetIndex` with the value `setValue`
64 // if the input with index `inputCutIndex` is in the range (`rangeStart`, `rangeEnd`)
65 for (auto const& inputToCut : (*m_pidNeuralNetworkParametersDB)->getInputsToCut()) {
66 const auto [inputSetIndex, inputCutIndex, rangeStart, rangeEnd, setValue] = inputToCut;
67 if (!std::isnan(rangeStart) and !std::isnan(rangeEnd)) {
68 if (input[inputCutIndex] >= rangeStart and input[inputCutIndex] <= rangeEnd)
69 input[inputSetIndex] = setValue;
70 } else if (!std::isnan(rangeStart)) {
71 if (input[inputCutIndex] >= rangeStart)
72 input[inputSetIndex] = setValue;
73 } else if (!std::isnan(rangeEnd)) {
74 if (input[inputCutIndex] <= rangeEnd)
75 input[inputSetIndex] = setValue;
76 }
77 }
78
79 // Normalize inputs
80 // By definition, this has to be done after applying the cuts and before handling missing information
81 for (size_t i = 0; i < input.size(); ++i) {
82 input[i] = (input[i] - (*m_pidNeuralNetworkParametersDB)->getMeanValues()[i]) /
83 (*m_pidNeuralNetworkParametersDB)->getStandardDeviations()[i];
84 }
85
86 // handle missing information
87 for (auto const& index_value : (*m_pidNeuralNetworkParametersDB)->getHandleMissingInputs()) {
88 const auto [index, value] = index_value;
89 if (std::isnan(input[index])) input[index] = value;
90 }
91
92 // apply neural network
93 const auto inputFdeep = fdeep::tensor(fdeep::tensor_shape(input.size()), input);
94 const auto result = m_model->predict({inputFdeep});
95
96 std::map<int, double> probabilities;
97 for (const auto pdgCode : getOutputSpeciesPdg()) {
98 const int outputIndex = (*m_pidNeuralNetworkParametersDB)->pdg2OutputIndex(pdgCode);
99 probabilities[pdgCode] = result.front().get(fdeep::tensor_pos(outputIndex));
100 }
101 return probabilities;
102}
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:162
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.