diff --git a/notebooks/end2end_example/cnv_end2end_example.ipynb b/notebooks/end2end_example/cnv_end2end_example.ipynb index f4bff38ce3bf893254f1fd3633a2019bb1b71f13..ce8c9decf4aaa6b7be2e556b6053abf380d0d373 100644 --- a/notebooks/end2end_example/cnv_end2end_example.ipynb +++ b/notebooks/end2end_example/cnv_end2end_example.ipynb @@ -274,7 +274,7 @@ "from finn.transformation.fpgadataflow.create_dataflow_partition import (\n", " CreateDataflowPartition,\n", ")\n", - "from finn.transformation.move_reshape import MoveReshape\n", + "from finn.transformation.move_reshape import RemoveCNVtoFCFlatten\n", "from finn.custom_op.registry import getCustomOp\n", "\n", "# choose the memory mode for the MVTU units, decoupled or const\n", @@ -286,7 +286,7 @@ "model = model.transform(to_hls.InferConvInpGen())\n", "model = model.transform(to_hls.InferStreamingMaxPool())\n", "# get rid of Reshape(-1, 1) operation between hlslib nodes\n", - "model = model.transform(MoveReshape())\n", + "model = model.transform(RemoveCNVtoFCFlatten())\n", "parent_model = model.transform(CreateDataflowPartition())\n", "parent_model.save(build_dir + \"/end2end_cnv_w1a1_dataflow_parent.onnx\")\n", "sdp_node = parent_model.get_nodes_by_op_type(\"StreamingDataflowPartition\")[0]\n", @@ -301,7 +301,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Notice the additional `MoveReshape` transformation that was not used for TFC-w1a1. In the last Netron visualization you may have noticed a `Reshape` operation towards the end of the network where the convolutional part of the network ends and the fully-connected layers started. That `Reshape` is essentialy a tensor flattening operation, which we can remove for the purposes of hardware implementation. We can examine the contents of the dataflow partition with Netron, and observe the `ConvolutionInputGenerator`, `StreamingFCLayer_Batch` and `StreamingMaxPool_Batch` nodes that implement the sliding window, matrix multiply and maxpool operations in hlslib. *Note that the StreamingFCLayer instances following the ConvolutionInputGenerator nodes are really implementing the convolutions, despite the name. The final three StreamingFCLayer instances implement actual FC layers.*" + "Notice the additional `RemoveCNVtoFCFlatten` transformation that was not used for TFC-w1a1. In the last Netron visualization you may have noticed a `Reshape` operation towards the end of the network where the convolutional part of the network ends and the fully-connected layers started. That `Reshape` is essentialy a tensor flattening operation, which we can remove for the purposes of hardware implementation. We can examine the contents of the dataflow partition with Netron, and observe the `ConvolutionInputGenerator`, `StreamingFCLayer_Batch` and `StreamingMaxPool_Batch` nodes that implement the sliding window, matrix multiply and maxpool operations in hlslib. *Note that the StreamingFCLayer instances following the ConvolutionInputGenerator nodes are really implementing the convolutions, despite the name. The final three StreamingFCLayer instances implement actual FC layers.*" ] }, { diff --git a/src/finn/transformation/move_reshape.py b/src/finn/transformation/move_reshape.py index 6a30fd93cc0bdc322b6ec7d892d42d3c3ca96fd6..2ddaf4f840f449d3f5ec5cb83eaf461d624eb7a2 100644 --- a/src/finn/transformation/move_reshape.py +++ b/src/finn/transformation/move_reshape.py @@ -17,7 +17,7 @@ def _is_fpgadataflow_node(node): return False -class MoveReshape(Transformation): +class RemoveCNVtoFCFlatten(Transformation): """Removes a node that implements a (1, -1) reshape if it is between two fpgadataflow nodes""" @@ -27,13 +27,13 @@ class MoveReshape(Transformation): graph_modified = False for n in graph.node: if n.op_type == "Reshape": - graph_modified = True shape = model.get_initializer(n.input[1]) if (shape == [1, -1]).all(): producer = model.find_producer(n.input[0]) if _is_fpgadataflow_node(producer) is True: consumer = model.find_consumer(n.output[0]) if _is_fpgadataflow_node(consumer) is True: + graph_modified = True consumer.input[0] = n.input[0] graph.node.remove(n) diff --git a/tests/end2end/test_end2end_cnv_w1a1.py b/tests/end2end/test_end2end_cnv_w1a1.py index d7f59ef35aaf61891937dcaa105cf1392133e732..703cb7ad92d6f4ec6dd67a05345f323a73ee178d 100644 --- a/tests/end2end/test_end2end_cnv_w1a1.py +++ b/tests/end2end/test_end2end_cnv_w1a1.py @@ -41,7 +41,7 @@ from finn.custom_op.registry import getCustomOp from finn.core.onnx_exec import execute_onnx from finn.transformation.double_to_single_float import DoubleToSingleFloat from finn.transformation.infer_shapes import InferShapes -from finn.transformation.move_reshape import MoveReshape +from finn.transformation.move_reshape import RemoveCNVtoFCFlatten from finn.transformation.fold_constants import FoldConstants from finn.transformation.general import GiveReadableTensorNames, GiveUniqueNodeNames from finn.transformation.streamline import Streamline @@ -117,7 +117,7 @@ def test_end2end_cnv_w1a1_convert_to_hls_layers(): model = model.transform(to_hls.InferQuantizedStreamingFCLayer(mem_mode)) model = model.transform(to_hls.InferConvInpGen()) model = model.transform(to_hls.InferStreamingMaxPool()) - model = model.transform(MoveReshape()) + model = model.transform(RemoveCNVtoFCFlatten()) model.save(build_dir + "/end2end_cnv_w1a1_hls_layers.onnx")