ATLAS Offline Software
Loading...
Searching...
No Matches
GNN.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
11
13
14namespace {
15 auto getSaltModel(const std::string& nn_file) {
16 using namespace FlavorTagInference;
17 std::string fullPathToOnnxFile = PathResolverFindCalibFile(nn_file);
18 auto saltShared = std::make_shared<const SaltModel>(fullPathToOnnxFile);
19 ISaltModelPtr retPtr = saltShared;
20 return retPtr;
21 }
22
23 template <typename T>
24 std::string join(const T& c) {
25 std::string out;
26 std::string sep = "";
27 for (const auto& [k, v]: c) {
28 out.append(sep);
29 sep = ", ";
30 out.append(k);
31 }
32 return out;
33 }
34}
35
36namespace FlavorTagInference {
37
38 GNN::GNN(const std::string& nn_file, const GNNOptions& o):
39 GNN(getSaltModel(nn_file), o)
40 {
41 }
42
43 GNN::GNN(const GNN& old, const GNNOptions& o):
44 GNN(old.m_saltModel, o)
45 {
46 }
47
51 {
52 // Retrieve the configuration for the model outputs.
53 OutputConfig gnn_output_config = m_saltModel->getOutputConfig();
54
55 // Create the output decorators.
56 auto [dd, rd] = createDecorators(gnn_output_config, m_dataLoader.ftag_options);
57 m_dataLoader.data_dependency_names += dd;
58
59 // Update dependencies and used remap from the constituents loaders.
60 for (const auto& loader : m_dataLoader.vectorVarLoaders) {
61 auto loader_name = loader.first;
62 auto constituent_loader = loader.second;
63 m_dataLoader.data_dependency_names += constituent_loader->getDependencies();
64 std::set<std::string> used_remap = constituent_loader->getUsedRemap();
65 rd.merge(used_remap);
66 }
67 dataprep::checkForUnusedRemaps(m_dataLoader.ftag_options.remap_scalar, rd);
68
69 // Build the default decorators. Note that this _must_ be called
70 // after createDecorators.
71 auto unused_defaults = o.default_output_values;
72 for (const auto& [name, dec]: m_decorators.jetFloat) {
73 float default_value = o.default_output_value;
74 if (auto def = unused_defaults.extract(name)) {
75 default_value = def.mapped();
76 }
77 m_defaultValues.emplace_back(dec, default_value);
78 }
79 if (!unused_defaults.empty()) {
80 throw std::runtime_error(
81 "unused default values: [" + join(unused_defaults) + "]");
82 }
84 }
85
86 GNN::GNN(const std::string& file,
87 const FlipTagConfig& flip,
88 const std::map<std::string, std::string>& remap,
89 float def_out_val):
90 GNN( file, GNNOptions { flip, remap, def_out_val, {}, false} )
91 {}
92
93 GNN::GNN(GNN&&) = default;
94 GNN::GNN(const GNN&) = default;
95 GNN::~GNN() = default;
96
97 void GNN::decorateWithDefaults(const xAOD::IParticle& i_jet) const {
98 for (const auto& [dec, v]: m_defaultValues) {
99 dec(i_jet) = v;
100 }
101 // for some networks we need to set a lot of empty vectors as well
102 if (m_saltModel->getSaltModelVersion() == SaltModelVersion::V1
103 || m_saltModel->getSaltModelVersion() == SaltModelVersion::V2) {
104 // vector outputs, e.g. track predictions
105 for (const auto& dec: m_decorators.jetVecChar) {
106 dec.second(i_jet) = {};
107 }
108 for (const auto& dec: m_decorators.jetVecFloat) {
109 dec.second(i_jet) = {};
110 }
111 for (const auto& [name, loader] : m_dataLoader.vectorVarLoaders) {
112 loader->setDefaults(i_jet);
113 }
114 for (const auto& dec: m_decorators.jetVecInt) {
115 dec.second(i_jet) = {};
116 }
117 for (const auto& dec: m_decorators.jetVecTruncFloat) {
118 dec.second(i_jet) = {};
119 }
120 }
121 }
122
123 void GNN::decorate(const xAOD::IParticle& i_jet) const {
124 /* Main function for decorating a i_jet object with GNN outputs. */
125 SaltModelData salt_model_data = m_dataLoader.loadInputs(&i_jet);
126 // DumpGnnInputs(salt_model_data.gnn_inputs);
127
128 // run inference
129 // -------------
130 if (m_defaultZeroTracks && salt_model_data.num_inputs == 0) {
131 this->decorateWithDefaults(i_jet);
132 return;
133 }
134 auto [out_f, out_vc, out_vf] = m_saltModel->runInference(salt_model_data.gnn_inputs);
135
136 // decorate outputs
137 // ----------------
138
139 // with old metadata, doesn't support writing aux tasks
140 if (m_saltModel->getSaltModelVersion() == SaltModelVersion::V0) {
141 for (const auto& dec: m_decorators.jetFloat) {
142 if (out_vf.at(dec.first).size() != 1){
143 throw std::logic_error("expected vectors of length 1 for float decorators");
144 }
145 dec.second(i_jet) = out_vf.at(dec.first).at(0);
146 }
147 }
148 // the new metadata format supports writing aux tasks
149 else if (m_saltModel->getSaltModelVersion() == SaltModelVersion::V1
150 || m_saltModel->getSaltModelVersion() == SaltModelVersion::V2) {
151 // float outputs, e.g. i_jet probabilities
152 for (const auto& dec: m_decorators.jetFloat) {
153 dec.second(i_jet) = out_f.at(dec.first);
154 }
155 // vector outputs, e.g. track predictions
156 for (const auto& dec: m_decorators.jetVecChar) {
157 dec.second(i_jet) = out_vc.at(dec.first);
158 }
159 for (const auto& dec: m_decorators.jetVecFloat) {
160 dec.second(i_jet) = out_vf.at(dec.first);
161 }
162 for (const auto& dec: m_decorators.jetVecInt) {
163 const auto& floats = out_vf.at(dec.first);
164 std::vector<int> ints(floats.begin(), floats.end());
165 dec.second(i_jet) = ints;
166 }
167 for (size_t idx = 0; idx < m_decorators.jetVecTruncFloat.size(); ++idx) {
168 const auto& dec = m_decorators.jetVecTruncFloat[idx];
169 const auto& floats = out_vf.at(dec.first);
170 const float scale = m_truncFloatScales[idx];
171 const int E = m_truncFloatBits[idx].first;
172 const int M = m_truncFloatBits[idx].second;
173 std::vector<float> truncated(floats.size());
174 for (size_t i = 0; i < floats.size(); ++i) {
175 truncated[i] = FPCompressionUtils::truncateToFloat(floats[i] * scale, E, M);
176 }
177 dec.second(i_jet) = truncated;
178 }
179
180 }
181 else {
182 throw std::logic_error("unsupported ONNX metadata version");
183 }
184 } // end of decorate()
185
186 // Dependencies
188 return m_dataLoader.data_dependency_names;
189 }
190
191 std::tuple<FTagDataDependencyNames, std::set<std::string>>
192 GNN::createDecorators(const OutputConfig& outConfig, const FTagOptions& options) {
194 Decorators decs;
195
196 std::map<std::string, std::string> remap = options.remap_scalar;
197 std::set<std::string> usedRemap;
198
199 // get the regex to rewrite the outputs if we're using flip taggers
200 auto flip_converters = dataprep::getNameFlippers(options.flip);
201 std::string context = "building negative tag b-btagger";
202
203 for (const auto& outNode : outConfig) {
204 // the node's output name will be used to define the decoration name
205 std::string dec_name = outNode.name;
206
207 // modify the deco name if we're using flip taggers
208 if (options.flip != FlipTagConfig::STANDARD) {
209 dec_name = str::sub_first(flip_converters, dec_name, context);
210 }
211
212 // remap the deco name if necessary
213 dec_name = str::remapName(dec_name, remap, usedRemap);
214
215 // keep track of dependencies for EDM bookkeeping
216 deps.bTagOutputs.insert(dec_name);
217
218 // Create decorators based on output type and target
219 switch (outNode.type) {
221 m_decorators.jetFloat.emplace_back(outNode.name, Dec<float>(dec_name));
222 break;
224 m_decorators.jetVecChar.emplace_back(outNode.name, Dec<std::vector<char>>(dec_name));
225 break;
227 m_decorators.jetVecFloat.emplace_back(outNode.name, Dec<std::vector<float>>(dec_name));
228 break;
230 m_decorators.jetVecInt.emplace_back(outNode.name, Dec<std::vector<int>>(dec_name));
231 break;
233 m_decorators.jetVecTruncFloat.emplace_back(outNode.name, Dec<std::vector<float>>(dec_name));
234 m_truncFloatScales.push_back(outNode.scale);
235 m_truncFloatBits.emplace_back(outNode.exp_bits, outNode.man_bits);
236 break;
237 default:
238 throw std::logic_error("Unknown output data type");
239 }
240 }
241
242 return std::make_tuple(deps, usedRemap);
243 }
244
245} // end of namespace FlavorTagInference
std::string PathResolverFindCalibFile(const std::string &logical_file_name)
std::tuple< FTagDataDependencyNames, std::set< std::string > > createDecorators(const OutputConfig &outConfig, const FTagOptions &options)
Definition GNN.cxx:192
bool m_defaultZeroTracks
Definition GNN.h:89
std::vector< std::pair< int, int > > m_truncFloatBits
Definition GNN.h:87
std::vector< float > m_truncFloatScales
Definition GNN.h:86
ISaltModelPtr m_saltModel
Definition GNN.h:81
GNNDataLoader m_dataLoader
Definition GNN.h:83
Decorators m_decorators
Definition GNN.h:85
virtual void decorateWithDefaults(const xAOD::IParticle &jet) const
Definition GNN.cxx:97
SG::Decorator< T > Dec
Definition GNN.h:62
virtual void decorate(const xAOD::IParticle &i_jet) const
Definition GNN.cxx:123
GNN(const std::string &nnFile, const GNNOptions &opts)
Definition GNN.cxx:38
FTagDataDependencyNames getDependencies() const
Definition GNN.cxx:187
std::vector< std::pair< Dec< float >, float > > m_defaultValues
Definition GNN.h:88
Class providing the definition of the 4-vector interface.
std::map< std::string, std::string > remap
list of directories to be explicitly remapped
Definition hcg.cxx:97
float truncateToFloat(float val, int exp_bits, int mantissa_bits)
void checkForUnusedRemaps(const std::map< std::string, std::string > &requested, const std::set< std::string > &used)
const std::string remapName(const std::string &name, std::map< std::string, std::string > &remap, std::set< std::string > &usedRemap)
std::string sub_first(const StringRegexes &res, const std::string &var_name, const std::string &context)
This file contains "getter" functions used for accessing tagger inputs from the EDM.
std::vector< SaltModelOutput > OutputConfig
Definition ISaltModel.h:38
std::shared_ptr< const ISaltModel > ISaltModelPtr
Definition ISaltModel.h:56
std::string join(const std::vector< std::string > &v, const char c=',')
std::map< std::string, float > default_output_values
Definition GNNOptions.h:19
TFile * file