1 #include "nomnigraph/Graph/Algorithms.h" 2 #include "nomnigraph/Graph/Graph.h" 4 #include "nomnigraph/Converters/Caffe2.h" 5 #include "nomnigraph/Converters/Dot.h" 7 #include "nomnigraph/Transformations/ConnectNet.h" 8 #include "nomnigraph/Transformations/OperatorFusion.h" 9 #include "nomnigraph/Transformations/Match.h" 11 #include "nomnigraph/Support/Casting.h" 17 #define ADD_ARG(_op, _name, _type, _val) \ 19 caffe2::Argument *arg = _op->add_arg(); \ 20 arg->set_name(_name); \ 21 arg->set_##_type(_val); \ 35 !nom::repr::nn::is<nom::repr::NeuralNetOperator>(a) ||
36 !nom::repr::nn::is<nom::repr::NeuralNetOperator>(b)) {
39 auto a_ = nom::repr::nn::get<nom::repr::NeuralNetOperator>(a);
40 auto b_ = nom::repr::nn::get<nom::repr::NeuralNetOperator>(b);
42 bool sameKind = a_->getKind() == b_->getKind();
43 if (sameKind && a_->getKind() == nom::repr::NeuralNetOperator::NNKind::GenericOperator) {
44 return a_->getName() == b_->getName();
51 auto bbprinter = [](
typename nom::repr::NNCFGraph::NodeRef node) {
52 std::map<std::string, std::string> labelMap;
53 assert(node->data() &&
"Node doesn't have data, can't render it");
54 auto *bb = dyn_cast<nom::repr::BasicBlockType<nom::repr::NNGraph>>(
56 labelMap[
"label"] = std::to_string((
unsigned long long)node) +
"\\n";
57 for (
const auto &instr : bb->getInstructions()) {
58 assert(isa<nom::repr::NeuralNetOperator>(instr->data()) &&
59 "Invalid instruction.");
61 bool hasOutput =
false;
62 for (
const auto &outEdge : instr->getOutEdges()) {
65 labelMap[
"label"] +=
" " + output->getName();
69 labelMap[
"label"] +=
" = ";
71 labelMap[
"label"] += op->getName();
72 for (
const auto &inEdge : instr->getInEdges()) {
75 labelMap[
"label"] +=
" " + arg->getName();
77 labelMap[
"label"] +=
"\\l";
79 labelMap[
"shape"] =
"box";
83 auto cfgedgeprinter = [](
typename nom::repr::NNCFGraph::EdgeRef edge) {
84 std::map<std::string, std::string> labelMap;
85 if (edge->data() == -1) {
86 labelMap[
"label"] =
"F";
87 }
else if (edge->data() == 1) {
88 labelMap[
"label"] =
"T";
94 std::map<std::string, std::string> labelMap;
95 assert(node->data() &&
"Node doesn't have data, can't render it");
96 if (isa<nom::repr::NeuralNetOperator>(node->data())) {
99 op->getName() +
" (" + std::to_string((
unsigned long long)node) +
")";
100 auto *annotation = op->getAnnotation();
101 if (annotation && isa<nom::repr::DeviceAnnotation>(annotation)) {
102 auto device_annotation =
104 labelMap[
"label"] +=
"\\n[" + device_annotation->getDevice() +
"]";
105 auto hash = std::hash<std::string>{}(device_annotation->getDevice());
106 std::stringstream hex_stream;
107 hex_stream << std::hex << hash;
108 labelMap[
"color"] =
"#" + hex_stream.str().substr(0, 6);
109 labelMap[
"fontcolor"] = labelMap[
"color"];
111 labelMap[
"shape"] =
"box";
112 }
else if (isa<nom::repr::Data>(node->data())) {
114 labelMap[
"label"] = tensor->getName();
115 labelMap[
"label"] +=
"_" + std::to_string(tensor->getVersion()) +
" " + std::to_string((
unsigned long long)node);
120 int main(
int argc,
char *argv[]) {
158 auto tarjans = nom::algorithm::Tarjans<TestClass, int>(&g);
159 auto sccs = tarjans.run();
164 std::vector<nom::Graph<TestClass, int>::NodeRef> nodes;
165 for (
auto i = 0; i < 10; ++i) {
167 nodes.emplace_back(g.
createNode(std::move(t)));
169 for (
auto i = 0; i < 30; ++i) {
170 int ri1 = rand() % nodes.size();
171 int ri2 = rand() % nodes.size();
175 auto tarjans = nom::algorithm::Tarjans<TestClass, int>(&g);
176 auto sccs = tarjans.run();
181 for (
auto i = 0; i < 10; ++i) {
183 caffe2::OperatorDef *def = net.add_op();
184 def->set_type(
"Conv");
186 def->add_input(
"W" + std::to_string(i));
187 ADD_ARG(def,
"kernel", i, 3);
188 ADD_ARG(def,
"stride", i, 1);
189 ADD_ARG(def,
"pad", i, 0);
190 ADD_ARG(def,
"order", s,
"NCHW");
191 def->add_output(
"X");
192 def->mutable_device_option()->set_node_name(
"conv_runner");
194 caffe2::OperatorDef *def = net.add_op();
195 def->set_type(
"Relu");
197 def->add_output(
"X");
198 def->mutable_device_option()->set_node_name(
"relu_runner");
201 auto nn = nom::converters::convertFromCaffe2Proto(net);
205 std::ofstream out(
"unfusedNet.dot");
206 out << nom::converters::convertToDotString(&g, nnprinter);
209 while (nom::transformations::fuseConvRelu(&g))
212 std::ofstream out2(
"fusedNet.dot");
213 out2 << nom::converters::convertToDotString(&g, nnprinter);
218 for (
auto i = 0; i < 10; ++i) {
220 caffe2::OperatorDef *def = net.add_op();
221 def->set_type(
"Conv");
222 def->add_input(
"X" + std::to_string(i));
223 def->add_input(
"W" + std::to_string(i));
224 def->add_input(
"b" + std::to_string(i));
225 ADD_ARG(def,
"kernel", i, 3);
226 ADD_ARG(def,
"stride", i, 1);
227 ADD_ARG(def,
"pad", i, 0);
228 ADD_ARG(def,
"order", s,
"NCHW");
229 def->add_output(
"X" + std::to_string(i+1));
230 def->mutable_device_option()->set_node_name(
"device_" +
231 std::to_string(rand() % 2));
233 caffe2::OperatorDef *def = net.add_op();
234 def->set_type(
"Relu");
235 def->add_input(
"X" + std::to_string(i));
236 def->add_output(
"X" + std::to_string(i+1));
237 def->mutable_device_option()->set_node_name(
"device_" +
238 std::to_string(rand() % 2));
241 auto nn = nom::converters::convertFromCaffe2Proto(net);
243 std::string dot1 = nom::converters::convertToDotString(&nn.dataFlow, nnprinter);
244 std::ofstream out1(
"disconnectedNet.dot");
248 assert(nom::transformations::connectNet(&nn.dataFlow));
249 nom::repr::nn::coalesceInsertedDataDependencies(&nn);
251 std::string dot = nom::converters::convertToDotString(&nn.dataFlow, nnprinter);
252 std::ofstream out(
"connectedNet.dot");
257 std::string dot = nom::converters::convertToDotString(&nn.controlFlow, bbprinter);
258 std::ofstream out(
"connectedNet_cfg.dot");
266 caffe2::OperatorDef *def = net.add_op();
267 def->set_type(
"NeverSeen");
269 def->add_output(
"X");
270 def->mutable_device_option()->set_node_name(
"device_" +
271 std::to_string(rand() % 2));
272 auto nn = nom::converters::convertFromCaffe2Proto(net);
275 nom::converters::convertToDotString(&nn.dataFlow, nnprinter).c_str();
276 auto new_netdef = nom::converters::convertToCaffe2Proto(nn);
281 std::vector<nom::Graph<TestClass, int>::NodeRef> nodes;
282 for (
auto i = 0; i < 100; ++i) {
284 nodes.emplace_back(g.
createNode(std::move(t)));
286 for (
auto i = 0; i < 200; ++i) {
287 int ri1 = rand() % nodes.size();
288 int ri2 = rand() % nodes.size();
292 auto sccs = nom::algorithm::tarjans(&g);
294 std::string dot = nom::converters::convertToDotString(
296 std::map<std::string, std::string> labelMap;
297 labelMap[
"label"] = std::to_string((
unsigned long long)node);
301 std::ofstream out(
"sccs.dot");
309 caffe2::OperatorDef *def = net.add_op();
310 def->set_type(
"While");
313 caffe2::NetDef body_net;
315 caffe2::OperatorDef *rdef = body_net.add_op();
316 rdef->set_type(
"Relu");
317 rdef->add_input(
"X");
318 rdef->add_output(
"X");
320 std::string body_net_serialized;
321 assert(body_net.SerializeToString(&body_net_serialized));
322 ADD_ARG(def,
"body", s, body_net_serialized);
324 auto nn = nom::converters::convertFromCaffe2Proto(net);
327 auto dot = nom::converters::convertToDotString(&g, nnprinter);
328 std::ofstream out(
"while.dot");
336 caffe2::OperatorDef *rdef = net.add_op();
337 rdef->set_type(
"Relu");
338 rdef->add_input(
"X");
339 rdef->add_output(
"X");
342 caffe2::OperatorDef *def = net.add_op();
343 def->set_type(
"While");
346 caffe2::NetDef body_net;
348 caffe2::OperatorDef *rdef = body_net.add_op();
349 rdef->set_type(
"Instr1");
350 rdef->add_input(
"X");
351 rdef->add_output(
"X");
354 caffe2::OperatorDef *rdef = body_net.add_op();
355 rdef->set_type(
"Instr2");
356 rdef->add_input(
"X");
357 rdef->add_output(
"X");
360 caffe2::OperatorDef *rdef = body_net.add_op();
361 rdef->set_type(
"Instr3");
362 rdef->add_input(
"X");
363 rdef->add_output(
"X");
365 std::string body_net_serialized;
366 assert(body_net.SerializeToString(&body_net_serialized));
367 ADD_ARG(def,
"body", s, body_net_serialized);
369 auto nn = nom::converters::convertFromCaffe2Proto(net);
376 printf(
"Try out ./nomnigraph_test tests/distrib_ads_trainer.pb\n");
380 std::fstream input(argv[1]);
381 std::string s(std::istreambuf_iterator<char>(input), {});
382 assert(net.ParseFromString(s) &&
"Couldn't parse network\n");
384 auto nn = nom::converters::convertFromCaffe2Proto(net);
386 auto dot = nom::converters::convertToDotString(&nn.dataFlow, nnprinter);
387 std::ofstream out(
"in.dot");
391 assert(nom::transformations::connectNet(&nn.dataFlow));
394 auto dot = nom::converters::convertToDotString(&nn.dataFlow, nnprinter);
395 std::ofstream out(
"out.dot");
405 caffe2::OperatorDef *rdef = net.add_op();
406 rdef->set_type(
"Relu");
407 rdef->add_input(
"X");
408 rdef->add_output(
"X");
411 caffe2::OperatorDef *def = net.add_op();
412 def->set_type(
"While");
415 caffe2::NetDef body_net;
417 caffe2::OperatorDef *rdef = body_net.add_op();
418 rdef->set_type(
"Relu");
419 rdef->add_input(
"X");
420 rdef->add_output(
"X");
423 caffe2::OperatorDef *rdef = body_net.add_op();
424 rdef->set_type(
"Instr2");
425 rdef->add_input(
"X");
426 rdef->add_output(
"X");
429 caffe2::OperatorDef *rdef = body_net.add_op();
430 rdef->set_type(
"Instr3");
431 rdef->add_input(
"X");
432 rdef->add_output(
"X");
435 caffe2::OperatorDef *rdef = body_net.add_op();
436 rdef->set_type(
"Instr4");
437 rdef->add_input(
"X");
438 rdef->add_output(
"Y");
440 std::string body_net_serialized;
441 assert(body_net.SerializeToString(&body_net_serialized));
442 ADD_ARG(def,
"body", s, body_net_serialized);
444 auto nn = nom::converters::convertFromCaffe2Proto(net);
446 auto sccs = nom::algorithm::tarjans(&nn.dataFlow);
447 auto cfgsccs = nom::algorithm::tarjans(&nn.controlFlow);
450 nom::converters::convertToDotString(&nn.dataFlow, sccs, nnprinter);
451 std::ofstream out(
"while2.dot");
457 nom::converters::convertToDotString(&nn.controlFlow, cfgsccs, bbprinter);
458 std::ofstream out(
"while_cfg.dot");
462 for (
auto node : nn.controlFlow.getMutableNodes()) {
463 printf(
"node addr %llu\n", (
unsigned long long)node);
465 auto domFrontMap = nom::algorithm::dominanceFrontierMap(&nn.controlFlow);
466 for (
auto pair : domFrontMap) {
467 for (
auto node : pair.second) {
468 printf(
"%llu - %llu\n", (
unsigned long long)pair.first, (
unsigned long long)node);
509 std::ofstream out(
"dominatorinput.dot");
510 out << nom::converters::convertToDotString(
512 std::map<std::string, std::string> labelMap;
513 labelMap[
"label"] = node->data();
519 auto tree = nom::algorithm::dominatorTree(&graph, r);
521 std::ofstream out(
"dominatoroutput.dot");
522 out << nom::converters::convertToDotString(
525 std::map<std::string, std::string> labelMap;
526 labelMap[
"label"] = node->data()->data();
531 auto map = nom::algorithm::immediateDominatorMap(&graph, r);
544 auto domFrontMap = nom::algorithm::dominanceFrontierMap(&graph, r);
551 auto entry = graph.
createNode(std::string(
"entry"));
559 auto exit = graph.
createNode(std::string(
"exit"));
572 auto domFrontMap = nom::algorithm::dominanceFrontierMap(&graph, entry);
574 std::unordered_map<noderef, std::unordered_set<noderef>> checkMap = {
582 for (
auto pair : domFrontMap) {
583 assert(pair.second == checkMap[pair.first]);
590 caffe2::OperatorDef *rdef = net.add_op();
591 rdef->set_type(
"Instr1");
592 rdef->add_input(
"X");
593 rdef->add_output(
"X");
596 caffe2::OperatorDef *rdef = net.add_op();
597 rdef->set_type(
"Instr2");
598 rdef->add_input(
"X");
599 rdef->add_output(
"X");
602 caffe2::OperatorDef *rdef = net.add_op();
603 rdef->set_type(
"Instr3");
604 rdef->add_input(
"X");
605 rdef->add_output(
"X");
607 auto nn = nom::converters::convertFromCaffe2Proto(net);
610 auto dot = nom::converters::convertToDotString(&nn.controlFlow, bbprinter);
611 std::ofstream out(
"dfg_test_in.dot");
616 auto randomNode = nn.dataFlow.getMutableNodes()[0];
617 nn.dataFlow.deleteNode(randomNode);
620 auto dot = nom::converters::convertToDotString(&nn.controlFlow, bbprinter);
621 std::ofstream out(
"dfg_test_out.dot");
629 auto entry = graph.
createNode(std::string(
"entry"));
637 auto exit = graph.
createNode(std::string(
"exit"));
651 auto m1 = match_graph.
createNode(std::string(
"1"));
652 auto m2 = match_graph.
createNode(std::string(
"2"));
656 assert(m.match(graph).size() == 1);
662 caffe2::OperatorDef *rdef = net.add_op();
663 rdef->set_type(
"Instr1");
664 rdef->add_input(
"X");
665 rdef->add_output(
"X");
668 caffe2::OperatorDef *rdef = net.add_op();
669 rdef->set_type(
"Instr2");
670 rdef->add_input(
"X");
671 rdef->add_output(
"X");
674 caffe2::OperatorDef *rdef = net.add_op();
675 rdef->set_type(
"Instr3");
676 rdef->add_input(
"X");
677 rdef->add_output(
"X");
679 auto nn = nom::converters::convertFromCaffe2Proto(net);
681 caffe2::NetDef matchnet;
683 caffe2::OperatorDef *rdef = matchnet.add_op();
684 rdef->set_type(
"Instr1");
686 auto matchnn = nom::converters::convertFromCaffe2Proto(matchnet);
688 assert(m.match(nn.dataFlow).size() == 1);
NodeRef createNode(T &&data)
Creates a node and retains ownership of it.
void deleteNode(NodeRef n, bool deleteEdges=true)
Deletes a node from the graph.
void deleteEdge(EdgeRef e)
Deletes a edge from the graph.
A simple graph implementation.
EdgeRef createEdge(NodeRef tail, NodeRef head)
Creates a directed edge and retains ownership of it.