ATLAS Offline Software
Loading...
Searching...
No Matches
InferenceConfig.py
Go to the documentation of this file.
1# Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
2
3from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
4from AthenaConfiguration.ComponentFactory import CompFactory
5
6DEFAULT_BUCKET_MODEL_PATH = "dev/MuonRecRTT/edgecnn_mu200.onnx"
7DEFAULT_BUCKET_SCORE_THRESHOLD = 0.160
8DEFAULT_BUCKET_SINGLE_OUTPUT_MODE = "logit"
9
10def MuonLearningOnnxRuntimeSvcCfg(flags, name="OnnxRuntimeSvc", **kwargs):
11 """Configure the shared ONNX Runtime service used by MuonLearning tools."""
12 result = ComponentAccumulator()
13 kwargs.setdefault("LogLevel", 3)
14 svc = CompFactory.AthOnnx.OnnxRuntimeSvc(name, **kwargs)
15 result.addService(svc, primary=False, create=True)
16 return result
17
18def GraphInferenceAlgCfg(flags, name = "GraphInferenceAlg", **kwargs):
19 result = ComponentAccumulator()
20 the_alg = CompFactory.MuonML.InferenceAlg(name, **kwargs)
21 result.addEventAlgo(the_alg, primary = True)
22 return result
23
24def GraphSPFilterToolCfg(flags, name ="GraphSPFilterTool", **kwargs):
25
26 from AthOnnxComps.OnnxRuntimeSessionConfig import OnnxRuntimeSessionToolCfg
27
28 result = ComponentAccumulator()
29 kwargs.setdefault("ModelSession", result.popToolsAndMerge(OnnxRuntimeSessionToolCfg(flags, model_fname="/eos/atlas/atlascerngroupdisk/data-art/grid-input/MuonRecRTT/TestModel.onnx")))
30 kwargs.setdefault("MLFilterCut", -3.6) # Working point cut
31
32 the_tool = CompFactory.MuonML.GraphSPFilterTool(name, **kwargs)
33 result.setPrivateTools(the_tool)
34 return result
35
36def GraphBucketFilterToolCfg(flags, name ="GraphBucketFilterTool", **kwargs):
37
38 from AthOnnxComps.OnnxRuntimeSessionConfig import OnnxRuntimeSessionToolCfg
39
40 result = ComponentAccumulator()
41 model_path = kwargs.pop("ModelPath", DEFAULT_BUCKET_MODEL_PATH)
42 single_output_mode = kwargs.pop("SingleOutputMode", None)
43 if single_output_mode is not None:
44 if "SingleOutputIsLogit" in kwargs:
45 raise ValueError(
46 "Specify either SingleOutputMode or SingleOutputIsLogit, not both."
47 )
48 if single_output_mode not in ("logit", "prob"):
49 raise ValueError(
50 "SingleOutputMode must be 'logit' or 'prob', got "
51 f"{single_output_mode!r}."
52 )
53 kwargs["SingleOutputIsLogit"] = (single_output_mode == "logit")
54
55 result.merge(MuonLearningOnnxRuntimeSvcCfg(flags))
56 kwargs.setdefault("ModelSession", result.popToolsAndMerge(
57 OnnxRuntimeSessionToolCfg(flags, model_fname=model_path,
58 OnnxRuntimeSvc=result.getService("OnnxRuntimeSvc"))))
59 kwargs.setdefault("OutputLevel", 3) # INFO level (1=VERBOSE, 2=DEBUG, 3=INFO, 4=WARNING, 5=ERROR, 6=FATAL)
60 kwargs.setdefault("ScoreThreshold", DEFAULT_BUCKET_SCORE_THRESHOLD)
61 kwargs.setdefault("OutputName", "logits")
62 kwargs.setdefault("SingleOutputIsLogit", DEFAULT_BUCKET_SINGLE_OUTPUT_MODE == "logit")
63
64 the_tool = CompFactory.MuonML.GraphBucketFilterTool(name, **kwargs)
65 result.setPrivateTools(the_tool)
66 return result
67
68
69def SegmentEdgeClassifierToolCfg(flags, name="SegmentEdgeClassifierTool", **kwargs):
70 from AthOnnxComps.OnnxRuntimeSessionConfig import OnnxRuntimeSessionToolCfg
71
72 result = ComponentAccumulator()
73 model_path = kwargs.pop("ModelPath", "MuonInference/models/edge_gnn_refit_top01_from_t0020.onnx")
74 result.merge(MuonLearningOnnxRuntimeSvcCfg(flags))
75 kwargs.setdefault("ModelSession", result.popToolsAndMerge(
76 OnnxRuntimeSessionToolCfg(flags, model_fname=model_path,
77 OnnxRuntimeSvc=result.getService("OnnxRuntimeSvc"))))
78 # Keep the same ONNX/model properties used by GraphBucketFilterToolCfg in this file.
79 kwargs.setdefault("InputNodeName", "x")
80 kwargs.setdefault("InputEdgeIndexName", "edge_index")
81 kwargs.setdefault("InputEdgeAttrName", "edge_attr")
82 kwargs.setdefault("OutputName", "logits")
83 kwargs.setdefault("MaxDeltaThetaDeg", 35.0)
84 kwargs.setdefault("MaxDeltaSector", 1)
85 kwargs.setdefault("SectorModulo", 16)
86 kwargs.setdefault("ReadSpacePoints", "MuonSpacePoints")
87 tool = CompFactory.MuonML.SegmentEdgeClassifierTool(name, **kwargs)
88 result.setPrivateTools(tool)
89 return result
90
91
92def SegmentTrackCandidateBuilderToolCfg(flags, name="SegmentTrackCandidateBuilderTool", **kwargs):
93 result = ComponentAccumulator()
94 # High-purity candidate cores are built with OverlapThreshold.
95 # A second low-threshold recovery pass is added with EdgeThreshold.
96 # This strongly reduces candidate loss from borderline true edges.
97 kwargs.setdefault("EdgeThreshold", 0.25)
98 kwargs.setdefault("OverlapThreshold", 0.8)
99 kwargs.setdefault("UseRecoveryComponents", True)
100 kwargs.setdefault("SymmetrizeDirectedEdges", True)
101 kwargs.setdefault("AddAllSegmentsRecoveryCandidate", False)
102 kwargs.setdefault("KeepIsolatedSegments", False)
103 kwargs.setdefault("MinCandidateSize", 2)
104 tool = CompFactory.MuonML.SegmentTrackCandidateBuilderTool(name, **kwargs)
105 result.setPrivateTools(tool)
106 return result
107
108
109def SegmentEdgeInferenceAlgCfg(flags, name="SegmentEdgeInferenceAlg", **kwargs):
110 result = ComponentAccumulator()
111 # Accept EdgeModelPath as a convenience shortcut so callers don't need to
112 # build the tool object themselves; a raw dict is also unwrapped for
113 # backwards-compatibility with call-sites that used dict syntax.
114 edge_tool_kwargs = {}
115 if "EdgeModelPath" in kwargs:
116 edge_tool_kwargs["ModelPath"] = kwargs.pop("EdgeModelPath")
117 # Silently unwrap legacy dict-style: EdgeClassifierTool={"ModelPath": ...}
118 if isinstance(kwargs.get("EdgeClassifierTool"), dict):
119 edge_tool_kwargs.update(kwargs.pop("EdgeClassifierTool"))
120
121 candidate_builder_kwargs = {}
122 for key in ("EdgeThreshold",
123 "OverlapThreshold",
124 "UseRecoveryComponents",
125 "SymmetrizeDirectedEdges",
126 "AddAllSegmentsRecoveryCandidate",
127 "KeepIsolatedSegments",
128 "MinCandidateSize"):
129 if key in kwargs:
130 candidate_builder_kwargs[key] = kwargs.pop(key)
131
132 if isinstance(kwargs.get("CandidateBuilderTool"), dict):
133 candidate_builder_kwargs.update(kwargs.pop("CandidateBuilderTool"))
134
135 if "EdgeClassifierTool" not in kwargs:
136 kwargs["EdgeClassifierTool"] = result.popToolsAndMerge(
137 SegmentEdgeClassifierToolCfg(flags, **edge_tool_kwargs))
138 kwargs.setdefault("CandidateBuilderTool", result.popToolsAndMerge(
139 SegmentTrackCandidateBuilderToolCfg(flags, **candidate_builder_kwargs)))
140 kwargs.setdefault("SegmentKey", "MuonSegmentsFromR4")
141 kwargs.setdefault("CandidateDecoration", "MuonSegmentsFromR4.trackCandidateIds")
142 alg = CompFactory.MuonML.SegmentEdgeInferenceAlg(name=name, **kwargs)
143 result.addEventAlgo(alg, primary=True)
144 return result
145
146
147def DisplacedVertexInferenceToolCfg(flags, name="DisplacedVertexInferenceTool", **kwargs):
148 """Configure the DisplacedVertex graph-level ONNX inference tool.
149 The current DV ONNX export consumes raw graph tensors with the contract
150 x [N,7], edge_index [2,E], edge_attr [E,5], n_muon_nodes [1] -> logits [1]
151 """
152 from AthOnnxComps.OnnxRuntimeSessionConfig import OnnxRuntimeSessionToolCfg
153
154 result = ComponentAccumulator()
155 model_path = kwargs.pop("ModelPath", "MuonInference/models/edge_class_dv_mu200.onnx")
156
157 result.merge(MuonLearningOnnxRuntimeSvcCfg(flags))
158 kwargs.setdefault("ModelSession", result.popToolsAndMerge(
159 OnnxRuntimeSessionToolCfg(flags, model_fname=model_path,
160 OnnxRuntimeSvc=result.getService("OnnxRuntimeSvc"))))
161 kwargs.setdefault("InputNodeName", "x")
162 kwargs.setdefault("InputEdgeIndexName", "edge_index")
163 kwargs.setdefault("InputEdgeAttrName", "edge_attr")
164 kwargs.setdefault("InputNMuonNodesName", "n_muon_nodes")
165 kwargs.setdefault("OutputName", "logits")
166 kwargs.setdefault("SingleOutputMode", "logit")
167 if "SpacePointKeys" not in kwargs:
168 sp_containers = []
169 if flags.Detector.GeometryMDT or flags.Detector.GeometryRPC or flags.Detector.GeometryTGC:
170 sp_containers.append("MuonSpacePoints")
171 elif flags.Detector.GeometryMM or flags.Detector.GeometrysTGC:
172 sp_containers.append("NswSpacePoints")
173 kwargs.setdefault("SpacePointKeys", sp_containers)
174 kwargs.setdefault("UseBucketSegmentSelection", True)
175 kwargs.setdefault("MinTowerEnergyMeV", 1000.0)
176 kwargs.setdefault("MaxTowerSegmentDR", 0.4)
177 kwargs.setdefault("CaloRMaxMm", 4250.0)
178 kwargs.setdefault("CaloZMaxMm", 6500.0)
179 kwargs.setdefault("SectorModulo", 16)
180 kwargs.setdefault("RequireEdges", False)
181 tool = CompFactory.MuonML.DVInferenceToolBase(name, **kwargs)
182 result.setPrivateTools(tool)
183 return result
184
185
187 """Configure the calorimeter reconstruction used by the DV training converter.
188 """
189 result = ComponentAccumulator()
190
191 # Same reconstruction chain used by MuonBucketDumpConfig.CaloCellsDumperCfg.
192 from CaloRec.CaloRecoConfig import CaloRecoCfg
193 result.merge(CaloRecoCfg(flags))
194
195 from CaloRec.CaloTowerMakerConfig import CaloTowerMakerCfg
196 result.getPrimaryAndMerge(CaloTowerMakerCfg(flags))
197
198 return result
199
200
201def DisplacedVertexInferenceAlgCfg(flags, name="DisplacedVertexInferenceAlg", **kwargs):
202 """Configure a runnable event-level DisplacedVertex inference algorithm."""
203 result = ComponentAccumulator()
204 do_calo_tower_build = kwargs.pop("DoCaloTowerBuild", True)
205 do_ml_bucket_filter = kwargs.pop("DoMLBucketFilter", True)
206 bucket_model_path = kwargs.pop("BucketModelPath", None)
207 bucket_threshold = kwargs.pop("BucketThreshold", None)
208 filtered_bucket_key = kwargs.pop("FilteredBucketKey", "FilteredMlBuckets")
209 use_filtered_buckets_for_dv_graph = kwargs.pop("UseFilteredBucketsForDVGraph", False)
210 alg_output_level = kwargs.get("OutputLevel", None)
211 tool_kwargs = {}
212 for key in (
213 "ModelPath",
214 "InputNodeName",
215 "InputEdgeIndexName",
216 "InputEdgeAttrName",
217 "InputNMuonNodesName",
218 "OutputName",
219 "SingleOutputMode",
220 "SegmentKey",
221 "SpacePointKeys",
222 "UseBucketSegmentSelection",
223 "TowerContainerKey",
224 "MinTowerEnergyMeV",
225 "MaxTowerSegmentDR",
226 "CaloRMaxMm",
227 "CaloZMaxMm",
228 "SectorModulo",
229 "RequireEdges",
230 "MaxEdges",
231 "FallbackToAllSegments",
232 "DebugDumpFirstNNodes",
233 "DebugDumpFirstNEdges",
234 "SpacePointKeys",
235 "UseBucketSegmentSelection",
236 "OutputLevel",
237 ):
238 if key in kwargs:
239 tool_kwargs[key] = kwargs.pop(key)
240
241 if isinstance(kwargs.get("InferenceTool"), dict):
242 tool_kwargs.update(kwargs.pop("InferenceTool"))
243
244 tower_key = tool_kwargs.get("TowerContainerKey", "CombinedTower")
245 if do_calo_tower_build and tower_key:
246 result.merge(DisplacedVertexCaloTowerCfg(flags))
247
248 if do_ml_bucket_filter:
249 bucket_filter_kwargs = {
250 "WriteSpacePointKey": filtered_bucket_key,
251 "ReadSpacePoints": "MuonSpacePoints",
252 }
253 if bucket_model_path is not None:
254 bucket_filter_kwargs["ModelPath"] = bucket_model_path
255 if bucket_threshold is not None:
256 bucket_filter_kwargs["ScoreThreshold"] = bucket_threshold
257 bucket_tool = result.popToolsAndMerge(
258 GraphBucketFilterToolCfg(flags, **bucket_filter_kwargs)
259 )
260 result.merge(
262 flags,
263 name="DVBucketPrefilterAlg",
264 InferenceTools=[bucket_tool],
265 )
266 )
267 if use_filtered_buckets_for_dv_graph:
268 tool_kwargs.setdefault("SpacePointKeys", [filtered_bucket_key])
269 tool_kwargs.setdefault("UseBucketSegmentSelection", True)
270
271 if "InferenceTool" not in kwargs:
272 kwargs["InferenceTool"] = result.popToolsAndMerge(
273 DisplacedVertexInferenceToolCfg(flags, **tool_kwargs)
274 )
275
276 if alg_output_level is not None:
277 kwargs["OutputLevel"] = alg_output_level
278
279 kwargs.setdefault("ScoreDecoration", "EventInfo.dv_score")
280 kwargs.setdefault("RawOutputDecoration", "EventInfo.dv_rawOutput")
281 kwargs.setdefault("PassDecoration", "EventInfo.dv_pass")
282 kwargs.setdefault("NNodesDecoration", "EventInfo.dv_nNodes")
283 kwargs.setdefault("NEdgesDecoration", "EventInfo.dv_nEdges")
284 alg = CompFactory.MuonML.DVInferenceAlg(name=name, **kwargs)
285 result.addEventAlgo(alg, primary=True)
286 return result
DisplacedVertexInferenceAlgCfg(flags, name="DisplacedVertexInferenceAlg", **kwargs)
GraphInferenceAlgCfg(flags, name="GraphInferenceAlg", **kwargs)
DisplacedVertexCaloTowerCfg(flags)
SegmentEdgeClassifierToolCfg(flags, name="SegmentEdgeClassifierTool", **kwargs)
MuonLearningOnnxRuntimeSvcCfg(flags, name="OnnxRuntimeSvc", **kwargs)
GraphBucketFilterToolCfg(flags, name="GraphBucketFilterTool", **kwargs)
SegmentTrackCandidateBuilderToolCfg(flags, name="SegmentTrackCandidateBuilderTool", **kwargs)
DisplacedVertexInferenceToolCfg(flags, name="DisplacedVertexInferenceTool", **kwargs)
SegmentEdgeInferenceAlgCfg(flags, name="SegmentEdgeInferenceAlg", **kwargs)
GraphSPFilterToolCfg(flags, name="GraphSPFilterTool", **kwargs)