Graph ===== .. contents:: :depth: 2 :local: Node ---- The Node class is used to form a node in a graph. In Aidge, there is no "edge" object per se, as the references to parent and child nodes are contained in the node. There is no graph container in Aidge: connected nodes intrinsically form a graph. .. tab-set:: .. tab-item:: Python .. autoclass:: aidge_core.Node :members: :inherited-members: .. tab-item:: C++ .. doxygenclass:: Aidge::Node GraphView --------- As the name suggests, a GraphView is not a graph container, but merely a "view" of some nodes in a graph. There can be multiple overlapping views of nodes in a graph. Nodes in a view do not have to form a single connected graph. A GraphView is however more than just a set of nodes. It has the following features: - It keeps track of all its inputs and outputs (if the parent of a node is not in the GraphView, the node is an input node for the GraphView). Furthermore, the GraphView inputs/outputs are ordered, and the order is **stable** during insertion or deletion of nodes in the GraphView; - There is a root node in the GraphView (by default, the first node added to it), and nodes inside a GraphView can be ranked with a unique and deterministic order if the nodes form a single connected graph; - Some methods can be applied globally to the GraphView, like ``setBackend()``. .. tab-set:: .. tab-item:: Python .. autoclass:: aidge_core.GraphView :members: :inherited-members: .. tab-item:: C++ .. doxygenclass:: Aidge::GraphView It is possible to automatically generate a GraphView that encompasses all the connected nodes with a path to a given node with the ``getConnectedGraphView`` function: .. tab-set:: .. tab-item:: Python .. autofunction:: aidge_core.get_connected_graph_view .. tab-item:: C++ .. doxygenfunction:: Aidge::getConnectedGraphView Graph helpers ------------- Graph helpers are pseudo-containers that allow you to quickly build a graph without explicit node connections, like the ``Sequential`` container in PyTorch. One important difference with PyTorch is that they are only temporary builders, and do not form a structure in the returned graph. They return a GraphView. .. tab-set:: .. tab-item:: Python .. autofunction:: aidge_core.sequential Usage example: .. code-block:: python input_data = np.array([0, 1, 2, 3]).astype(np.float32) input_tensor = aidge_core.Tensor(input_data) graph_view = aidge_core.sequential([ aidge_core.Producer(input_tensor, "IN"), aidge_core.FC(1, 50, name='FC0'), aidge_core.FC(50, 50, name='FC1'), aidge_core.FC(50, 10, name='FC2'), ]) .. tab-item:: C++ .. doxygenfunction:: Aidge::Sequential Usage example: .. code-block:: C++ auto input_tensor = std::make_shared(Array1D{{0, 1, 2, 3}}); auto graph_view = Sequential({ Producer(input_tensor, "IN"), FC(1, 50, false, "FC0"), FC(50, 50, false, "FC1"), FC(50, 10, false, "FC2") }) .. tab-set:: .. tab-item:: Python .. autofunction:: aidge_core.parallel Usage example: .. code-block:: python input_data = np.array([0, 1, 2, 3]).astype(np.float32) input_tensor = aidge_core.Tensor(input_data) graph_view = aidge_core.sequential([ aidge_core.Producer(input_tensor, "X"), aidge_core.FC(1, 50, name='FC0'), aidge_core.parallel([ aidge_core.FC(50, 50, name='FC1'), aidge_core.FC(50, 50, name='FC3') ]), aidge_core.Add(2, name='FC2'), ]) .. tab-item:: C++ .. doxygenfunction:: Aidge::Parallel Usage example: .. code-block:: C++ auto g = Sequential({ Conv(1, 3, {3, 3}, "inputConv"), Parallel({ Conv(3, 3, {1, 1}, "conv1.1"), Conv(3, 3, {1, 1}, "conv1.2"), Conv(3, 3, {1, 1}, "conv1.3") }), Add(3, "add1"), Conv(3, 2, {1, 1}, "conv2"), FC(18, 5, false, "out") }); .. tab-set:: .. tab-item:: Python .. autofunction:: aidge_core.residual .. tab-item:: C++ .. doxygenfunction:: Aidge::Residual Connector --------- The Connector object enables you to build a graph in a functional style like you would often do in other DL frameworks. However, please note that doing so is just a way of building a graph, and does not result in any "eager" execution. Using an explicit Connector object is here to make that intent clear. Additionally, it is possible to mix both graph helpers and functional Connector-based styles. .. tab-set:: .. tab-item:: Python .. autoclass:: aidge_core.Connector :members: :inherited-members: .. tab-item:: C++ .. doxygenclass:: Aidge::Connector Usage example: .. code-block:: C++ auto x = Connector(); auto y = Connector(); x = (*GenericOperator("Producer", 0, 0, 1))({}); y = (*GenericOperator("Producer", 0, 0, 1))({}); // Connect 5 successive convolution for (int i = 0; i < 5; ++i) { x = (*GenericOperator("Conv", 1, 0, 1))({x}); } y = (*GenericOperator("ElemWise", 2, 0, 1))({y, x}); // Create a GraphView auto g = generateGraph({y}); A GraphView can be obtained directly from the last Connector with the ``generateGraph`` function. .. tab-set:: .. tab-item:: Python .. autofunction:: aidge_core.generate_graph .. tab-item:: C++ .. doxygenfunction:: Aidge::generateGraph