diff --git a/plugins/machine_learning/include/machine_learning/graph_neural_network.h b/plugins/machine_learning/include/machine_learning/graph_neural_network.h index d8b15758537..3623158b682 100644 --- a/plugins/machine_learning/include/machine_learning/graph_neural_network.h +++ b/plugins/machine_learning/include/machine_learning/graph_neural_network.h @@ -1,4 +1,10 @@ +/** + * @file netlist_graph.h + * @brief This file contains structures and functions for creating and annotating netlist graphs used in machine learning applications. + */ + #pragma once + #include "hal_core/defines.h" #include "machine_learning/types.h" @@ -7,20 +13,65 @@ namespace hal { class Netlist; + class Gate; namespace machine_learning { - namespace graph + + /** + * @struct NetlistGraph + * @brief Represents a directed graph structure for a netlist. + * + * This structure holds the edges of the graph as pairs of node indices and the graph's directional configuration. + */ + struct NetlistGraph { - struct NetlistGraph - { - std::pair, std::vector> edge_list; - GraphDirection direction; - }; + /** + * @brief Edge list of the graph represented by pairs of node indices. + */ + std::pair, std::vector> edge_list; + + /** + * @brief The direction of the graph (e.g., forward or backward). + */ + GraphDirection direction; + }; + + /** + * @brief Constructs a graph representation of a netlist. The connections are an edge list of indices representing the position of the gates in the gates vector. + * + * This function constructs a netlist graph by analyzing the connections among all gates in a netlist. + * + * @param[in] nl - The netlist to operate on. + * @param[in] gates - The order of the gates, needed for the index representation. + * @param[in] dir - The direction of the graph. + * @returns A `NetlistGraph` representing the netlist connections. + */ + NetlistGraph construct_netlist_graph(const Netlist* nl, const std::vector& gates, const GraphDirection& dir); + + /** + * @brief Constructs a sequential netlist graph representation. The connections are an edge list of indices representing the position of the gates in the gates vector. + * + * This function constructs a sequential graph representation of the netlist, capturing only the sequential dependencies between gates. + * + * @param[in] nl - The netlist to operate on. + * @param[in] gates - The order of the gates, needed for the index representation. + * @param[in] dir - The direction of the graph. + * @returns A `NetlistGraph` representing the sequential connections within the netlist. + */ + NetlistGraph construct_sequential_netlist_graph(const Netlist* nl, const std::vector& gates, const GraphDirection& dir); - NetlistGraph construct_netlist_graph(const Netlist* nl, const std::vector& gates, const GraphDirection& dir); + /** + * @brief Annotates a netlist graph with features for machine learning tasks. + * + * This function annotates a netlist graph by attaching features to each node. This is only for visualization and testing purposes. + * + * @param[in] nl - The netlist to annotate. + * @param[in] gates - The set of gates in the netlist graph. + * @param[in] nlg - The netlist graph to annotate. + * @param[in] node_features - A matrix of features for each node. + */ + void annotate_netlist_graph(Netlist* nl, const std::vector& gates, const NetlistGraph& nlg, const std::vector>& node_features); - void annotate_netlist_graph(Netlist* nl, const std::vector& gates, const NetlistGraph& nlg, const std::vector>& node_features); - } // namespace graph } // namespace machine_learning } // namespace hal \ No newline at end of file diff --git a/plugins/machine_learning/python/python_bindings.cpp b/plugins/machine_learning/python/python_bindings.cpp index 5c89f90cc6f..e63449a4f3c 100644 --- a/plugins/machine_learning/python/python_bindings.cpp +++ b/plugins/machine_learning/python/python_bindings.cpp @@ -30,7 +30,6 @@ namespace hal py::module py_gate_feature = m.def_submodule("gate_feature"); py::module py_gate_pair_feature = m.def_submodule("gate_pair_feature"); py::module py_gate_pair_label = m.def_submodule("gate_pair_label"); - py::module py_graph = m.def_submodule("graph"); py::class_, BasePluginInterface> py_machine_learning_plugin( m, "MachineLearningPlugin", R"(Provides machine learning functionality as a plugin within the HAL framework.)"); @@ -104,12 +103,12 @@ namespace hal )"); // Bindings for construct_netlist_graph - py_graph.def("construct_netlist_graph", - &machine_learning::graph::construct_netlist_graph, - py::arg("netlist"), - py::arg("gates"), - py::arg("direction"), - R"( + m.def("construct_netlist_graph", + &machine_learning::graph::construct_netlist_graph, + py::arg("netlist"), + py::arg("gates"), + py::arg("direction"), + R"( Constructs a netlist graph from the given netlist and gates. :param hal_py.Netlist netlist: The netlist. @@ -120,13 +119,13 @@ namespace hal )"); // Bindings for annotate_netlist_graph - py_graph.def("annotate_netlist_graph", - &machine_learning::graph::annotate_netlist_graph, - py::arg("netlist"), - py::arg("gates"), - py::arg("netlist_graph"), - py::arg("node_features"), - R"( + m.def("annotate_netlist_graph", + &machine_learning::graph::annotate_netlist_graph, + py::arg("netlist"), + py::arg("gates"), + py::arg("netlist_graph"), + py::arg("node_features"), + R"( Annotates the netlist graph with the given node features. :param hal_py.Netlist netlist: The netlist. diff --git a/plugins/machine_learning/scripts/ml_testing/minimal_test.py b/plugins/machine_learning/scripts/ml_testing/minimal_test.py index 2f2f76c6eb4..d3ebd7c6216 100644 --- a/plugins/machine_learning/scripts/ml_testing/minimal_test.py +++ b/plugins/machine_learning/scripts/ml_testing/minimal_test.py @@ -9,11 +9,11 @@ if user_name == "simon": base_path = "/home/simon/projects/hal/" benchmarks_base_path = pathlib.Path("/home/simon/projects/benchmarks") -if user_name == "klix": +elif user_name == "klix": base_path = "/home/klix/projects/hal/" benchmarks_base_path = pathlib.Path("/home/klix/projects/benchmarks") else: - print("add base paths foe user {}before executing...".format(user_name)) + print("add base paths for user {} before executing...".format(user_name)) exit() sys.path.append(base_path + "build/lib/") #this is where your hal python lib is located diff --git a/plugins/machine_learning/scripts/ml_testing/test_noise_resistance.py b/plugins/machine_learning/scripts/ml_testing/test_noise_resistance.py index a3b98f388da..e741f943d90 100644 --- a/plugins/machine_learning/scripts/ml_testing/test_noise_resistance.py +++ b/plugins/machine_learning/scripts/ml_testing/test_noise_resistance.py @@ -1,7 +1,7 @@ import torch -samples = 128 -noise_dimension = 1024 +samples = 256 +noise_dimension = 128 device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') @@ -54,7 +54,7 @@ def forward(self, x): model = NN().to(device) optimizer = torch.optim.Adam(model.parameters(), lr=0.001) -for epoch in range(10000): +for epoch in range(1000): optimizer.zero_grad() out = model(x.float()) diff --git a/plugins/machine_learning/src/graph_neural_network.cpp b/plugins/machine_learning/src/graph_neural_network.cpp index 806bb6c4241..6bdd87dec85 100644 --- a/plugins/machine_learning/src/graph_neural_network.cpp +++ b/plugins/machine_learning/src/graph_neural_network.cpp @@ -1,6 +1,7 @@ #include "machine_learning/graph_neural_network.h" #include "hal_core/defines.h" +#include "hal_core/netlist/decorators/netlist_abstraction_decorator.h" #include "hal_core/netlist/gate.h" #include "hal_core/netlist/netlist.h" #include "hal_core/utilities/utils.h" @@ -12,86 +13,152 @@ namespace hal { namespace machine_learning { - namespace graph + + NetlistGraph construct_netlist_graph(const Netlist* nl, const std::vector& gates, const GraphDirection& dir) { - NetlistGraph construct_netlist_graph(const Netlist* nl, const std::vector& gates, const GraphDirection& dir) + std::unordered_map gate_to_idx; + // init gate to index mapping + for (u32 g_idx = 0; g_idx < gates.size(); g_idx++) { - std::unordered_map gate_to_idx; - // init gate to index mapping - for (u32 g_idx = 0; g_idx < gates.size(); g_idx++) - { - const Gate* g = gates.at(g_idx); - gate_to_idx.insert({g, g_idx}); - } + const Gate* g = gates.at(g_idx); + gate_to_idx.insert({g, g_idx}); + } - // edge list - std::vector sources; - std::vector destinations; + // edge list + std::vector sources; + std::vector destinations; - for (const auto& g : gates) + for (const auto& g : gates) + { + const u32 g_idx = gate_to_idx.at(g); + if (dir == GraphDirection::directed_backward) { - const u32 g_idx = gate_to_idx.at(g); - if (dir == GraphDirection::directed_backward) + for (const auto& pre : g->get_unique_predecessors()) { - for (const auto& pre : g->get_unique_predecessors()) - { - sources.push_back(gate_to_idx.at(pre)); - destinations.push_back(g_idx); - } + sources.push_back(gate_to_idx.at(pre)); + destinations.push_back(g_idx); } + } - if (dir == GraphDirection::directed_forward) + if (dir == GraphDirection::directed_forward) + { + for (const auto& suc : g->get_unique_successors()) { - for (const auto& suc : g->get_unique_successors()) - { - sources.push_back(g_idx); - destinations.push_back(gate_to_idx.at(suc)); - } + sources.push_back(g_idx); + destinations.push_back(gate_to_idx.at(suc)); } + } - if (dir == GraphDirection::bidirectional) + if (dir == GraphDirection::bidirectional) + { + for (const auto& suc : g->get_unique_successors()) { - for (const auto& suc : g->get_unique_successors()) - { - sources.push_back(g_idx); - destinations.push_back(gate_to_idx.at(suc)); - - sources.push_back(gate_to_idx.at(suc)); - destinations.push_back(g_idx); - } + sources.push_back(g_idx); + destinations.push_back(gate_to_idx.at(suc)); + + sources.push_back(gate_to_idx.at(suc)); + destinations.push_back(g_idx); } } - - return {{sources, destinations}, dir}; } - void annotate_netlist_graph(Netlist* nl, const std::vector& gates, const NetlistGraph& nlg, const std::vector>& node_features) + return {{sources, destinations}, dir}; + } + + NetlistGraph construct_sequential_netlist_graph(const Netlist* nl, const std::vector& gates, const GraphDirection& dir) + { + std::unordered_map gate_to_idx; + // init gate to index mapping + for (u32 g_idx = 0; g_idx < gates.size(); g_idx++) { - for (u32 g_idx = 0; g_idx < gates.size(); g_idx++) + const Gate* g = gates.at(g_idx); + if (!g->get_type()->has_property(GateTypeProperty::sequential)) { - gates.at(g_idx)->set_data("netlist_graph", "gate_index", "string", std::to_string(g_idx)); + log_error("machine_learning", "got not sequnetial gate in gate vector for sequential netlist graph"); + return {}; + } - const auto feature_vec = node_features.at(g_idx); - const auto feature_str = utils::join(", ", feature_vec.begin(), feature_vec.end(), [](const u32 u) { return std::to_string(u); }); + gate_to_idx.insert({g, g_idx}); + } - gates.at(g_idx)->set_data("netlist_graph", "features", "string", feature_str); - } + const std::vector forbidden_pins = { + PinType::clock, /*PinType::done, PinType::error, PinType::error_detection,*/ /*PinType::none,*/ PinType::ground, PinType::power /*, PinType::status*/}; + + const auto endpoint_filter = [forbidden_pins](const auto* ep, const auto& _d) { + UNUSED(_d); + return std::find(forbidden_pins.begin(), forbidden_pins.end(), ep->get_pin()->get_type()) == forbidden_pins.end(); + }; - std::unordered_map> edges; - for (u32 edge_idx = 0; edge_idx < nlg.edge_list.first.size(); edge_idx++) + const auto sequential_abstraction = NetlistAbstraction(nl, gates, true, endpoint_filter, endpoint_filter); + + // edge list + std::vector sources; + std::vector destinations; + + for (const auto& g : gates) + { + const u32 g_idx = gate_to_idx.at(g); + if (dir == GraphDirection::directed_backward) { - const auto src = nlg.edge_list.first.at(edge_idx); - const auto dst = nlg.edge_list.second.at(edge_idx); + for (const auto& pre : sequential_abstraction.get_unique_predecessors(g)) + { + sources.push_back(gate_to_idx.at(pre)); + destinations.push_back(g_idx); + } + } - edges[src].push_back(dst); + if (dir == GraphDirection::directed_forward) + { + for (const auto& suc : sequential_abstraction.get_unique_successors(g)) + { + sources.push_back(g_idx); + destinations.push_back(gate_to_idx.at(suc)); + } } - for (const auto [src, dsts] : edges) + if (dir == GraphDirection::bidirectional) { - const auto vec_str = utils::join(", ", dsts.begin(), dsts.end(), [](const u32 u) { return std::to_string(u); }); - gates.at(src)->set_data("netlist_graph", "destinations", "string", vec_str); + for (const auto& suc : sequential_abstraction.get_unique_successors(g)) + { + sources.push_back(g_idx); + destinations.push_back(gate_to_idx.at(suc)); + + sources.push_back(gate_to_idx.at(suc)); + destinations.push_back(g_idx); + } } } - } // namespace graph + + return {{sources, destinations}, dir}; + } + + void annotate_netlist_graph(Netlist* nl, const std::vector& gates, const NetlistGraph& nlg, const std::vector>& node_features) + { + for (u32 g_idx = 0; g_idx < gates.size(); g_idx++) + { + gates.at(g_idx)->set_data("netlist_graph", "gate_index", "string", std::to_string(g_idx)); + + const auto feature_vec = node_features.at(g_idx); + const auto feature_str = utils::join(", ", feature_vec.begin(), feature_vec.end(), [](const u32 u) { return std::to_string(u); }); + + gates.at(g_idx)->set_data("netlist_graph", "features", "string", feature_str); + } + + std::unordered_map> edges; + for (u32 edge_idx = 0; edge_idx < nlg.edge_list.first.size(); edge_idx++) + { + const auto src = nlg.edge_list.first.at(edge_idx); + const auto dst = nlg.edge_list.second.at(edge_idx); + + edges[src].push_back(dst); + } + + for (const auto [src, dsts] : edges) + { + const auto vec_str = utils::join(", ", dsts.begin(), dsts.end(), [](const u32 u) { return std::to_string(u); }); + gates.at(src)->set_data("netlist_graph", "destinations", "string", vec_str); + } + } + } // namespace machine_learning } // namespace hal \ No newline at end of file