From 2db61685a41304522869707f7c30bf81e5b17755 Mon Sep 17 00:00:00 2001 From: auphelia <jakobapk@web.de> Date: Tue, 17 Dec 2019 12:34:01 +0000 Subject: [PATCH] [notebook] Changed font size back to normal --- notebooks/FINN-HowToWorkWithONNX.ipynb | 89 +++++++++----------------- 1 file changed, 32 insertions(+), 57 deletions(-) diff --git a/notebooks/FINN-HowToWorkWithONNX.ipynb b/notebooks/FINN-HowToWorkWithONNX.ipynb index 4c79fb0be..4d866325a 100644 --- a/notebooks/FINN-HowToWorkWithONNX.ipynb +++ b/notebooks/FINN-HowToWorkWithONNX.ipynb @@ -6,7 +6,7 @@ "source": [ "# FINN - How to work with ONNX\n", "\n", - "<font size=\"3\">This notebook should give an overview of ONNX ProtoBuf, help to create and manipulate an ONNX model and use FINN functions to work with it. There may be overlaps to other notebooks, like [FINN-ModelWrapper](FINN-ModelWrapper.ipynb) and [FINN-CustomOps](FINN-CustomOps.ipynb), but this notebook will give an overview about the handling of ONNX models in FINN. </font>" + "This notebook should give an overview of ONNX ProtoBuf, help to create and manipulate an ONNX model and use FINN functions to work with it. There may be overlaps to other notebooks, like [FINN-ModelWrapper](FINN-ModelWrapper.ipynb) and [FINN-CustomOps](FINN-CustomOps.ipynb), but this notebook will give an overview about the handling of ONNX models in FINN." ] }, { @@ -24,14 +24,14 @@ "source": [ "### How to create a simple model\n", "\n", - "<font size=\"3\">To explain how to create an ONNX graph a simple example with mathematical operations is used. All nodes are from the [standard operations library of ONNX](https://github.com/onnx/onnx/blob/master/docs/Operators.md).\n", + "To explain how to create an ONNX graph a simple example with mathematical operations is used. All nodes are from the [standard operations library of ONNX](https://github.com/onnx/onnx/blob/master/docs/Operators.md).\n", "\n", - "First ONNX is imported, then the helper function can be used to make a node.</font>" + "First ONNX is imported, then the helper function can be used to make a node." ] }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -49,14 +49,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "<font size=\"3\">The first attribute of the node is the operation type. In this case it is `'Add'`, so it is an adder node. Then the input names are passed to the node and at the end a name is assigned to the output.\n", + "The first attribute of the node is the operation type. In this case it is `'Add'`, so it is an adder node. Then the input names are passed to the node and at the end a name is assigned to the output.\n", " \n", - "For this example we want two other adder nodes, one abs node and the output shall be rounded so one round node is needed. </font>" + "For this example we want two other adder nodes, one abs node and the output shall be rounded so one round node is needed." ] }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -93,7 +93,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "<font size=\"3\">The names of the inputs and outputs of the nodes give already an idea of the structure of the resulting graph. In order to integrate the nodes into a graph environment, the inputs and outputs of the graph have to be specified first. In ONNX all data edges are processed as tensors. So with the helper function tensor value infos are created for the input and output tensors of the graph. Float from ONNX is used as data type. </font>" + "The names of the inputs and outputs of the nodes give already an idea of the structure of the resulting graph. In order to integrate the nodes into a graph environment, the inputs and outputs of the graph have to be specified first. In ONNX all data edges are processed as tensors. So with the helper function tensor value infos are created for the input and output tensors of the graph. Float from ONNX is used as data type. " ] }, { @@ -112,9 +112,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "<font size=\"3\">Now the graph can be built. First all nodes are passed. Here it is to be noted that it requires a certain sequence. The nodes must be instantiated in their dependencies to each other. This means Add2 must not be listed before Add1, because Add2 depends on the result of Add1. A name is then assigned to the graph. This is followed by the inputs and outputs. \n", + "Now the graph can be built. First all nodes are passed. Here it is to be noted that it requires a certain sequence. The nodes must be instantiated in their dependencies to each other. This means Add2 must not be listed before Add1, because Add2 depends on the result of Add1. A name is then assigned to the graph. This is followed by the inputs and outputs. \n", "\n", - "`value_info` of the graph contains the remaining tensors within the graph. When creating the nodes we have already defined names for the inner data edges and now these are assigned tensors of the datatype float and a certain shape.</font>" + "`value_info` of the graph contains the remaining tensors within the graph. When creating the nodes we have already defined names for the inner data edges and now these are assigned tensors of the datatype float and a certain shape." ] }, { @@ -147,9 +147,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "<font size=\"3\">**Important**: In our example, the shape of the tensors does not change during the calculation. This is not always the case. So you have to make sure that you specify the shape correctly.\n", + "**Important**: In our example, the shape of the tensors does not change during the calculation. This is not always the case. So you have to make sure that you specify the shape correctly.\n", "\n", - "Now a model can be created from the graph and saved using the `.save` function. The model is saved in .onnx format and can be reloaded with `onnx.load()`. This also means that you can easily share your own model in .onnx format with others.</font>" + "Now a model can be created from the graph and saved using the `.save` function. The model is saved in .onnx format and can be reloaded with `onnx.load()`. This also means that you can easily share your own model in .onnx format with others." ] }, { @@ -166,7 +166,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "<font size='3'>To visualize the created model, [netron](https://github.com/lutzroeder/netron) can be used. Netron is a visualizer for neural network, deep learning and machine learning models. <font>" + "To visualize the created model, [netron](https://github.com/lutzroeder/netron) can be used. Netron is a visualizer for neural network, deep learning and machine learning models." ] }, { @@ -216,9 +216,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "<font size=\"3\">Netron also allows you to interactively explore the model. If you click on a node, the node attributes will be displayed. \n", + "Netron also allows you to interactively explore the model. If you click on a node, the node attributes will be displayed. \n", "\n", - "In order to test the resulting model, a function is first written in Python that calculates the expected output. Because numpy arrays are to be used, numpy is imported first.</font>" + "In order to test the resulting model, a function is first written in Python that calculates the expected output. Because numpy arrays are to be used, numpy is imported first." ] }, { @@ -241,7 +241,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "<font size=\"3\">Then the values for the three inputs are calculated. Random numbers are used.</font>" + "Then the values for the three inputs are calculated. Random numbers are used." ] }, { @@ -259,7 +259,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "<font size=\"3\">We can easily pass the values to the function we just wrote to calculate the expected result. For the created model the inputs must be summarized in a dictionary, which is then passed on to the model.</font>" + "We can easily pass the values to the function we just wrote to calculate the expected result. For the created model the inputs must be summarized in a dictionary, which is then passed on to the model." ] }, { @@ -278,7 +278,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "<font size=\"3\">To run the model and calculate the output, [onnxruntime](https://github.com/microsoft/onnxruntime) can be used. ONNX Runtime is a performance-focused complete scoring engine for Open Neural Network Exchange (ONNX) models from Microsoft. The `.InferenceSession` function is used to create a session of the model and `.run` is used to execute the model. </font>" + "To run the model and calculate the output, [onnxruntime](https://github.com/microsoft/onnxruntime) can be used. ONNX Runtime is a performance-focused complete scoring engine for Open Neural Network Exchange (ONNX) models from Microsoft. The `.InferenceSession` function is used to create a session of the model and `.run` is used to execute the model." ] }, { @@ -297,7 +297,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "<font size=\"3\">The input values are also transferred to the reference function. Now the output of the execution of the model can be compared with that of the reference. </font>" + "The input values are also transferred to the reference function. Now the output of the execution of the model can be compared with that of the reference." ] }, { @@ -340,7 +340,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "<font size=\"3\">Now that we have verified that the model works as we expected it to, we can continue working with the graph. </font>" + "Now that we have verified that the model works as we expected it to, we can continue working with the graph." ] }, { @@ -349,16 +349,16 @@ "source": [ "### How to manipulate an ONNX model\n", "\n", - "<font size=\"3\">In the model there are two successive adder nodes. An adder node in ONNX can only add two inputs, but there is also the [**sum**](https://github.com/onnx/onnx/blob/master/docs/Operators.md#Sum) node, which can process more than one input. So it would be a reasonable change of the graph to combine the two successive adder nodes to one sum node. </font>" + "In the model there are two successive adder nodes. An adder node in ONNX can only add two inputs, but there is also the [**sum**](https://github.com/onnx/onnx/blob/master/docs/Operators.md#Sum) node, which can process more than one input. So it would be a reasonable change of the graph to combine the two successive adder nodes to one sum node." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "<font size=\"3\">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", + "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/dev/src/finn/core/modelwrapper.py) and you can find a more detailed description in the notebook [FINN-ModelWrapper](FINN-ModelWrapper.ipynb).</font>" + "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/dev/src/finn/core/modelwrapper.py) and you can find a more detailed description in the notebook [FINN-ModelWrapper](FINN-ModelWrapper.ipynb)." ] }, { @@ -382,7 +382,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "<font size=\"3\">Now we design a function that searches for adder nodes in the graph and returns the found nodes. </font>" + "Now we design a function that searches for adder nodes in the graph and returns the found nodes. " ] }, { @@ -404,9 +404,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "<font size=\"3\">The function iterates over all nodes of the model and if the operation type is `\"Add\"` the node will be stored in `add_nodes`. At the end `add_nodes` is returned.\n", + "The function iterates over all nodes of the model and if the operation type is `\"Add\"` the node will be stored in `add_nodes`. At the end `add_nodes` is returned.\n", "\n", - "If we apply this to our model, three nodes should be returned.</font> " + "If we apply this to our model, three nodes should be returned." ] }, { @@ -434,7 +434,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "<font size=\"3\">Among other helper functions, ModelWrapper offers two functions 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.</font>" + "Among other helper functions, ModelWrapper offers two functions 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." ] }, { @@ -463,9 +463,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "<font size=\"3\">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. \n", + "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. \n", "\n", - "So now we can find out which adder node has an adder node as successor</font>" + "So now we can find out which adder node has an adder node as successor." ] }, { @@ -526,14 +526,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "<font size=\"3\">Now that the pair to be replaced has been identified, a sum node can be instantiated and inserted into the graph at the correct position. \n", + "Now that the pair to be replaced has been identified, a sum node can be instantiated and inserted into the graph at the correct position. \n", "\n", - "First of all, the inputs must be determined. For this the adder nodes inputs are used minus the input, which corresponds to the output of the other adder node.</font>" + "First of all, the inputs must be determined. For this the adder nodes inputs are used minus the input, which corresponds to the output of the other adder node." ] }, { "cell_type": "code", - "execution_count": 74, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -549,31 +549,6 @@ " input_list.append(substitute_pair[i].input[j])\n", " " ] - }, - { - "cell_type": "code", - "execution_count": 73, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "['in1', 'in2', 'in3']" - ] - }, - "execution_count": 73, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { -- GitLab