Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TMVA_SOFIE_GNN_Parser.py
Go to the documentation of this file.
1## \file
2## \ingroup tutorial_ml
3## \notebook -nodraw
4##
5## Tutorial showing how to parse a GNN from GraphNet and make a SOFIE model
6## The tutorial also generate some data which can serve as input for the tutorial TMVA_SOFIE_GNN_Application.C
7##
8## \macro_code
9
10import os
11
12#for getting time and memory
13import time
14
15import graph_nets as gn
16import numpy as np
17import psutil
18import ROOT
19import sonnet as snt
20from graph_nets import utils_tf
21
22# defining graph properties. Number of edges/modes are the maximum
23num_max_nodes=100
24num_max_edges=300
25node_size=4
26edge_size=4
27global_size=1
28LATENT_SIZE = 100
29NUM_LAYERS = 4
30processing_steps = 5
31numevts = 100
32
33verbose = False
34
35#print the used memory in MB
37 #get memory of current process
38 pid = os.getpid()
39 python_process = psutil.Process(pid)
40 memoryUse = python_process.memory_info()[0]/(1024.*1024.) #divide by 1024 * 1024 to get memory in MB
41 print(s,"memory:",memoryUse,"(MB)")
42
43
44# method for returning dictionary of graph data
46 num_nodes = np.random.randint(num_max_nodes-2, size=1)[0] + 2
47 num_edges = np.random.randint(num_max_edges-1, size=1)[0] + 1
48 return {
49 "globals": 10*np.random.rand(GLOBAL_FEATURE_SIZE).astype(np.float32)-5.,
50 "nodes": 10*np.random.rand(num_nodes, NODE_FEATURE_SIZE).astype(np.float32)-5.,
51 "edges": 10*np.random.rand(num_edges, EDGE_FEATURE_SIZE).astype(np.float32)-5.,
52 "senders": np.random.randint(num_nodes, size=num_edges, dtype=np.int32),
53 "receivers": np.random.randint(num_nodes, size=num_edges, dtype=np.int32)
54 }
55
56# generate graph data with a fixed number of nodes/edges
58 return {
59 "globals": np.ones((GLOBAL_FEATURE_SIZE),dtype=np.float32),
60 "nodes": np.ones((num_nodes, NODE_FEATURE_SIZE), dtype = np.float32),
61 "edges": np.ones((num_edges, EDGE_FEATURE_SIZE), dtype = np.float32),
62 "senders": np.random.randint(num_nodes, size=num_edges, dtype=np.int32),
63 "receivers": np.random.randint(num_nodes, size=num_edges, dtype=np.int32)
64 }
65
66
67
68
69# method to instantiate mlp model to be added in GNN
71 return snt.Sequential([
72 snt.nets.MLP([LATENT_SIZE]*NUM_LAYERS, activate_final=True),
73 snt.LayerNorm(axis=-1, create_offset=True, create_scale=True)
74 ])
75
76# defining GraphIndependent class with MLP edge, node, and global models.
77class MLPGraphIndependent(snt.Module):
78 def __init__(self, name="MLPGraphIndependent"):
79 super(MLPGraphIndependent, self).__init__(name=name)
81 edge_model_fn = lambda: snt.nets.MLP([LATENT_SIZE]*NUM_LAYERS, activate_final=True),
82 node_model_fn = lambda: snt.nets.MLP([LATENT_SIZE]*NUM_LAYERS, activate_final=True),
83 global_model_fn = lambda: snt.nets.MLP([LATENT_SIZE]*NUM_LAYERS, activate_final=True))
84
85 def __call__(self, inputs):
86 return self._network(inputs)
87
88# defining Graph network class with MLP edge, node, and global models.
89class MLPGraphNetwork(snt.Module):
90 def __init__(self, name="MLPGraphNetwork"):
91 super(MLPGraphNetwork, self).__init__(name=name)
93 edge_model_fn=make_mlp_model,
94 node_model_fn=make_mlp_model,
95 global_model_fn=make_mlp_model)
96
97 def __call__(self, inputs):
98 return self._network(inputs)
99
100# defining a Encode-Process-Decode module for LHCb toy model
101class EncodeProcessDecode(snt.Module):
102
103 def __init__(self,
104 name="EncodeProcessDecode"):
105 super(EncodeProcessDecode, self).__init__(name=name)
110
111 def __call__(self, input_op, num_processing_steps):
112 latent = self._encoder(input_op)
113 latent0 = latent
114 output_ops = []
115 for _ in range(num_processing_steps):
116 core_input = utils_tf.concat([latent0, latent], axis=1)
117 latent = self._core(core_input)
118 decoded_op = self._decoder(latent)
119 output_ops.append(self._output_transform(decoded_op))
120 return output_ops
121
122
123########################################################################################################
124
125# Instantiating EncodeProcessDecode Model
126
127printMemory("before instantiating")
128ep_model = EncodeProcessDecode()
129printMemory("after instantiating")
130
131# Initializing randomized input data with maximum number of nodes/edges
133
134#input_graphs is a tuple representing the initial data
136
137# Initializing randomized input data for core
138# note that the core network has as input a double number of features
141
142#initialize graph data for decoder (input is LATENT_SIZE)
144
145# Make prediction of GNN. This will initialize the GNN with weights
146printMemory("before first eval")
148printMemory("after first eval")
149#print("---> Input:\n",input_graph_data)
150#print("\n\n------> Input core data:\n",input_core_graph_data)
151#print("\n\n---> Output:\n",output_gn)
152
153# Make SOFIE Model, the model will be made using a maximum number of nodes/edges which are inside GraphData
154
158
162
166
170
171####################################################################################################################################
172
173#generate data and save in a ROOT TTree
174#
175
178#need to store each element since annot store RTensor
179
186
187tree.Branch("node_data", "std::vector<float>" , node_data)
188tree.Branch("edge_data", "std::vector<float>" , edge_data)
189tree.Branch("global_data", "std::vector<float>" , global_data)
190tree.Branch("receivers", "std::vector<int>" , receivers)
191tree.Branch("senders", "std::vector<int>" , senders)
192
193
194print("\n\nSaving data in a ROOT File:")
198dataset = []
199for i in range(0,numevts):
201 s_nodes = graphData['nodes'].size
202 s_edges = graphData['edges'].size
203 num_edges = graphData['edges'].shape[0]
204 tmp = ROOT.std.vector['float'](graphData['nodes'].reshape((graphData['nodes'].size)))
206 tmp = ROOT.std.vector['float'](graphData['edges'].reshape((graphData['edges'].size)))
208 tmp = ROOT.std.vector['float'](graphData['globals'].reshape((graphData['globals'].size)))
210 #make sure dtype of graphData['receivers'] and senders is int32
211 tmp = ROOT.std.vector['int'](graphData['receivers'])
213 tmp = ROOT.std.vector['int'](graphData['senders'])
215 if (i < 1 and verbose) :
216 print("Nodes - shape:",int(node_data.size()/node_size),node_size,"data: ",node_data)
217 print("Edges - shape:",num_edges, edge_size,"data: ", edge_data)
218 print("Globals : ",global_data)
219 print("Receivers : ",receivers)
220 print("Senders : ",senders)
221#
222#evaluate graph net on these events
223#
224 tree.Fill()
226 dataset.append(tf_graph_data)
227
229
230#do a first evaluation
231printMemory("before eval1")
233printMemory("after eval1")
234
235start = time.time()
236firstEvent = True
237for tf_graph_data in dataset:
238 output_gnn = ep_model(tf_graph_data, processing_steps)
239 output_nodes = output_gnn[-1].nodes.numpy()
240 output_edges = output_gnn[-1].edges.numpy()
241 output_globals = output_gnn[-1].globals.numpy()
242 outgnn[0] = np.mean(output_nodes)
243 outgnn[1] = np.mean(output_edges)
244 outgnn[2] = np.mean(output_globals)
245 h1.Fill(outgnn[0])
246 h2.Fill(outgnn[1])
247 h3.Fill(outgnn[2])
248 if (firstEvent and verbose) :
249 print("Output of first event")
250 print("nodes data", output_gnn[-1].nodes.numpy())
251 print("edge data", output_gnn[-1].edges.numpy())
252 print("global data", output_gnn[-1].globals.numpy())
253 firstEvent = False
254
255
256end = time.time()
257
258print("time to evaluate events",end-start)
259printMemory("after eval Nevts")
260
262c1.Divide(1,3)
263c1.cd(1)
265c1.cd(2)
267c1.cd(3)
269
271h1.Write()
272h2.Write()
273h3.Write()
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
__init__(self, name="EncodeProcessDecode")
__call__(self, input_op, num_processing_steps)
__init__(self, name="MLPGraphIndependent")
__init__(self, name="MLPGraphNetwork")
get_dynamic_graph_data_dict(NODE_FEATURE_SIZE=2, EDGE_FEATURE_SIZE=2, GLOBAL_FEATURE_SIZE=1)
get_fix_graph_data_dict(num_nodes, num_edges, NODE_FEATURE_SIZE=2, EDGE_FEATURE_SIZE=2, GLOBAL_FEATURE_SIZE=1)