diff --git a/notebooks/basics/0_how_to_work_with_onnx.ipynb b/notebooks/basics/0_how_to_work_with_onnx.ipynb index a4ea75fe38aac6720671a9b51de0ef31951cccb0..514efd1693d667af896e89902a264ea7e6e01da7 100644 --- a/notebooks/basics/0_how_to_work_with_onnx.ipynb +++ b/notebooks/basics/0_how_to_work_with_onnx.ipynb @@ -313,7 +313,7 @@ "source": [ "In the following we assume that we do not know the appearance of the model, so we first try to identify whether there are two consecutive adders in the graph and then convert them into a sum node. \n", "\n", - "Here we make use of FINN. FINN provides a thin wrapper around the model which provides several additional helper functions to manipulate the graph. The code can be found [here](https://github.com/Xilinx/finn/blob/master/src/finn/core/modelwrapper.py)." + "Here we make use of FINN. FINN provides a thin wrapper around the model which provides several additional helper functions to manipulate the graph. The so called `ModelWrapper` can be found in the QONNX repository which contains a lot of functionality that is used by FINN, you can find it [here](https://github.com/fastmachinelearning/qonnx/blob/main/src/qonnx/core/modelwrapper.py)." ] }, { @@ -395,36 +395,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Among other helper functions, `ModelWrapper` offers two functions that can help to determine the preceding and succeeding node of a node. However, these functions are not getting a node as input, but can determine the consumer or producer of a tensor. We write two functions that uses these helper functions to determine the previous and the next node of a node." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def find_predecessor(model, node):\n", - " predecessors = []\n", - " for i in range(len(node.input)):\n", - " producer = model.find_producer(node.input[i])\n", - " predecessors.append(producer)\n", - " return predecessors\n", - " \n", - "\n", - "def find_successor(model, node):\n", - " successors = []\n", - " for i in range(len(node.output)):\n", - " consumer = model.find_consumer(node.output[i])\n", - " successors.append(consumer)\n", - " return successors" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The first function uses `find_producer` from `ModelWrapper` to create a list of the producers of the inputs of the given node. So the returned list is indirectly filled with the predecessors of the node. The second function works in a similar way, `find_consumer` from `ModelWrapper` is used to find the consumers of the output tensors of the node and so a list with the successors can be created. " + "Among other helper functions, `ModelWrapper` offers two functions that can help to determine the preceding and succeeding node of a node: `find_direct_successors` and `find_direct_predecessors`. So we can use one of them to define a function to find adder pairs." ] }, { @@ -436,7 +407,7 @@ "def adder_pair(model, node):\n", " adder_pairs = []\n", " node_pair = []\n", - " successor_list = find_successor(model, node)\n", + " successor_list = model.find_direct_successors(node)\n", " \n", " for successor in successor_list:\n", " if successor.op_type == \"Add\":\n", @@ -444,15 +415,14 @@ " node_pair.append(successor)\n", " adder_pairs.append((node_pair))\n", " node_pair = []\n", - " return adder_pairs\n", - " " + " return adder_pairs " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "The function gets a node and the model as input. Two empty lists are created to be filled with a list of adder node pairs that can be returned as result of the function. Then the function `find_successor` is used to return all of the successors of the node. If one of the successors is an adder node, the node is saved in `node_pair` together with the successive adder node and put in the list `adder_pairs`. Then the temporary list is cleaned and can be filled with the next adder node pair. Since it is theoretically possible for an adder node to have more than one subsequent adder node, a list of lists is created. This list of the node with all its successive adder nodes is returned.\n", + "The function gets a node and the model as input. Two empty lists are created to be filled with a list of adder node pairs that can be returned as result of the function. Then the function `find_direct_successors` is used to return all of the successors of the node. If one of the successors is an adder node, the node is saved in `node_pair` together with the successive adder node and put in the list `adder_pairs`. Then the temporary list is cleaned and can be filled with the next adder node pair. Since it is theoretically possible for an adder node to have more than one subsequent adder node, a list of lists is created. This list of the node with all its successive adder nodes is returned.\n", "\n", "So now we can find out which adder node has an adder node as successor. Since the model is known, one adder pair (Add1+Add2) should be found when applying the function to the previously determined adder node list (`add_nodes`)." ] @@ -522,7 +492,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The summary node can be created with this information." + "The sum node can be created with this information." ] }, { @@ -642,7 +612,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.6.8" + "version": "3.8.5" } }, "nbformat": 4,