Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TMVA_SOFIE_GNN.py
Go to the documentation of this file.
1## \file
2## \ingroup tutorial_ml
3## \notebook -nodraw
4##
5## \macro_code
6
7import ROOT
8
9# Load system openblas library explicitly if available. This avoids pulling in
10# NumPys builtin openblas later, which will conflict with the system openblas.
11ROOT.gInterpreter.Load("libopenblaso.so")
12
13import time
14
15import graph_nets as gn
16import numpy as np
17import sonnet as snt
18from graph_nets import utils_tf
19
20# defining graph properties
21num_nodes = 5
22num_edges = 20
25node_size = 4
26edge_size = 4
27global_size = 1
28LATENT_SIZE = 100
29NUM_LAYERS = 4
30processing_steps = 5
31
32
33# method for returning dictionary of graph data
35 return {
36 "globals": 10 * np.random.rand(GLOBAL_FEATURE_SIZE).astype(np.float32) - 5.0,
37 "nodes": 10 * np.random.rand(num_nodes, NODE_FEATURE_SIZE).astype(np.float32) - 5.0,
38 "edges": 10 * np.random.rand(num_edges, EDGE_FEATURE_SIZE).astype(np.float32) - 5.0,
39 "senders": snd,
40 "receivers": rec,
41 }
42
43
44# method to instantiate mlp model to be added in GNN
46 return snt.Sequential(
47 [
48 snt.nets.MLP([LATENT_SIZE] * NUM_LAYERS, activate_final=True),
49 snt.LayerNorm(axis=-1, create_offset=True, create_scale=True),
50 ]
51 )
52
53
54# defining GraphIndependent class with MLP edge, node, and global models.
55class MLPGraphIndependent(snt.Module):
56 def __init__(self, name="MLPGraphIndependent"):
57 super(MLPGraphIndependent, self).__init__(name=name)
59 edge_model_fn=lambda: snt.nets.MLP([LATENT_SIZE] * NUM_LAYERS, activate_final=True),
60 node_model_fn=lambda: snt.nets.MLP([LATENT_SIZE] * NUM_LAYERS, activate_final=True),
61 global_model_fn=lambda: snt.nets.MLP([LATENT_SIZE] * NUM_LAYERS, activate_final=True),
62 )
63
64 def __call__(self, inputs):
65 return self._network(inputs)
66
67
68# defining Graph network class with MLP edge, node, and global models.
69class MLPGraphNetwork(snt.Module):
70 def __init__(self, name="MLPGraphNetwork"):
71 super(MLPGraphNetwork, self).__init__(name=name)
73 edge_model_fn=make_mlp_model, node_model_fn=make_mlp_model, global_model_fn=make_mlp_model
74 )
75
76 def __call__(self, inputs):
77 return self._network(inputs)
78
79
80# defining a Encode-Process-Decode module for LHCb toy model
81class EncodeProcessDecode(snt.Module):
82
83 def __init__(self, name="EncodeProcessDecode"):
84 super(EncodeProcessDecode, self).__init__(name=name)
89
90 def __call__(self, input_op, num_processing_steps):
91 latent = self._encoder(input_op)
92 latent0 = latent
93 output_ops = []
94 for _ in range(num_processing_steps):
95 core_input = utils_tf.concat([latent0, latent], axis=1)
96 latent = self._core(core_input)
97 decoded_op = self._decoder(latent)
98 output_ops.append(self._output_transform(decoded_op))
99 return output_ops
100
101
102# Instantiating EncodeProcessDecode Model
103ep_model = EncodeProcessDecode()
104
105# Initializing randomized input data
107
108# input_graphs is a tuple representing the initial data
110
111# Initializing randomized input data for core
112# note that the core network has as input a double number of features
115
116# initialize graph data for decoder (input is LATENT_SIZE)
118
119# Make prediction of GNN
121# print("---> Input:\n",input_graph_data)
122# print("\n\n------> Input core data:\n",input_core_graph_data)
123# print("\n\n---> Output:\n",output_gn)
124
125# Make SOFIE Model
127 ep_model._encoder._network, GraphData, filename="gnn_encoder"
128)
131
133 ep_model._core._network, CoreGraphData, filename="gnn_core"
134)
137
139 ep_model._decoder._network, DecodeGraphData, filename="gnn_decoder"
140)
143
145 ep_model._output_transform._network, DecodeGraphData, filename="gnn_output_transform"
146)
149
150# Compile now the generated C++ code from SOFIE
151gen_code = '''#pragma cling optimize(2)
152#include "gnn_encoder.hxx"
153#include "gnn_core.hxx"
154#include "gnn_decoder.hxx"
155#include "gnn_output_transform.hxx"'''
157
158
159# helper function to print SOFIE GNN data structure
164 if printShape:
165 print("SOFIE data ... shapes", n.shape, e.shape, g.shape)
166 print(
167 " node data",
168 n.reshape(
169 n.size,
170 ),
171 )
172 print(
173 " edge data",
174 e.reshape(
175 e.size,
176 ),
177 )
178 print(
179 " global data",
180 g.reshape(
181 g.size,
182 ),
183 )
184
185
187 output_data = ROOT.TMVA.Experimental.SOFIE.Copy(input_data)
188 return output_data
189
190
191# Build SOFIE GNN Model and run inference
199 def infer(self, graphData):
200 # copy the input data
201 input_data = CopyData(graphData)
202
203 # running inference on sofie
204 self.encoder_session.infer(input_data)
205 latent0 = CopyData(input_data)
206 latent = input_data
207 output_ops = []
208 for _ in range(processing_steps):
209 core_input = ROOT.TMVA.Experimental.SOFIE.Concatenate(latent0, latent, axis=1)
210 self.core_session.infer(core_input)
211 latent = CopyData(core_input)
212 self.decoder_session.infer(core_input)
213 self.output_transform_session.infer(core_input)
214 output = CopyData(core_input)
215 output_ops.append(output)
216
217 return output_ops
218
219
220# Test both GNN on some simulated events
222 data = get_graph_data_dict(num_nodes, num_edges, node_size, edge_size, global_size)
223 return data
224
225
226numevts = 40
227dataSet = []
228for i in range(0, numevts):
229 data = GenerateData()
230 dataSet.append(data)
231
232# Run graph_nets model
233# First we convert input data to the required input format
234gnetData = []
235for i in range(0, numevts):
236 graphData = dataSet[i]
238 gnetData.append(gnet_data_i)
239
240
241# Function to run the graph net
243 output_gn = ep_model(inputGraphData, processing_steps)
244 return output_gn
245
246
247start = time.time()
249for i in range(0, numevts):
251 g = out[1].globals.numpy()
252 hG.Fill(np.mean(g))
253
254end = time.time()
255print("elapsed time for ", numevts, "events = ", end - start)
256
257# running SOFIE-GNN
258sofieData = []
259for i in range(0, numevts):
260 graphData = dataSet[i]
266 sofieData.append(input_data)
267
268
269endSC = time.time()
270print("time to convert data to SOFIE format", endSC - end)
271
273start0 = time.time()
274gnn = SofieGNN()
275start = time.time()
276print("time to create SOFIE GNN class", start - start0)
277for i in range(0, numevts):
278 # print("inference event....",i)
279 out = gnn.infer(sofieData[i])
280 g = np.asarray(out[1].global_data)
281 hS.Fill(np.mean(g))
282
283end = time.time()
284print("elapsed time for ", numevts, "events = ", end - start)
285
287c0.Divide(1, 2)
288c1 = c0.cd(1)
289c1.Divide(2, 1)
290c1.cd(1)
291hG.Draw()
292c1.cd(2)
293hS.Draw()
294
298# compute differences between SOFIE and GNN
299for i in range(0, numevts):
300 outSofie = gnn.infer(sofieData[i])
301 outGnet = RunGNet(gnetData[i])
302 edgesG = outGnet[1].edges.numpy()
304 if i == 0:
305 print(edgesG.shape)
306 for j in range(0, edgesG.shape[0]):
307 for k in range(0, edgesG.shape[1]):
308 hDe.Fill(edgesG[j, k] - edgesS[j, k])
309
310 nodesG = outGnet[1].nodes.numpy()
312 for j in range(0, nodesG.shape[0]):
313 for k in range(0, nodesG.shape[1]):
314 hDn.Fill(nodesG[j, k] - nodesS[j, k])
315
316 globG = outGnet[1].globals.numpy()
318 for j in range(0, globG.shape[1]):
319 hDg.Fill(globG[0, j] - globS[j])
320
321
322c2 = c0.cd(2)
323c2.Divide(3, 1)
324c2.cd(1)
325hDe.Draw()
326c2.cd(2)
327hDn.Draw()
328c2.cd(3)
329hDg.Draw()
330
331c0.Draw()
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
__call__(self, input_op, num_processing_steps)
__init__(self, name="EncodeProcessDecode")
__init__(self, name="MLPGraphIndependent")
__init__(self, name="MLPGraphNetwork")
CopyData(input_data)
get_graph_data_dict(num_nodes, num_edges, NODE_FEATURE_SIZE=2, EDGE_FEATURE_SIZE=2, GLOBAL_FEATURE_SIZE=1)
RunGNet(inputGraphData)
PrintSofie(output, printShape=False)