Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RModel_GraphIndependent.cxx
Go to the documentation of this file.
1#include <limits>
2#include <algorithm>
3#include <cctype>
4
6
7namespace TMVA {
8namespace Experimental {
9namespace SOFIE {
10
12 edges_update_block = std::move(graph_input_struct.edges_update_block);
13 nodes_update_block = std::move(graph_input_struct.nodes_update_block);
14 globals_update_block = std::move(graph_input_struct.globals_update_block);
15
16 num_nodes = graph_input_struct.num_nodes;
17 num_edges = graph_input_struct.edges.size();
18 num_node_features = graph_input_struct.num_node_features;
19 num_edge_features = graph_input_struct.num_edge_features;
20 num_global_features = graph_input_struct.num_global_features;
21
23 fName = fFileName.substr(0, fFileName.rfind("."));
24
25 std::time_t ttime = std::time(0);
26 std::tm* gmt_time = std::gmtime(&ttime);
27 fParseTime = std::asctime(gmt_time);
28}
29
31 std::string hgname;
32 // the inference interface uses the GNN_Data helper type
33 AddNeededHelperFunction("GNN_Data");
35
36 std::ofstream f;
37 f.open(fName+".dat");
38 f.close();
39
40
41 long next_pos = 0;
45
46 //Generating Infer function definition for Edge update function
48 size_t block_size = num_edges;
49 fGC += "\n\nnamespace Edge_Update{\nstruct Session {\n";
50 std::vector<std::vector<Dim>> update_Input = { { Dim{"num_edges",block_size}, Dim{num_edge_features}} };
51 edges_update_block->Initialize();
52 edges_update_block->AddInputTensors(update_Input);
53 fGC += edges_update_block->GenerateModel(fName);
54 next_pos = edges_update_block->GetFunctionBlock()->WriteInitializedTensorsToFile(fName + ".dat");
55 fGC += "};\n}\n";
56
57 // the number of output edges features can be smaller, so we need to correct here
58 // assume num_edge_features is not a parametric shape
59 auto edges_update_output_shape = edges_update_block->GetFunctionBlock()->GetDynamicTensorShape(edges_update_block->GetFunctionBlock()->GetOutputTensorNames()[0]);
62 }
63 }
64
66 fGC+="\n\nnamespace Node_Update{\nstruct Session {\n";
67 // Generating Infer function definition for Node Update function
68 // num_node_features is the output one
69 size_t block_size = num_nodes;
70 std::vector<std::vector<Dim>> update_Input = { {Dim{"num_nodes", block_size}, Dim{num_node_features}} };
71 nodes_update_block->Initialize();
72 nodes_update_block->AddInputTensors(update_Input);
73 fGC+=nodes_update_block->GenerateModel(fName,next_pos);
74 next_pos = nodes_update_block->GetFunctionBlock()->WriteInitializedTensorsToFile(fName+".dat");
75 fGC+="};\n}\n";
76
77 // we need to correct the output number of node features
78 auto nodes_update_output_shape = nodes_update_block->GetFunctionBlock()->GetDynamicTensorShape(nodes_update_block->GetFunctionBlock()->GetOutputTensorNames()[0]);
81 }
82 }
83
84 // Generating Infer function definition for Global Update function
86 fGC+="\n\nnamespace Global_Update{\nstruct Session {\n";
87 std::vector<std::vector<std::size_t>> update_Input = {{1, num_global_features}};
88 globals_update_block->Initialize();
89 globals_update_block->AddInputTensors(update_Input);
90 fGC+=globals_update_block->GenerateModel(fName,next_pos);
91 next_pos = globals_update_block->GetFunctionBlock()->WriteInitializedTensorsToFile(fName+".dat");
92 fGC+="};\n}\n";
93
94 // we need to correct the output number of global features
95 // global features are in shape[1]
96#if 0
97 auto globals_update_output_shape = globals_update_block->GetFunctionBlock()->GetDynamicTensorShape(globals_update_block->GetFunctionBlock()->GetOutputTensorNames()[0]);
100 }
101#endif
102 if(globals_update_block->GetFunctionBlock()->GetTensorShape(globals_update_block->GetFunctionBlock()->GetOutputTensorNames()[0])[1] != num_global_features) {
103 num_global_features = globals_update_block->GetFunctionBlock()->GetTensorShape(globals_update_block->GetFunctionBlock()->GetOutputTensorNames()[0])[1];
104 }
105 }
106
107
108 // computing inplace on input graph
109 fGC += "struct Session {\n";
110 fGC += "\n// Instantiating session objects for graph components\n";
111 // create session classes and corresponding temporary vectors
112 if (edges_update_block) {
113 fGC += "Edge_Update::Session edge_update;\n";
114 // this we can remove when we support full dynamic edges and nodes
115 fGC += "std::vector<float> fEdgeInputs = std::vector<float>(" + std::to_string(num_edges) + "*" + std::to_string(num_edge_features_input) + ");\n";
116 //fGC += "std::vector<float> fEdgeUpdates {" + std::to_string(num_edges) + "*" + std::to_string(num_edge_features) + "};";
117 }
118 if (nodes_update_block) {
119 fGC += "Node_Update::Session node_update;\n";
120 fGC += "std::vector<float> fNodeInputs = std::vector<float>(" + std::to_string(num_nodes) + "*" + std::to_string(num_node_features_input) + ");\n";
121 //fGC += "std::vector<float> fNodeUpdates {" + std::to_string(num_nodes) + "*" + std::to_string(num_node_features) + "};";
122 }
124 fGC += "Global_Update::Session global_update;\n\n";
125 //fGC += "std::vector<float> fGlobalUpdates {" + std::to_string(num_global_features) + "};";
126 }
127
128 fGC += "\nvoid infer(GNN_Data& input_graph){\n";
129
130 // computing updated edge attributes
131 // could use std::span
132 if (edges_update_block) {
133 fGC += "\n// --- Edge Update ---\n";
134
135 std::string e_size_input = std::to_string(num_edge_features_input);
136 fGC += "size_t n_edges = input_graph.edge_data.GetShape()[0];\n";
137 fGC += "for (size_t k = 0; k < n_edges; k++) { \n";
138 fGC += " std::copy(input_graph.edge_data.GetData() + k * " + e_size_input +
139 ", input_graph.edge_data.GetData() + (k + 1) * " + e_size_input + ", fEdgeInputs.begin() + k * " +
140 e_size_input + ");\n";
141 fGC += "}\n";
142
143 fGC += "auto edgeUpdates = " + edges_update_block->Generate({"n_edges","fEdgeInputs.data()"}) + "\n";
144
146 fGC += "\n// resize edge graph data since output feature size is not equal to input size\n";
147 fGC += "input_graph.edge_data = input_graph.edge_data.Resize({ n_edges, " +
148 std::to_string(num_edge_features) + "});\n";
149 }
150 // copy output
151 fGC += "\nfor (size_t k = 0; k < n_edges; k++) { \n";
152 fGC += " std::copy(edgeUpdates.begin()+ k * " + std::to_string(num_edge_features) +
153 ", edgeUpdates.begin()+ (k+1) * " + std::to_string(num_edge_features) +
154 ",input_graph.edge_data.GetData() + k * " + std::to_string(num_edge_features) + ");\n";
155 fGC += "}\n";
156 fGC += "\n";
157 }
158
159 // computing updated node attributes
160 if (nodes_update_block) {
161 std::string n_size_input = std::to_string(num_node_features_input);
162 fGC += "\n// --- Node Update ---\n";
163 fGC += "size_t n_nodes = input_graph.node_data.GetShape()[0];\n";
164 fGC += "for (size_t k = 0; k < n_nodes; k++) { \n";
165 fGC += " std::copy(input_graph.node_data.GetData() + k * " + n_size_input +
166 ", input_graph.node_data.GetData() + (k + 1) * " + n_size_input + ", fNodeInputs.begin() + k * " +
167 n_size_input + ");\n";
168 fGC += "}\n";
169
170 fGC += "auto nodeUpdates = ";
171 fGC += nodes_update_block->Generate({"n_nodes","fNodeInputs.data()"}); // computing updated node attributes
172 fGC += "\n";
173
175 fGC += "\n// resize node graph data since output feature size is not equal to input size\n";
176 fGC += "input_graph.node_data = input_graph.node_data.Resize({ n_nodes, " +
177 std::to_string(num_node_features) + "});\n";
178 }
179 // copy output
180 fGC += "\nfor (size_t k = 0; k < n_nodes; k++) { \n";
181 fGC += " std::copy(nodeUpdates.begin()+ k * " + std::to_string(num_node_features) +
182 ", nodeUpdates.begin() + (k+1) * " + std::to_string(num_node_features) +
183 ",input_graph.node_data.GetData() + k * " + std::to_string(num_node_features) + ");\n";
184 fGC += "}\n";
185 fGC += "\n";
186 }
187
188 // computing updated global attributes
190 fGC += "\n// --- Global Update ---\n";
191 fGC += "std::vector<float> Global_Data = ";
192 fGC += globals_update_block->Generate({"input_graph.global_data.GetData()"});
193 fGC += "\n";
194
196 fGC += "\n// resize global graph data since output feature size is not equal to input size\n";
197 fGC += "input_graph.global_data = input_graph.global_data.Resize({" + std::to_string(num_global_features) +
198 "});\n";
199 }
200
201 fGC += "\nstd::copy(Global_Data.begin(), Global_Data.end(), input_graph.global_data.GetData());";
202 fGC += "\n";
203 }
204
205 // propagate helper functions needed by the update-function components
206 for (auto *block : {edges_update_block.get(), nodes_update_block.get(), globals_update_block.get()}) {
207 if (block && block->GetFunctionBlock()) {
208 for (auto const &h : block->GetFunctionBlock()->GetNeededHelperFunctions())
210 }
211 }
212
213 fGC += ("}\n};\n} //TMVA_SOFIE_" + fName + "\n");
214 fGC += "\n#endif // TMVA_SOFIE_" + hgname + "\n";
215
216 // dump the standalone helper-function definitions into the generated header
218}
219
220}//SOFIE
221}//Experimental
222}//TMVA
#define f(i)
Definition RSha256.hxx:104
#define h(i)
Definition RSha256.hxx:106
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
void GenerateHeaderInfo(std::string &hgname)
void AddNeededHelperFunction(std::string name)
RModel_GraphIndependent(GraphIndependent_Init &graph_input_struct)
create variable transformations