From f9d44ea30c4885ca8c9143152dd2609dcc9a22c5 Mon Sep 17 00:00:00 2001 From: Felix Jentzsch Date: Thu, 1 Jul 2021 17:49:24 +0200 Subject: [PATCH 01/49] Fix: Sorting of labeled ImageNet subfolders --- finn_examples/notebooks/2_imagenet_with_cnns.ipynb | 1 + 1 file changed, 1 insertion(+) diff --git a/finn_examples/notebooks/2_imagenet_with_cnns.ipynb b/finn_examples/notebooks/2_imagenet_with_cnns.ipynb index 164f1ef..93ed7ed 100755 --- a/finn_examples/notebooks/2_imagenet_with_cnns.ipynb +++ b/finn_examples/notebooks/2_imagenet_with_cnns.ipynb @@ -166,6 +166,7 @@ "def setup_dataloader(val_path, label_file_path = None, batch_size=100, n_images = 50000):\n", " if label_file_path is None:\n", " val_folders = [ f.name for f in os.scandir(val_path) if f.is_dir() ]\n", + " val_folders = sorted(val_folders)\n", " assert len(val_folders) == 1000, \"Expected 1000 subfolders in ILSVRC2012 val\"\n", " files = []\n", " labels = []\n", From 9816d979e7a2f9cf8ab04ddef142cdcbb95a5626 Mon Sep 17 00:00:00 2001 From: Nael Fasfous Date: Wed, 14 Jul 2021 23:45:03 +0200 Subject: [PATCH 02/49] [Notebook] Added BinCoP face-mask detection example --- finn_examples/models.py | 18 +- .../3_binarycop_mask_detection.ipynb | 466 ++++++++++++++++++ 2 files changed, 483 insertions(+), 1 deletion(-) create mode 100644 finn_examples/notebooks/3_binarycop_mask_detection.ipynb diff --git a/finn_examples/models.py b/finn_examples/models.py index 9dd69aa..1ec9aaf 100644 --- a/finn_examples/models.py +++ b/finn_examples/models.py @@ -57,6 +57,17 @@ "oshape_packed": (1, 1, 1), } +_bincop_cnv_io_shape_dict = { + "idt": DataType.UINT8, + "odt": DataType.UINT8, + "ishape_normal": (1, 72, 72, 3), + "oshape_normal": (1, 1), + "ishape_folded": (1, 1, 72, 72, 1, 3), + "oshape_folded": (1, 1, 1), + "ishape_packed": (1, 1, 72, 72, 1, 3), + "oshape_packed": (1, 1, 1), +} + _imagenet_top5inds_io_shape_dict = { "idt": DataType.UINT8, "odt": DataType.UINT16, @@ -83,7 +94,6 @@ "number_of_external_weights": 1 } - # from https://github.com/Xilinx/PYNQ-HelloWorld/blob/master/setup.py # get current platform: either edge or pcie @@ -202,6 +212,12 @@ def cnv_w2a2_cifar10(target_platform=None): filename = find_bitfile(model_name, target_platform) return FINNExampleOverlay(filename, driver_mode, _cifar10_cnv_io_shape_dict) +def bincop_cnv(target_platform=None): + target_platform = resolve_target_platform(target_platform) + driver_mode = get_driver_mode() + model_name = "bincop-cnv" + filename = find_bitfile(model_name, target_platform) + return FINNExampleOverlay(filename, driver_mode, _bincop_cnv_io_shape_dict) def mobilenetv1_w4a4_imagenet(target_platform=None): target_platform = resolve_target_platform(target_platform) diff --git a/finn_examples/notebooks/3_binarycop_mask_detection.ipynb b/finn_examples/notebooks/3_binarycop_mask_detection.ipynb new file mode 100644 index 0000000..1d8f5bf --- /dev/null +++ b/finn_examples/notebooks/3_binarycop_mask_detection.ipynb @@ -0,0 +1,466 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "data": { + "application/javascript": [ + "\n", + "require(['notebook/js/codecell'], function(codecell) {\n", + " codecell.CodeCell.options_default.highlight_modes[\n", + " 'magic_text/x-csrc'] = {'reg':[/^%%microblaze/]};\n", + " Jupyter.notebook.events.one('kernel_ready.Kernel', function(){\n", + " Jupyter.notebook.get_cells().map(function(cell){\n", + " if (cell.cell_type == 'code'){ cell.auto_highlight(); } }) ;\n", + " });\n", + "});\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from finn_examples import models\n", + "import os\n", + "from PIL import Image\n", + "import numpy as np\n", + "import cv2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Initialize the Accelerator" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "accel = models.bincop_cnv()" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Expected input shape and datatype: (1, 72, 72, 3) DataType.UINT8\n", + "Expected output shape and datatype: (1, 1) DataType.UINT8\n" + ] + } + ], + "source": [ + "class_dict = {0: \"Correctly Masked\", 1: \"Incorrectly Worn\", 2: \"No Mask\"}\n", + "\n", + "print(\"Expected input shape and datatype: %s %s\" % (str(accel.ishape_normal), str(accel.idt)))\n", + "print(\"Expected output shape and datatype: %s %s\" % (str(accel.oshape_normal), str(accel.odt)))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Load Mask Examples" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "mask_examples_dir = \"/tmp/mask_examples\"\n", + "if not os.path.exists(mask_examples_dir):\n", + " os.makedirs(mask_examples_dir)\n", + " \n", + "for i in range(6):\n", + " if \"{}.jpg\".format(i+1) not in os.listdir(mask_examples_dir):\n", + " os.system(\"wget -P \" + mask_examples_dir + \" https://github.com/NaelF/BinaryCoP/raw/master/notebook/pictures/{}.jpg\".format(i+1))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Run Inference" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "def resize(img):\n", + " img = np.array(img)\n", + " if img.shape[0] != 72 or img.shape[1] != 72:\n", + " resized_img = cv2.resize(img,(72,72))\n", + " return (resized_img) \n", + " else: return img" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Returned class is: Correctly Masked\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Returned class is: Correctly Masked\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Returned class is: Incorrectly Worn\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Returned class is: Incorrectly Worn\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Returned class is: No Mask\n" + ] + } + ], + "source": [ + "im = Image.open(mask_examples_dir + '/1.jpg')\n", + "im = resize(im)\n", + "accel_in = im.reshape(accel.ishape_normal)\n", + "im = Image.fromarray(im, 'RGB')\n", + "display(im)\n", + "accel_out = accel.execute(accel_in)\n", + "print(\"Returned class is: \" + class_dict[int(accel_out)])\n", + "\n", + "im = Image.open(mask_examples_dir + '/2.jpg')\n", + "im = resize(im)\n", + "accel_in = im.reshape(accel.ishape_normal)\n", + "im = Image.fromarray(im, 'RGB')\n", + "display(im)\n", + "accel_out = accel.execute(accel_in)\n", + "print(\"Returned class is: \" + class_dict[int(accel_out)])\n", + "\n", + "im = Image.open(mask_examples_dir + '/3.jpg')\n", + "im = resize(im)\n", + "accel_in = im.reshape(accel.ishape_normal)\n", + "im = Image.fromarray(im, 'RGB')\n", + "display(im)\n", + "accel_out = accel.execute(accel_in)\n", + "print(\"Returned class is: \" + class_dict[int(accel_out)])\n", + "\n", + "im = Image.open(mask_examples_dir + '/4.jpg')\n", + "im = resize(im)\n", + "accel_in = im.reshape(accel.ishape_normal)\n", + "im = Image.fromarray(im, 'RGB')\n", + "display(im)\n", + "accel_out = accel.execute(accel_in)\n", + "print(\"Returned class is: \" + class_dict[int(accel_out)])\n", + "\n", + "im = Image.open(mask_examples_dir + '/5.jpg')\n", + "im = resize(im)\n", + "accel_in = im.reshape(accel.ishape_normal)\n", + "im = Image.fromarray(im, 'RGB')\n", + "display(im)\n", + "accel_out = accel.execute(accel_in)\n", + "print(\"Returned class is: \" + class_dict[int(accel_out)])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Run Webcam" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "from IPython.display import clear_output\n", + "\n", + "def producer_live(cap):\n", + " # grab most recent frame in buffer\n", + " for i in range(4):\n", + " cap.grab()\n", + " \n", + " flag, frame = cap.read()\n", + "\n", + " if flag:\n", + " frame = webcam_rev(frame)\n", + " img = Image.fromarray(frame, 'RGB')\n", + " frame = frame.reshape(accel.ishape_normal)\n", + " return frame, img\n", + "\n", + " else:\n", + " print (\"frame is not ready\")\n", + " cv2.waitKey(1)\n", + " \n", + "def consumer_live(accel, frame):\n", + " class_out = accel.execute(frame)\n", + " print(\"Class name: {}\".format(class_dict[int(class_out)]))\n", + "\n", + "def webcam_rev(img):\n", + " img = np.array(img)\n", + " img_cropped = img[:, 20:140, :]\n", + " img_resized = cv2.resize(img_cropped,(72,72))\n", + " img_rev = cv2.cvtColor(img_resized, cv2.COLOR_BGR2RGB)\n", + " return img_rev" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cap = cv2.VideoCapture(0)\n", + "while not cap.isOpened():\n", + " cap = cv2.VideoCapture(0)\n", + " cv2.waitKey(1)\n", + " print (\"Wait for the device\")\n", + "\n", + "# set small capture resolution for faster processing\n", + "cap.set(cv2.CAP_PROP_FRAME_WIDTH, 160)\n", + "cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 120)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Classify Webcam Input\n", + "* Make sure you are in a well-lit environment\n", + "* Blue-colored masks are classified best (will be improved in next update)\n", + "* Position your face in the center of the frame, close to camera (see examples)\n", + "\n", + "This notebook is a basic proof-of-concept. Model was trained on simple blue-mask augmentation of Flickr-Faces-HQ (FFHQ). For better results, more mask-types can be supported (e.g. https://github.com/aqeelanwar/MaskTheFace)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Class name: Correctly Masked\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "clear_output()\n", + "frame, img = producer_live(cap)\n", + "consumer_live(accel, frame)\n", + "img" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Class name: Incorrectly Worn\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "clear_output()\n", + "frame, img = producer_live(cap)\n", + "consumer_live(accel, frame)\n", + "img" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Class name: No Mask\n" + ] + }, + { + "data": { + "image/png": "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Erwfc8qqZGYGQiBqo2RwTMyugKkaITgiMyPzZGCghlC07FqviQDMPBMjJLGzx9t3fuv125/7uMXgVLUfW3735Df+zsU7H9z4zL9yUc+mCsYR7PDg3/j5/+Qr/+Bv3n/nW4fVgfYl+PLkcy89970/cXeajQ5ghEJ27wNM90+a09e7k6+049cr3pwc55PX17x2FlgCj+kYicRQiqqamRKzJNVAQ8qTakBMpRSRYppFppIpepeswKUjCGygBo6cmgLRbmcjqkweQREohphHKMLv3blXB5g9eZUOD3ogy44pbb/5v/zBe9988cf+QplfCx4GgrsZPvWln31xLu994w9OT6frN59ZV8vvTFDt43KC00eWi23vfbd69H8dlNeqfJK5fu9hf/z63cVmEwoKx9J0m2FY1EEEiuzEYsOdjGOUBNQIEHLOKmKmpppSqgDdpBPpznsAR4xqKmpmhDv1w4qZZzBllRxCxVOOpYiVb751/2BTrj812l7cxj3RxoXTsH337V/7766+8PnmU/9qCfHRCs4E3niXnm4+3lX9sblHE0+Ip++abqb+/B4df+Pa9K253kW8WJucvv1o/c67cXM+UVAfZpar6ex4HJazToqI6u4DO0Zm74ppQRQk21liZqA7DRdLzv8fz6kM7g19L04AAAAASUVORK5CYII=\n", + "text/plain": [ + "" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "clear_output()\n", + "frame, img = producer_live(cap)\n", + "consumer_live(accel, frame)\n", + "img" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Release Webcam" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "cap.release()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} From ec2c14bab6f1db6bb8dc17b3c355054b20f0f477 Mon Sep 17 00:00:00 2001 From: Felix Jentzsch Date: Thu, 22 Jul 2021 21:24:48 +0200 Subject: [PATCH 03/49] Initial ZCU104 testing --- build/vgg10/README.md | 53 ++ build/vgg10/build.py | 209 +++++ build/vgg10/custom_steps.py | 61 ++ .../folding_config/ZCU104_folding_config.json | 136 +++ build/vgg10/models/download_vgg10.sh | 4 + finn_examples/models.py | 46 +- .../notebooks/3_radioml_with_cnns.ipynb | 819 ++++++++++++++++++ 7 files changed, 1318 insertions(+), 10 deletions(-) create mode 100755 build/vgg10/README.md create mode 100755 build/vgg10/build.py create mode 100755 build/vgg10/custom_steps.py create mode 100755 build/vgg10/folding_config/ZCU104_folding_config.json create mode 100755 build/vgg10/models/download_vgg10.sh create mode 100755 finn_examples/notebooks/3_radioml_with_cnns.ipynb diff --git a/build/vgg10/README.md b/build/vgg10/README.md new file mode 100755 index 0000000..38b69a2 --- /dev/null +++ b/build/vgg10/README.md @@ -0,0 +1,53 @@ +# MobileNet-v1 + +MobileNet-v1 was [introduced](https://arxiv.org/abs/1704.04861) by Google in 2017 as a lightweight +DNN targeting the ImageNet dataset. +It has a repeated structure of depthwise-separable (dws) convolution building blocks. +Each dws convolution consists +of a depthwise and a pointwise convolution each followed by a batchnorm and ReLU block. +MobileNet-v1 has 13 of these blocks. +Here, we use a reduced-precision implementation of MobileNet-v1 from [Brevitas](https://github.com/Xilinx/brevitas/tree/master/brevitas_examples/imagenet_classification), +where the weights and activations are quantized to 4-bit, except for the first +layer which uses 8-bit weights and inputs. +It requires about 2 MB of weight storage and 1.1 GMACs per inference, yielding +70.4\% top-1 accuracy on ImageNet. + +## Build bitfiles for MobileNet-v1 + +Due to the depthwise separable convolutions in MobileNet-v1, +we use a specialized build script that replaces a few of the standard steps +in FINN with custom ones. +**MobileNet-v1 is currently only supported on Alveo U250 and ZCU104.** +We also provide a folding configuration for the **ZCU102**, but there is no pre-built Pynq image available for this board. + +0. Ensure you have performed the *Setup* steps in the top-level README for setting up the FINN requirements and environment variables. + +1. Download the pretrained MobileNet-v1 ONNX model from the releases page, and extract +the zipfile under `mobilenet-v1/models`. You should have e.g. `mobilenetv1/models∕mobilenetv1-w4a4_pre_post_tidy.onnx` as a result. +You can use the provided `mobilenet-v1/models/download_mobilenet.sh` script for this. + +2. Launch the build as follows: +```SHELL +# update this according to where you cloned this repo: +FINN_EXAMPLES=/path/to/finn-examples +# cd into finn submodule +cd $FINN_EXAMPLES/build/finn +# launch the build on the mobilenet-v1 folder +./run-docker.sh build_custom /path/to/finn-examples/build/mobilenet-v1 +``` + +5. The generated outputs will be under `mobilenet-v1/output__`. You can find a description of the generated files [here](https://finn-dev.readthedocs.io/en/latest/command_line.html#simple-dataflow-build-mode). + +## Where did the ONNX model files come from? + +The 4-bit quantized MobileNet-v1 is part of the +[Brevitas examples](https://github.com/Xilinx/brevitas/tree/master/brevitas_examples/imagenet_classification). +Subsequently, the trained networks is [exported to ONNX](https://github.com/Xilinx/finn/blob/master/notebooks/basics/1_brevitas_network_import.ipynb). In addition, the particular version used here has two additions for pre- and postprocessing: + +* A divide-by-255 node is added at the input, and the input is marked as 8-bit (to directly accept 8-bit images as input) +* Normalization is added at the input with `mean = [0.485, 0.456, 0.406]` and `std = 0.226`. Note that the `std` is global and not per-channel to facilitate its removal via the [streamlining transform](https://arxiv.org/pdf/1709.04060). +* A top-K node with k=5 is added at the output (to return the top-5 class indices instead of logits) + +These modifications are done as part of the end2end MobileNet-v1 test in FINN. +You can [see more here](https://github.com/Xilinx/finn/blob/bf9a67eee6ff5a797ea3a0bd866706d7518c3c6f/tests/end2end/test_end2end_mobilenet_v1.py#L102) +for further reference. diff --git a/build/vgg10/build.py b/build/vgg10/build.py new file mode 100755 index 0000000..8c6aa3a --- /dev/null +++ b/build/vgg10/build.py @@ -0,0 +1,209 @@ +# Copyright (c) 2020, Xilinx +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of FINN nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +import finn.builder.build_dataflow as build +import finn.builder.build_dataflow_config as build_cfg +from finn.util.basic import alveo_default_platform +import os +import shutil + +# custom steps +from custom_steps import step_pre_streamline, step_convert_final_layers + +model_name = "18_VGG10_w4a4w2a2_v2_ready" +# model_name = "yolov4-tiny-2b3b-dw_final_cutoff" +# model_name = "ConvAsFC_test_in_2_512_32" #test model + +# which platforms to build the networks for +zynq_platforms = ["ZCU104"] +alveo_platforms = [] +platforms_to_build = zynq_platforms + alveo_platforms + + +# determine which shell flow to use for a given platform +def platform_to_shell(platform): + if platform in zynq_platforms: + return build_cfg.ShellFlowType.VIVADO_ZYNQ + elif platform in alveo_platforms: + return build_cfg.ShellFlowType.VITIS_ALVEO + else: + raise Exception("Unknown platform, can't determine ShellFlowType") + + +# select target clock frequency +def select_clk_period(platform): + return 5.0 + + +# select build steps (ZCU104/102 folding config is based on separate thresholding nodes) +# """ normal +def select_build_steps(platform): + return [ + "step_tidy_up", + step_pre_streamline, + "step_streamline", + "step_convert_to_hls", + step_convert_final_layers, + "step_create_dataflow_partition", + "step_target_fps_parallelization", + "step_apply_folding_config", + "step_generate_estimate_reports", + "step_hls_codegen", + "step_hls_ipgen", + "step_set_fifo_depths", + "step_create_stitched_ip", + "step_measure_rtlsim_performance", + "step_out_of_context_synthesis", + "step_synthesize_bitfile", + "step_make_pynq_driver", + "step_deployment_package", + ] + + +# """ +""" experimental fg mmv +def select_build_steps(platform): + return [ + "step_tidy_up", + step_pre_streamline, + "step_streamline", + "step_convert_to_hls", + step_convert_final_layers, + "step_create_dataflow_partition", + step_experimentalfg, + "step_target_fps_parallelization", + "step_apply_folding_config", + "step_generate_estimate_reports", + "step_hls_codegen", + "step_hls_ipgen", + #"step_set_fifo_depths", + "step_create_stitched_ip", + #"step_measure_rtlsim_performance", + "step_out_of_context_synthesis", + "step_synthesize_bitfile", + "step_make_pynq_driver", + "step_deployment_package", + ] +""" +""" experimental conv as fc (full unrolling) +def select_build_steps(platform): + return [ + #"step_tidy_up", + #step_pre_streamline, + #"step_streamline", + #"step_convert_to_hls", + #step_convert_final_layers, + step_experimentalconv, + "step_create_dataflow_partition", + "step_target_fps_parallelization", + "step_apply_folding_config", + "step_generate_estimate_reports", + "step_hls_codegen", + "step_hls_ipgen", + "step_set_fifo_depths", + "step_create_stitched_ip", + "step_measure_rtlsim_performance", + "step_out_of_context_synthesis", + "step_synthesize_bitfile", + "step_make_pynq_driver", + "step_deployment_package", + ] +""" +# create a release dir, used for finn-examples release packaging +os.makedirs("release", exist_ok=True) + + +for platform_name in platforms_to_build: + shell_flow_type = platform_to_shell(platform_name) + if shell_flow_type == build_cfg.ShellFlowType.VITIS_ALVEO: + vitis_platform = alveo_default_platform[platform_name] + # for Alveo, use the Vitis platform name as the release name + # e.g. xilinx_u250_xdma_201830_2 + release_platform_name = vitis_platform + else: + vitis_platform = None + # for Zynq, use the board name as the release name + # e.g. ZCU104 + release_platform_name = platform_name + platform_dir = "release/%s" % release_platform_name + os.makedirs(platform_dir, exist_ok=True) + + cfg = build_cfg.DataflowBuildConfig( + steps=select_build_steps(platform_name), + output_dir="output_%s_%s" % (model_name, release_platform_name), + synth_clk_period_ns=select_clk_period(platform_name), + board=platform_name, + shell_flow_type=shell_flow_type, + vitis_platform=vitis_platform, + folding_config_file="folding_config/%s_folding_config.json" % platform_name, + # target_fps=100000, + # mvau_wwidth_max = 36, + auto_fifo_depths=True, + standalone_thresholds=False, # needed (only) for experimental fg flow + # enable extra performance optimizations (physopt) + vitis_opt_strategy=build_cfg.VitisOptStrategyCfg.PERFORMANCE_BEST, + generate_outputs=[ + build_cfg.DataflowOutputType.ESTIMATE_REPORTS, + build_cfg.DataflowOutputType.STITCHED_IP, + # build_cfg.DataflowOutputType.OOC_SYNTH, + build_cfg.DataflowOutputType.RTLSIM_PERFORMANCE, + build_cfg.DataflowOutputType.BITFILE, + build_cfg.DataflowOutputType.DEPLOYMENT_PACKAGE, + build_cfg.DataflowOutputType.PYNQ_DRIVER, + ], + ) + model_file = "models/%s.onnx" % model_name + build.build_dataflow_cfg(model_file, cfg) + + # copy bitfiles and runtime weights into release dir if found + bitfile_gen_dir = cfg.output_dir + "/bitfile" + files_to_check_and_copy = [ + "finn-accel.bit", + "finn-accel.hwh", + "finn-accel.xclbin", + ] + for f in files_to_check_and_copy: + src_file = bitfile_gen_dir + "/" + f + dst_file = platform_dir + "/" + f.replace("finn-accel", model_name) + if os.path.isfile(src_file): + shutil.copy(src_file, dst_file) + + weight_gen_dir = cfg.output_dir + "/driver/runtime_weights" + weight_dst_dir = platform_dir + "/%s_runtime_weights" % model_name + if os.path.isdir(weight_gen_dir): + weight_files = os.listdir(weight_gen_dir) + if weight_files: + shutil.copytree(weight_gen_dir, weight_dst_dir) + + # create zipfile for all examples for this platform + shutil.make_archive( + "release/" + release_platform_name, + "zip", + root_dir="release", + base_dir=release_platform_name, + ) diff --git a/build/vgg10/custom_steps.py b/build/vgg10/custom_steps.py new file mode 100755 index 0000000..e5ca94d --- /dev/null +++ b/build/vgg10/custom_steps.py @@ -0,0 +1,61 @@ +# Copyright (c) 2020, Xilinx +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of FINN nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +from finn.core.modelwrapper import ModelWrapper +from finn.builder.build_dataflow_config import DataflowBuildConfig + +from finn.transformation.change_3d_tensors_to_4d import Change3DTo4DTensors +from finn.transformation.general import GiveUniqueNodeNames, GiveReadableTensorNames +import finn.transformation.fpgadataflow.convert_to_hls_layers as to_hls +import finn.transformation.streamline.absorb as absorb + +from finn.transformation.fpgadataflow.make_finegrained import MakeFinegrained + + +def step_pre_streamline(model: ModelWrapper, cfg: DataflowBuildConfig): + model = model.transform(Change3DTo4DTensors()) + model = model.transform(absorb.AbsorbScalarMulAddIntoTopK()) + return model + + +def step_convert_final_layers(model: ModelWrapper, cfg: DataflowBuildConfig): + model = model.transform(to_hls.InferChannelwiseLinearLayer()) + model = model.transform(to_hls.InferLabelSelectLayer()) + model = model.transform(GiveUniqueNodeNames()) + return model + + +def step_experimentalconv(model: ModelWrapper, cfg: DataflowBuildConfig): + model = model.transform(to_hls.InferExperimentalConvAsFC()) + return model + + +def step_experimentalfg(model: ModelWrapper, cfg: DataflowBuildConfig): + model = model.transform(MakeFinegrained()) + model = model.transform(GiveUniqueNodeNames()) + model = model.transform(GiveReadableTensorNames()) + return model diff --git a/build/vgg10/folding_config/ZCU104_folding_config.json b/build/vgg10/folding_config/ZCU104_folding_config.json new file mode 100755 index 0000000..77c8a1b --- /dev/null +++ b/build/vgg10/folding_config/ZCU104_folding_config.json @@ -0,0 +1,136 @@ +{ + "Defaults": {}, + "FMPadding_Batch_0": { + "SIMD": 1 + }, + "ConvolutionInputGenerator1D_0": { + "SIMD": 2, + "ram_style": "auto" + }, + "StreamingFCLayer_Batch_0": { + "PE": 16, + "SIMD": 6, + "ram_style": "auto", + "mem_mode": "const", + "runtime_writeable_weights": 0 + }, + "StreamingMaxPool_Batch_0": { + }, + "FMPadding_Batch_1": { + "SIMD": 16 + }, + "ConvolutionInputGenerator1D_1": { + "SIMD": 64, + "ram_style": "auto" + }, + "StreamingFCLayer_Batch_1": { + "PE": 32, + "SIMD": 64, + "ram_style": "auto", + "mem_mode": "const", + "runtime_writeable_weights": 0 + }, + "StreamingMaxPool_Batch_1": { + }, + "FMPadding_Batch_2": { + "SIMD": 8 + }, + "ConvolutionInputGenerator1D_2": { + "SIMD": 64, + "ram_style": "auto" + }, + "StreamingFCLayer_Batch_2": { + "PE": 16, + "SIMD": 64, + "ram_style": "auto", + "mem_mode": "const", + "runtime_writeable_weights": 0 + }, + "StreamingMaxPool_Batch_2": { + }, + "FMPadding_Batch_3": { + "SIMD": 4 + }, + "ConvolutionInputGenerator1D_3": { + "SIMD": 64, + "ram_style": "auto" + }, + "StreamingFCLayer_Batch_3": { + "PE": 8, + "SIMD": 64, + "ram_style": "auto", + "mem_mode": "const", + "runtime_writeable_weights": 0 + }, + "StreamingMaxPool_Batch_3": { + }, + "FMPadding_Batch_4": { + "SIMD": 2 + }, + "ConvolutionInputGenerator1D_4": { + "SIMD": 64, + "ram_style": "auto" + }, + "StreamingFCLayer_Batch_4": { + "PE": 4, + "SIMD": 64, + "ram_style": "auto", + "mem_mode": "const", + "runtime_writeable_weights": 0 + }, + "StreamingMaxPool_Batch_4": { + }, + "FMPadding_Batch_5": { + "SIMD": 1 + }, + "ConvolutionInputGenerator1D_5": { + "SIMD": 64, + "ram_style": "auto" + }, + "StreamingFCLayer_Batch_5": { + "PE": 2, + "SIMD": 64, + "ram_style": "auto", + "mem_mode": "const", + "runtime_writeable_weights": 0 + }, + "StreamingMaxPool_Batch_5": { + }, + "FMPadding_Batch_6": { + "SIMD": 1 + }, + "ConvolutionInputGenerator1D_6": { + "SIMD": 64, + "ram_style": "auto" + }, + "StreamingFCLayer_Batch_6": { + "PE": 1, + "SIMD": 64, + "ram_style": "auto", + "mem_mode": "const", + "runtime_writeable_weights": 0 + }, + "StreamingMaxPool_Batch_6": { + }, + "StreamingFCLayer_Batch_7": { + "PE": 1, + "SIMD": 16, + "ram_style": "auto", + "mem_mode": "const", + "runtime_writeable_weights": 0 + }, + "StreamingFCLayer_Batch_8": { + "PE": 1, + "SIMD": 4, + "ram_style": "auto", + "mem_mode": "const", + "runtime_writeable_weights": 0 + }, + "StreamingFCLayer_Batch_9": { + "PE": 1, + "SIMD": 1, + "ram_style": "auto", + "mem_mode": "const", + "runtime_writeable_weights": 0 + } +} diff --git a/build/vgg10/models/download_vgg10.sh b/build/vgg10/models/download_vgg10.sh new file mode 100755 index 0000000..fe54a6c --- /dev/null +++ b/build/vgg10/models/download_vgg10.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +wget https://github.com/Xilinx/finn-examples/releases/download/v0.0.1a/onnx-models-mobilenetv1.zip +unzip onnx-models-mobilenetv1.zip diff --git a/finn_examples/models.py b/finn_examples/models.py index 9dd69aa..0dc5fc9 100644 --- a/finn_examples/models.py +++ b/finn_examples/models.py @@ -71,18 +71,30 @@ # resnet50 uses a different io_shape_dict due to # external weights for last layer _imagenet_resnet50_top5inds_io_shape_dict = { - "idt" : DataType.UINT8, - "odt" : DataType.UINT16, - "ishape_normal" : (1, 224, 224, 3), - "oshape_normal" : (1, 5), - "ishape_folded" : (1, 224, 224, 3), - "oshape_folded" : (1, 5, 1), - "ishape_packed" : (1, 224, 224, 3), - "oshape_packed" : (1, 5, 2), - "input_dma_name" : 'idma1', - "number_of_external_weights": 1 + "idt": DataType.UINT8, + "odt": DataType.UINT16, + "ishape_normal": (1, 224, 224, 3), + "oshape_normal": (1, 5), + "ishape_folded": (1, 224, 224, 3), + "oshape_folded": (1, 5, 1), + "ishape_packed": (1, 224, 224, 3), + "oshape_packed": (1, 5, 2), + "input_dma_name": "idma1", + "number_of_external_weights": 1, } +_radioml_io_shape_dict = { + "idt": DataType.INT8, + "odt": DataType.UINT8, + "ishape_normal": (1, 1024, 1, 2), + "oshape_normal": (1, 1), + "ishape_folded": (1, 1024, 1, 2, 1), + "oshape_folded": (1, 1, 1), + "ishape_packed": (1, 1024, 1, 2, 1), + "oshape_packed": (1, 1, 1), + "input_dma_name": "idma0", + "number_of_external_weights": 0, +} # from https://github.com/Xilinx/PYNQ-HelloWorld/blob/master/setup.py # get current platform: either edge or pcie @@ -222,6 +234,7 @@ def mobilenetv1_w4a4_imagenet(target_platform=None): fclk_mhz=fclk_mhz, ) + def resnet50_w1a2_imagenet(target_platform=None): target_platform = resolve_target_platform(target_platform) driver_mode = get_driver_mode() @@ -235,3 +248,16 @@ def resnet50_w1a2_imagenet(target_platform=None): runtime_weight_dir=runtime_weight_dir, ) + +def vgg10_w2a2_radioml(target_platform=None): + target_platform = resolve_target_platform(target_platform) + driver_mode = get_driver_mode() + model_name = "vgg10-w2a2" + filename = find_bitfile(model_name, target_platform) + fclk_mhz = 185.0 + return FINNExampleOverlay( + filename, + driver_mode, + _radioml_io_shape_dict, + fclk_mhz=fclk_mhz, + ) diff --git a/finn_examples/notebooks/3_radioml_with_cnns.ipynb b/finn_examples/notebooks/3_radioml_with_cnns.ipynb new file mode 100755 index 0000000..c65c086 --- /dev/null +++ b/finn_examples/notebooks/3_radioml_with_cnns.ipynb @@ -0,0 +1,819 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Initialize the accelerator" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: pip in /usr/local/lib/python3.6/dist-packages (21.1.1)\n", + "Collecting pip\n", + " Downloading pip-21.1.2-py3-none-any.whl (1.5 MB)\n", + "\u001b[K |████████████████████████████████| 1.5 MB 2.1 MB/s eta 0:00:01 |██████████████▋ | 706 kB 2.1 MB/s eta 0:00:01\n", + "\u001b[?25hRequirement already satisfied: setuptools in /usr/local/lib/python3.6/dist-packages (56.2.0)\n", + "Collecting setuptools\n", + " Downloading setuptools-57.0.0-py3-none-any.whl (821 kB)\n", + "\u001b[K |████████████████████████████████| 821 kB 6.9 MB/s eta 0:00:01\n", + "\u001b[?25hRequirement already satisfied: wheel in /usr/local/lib/python3.6/dist-packages (0.36.2)\n", + "Installing collected packages: setuptools, pip\n", + " Attempting uninstall: setuptools\n", + " Found existing installation: setuptools 56.2.0\n", + " Uninstalling setuptools-56.2.0:\n", + " Successfully uninstalled setuptools-56.2.0\n", + " Attempting uninstall: pip\n", + " Found existing installation: pip 21.1.1\n", + " Uninstalling pip-21.1.1:\n", + " Successfully uninstalled pip-21.1.1\n", + "Successfully installed pip-21.1.2 setuptools-57.0.0\n", + "\u001b[33mWARNING: Running pip as root will break packages and permissions. You should install packages reliably by using venv: https://pip.pypa.io/warnings/venv\u001b[0m\n", + "Requirement already satisfied: versioned-hdf5 in /usr/local/lib/python3.6/dist-packages (1.2)\n", + "Requirement already satisfied: h5py<3 in /usr/local/lib/python3.6/dist-packages (from versioned-hdf5) (2.10.0)\n", + "Requirement already satisfied: numpy in /usr/local/lib/python3.6/dist-packages (from versioned-hdf5) (1.16.0)\n", + "Requirement already satisfied: ndindex>=1.3 in /usr/local/lib/python3.6/dist-packages (from versioned-hdf5) (1.4)\n", + "Requirement already satisfied: six in /usr/lib/python3/dist-packages (from h5py<3->versioned-hdf5) (1.11.0)\n", + "Requirement already satisfied: sympy in /usr/lib/python3/dist-packages (from ndindex>=1.3->versioned-hdf5) (1.1.1)\n", + "\u001b[33mWARNING: Running pip as root will break packages and permissions. You should install packages reliably by using venv: https://pip.pypa.io/warnings/venv\u001b[0m\n", + "Requirement already satisfied: h5py in /usr/local/lib/python3.6/dist-packages (2.10.0)\n", + "Requirement already satisfied: six in /usr/lib/python3/dist-packages (from h5py) (1.11.0)\n", + "Requirement already satisfied: numpy>=1.7 in /usr/local/lib/python3.6/dist-packages (from h5py) (1.16.0)\n", + "\u001b[33mWARNING: Running pip as root will break packages and permissions. You should install packages reliably by using venv: https://pip.pypa.io/warnings/venv\u001b[0m\n" + ] + } + ], + "source": [ + "# apt-get install libhdf5-dev\n", + "#! pip install --upgrade pip setuptools wheel\n", + "! pip install versioned-hdf5\n", + "#! pip install h5py" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "application/javascript": [ + "\n", + "try {\n", + "require(['notebook/js/codecell'], function(codecell) {\n", + " codecell.CodeCell.options_default.highlight_modes[\n", + " 'magic_text/x-csrc'] = {'reg':[/^%%microblaze/]};\n", + " Jupyter.notebook.events.one('kernel_ready.Kernel', function(){\n", + " Jupyter.notebook.get_cells().map(function(cell){\n", + " if (cell.cell_type == 'code'){ cell.auto_highlight(); } }) ;\n", + " });\n", + "});\n", + "} catch (e) {};\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/javascript": [ + "\n", + "try {\n", + "require(['notebook/js/codecell'], function(codecell) {\n", + " codecell.CodeCell.options_default.highlight_modes[\n", + " 'magic_text/x-csrc'] = {'reg':[/^%%pybind11/]};\n", + " Jupyter.notebook.events.one('kernel_ready.Kernel', function(){\n", + " Jupyter.notebook.get_cells().map(function(cell){\n", + " if (cell.cell_type == 'code'){ cell.auto_highlight(); } }) ;\n", + " });\n", + "});\n", + "} catch (e) {};\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import os\n", + "import sys\n", + "module_path = os.path.abspath(os.path.join('/home/xilinx/radioml_deploy'))\n", + "if module_path not in sys.path:\n", + " sys.path.append(module_path)\n", + " \n", + "from driver.driver_base import FINNExampleOverlay\n", + "from finn.core.datatype import DataType" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "# taken from generated driver.py:\n", + "io_shape_dict = {\n", + " # FINN DataType for input and output tensors\n", + " \"idt\" : DataType.INT8,\n", + " \"odt\" : DataType.UINT8,\n", + " # shapes for input and output tensors (NHWC layout)\n", + " \"ishape_normal\" : (1, 128, 1, 16),\n", + " \"oshape_normal\" : (1, 1),\n", + " # folded / packed shapes below depend on idt/odt and input/output\n", + " # PE/SIMD parallelization settings -- these are calculated by the\n", + " # FINN compiler.\n", + " \"ishape_folded\" : (1, 128, 1, 4, 4),\n", + " \"oshape_folded\" : (1, 1, 1),\n", + " \"ishape_packed\" : (1, 128, 1, 4, 4),\n", + " \"oshape_packed\" : (1, 1, 1),\n", + " \"input_dma_name\" : 'idma0',\n", + " \"number_of_external_weights\": 0\n", + "}\n", + "\n", + "accel = FINNExampleOverlay(\n", + " bitfile_name = \"/home/xilinx/radioml_deploy/bitfile/finn-accel.bit\", platform = \"zynq-iodma\",\n", + " io_shape_dict = io_shape_dict, batch_size = 1, fclk_mhz = 187.0)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Expected input shape and datatype: (1, 128, 1, 16) DataType.INT8\n", + "Expected output shape and datatype: (1, 1) DataType.UINT8\n" + ] + } + ], + "source": [ + "print(\"Expected input shape and datatype: %s %s\" % (str(accel.ishape_normal), str(accel.idt)))\n", + "print(\"Expected output shape and datatype: %s %s\" % (str(accel.oshape_normal), str(accel.odt)))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Load RadioML 2018 dataset" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "/home/xilinx/dataset/RadioML\n" + ] + } + ], + "source": [ + "import numpy as np\n", + "import pickle\n", + "import os\n", + "import h5py\n", + "\n", + "val_dir = \"/home/xilinx/dataset/RadioML\"\n", + "print(val_dir)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "h5_file = h5py.File(val_dir + \"/2018/GOLD_XYZ_OSC.0001_1024.hdf5\",'r')\n", + "X = h5_file['X']\n", + "Y = np.argmax(h5_file['Y'], axis=1) # comes in one-hot encoding\n", + "Z = h5_file['Z'][:,0]\n", + "\n", + "np.random.seed(2018)\n", + "test_indices = []\n", + "for mod in range(0, 24): #all modulations (0 to 23)\n", + " for snr_idx in range(0, 26): #all SNRs (0 to 25 = -20dB to +30dB)\n", + " start_idx = 26*4096*mod + 4096*snr_idx\n", + " indices_subclass = list(range(start_idx, start_idx+4096))\n", + "\n", + " split = int(np.ceil(0.1 * 4096)) #90%/10% split\n", + " np.random.shuffle(indices_subclass)\n", + " train_indices_subclass, val_indices_subclass = indices_subclass[split:], indices_subclass[:split]\n", + "\n", + " if snr_idx >= 25: #only SNR >= +30dB\n", + " test_indices.extend(val_indices_subclass)\n", + "\n", + "test_indices = np.sort(test_indices)\n", + "\n", + "X_test = X[test_indices]\n", + "Y_test = Y[test_indices]\n", + "Z_test = Z[test_indices]\n", + "\n", + "# bring into 4D NHWC format\n", + "#X_test = np.expand_dims(X_test, 2)\n", + "\n", + "# note: labels given in the \"classes.txt\" file are not in the correct order (https://github.com/radioML/dataset/issues/25)\n", + "self.mod_classes = ['OOK','4ASK','8ASK','BPSK','QPSK','8PSK','16PSK','32PSK',\n", + "'16APSK','32APSK','64APSK','128APSK','16QAM','32QAM','64QAM','128QAM','256QAM',\n", + "'AM-SSB-WC','AM-SSB-SC','AM-DSB-WC','AM-DSB-SC','FM','GMSK','OQPSK']\n", + "snr_classes = np.arange(-20., 32., 2) # -20dB to 30dB" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(9840, 1024, 2)\n", + "(9840,)\n", + "(9840,)\n", + "[ 102401 102404 102414 ... 2555870 2555878 2555889]\n" + ] + } + ], + "source": [ + "print(X_test.shape)\n", + "print(Y_test.shape)\n", + "print(Z_test.shape)\n", + "print(test_indices)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Inspect a single sample" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Modulation: 32QAM, SNR: 30.0 dB\n" + ] + } + ], + "source": [ + "from matplotlib import pyplot as plt\n", + "\n", + "idx = 1086\n", + "data, mod, snr = X_test[idx], Y_test[idx], Z_test[idx]\n", + "plt.figure()\n", + "plt.plot(data)\n", + "print(\"Modulation: %s, SNR: %.1f dB\" % (mod_classes[mod], snr))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Quantize dataset" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Modulation: 32QAM, SNR: 30.0 dB\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "def quantize(data, quant_min, quant_max):\n", + " quant_range = quant_max - quant_min\n", + " data_quant = (data - quant_min) / quant_range\n", + " data_quant = np.round(data_quant * 256) - 128\n", + " data_quant = np.clip(data_quant, -128, 127)\n", + " data_quant = data_quant.astype(np.int8)\n", + " return data_quant\n", + "\n", + "#whole validation set:\n", + "quant_min = -2.0\n", + "quant_max = 2.0\n", + "X_test = quantize(X_test, quant_min, quant_max)\n", + "\n", + "idx = 1086\n", + "data, mod, snr = X_test[idx], Y_test[idx], Z_test[idx]\n", + "plt.figure()\n", + "plt.plot(data)\n", + "print(\"Modulation: %s, SNR: %.1f dB\" % (mod_classes[mod], snr))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Classify a single sample" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Input buffer shape is (1, 128, 1, 16) and datatype is int8\n" + ] + } + ], + "source": [ + "accel_in = data.reshape(accel.ishape_normal)\n", + "print(\"Input buffer shape is %s and datatype is %s\" % (str(accel_in.shape), str(accel_in.dtype)))" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "accel_out = accel.execute(accel_in)\n", + "#accel_out = post_process(accel_out)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Result: [[18.]]\n", + "Top-1 class predicted by the accelerator: 64QAM\n" + ] + } + ], + "source": [ + "print(\"Result: \" + str(accel_out))\n", + "print(\"Top-1 class predicted by the accelerator: \" + mod_classes[int(accel_out)])" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1000 loops, best of 3: 843 µs per loop\n" + ] + } + ], + "source": [ + "%%timeit\n", + "accel_out = accel.execute(accel_in)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Validate accuracy on entire validation set" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Accelerator buffer shapes are (120, 128, 1, 4, 4) for input, (120, 1, 1) for output\n", + "Accelerator buffer shapes are (120, 128, 1, 4, 4) for input, (120, 1, 1) for output\n", + "Accelerator buffer shapes are (120, 128, 1, 16) for input, (120, 1) for output\n" + ] + } + ], + "source": [ + "batch_size = 120\n", + "accel.batch_size = batch_size\n", + "print(\"Accelerator buffer shapes are %s for input, %s for output\" % (str(accel.ishape_packed), str(accel.oshape_packed)) )\n", + "print(\"Accelerator buffer shapes are %s for input, %s for output\" % (str(accel.ishape_folded), str(accel.oshape_folded)) )\n", + "print(\"Accelerator buffer shapes are %s for input, %s for output\" % (str(accel.ishape_normal), str(accel.oshape_normal)) )" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 0 : total OK 119 NOK 1\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 1 : total OK 239 NOK 1\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 2 : total OK 359 NOK 1\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 3 : total OK 471 NOK 9\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 4 : total OK 585 NOK 15\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 5 : total OK 691 NOK 29\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 6 : total OK 792 NOK 48\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 7 : total OK 894 NOK 66\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 8 : total OK 998 NOK 82\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 9 : total OK 1105 NOK 95\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 10 : total OK 1219 NOK 101\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 11 : total OK 1339 NOK 101\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 12 : total OK 1459 NOK 101\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 13 : total OK 1579 NOK 101\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 14 : total OK 1698 NOK 102\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 15 : total OK 1818 NOK 102\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 16 : total OK 1938 NOK 102\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 17 : total OK 2048 NOK 112\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 18 : total OK 2160 NOK 120\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 19 : total OK 2262 NOK 138\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 20 : total OK 2348 NOK 172\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 21 : total OK 2395 NOK 245\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 22 : total OK 2441 NOK 319\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 23 : total OK 2501 NOK 379\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 24 : total OK 2571 NOK 429\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 25 : total OK 2650 NOK 470\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 26 : total OK 2725 NOK 515\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 27 : total OK 2832 NOK 528\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 28 : total OK 2947 NOK 533\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 29 : total OK 3064 NOK 536\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 30 : total OK 3181 NOK 539\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 31 : total OK 3298 NOK 542\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 32 : total OK 3415 NOK 545\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 33 : total OK 3531 NOK 549\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 34 : total OK 3611 NOK 589\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 35 : total OK 3672 NOK 648\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 36 : total OK 3727 NOK 713\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 37 : total OK 3783 NOK 777\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 38 : total OK 3846 NOK 834\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 39 : total OK 3903 NOK 897\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 40 : total OK 3970 NOK 950\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 41 : total OK 4063 NOK 977\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 42 : total OK 4146 NOK 1014\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 43 : total OK 4239 NOK 1041\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 44 : total OK 4315 NOK 1085\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 45 : total OK 4381 NOK 1139\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 46 : total OK 4452 NOK 1188\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 47 : total OK 4513 NOK 1247\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 48 : total OK 4553 NOK 1327\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 49 : total OK 4600 NOK 1400\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 50 : total OK 4644 NOK 1476\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 51 : total OK 4665 NOK 1575\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 52 : total OK 4672 NOK 1688\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 53 : total OK 4685 NOK 1795\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 54 : total OK 4700 NOK 1900\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 55 : total OK 4719 NOK 2001\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 56 : total OK 4736 NOK 2104\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 57 : total OK 4754 NOK 2206\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 58 : total OK 4841 NOK 2239\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 59 : total OK 4930 NOK 2270\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 60 : total OK 5013 NOK 2307\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 61 : total OK 5084 NOK 2356\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 62 : total OK 5116 NOK 2444\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 63 : total OK 5152 NOK 2528\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 64 : total OK 5187 NOK 2613\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 65 : total OK 5302 NOK 2618\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 66 : total OK 5417 NOK 2623\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 67 : total OK 5536 NOK 2624\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 68 : total OK 5636 NOK 2644\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 69 : total OK 5731 NOK 2669\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 70 : total OK 5823 NOK 2697\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 71 : total OK 5925 NOK 2715\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 72 : total OK 6045 NOK 2715\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 73 : total OK 6165 NOK 2715\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 74 : total OK 6285 NOK 2715\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 75 : total OK 6405 NOK 2715\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 76 : total OK 6525 NOK 2715\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 77 : total OK 6645 NOK 2715\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 78 : total OK 6765 NOK 2715\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 79 : total OK 6885 NOK 2715\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 80 : total OK 7004 NOK 2716\n", + "(120, 128, 16)\n", + "(120, 128, 1, 16)\n", + "batch 81 : total OK 7124 NOK 2716\n" + ] + } + ], + "source": [ + "ok = 0\n", + "nok = 0\n", + "for i in range(int(X_test.shape[0]/batch_size)):\n", + " batch_idx = i*batch_size\n", + " data, mod, snr = X_test[batch_idx:batch_idx+batch_size], Y_test[batch_idx:batch_idx+batch_size], Z_test[batch_idx:batch_idx+batch_size]\n", + "\n", + " data = data.transpose(0,2,1)\n", + " data = data.reshape(-1, 16, 128)\n", + " data = data.transpose(0,2,1)\n", + " #x = x.reshape(-1,2,int(1024/interleave),int(interleave))\n", + " #x = x.permute(0,1,3,2).contiguous()\n", + " ibuf_normal = data.reshape(accel.ishape_normal)\n", + " obuf_normal = accel.execute(ibuf_normal)\n", + " obuf_normal = obuf_normal.reshape(batch_size)\n", + " #obuf_normal = post_process(obuf_normal)\n", + " \n", + " pred = obuf_normal.astype(int)\n", + " \n", + " print(data.shape)\n", + " print(ibuf_normal.shape)\n", + " #print(obuf_normal.shape) \n", + " #print(mod.shape)\n", + " #print(pred.shape)\n", + " \n", + " ok += np.equal(pred, mod).sum().item()\n", + " nok += np.not_equal(pred, mod).sum().item()\n", + " \n", + " print(\"batch %d : total OK %d NOK %d\" % (i, ok, nok))" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "30dB top-1 accuracy: 72.39837398373983%\n" + ] + } + ], + "source": [ + "total = X_test.shape[0]\n", + "acc = 100.0 * ok / (total)\n", + "print(\"30dB top-1 accuracy: {}%\".format(acc))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## More benchmarking" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'DRAM_in_bandwidth[Mb/s]': 435.46256676467607,\n", + " 'DRAM_out_bandwidth[Mb/s]': 0.2126282064280645,\n", + " 'batch_size': 1000,\n", + " 'copy_input_data_to_device[ms]': 1.878499984741211,\n", + " 'copy_output_data_from_device[ms]': 0.08535385131835938,\n", + " 'fclk[mhz]': 187.498125,\n", + " 'fold_input[ms]': 0.09822845458984375,\n", + " 'pack_input[ms]': 0.11038780212402344,\n", + " 'runtime[ms]': 4.703044891357422,\n", + " 'throughput[images/s]': 212628.20642806447,\n", + " 'unfold_output[ms]': 0.08726119995117188,\n", + " 'unpack_output[ms]': 0.6067752838134766}" + ] + }, + "execution_count": 50, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "accel.batch_size = 1000\n", + "accel.throughput_test()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.5" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From f87587d27c8428eff6cd0ac6bb257cfc1eca8005 Mon Sep 17 00:00:00 2001 From: Felix Jentzsch Date: Fri, 30 Jul 2021 15:36:14 +0200 Subject: [PATCH 04/49] Clean up build scripts, notebook --- build/vgg10/build.py | 63 +- build/vgg10/custom_steps.py | 17 +- finn_examples/models.py | 4 +- .../notebooks/3_radioml_with_cnns.ipynb | 802 ++++++++---------- 4 files changed, 372 insertions(+), 514 deletions(-) diff --git a/build/vgg10/build.py b/build/vgg10/build.py index 8c6aa3a..01dbd41 100755 --- a/build/vgg10/build.py +++ b/build/vgg10/build.py @@ -35,9 +35,7 @@ # custom steps from custom_steps import step_pre_streamline, step_convert_final_layers -model_name = "18_VGG10_w4a4w2a2_v2_ready" -# model_name = "yolov4-tiny-2b3b-dw_final_cutoff" -# model_name = "ConvAsFC_test_in_2_512_32" #test model +model_name = "radioml_w4a3_tidy" # which platforms to build the networks for zynq_platforms = ["ZCU104"] @@ -60,8 +58,7 @@ def select_clk_period(platform): return 5.0 -# select build steps (ZCU104/102 folding config is based on separate thresholding nodes) -# """ normal +# assemble build flow from custom and pre-existing steps def select_build_steps(platform): return [ "step_tidy_up", @@ -85,59 +82,9 @@ def select_build_steps(platform): ] -# """ -""" experimental fg mmv -def select_build_steps(platform): - return [ - "step_tidy_up", - step_pre_streamline, - "step_streamline", - "step_convert_to_hls", - step_convert_final_layers, - "step_create_dataflow_partition", - step_experimentalfg, - "step_target_fps_parallelization", - "step_apply_folding_config", - "step_generate_estimate_reports", - "step_hls_codegen", - "step_hls_ipgen", - #"step_set_fifo_depths", - "step_create_stitched_ip", - #"step_measure_rtlsim_performance", - "step_out_of_context_synthesis", - "step_synthesize_bitfile", - "step_make_pynq_driver", - "step_deployment_package", - ] -""" -""" experimental conv as fc (full unrolling) -def select_build_steps(platform): - return [ - #"step_tidy_up", - #step_pre_streamline, - #"step_streamline", - #"step_convert_to_hls", - #step_convert_final_layers, - step_experimentalconv, - "step_create_dataflow_partition", - "step_target_fps_parallelization", - "step_apply_folding_config", - "step_generate_estimate_reports", - "step_hls_codegen", - "step_hls_ipgen", - "step_set_fifo_depths", - "step_create_stitched_ip", - "step_measure_rtlsim_performance", - "step_out_of_context_synthesis", - "step_synthesize_bitfile", - "step_make_pynq_driver", - "step_deployment_package", - ] -""" # create a release dir, used for finn-examples release packaging os.makedirs("release", exist_ok=True) - for platform_name in platforms_to_build: shell_flow_type = platform_to_shell(platform_name) if shell_flow_type == build_cfg.ShellFlowType.VITIS_ALVEO: @@ -161,17 +108,15 @@ def select_build_steps(platform): shell_flow_type=shell_flow_type, vitis_platform=vitis_platform, folding_config_file="folding_config/%s_folding_config.json" % platform_name, - # target_fps=100000, - # mvau_wwidth_max = 36, auto_fifo_depths=True, - standalone_thresholds=False, # needed (only) for experimental fg flow + standalone_thresholds=False, # enable extra performance optimizations (physopt) vitis_opt_strategy=build_cfg.VitisOptStrategyCfg.PERFORMANCE_BEST, generate_outputs=[ build_cfg.DataflowOutputType.ESTIMATE_REPORTS, build_cfg.DataflowOutputType.STITCHED_IP, # build_cfg.DataflowOutputType.OOC_SYNTH, - build_cfg.DataflowOutputType.RTLSIM_PERFORMANCE, + # build_cfg.DataflowOutputType.RTLSIM_PERFORMANCE, build_cfg.DataflowOutputType.BITFILE, build_cfg.DataflowOutputType.DEPLOYMENT_PACKAGE, build_cfg.DataflowOutputType.PYNQ_DRIVER, diff --git a/build/vgg10/custom_steps.py b/build/vgg10/custom_steps.py index e5ca94d..2953fb7 100755 --- a/build/vgg10/custom_steps.py +++ b/build/vgg10/custom_steps.py @@ -27,14 +27,11 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. from finn.core.modelwrapper import ModelWrapper from finn.builder.build_dataflow_config import DataflowBuildConfig - from finn.transformation.change_3d_tensors_to_4d import Change3DTo4DTensors -from finn.transformation.general import GiveUniqueNodeNames, GiveReadableTensorNames +from finn.transformation.general import GiveUniqueNodeNames import finn.transformation.fpgadataflow.convert_to_hls_layers as to_hls import finn.transformation.streamline.absorb as absorb -from finn.transformation.fpgadataflow.make_finegrained import MakeFinegrained - def step_pre_streamline(model: ModelWrapper, cfg: DataflowBuildConfig): model = model.transform(Change3DTo4DTensors()) @@ -47,15 +44,3 @@ def step_convert_final_layers(model: ModelWrapper, cfg: DataflowBuildConfig): model = model.transform(to_hls.InferLabelSelectLayer()) model = model.transform(GiveUniqueNodeNames()) return model - - -def step_experimentalconv(model: ModelWrapper, cfg: DataflowBuildConfig): - model = model.transform(to_hls.InferExperimentalConvAsFC()) - return model - - -def step_experimentalfg(model: ModelWrapper, cfg: DataflowBuildConfig): - model = model.transform(MakeFinegrained()) - model = model.transform(GiveUniqueNodeNames()) - model = model.transform(GiveReadableTensorNames()) - return model diff --git a/finn_examples/models.py b/finn_examples/models.py index 0dc5fc9..9bc799e 100644 --- a/finn_examples/models.py +++ b/finn_examples/models.py @@ -249,10 +249,10 @@ def resnet50_w1a2_imagenet(target_platform=None): ) -def vgg10_w2a2_radioml(target_platform=None): +def vgg10_w4a3_radioml(target_platform=None): target_platform = resolve_target_platform(target_platform) driver_mode = get_driver_mode() - model_name = "vgg10-w2a2" + model_name = "vgg10-w4a3" filename = find_bitfile(model_name, target_platform) fclk_mhz = 185.0 return FINNExampleOverlay( diff --git a/finn_examples/notebooks/3_radioml_with_cnns.ipynb b/finn_examples/notebooks/3_radioml_with_cnns.ipynb index c65c086..71d143e 100755 --- a/finn_examples/notebooks/3_radioml_with_cnns.ipynb +++ b/finn_examples/notebooks/3_radioml_with_cnns.ipynb @@ -11,50 +11,11 @@ "cell_type": "code", "execution_count": 1, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Requirement already satisfied: pip in /usr/local/lib/python3.6/dist-packages (21.1.1)\n", - "Collecting pip\n", - " Downloading pip-21.1.2-py3-none-any.whl (1.5 MB)\n", - "\u001b[K |████████████████████████████████| 1.5 MB 2.1 MB/s eta 0:00:01 |██████████████▋ | 706 kB 2.1 MB/s eta 0:00:01\n", - "\u001b[?25hRequirement already satisfied: setuptools in /usr/local/lib/python3.6/dist-packages (56.2.0)\n", - "Collecting setuptools\n", - " Downloading setuptools-57.0.0-py3-none-any.whl (821 kB)\n", - "\u001b[K |████████████████████████████████| 821 kB 6.9 MB/s eta 0:00:01\n", - "\u001b[?25hRequirement already satisfied: wheel in /usr/local/lib/python3.6/dist-packages (0.36.2)\n", - "Installing collected packages: setuptools, pip\n", - " Attempting uninstall: setuptools\n", - " Found existing installation: setuptools 56.2.0\n", - " Uninstalling setuptools-56.2.0:\n", - " Successfully uninstalled setuptools-56.2.0\n", - " Attempting uninstall: pip\n", - " Found existing installation: pip 21.1.1\n", - " Uninstalling pip-21.1.1:\n", - " Successfully uninstalled pip-21.1.1\n", - "Successfully installed pip-21.1.2 setuptools-57.0.0\n", - "\u001b[33mWARNING: Running pip as root will break packages and permissions. You should install packages reliably by using venv: https://pip.pypa.io/warnings/venv\u001b[0m\n", - "Requirement already satisfied: versioned-hdf5 in /usr/local/lib/python3.6/dist-packages (1.2)\n", - "Requirement already satisfied: h5py<3 in /usr/local/lib/python3.6/dist-packages (from versioned-hdf5) (2.10.0)\n", - "Requirement already satisfied: numpy in /usr/local/lib/python3.6/dist-packages (from versioned-hdf5) (1.16.0)\n", - "Requirement already satisfied: ndindex>=1.3 in /usr/local/lib/python3.6/dist-packages (from versioned-hdf5) (1.4)\n", - "Requirement already satisfied: six in /usr/lib/python3/dist-packages (from h5py<3->versioned-hdf5) (1.11.0)\n", - "Requirement already satisfied: sympy in /usr/lib/python3/dist-packages (from ndindex>=1.3->versioned-hdf5) (1.1.1)\n", - "\u001b[33mWARNING: Running pip as root will break packages and permissions. You should install packages reliably by using venv: https://pip.pypa.io/warnings/venv\u001b[0m\n", - "Requirement already satisfied: h5py in /usr/local/lib/python3.6/dist-packages (2.10.0)\n", - "Requirement already satisfied: six in /usr/lib/python3/dist-packages (from h5py) (1.11.0)\n", - "Requirement already satisfied: numpy>=1.7 in /usr/local/lib/python3.6/dist-packages (from h5py) (1.16.0)\n", - "\u001b[33mWARNING: Running pip as root will break packages and permissions. You should install packages reliably by using venv: https://pip.pypa.io/warnings/venv\u001b[0m\n" - ] - } - ], + "outputs": [], "source": [ - "# apt-get install libhdf5-dev\n", - "#! pip install --upgrade pip setuptools wheel\n", - "! pip install versioned-hdf5\n", - "#! pip install h5py" + "# remember to install the following dependencies\n", + "#! apt-get install libhdf5-dev -y\n", + "#! pip install versioned-hdf5" ] }, { @@ -99,47 +60,38 @@ }, "metadata": {}, "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['_radioml_io_shape_dict', 'vgg10_w2a2_radioml']\n" + ] } ], "source": [ - "import os\n", - "import sys\n", - "module_path = os.path.abspath(os.path.join('/home/xilinx/radioml_deploy'))\n", - "if module_path not in sys.path:\n", - " sys.path.append(module_path)\n", - " \n", - "from driver.driver_base import FINNExampleOverlay\n", - "from finn.core.datatype import DataType" + "from finn_examples import models\n", + "print(list(filter(lambda x: \"radioml\" in x, dir(models))))" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/usr/local/lib/python3.6/dist-packages/pynq/ps.py:464: UserWarning: Setting frequency to the closest possible value 187.49812MHz.\n", + " round(freq_high / q0, 5)))\n" + ] + } + ], "source": [ - "# taken from generated driver.py:\n", - "io_shape_dict = {\n", - " # FINN DataType for input and output tensors\n", - " \"idt\" : DataType.INT8,\n", - " \"odt\" : DataType.UINT8,\n", - " # shapes for input and output tensors (NHWC layout)\n", - " \"ishape_normal\" : (1, 128, 1, 16),\n", - " \"oshape_normal\" : (1, 1),\n", - " # folded / packed shapes below depend on idt/odt and input/output\n", - " # PE/SIMD parallelization settings -- these are calculated by the\n", - " # FINN compiler.\n", - " \"ishape_folded\" : (1, 128, 1, 4, 4),\n", - " \"oshape_folded\" : (1, 1, 1),\n", - " \"ishape_packed\" : (1, 128, 1, 4, 4),\n", - " \"oshape_packed\" : (1, 1, 1),\n", - " \"input_dma_name\" : 'idma0',\n", - " \"number_of_external_weights\": 0\n", - "}\n", - "\n", - "accel = FINNExampleOverlay(\n", - " bitfile_name = \"/home/xilinx/radioml_deploy/bitfile/finn-accel.bit\", platform = \"zynq-iodma\",\n", - " io_shape_dict = io_shape_dict, batch_size = 1, fclk_mhz = 187.0)" + "accel = models.vgg10_w4a3_radioml()\n", + "#some systems might require a manual platform setting:\n", + "#accel = models.vgg10_w4a3_radioml(\"ZCU102\")" ] }, { @@ -151,7 +103,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Expected input shape and datatype: (1, 128, 1, 16) DataType.INT8\n", + "Expected input shape and datatype: (1, 1024, 1, 2) DataType.INT8\n", "Expected output shape and datatype: (1, 1) DataType.UINT8\n" ] } @@ -177,18 +129,19 @@ "name": "stdout", "output_type": "stream", "text": [ - "/home/xilinx/dataset/RadioML\n" + "/mnt/radioml_2018\n" ] } ], "source": [ "import numpy as np\n", + "import math\n", "import pickle\n", "import os\n", "import h5py\n", "\n", - "val_dir = \"/home/xilinx/dataset/RadioML\"\n", - "print(val_dir)" + "dataset_dir = \"/mnt/radioml_2018\"\n", + "print(dataset_dir)" ] }, { @@ -197,11 +150,13 @@ "metadata": {}, "outputs": [], "source": [ - "h5_file = h5py.File(val_dir + \"/2018/GOLD_XYZ_OSC.0001_1024.hdf5\",'r')\n", - "X = h5_file['X']\n", - "Y = np.argmax(h5_file['Y'], axis=1) # comes in one-hot encoding\n", - "Z = h5_file['Z'][:,0]\n", + "h5_file = h5py.File(dataset_dir + \"/GOLD_XYZ_OSC.0001_1024.hdf5\",'r')\n", + "data_h5 = h5_file['X']\n", + "label_mod = np.argmax(h5_file['Y'], axis=1) # comes in one-hot encoding\n", + "label_snr = h5_file['Z'][:,0]\n", "\n", + "# assemble list of test set indices\n", + "# do not pre-load large dataset into memory\n", "np.random.seed(2018)\n", "test_indices = []\n", "for mod in range(0, 24): #all modulations (0 to 23)\n", @@ -213,20 +168,13 @@ " np.random.shuffle(indices_subclass)\n", " train_indices_subclass, val_indices_subclass = indices_subclass[split:], indices_subclass[:split]\n", "\n", - " if snr_idx >= 25: #only SNR >= +30dB\n", + " if snr_idx >= 0: #select which SNRs to test on\n", " test_indices.extend(val_indices_subclass)\n", "\n", - "test_indices = np.sort(test_indices)\n", - "\n", - "X_test = X[test_indices]\n", - "Y_test = Y[test_indices]\n", - "Z_test = Z[test_indices]\n", - "\n", - "# bring into 4D NHWC format\n", - "#X_test = np.expand_dims(X_test, 2)\n", + "test_indices = sorted(test_indices)\n", "\n", "# note: labels given in the \"classes.txt\" file are not in the correct order (https://github.com/radioML/dataset/issues/25)\n", - "self.mod_classes = ['OOK','4ASK','8ASK','BPSK','QPSK','8PSK','16PSK','32PSK',\n", + "mod_classes = ['OOK','4ASK','8ASK','BPSK','QPSK','8PSK','16PSK','32PSK',\n", "'16APSK','32APSK','64APSK','128APSK','16QAM','32QAM','64QAM','128QAM','256QAM',\n", "'AM-SSB-WC','AM-SSB-SC','AM-DSB-WC','AM-DSB-SC','FM','GMSK','OQPSK']\n", "snr_classes = np.arange(-20., 32., 2) # -20dB to 30dB" @@ -241,25 +189,25 @@ "name": "stdout", "output_type": "stream", "text": [ - "(9840, 1024, 2)\n", - "(9840,)\n", - "(9840,)\n", - "[ 102401 102404 102414 ... 2555870 2555878 2555889]\n" + "(2555904, 1024, 2)\n", + "(2555904,)\n", + "(2555904,)\n", + "255840\n" ] } ], "source": [ - "print(X_test.shape)\n", - "print(Y_test.shape)\n", - "print(Z_test.shape)\n", - "print(test_indices)" + "print(data_h5.shape)\n", + "print(label_mod.shape)\n", + "print(label_snr.shape)\n", + "print(len(test_indices))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "# Inspect a single sample" + "# Inspect a single frame" ] }, { @@ -271,15 +219,20 @@ "name": "stdout", "output_type": "stream", "text": [ - "Modulation: 32QAM, SNR: 30.0 dB\n" + "Modulation: 16QAM, SNR: 30.0 dB\n" ] } ], "source": [ "from matplotlib import pyplot as plt\n", "\n", - "idx = 1086\n", - "data, mod, snr = X_test[idx], Y_test[idx], Z_test[idx]\n", + "# Inspect a frame\n", + "mod = 12 # 0 to 23\n", + "snr_idx = 25 # 0 to 25 = -20dB to +30dB\n", + "sample = 123 # 0 to 4095\n", + "#-----------------------#\n", + "idx = 26*4096*mod + 4096*snr_idx + sample\n", + "data, mod, snr = data_h5[idx], label_mod[idx], label_snr[idx]\n", "plt.figure()\n", "plt.plot(data)\n", "print(\"Modulation: %s, SNR: %.1f dB\" % (mod_classes[mod], snr))" @@ -289,58 +242,32 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Quantize dataset" + "# Input quantization\n", + "Quantize input data on-the-fly in software before feeding it to the accelerator. Use the uniform quantization range on which the model was trained." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Modulation: 32QAM, SNR: 30.0 dB\n" - ] - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ - "def quantize(data, quant_min, quant_max):\n", + "def quantize(data):\n", + " quant_min = -1.7981509\n", + " quant_max = 1.7840475\n", " quant_range = quant_max - quant_min\n", " data_quant = (data - quant_min) / quant_range\n", " data_quant = np.round(data_quant * 256) - 128\n", " data_quant = np.clip(data_quant, -128, 127)\n", " data_quant = data_quant.astype(np.int8)\n", - " return data_quant\n", - "\n", - "#whole validation set:\n", - "quant_min = -2.0\n", - "quant_max = 2.0\n", - "X_test = quantize(X_test, quant_min, quant_max)\n", - "\n", - "idx = 1086\n", - "data, mod, snr = X_test[idx], Y_test[idx], Z_test[idx]\n", - "plt.figure()\n", - "plt.plot(data)\n", - "print(\"Modulation: %s, SNR: %.1f dB\" % (mod_classes[mod], snr))" + " return data_quant" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "# Classify a single sample" + "# Classify a single frame" ] }, { @@ -352,12 +279,12 @@ "name": "stdout", "output_type": "stream", "text": [ - "Input buffer shape is (1, 128, 1, 16) and datatype is int8\n" + "Input buffer shape is (1, 1024, 1, 2) and datatype is int8\n" ] } ], "source": [ - "accel_in = data.reshape(accel.ishape_normal)\n", + "accel_in = quantize(data).reshape(accel.ishape_normal)\n", "print(\"Input buffer shape is %s and datatype is %s\" % (str(accel_in.shape), str(accel_in.dtype)))" ] }, @@ -373,15 +300,15 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Result: [[18.]]\n", - "Top-1 class predicted by the accelerator: 64QAM\n" + "Result: [[12.]]\n", + "Top-1 class predicted by the accelerator: 16QAM\n" ] } ], @@ -392,14 +319,14 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "1000 loops, best of 3: 843 µs per loop\n" + "1000 loops, best of 3: 1.01 ms per loop\n" ] } ], @@ -412,26 +339,26 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Validate accuracy on entire validation set" + "# Validate accuracy on entire test set" ] }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Accelerator buffer shapes are (120, 128, 1, 4, 4) for input, (120, 1, 1) for output\n", - "Accelerator buffer shapes are (120, 128, 1, 4, 4) for input, (120, 1, 1) for output\n", - "Accelerator buffer shapes are (120, 128, 1, 16) for input, (120, 1) for output\n" + "Accelerator buffer shapes are (1024, 1024, 1, 2, 1) for input, (1024, 1, 1) for output\n", + "Accelerator buffer shapes are (1024, 1024, 1, 2, 1) for input, (1024, 1, 1) for output\n", + "Accelerator buffer shapes are (1024, 1024, 1, 2) for input, (1024, 1) for output\n" ] } ], "source": [ - "batch_size = 120\n", + "batch_size = 1024\n", "accel.batch_size = batch_size\n", "print(\"Accelerator buffer shapes are %s for input, %s for output\" % (str(accel.ishape_packed), str(accel.oshape_packed)) )\n", "print(\"Accelerator buffer shapes are %s for input, %s for output\" % (str(accel.ishape_folded), str(accel.oshape_folded)) )\n", @@ -440,7 +367,7 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 15, "metadata": { "scrolled": true }, @@ -449,303 +376,304 @@ "name": "stdout", "output_type": "stream", "text": [ - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 0 : total OK 119 NOK 1\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 1 : total OK 239 NOK 1\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 2 : total OK 359 NOK 1\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 3 : total OK 471 NOK 9\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 4 : total OK 585 NOK 15\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 5 : total OK 691 NOK 29\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 6 : total OK 792 NOK 48\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 7 : total OK 894 NOK 66\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 8 : total OK 998 NOK 82\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 9 : total OK 1105 NOK 95\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 10 : total OK 1219 NOK 101\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 11 : total OK 1339 NOK 101\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 12 : total OK 1459 NOK 101\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 13 : total OK 1579 NOK 101\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 14 : total OK 1698 NOK 102\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 15 : total OK 1818 NOK 102\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 16 : total OK 1938 NOK 102\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 17 : total OK 2048 NOK 112\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 18 : total OK 2160 NOK 120\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 19 : total OK 2262 NOK 138\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 20 : total OK 2348 NOK 172\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 21 : total OK 2395 NOK 245\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 22 : total OK 2441 NOK 319\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 23 : total OK 2501 NOK 379\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 24 : total OK 2571 NOK 429\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 25 : total OK 2650 NOK 470\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 26 : total OK 2725 NOK 515\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 27 : total OK 2832 NOK 528\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 28 : total OK 2947 NOK 533\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 29 : total OK 3064 NOK 536\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 30 : total OK 3181 NOK 539\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 31 : total OK 3298 NOK 542\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 32 : total OK 3415 NOK 545\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 33 : total OK 3531 NOK 549\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 34 : total OK 3611 NOK 589\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 35 : total OK 3672 NOK 648\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 36 : total OK 3727 NOK 713\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 37 : total OK 3783 NOK 777\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 38 : total OK 3846 NOK 834\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 39 : total OK 3903 NOK 897\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 40 : total OK 3970 NOK 950\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 41 : total OK 4063 NOK 977\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 42 : total OK 4146 NOK 1014\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 43 : total OK 4239 NOK 1041\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 44 : total OK 4315 NOK 1085\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 45 : total OK 4381 NOK 1139\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 46 : total OK 4452 NOK 1188\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 47 : total OK 4513 NOK 1247\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 48 : total OK 4553 NOK 1327\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 49 : total OK 4600 NOK 1400\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 50 : total OK 4644 NOK 1476\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 51 : total OK 4665 NOK 1575\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 52 : total OK 4672 NOK 1688\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 53 : total OK 4685 NOK 1795\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 54 : total OK 4700 NOK 1900\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 55 : total OK 4719 NOK 2001\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 56 : total OK 4736 NOK 2104\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 57 : total OK 4754 NOK 2206\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 58 : total OK 4841 NOK 2239\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 59 : total OK 4930 NOK 2270\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 60 : total OK 5013 NOK 2307\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 61 : total OK 5084 NOK 2356\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 62 : total OK 5116 NOK 2444\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 63 : total OK 5152 NOK 2528\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 64 : total OK 5187 NOK 2613\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 65 : total OK 5302 NOK 2618\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 66 : total OK 5417 NOK 2623\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 67 : total OK 5536 NOK 2624\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 68 : total OK 5636 NOK 2644\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 69 : total OK 5731 NOK 2669\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 70 : total OK 5823 NOK 2697\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 71 : total OK 5925 NOK 2715\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 72 : total OK 6045 NOK 2715\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 73 : total OK 6165 NOK 2715\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 74 : total OK 6285 NOK 2715\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 75 : total OK 6405 NOK 2715\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 76 : total OK 6525 NOK 2715\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 77 : total OK 6645 NOK 2715\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 78 : total OK 6765 NOK 2715\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 79 : total OK 6885 NOK 2715\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 80 : total OK 7004 NOK 2716\n", - "(120, 128, 16)\n", - "(120, 128, 1, 16)\n", - "batch 81 : total OK 7124 NOK 2716\n" + "batch 0 : total OK 5 NOK 1019\n", + "batch 1 : total OK 51 NOK 1997\n", + "batch 2 : total OK 520 NOK 2552\n", + "batch 3 : total OK 1370 NOK 2726\n", + "batch 4 : total OK 2391 NOK 2729\n", + "batch 5 : total OK 3415 NOK 2729\n", + "batch 6 : total OK 4439 NOK 2729\n", + "batch 7 : total OK 5463 NOK 2729\n", + "batch 8 : total OK 6487 NOK 2729\n", + "batch 9 : total OK 7511 NOK 2729\n", + "batch 10 : total OK 7931 NOK 3333\n", + "batch 11 : total OK 7934 NOK 4354\n", + "batch 12 : total OK 7993 NOK 5319\n", + "batch 13 : total OK 8360 NOK 5976\n", + "batch 14 : total OK 9056 NOK 6304\n", + "batch 15 : total OK 9940 NOK 6444\n", + "batch 16 : total OK 10957 NOK 6451\n", + "batch 17 : total OK 11977 NOK 6455\n", + "batch 18 : total OK 13000 NOK 6456\n", + "batch 19 : total OK 14020 NOK 6460\n", + "batch 20 : total OK 14864 NOK 6640\n", + "batch 21 : total OK 14923 NOK 7605\n", + "batch 22 : total OK 15078 NOK 8474\n", + "batch 23 : total OK 15374 NOK 9202\n", + "batch 24 : total OK 16120 NOK 9480\n", + "batch 25 : total OK 17031 NOK 9593\n", + "batch 26 : total OK 18028 NOK 9620\n", + "batch 27 : total OK 19051 NOK 9621\n", + "batch 28 : total OK 20068 NOK 9628\n", + "batch 29 : total OK 21087 NOK 9633\n", + "batch 30 : total OK 22109 NOK 9635\n", + "batch 31 : total OK 22403 NOK 10365\n", + "batch 32 : total OK 22488 NOK 11304\n", + "batch 33 : total OK 22743 NOK 12073\n", + "batch 34 : total OK 23616 NOK 12224\n", + "batch 35 : total OK 24640 NOK 12224\n", + "batch 36 : total OK 25664 NOK 12224\n", + "batch 37 : total OK 26688 NOK 12224\n", + "batch 38 : total OK 27712 NOK 12224\n", + "batch 39 : total OK 28736 NOK 12224\n", + "batch 40 : total OK 29760 NOK 12224\n", + "batch 41 : total OK 30416 NOK 12592\n", + "batch 42 : total OK 30418 NOK 13614\n", + "batch 43 : total OK 30419 NOK 14637\n", + "batch 44 : total OK 30436 NOK 15644\n", + "batch 45 : total OK 31002 NOK 16102\n", + "batch 46 : total OK 32022 NOK 16106\n", + "batch 47 : total OK 33046 NOK 16106\n", + "batch 48 : total OK 34070 NOK 16106\n", + "batch 49 : total OK 35094 NOK 16106\n", + "batch 50 : total OK 36118 NOK 16106\n", + "batch 51 : total OK 37142 NOK 16106\n", + "batch 52 : total OK 37212 NOK 17060\n", + "batch 53 : total OK 37229 NOK 18067\n", + "batch 54 : total OK 37247 NOK 19073\n", + "batch 55 : total OK 37257 NOK 20087\n", + "batch 56 : total OK 37769 NOK 20599\n", + "batch 57 : total OK 38779 NOK 20613\n", + "batch 58 : total OK 39803 NOK 20613\n", + "batch 59 : total OK 40827 NOK 20613\n", + "batch 60 : total OK 41851 NOK 20613\n", + "batch 61 : total OK 42875 NOK 20613\n", + "batch 62 : total OK 43346 NOK 21166\n", + "batch 63 : total OK 43346 NOK 22190\n", + "batch 64 : total OK 43346 NOK 23214\n", + "batch 65 : total OK 43347 NOK 24237\n", + "batch 66 : total OK 43504 NOK 25104\n", + "batch 67 : total OK 44217 NOK 25415\n", + "batch 68 : total OK 45216 NOK 25440\n", + "batch 69 : total OK 46238 NOK 25442\n", + "batch 70 : total OK 47261 NOK 25443\n", + "batch 71 : total OK 48283 NOK 25445\n", + "batch 72 : total OK 49216 NOK 25536\n", + "batch 73 : total OK 49596 NOK 26180\n", + "batch 74 : total OK 49976 NOK 26824\n", + "batch 75 : total OK 50393 NOK 27431\n", + "batch 76 : total OK 50777 NOK 28071\n", + "batch 77 : total OK 51158 NOK 28714\n", + "batch 78 : total OK 51986 NOK 28910\n", + "batch 79 : total OK 52990 NOK 28930\n", + "batch 80 : total OK 54008 NOK 28936\n", + "batch 81 : total OK 55024 NOK 28944\n", + "batch 82 : total OK 56037 NOK 28955\n", + "batch 83 : total OK 56324 NOK 29692\n", + "batch 84 : total OK 56324 NOK 30716\n", + "batch 85 : total OK 56325 NOK 31739\n", + "batch 86 : total OK 56360 NOK 32728\n", + "batch 87 : total OK 56904 NOK 33208\n", + "batch 88 : total OK 57886 NOK 33250\n", + "batch 89 : total OK 58910 NOK 33250\n", + "batch 90 : total OK 59934 NOK 33250\n", + "batch 91 : total OK 60958 NOK 33250\n", + "batch 92 : total OK 61982 NOK 33250\n", + "batch 93 : total OK 62688 NOK 33568\n", + "batch 94 : total OK 62688 NOK 34592\n", + "batch 95 : total OK 62688 NOK 35616\n", + "batch 96 : total OK 62703 NOK 36625\n", + "batch 97 : total OK 63109 NOK 37243\n", + "batch 98 : total OK 63998 NOK 37378\n", + "batch 99 : total OK 65016 NOK 37384\n", + "batch 100 : total OK 66039 NOK 37385\n", + "batch 101 : total OK 67063 NOK 37385\n", + "batch 102 : total OK 68087 NOK 37385\n", + "batch 103 : total OK 69110 NOK 37386\n", + "batch 104 : total OK 69215 NOK 38305\n", + "batch 105 : total OK 69215 NOK 39329\n", + "batch 106 : total OK 69215 NOK 40353\n", + "batch 107 : total OK 69223 NOK 41369\n", + "batch 108 : total OK 69374 NOK 42242\n", + "batch 109 : total OK 69913 NOK 42727\n", + "batch 110 : total OK 70805 NOK 42859\n", + "batch 111 : total OK 71733 NOK 42955\n", + "batch 112 : total OK 72665 NOK 43047\n", + "batch 113 : total OK 73600 NOK 43136\n", + "batch 114 : total OK 74073 NOK 43687\n", + "batch 115 : total OK 74073 NOK 44711\n", + "batch 116 : total OK 74074 NOK 45734\n", + "batch 117 : total OK 74075 NOK 46757\n", + "batch 118 : total OK 74162 NOK 47694\n", + "batch 119 : total OK 74685 NOK 48195\n", + "batch 120 : total OK 75623 NOK 48281\n", + "batch 121 : total OK 76612 NOK 48316\n", + "batch 122 : total OK 77615 NOK 48337\n", + "batch 123 : total OK 78608 NOK 48368\n", + "batch 124 : total OK 79521 NOK 48479\n", + "batch 125 : total OK 79528 NOK 49496\n", + "batch 126 : total OK 79538 NOK 50510\n", + "batch 127 : total OK 79553 NOK 51519\n", + "batch 128 : total OK 79631 NOK 52465\n", + "batch 129 : total OK 80030 NOK 53090\n", + "batch 130 : total OK 80982 NOK 53162\n", + "batch 131 : total OK 82005 NOK 53163\n", + "batch 132 : total OK 83028 NOK 53164\n", + "batch 133 : total OK 84051 NOK 53165\n", + "batch 134 : total OK 85074 NOK 53166\n", + "batch 135 : total OK 85414 NOK 53850\n", + "batch 136 : total OK 85414 NOK 54874\n", + "batch 137 : total OK 85414 NOK 55898\n", + "batch 138 : total OK 85435 NOK 56901\n", + "batch 139 : total OK 85606 NOK 57754\n", + "batch 140 : total OK 86080 NOK 58304\n", + "batch 141 : total OK 87002 NOK 58406\n", + "batch 142 : total OK 87994 NOK 58438\n", + "batch 143 : total OK 88990 NOK 58466\n", + "batch 144 : total OK 89989 NOK 58491\n", + "batch 145 : total OK 90720 NOK 58784\n", + "batch 146 : total OK 90720 NOK 59808\n", + "batch 147 : total OK 90720 NOK 60832\n", + "batch 148 : total OK 90720 NOK 61856\n", + "batch 149 : total OK 90726 NOK 62874\n", + "batch 150 : total OK 90772 NOK 63852\n", + "batch 151 : total OK 91140 NOK 64508\n", + "batch 152 : total OK 91717 NOK 64955\n", + "batch 153 : total OK 92309 NOK 65387\n", + "batch 154 : total OK 92941 NOK 65779\n", + "batch 155 : total OK 93564 NOK 66180\n", + "batch 156 : total OK 93717 NOK 67051\n", + "batch 157 : total OK 93806 NOK 67986\n", + "batch 158 : total OK 93923 NOK 68893\n", + "batch 159 : total OK 94149 NOK 69691\n", + "batch 160 : total OK 94278 NOK 70586\n", + "batch 161 : total OK 94655 NOK 71233\n", + "batch 162 : total OK 95420 NOK 71492\n", + "batch 163 : total OK 96239 NOK 71697\n", + "batch 164 : total OK 97071 NOK 71889\n", + "batch 165 : total OK 97911 NOK 72073\n", + "batch 166 : total OK 98390 NOK 72618\n", + "batch 167 : total OK 98406 NOK 73626\n", + "batch 168 : total OK 98431 NOK 74625\n", + "batch 169 : total OK 98497 NOK 75583\n", + "batch 170 : total OK 98645 NOK 76459\n", + "batch 171 : total OK 99041 NOK 77087\n", + "batch 172 : total OK 99671 NOK 77481\n", + "batch 173 : total OK 100412 NOK 77764\n", + "batch 174 : total OK 101156 NOK 78044\n", + "batch 175 : total OK 101917 NOK 78307\n", + "batch 176 : total OK 102635 NOK 78613\n", + "batch 177 : total OK 102702 NOK 79570\n", + "batch 178 : total OK 102953 NOK 80343\n", + "batch 179 : total OK 103569 NOK 80751\n", + "batch 180 : total OK 104381 NOK 80963\n", + "batch 181 : total OK 105164 NOK 81204\n", + "batch 182 : total OK 106173 NOK 81219\n", + "batch 183 : total OK 107165 NOK 81251\n", + "batch 184 : total OK 108118 NOK 81322\n", + "batch 185 : total OK 109045 NOK 81419\n", + "batch 186 : total OK 109977 NOK 81511\n", + "batch 187 : total OK 110393 NOK 82119\n", + "batch 188 : total OK 110508 NOK 83028\n", + "batch 189 : total OK 110612 NOK 83948\n", + "batch 190 : total OK 110759 NOK 84825\n", + "batch 191 : total OK 111221 NOK 85387\n", + "batch 192 : total OK 111277 NOK 86355\n", + "batch 193 : total OK 111336 NOK 87320\n", + "batch 194 : total OK 111425 NOK 88255\n", + "batch 195 : total OK 111554 NOK 89150\n", + "batch 196 : total OK 111691 NOK 90037\n", + "batch 197 : total OK 111800 NOK 90952\n", + "batch 198 : total OK 111867 NOK 91909\n", + "batch 199 : total OK 112010 NOK 92790\n", + "batch 200 : total OK 112335 NOK 93489\n", + "batch 201 : total OK 112898 NOK 93950\n", + "batch 202 : total OK 113797 NOK 94075\n", + "batch 203 : total OK 114799 NOK 94097\n", + "batch 204 : total OK 115816 NOK 94104\n", + "batch 205 : total OK 116825 NOK 94119\n", + "batch 206 : total OK 117838 NOK 94130\n", + "batch 207 : total OK 118844 NOK 94148\n", + "batch 208 : total OK 119131 NOK 94885\n", + "batch 209 : total OK 119332 NOK 95708\n", + "batch 210 : total OK 119799 NOK 96265\n", + "batch 211 : total OK 120511 NOK 96577\n", + "batch 212 : total OK 121195 NOK 96917\n", + "batch 213 : total OK 122086 NOK 97050\n", + "batch 214 : total OK 122976 NOK 97184\n", + "batch 215 : total OK 123898 NOK 97286\n", + "batch 216 : total OK 124827 NOK 97381\n", + "batch 217 : total OK 125740 NOK 97492\n", + "batch 218 : total OK 126349 NOK 97907\n", + "batch 219 : total OK 126519 NOK 98761\n", + "batch 220 : total OK 126980 NOK 99324\n", + "batch 221 : total OK 127978 NOK 99350\n", + "batch 222 : total OK 129002 NOK 99350\n", + "batch 223 : total OK 130026 NOK 99350\n", + "batch 224 : total OK 131050 NOK 99350\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "batch 225 : total OK 132074 NOK 99350\n", + "batch 226 : total OK 133098 NOK 99350\n", + "batch 227 : total OK 134122 NOK 99350\n", + "batch 228 : total OK 135146 NOK 99350\n", + "batch 229 : total OK 135170 NOK 100350\n", + "batch 230 : total OK 135173 NOK 101371\n", + "batch 231 : total OK 135266 NOK 102302\n", + "batch 232 : total OK 136058 NOK 102534\n", + "batch 233 : total OK 137082 NOK 102534\n", + "batch 234 : total OK 138106 NOK 102534\n", + "batch 235 : total OK 139130 NOK 102534\n", + "batch 236 : total OK 140154 NOK 102534\n", + "batch 237 : total OK 141178 NOK 102534\n", + "batch 238 : total OK 142202 NOK 102534\n", + "batch 239 : total OK 142647 NOK 103113\n", + "batch 240 : total OK 142647 NOK 104137\n", + "batch 241 : total OK 142649 NOK 105159\n", + "batch 242 : total OK 142742 NOK 106090\n", + "batch 243 : total OK 143513 NOK 106343\n", + "batch 244 : total OK 144535 NOK 106345\n", + "batch 245 : total OK 145559 NOK 106345\n", + "batch 246 : total OK 146583 NOK 106345\n", + "batch 247 : total OK 147607 NOK 106345\n", + "batch 248 : total OK 148631 NOK 106345\n", + "batch 249 : total OK 149495 NOK 106345\n" ] } ], "source": [ "ok = 0\n", "nok = 0\n", - "for i in range(int(X_test.shape[0]/batch_size)):\n", - " batch_idx = i*batch_size\n", - " data, mod, snr = X_test[batch_idx:batch_idx+batch_size], Y_test[batch_idx:batch_idx+batch_size], Z_test[batch_idx:batch_idx+batch_size]\n", + "total = len(test_indices)\n", + "for i_batch in range(math.ceil(total/batch_size)):\n", + " i_frame = i_batch*batch_size\n", + " if i_frame+batch_size > total:\n", + " batch_size = total - i_frame\n", + " accel.batch_size = batch_size\n", + " batch_indices = test_indices[i_frame:i_frame+batch_size]\n", + " data, mod, snr = data_h5[batch_indices], label_mod[batch_indices], label_snr[batch_indices]\n", + "\n", + " ibuf = quantize(data).reshape(accel.ishape_normal)\n", + " obuf = accel.execute(ibuf)\n", + "\n", + " pred = obuf.reshape(batch_size).astype(int)\n", "\n", - " data = data.transpose(0,2,1)\n", - " data = data.reshape(-1, 16, 128)\n", - " data = data.transpose(0,2,1)\n", - " #x = x.reshape(-1,2,int(1024/interleave),int(interleave))\n", - " #x = x.permute(0,1,3,2).contiguous()\n", - " ibuf_normal = data.reshape(accel.ishape_normal)\n", - " obuf_normal = accel.execute(ibuf_normal)\n", - " obuf_normal = obuf_normal.reshape(batch_size)\n", - " #obuf_normal = post_process(obuf_normal)\n", - " \n", - " pred = obuf_normal.astype(int)\n", - " \n", - " print(data.shape)\n", - " print(ibuf_normal.shape)\n", - " #print(obuf_normal.shape) \n", - " #print(mod.shape)\n", - " #print(pred.shape)\n", - " \n", " ok += np.equal(pred, mod).sum().item()\n", " nok += np.not_equal(pred, mod).sum().item()\n", " \n", - " print(\"batch %d : total OK %d NOK %d\" % (i, ok, nok))" + " print(\"batch %d : total OK %d NOK %d\" % (i_batch, ok, nok))" ] }, { "cell_type": "code", - "execution_count": 33, + "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "30dB top-1 accuracy: 72.39837398373983%\n" + "Overall top-1 accuracy: 58.43300500312696%\n" ] } ], "source": [ - "total = X_test.shape[0]\n", "acc = 100.0 * ok / (total)\n", - "print(\"30dB top-1 accuracy: {}%\".format(acc))" + "print(\"Overall top-1 accuracy: {}%\".format(acc))" ] }, { @@ -757,33 +685,33 @@ }, { "cell_type": "code", - "execution_count": 50, + "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "{'DRAM_in_bandwidth[Mb/s]': 435.46256676467607,\n", - " 'DRAM_out_bandwidth[Mb/s]': 0.2126282064280645,\n", - " 'batch_size': 1000,\n", - " 'copy_input_data_to_device[ms]': 1.878499984741211,\n", - " 'copy_output_data_from_device[ms]': 0.08535385131835938,\n", + "{'DRAM_in_bandwidth[Mb/s]': 64.74523228253237,\n", + " 'DRAM_out_bandwidth[Mb/s]': 0.03161388295045526,\n", + " 'batch_size': 1024,\n", + " 'copy_input_data_to_device[ms]': 2.189159393310547,\n", + " 'copy_output_data_from_device[ms]': 0.08916854858398438,\n", " 'fclk[mhz]': 187.498125,\n", - " 'fold_input[ms]': 0.09822845458984375,\n", - " 'pack_input[ms]': 0.11038780212402344,\n", - " 'runtime[ms]': 4.703044891357422,\n", - " 'throughput[images/s]': 212628.20642806447,\n", + " 'fold_input[ms]': 0.1010894775390625,\n", + " 'pack_input[ms]': 0.1556873321533203,\n", + " 'runtime[ms]': 32.39083290100098,\n", + " 'throughput[images/s]': 31613.88295045526,\n", " 'unfold_output[ms]': 0.08726119995117188,\n", - " 'unpack_output[ms]': 0.6067752838134766}" + " 'unpack_output[ms]': 0.6263256072998047}" ] }, - "execution_count": 50, + "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "accel.batch_size = 1000\n", + "accel.batch_size = 1024\n", "accel.throughput_test()" ] }, From 900c80e3a6261e4561a64d0aa24ca81470fac837 Mon Sep 17 00:00:00 2001 From: Felix Jentzsch <45395194+fpjentzsch@users.noreply.github.com> Date: Fri, 30 Jul 2021 16:36:34 +0200 Subject: [PATCH 05/49] Update README.md --- build/vgg10/README.md | 57 +++++++++++++++---------------------------- 1 file changed, 20 insertions(+), 37 deletions(-) diff --git a/build/vgg10/README.md b/build/vgg10/README.md index 38b69a2..7fdcf49 100755 --- a/build/vgg10/README.md +++ b/build/vgg10/README.md @@ -1,30 +1,21 @@ -# MobileNet-v1 - -MobileNet-v1 was [introduced](https://arxiv.org/abs/1704.04861) by Google in 2017 as a lightweight -DNN targeting the ImageNet dataset. -It has a repeated structure of depthwise-separable (dws) convolution building blocks. -Each dws convolution consists -of a depthwise and a pointwise convolution each followed by a batchnorm and ReLU block. -MobileNet-v1 has 13 of these blocks. -Here, we use a reduced-precision implementation of MobileNet-v1 from [Brevitas](https://github.com/Xilinx/brevitas/tree/master/brevitas_examples/imagenet_classification), -where the weights and activations are quantized to 4-bit, except for the first -layer which uses 8-bit weights and inputs. -It requires about 2 MB of weight storage and 1.1 GMACs per inference, yielding -70.4\% top-1 accuracy on ImageNet. - -## Build bitfiles for MobileNet-v1 - -Due to the depthwise separable convolutions in MobileNet-v1, -we use a specialized build script that replaces a few of the standard steps -in FINN with custom ones. -**MobileNet-v1 is currently only supported on Alveo U250 and ZCU104.** -We also provide a folding configuration for the **ZCU102**, but there is no pre-built Pynq image available for this board. +# VGG10 + +This 1-dimensional CNN was [introduced](https://arxiv.org/pdf/1712.04578.pdf) by DeepSig alongside their RadioML 2018 dataset for RF modulation classification. +It consists of 7 1D convolution + maxpooling layers, followed by 2 hidden dense layers and the final dense classification layer. ReLU activations and Batchnorm are applied throughout the network. The input is a frame of 1024 I/Q samples (i.e. shape [1024,2]), the classifier distinguishes 24 classes (i.e. modulation types). + +Here, we use a reduced-precision implementation trained on [RadioML 2018.01A](https://www.deepsig.ai/datasets) with Brevitas. The weights are quantized to 4-bit and the activations to 3-bit, except for the first layer which uses 4-bit activations. The pre-trained model reaches 58.4% overall accuracy and 90.9% at the highest SNR (30 dB). + +## Build bitfiles for VGG10 + +Due to the 1-dimensional topology in VGG10, +we use a specialized build script that adds a few custom build steps to the standard steps in FINN. +**We currently provide bitstreams and the corresponding build configuration only for the ZCU104, but plan to extend to other boards shortly.** 0. Ensure you have performed the *Setup* steps in the top-level README for setting up the FINN requirements and environment variables. -1. Download the pretrained MobileNet-v1 ONNX model from the releases page, and extract -the zipfile under `mobilenet-v1/models`. You should have e.g. `mobilenetv1/models∕mobilenetv1-w4a4_pre_post_tidy.onnx` as a result. -You can use the provided `mobilenet-v1/models/download_mobilenet.sh` script for this. +1. Download the pretrained VGG10 ONNX model from the releases page, and extract +the zipfile under `vgg10/models`. You should have e.g. `vgg10/models∕radioml-w4a3_tidy.onnx` as a result. +You can use the provided `vgg10/models/download_vgg10.sh` script for this. 2. Launch the build as follows: ```SHELL @@ -32,22 +23,14 @@ You can use the provided `mobilenet-v1/models/download_mobilenet.sh` script for FINN_EXAMPLES=/path/to/finn-examples # cd into finn submodule cd $FINN_EXAMPLES/build/finn -# launch the build on the mobilenet-v1 folder -./run-docker.sh build_custom /path/to/finn-examples/build/mobilenet-v1 +# launch the build on the vgg10 folder +./run-docker.sh build_custom /path/to/finn-examples/build/vgg10 ``` -5. The generated outputs will be under `mobilenet-v1/output__`. You can find a description of the generated files [here](https://finn-dev.readthedocs.io/en/latest/command_line.html#simple-dataflow-build-mode). +5. The generated outputs will be under `vgg10/output__`. You can find a description of the generated files [here](https://finn-dev.readthedocs.io/en/latest/command_line.html#simple-dataflow-build-mode). ## Where did the ONNX model files come from? -The 4-bit quantized MobileNet-v1 is part of the -[Brevitas examples](https://github.com/Xilinx/brevitas/tree/master/brevitas_examples/imagenet_classification). -Subsequently, the trained networks is [exported to ONNX](https://github.com/Xilinx/finn/blob/master/notebooks/basics/1_brevitas_network_import.ipynb). In addition, the particular version used here has two additions for pre- and postprocessing: - -* A divide-by-255 node is added at the input, and the input is marked as 8-bit (to directly accept 8-bit images as input) -* Normalization is added at the input with `mean = [0.485, 0.456, 0.406]` and `std = 0.226`. Note that the `std` is global and not per-channel to facilitate its removal via the [streamlining transform](https://arxiv.org/pdf/1709.04060). -* A top-K node with k=5 is added at the output (to return the top-5 class indices instead of logits) +The quantized VGG10 is based on the baseline topology for our problem statement in the ITU AI/ML in 5G Challenge. You can find it in our [sandbox repository](https://github.com/Xilinx/brevitas-radioml-challenge-21). -These modifications are done as part of the end2end MobileNet-v1 test in FINN. -You can [see more here](https://github.com/Xilinx/finn/blob/bf9a67eee6ff5a797ea3a0bd866706d7518c3c6f/tests/end2end/test_end2end_mobilenet_v1.py#L102) -for further reference. +In addition, the ONNX model has been tidied up by removing the input quantization, which we do in software for this example, and by adding a top-k (k=1) node at the output. Thus, the accelerator returns the top-1 class index instead of logits. From 0cd6d3dacceb8b32f5b275c855b38b588083387f Mon Sep 17 00:00:00 2001 From: Felix Jentzsch <45395194+fpjentzsch@users.noreply.github.com> Date: Fri, 30 Jul 2021 16:44:04 +0200 Subject: [PATCH 06/49] RadioML example image for readme --- docs/img/radioml.png | Bin 0 -> 38471 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/img/radioml.png diff --git a/docs/img/radioml.png b/docs/img/radioml.png new file mode 100644 index 0000000000000000000000000000000000000000..caf42b571c428734b120da6cfda9b2eba51ba92d GIT binary patch literal 38471 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 literal 0 HcmV?d00001 From 92e6f4ec0e43baa53da3bf99c67f3eae291e5345 Mon Sep 17 00:00:00 2001 From: Felix Jentzsch <45395194+fpjentzsch@users.noreply.github.com> Date: Fri, 30 Jul 2021 16:47:35 +0200 Subject: [PATCH 07/49] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a95549e..5a381a5 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ dummy_out = accel.execute(dummy_in) |

MNIST | 3-layer fully-connected | several variants:
1/2-bit weights/activations | all | |

ImageNet | MobileNet-v1 | 4-bit weights and activations
8-bit first layer weights | Alveo U250
ZCU104 | |

ImageNet | ResNet-50 | 1-bit weights 2-bit activations
4-bit residuals
8-bit first/last layer weights | Alveo U250 | - +|

RadioML 2018 | 1D CNN (VGG10) | 4-bit weights, 3-bit activations
4-bit first layer activations | ZCU104
(to be extended) ## Supported Boards *Note that the larger NNs are only available on Alveo or selected Zynq boards.* From 7898153759c00c170f885cef80f9d2a707923b96 Mon Sep 17 00:00:00 2001 From: Yaman Umuroglu Date: Fri, 27 Aug 2021 11:26:48 +0200 Subject: [PATCH 08/49] updated Pynq-Z1 link for new zip including binary-cop --- finn_examples/bitfiles/bitfiles.zip.link | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/finn_examples/bitfiles/bitfiles.zip.link b/finn_examples/bitfiles/bitfiles.zip.link index 95e7e0d..1a8d6cf 100644 --- a/finn_examples/bitfiles/bitfiles.zip.link +++ b/finn_examples/bitfiles/bitfiles.zip.link @@ -1,7 +1,7 @@ { "Pynq-Z1": { - "url": "https://github.com/Xilinx/finn-examples/releases/download/v0.0.1a/Pynq-Z1.zip", - "md5sum": "04f4887540a2156bd2886c9bb2bb2ff6" + "url": "https://github.com/Xilinx/finn-examples/releases/download/binary-cop/Pynq-Z1.zip", + "md5sum": "8d36644dfa90711767e979c1a437b46d" }, "Pynq-Z2": { "url": "https://github.com/Xilinx/finn-examples/releases/download/v0.0.1a/Pynq-Z2.zip", From 207f5ed6e48cf1f3420f41d0ee5641820327c715 Mon Sep 17 00:00:00 2001 From: Yaman Umuroglu Date: Fri, 27 Aug 2021 11:41:56 +0200 Subject: [PATCH 09/49] Add Binary-CoP to README --- README.md | 5 ++++- docs/img/maskedfacenet.jpg | Bin 0 -> 93398 bytes 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 docs/img/maskedfacenet.jpg diff --git a/README.md b/README.md index a95549e..331fd7f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -## Dataflow Accelerator Examples +## Dataflow Accelerator Examples *for PYNQ on Zynq and Alveo* drawing @@ -67,6 +67,9 @@ dummy_out = accel.execute(dummy_in) |

MNIST | 3-layer fully-connected | several variants:
1/2-bit weights/activations | all | |

ImageNet | MobileNet-v1 | 4-bit weights and activations
8-bit first layer weights | Alveo U250
ZCU104 | |

ImageNet | ResNet-50 | 1-bit weights 2-bit activations
4-bit residuals
8-bit first/last layer weights | Alveo U250 | +|

MaskedFace-Net | [BinaryCoP](https://arxiv.org/pdf/2102.03456)
*Contributed by TU Munich+BMW* | 1-bit weights and activations | Pynq-Z1 | + +We welcome community contributions to add more examples to this repo! ## Supported Boards diff --git a/docs/img/maskedfacenet.jpg b/docs/img/maskedfacenet.jpg new file mode 100644 index 0000000000000000000000000000000000000000..de189952b6d237a53b99fc3ac00018ab2f62eaf4 GIT binary patch literal 93398 zcmd431zc2J*El*f2uLU*4Fb~LH3&$T(v2`Pz|aicB7$^Emvn=4t8__sH%NDf|Iz2s z$M^le-@V^=>vs>FIeV|Y*4lf;UVERJbJq9C?~4FjIVo8w00II6zz+Tg_`W2pF6ja_ z0RUuW83E`30Q|&9Kms7ZOFvFx1eBjwYj~OD@3IrTO#e3yBD~CjfC#{XU%lWbC%pU+ zehq@3Lh!OU{F(|sq3@7?@>ztJpTHTzyZ%}Kb(NM?d_l>{%FoKl3E*VsG)=(izc_SFqic-eN%F4zO46n-=S;Fh$5Nk6dW2hy> zUWiiB$m~ZOr6R=A0%8Rf0-yi@5oiEpc)xJ=?0^q{mpRzk5kCAS@AvNj0OE(g#tDLt z5$W$T_=h6k2Py#RZ>dq?wO^XCg}46Fj0?Q{r)Cfk|Kj!<4oCdE+$Z>x8Q=sCga7}& ze*e=tKbqi;-)8_40CZGTG*lFHG&D2}4D@?g53#W@F|mm7AK*MBBc>oHBPJ!Kq+z9_ ze8NmkN=nbiz|79U&CN|gCm_PlDa^{n&G~}~0tN;K7ADqXZ0yIJRHRg#|KsEP7XThQ zpbgN9gzyA_h=+iLhw!}(Kmi{o3fz}|xYOSU0wNMJ3Mv{p#yw0pLKQ9m5djGa5g7>u z1sSe;1W$N702vPjpNc~a^}$Ocv?q2CIejA2(W%ADnh8{f4rsWHVQ(<*JtBNeL`?gX zj-G*$n}?T=UqDdexule|jI5lhn!1LjmbMNE3^6e^gPPkrI667IxVrhi_49uh5Ev8{ z{XQl(E>3PvaF51p`67ozsicn^XX+e$1N4ciP z*7}nL(F3tfd?4y*r3ptC%j_cT93qq!$hj$iqBE$2>A4$$K0okzrS5x_`CR8SSIW`- zr?HOA>UyiB$p=htMtOQK9EF0lZ1y$iwXz^KM3-pD8~l{VSDFQ8cUan$tEp$pGVvSc zk|BQQz|&=?L&5}AG9}Rm5=w#usoFutmX7*cOzeQ@sM4l@NwHNsgXm)V zp_hTp@;De8_L0$r7xrye`h{|deZ8TLK0>P#NaR&TEIpa#aZ~pZD9pSKi``Qjyj|Up zd8_4VEHmBlVOim8284x^y^vzd1i6ax`fzo+(oMOyYa%o@IvoCG($XmNRe5ugP}F>< za3()2Q%juj`iBRfLp;{~v2|qMdlS_e-E1?pj@z)DHXeF>jlz|_L8HDT-aqN>(~eq7 zQqn&Rc@t&3@J?s7eJn90!{%)|hSZUOko~dXB=96w8X`PAh4uDC6M4dEjY- zE;N$OWEm96K(m1~UOCP*w9N15egS$1sQ`X)K|;Hc6#6nxGhE6&Gv%oD#FhN8$4UVZ zuZOdt)4~};%e&LBr@rJ({W{EH1TNSMeS_g=T~vmo4y@P z*@vXx0hSX*po8^f8rcWnqWomiROJtd8CBj7pz}}U?agSa(HdVN0_%$LV``qhHy+Qa z@%N%KAKtD`l&Uh%*wP;6pmEg$pA)1XQW!MVj%FO3r7#CP(@e;K5e0s0^l}V!MTdyR^G-HCe~Gwx~etrAwB95ze4Ebl;1$6A1?0Y8rgE4mKDDdNzb;a11Gdp&E_wM59Kxw$I_ej;Cwv=V44A@Oz3-jQCP z-c|XTW)d~3XKg*03CNM4dez&HnCvhhAgsZjPbZ=jRQW31v2F`bfFn$i02%F^>0(IV zG}V z?V{M-Y^&nv*;oHRXu_3KQ#)5NN z6SvM_VNKNVY*^O>mZ<%`6S@x~f>;{|#iH+s*ZK>WDnt%(C{drZc^(K-j5kgwPv8WX z78Pej%w*>n$ZIQ|)}G(sn4c;>Ql*R%DG2!Rin4<~ALy#jL@55AN_sx7QI@njx5JA1 z6+Wj^Vc6^Bu+eUws7Rs4t^(g=j+K*wtF=h>-~=}O+0Jo^&3(N@SyMa4ncM)Y$*##K zGV%A_eIu|flyO&-V_FR(dv&okR1=h?w;Xg>Zn6~~_+g3JRh6T66P4l(8<2Qvj9d6z z$FFI6aed+0DP20w70DW(VAer~7)yB!b^<>e_BR?YkIUGAtDk`*_44is@bi}fU!=so zvow9^zM7bE8R^5IZukCD3VnN9%|o_8r#0Kx!CwP(J%CnDR0fsC?%@1TO9a)69yx#WG~CroVHJPEO)Ihn&4oI z#jVU+n4^whnrWn67T__w-)YAvP1?TTVOlopo_H+JhO{s{SH$QvD}+T&1z>Zc%R#X= z@Qho!VLNNmnyvhB>2x6J&&)3z9pW}Nl>b;P?2pYa$fX^Eob6K zP@2j!vw2#ItGD24j+p!!N75iI)XaQd*i%9=ah}BDePCBFw=bC+>AhVKmUI^zl>@sb z-}90#6%EH;Nvg-)?As^BzV~bX9unYA0LL64#Q7JU$?H{FWCZ1F5 zq6CJ=eq^v-e3drbxG#P{?INlkte^HWY*`5R=+YQ&Z(O14Q60iCb;pF&QD)IfD%L*y zjt-VOVDjOvq(BGTg67jIfj(AQt=`Pofh25fKM6u!7{T4^C3`}Br}uza?3 zT6l~EF`rh3IyK4uVnW23;b~|l@^ZR;`N7&ibgoRE8ec+MQb>r~a*gq)c#8Or4=1;a z0yo(92WAuHQbWzo_=PwzjhWl0`Pm=GPOcds_!9O{7=U^fACsNBpVpfh=eIw^>$@s9td+wZ{A@Qt*FUxW-1jS8Pmb75xxF_AgG3E=R#PAt$K>xB@|(pz zGo`+DbTY=RCtnfqjsbnUqf}I0mZ_4(q|MF>OzjX?OY6eYL?di-sjSvD{75_H<55}L zkAYb3z~Uqn{*a`tUeIH>j`5@LOMU-aKVQiif?7aLn#-=~@rKVUmG`7#=+t&hb zUy-e<*kJP9L*QM<5!7m2zV4d>WbH< z9w!RmehN;B#h_)K_Dkun&)WH$JLEX$9x!xxoj94YEGKnaSEc7RevrgPgIZ(aCErzP zdXd z8g2C*)23%}I53oGizuX_>GwM3&gu$PkeDKJy0%0{h~BrrY~>wnT}dd(e%4HE(t4l2 z`z~g9Q^)ulpWAz=kSx*6am+NQl$*QhX$djI9!r%})QU@(;x;wasx|V1t1%XW>^eWG zq(&!G{iUfQ9;SgRbIump_`QTFe>Erami(>glE`ID-CO>AysxOMR563exOUB5#l6Z1 z7qEWl!qT!6MQiVhQMY)~8#x>pB~_GF zhpdYld&`(%-S_-Z-k`MNcmy3N0{dq=KR?)Ct&b*F!>=CHC3@C*PlOZZEqHEmse6Yv zlOJ>B)%NxAsVLQYqv7ISTF%^N;`?(&`daOg7#QGj*T70*edPNUGiwlrIR1KS*Z%1( zl7t{lz2yttPQqB*fJ~A$>+r>f)(Rr=(##EeC8?gg}Kd+g_||F?DwNX1RbgKDYDfL-T5y9 z&GXM^lwOE=Hoak zIn*?fiaO4V53j4kuDMv>sZ*Sn(7E)!4vERPNz(iLMX|(HrB?T@<}hcHRQuRi97E;F6H-Lnc zcq#%?P&Akq(w4!yERc8XT$-=5Xs`b$H44ro0{R=IE$w1K^SP#G$_bhycAIZ3Vh&A$ zbH!{(CYv9M>G~_+v@~=zQkg`)4ZA(_?-tLsQC1w2Ry{CD!)};YbdwXi?(AP*bONL@ zW$^0^#;hh(DOeL12^f#{$2BVpU5F}iS#w&xlE3d_Okb>gU+TV(*;l}9_UjXrK#KH? z%9r|KPfv$Z1qzwy0%)838tZoV<|afAI%<@|c7!XTX}#|w(2vf&p5HqX#eMW0@HS5E zGW^D~cj2}|7f5`7n!hY>QjZnUJcRZ3X3XIbKWDF+K<}aH!|XyK5*u7e$I?DeTXfln zk|Z4KJQT~WB`b1xJ^iwa09Z~VllH-<+@;`jl)&OE28-txE zOb^a&mAq3-8OP&<_%eOhbB5hY-sNuV6bagQe9g)vE3#`a+mZPW5V2qteW0~kzT-^F zD3t&@DV7}H%?4ZsS#Y&!@Dk_5Lm1ZPrR+&^NdkAgnna0hzs{;hah1MrzrGF)nIFj2 z)6)y#>e7mE!?Hyit`iYg3zn@5GYf>hWeyTRK766OIZ=HUj4v%*A)F@6$>OdS%Qs^E=_bV8xCwd;ZDigsn>DCEDcXPOwrLj1D9dGEMmXu2wu z(>^G8vUV|lBsxy@!=NM2A%$=1EN*!c2ga=3@xv#LHcMX7CEo!p%C2OYMR>Y5amEUZ z$00apg`jpp81|Dr?H5G5hwqrB29-EEJti;g5YLOG*fJ+GTI9;u{M4%A zi>PB+zulYcpxv12ZdSw)tc`_Ym%UJw`Qqhx+O{}+jJDy=H<&buRcB`7iwF(KE78fC z%1io!n0a6XZEGto#(GlleOK<)ts2*!B_(c97By&aKfBQ-AV`@(TX~N3jLe&O&7sL& zb+%&}jjr^wjWtcROi_xX77RmeNS=$(Xw}q-)}9PeD!|EIWVI3-{Cb z2@3|k1r$;V(|(XCou+V>cLOcjcCP2f%TmUETW%G@2O>Qw=8hVN<=rK96 z0{i$Z7qD^>uxEjEP0^OfQ&qJy-22d2F^`~&(QShuu~cQYahh~NC1*jDHOmcyVVO)M zo zmeh7gxrG<&jVrusxeA@l?X3u!OGtjhS94IXQKG~Y|9QkiktZ5wH{TJ{=r|rCoUF-G zXue-WLvCa?%`=G@!itthwq2st-NVa&mwQiTy=)7Jf0#6Xq0`~I%fZBiIz5T(Pc52F zkg&M8y(CZN$G^}&`yD{?QhR=VLfB9zFy~MspE%5Gg5xG3)IH5FYFlw+u_kJ$4ftZZ z&9@6F6^$a)CHp%5#;~A1B+`-nW_IG!q=m`8a&_$+HE=8~WOkK2O^(6nwrOk^WU0Zn zbyG4?*Xbb@bhpxKFH74XHP}TYPayOzuT$<=gh}@Es9vur`LSigD$xeTs%FhagGP`j z_AE5H za8hWI$5Vhl6yx+7)uo6H_aboT#J$izf$uHjYw%5{&z+r4Cm>TfRXM#^lhx*@J_CTkw#x= zmd=-ZCiUw@W8i~shjC6y(0i1CM}zdDt`(WVFY1p<9_b=cyay^LQ*hldC5`Rd7|XC_ zm0b&FE%WJ5%@=og>y6DQ<6<_@vx4l(!C2{?)YJKf`YAT5;ffNCx;T{z?hMWMfQ|5u z9QB^$DyJnq%MCq?KJ%zQ<^N1RAD}ZmRY%Ar^|dJ(;C9DfQXxKUZPmyIw&WJV?1+i4 zizN{9G8R}F)O>KrITu!u*@ceCL*sjQP}12jMS*-m;pD_bktdM9 zeFrT1-AmI^obF0fJ=ooNbJGQBeDm$|J>!0{6UuX8;;LL165YCTzBqh&lEZS&R=Ou; zjq(NanBmN`jT!UG?D+O?Z~(-on4S)LGwpULEsd}|Fiq;aP2Hi)-6ZEn)DKS0+G!nJ zfrZ#-33*k;M~~MrqodDX_v38p1154lUT_tBaMreVe1KSaHogxbTFAH~Ol}Se&-LH)bw9(ex zU5nS0CaG^+vk#h*BU%OSt2kR_(mg&WD!8)RpY~98uy#tIgW`*{QoB;n1Lshj?l9l< ztRHP$OVM0Ee}&?6^h{*n6UWs!-rH=}=MHN5=+e_bzul*b)+Eqf?Hu_GWfScm;0OgfWLl_2K^Q&PL2hDwc2$daxpkfchKj&=Zx<9s@(Y{`mG<6UcP zpom`^4Es__BJ#M307D2X-}yjiTHko@{MzKzh{B#`_hXVkU{yl?4D=4MGOYF5+#)}Y z?acA*gKjzzua^eB-t^Tq^|c~Tq`bRK8sD{O2s&k2cov&mme1)`$aUyNm2DthsvBEK zV-wI9D;}JXGt~BdgXx5aGCQio9_#AAmByl>l?Ax5DUUZ8zKh-@R*0*acDy#^8B~vA zPz6bbtki9%4cFQ{YR-{{vF^ZKr4Z#Y#jUw>Yg17U z^cB;Gw6=PWsGf{XrG9NE^0aWB)njS1Czawias9LvN!ips|Fl2RE`& z@;NC*k|nr|Ik!_Aqi*o!3wm~kHGv(Plg`syur8%G^YIEyy#MJzO#&#NLKfG{zfQVw zB>Rx%a#Wjuc*%c4beFhpAWHC_ACLO9G~W~HqWKy5yxVH}SG2(eHZ!RgD?uj>I4C+( zE`mEVTT(8wNuN0~$o!ve@4hf+$()kHXE4&HQ6hAbrC8DjhT`YGW<@MPi{wREb>Q*K z3~`BFT2^S5hO znJ;F6`kj)Jm*%`9T5)$VB5*(~R^sM{|aaYirbCNr5b3 z36JyN8>glyB`c8)S7tJ`b(J614qETO3L4dyWKh39P$LB6a}a^nd=gCk4p5ApqEw&1 z7uA<+`dKXXw68fk!FYi|l;e`!)-JJ_r}6LsK!YVD#4%k~5>^~0Af*zOq?1IoOQU3)&5FtN`@qA)_tolduuZ|XO!yo0hmgHBClUsZf@kp;%PQ_*Z7l#-e#ISl~5Xou{#yAN_ zcUFNfRNIFovu}fz1)QfJ(XDkcq;jOL@VA>ah00dxf*G#e)JD=91m~Qa&-l*DJ^glz zr{ZE=x>pWLq?g29iAxGT%8|e__B!|geZIcR<2RmmBJaoD^s{=IgL?Y65C9>h^!pk> zqRFmAzmxTOEj7P;+@eq)P(hyvK*}h zt)Eoa5jTA}(x!Ih7gA0a9j+aPc4V$zC~c?|X4TzM=e}!k z%_lnyNkxrJAc5@zj$F1c#)9W`#>d4r;tAqc*p8yL-6jH`)mdP?$T0q^ ziF}P1^pSeu0`)`u{GKaon;V8;r=$YLn}!ruvRaTWR$|0vevS}+*Emj7Ezh!Bk`8#3wcL<6Otmki@BM8O053HeGb14K_|3g*Bx?( z>XgP>B88$EwMF`kI$+EUU)ae&MbrDBZM(`g;qoGk4g}I$#)6S-)Ta2C#R2(*yJ12q z2RXhuz2KH%(fK(VSj?9$ftBNS{qPnb`MUu%6!i|?2P3CNr9>E@gYDalGx{vn;)jqg z5vhGX!*#tB0deHd?eu1ZD;O6WE!jJ-R5N!>nvTs!4;k@daB4SibDkR*{8kiDw+(fIny7W)%BOXPZXD0Aga?W7_%RET00dPHsluwd+xgZ9WVhrZK7fO zyrW>nlFF$a+7>TT_FAMuVpVBKhfEzh8j3ESd0sag7l6J}ACS6l|&5q`QzYrs;R$W&)yjbf` z7bYXe{fZU1*-a5p(5ey~tnW+6a7;Ir^x%S|C3@yD{-d{-NxemByq=uy?wUNM7eX?F z@ZaQu<@5Q3ubmX6DH((*^p;D*$(}{A*M_a>qkT=4we}2`&=U=+O3`dPkL-Sw;#B?d z5OCB@c@FX!uguG%-P?ny#M1VROrCk;aNM=PzsL6R{w5XFdtkMib`Us;nIzD-SVTeT zo3blu592CX`y2qI^u&>mVOg;18x19{IVUWnSQRB+IiWx>*J*F6+S#G3q5F#P>5$CL zebk%4rhOo2xlH5I=vC;cN%t*>L1b=q9d=BceRi#y`lB`7gN>k;OsJWS6o-4N{4xvM z%Y%gg;Jj;yY#j|5FlLvx2GcQTa+Yo`in8?(FhRIXVsRagxkarjGvtdv!elCZ7>1^^ zTiN@l{9rs1>2~S9@}~Yn@TKKfi*|c`a`_b&d5uHSpgnF(qOTgUwVDVYiORb9Z_4x_ z9pOdaxb~wMjOkqxIqfck_I4{-9C>=LXSA}&9aoE~DHlCv?~C<0IP42 zKRRCF4cE=d)~8AhW#3nH#zEQUOMQAEvg2&?X`R;HoBKO}T=k9TWeJ+tA!NeugiKfA zQ$(+)iS$%VzZllD?Qav&!Ww?B){0)TlgCVnYMiwx$mYPUEmE_o{R2_ zDc1G3X;F~JsGs~Rl63T0mJ|7x;z`AW#JW1|!NO#xK$W>H!{256Qg+cdV?~icV%^9cou%`^A!1C_~Oyd<|yWrbDRiC#9;B z(!@YV^D8EomWO!wND`;Yx+&e%Qi;{c8AkBcFD0j~fxfn-n)05KB`Wlb{z6ZK9l|&| zYvh(STLt|}gLm}Ai>-K;(bq!Oo-uQzDRh!3n$=H#>1lo`7^_0$qomhew7LAGeGg5> zM&C3DdF%A`I8TmqFJ@*{31>F5)5f(GqBpk3;AHppD5>$c!urj5h;inbKK zZD6z%&_?lqd07NsN)Io@2;0r8#ztf``Zh??HHwD{0gW_uEXKXZ9K(UDwTC_FeHbfG zWb)mf!r7P7X9p>pHAB`-oaGzpo+mMpcAPzTLicxoRbJkc>R2A8heJ=$EEyuOU}hz? z&GcEWM+LJvzF=T5YJqn)DSb_SVC%EV90(pxE$EDwE14gPRZ5 zS)AL6D@S@A2|{3eag<1`JF-S2A9Brsc;PLP(iZ7D`i64@vAqaYfIUSA)zY2YZGF#KCaYY`6*aHWD7|$~Q=UJOG|LkcBS#=l*6in7X^VC4&Fjvv z;_!{gd?U1hCbBK*MLpoSl=g9|Tcl}HNKas%fZhIMYD(VOVcul|SN5rkMY#yssXGH3 zD@t@qF*Soxm#F~>>9uOcC{~me{+yHd$xs#4!JAhk&<=UFQuV>>)(am}-+fKy zMvrN)%z7r7zc=ruy^_}EYY=IFD6QU5o;bE+h1g3X^_9;Q86;xiGvtAp=aRGbme0+z zNVem0PtEHY_%5brgE+d;jcn5Lxw*L7O5N@mIi>uznYC4}bdclyq>7R4KFQ_q2d!By zUR!(X&#~8H0_}Rs77_FcT#(v7JsLtEN>dy~eA6b$MM&Nt@ydSFK(W9)?y70rk;p)s z@O6oD?+%*zcD`XM@9JpBW2j2Z?8%PP70OBd-n%>nacSlng=WoaHBHsUCUad(si9IX z(n$Ovj&EB^cBce!2ZpV&^Hf$U7$&iJR%OlML{?Le1x{wJCOnrZ&@T*I4~wqC3Z25~ z@Hz^Lc26D`G1SOu3Ka;t1bLK0SR~pgXE>!u zG~Pr}d`3zpo*wpMWyikF1|fd3^+&PvR8mwFJY`sjQ)9L!PtghNAM(;AD-C-3aj=m; z(Qk+2JHSjhh$n!u`8uNwU*fMp%+TH?kTSrm81Dg`K|eXZD?&x{Zd+t}OW-A4x|xZ07jmdE^^B-FIPY*0C!6 zGR*_xqS;QLFelItu~(ye#N~;aK_keZ%W=X09?{+FxAmU9)6-xI;g7!cVqrJO+Ppfi zE92#fttmNUtl#4KCT@geKgu56Og3U_Zz9^;P`8~CUP?QM|EObcKy~Q3_BM7ucP^Zc zrOAaVp4{tGT8eFT#@#Xv)aGdz10jHcZf%cCM^ncvPO0W?1xhfCiP5fmK%k(_xNbN| zV^50kUVe>$+-MmN7Dcbmm#frg0L+%?CDI#GL%adTQ8@KjBhy> zF7A3`C5@V%*^gN|QY??Kmt;JA!|L`t3#B#2K2(i@{jwlY^feKLHD2Dt>874G52ttX z&s<1_3uu)i%Z@!dM>hykGB$}l+=RWr{_^=RYi1SwSuyd&Hrv6Q{ke76eM=e-(<<{$ zCWA!8MYOsGg&t8x&>-=wgj)}8^O--R5JE(=wwOzjeKU5m?ULRPG|pPRbNq7gshI_& z;m<(|ldru=ZXk_vc7vfZrLxB`=*Ug5u_rSbLFl`=!+^sK`!*iI5YQVWb`|k()!q4~ zu$7ii4{HXEYTV6IN^nu)saQKH+(inLFKkS671QT$3&v=Z2Bt4peSE^bb#{qoWD`K4 zJ27L@Jw;hQ{q8|qVfTx*@}Ku^Pr6~K?6`Q04@2F?`cv0Zxozgk_5{O+8*ZhS=7X`= z=aM#ymt7*~0yUZ`y2CBE_FWRhYm>N0IwTWUhDdCBxqVI{0&1P^VRy7Fy=a zC|xAXOOvt?eSvO~6DAC~=(he`>4*L5+@Uo3u8*c~N3o|RdcFfz8oX0rUNj>tyR6Hx z*eaMuJIx6MF+SvVbfPaTW*>+RWkgzoYy3=1u%GPq+l7R8lAi7xNUvNA35nwO+JJDw z2-Kr((v6}79X1U@==*tLobASWvivQ5m*l?Jz&yhGLo$UIrpInPx3WAofts9h?Tc0R z_vnc_=5Z+W5|yVed|XS(Tj-UyPNSC|q#b_;%L%a zx8w`ApyY>ZgS%Dv@Td2aR8P{uoO5EkMx zG`w^#-;*^FdFVEw$Z7WIEYLin=%~mG9JONC2~)mM|LmViRxw^uYRy`bC}2!|&h*%_ z^pl&tK^o3GVJ;I>Oye+<$I&94Igcu@nsiF%Cf@~RO0RewE>2rz9d8Ys$-9;yN@+V$ z8RsdhhRbahYdnt}myEXGqx*W@mg-uvt$eT^xU~Nm^ID8?9s5q6A;OU+GF1vN0Q9e0 zz_;Ku*Qw}R=XxHdz_`#-_Z_f3rW))g5A;q-);=rXGmm1K|l_@*hv6isV{$bu+Rs>G(hva<^wYB3XNfAU%% z;7C`5@s%y@x*0`Cb0$0R3r9c~4(Z_!oD#O)O;g>)m`Ev#Z$S|m_dWB30Q>~$HjCGF zLE)9+d=4FoZu~mj1(Nk4$A<)T7_^FH`~Dk)yNx1N>&o|D^RY*~`Eq?1JwzoU;^KaB)(;m}r zheEonN!e~sTuXvlmmFi}V^C&m9q+@?2U|!ob5m;!v1#o`DOrw!uAOY-D0(#V00O19rP@#LZ{J9%7sV;aWy16uH^6+ zB}pDWcdO86dv{73Nx>mFUB=XbPEG223ym9@qYXLRrFpZY>9#_X4B`j2CcbO+5Bu%mN_^lG;Dk!N^Z^|DS2$L;jmh4)=oFk=Oko!AtNld8qU{p_2s?&b)gAFRQwtB zrh#4I<{kYQk8bc(BVPd$(}vAdn$O_<)YqD&(kr*-2bCYY31c2#zJ7*KQri0I$-6dQ z6&XUyp;t1Q3+V*&g>r7ZuE#AMX-!rGf)_lG3Nvy8Qn#fW{k17Wo<-&K?eLvj-sivB z?q7bVHRxDr5#vs@9PxSI9|;luXxxWmLj|r^i<)sRg)J=0X(avoLXueQ84g=A0~9GP zQD4D_Q5h#Ss`atttWi*#!2x|w8|Iv_m6v62WwMM+i3G?5Hnq}licdkyY}K2?&#K31 z62LKsxO%u^z!h$nxTVHK$mawLstBK0lPU$Ppnz9 z_d4=gQZh1)vs2UaT)e(*X*^o3)i2LvXv>ehIuJN3$(UINJ9h=dYWBjEuioolUXfSz zOJjEiG(MkJtYf-IS|)5|*wSDz;ICsdxnl7Glt37Z77MJJB2`N-i&3Cq`eYKOVu-hW zuCv=!H&S9%l%<$%^46DJXoCp(IMuGt(F_0JG_}ymE^l6kd+19uh*d`F?p&~wxC`Bw-Wt0rbKKopUH?_84SSCpAHc@Vd zjP~v`2$cW6JZe%G{R;yU8(M1XrOM{?`>SJ~s!CWl5r0g}LE+ugy3aT_!us+`@-sjk3!L zlr@P`)uA`F5y?-{RKwls)lJ2?6Yz712hTrow#+xm(Ws(;{uRN8^3JKf&c0S1Zq$WI6T`vosJzO9+ zL>=20*}aUI6_W9;=OaG7em++0FfPlQVOdawRhAaFJs?upYkY8RamO&R%nu~zmfpKUyc6yJ{PU9M@UlY9KC_?w|v2q=Us3+a|AdW2iI;d6zA z1xA#s?mdJ~$v#JR=#e>)l~;)qViM3X#|yVYxM4>X3-=}W6!WUQY|0B^0V06D*Bb+uaX^)@xolsa$1** zfm_I_Ok+pMru%s_rvu6z<%Dhc7CH@*IhGOF1xd4cUT!{-k;!N9rHV?{KG%LA>}j#{ z&a9=IdegK4S|p8h>#G>bv!bL1%=WRqxuU?bk6?*zet_Mj$_0cqs(;CPoWPFbOCaKF zcEg8QBiLe!W}g=4sdGWL4TuP!_8jMM#QhtGwOEB{%lqW!b1zPBjCS zMzjT%Yk0~9fY7FfVai$S!9ma_k&zDE>4CbxVGk7YNyB#M84l%~hi$!VHgTVkIZWGU^eNmfh zLrf>r`kNGh1nTcZ`gNv!Gg*~X6O&qNLQA}%N{8*$v+1vjxMI;rkEipu$;qNFHf!$9 ztk86FpwannQ1}#2-Kb|_>t3^Ns2t^D)P7iTa!2aNsnJOg~K#N~-KEj53z(l8YB^pae{@h>PLted@>{#{mm!kXG?vST-r^ zpv3p@n7b_uJ7kS>|FAvI;#@PpSnjo3F;qAr9aw}#?mZ(NUE{U8LecvjP-@^@XgIrl z)sb5$iL2#sZC9q}sQ3jO?%7e9`Y46KrJ+JlYr1NIITIYNSBGIQkV59vg%omyi%k%{ zL|-Lh({iTsF8VQkA%Nfjpus4ZX3og`W$$DG!ED+fJ>T$|wT`F6t-bK;MR4+ce$o-$ zFM>h~Vh#fiIt29j>)3B8UIx(@t;X^6EiTXo34U%#!`^9>RP)V7tx{2~vIp{g&1uCDo(3cE7v z>PVso#PlU0oU#oMw5!2%Up}K}qAuiBi#7><2ORPU-4Gr$^sW-x!dxOollI}2t@zjggqA`K!6CHjm;^U?f9 zwXEgRZw@2x-#^OXyb&5yOP>;O?CjTj#J`yee@n#1jii?Yv4kJ3gnv8LtMa8z zKb~!cWRJ?)YN>+VSzhyt+jpV`L>2$6-P{7^ap73d~$$LMs{yPBOLx3l{sj*^<^&^;?d$Ahh zo6t%u(D9%?xDBe;oijHJQ>%B~_Me7v9bE-A*dNS1s~?TM5`)oVY57o2w}p^~ zxV@A#<;l+?DU-f?_#NQ)Y3}S}jeGshF`>;`b*Xnt^`LO56agW9++jfW4CRvaxywrS zLsiTQ&F2SI{yv#An@%N^jBMFBSlQVC!lEv=Mj#7_1En#<6lyI(x8LxYjuHwMq0{71WLLD6fS5sL z++Yw@HzhTYn*~S!OeYGwC+s5VVr6RuaWJBEv9h$b7jzM!`^j7oUj6}Qqk|*Cz$St! z&!zrGf!9Rn{vM07vootR7po1-l#N3`K!A;%lZ}&;1&+aD?`rK}NsT_CtQk7iKmNHuh#V zwv?P4tQ?f|now)7jk7(2Fx$W5|Kg!&1BRNoJ~wiJ0O9XMv$Jq;uyFFLaR>iT}X-MXU(dCD_Qp=)WNU*S`P6g{zM3hyMT2-T#3; z!Jyyjv~`48{xl32#0Ig1SV62E?BTA$@x!8Um4ZQnCN?lDBL^VV%E%PLW^M~H6=wSf z`Zo^fFRlL|`OAi?5WAn1ziO6HxGnx~zDWL;d~i-b`}isB-<|v%&p#vhpD4oimv8*m z$G^DO@8+MA=P!-?h6zg8SlYng9smJy3A6nt@DJtu1DBPMcmcC9fxjjXv{#W9r*z_` zgo7w;VGt7t3}Ov}P})LZAc(Dlqmd;g)Y<`V3HT(1PdPBu-qzB{l@erWWN-gxPk(Uy z*RKBmHM0MSLEuwTQSm<;<5vuW{{;AZy2HQ6mbJEbFoJ7O_Bjwv%nF5q1wlsKU>;sx zBNh{GZXOmB2sbZ_5j%*T1!T-^#LdCZ1v28{{5gOBmHdYefA%k^41>ahqmkuv8<69V z8Syu7Fr2rMF()@ar+^6y*qE1#g_Gw8Z?Fj`3$F>77sAiS&dqJY@r(C=VDnEO|8I=@ zpYc-u2nH~Sy^SN>rG5o#unh<J zn};7_Y|KGN$@Vi4{C}qy8K^xxfV=+hvE(m5`aS9Y8qq)4{}VTZz*BGhXD|EF^2cod zQ5BT^5&ATtUg z9uoMODS!O`P4KU6zeyx)tl;6o-X6X(0u^*LDd9`|ulnDFe`5S5d+{U6!Ix#|E3&iqA zl>DiUe~14j&{Bartfk}6k#TVRLjM!`8&&&1qW%f}jrzjU$l3@dVPkCqHFbpjHT=I| zlz%O4zclb4@P0G-r#p3Pr~^>e8f5l2*}t{?rckvpad0+*LHbcJv4;TwIn-?szs%I_Nrh&B8!0`}u};b;0BB*Y)bk544{fsBg$!2?3rt=2!Y0Qg~LNpLu3}CC>q%q9LQ8BOxLH;7Mpm;JI3UwEk`c zAR!|lqM!oMzW<%c1s4eyo>FIMtBka_D70`=Em2**I1wXav3$<~7;>-b=FIMA9FttWiCqYN$&n(T`cnhmBs7*ostWJ~}Uo@l^&^ryTK5t*RDl6zg zV2w_F8_j*r+0w{+8|QnuzD`=v&&^qMJ|DJCWsC8eI2@nk3%JS^X#4icmeVcX_TyTooMz z&TmIOaUA4kne=F0^f{j5ESGeDmhT2GiuK(0=I=NA(6q?hc;@OC-kF;-QoQWJ)aDBG z@o2I)#aHX}L}dC_p;|ccw)yy+_Vr$NoVF~8&tRpXGxoA%R>OFkig8Sy&ZP;WN)Ewm%etqOn!-XSW`{(4wenw zCp+ct=~pt^^BGA!Kt|wvaV#Jqyf&jmxQbcSL$n~Z>DDMu6bQYMt6#+W;`Xw)tyMi) zm%GskrQkI)g!;6Xjcx`4POM^tJa@eG4qwEh_i9^;u9(_;nRyi|;??$J0Zvyl@ zzZ;BMJ!c40(k8Alwbqw{bT#{gy3_H@e!Hi|S6>LiA( zs2!zuCGx^!@#TofoK?4mUZQFI^DQjrFQ!aeIV#y{?rh?|R;AeLKAXqFJ+R9eS zqsYE)BXPBO`rb$!YBzB)EoH%{n#g}I z!A79Q+$zk{yJ#~FOATxfWT#QsM=x@qH&m@gHj+%Oe6LX>n7hOZzi4H#Ep4-Qx$kQ? z`_qLpb+jEU&8_C_;dnT^`UtW&72&pI74`=AJu!v;%x0c@q@xjZ?=!W}TRQKwlFIU}h>(#%v&-&h%2(TkqWz`EYWcK1)XzEcDUK-?wGy43Iy{ub~9C_n|nAQ zXz3|(^=zvzu5)IoD6oB`pMVL7th6=BcA7(3(#-NqQrL5HuPnX#(|DwABtrIw`SA31VG6 zv1(_8X7lH{@2jTv_NNUT%P6fzbFrUYq{{tnu^Nx1$xR_KjuzP!spMZgqrw-o$xo|w zN=(E}A}77Zv==xDe0yq@kD;ML7h~Jjb`N?@K`0=9F7%PLwIO@n$79g4L@g2(^{2wt zjH^sLfv(E{iRdRWvAUZI5(aF`9+uc`WndbRz)a7JLAut|P$HADo19>_@VBd`mh&`6 zP@Pm&+4Q!PKRVa`xq%`HGZk0l?pT(&bf7Dw(Je;(N=kyXgI6rT?$&w9eHNFhAF5bf zw)N?svo@#WHRtKCq_VEG$qE@gw$#$vMwGDMOlRcds@+FS`Y$@rjy6vyrmQ+A)1f-!@@3qqRk=TZmm5YdDHd_wgW# zqqr4}D9veZis=ki>n;{LqZetGdkYfmEpBw(r7A$yaLL<0t(3twwAR6r;v8mEIeTjqG_8Cy zB7vCVb{aWZ`w`mJCt1I2RxQqUOH_5dFQN<351#oh?x=5S9e!)({{Sxv)m`&?NuF~| z%;b7oR9U48yAD6xcuSP)%QK$JdWoN~tIwk4<4=f#)I(XDBxi_(pwX5nTcBT=A zhEFU`iAs*cq=s^vBt?bmAI3rQO;&<5e)Cjm=u;=4d#jiYOPnBi#2!x9NAIlDGL+Q1 z@f{~e%(?;3r1Sp(bOyE^4!jmgf!zN9ovlspGwV-vxmKnz zfktk-{Cx-GnwON0O0QRC1)ZWXSvDmbRUNuzo9dDZZB=YuAvWf1R*LpPa+}xjHM6?4 z)b4DwBba5V3 zOqsRRFTgQHa9D|h;|BPNQ~%auLHRTwc*zm`@&{3lz#-4PEW);e)}$_CTR`q6%57UoWR-drQeR7iHdEMGmp)t@ zqw8!BcFg=cLPt)2s4}av8&cO}3&Q3*y=X*AS@4)ItNrU21Cg_J+&woFV%n1gL|;GD zS)risZ#u769zL#QklsRXF1X(AxvbVVPs;t#&-v)9%hXWfZR_Hde9FAH`HpiEkkVn| zbR%~1zt7rq9A%3LeG>@`KdljamxgukTE#qfD~Ol@=R1kVLI$2!TY&dN6Qo+LW|5d( zF1a6o<($!(s#(x-r>*DFC8Vm#+;Bi$E#{B5sOH`c$WQy5>Vb1!pkZc4zE^$jd+b_| zpXfjpV_lGeGb>Gu8HZNG6QyLVz+6~Tnu*;4nZL-=Dc5lZ@s)VqQplt(M(;mBqpY!L z&_n(DE;@j+K$??^6%JO&U6|g0u+ryQ)T)1Yjb=q$QM$tH$*ujwrBSs#f?ZQPDo}Y8 z1<7}5NVttfZ&JHWtA=M`%nBu=NT$DkP3tJdb1BQp^yrvqL95$~-)8SITa0Hbi%$bF zXwUAZ2(bEC8kA}+qg)wAcvHrM2@Mr&>!n&i<;l4cZ?KnTA)}na&_UN>f{yvyCrhOI zg|!?f5z6i+SG*XrRcGRix%s@_?5a!jZUP4_*w3qy4Npud19O$p94Bv&31W53%2=_e zRw)8MLaUk2YK55sXSLTFCxkq%%gt{-C)HK@@}y^h73#U?9Zon=R?GuuS)rx&d>~;e z_3^Z=go+VqFt=F)U_(bXgF`n!Bc+j5V3O6GB2%Se+ZU$$pRCnuuPg8&moq6uA>q6gO=G>b6_o<+cS54SE_Y`8c*_T_~4_i!ZefoU)wH%r$v>x+q&5H)&z-Y>0~r?GF3R;E{z?@ z2sL$W8T^lWc@~K2pChmhovVw->+KwkHPCYQKCnhM-fYa>(GjQ|O0u>&4;QU2CumD) zyz>&XX;GukMSmrWhtQyQGgOg!HR|uu%V%n0dQ(9?gVe4r3y_hLz?j_!DdXM~@A(iS3kvD3V2ht)XQI}rzbsz zW1aKXF89{y{WadCMp9RoC&sQ0^u*g(1l1T_15SreG?D(cI5p!m-mFZ`OYkzOcRFvY zeBQOQ{Mk1#(YID~a$zT{hgjM+cK7N_Un6;vu8cc`A43t;+DUbc&oEQyY{^$jKda<` zShdH{+eMjOcBn`>9$UpCSAf!+KUP&DF$Z%y6lEZ(Me#d~KZ4K6`M6ZBsNCGVA>uuYJ!a^3-JT-Ki#Kp;GKq#Jx3f zRTKpAIpmAykrCCmt3SwaQ-M%h`hN2Q#$T) zd`n9gM6WAnhBrY-GP8OPO(7K;$cPqtklmZ=^K)2?#YPclsindAEL z?A&W-eum!aesOD|ls3B=y*Bw0H=ah`DG?gGI7fOpi_9*F7dus?0t+s<5VY~dt_xllqb^{&_0iH zS&(fUwibz305{`h6t|ux7dwfDLY{SIytlb2x-M(I2+qOW?dqa>+!58yLMychsg^H9 z%CM}OLpxH#KALD^5rs`7u%+ImSHG)$QzNsqKQJ4S(wYctaJGmkx3!sh#i|Ufrq?kbKLWit)WOvHYYMK|U zOHj)^>@s@OJw=rsCb&aajLvB?!ObMjvd1wLx%%xd9cU{85plDuCuwLBN`&7cF8F^Q zc&Q)a9g6dKR(&}u?c_7aQNpcd7+C9zQ7fbFWfNuY=ow6|v@qYxX_EM>{{Re?{9}2d z6fCI3%YQFp$vm%rCDg)ij{yT0P)+obnm=oGr6n%*W9X|&5djm@dr^uwm28H9sg1E) z3Y^3aSKLpHJTppz&%}EXEx3o(jy%{ZAzD=01Fb%ZPi#wHNOfR*Xx^Fy4`y&3vx|ku zNg2y*dbt9{t5xFUG^1XF&Z2VGew>x^&#V<|Yo=D`lDz*L%JX$^2j3%{&MqEBjAj?<~tj-PT~1B$1N2Fe(&?YO$&-H_xOj= zhq`R89nU^lz0dNSb)@j(d#=|IPLk)H4p9k6n

Hd!%Bsruv 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�$K}{l5 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Πqz8E5~hcAgO`mMWUt}eM-7+ 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 literal 0 HcmV?d00001 From 3d843e244090ac8ec504270491b711e728c57892 Mon Sep 17 00:00:00 2001 From: Yaman Umuroglu Date: Tue, 5 Oct 2021 15:32:40 +0200 Subject: [PATCH 10/49] ignore build/release dirs --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index ed83b46..d898ac7 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,5 @@ build/finn *.link_summary *.onnx *.pyc +output_*/ +release/ \ No newline at end of file From 2e09305db54304ecd6920fa9edc50794b0978447 Mon Sep 17 00:00:00 2001 From: Yaman Umuroglu Date: Tue, 5 Oct 2021 15:35:34 +0200 Subject: [PATCH 11/49] update finn to latest dev --- build/get-finn.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/get-finn.sh b/build/get-finn.sh index b178262..5ca3735 100755 --- a/build/get-finn.sh +++ b/build/get-finn.sh @@ -30,7 +30,7 @@ # URL for git repo to be cloned REPO_URL=https://github.com/Xilinx/finn # commit hash for repo -REPO_COMMIT=c8be5048a7f1647f7c72be7c7cd158e851d47a86 +REPO_COMMIT=df872f7c624592f16df1309866f7b33c627fa904 # directory (under the same folder as this script) to clone to REPO_DIR=finn From a2040a09248c8963cea7c4205b546cf19d217f14 Mon Sep 17 00:00:00 2001 From: Yaman Umuroglu Date: Tue, 5 Oct 2021 15:35:47 +0200 Subject: [PATCH 12/49] call absorb consecutive transposes for MNv1/RN50 --- build/mobilenet-v1/custom_steps.py | 1 + build/resnet50/custom_steps.py | 2 ++ 2 files changed, 3 insertions(+) diff --git a/build/mobilenet-v1/custom_steps.py b/build/mobilenet-v1/custom_steps.py index 9f30597..3c94e30 100644 --- a/build/mobilenet-v1/custom_steps.py +++ b/build/mobilenet-v1/custom_steps.py @@ -78,6 +78,7 @@ def step_mobilenet_streamline(model: ModelWrapper, cfg: DataflowBuildConfig): def step_mobilenet_lower_convs(model: ModelWrapper, cfg: DataflowBuildConfig): model = model.transform(LowerConvsToMatMul()) model = model.transform(absorb.AbsorbTransposeIntoMultiThreshold()) + model = model.transform(absorb.AbsorbConsecutiveTransposes()) model = model.transform(GiveUniqueNodeNames()) model = model.transform(GiveReadableTensorNames()) model = model.transform(InferDataTypes()) diff --git a/build/resnet50/custom_steps.py b/build/resnet50/custom_steps.py index 518554c..0b21e42 100644 --- a/build/resnet50/custom_steps.py +++ b/build/resnet50/custom_steps.py @@ -52,6 +52,7 @@ FactorOutMulSignMagnitude, Absorb1BitMulIntoMatMul, Absorb1BitMulIntoConv, + AbsorbConsecutiveTransposes, ) from finn.transformation.streamline.collapse_repeated import ( @@ -233,6 +234,7 @@ def step_resnet50_convert_to_hls(model: ModelWrapper, cfg: DataflowBuildConfig): to_hls.InferChannelwiseLinearLayer, to_hls.InferPool_Batch, AbsorbTransposeIntoMultiThreshold, + AbsorbConsecutiveTransposes, RoundAndClipThresholds, to_hls.InferQuantizedStreamingFCLayer, to_hls.InferThresholdingLayer, From 1017a59851fd14b3f18d6cef016bc15743dbf86e Mon Sep 17 00:00:00 2001 From: Felix Jentzsch Date: Mon, 11 Oct 2021 11:14:19 +0200 Subject: [PATCH 13/49] RadioML notebook: support for recent driver changes --- .../notebooks/3_radioml_with_cnns.ipynb | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/finn_examples/notebooks/3_radioml_with_cnns.ipynb b/finn_examples/notebooks/3_radioml_with_cnns.ipynb index 71d143e..60efcf4 100755 --- a/finn_examples/notebooks/3_radioml_with_cnns.ipynb +++ b/finn_examples/notebooks/3_radioml_with_cnns.ipynb @@ -109,8 +109,8 @@ } ], "source": [ - "print(\"Expected input shape and datatype: %s %s\" % (str(accel.ishape_normal), str(accel.idt)))\n", - "print(\"Expected output shape and datatype: %s %s\" % (str(accel.oshape_normal), str(accel.odt)))" + "print(\"Expected input shape and datatype: %s %s\" % (str(accel.ishape_normal(0)), str(accel.idt(0))))\n", + "print(\"Expected output shape and datatype: %s %s\" % (str(accel.oshape_normal(0)), str(accel.odt(0))))" ] }, { @@ -284,7 +284,7 @@ } ], "source": [ - "accel_in = quantize(data).reshape(accel.ishape_normal)\n", + "accel_in = quantize(data).reshape(accel.ishape_normal(0))\n", "print(\"Input buffer shape is %s and datatype is %s\" % (str(accel_in.shape), str(accel_in.dtype)))" ] }, @@ -360,9 +360,9 @@ "source": [ "batch_size = 1024\n", "accel.batch_size = batch_size\n", - "print(\"Accelerator buffer shapes are %s for input, %s for output\" % (str(accel.ishape_packed), str(accel.oshape_packed)) )\n", - "print(\"Accelerator buffer shapes are %s for input, %s for output\" % (str(accel.ishape_folded), str(accel.oshape_folded)) )\n", - "print(\"Accelerator buffer shapes are %s for input, %s for output\" % (str(accel.ishape_normal), str(accel.oshape_normal)) )" + "print(\"Accelerator buffer shapes are %s for input, %s for output\" % (str(accel.ishape_packed(0)), str(accel.oshape_packed(0))) )\n", + "print(\"Accelerator buffer shapes are %s for input, %s for output\" % (str(accel.ishape_folded(0)), str(accel.oshape_folded(0))) )\n", + "print(\"Accelerator buffer shapes are %s for input, %s for output\" % (str(accel.ishape_normal(0)), str(accel.oshape_normal(0))) )" ] }, { @@ -647,7 +647,7 @@ " batch_indices = test_indices[i_frame:i_frame+batch_size]\n", " data, mod, snr = data_h5[batch_indices], label_mod[batch_indices], label_snr[batch_indices]\n", "\n", - " ibuf = quantize(data).reshape(accel.ishape_normal)\n", + " ibuf = quantize(data).reshape(accel.ishape_normal(0))\n", " obuf = accel.execute(ibuf)\n", "\n", " pred = obuf.reshape(batch_size).astype(int)\n", @@ -725,7 +725,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -739,7 +739,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.6.5" + "version": "3.8.5" } }, "nbformat": 4, From 1f7aed26a92819e8584d5392195f8a9f75ebc0cd Mon Sep 17 00:00:00 2001 From: Yaman Umuroglu Date: Wed, 20 Oct 2021 09:42:43 +0200 Subject: [PATCH 14/49] Driver fixes for latest FINN dev --- finn_examples/driver.py | 4 ++-- finn_examples/models.py | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/finn_examples/driver.py b/finn_examples/driver.py index 4dd5a08..d4e69e7 100644 --- a/finn_examples/driver.py +++ b/finn_examples/driver.py @@ -418,9 +418,9 @@ def throughput_test(self): # also benchmark driver-related overheads input_npy = gen_finn_dt_tensor(self.idt, self.ishape_normal) # provide as int8/uint8 to support fast packing path where possible - if self.idt == DataType.UINT8: + if self.idt == DataType["UINT8"]: input_npy = input_npy.astype(np.uint8) - elif self.idt == DataType.INT8: + elif self.idt == DataType["INT8"]: input_npy = input_npy.astype(np.int8) start = time.time() ibuf_folded = self.fold_input(input_npy) diff --git a/finn_examples/models.py b/finn_examples/models.py index 1ec9aaf..af042b8 100644 --- a/finn_examples/models.py +++ b/finn_examples/models.py @@ -36,8 +36,8 @@ from finn_examples.driver import FINNExampleOverlay _mnist_fc_io_shape_dict = { - "idt": DataType.UINT8, - "odt": DataType.UINT8, + "idt": DataType["UINT8"], + "odt": DataType["UINT8"], "ishape_normal": (1, 784), "oshape_normal": (1, 1), "ishape_folded": (1, 1, 784), @@ -47,8 +47,8 @@ } _cifar10_cnv_io_shape_dict = { - "idt": DataType.UINT8, - "odt": DataType.UINT8, + "idt": DataType["UINT8"], + "odt": DataType["UINT8"], "ishape_normal": (1, 32, 32, 3), "oshape_normal": (1, 1), "ishape_folded": (1, 1, 32, 32, 1, 3), @@ -58,8 +58,8 @@ } _bincop_cnv_io_shape_dict = { - "idt": DataType.UINT8, - "odt": DataType.UINT8, + "idt": DataType["UINT8"], + "odt": DataType["UINT8"], "ishape_normal": (1, 72, 72, 3), "oshape_normal": (1, 1), "ishape_folded": (1, 1, 72, 72, 1, 3), @@ -69,8 +69,8 @@ } _imagenet_top5inds_io_shape_dict = { - "idt": DataType.UINT8, - "odt": DataType.UINT16, + "idt": DataType["UINT8"], + "odt": DataType["UINT16"], "ishape_normal": (1, 224, 224, 3), "oshape_normal": (1, 1, 1, 5), "ishape_folded": (1, 224, 224, 1, 3), @@ -82,8 +82,8 @@ # resnet50 uses a different io_shape_dict due to # external weights for last layer _imagenet_resnet50_top5inds_io_shape_dict = { - "idt" : DataType.UINT8, - "odt" : DataType.UINT16, + "idt" : DataType["UINT8"], + "odt" : DataType["UINT16"], "ishape_normal" : (1, 224, 224, 3), "oshape_normal" : (1, 5), "ishape_folded" : (1, 224, 224, 3), From 6da3618d989b9a62bdbcb390f187e3cfa4abdef4 Mon Sep 17 00:00:00 2001 From: Yaman Umuroglu Date: Wed, 20 Oct 2021 09:53:41 +0200 Subject: [PATCH 15/49] update to latest FINN dev branch --- build/get-finn.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/get-finn.sh b/build/get-finn.sh index 5ca3735..27ab15f 100755 --- a/build/get-finn.sh +++ b/build/get-finn.sh @@ -30,7 +30,7 @@ # URL for git repo to be cloned REPO_URL=https://github.com/Xilinx/finn # commit hash for repo -REPO_COMMIT=df872f7c624592f16df1309866f7b33c627fa904 +REPO_COMMIT=beebdd77a29b84ab3b741a1a0544438191822d71 # directory (under the same folder as this script) to clone to REPO_DIR=finn From 4ec10cba0741d3073e5ed7481b60b712ba16a876 Mon Sep 17 00:00:00 2001 From: Yaman Umuroglu Date: Wed, 20 Oct 2021 09:54:02 +0200 Subject: [PATCH 16/49] fixes to RN50 build for latest dev, still broken --- build/resnet50/custom_steps.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build/resnet50/custom_steps.py b/build/resnet50/custom_steps.py index 0b21e42..c3baabb 100644 --- a/build/resnet50/custom_steps.py +++ b/build/resnet50/custom_steps.py @@ -179,6 +179,7 @@ def step_resnet50_streamline_linear(model: ModelWrapper, cfg: DataflowBuildConfi AbsorbMulIntoMultiThreshold(), Absorb1BitMulIntoMatMul(), Absorb1BitMulIntoConv(), + RoundAndClipThresholds(), ] for trn in streamline_transformations: model = model.transform(trn) @@ -214,7 +215,7 @@ def step_resnet50_streamline(model: ModelWrapper, cfg: DataflowBuildConfig): def step_resnet50_convert_to_hls(model: ModelWrapper, cfg: DataflowBuildConfig): - model.set_tensor_datatype(model.graph.input[0].name, DataType.UINT8) + model.set_tensor_datatype(model.graph.input[0].name, DataType["UINT8"]) model = model.transform(InferDataLayouts()) try: @@ -229,16 +230,15 @@ def step_resnet50_convert_to_hls(model: ModelWrapper, cfg: DataflowBuildConfig): model = model.transform(SortGraph()) to_hls_transformations = [ - to_hls.InferAddStreamsLayer, LowerConvsToMatMul, - to_hls.InferChannelwiseLinearLayer, - to_hls.InferPool_Batch, + AbsorbConsecutiveTransposes, AbsorbTransposeIntoMultiThreshold, AbsorbConsecutiveTransposes, - RoundAndClipThresholds, + to_hls.InferAddStreamsLayer, + to_hls.InferChannelwiseLinearLayer, + to_hls.InferPool_Batch, to_hls.InferQuantizedStreamingFCLayer, to_hls.InferThresholdingLayer, - AbsorbConsecutiveTransposes, to_hls.InferConvInpGen, to_hls.InferDuplicateStreamsLayer, to_hls.InferLabelSelectLayer, From 76158d282bad1b58f18746230d11a270232724be Mon Sep 17 00:00:00 2001 From: Felix Jentzsch Date: Fri, 29 Oct 2021 14:14:39 +0200 Subject: [PATCH 17/49] Update to w4a4_small model at 250MHz --- build/vgg10/build.py | 4 +- .../folding_config/ZCU104_folding_config.json | 52 +++++++++---------- build/vgg10/models/download_vgg10.sh | 4 +- 3 files changed, 30 insertions(+), 30 deletions(-) diff --git a/build/vgg10/build.py b/build/vgg10/build.py index 01dbd41..623804e 100755 --- a/build/vgg10/build.py +++ b/build/vgg10/build.py @@ -35,7 +35,7 @@ # custom steps from custom_steps import step_pre_streamline, step_convert_final_layers -model_name = "radioml_w4a3_tidy" +model_name = "radioml_w4a4_small_tidy" # which platforms to build the networks for zynq_platforms = ["ZCU104"] @@ -55,7 +55,7 @@ def platform_to_shell(platform): # select target clock frequency def select_clk_period(platform): - return 5.0 + return 4.0 # assemble build flow from custom and pre-existing steps diff --git a/build/vgg10/folding_config/ZCU104_folding_config.json b/build/vgg10/folding_config/ZCU104_folding_config.json index 77c8a1b..94cd96c 100755 --- a/build/vgg10/folding_config/ZCU104_folding_config.json +++ b/build/vgg10/folding_config/ZCU104_folding_config.json @@ -1,14 +1,14 @@ { "Defaults": {}, "FMPadding_Batch_0": { - "SIMD": 1 + "SIMD": 2 }, "ConvolutionInputGenerator1D_0": { "SIMD": 2, "ram_style": "auto" }, "StreamingFCLayer_Batch_0": { - "PE": 16, + "PE": 32, "SIMD": 6, "ram_style": "auto", "mem_mode": "const", @@ -20,12 +20,12 @@ "SIMD": 16 }, "ConvolutionInputGenerator1D_1": { - "SIMD": 64, + "SIMD": 32, "ram_style": "auto" }, "StreamingFCLayer_Batch_1": { - "PE": 32, - "SIMD": 64, + "PE": 16, + "SIMD": 96, "ram_style": "auto", "mem_mode": "const", "runtime_writeable_weights": 0 @@ -36,12 +36,12 @@ "SIMD": 8 }, "ConvolutionInputGenerator1D_2": { - "SIMD": 64, + "SIMD": 32, "ram_style": "auto" }, "StreamingFCLayer_Batch_2": { - "PE": 16, - "SIMD": 64, + "PE": 8, + "SIMD": 96, "ram_style": "auto", "mem_mode": "const", "runtime_writeable_weights": 0 @@ -49,15 +49,15 @@ "StreamingMaxPool_Batch_2": { }, "FMPadding_Batch_3": { - "SIMD": 4 + "SIMD": 8 }, "ConvolutionInputGenerator1D_3": { - "SIMD": 64, + "SIMD": 32, "ram_style": "auto" }, "StreamingFCLayer_Batch_3": { - "PE": 8, - "SIMD": 64, + "PE": 4, + "SIMD": 96, "ram_style": "auto", "mem_mode": "const", "runtime_writeable_weights": 0 @@ -65,15 +65,15 @@ "StreamingMaxPool_Batch_3": { }, "FMPadding_Batch_4": { - "SIMD": 2 + "SIMD": 4 }, "ConvolutionInputGenerator1D_4": { - "SIMD": 64, + "SIMD": 32, "ram_style": "auto" }, "StreamingFCLayer_Batch_4": { - "PE": 4, - "SIMD": 64, + "PE": 2, + "SIMD": 96, "ram_style": "auto", "mem_mode": "const", "runtime_writeable_weights": 0 @@ -81,15 +81,15 @@ "StreamingMaxPool_Batch_4": { }, "FMPadding_Batch_5": { - "SIMD": 1 + "SIMD": 2 }, "ConvolutionInputGenerator1D_5": { - "SIMD": 64, + "SIMD": 32, "ram_style": "auto" }, "StreamingFCLayer_Batch_5": { - "PE": 2, - "SIMD": 64, + "PE": 1, + "SIMD": 96, "ram_style": "auto", "mem_mode": "const", "runtime_writeable_weights": 0 @@ -100,12 +100,12 @@ "SIMD": 1 }, "ConvolutionInputGenerator1D_6": { - "SIMD": 64, + "SIMD": 32, "ram_style": "auto" }, "StreamingFCLayer_Batch_6": { "PE": 1, - "SIMD": 64, + "SIMD": 96, "ram_style": "auto", "mem_mode": "const", "runtime_writeable_weights": 0 @@ -113,22 +113,22 @@ "StreamingMaxPool_Batch_6": { }, "StreamingFCLayer_Batch_7": { - "PE": 1, - "SIMD": 16, + "PE": 2, + "SIMD": 32, "ram_style": "auto", "mem_mode": "const", "runtime_writeable_weights": 0 }, "StreamingFCLayer_Batch_8": { "PE": 1, - "SIMD": 4, + "SIMD": 32, "ram_style": "auto", "mem_mode": "const", "runtime_writeable_weights": 0 }, "StreamingFCLayer_Batch_9": { "PE": 1, - "SIMD": 1, + "SIMD": 8, "ram_style": "auto", "mem_mode": "const", "runtime_writeable_weights": 0 diff --git a/build/vgg10/models/download_vgg10.sh b/build/vgg10/models/download_vgg10.sh index fe54a6c..710e608 100755 --- a/build/vgg10/models/download_vgg10.sh +++ b/build/vgg10/models/download_vgg10.sh @@ -1,4 +1,4 @@ #!/bin/sh -wget https://github.com/Xilinx/finn-examples/releases/download/v0.0.1a/onnx-models-mobilenetv1.zip -unzip onnx-models-mobilenetv1.zip +wget https://github.com/Xilinx/finn-examples/releases/download/*ToDo*/onnx-models-vgg10.zip +unzip onnx-models-vgg10.zip From 21af2e02272b537554a43f8353961c7bc399cc49 Mon Sep 17 00:00:00 2001 From: Felix Jentzsch Date: Fri, 29 Oct 2021 15:14:43 +0200 Subject: [PATCH 18/49] Update readme, notebook --- build/vgg10/README.md | 9 +- .../notebooks/3_radioml_with_cnns.ipynb | 747 ------------------ .../notebooks/4_radioml_with_cnns.ipynb | 489 ++++++++++++ 3 files changed, 493 insertions(+), 752 deletions(-) delete mode 100755 finn_examples/notebooks/3_radioml_with_cnns.ipynb create mode 100755 finn_examples/notebooks/4_radioml_with_cnns.ipynb diff --git a/build/vgg10/README.md b/build/vgg10/README.md index 7fdcf49..9ce5bcd 100755 --- a/build/vgg10/README.md +++ b/build/vgg10/README.md @@ -3,18 +3,17 @@ This 1-dimensional CNN was [introduced](https://arxiv.org/pdf/1712.04578.pdf) by DeepSig alongside their RadioML 2018 dataset for RF modulation classification. It consists of 7 1D convolution + maxpooling layers, followed by 2 hidden dense layers and the final dense classification layer. ReLU activations and Batchnorm are applied throughout the network. The input is a frame of 1024 I/Q samples (i.e. shape [1024,2]), the classifier distinguishes 24 classes (i.e. modulation types). -Here, we use a reduced-precision implementation trained on [RadioML 2018.01A](https://www.deepsig.ai/datasets) with Brevitas. The weights are quantized to 4-bit and the activations to 3-bit, except for the first layer which uses 4-bit activations. The pre-trained model reaches 58.4% overall accuracy and 90.9% at the highest SNR (30 dB). +Here, we use a reduced-precision implementation trained on [RadioML 2018.01A](https://www.deepsig.ai/datasets) with Brevitas. The weights and activations are quantized to 4-bit. The number of filters in the convolution layers has been reduced from 64 to 32. The pre-trained model reaches 55.9% overall accuracy and 87.9% at the highest SNR (30 dB). At 250MHz, the accelerator reaches ~230k frames/s (236M samples/s) with the supplied folding configuration. ## Build bitfiles for VGG10 -Due to the 1-dimensional topology in VGG10, -we use a specialized build script that adds a few custom build steps to the standard steps in FINN. -**We currently provide bitstreams and the corresponding build configuration only for the ZCU104, but plan to extend to other boards shortly.** +Due to the 1-dimensional topology in VGG10 we use a specialized build script that adds a few custom build steps to the standard steps in FINN. +**We currently provide bitstreams and the corresponding folding configuration only for the ZCU104, but plan to extend to other boards in the future.** 0. Ensure you have performed the *Setup* steps in the top-level README for setting up the FINN requirements and environment variables. 1. Download the pretrained VGG10 ONNX model from the releases page, and extract -the zipfile under `vgg10/models`. You should have e.g. `vgg10/models∕radioml-w4a3_tidy.onnx` as a result. +the zipfile under `vgg10/models`. You should have e.g. `vgg10/models/radioml_w4a4_small_tidy.onnx` as a result. You can use the provided `vgg10/models/download_vgg10.sh` script for this. 2. Launch the build as follows: diff --git a/finn_examples/notebooks/3_radioml_with_cnns.ipynb b/finn_examples/notebooks/3_radioml_with_cnns.ipynb deleted file mode 100755 index 60efcf4..0000000 --- a/finn_examples/notebooks/3_radioml_with_cnns.ipynb +++ /dev/null @@ -1,747 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Initialize the accelerator" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "# remember to install the following dependencies\n", - "#! apt-get install libhdf5-dev -y\n", - "#! pip install versioned-hdf5" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "application/javascript": [ - "\n", - "try {\n", - "require(['notebook/js/codecell'], function(codecell) {\n", - " codecell.CodeCell.options_default.highlight_modes[\n", - " 'magic_text/x-csrc'] = {'reg':[/^%%microblaze/]};\n", - " Jupyter.notebook.events.one('kernel_ready.Kernel', function(){\n", - " Jupyter.notebook.get_cells().map(function(cell){\n", - " if (cell.cell_type == 'code'){ cell.auto_highlight(); } }) ;\n", - " });\n", - "});\n", - "} catch (e) {};\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/javascript": [ - "\n", - "try {\n", - "require(['notebook/js/codecell'], function(codecell) {\n", - " codecell.CodeCell.options_default.highlight_modes[\n", - " 'magic_text/x-csrc'] = {'reg':[/^%%pybind11/]};\n", - " Jupyter.notebook.events.one('kernel_ready.Kernel', function(){\n", - " Jupyter.notebook.get_cells().map(function(cell){\n", - " if (cell.cell_type == 'code'){ cell.auto_highlight(); } }) ;\n", - " });\n", - "});\n", - "} catch (e) {};\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "['_radioml_io_shape_dict', 'vgg10_w2a2_radioml']\n" - ] - } - ], - "source": [ - "from finn_examples import models\n", - "print(list(filter(lambda x: \"radioml\" in x, dir(models))))" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/usr/local/lib/python3.6/dist-packages/pynq/ps.py:464: UserWarning: Setting frequency to the closest possible value 187.49812MHz.\n", - " round(freq_high / q0, 5)))\n" - ] - } - ], - "source": [ - "accel = models.vgg10_w4a3_radioml()\n", - "#some systems might require a manual platform setting:\n", - "#accel = models.vgg10_w4a3_radioml(\"ZCU102\")" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Expected input shape and datatype: (1, 1024, 1, 2) DataType.INT8\n", - "Expected output shape and datatype: (1, 1) DataType.UINT8\n" - ] - } - ], - "source": [ - "print(\"Expected input shape and datatype: %s %s\" % (str(accel.ishape_normal(0)), str(accel.idt(0))))\n", - "print(\"Expected output shape and datatype: %s %s\" % (str(accel.oshape_normal(0)), str(accel.odt(0))))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Load RadioML 2018 dataset" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "/mnt/radioml_2018\n" - ] - } - ], - "source": [ - "import numpy as np\n", - "import math\n", - "import pickle\n", - "import os\n", - "import h5py\n", - "\n", - "dataset_dir = \"/mnt/radioml_2018\"\n", - "print(dataset_dir)" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "h5_file = h5py.File(dataset_dir + \"/GOLD_XYZ_OSC.0001_1024.hdf5\",'r')\n", - "data_h5 = h5_file['X']\n", - "label_mod = np.argmax(h5_file['Y'], axis=1) # comes in one-hot encoding\n", - "label_snr = h5_file['Z'][:,0]\n", - "\n", - "# assemble list of test set indices\n", - "# do not pre-load large dataset into memory\n", - "np.random.seed(2018)\n", - "test_indices = []\n", - "for mod in range(0, 24): #all modulations (0 to 23)\n", - " for snr_idx in range(0, 26): #all SNRs (0 to 25 = -20dB to +30dB)\n", - " start_idx = 26*4096*mod + 4096*snr_idx\n", - " indices_subclass = list(range(start_idx, start_idx+4096))\n", - "\n", - " split = int(np.ceil(0.1 * 4096)) #90%/10% split\n", - " np.random.shuffle(indices_subclass)\n", - " train_indices_subclass, val_indices_subclass = indices_subclass[split:], indices_subclass[:split]\n", - "\n", - " if snr_idx >= 0: #select which SNRs to test on\n", - " test_indices.extend(val_indices_subclass)\n", - "\n", - "test_indices = sorted(test_indices)\n", - "\n", - "# note: labels given in the \"classes.txt\" file are not in the correct order (https://github.com/radioML/dataset/issues/25)\n", - "mod_classes = ['OOK','4ASK','8ASK','BPSK','QPSK','8PSK','16PSK','32PSK',\n", - "'16APSK','32APSK','64APSK','128APSK','16QAM','32QAM','64QAM','128QAM','256QAM',\n", - "'AM-SSB-WC','AM-SSB-SC','AM-DSB-WC','AM-DSB-SC','FM','GMSK','OQPSK']\n", - "snr_classes = np.arange(-20., 32., 2) # -20dB to 30dB" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "(2555904, 1024, 2)\n", - "(2555904,)\n", - "(2555904,)\n", - "255840\n" - ] - } - ], - "source": [ - "print(data_h5.shape)\n", - "print(label_mod.shape)\n", - "print(label_snr.shape)\n", - "print(len(test_indices))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Inspect a single frame" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Modulation: 16QAM, SNR: 30.0 dB\n" - ] - } - ], - "source": [ - "from matplotlib import pyplot as plt\n", - "\n", - "# Inspect a frame\n", - "mod = 12 # 0 to 23\n", - "snr_idx = 25 # 0 to 25 = -20dB to +30dB\n", - "sample = 123 # 0 to 4095\n", - "#-----------------------#\n", - "idx = 26*4096*mod + 4096*snr_idx + sample\n", - "data, mod, snr = data_h5[idx], label_mod[idx], label_snr[idx]\n", - "plt.figure()\n", - "plt.plot(data)\n", - "print(\"Modulation: %s, SNR: %.1f dB\" % (mod_classes[mod], snr))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Input quantization\n", - "Quantize input data on-the-fly in software before feeding it to the accelerator. Use the uniform quantization range on which the model was trained." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "def quantize(data):\n", - " quant_min = -1.7981509\n", - " quant_max = 1.7840475\n", - " quant_range = quant_max - quant_min\n", - " data_quant = (data - quant_min) / quant_range\n", - " data_quant = np.round(data_quant * 256) - 128\n", - " data_quant = np.clip(data_quant, -128, 127)\n", - " data_quant = data_quant.astype(np.int8)\n", - " return data_quant" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Classify a single frame" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Input buffer shape is (1, 1024, 1, 2) and datatype is int8\n" - ] - } - ], - "source": [ - "accel_in = quantize(data).reshape(accel.ishape_normal(0))\n", - "print(\"Input buffer shape is %s and datatype is %s\" % (str(accel_in.shape), str(accel_in.dtype)))" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "accel_out = accel.execute(accel_in)\n", - "#accel_out = post_process(accel_out)" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Result: [[12.]]\n", - "Top-1 class predicted by the accelerator: 16QAM\n" - ] - } - ], - "source": [ - "print(\"Result: \" + str(accel_out))\n", - "print(\"Top-1 class predicted by the accelerator: \" + mod_classes[int(accel_out)])" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1000 loops, best of 3: 1.01 ms per loop\n" - ] - } - ], - "source": [ - "%%timeit\n", - "accel_out = accel.execute(accel_in)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Validate accuracy on entire test set" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Accelerator buffer shapes are (1024, 1024, 1, 2, 1) for input, (1024, 1, 1) for output\n", - "Accelerator buffer shapes are (1024, 1024, 1, 2, 1) for input, (1024, 1, 1) for output\n", - "Accelerator buffer shapes are (1024, 1024, 1, 2) for input, (1024, 1) for output\n" - ] - } - ], - "source": [ - "batch_size = 1024\n", - "accel.batch_size = batch_size\n", - "print(\"Accelerator buffer shapes are %s for input, %s for output\" % (str(accel.ishape_packed(0)), str(accel.oshape_packed(0))) )\n", - "print(\"Accelerator buffer shapes are %s for input, %s for output\" % (str(accel.ishape_folded(0)), str(accel.oshape_folded(0))) )\n", - "print(\"Accelerator buffer shapes are %s for input, %s for output\" % (str(accel.ishape_normal(0)), str(accel.oshape_normal(0))) )" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "batch 0 : total OK 5 NOK 1019\n", - "batch 1 : total OK 51 NOK 1997\n", - "batch 2 : total OK 520 NOK 2552\n", - "batch 3 : total OK 1370 NOK 2726\n", - "batch 4 : total OK 2391 NOK 2729\n", - "batch 5 : total OK 3415 NOK 2729\n", - "batch 6 : total OK 4439 NOK 2729\n", - "batch 7 : total OK 5463 NOK 2729\n", - "batch 8 : total OK 6487 NOK 2729\n", - "batch 9 : total OK 7511 NOK 2729\n", - "batch 10 : total OK 7931 NOK 3333\n", - "batch 11 : total OK 7934 NOK 4354\n", - "batch 12 : total OK 7993 NOK 5319\n", - "batch 13 : total OK 8360 NOK 5976\n", - "batch 14 : total OK 9056 NOK 6304\n", - "batch 15 : total OK 9940 NOK 6444\n", - "batch 16 : total OK 10957 NOK 6451\n", - "batch 17 : total OK 11977 NOK 6455\n", - "batch 18 : total OK 13000 NOK 6456\n", - "batch 19 : total OK 14020 NOK 6460\n", - "batch 20 : total OK 14864 NOK 6640\n", - "batch 21 : total OK 14923 NOK 7605\n", - "batch 22 : total OK 15078 NOK 8474\n", - "batch 23 : total OK 15374 NOK 9202\n", - "batch 24 : total OK 16120 NOK 9480\n", - "batch 25 : total OK 17031 NOK 9593\n", - "batch 26 : total OK 18028 NOK 9620\n", - "batch 27 : total OK 19051 NOK 9621\n", - "batch 28 : total OK 20068 NOK 9628\n", - "batch 29 : total OK 21087 NOK 9633\n", - "batch 30 : total OK 22109 NOK 9635\n", - "batch 31 : total OK 22403 NOK 10365\n", - "batch 32 : total OK 22488 NOK 11304\n", - "batch 33 : total OK 22743 NOK 12073\n", - "batch 34 : total OK 23616 NOK 12224\n", - "batch 35 : total OK 24640 NOK 12224\n", - "batch 36 : total OK 25664 NOK 12224\n", - "batch 37 : total OK 26688 NOK 12224\n", - "batch 38 : total OK 27712 NOK 12224\n", - "batch 39 : total OK 28736 NOK 12224\n", - "batch 40 : total OK 29760 NOK 12224\n", - "batch 41 : total OK 30416 NOK 12592\n", - "batch 42 : total OK 30418 NOK 13614\n", - "batch 43 : total OK 30419 NOK 14637\n", - "batch 44 : total OK 30436 NOK 15644\n", - "batch 45 : total OK 31002 NOK 16102\n", - "batch 46 : total OK 32022 NOK 16106\n", - "batch 47 : total OK 33046 NOK 16106\n", - "batch 48 : total OK 34070 NOK 16106\n", - "batch 49 : total OK 35094 NOK 16106\n", - "batch 50 : total OK 36118 NOK 16106\n", - "batch 51 : total OK 37142 NOK 16106\n", - "batch 52 : total OK 37212 NOK 17060\n", - "batch 53 : total OK 37229 NOK 18067\n", - "batch 54 : total OK 37247 NOK 19073\n", - "batch 55 : total OK 37257 NOK 20087\n", - "batch 56 : total OK 37769 NOK 20599\n", - "batch 57 : total OK 38779 NOK 20613\n", - "batch 58 : total OK 39803 NOK 20613\n", - "batch 59 : total OK 40827 NOK 20613\n", - "batch 60 : total OK 41851 NOK 20613\n", - "batch 61 : total OK 42875 NOK 20613\n", - "batch 62 : total OK 43346 NOK 21166\n", - "batch 63 : total OK 43346 NOK 22190\n", - "batch 64 : total OK 43346 NOK 23214\n", - "batch 65 : total OK 43347 NOK 24237\n", - "batch 66 : total OK 43504 NOK 25104\n", - "batch 67 : total OK 44217 NOK 25415\n", - "batch 68 : total OK 45216 NOK 25440\n", - "batch 69 : total OK 46238 NOK 25442\n", - "batch 70 : total OK 47261 NOK 25443\n", - "batch 71 : total OK 48283 NOK 25445\n", - "batch 72 : total OK 49216 NOK 25536\n", - "batch 73 : total OK 49596 NOK 26180\n", - "batch 74 : total OK 49976 NOK 26824\n", - "batch 75 : total OK 50393 NOK 27431\n", - "batch 76 : total OK 50777 NOK 28071\n", - "batch 77 : total OK 51158 NOK 28714\n", - "batch 78 : total OK 51986 NOK 28910\n", - "batch 79 : total OK 52990 NOK 28930\n", - "batch 80 : total OK 54008 NOK 28936\n", - "batch 81 : total OK 55024 NOK 28944\n", - "batch 82 : total OK 56037 NOK 28955\n", - "batch 83 : total OK 56324 NOK 29692\n", - "batch 84 : total OK 56324 NOK 30716\n", - "batch 85 : total OK 56325 NOK 31739\n", - "batch 86 : total OK 56360 NOK 32728\n", - "batch 87 : total OK 56904 NOK 33208\n", - "batch 88 : total OK 57886 NOK 33250\n", - "batch 89 : total OK 58910 NOK 33250\n", - "batch 90 : total OK 59934 NOK 33250\n", - "batch 91 : total OK 60958 NOK 33250\n", - "batch 92 : total OK 61982 NOK 33250\n", - "batch 93 : total OK 62688 NOK 33568\n", - "batch 94 : total OK 62688 NOK 34592\n", - "batch 95 : total OK 62688 NOK 35616\n", - "batch 96 : total OK 62703 NOK 36625\n", - "batch 97 : total OK 63109 NOK 37243\n", - "batch 98 : total OK 63998 NOK 37378\n", - "batch 99 : total OK 65016 NOK 37384\n", - "batch 100 : total OK 66039 NOK 37385\n", - "batch 101 : total OK 67063 NOK 37385\n", - "batch 102 : total OK 68087 NOK 37385\n", - "batch 103 : total OK 69110 NOK 37386\n", - "batch 104 : total OK 69215 NOK 38305\n", - "batch 105 : total OK 69215 NOK 39329\n", - "batch 106 : total OK 69215 NOK 40353\n", - "batch 107 : total OK 69223 NOK 41369\n", - "batch 108 : total OK 69374 NOK 42242\n", - "batch 109 : total OK 69913 NOK 42727\n", - "batch 110 : total OK 70805 NOK 42859\n", - "batch 111 : total OK 71733 NOK 42955\n", - "batch 112 : total OK 72665 NOK 43047\n", - "batch 113 : total OK 73600 NOK 43136\n", - "batch 114 : total OK 74073 NOK 43687\n", - "batch 115 : total OK 74073 NOK 44711\n", - "batch 116 : total OK 74074 NOK 45734\n", - "batch 117 : total OK 74075 NOK 46757\n", - "batch 118 : total OK 74162 NOK 47694\n", - "batch 119 : total OK 74685 NOK 48195\n", - "batch 120 : total OK 75623 NOK 48281\n", - "batch 121 : total OK 76612 NOK 48316\n", - "batch 122 : total OK 77615 NOK 48337\n", - "batch 123 : total OK 78608 NOK 48368\n", - "batch 124 : total OK 79521 NOK 48479\n", - "batch 125 : total OK 79528 NOK 49496\n", - "batch 126 : total OK 79538 NOK 50510\n", - "batch 127 : total OK 79553 NOK 51519\n", - "batch 128 : total OK 79631 NOK 52465\n", - "batch 129 : total OK 80030 NOK 53090\n", - "batch 130 : total OK 80982 NOK 53162\n", - "batch 131 : total OK 82005 NOK 53163\n", - "batch 132 : total OK 83028 NOK 53164\n", - "batch 133 : total OK 84051 NOK 53165\n", - "batch 134 : total OK 85074 NOK 53166\n", - "batch 135 : total OK 85414 NOK 53850\n", - "batch 136 : total OK 85414 NOK 54874\n", - "batch 137 : total OK 85414 NOK 55898\n", - "batch 138 : total OK 85435 NOK 56901\n", - "batch 139 : total OK 85606 NOK 57754\n", - "batch 140 : total OK 86080 NOK 58304\n", - "batch 141 : total OK 87002 NOK 58406\n", - "batch 142 : total OK 87994 NOK 58438\n", - "batch 143 : total OK 88990 NOK 58466\n", - "batch 144 : total OK 89989 NOK 58491\n", - "batch 145 : total OK 90720 NOK 58784\n", - "batch 146 : total OK 90720 NOK 59808\n", - "batch 147 : total OK 90720 NOK 60832\n", - "batch 148 : total OK 90720 NOK 61856\n", - "batch 149 : total OK 90726 NOK 62874\n", - "batch 150 : total OK 90772 NOK 63852\n", - "batch 151 : total OK 91140 NOK 64508\n", - "batch 152 : total OK 91717 NOK 64955\n", - "batch 153 : total OK 92309 NOK 65387\n", - "batch 154 : total OK 92941 NOK 65779\n", - "batch 155 : total OK 93564 NOK 66180\n", - "batch 156 : total OK 93717 NOK 67051\n", - "batch 157 : total OK 93806 NOK 67986\n", - "batch 158 : total OK 93923 NOK 68893\n", - "batch 159 : total OK 94149 NOK 69691\n", - "batch 160 : total OK 94278 NOK 70586\n", - "batch 161 : total OK 94655 NOK 71233\n", - "batch 162 : total OK 95420 NOK 71492\n", - "batch 163 : total OK 96239 NOK 71697\n", - "batch 164 : total OK 97071 NOK 71889\n", - "batch 165 : total OK 97911 NOK 72073\n", - "batch 166 : total OK 98390 NOK 72618\n", - "batch 167 : total OK 98406 NOK 73626\n", - "batch 168 : total OK 98431 NOK 74625\n", - "batch 169 : total OK 98497 NOK 75583\n", - "batch 170 : total OK 98645 NOK 76459\n", - "batch 171 : total OK 99041 NOK 77087\n", - "batch 172 : total OK 99671 NOK 77481\n", - "batch 173 : total OK 100412 NOK 77764\n", - "batch 174 : total OK 101156 NOK 78044\n", - "batch 175 : total OK 101917 NOK 78307\n", - "batch 176 : total OK 102635 NOK 78613\n", - "batch 177 : total OK 102702 NOK 79570\n", - "batch 178 : total OK 102953 NOK 80343\n", - "batch 179 : total OK 103569 NOK 80751\n", - "batch 180 : total OK 104381 NOK 80963\n", - "batch 181 : total OK 105164 NOK 81204\n", - "batch 182 : total OK 106173 NOK 81219\n", - "batch 183 : total OK 107165 NOK 81251\n", - "batch 184 : total OK 108118 NOK 81322\n", - "batch 185 : total OK 109045 NOK 81419\n", - "batch 186 : total OK 109977 NOK 81511\n", - "batch 187 : total OK 110393 NOK 82119\n", - "batch 188 : total OK 110508 NOK 83028\n", - "batch 189 : total OK 110612 NOK 83948\n", - "batch 190 : total OK 110759 NOK 84825\n", - "batch 191 : total OK 111221 NOK 85387\n", - "batch 192 : total OK 111277 NOK 86355\n", - "batch 193 : total OK 111336 NOK 87320\n", - "batch 194 : total OK 111425 NOK 88255\n", - "batch 195 : total OK 111554 NOK 89150\n", - "batch 196 : total OK 111691 NOK 90037\n", - "batch 197 : total OK 111800 NOK 90952\n", - "batch 198 : total OK 111867 NOK 91909\n", - "batch 199 : total OK 112010 NOK 92790\n", - "batch 200 : total OK 112335 NOK 93489\n", - "batch 201 : total OK 112898 NOK 93950\n", - "batch 202 : total OK 113797 NOK 94075\n", - "batch 203 : total OK 114799 NOK 94097\n", - "batch 204 : total OK 115816 NOK 94104\n", - "batch 205 : total OK 116825 NOK 94119\n", - "batch 206 : total OK 117838 NOK 94130\n", - "batch 207 : total OK 118844 NOK 94148\n", - "batch 208 : total OK 119131 NOK 94885\n", - "batch 209 : total OK 119332 NOK 95708\n", - "batch 210 : total OK 119799 NOK 96265\n", - "batch 211 : total OK 120511 NOK 96577\n", - "batch 212 : total OK 121195 NOK 96917\n", - "batch 213 : total OK 122086 NOK 97050\n", - "batch 214 : total OK 122976 NOK 97184\n", - "batch 215 : total OK 123898 NOK 97286\n", - "batch 216 : total OK 124827 NOK 97381\n", - "batch 217 : total OK 125740 NOK 97492\n", - "batch 218 : total OK 126349 NOK 97907\n", - "batch 219 : total OK 126519 NOK 98761\n", - "batch 220 : total OK 126980 NOK 99324\n", - "batch 221 : total OK 127978 NOK 99350\n", - "batch 222 : total OK 129002 NOK 99350\n", - "batch 223 : total OK 130026 NOK 99350\n", - "batch 224 : total OK 131050 NOK 99350\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "batch 225 : total OK 132074 NOK 99350\n", - "batch 226 : total OK 133098 NOK 99350\n", - "batch 227 : total OK 134122 NOK 99350\n", - "batch 228 : total OK 135146 NOK 99350\n", - "batch 229 : total OK 135170 NOK 100350\n", - "batch 230 : total OK 135173 NOK 101371\n", - "batch 231 : total OK 135266 NOK 102302\n", - "batch 232 : total OK 136058 NOK 102534\n", - "batch 233 : total OK 137082 NOK 102534\n", - "batch 234 : total OK 138106 NOK 102534\n", - "batch 235 : total OK 139130 NOK 102534\n", - "batch 236 : total OK 140154 NOK 102534\n", - "batch 237 : total OK 141178 NOK 102534\n", - "batch 238 : total OK 142202 NOK 102534\n", - "batch 239 : total OK 142647 NOK 103113\n", - "batch 240 : total OK 142647 NOK 104137\n", - "batch 241 : total OK 142649 NOK 105159\n", - "batch 242 : total OK 142742 NOK 106090\n", - "batch 243 : total OK 143513 NOK 106343\n", - "batch 244 : total OK 144535 NOK 106345\n", - "batch 245 : total OK 145559 NOK 106345\n", - "batch 246 : total OK 146583 NOK 106345\n", - "batch 247 : total OK 147607 NOK 106345\n", - "batch 248 : total OK 148631 NOK 106345\n", - "batch 249 : total OK 149495 NOK 106345\n" - ] - } - ], - "source": [ - "ok = 0\n", - "nok = 0\n", - "total = len(test_indices)\n", - "for i_batch in range(math.ceil(total/batch_size)):\n", - " i_frame = i_batch*batch_size\n", - " if i_frame+batch_size > total:\n", - " batch_size = total - i_frame\n", - " accel.batch_size = batch_size\n", - " batch_indices = test_indices[i_frame:i_frame+batch_size]\n", - " data, mod, snr = data_h5[batch_indices], label_mod[batch_indices], label_snr[batch_indices]\n", - "\n", - " ibuf = quantize(data).reshape(accel.ishape_normal(0))\n", - " obuf = accel.execute(ibuf)\n", - "\n", - " pred = obuf.reshape(batch_size).astype(int)\n", - "\n", - " ok += np.equal(pred, mod).sum().item()\n", - " nok += np.not_equal(pred, mod).sum().item()\n", - " \n", - " print(\"batch %d : total OK %d NOK %d\" % (i_batch, ok, nok))" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Overall top-1 accuracy: 58.43300500312696%\n" - ] - } - ], - "source": [ - "acc = 100.0 * ok / (total)\n", - "print(\"Overall top-1 accuracy: {}%\".format(acc))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## More benchmarking" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'DRAM_in_bandwidth[Mb/s]': 64.74523228253237,\n", - " 'DRAM_out_bandwidth[Mb/s]': 0.03161388295045526,\n", - " 'batch_size': 1024,\n", - " 'copy_input_data_to_device[ms]': 2.189159393310547,\n", - " 'copy_output_data_from_device[ms]': 0.08916854858398438,\n", - " 'fclk[mhz]': 187.498125,\n", - " 'fold_input[ms]': 0.1010894775390625,\n", - " 'pack_input[ms]': 0.1556873321533203,\n", - " 'runtime[ms]': 32.39083290100098,\n", - " 'throughput[images/s]': 31613.88295045526,\n", - " 'unfold_output[ms]': 0.08726119995117188,\n", - " 'unpack_output[ms]': 0.6263256072998047}" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "accel.batch_size = 1024\n", - "accel.throughput_test()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.5" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/finn_examples/notebooks/4_radioml_with_cnns.ipynb b/finn_examples/notebooks/4_radioml_with_cnns.ipynb new file mode 100755 index 0000000..56e15d4 --- /dev/null +++ b/finn_examples/notebooks/4_radioml_with_cnns.ipynb @@ -0,0 +1,489 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Initialize the accelerator" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "# remember to install the following dependencies\n", + "#! apt-get install libhdf5-dev -y\n", + "#! pip install versioned-hdf5" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "application/javascript": [ + "\n", + "try {\n", + "require(['notebook/js/codecell'], function(codecell) {\n", + " codecell.CodeCell.options_default.highlight_modes[\n", + " 'magic_text/x-csrc'] = {'reg':[/^%%microblaze/]};\n", + " Jupyter.notebook.events.one('kernel_ready.Kernel', function(){\n", + " Jupyter.notebook.get_cells().map(function(cell){\n", + " if (cell.cell_type == 'code'){ cell.auto_highlight(); } }) ;\n", + " });\n", + "});\n", + "} catch (e) {};\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/javascript": [ + "\n", + "try {\n", + "require(['notebook/js/codecell'], function(codecell) {\n", + " codecell.CodeCell.options_default.highlight_modes[\n", + " 'magic_text/x-csrc'] = {'reg':[/^%%pybind11/]};\n", + " Jupyter.notebook.events.one('kernel_ready.Kernel', function(){\n", + " Jupyter.notebook.get_cells().map(function(cell){\n", + " if (cell.cell_type == 'code'){ cell.auto_highlight(); } }) ;\n", + " });\n", + "});\n", + "} catch (e) {};\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['_radioml_io_shape_dict', 'vgg10_w4a4_radioml']\n" + ] + } + ], + "source": [ + "from finn_examples import models\n", + "print(list(filter(lambda x: \"radioml\" in x, dir(models))))" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "accel = models.vgg10_w4a4_radioml()" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Expected input shape and datatype: (1, 1024, 1, 2) DataType.INT8\n", + "Expected output shape and datatype: (1, 1) DataType.UINT8\n" + ] + } + ], + "source": [ + "print(\"Expected input shape and datatype: %s %s\" % (str(accel.ishape_normal), str(accel.idt)))\n", + "print(\"Expected output shape and datatype: %s %s\" % (str(accel.oshape_normal), str(accel.odt)))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Load RadioML 2018 dataset" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "/home/xilinx/datasets/radioml_2018\n" + ] + } + ], + "source": [ + "import numpy as np\n", + "import math\n", + "import pickle\n", + "import os\n", + "import h5py\n", + "\n", + "dataset_dir = \"/home/xilinx/datasets/radioml_2018\"\n", + "print(dataset_dir)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "h5_file = h5py.File(dataset_dir + \"/GOLD_XYZ_OSC.0001_1024.hdf5\",'r')\n", + "data_h5 = h5_file['X']\n", + "label_mod = np.argmax(h5_file['Y'], axis=1) # comes in one-hot encoding\n", + "label_snr = h5_file['Z'][:,0]\n", + "\n", + "# assemble list of test set indices\n", + "# do not pre-load large dataset into memory\n", + "np.random.seed(2018)\n", + "test_indices = []\n", + "for mod in range(0, 24): #all modulations (0 to 23)\n", + " for snr_idx in range(0, 26): #all SNRs (0 to 25 = -20dB to +30dB)\n", + " start_idx = 26*4096*mod + 4096*snr_idx\n", + " indices_subclass = list(range(start_idx, start_idx+4096))\n", + "\n", + " split = int(np.ceil(0.1 * 4096)) #90%/10% split\n", + " np.random.shuffle(indices_subclass)\n", + " train_indices_subclass, val_indices_subclass = indices_subclass[split:], indices_subclass[:split]\n", + "\n", + " if snr_idx >= 25: #select which SNRs to test on\n", + " test_indices.extend(val_indices_subclass)\n", + "\n", + "test_indices = sorted(test_indices)\n", + "\n", + "# note: labels given in the \"classes.txt\" file are not in the correct order (https://github.com/radioML/dataset/issues/25)\n", + "mod_classes = ['OOK','4ASK','8ASK','BPSK','QPSK','8PSK','16PSK','32PSK',\n", + "'16APSK','32APSK','64APSK','128APSK','16QAM','32QAM','64QAM','128QAM','256QAM',\n", + "'AM-SSB-WC','AM-SSB-SC','AM-DSB-WC','AM-DSB-SC','FM','GMSK','OQPSK']\n", + "snr_classes = np.arange(-20., 32., 2) # -20dB to 30dB" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(2555904, 1024, 2)\n", + "(2555904,)\n", + "(2555904,)\n", + "9840\n" + ] + } + ], + "source": [ + "print(data_h5.shape)\n", + "print(label_mod.shape)\n", + "print(label_snr.shape)\n", + "print(len(test_indices))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Inspect a single frame" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Modulation: 16QAM, SNR: 30.0 dB\n" + ] + } + ], + "source": [ + "from matplotlib import pyplot as plt\n", + "\n", + "# Inspect a frame\n", + "mod = 12 # 0 to 23\n", + "snr_idx = 25 # 0 to 25 = -20dB to +30dB\n", + "sample = 123 # 0 to 4095\n", + "#-----------------------#\n", + "idx = 26*4096*mod + 4096*snr_idx + sample\n", + "data, mod, snr = data_h5[idx], label_mod[idx], label_snr[idx]\n", + "plt.figure()\n", + "plt.plot(data)\n", + "print(\"Modulation: %s, SNR: %.1f dB\" % (mod_classes[mod], snr))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Input quantization\n", + "Quantize input data on-the-fly in software before feeding it to the accelerator. Use the uniform quantization range on which the model was trained." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "def quantize(data):\n", + " quant_min = -2.0\n", + " quant_max = 2.0\n", + " quant_range = quant_max - quant_min\n", + " data_quant = (data - quant_min) / quant_range\n", + " data_quant = np.round(data_quant * 256) - 128\n", + " data_quant = np.clip(data_quant, -128, 127)\n", + " data_quant = data_quant.astype(np.int8)\n", + " return data_quant" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Classify a single frame" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Input buffer shape is (1, 1024, 1, 2) and datatype is int8\n" + ] + } + ], + "source": [ + "accel_in = quantize(data).reshape(accel.ishape_normal)\n", + "print(\"Input buffer shape is %s and datatype is %s\" % (str(accel_in.shape), str(accel_in.dtype)))" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "accel_out = accel.execute(accel_in)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Result: [[12.]]\n", + "Top-1 class predicted by the accelerator: 16QAM\n" + ] + } + ], + "source": [ + "print(\"Result: \" + str(accel_out))\n", + "print(\"Top-1 class predicted by the accelerator: \" + mod_classes[int(accel_out)])" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1000 loops, best of 3: 822 µs per loop\n" + ] + } + ], + "source": [ + "%%timeit\n", + "accel_out = accel.execute(accel_in)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Validate accuracy on entire test set" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Accelerator buffer shapes are (1024, 1024, 1, 1, 2) for input, (1024, 1, 1) for output\n", + "Accelerator buffer shapes are (1024, 1024, 1, 1, 2) for input, (1024, 1, 1) for output\n", + "Accelerator buffer shapes are (1024, 1024, 1, 2) for input, (1024, 1) for output\n" + ] + } + ], + "source": [ + "batch_size = 1024\n", + "accel.batch_size = batch_size\n", + "print(\"Accelerator buffer shapes are %s for input, %s for output\" % (str(accel.ishape_packed), str(accel.oshape_packed)) )\n", + "print(\"Accelerator buffer shapes are %s for input, %s for output\" % (str(accel.ishape_folded), str(accel.oshape_folded)) )\n", + "print(\"Accelerator buffer shapes are %s for input, %s for output\" % (str(accel.ishape_normal), str(accel.oshape_normal)) )" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "batch 0 : total OK 1018 NOK 6\n", + "batch 1 : total OK 2041 NOK 7\n", + "batch 2 : total OK 3059 NOK 13\n", + "batch 3 : total OK 4082 NOK 14\n", + "batch 4 : total OK 4948 NOK 172\n", + "batch 5 : total OK 5682 NOK 462\n", + "batch 6 : total OK 6314 NOK 854\n", + "batch 7 : total OK 7039 NOK 1153\n", + "batch 8 : total OK 8024 NOK 1192\n", + "batch 9 : total OK 8648 NOK 1192\n" + ] + } + ], + "source": [ + "ok = 0\n", + "nok = 0\n", + "total = len(test_indices)\n", + "for i_batch in range(math.ceil(total/batch_size)):\n", + " i_frame = i_batch*batch_size\n", + " if i_frame+batch_size > total:\n", + " batch_size = total - i_frame\n", + " accel.batch_size = batch_size\n", + " batch_indices = test_indices[i_frame:i_frame+batch_size]\n", + " data, mod, snr = data_h5[batch_indices], label_mod[batch_indices], label_snr[batch_indices]\n", + "\n", + " ibuf = quantize(data).reshape(accel.ishape_normal)\n", + " obuf = accel.execute(ibuf)\n", + "\n", + " pred = obuf.reshape(batch_size).astype(int)\n", + "\n", + " ok += np.equal(pred, mod).sum().item()\n", + " nok += np.not_equal(pred, mod).sum().item()\n", + " \n", + " print(\"batch %d : total OK %d NOK %d\" % (i_batch, ok, nok))" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Overall top-1 accuracy: 87.88617886178862%\n" + ] + } + ], + "source": [ + "acc = 100.0 * ok / (total)\n", + "print(\"Overall top-1 accuracy: {}%\".format(acc))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## More benchmarking" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'DRAM_in_bandwidth[Mb/s]': 473.18806940706867,\n", + " 'DRAM_out_bandwidth[Mb/s]': 0.23104886201517025,\n", + " 'batch_size': 1024,\n", + " 'copy_input_data_to_device[ms]': 2.1643638610839844,\n", + " 'copy_output_data_from_device[ms]': 0.08821487426757812,\n", + " 'fclk[mhz]': 249.9975,\n", + " 'fold_input[ms]': 0.1418590545654297,\n", + " 'pack_input[ms]': 0.110626220703125,\n", + " 'runtime[ms]': 4.431962966918945,\n", + " 'throughput[images/s]': 231048.86201517025,\n", + " 'unfold_output[ms]': 0.08678436279296875,\n", + " 'unpack_output[ms]': 0.6284713745117188}" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "accel.batch_size = 1024\n", + "accel.throughput_test()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.5" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From 65ccad3f282021b8556dde18660d1512861c886d Mon Sep 17 00:00:00 2001 From: Hendrik Borras Date: Mon, 1 Nov 2021 09:10:28 +0000 Subject: [PATCH 19/49] Updated FINN commit. --- build/get-finn.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/get-finn.sh b/build/get-finn.sh index 27ab15f..d3fce9b 100755 --- a/build/get-finn.sh +++ b/build/get-finn.sh @@ -30,7 +30,7 @@ # URL for git repo to be cloned REPO_URL=https://github.com/Xilinx/finn # commit hash for repo -REPO_COMMIT=beebdd77a29b84ab3b741a1a0544438191822d71 +REPO_COMMIT=6a22a11fee35a61bea43ab0ad2f58db53cfb68c3 # directory (under the same folder as this script) to clone to REPO_DIR=finn From b29f0943a6aa1e5f270f180431734ac5c0a101db Mon Sep 17 00:00:00 2001 From: Hendrik Borras Date: Mon, 1 Nov 2021 09:11:03 +0000 Subject: [PATCH 20/49] Added KWS build files. --- build/kws/README.md | 24 +++++ build/kws/build.py | 161 ++++++++++++++++++++++++++++++++ build/kws/expected_output.npy | Bin 0 -> 136 bytes build/kws/get-kws-data-model.sh | 32 +++++++ build/kws/input.npy | Bin 0 -> 2088 bytes 5 files changed, 217 insertions(+) create mode 100644 build/kws/README.md create mode 100644 build/kws/build.py create mode 100644 build/kws/expected_output.npy create mode 100755 build/kws/get-kws-data-model.sh create mode 100644 build/kws/input.npy diff --git a/build/kws/README.md b/build/kws/README.md new file mode 100644 index 0000000..9588204 --- /dev/null +++ b/build/kws/README.md @@ -0,0 +1,24 @@ +# The KWS examplee + +The KWS example includes an MLP for the Google SpeechCommandsV2 dataset. + +## Build bitfiles for BNN-PYNQ examples + +The build is currently configured for the PYNQ-Z1 board and a throughput of 200k FPS at a clock frequency of 100 MHz. + +1. Download the pretrained MLP ONNX models and pre-processed validation data using the `get-kws-data-model.sh` script. + +2. Launch the build as follows: +```shell +# update this according to where you cloned this repo: +FINN_EXAMPLES=/path/to/finn-examples +# cd into finn submodule +cd $FINN_EXAMPLES/build/finn +# launch the build on the bnn-pynq folder +bash run-docker.sh build_custom /path/to/finn-examples/build/kws +``` + +3. The generated outputs will be under `kws/_output__`. +You can find a description of the generated files [here](https://finn-dev.readthedocs.io/en/latest/command_line.html#simple-dataflow-build-mode). +The folder will additionally include the quantized inputs for verification (`all_validation_KWS_data_inputs_len_10102.npy`) and the expected outputs (`all_validation_KWS_data_outputs_len_10102.npy`). +When running the network on hardware the validation should achieve an accuracy of 89.78 % with 9070 of the 10102 samples being classified correctly. diff --git a/build/kws/build.py b/build/kws/build.py new file mode 100644 index 0000000..af22cc4 --- /dev/null +++ b/build/kws/build.py @@ -0,0 +1,161 @@ +# Copyright (c) 2021, Xilinx +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of FINN nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +import finn.builder.build_dataflow as build +import finn.builder.build_dataflow_config as build_cfg + +from finn.core.modelwrapper import ModelWrapper +from finn.builder.build_dataflow_config import DataflowBuildConfig +from finn.transformation.insert_topk import InsertTopK +from finn.builder.build_dataflow_steps import build_dataflow_step_lookup +import time +import finn.core.onnx_exec as oxe +import numpy as np +import datetime +from glob import glob + + +# Inject the preprocessing step into FINN to enable json serialization later on +def step_preprocess(model: ModelWrapper, cfg: DataflowBuildConfig): + model = model.transform(InsertTopK(k=1)) + return model + + +build_dataflow_step_lookup["step_preprocess_InsertTopK"] = step_preprocess + +estimate_steps = ["step_preprocess_InsertTopK"] + build_cfg.estimate_only_dataflow_steps +estimate_outputs = [build_cfg.DataflowOutputType.ESTIMATE_REPORTS] +build_steps = ["step_preprocess_InsertTopK"] + build_cfg.default_build_dataflow_steps +build_outputs = [ + build_cfg.DataflowOutputType.ESTIMATE_REPORTS, + build_cfg.DataflowOutputType.STITCHED_IP, + build_cfg.DataflowOutputType.PYNQ_DRIVER, + build_cfg.DataflowOutputType.BITFILE, + build_cfg.DataflowOutputType.DEPLOYMENT_PACKAGE, +] +verification_steps = [ + build_cfg.VerificationStepType.QONNX_TO_FINN_PYTHON, + build_cfg.VerificationStepType.TIDY_UP_PYTHON, + build_cfg.VerificationStepType.STREAMLINED_PYTHON, + build_cfg.VerificationStepType.FOLDED_HLS_CPPSIM, + # build_cfg.VerificationStepType.STITCHED_IP_RTLSIM, # Fails with timeout +] + +model_name = ( + "MLP_W3A3_scale_init-0.1_no_per_channel_" + "scaling_at_output_usigned_non-narrow_relu_act_QONNX" +) +model_file = model_name + ".onnx" + +# Change the ONNX opset from version 9 to 11, which adds support for the TopK node +from finn.core.modelwrapper import ModelWrapper +model = ModelWrapper(model_file) +model.model.opset_import[0].version = 11 +model_file = model_file.replace(".onnx", "_opset-11.onnx") +model.save(model_file) + +platform_name = "Pynq-Z1" +output_dir = f"{time.time():.2f}_output_{model_name.replace('/','_')}_{platform_name}" + +# Configure build +cfg = build_cfg.DataflowBuildConfig( + # steps=estimate_steps, generate_outputs=estimate_outputs, + verify_steps=verification_steps, + steps=build_steps, + generate_outputs=build_outputs, + output_dir=output_dir, + target_fps=200000, + synth_clk_period_ns=10.0, + board=platform_name, + shell_flow_type=build_cfg.ShellFlowType.VIVADO_ZYNQ, + save_intermediate_models=True, + stitched_ip_gen_dcp=True, + verify_save_full_context=True, +) +# Build the model +build.build_dataflow_cfg(model_file, cfg) + +# Save Build config +config_json_path = f"{output_dir}/DataflowBuildConfig.json" +with open(config_json_path, "w") as f: + f.write(cfg.to_json()) +print(f"Saved DataflowBuildConfig to: {config_json_path}") + +# Export quantized inputs +print("Quantizing validation dataset.") +parent_model = ModelWrapper(output_dir + "/intermediate_models/dataflow_parent.onnx") +input_shape = (1, 1, 10, 49) +last_node = parent_model.graph.node[-2] + +for f_name in glob("*.npz"): + print(f"Processing file: {f_name}") + + with open(f_name, "rb") as f: + np_f = np.load(f) + data_arr = np_f["data_arr"] + label_arr = np_f["label_arr"] + + pre_processed_inputs = [] + start_time = time.time() + for i in range(len(data_arr)): + input_tensor_finn = data_arr[i].reshape(input_shape) + + # Execute with FINN-ONNX + input_dict = {parent_model.graph.input[0].name: input_tensor_finn} + output_dict = oxe.execute_onnx( + parent_model, + input_dict, + True, + end_node=last_node, + ) + finn_output = output_dict[last_node.output[0]] + pre_processed_inputs.append(finn_output) + + diff_time = time.time() - start_time + time_per_sample = diff_time / (i + 1) + time_left = (len(data_arr) - (i + 1)) * time_per_sample + time_left = datetime.timedelta(seconds=time_left) + print( + f"Processed: {100*(i+1)/len(data_arr):.1f} [%], " + f"time left: {str(time_left)}", + end="\r", + ) + print() + + # Make compatible with FINN driver + pre_processed_inputs = np.asarray(pre_processed_inputs) + pre_processed_inputs = np.squeeze(pre_processed_inputs) + pre_processed_inputs = pre_processed_inputs.astype(np.int8) + + # Save data + export_path = output_dir + "/" + f_name.replace(".npz", "_{}_len_{}.npy") + print(f"Saving data to: {export_path}") + np.save( + export_path.format("inputs", len(pre_processed_inputs)), pre_processed_inputs + ) + np.save(export_path.format("outputs", len(label_arr)), label_arr) diff --git a/build/kws/expected_output.npy b/build/kws/expected_output.npy new file mode 100644 index 0000000000000000000000000000000000000000..0058afee01414e4a4c55b803e2cde6e6e722c00c GIT binary patch literal 136 zcmbR27wQ`j$;eQ~P_3SlTAW;@Zl$1ZlWC!@qoAIaUsO_*m=~X4l#&V(cT3DEP6dh= ZXCxM+0{I$-I+{8PwF(pfE@lP@001yk8)5(e literal 0 HcmV?d00001 diff --git a/build/kws/get-kws-data-model.sh b/build/kws/get-kws-data-model.sh new file mode 100755 index 0000000..61a54a4 --- /dev/null +++ b/build/kws/get-kws-data-model.sh @@ -0,0 +1,32 @@ +#!/bin/bash +# Copyright (c) 2020, Xilinx +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of FINN nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Download validation data and model +wget https://github.com/Xilinx/finn-examples/releases/download/kws/all_validation_KWS_data.npz +wget https://github.com/Xilinx/finn-examples/releases/download/kws/MLP_W3A3_scale_init-0.1_no_per_channel_scaling_at_output_usigned_non-narrow_relu_act_QONNX.onnx diff --git a/build/kws/input.npy b/build/kws/input.npy new file mode 100644 index 0000000000000000000000000000000000000000..97fe531335aea0e5656794526ed3421cc154dbba GIT binary patch literal 2088 zcmb7&`9GHF9)KA#vPQB*&3i_A5kgXy_x|1wm5_R?lcHoxR3}PNqveS9PAH-hSz6GJ zEb-po=P9ByoGDbYM93B?EjnqMGxH~$>vR2bUCB#Vc}acb<)Y>Gh&P1n2#ypxip0(v z?Zg%$@y3YAosogz{t=NILjL-HkBkcWbMFWX+!pd@n%Y>1{?gh)WanUJA=)SU|4~U8 zY7sP(=1~z*r8cQgK<6RCMZd$iuEthEQ-6w+5-EX158TTZ1=Cur{Y>zMnjK~V`Wco?yrN7Vl|=_RYR_|{*1wX z6EME`5(Y3ibiSL)Ao;Z*1P#I-{~=J`ZUs&|Qd!?BL(F&UB5N0vGnYnFa&m$qDwGTg zatHnkwv!p;t2}@TtzhtN^Jix~e4TBs*0avs5PY4_p~?C&A!nW*H7#fdz0wR)){;ar zy-O?NJdH81ZX-Ty^k$7K=d+NycS3&RFuW)og;qaXa_@i&$TB_HN23L}K69KrZl4N& zBw6AK_cubcVjY}*qe;^t5=@U)5a)pe5^Zsqb!Yu1J4`m<`zxV1Lp&lVRX&A3`X*4X zv;??NoJ-mtC1Sm*EpEw~PHNUFk)j$SQq%EP&`X#>bH2`|dh1=G>O(e|dF}=6%mb{T zpJ(!U5yZOgDvQ|gQn+-&ls;Y44@Os(z%mm{(yjQ2eEDFBx`v<8r~5e0_&t$Xw!Rcn zCc08GcOU)NwC|91&5MkfH!<^N=kWXBZ9HY=D{HboEBT=KMwn!%OQTnI!SVi3$p5Sj zL36Ll)RhcKg@}<$!<6mXs}B3q(}Wv^nw-a{8tRfKgF8iqr1ydh7fB!DSVk*blgA<7 za)jA-2MXD{thmVvkEy4-GCjTbzN~XJ6&*!W_~^NZaH~-PQ(e6c6jUU_h>i^xuTVuF z1!ckIj(XXSrOkM|WFo(fcwqo)NDN&(U{3d3!OG8uGw!`XAAT%^>i7h*EjI>R1sC4P zL5!NVMUv2yW$@HjQ7|wNahuPl({mD28a{qNV)0`l8lfMr8{5D}9qL)`(idP{rN;+N zdP_~U57L#-V(8kG9&B`t=I=Rnu>NzFFg1S?9y;PklO&eh40$#Yw|?$>EdJJ?_!R%%43iy(V~OpNl0@e*<+98T=wNOYP0PMF+MLx zPKRbmg53?!*XAkw`_wCV*^-2johQ(6wwPNGmO!6Z+Yr@XGoZ(*1bz?o!G~NrxLnhs z55^@pI+}n5!(%k_WxYuAn7l|8Dy*(Y(?9%BW9i&E^ z^r1%nxGX!Y1KjdN;GNR}zCmlKnLb7FiD~?-kIt0IF}mD75!SZNl&uWXrD`6115F_3+f1)sFa>f>8NSCl(YWgKP%)rGN);Y~n?(|9GBe_r&ko0v zVM?4ZvkbJYL?Bktqq68`N!Cw$(b=UI6166w{0cX`RJnG+K-I2T zDAGybgP+agZpX}_3r4DNi;I!OE;SqjbmFjb36mYo$VcaDAMkXo;#I@!IakL4=vp?5 zf4a#F?~L3*yCDw@?u^B#%?fVt$N8PDrixU4u-<|19Jpl44tD&(d5nr_V;j@-@616c(HS3y72nCAGLSALBeZopjmnhZhdG&?pPa&_RWM9?W!0*qXOsMsuj8}YEqEa z!Fb|LQk=XVb{7}p!VWb)t?4J!(3|V5^Wz2#yw3{`+8)$z&lNbcdR(^4`W`tNppKJ6 zH{tSEf#k`jQ1(T>k5%hF7dp~JbWd{@7}qM1i1J2>`erZG->iqzd(NZ5TR9}}9P#m? oX5qPxHXVqcOuNt4LP?Ai()!{h;nFME2iSPpf&c&j literal 0 HcmV?d00001 From eccd2586000e450d236c33911f16e8648fae55a9 Mon Sep 17 00:00:00 2001 From: Yaman Umuroglu Date: Wed, 3 Nov 2021 10:51:15 +0100 Subject: [PATCH 21/49] remove transformations got moved, rename import --- build/mobilenet-v1/custom_steps.py | 2 +- build/resnet50/custom_steps.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build/mobilenet-v1/custom_steps.py b/build/mobilenet-v1/custom_steps.py index 3c94e30..3643b30 100644 --- a/build/mobilenet-v1/custom_steps.py +++ b/build/mobilenet-v1/custom_steps.py @@ -36,7 +36,7 @@ import finn.transformation.streamline.reorder as reorder from finn.transformation.infer_data_layouts import InferDataLayouts from finn.transformation.streamline.collapse_repeated import CollapseRepeatedMul -from finn.transformation.streamline.remove import RemoveIdentityOps +from finn.transformation.remove import RemoveIdentityOps from finn.transformation.streamline.round_thresholds import RoundAndClipThresholds from finn.transformation.lower_convs_to_matmul import LowerConvsToMatMul from finn.transformation.general import ( diff --git a/build/resnet50/custom_steps.py b/build/resnet50/custom_steps.py index c3baabb..01431f4 100644 --- a/build/resnet50/custom_steps.py +++ b/build/resnet50/custom_steps.py @@ -81,7 +81,7 @@ ) from finn.transformation.double_to_single_float import DoubleToSingleFloat -from finn.transformation.streamline.remove import RemoveIdentityOps +from finn.transformation.remove import RemoveIdentityOps from finn.core.datatype import DataType from finn.transformation.infer_shapes import InferShapes From ec82fa0ff6b308c6ae053fada64747abfbb1b862 Mon Sep 17 00:00:00 2001 From: Yaman Umuroglu Date: Wed, 3 Nov 2021 10:52:09 +0100 Subject: [PATCH 22/49] update to latest finn dev --- build/get-finn.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/get-finn.sh b/build/get-finn.sh index 27ab15f..b5d29a6 100755 --- a/build/get-finn.sh +++ b/build/get-finn.sh @@ -30,7 +30,7 @@ # URL for git repo to be cloned REPO_URL=https://github.com/Xilinx/finn # commit hash for repo -REPO_COMMIT=beebdd77a29b84ab3b741a1a0544438191822d71 +REPO_COMMIT=918ba0084fee32e340274ad042811e24203de300 # directory (under the same folder as this script) to clone to REPO_DIR=finn From 8716473925ea281a5400242c72b2d3969043e7f4 Mon Sep 17 00:00:00 2001 From: Yaman Umuroglu Date: Wed, 3 Nov 2021 12:55:27 +0100 Subject: [PATCH 23/49] add KWS MLP to table in README --- README.md | 1 + docs/img/keyword-spotting.png | Bin 0 -> 29940 bytes 2 files changed, 1 insertion(+) create mode 100644 docs/img/keyword-spotting.png diff --git a/README.md b/README.md index 331fd7f..62721b4 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,7 @@ dummy_out = accel.execute(dummy_in) |

ImageNet | MobileNet-v1 | 4-bit weights and activations
8-bit first layer weights | Alveo U250
ZCU104 | |

ImageNet | ResNet-50 | 1-bit weights 2-bit activations
4-bit residuals
8-bit first/last layer weights | Alveo U250 | |

MaskedFace-Net | [BinaryCoP](https://arxiv.org/pdf/2102.03456)
*Contributed by TU Munich+BMW* | 1-bit weights and activations | Pynq-Z1 | +|

Google Speech Commands v2 | 3-layer fully-connected | 3-bit weights and activations | Pynq-Z1 | We welcome community contributions to add more examples to this repo! diff --git a/docs/img/keyword-spotting.png b/docs/img/keyword-spotting.png new file mode 100644 index 0000000000000000000000000000000000000000..dea15b09d80cd37d68cd442cc7f8d3dd36e22fce GIT binary patch literal 29940 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 DX+Agm literal 0 HcmV?d00001 From 0b417b9ba238c0c3f175d14615cc5d0b9b7bba7b Mon Sep 17 00:00:00 2001 From: Yaman Umuroglu Date: Wed, 3 Nov 2021 12:56:00 +0100 Subject: [PATCH 24/49] add linkfile to download preproc'd KWS validation data --- finn_examples/data/__init__.py | 0 .../data/all_validation_kws_data_preprocessed.zip.link | 6 ++++++ 2 files changed, 6 insertions(+) create mode 100644 finn_examples/data/__init__.py create mode 100644 finn_examples/data/all_validation_kws_data_preprocessed.zip.link diff --git a/finn_examples/data/__init__.py b/finn_examples/data/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/finn_examples/data/all_validation_kws_data_preprocessed.zip.link b/finn_examples/data/all_validation_kws_data_preprocessed.zip.link new file mode 100644 index 0000000..f5db5f2 --- /dev/null +++ b/finn_examples/data/all_validation_kws_data_preprocessed.zip.link @@ -0,0 +1,6 @@ +{ + "url": "https://github.com/Xilinx/finn-examples/releases/download/kws/all_validation_kws_data_preprocessed.zip", + "md5sum": "bb314d1aeff7a822a00bc3d98fbf05f7" +} + + From 23ee12fe8f86fdf1eb1368eb1bd96ad511e087d4 Mon Sep 17 00:00:00 2001 From: Yaman Umuroglu Date: Wed, 3 Nov 2021 12:56:35 +0100 Subject: [PATCH 25/49] add KWS MLP to models.py --- finn_examples/models.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/finn_examples/models.py b/finn_examples/models.py index af042b8..3838530 100644 --- a/finn_examples/models.py +++ b/finn_examples/models.py @@ -94,6 +94,18 @@ "number_of_external_weights": 1 } +_gscv2_mlp_io_shape_dict = { + "idt" : DataType['INT8'], + "odt" : DataType['UINT8'], + "ishape_normal" : (1, 490), + "oshape_normal" : (1, 1), + "ishape_folded" : (1, 49, 10), + "oshape_folded" : (1, 1, 1), + "ishape_packed" : (1, 49, 10), + "oshape_packed" : (1, 1, 1), + "input_dma_name" : 'idma0', +} + # from https://github.com/Xilinx/PYNQ-HelloWorld/blob/master/setup.py # get current platform: either edge or pcie @@ -164,6 +176,12 @@ def resolve_target_platform(target_platform): assert target_platform in [x.name for x in pynq.Device.devices] return target_platform +def kws_mlp(target_platform=None): + target_platform = resolve_target_platform(target_platform) + driver_mode = get_driver_mode() + model_name = "kwsmlp-w3a3" + filename = find_bitfile(model_name, target_platform) + return FINNExampleOverlay(filename, driver_mode, _mnist_fc_io_shape_dict) def tfc_w1a1_mnist(target_platform=None): target_platform = resolve_target_platform(target_platform) From 5bb98c2ef5452c73a262613bf35c5844c1d4088b Mon Sep 17 00:00:00 2001 From: Yaman Umuroglu Date: Wed, 3 Nov 2021 13:24:59 +0100 Subject: [PATCH 26/49] add data folder to setup.py --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index aa38a35..31baa02 100644 --- a/setup.py +++ b/setup.py @@ -86,6 +86,7 @@ def extend_package(path): readme_lines = fh.readlines()[4:] long_description = "".join(readme_lines) extend_package(os.path.join(module_name, "bitfiles")) +extend_package(os.path.join(module_name, "data")) extend_package(os.path.join(module_name, "notebooks")) setup( From c4ae34021cdb8606a6fc80df2c2c16c8a45b36ee Mon Sep 17 00:00:00 2001 From: Yaman Umuroglu Date: Wed, 3 Nov 2021 13:28:13 +0100 Subject: [PATCH 27/49] start KWS notebook and fix io dict --- finn_examples/models.py | 2 +- .../notebooks/4_keyword_spotting.ipynb | 61 +++++++++++++++++++ 2 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 finn_examples/notebooks/4_keyword_spotting.ipynb diff --git a/finn_examples/models.py b/finn_examples/models.py index 3838530..c089cd6 100644 --- a/finn_examples/models.py +++ b/finn_examples/models.py @@ -181,7 +181,7 @@ def kws_mlp(target_platform=None): driver_mode = get_driver_mode() model_name = "kwsmlp-w3a3" filename = find_bitfile(model_name, target_platform) - return FINNExampleOverlay(filename, driver_mode, _mnist_fc_io_shape_dict) + return FINNExampleOverlay(filename, driver_mode, _gscv2_mlp_io_shape_dict) def tfc_w1a1_mnist(target_platform=None): target_platform = resolve_target_platform(target_platform) diff --git a/finn_examples/notebooks/4_keyword_spotting.ipynb b/finn_examples/notebooks/4_keyword_spotting.ipynb new file mode 100644 index 0000000..ac2fcdf --- /dev/null +++ b/finn_examples/notebooks/4_keyword_spotting.ipynb @@ -0,0 +1,61 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# Initialize the accelerator" + ], + "metadata": {} + }, + { + "cell_type": "code", + "execution_count": null, + "source": [ + "from finn_examples import models\n", + "print(list(filter(lambda x: \"kws\" in x, dir(models))))" + ], + "outputs": [], + "metadata": {} + }, + { + "cell_type": "code", + "execution_count": null, + "source": [ + "accel = models.kws_mlp()" + ], + "outputs": [], + "metadata": {} + }, + { + "cell_type": "code", + "execution_count": null, + "source": [ + "print(\"Expected input shape and datatype: %s %s\" % (str(accel.ishape_normal), str(accel.idt)))\n", + "print(\"Expected output shape and datatype: %s %s\" % (str(accel.oshape_normal), str(accel.odt)))" + ], + "outputs": [], + "metadata": {} + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.5" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} \ No newline at end of file From 651ad2b883f726a95509ea8722c27f59c34e5697 Mon Sep 17 00:00:00 2001 From: Yaman Umuroglu Date: Wed, 3 Nov 2021 13:51:31 +0100 Subject: [PATCH 28/49] update README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 62721b4..4340c05 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ Retrieve the example Jupyter notebooks using the PYNQ get-notebooks command: ```shell # on PYNQ boards, first cd /home/xilinx/jupyter_notebooks -pynq get-notebooks --from-package finn-examples -p . +pynq get-notebooks --from-package finn-examples -p . --force ``` You can now navigate the provided Jupyter notebook examples, or just use the From c2b0621aa84249bc01b029ec9e819e91859b9a65 Mon Sep 17 00:00:00 2001 From: Yaman Umuroglu Date: Wed, 3 Nov 2021 13:51:39 +0100 Subject: [PATCH 29/49] update kws notebook --- .../notebooks/4_keyword_spotting.ipynb | 248 +++++++++++++++++- 1 file changed, 235 insertions(+), 13 deletions(-) diff --git a/finn_examples/notebooks/4_keyword_spotting.ipynb b/finn_examples/notebooks/4_keyword_spotting.ipynb index ac2fcdf..9c1f833 100644 --- a/finn_examples/notebooks/4_keyword_spotting.ipynb +++ b/finn_examples/notebooks/4_keyword_spotting.ipynb @@ -2,39 +2,261 @@ "cells": [ { "cell_type": "markdown", + "metadata": {}, "source": [ "# Initialize the accelerator" - ], - "metadata": {} + ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "data": { + "application/javascript": [ + "\n", + "try {\n", + "require(['notebook/js/codecell'], function(codecell) {\n", + " codecell.CodeCell.options_default.highlight_modes[\n", + " 'magic_text/x-csrc'] = {'reg':[/^%%microblaze/]};\n", + " Jupyter.notebook.events.one('kernel_ready.Kernel', function(){\n", + " Jupyter.notebook.get_cells().map(function(cell){\n", + " if (cell.cell_type == 'code'){ cell.auto_highlight(); } }) ;\n", + " });\n", + "});\n", + "} catch (e) {};\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/javascript": [ + "\n", + "try {\n", + "require(['notebook/js/codecell'], function(codecell) {\n", + " codecell.CodeCell.options_default.highlight_modes[\n", + " 'magic_text/x-csrc'] = {'reg':[/^%%pybind11/]};\n", + " Jupyter.notebook.events.one('kernel_ready.Kernel', function(){\n", + " Jupyter.notebook.get_cells().map(function(cell){\n", + " if (cell.cell_type == 'code'){ cell.auto_highlight(); } }) ;\n", + " });\n", + "});\n", + "} catch (e) {};\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['kws_mlp']\n" + ] + } + ], "source": [ "from finn_examples import models\n", "print(list(filter(lambda x: \"kws\" in x, dir(models))))" - ], - "outputs": [], - "metadata": {} + ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, + "metadata": {}, + "outputs": [], "source": [ "accel = models.kws_mlp()" - ], - "outputs": [], - "metadata": {} + ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Expected input shape and datatype: (1, 490) DataType.INT8\n", + "Expected output shape and datatype: (1, 1) DataType.UINT8\n" + ] + } + ], "source": [ "print(\"Expected input shape and datatype: %s %s\" % (str(accel.ishape_normal), str(accel.idt)))\n", "print(\"Expected output shape and datatype: %s %s\" % (str(accel.oshape_normal), str(accel.odt)))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Load preprocessed Google Speech Commands v2 validation data" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Input data shape: (10102, 490)\n", + "Label shape: (10102,)\n" + ] + } ], + "source": [ + "import pkg_resources as pk\n", + "import numpy as np\n", + "\n", + "input_npy = pk.resource_filename(\"finn_examples\", \"data/all_validation_KWS_data_inputs_len_10102.npy\")\n", + "golden_out_npy = pk.resource_filename(\"finn_examples\", \"data/all_validation_KWS_data_outputs_len_10102.npy\")\n", + "\n", + "input_data = np.load(input_npy)\n", + "golden_out_data = np.load(golden_out_npy)\n", + "num_samples = input_data.shape[0]\n", + "\n", + "print(\"Input data shape: \" + str(input_data.shape))\n", + "print(\"Label shape: \" + str(golden_out_data.shape))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Validate accuracy" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Accelerator output shape: (10102, 1)\n" + ] + } + ], + "source": [ + "accel.batch_size = num_samples\n", + "accel_out_data = accel.execute(input_data)\n", + "\n", + "print(\"Accelerator output shape: \" + str(accel_out_data.shape))" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Correctly predicted: 9070 / 10102 \n", + "Incorrectly predicted: 1032 / 10102 \n", + "Accuracy: 89.784201%\n" + ] + } + ], + "source": [ + "score = np.unique(accel_out_data.flatten() == golden_out_data.flatten(), return_counts=True)\n", + "print(\"Correctly predicted: %d / %d \" % (score[1][1], num_samples))\n", + "print(\"Incorrectly predicted: %d / %d \" % (score[1][0], num_samples))\n", + "print(\"Accuracy: %f%%\" % (100.0 * score[1][1] / num_samples))" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, "outputs": [], - "metadata": {} + "source": [ + "def run_validation():\n", + " accel_out_data = accel.execute(input_data)" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "5 loops, best of 3: 69 ms per loop\n" + ] + } + ], + "source": [ + "full_validation_time = %timeit -n 5 -o run_validation()" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "146301.715477 images per second including data movement\n" + ] + } + ], + "source": [ + "print(\"%f images per second including data movement\" % (num_samples / float(full_validation_time.best)))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Run built-in performance benchmark" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'DRAM_in_bandwidth[Mb/s]': 121.19740179165815,\n", + " 'DRAM_out_bandwidth[Mb/s]': 0.24734163630950642,\n", + " 'batch_size': 10102,\n", + " 'copy_input_data_to_device[ms]': 26.500940322875977,\n", + " 'copy_output_data_from_device[ms]': 0.23293495178222656,\n", + " 'fclk[mhz]': 100.0,\n", + " 'fold_input[ms]': 0.16808509826660156,\n", + " 'pack_input[ms]': 0.1747608184814453,\n", + " 'runtime[ms]': 40.842294692993164,\n", + " 'throughput[images/s]': 247341.63630950643,\n", + " 'unfold_output[ms]': 0.19407272338867188,\n", + " 'unpack_output[ms]': 1.2056827545166016}" + ] + }, + "execution_count": 36, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "accel.throughput_test()" + ] } ], "metadata": { @@ -58,4 +280,4 @@ }, "nbformat": 4, "nbformat_minor": 2 -} \ No newline at end of file +} From f20aad07db2fa9d429120ca5c23033911e5ba4f0 Mon Sep 17 00:00:00 2001 From: Yaman Umuroglu Date: Wed, 3 Nov 2021 13:59:38 +0100 Subject: [PATCH 30/49] update zipfile link for Pynq-Z1 --- finn_examples/bitfiles/bitfiles.zip.link | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/finn_examples/bitfiles/bitfiles.zip.link b/finn_examples/bitfiles/bitfiles.zip.link index 1a8d6cf..ccafcbc 100644 --- a/finn_examples/bitfiles/bitfiles.zip.link +++ b/finn_examples/bitfiles/bitfiles.zip.link @@ -1,7 +1,7 @@ { "Pynq-Z1": { - "url": "https://github.com/Xilinx/finn-examples/releases/download/binary-cop/Pynq-Z1.zip", - "md5sum": "8d36644dfa90711767e979c1a437b46d" + "url": "https://github.com/Xilinx/finn-examples/releases/download/kws/Pynq-Z1.zip", + "md5sum": "9d558be328ccc1194b0381d1009a5718" }, "Pynq-Z2": { "url": "https://github.com/Xilinx/finn-examples/releases/download/v0.0.1a/Pynq-Z2.zip", From 54275a4ce1d6fdc4bf4c249850926b33121086ef Mon Sep 17 00:00:00 2001 From: Mirza Mrahorovic Date: Wed, 3 Nov 2021 13:56:15 +0000 Subject: [PATCH 31/49] reverted sequence of to_hls transformations --- build/resnet50/custom_steps.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/build/resnet50/custom_steps.py b/build/resnet50/custom_steps.py index 01431f4..86484eb 100644 --- a/build/resnet50/custom_steps.py +++ b/build/resnet50/custom_steps.py @@ -230,19 +230,18 @@ def step_resnet50_convert_to_hls(model: ModelWrapper, cfg: DataflowBuildConfig): model = model.transform(SortGraph()) to_hls_transformations = [ - LowerConvsToMatMul, - AbsorbConsecutiveTransposes, - AbsorbTransposeIntoMultiThreshold, - AbsorbConsecutiveTransposes, to_hls.InferAddStreamsLayer, + LowerConvsToMatMul, to_hls.InferChannelwiseLinearLayer, to_hls.InferPool_Batch, + AbsorbTransposeIntoMultiThreshold, + RoundAndClipThresholds, to_hls.InferQuantizedStreamingFCLayer, to_hls.InferThresholdingLayer, + AbsorbConsecutiveTransposes, to_hls.InferConvInpGen, to_hls.InferDuplicateStreamsLayer, - to_hls.InferLabelSelectLayer, - + to_hls.InferLabelSelectLayer ] for trn in to_hls_transformations: model = model.transform(trn()) From 5cbfa83a6ec4e251d46fb77d36338aef7b2bc313 Mon Sep 17 00:00:00 2001 From: Yaman Umuroglu Date: Wed, 3 Nov 2021 15:14:41 +0100 Subject: [PATCH 32/49] change nb prefix --- .../{4_radioml_with_cnns.ipynb => 5_radioml_with_cnns.ipynb} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename finn_examples/notebooks/{4_radioml_with_cnns.ipynb => 5_radioml_with_cnns.ipynb} (100%) diff --git a/finn_examples/notebooks/4_radioml_with_cnns.ipynb b/finn_examples/notebooks/5_radioml_with_cnns.ipynb similarity index 100% rename from finn_examples/notebooks/4_radioml_with_cnns.ipynb rename to finn_examples/notebooks/5_radioml_with_cnns.ipynb From 82acc9df9596917a52f47715cbcf2712a51fa636 Mon Sep 17 00:00:00 2001 From: Hendrik Borras Date: Thu, 4 Nov 2021 10:45:18 +0000 Subject: [PATCH 33/49] Updated KWS build to use model with python_speech_features pre-processing. --- build/kws/build.py | 4 +--- build/kws/input.npy | Bin 2088 -> 2088 bytes 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/build/kws/build.py b/build/kws/build.py index af22cc4..17e6079 100644 --- a/build/kws/build.py +++ b/build/kws/build.py @@ -63,12 +63,10 @@ def step_preprocess(model: ModelWrapper, cfg: DataflowBuildConfig): build_cfg.VerificationStepType.TIDY_UP_PYTHON, build_cfg.VerificationStepType.STREAMLINED_PYTHON, build_cfg.VerificationStepType.FOLDED_HLS_CPPSIM, - # build_cfg.VerificationStepType.STITCHED_IP_RTLSIM, # Fails with timeout ] model_name = ( - "MLP_W3A3_scale_init-0.1_no_per_channel_" - "scaling_at_output_usigned_non-narrow_relu_act_QONNX" + "MLP_W3A3_python_speech_features_pre-processing_QONNX" ) model_file = model_name + ".onnx" diff --git a/build/kws/input.npy b/build/kws/input.npy index 97fe531335aea0e5656794526ed3421cc154dbba..d25736222759ec8da885e3793d0d11054c4a2049 100644 GIT binary patch literal 2088 zcmb7F`!|(&A3bpla!J%tBXY{?I71B~iF3Z+r<7tyS4xv{ry(4n3ok>85@iY{x1{9O zW!$o+=kqyFBe!ZK^A@?K(9JZ3bQ!&``4ir~_Ah&{z1Ci9|FVB}-Rk1DeFiU@cTnW# zAL%O-tuz$b2Uv;B3`GH9vb{3zJzillKmULHEwU*8X*)8=JKTR-npl__{zG#!Ln~Xc znPHsa|Bsn7-d*HQ9oAqDji=Jnr~PTBhc-Q)u7yUX_V_kL84lOXz?GWmY~RTe?(`~s z#-J#M8g1A{#d>1+x0W4FRZAsK;>b3=`JTDBA(7lmVOQP zmwVxsh8JmY-$WEAJ3-B(l6!Tcj{c&ZNVD0yWY)~gn>!z7vjW>%n8=oaTJ2(Nb(x6| zysNk^p&WHe@ukM`?Zm|CB^%>rhjTL9AT{r-l<#p$YF?NmZ7rzcG{$(0!ut~17uZb7 zReAJ*UNhnKrGctvGVF?&kTkfbL(5mCoVtM$)3q{^R;LdVov$uS6+&D{SydY--t$B6 zjzM(v6CTM?TEbXsOxT!LE2}<;>(fzzB4p=I(d6uT^{@w~MD(Dq$ z`@D{RPEe++hL4km`_EWGv_zU8t4$2Ow86~h1ThHD;6jErbH3$`r14{lu;G2j*BHVG7&U(RmZiki*}BX~G*A7^jZhffx|3=F|K$ zG2GO9U|Pgtrq14xWTfig(!@M0f6n3ye{I}291aIWZPHfND9&~SnP$*tbcJ%VZ|EoZ ze9IkwMp!VJ3@%5K7+^x8pUNhsIN)Y{j0lZ{^F086#d6%3AjhlL<`?>UL!| zN=hG-?y2vo-EC8pX%TdtQs$J+U75|HDP-G>QF2GefmnYrg&n&csCirvo&1!EH%8ph zH%P$A_60KKzFB0^WG>sd-kyFOa3pc^_4J5!B|Z1d0nf!;MdQ&$oVU{t%pKQ{_;fuG3mSG&-_%RJMlrLd%unFf79M8O$Cy?b+0;1_zO0V~}5O24y;VGj{ zJ5LS4xTq2Zqbs!EwK6&28AO}z9)S=~id_~>M5|^2_De4M`)lgVJND9WkPDAHBj{(5ayjHTjs7dKB6>rI8fgHzXlp84ByB z;8j5|@vuqc0_LVL#?Hai%)%UfN2;Ye2b#d|FCl(Wc?&`4Oz>kW?aU41GFNyqrEwK# z^MT+jO%>YMJRjRXoP?|;%c$@E3*h(1Bs;%+2dBQdjB2Im$}5Zc^wj z8dxr)lk+=R@uFb}IUT{NUAaZ?y7Zx$z?=Sg=qSzXYR9Lg8}Y-MWXYJ1K7^m>2EI!Y z=N_uTIPP1I+sApdGB<}HW@KgTJQ#aut7=+6j`V=!F}deJho`dHkB)8T<|Axc$ohsd1V;-_*wb4;h8! AUjP6A literal 2088 zcmb7&`9GHF9)KA#vPQB*&3i_A5kgXy_x|1wm5_R?lcHoxR3}PNqveS9PAH-hSz6GJ zEb-po=P9ByoGDbYM93B?EjnqMGxH~$>vR2bUCB#Vc}acb<)Y>Gh&P1n2#ypxip0(v z?Zg%$@y3YAosogz{t=NILjL-HkBkcWbMFWX+!pd@n%Y>1{?gh)WanUJA=)SU|4~U8 zY7sP(=1~z*r8cQgK<6RCMZd$iuEthEQ-6w+5-EX158TTZ1=Cur{Y>zMnjK~V`Wco?yrN7Vl|=_RYR_|{*1wX z6EME`5(Y3ibiSL)Ao;Z*1P#I-{~=J`ZUs&|Qd!?BL(F&UB5N0vGnYnFa&m$qDwGTg zatHnkwv!p;t2}@TtzhtN^Jix~e4TBs*0avs5PY4_p~?C&A!nW*H7#fdz0wR)){;ar zy-O?NJdH81ZX-Ty^k$7K=d+NycS3&RFuW)og;qaXa_@i&$TB_HN23L}K69KrZl4N& zBw6AK_cubcVjY}*qe;^t5=@U)5a)pe5^Zsqb!Yu1J4`m<`zxV1Lp&lVRX&A3`X*4X zv;??NoJ-mtC1Sm*EpEw~PHNUFk)j$SQq%EP&`X#>bH2`|dh1=G>O(e|dF}=6%mb{T zpJ(!U5yZOgDvQ|gQn+-&ls;Y44@Os(z%mm{(yjQ2eEDFBx`v<8r~5e0_&t$Xw!Rcn zCc08GcOU)NwC|91&5MkfH!<^N=kWXBZ9HY=D{HboEBT=KMwn!%OQTnI!SVi3$p5Sj zL36Ll)RhcKg@}<$!<6mXs}B3q(}Wv^nw-a{8tRfKgF8iqr1ydh7fB!DSVk*blgA<7 za)jA-2MXD{thmVvkEy4-GCjTbzN~XJ6&*!W_~^NZaH~-PQ(e6c6jUU_h>i^xuTVuF z1!ckIj(XXSrOkM|WFo(fcwqo)NDN&(U{3d3!OG8uGw!`XAAT%^>i7h*EjI>R1sC4P zL5!NVMUv2yW$@HjQ7|wNahuPl({mD28a{qNV)0`l8lfMr8{5D}9qL)`(idP{rN;+N zdP_~U57L#-V(8kG9&B`t=I=Rnu>NzFFg1S?9y;PklO&eh40$#Yw|?$>EdJJ?_!R%%43iy(V~OpNl0@e*<+98T=wNOYP0PMF+MLx zPKRbmg53?!*XAkw`_wCV*^-2johQ(6wwPNGmO!6Z+Yr@XGoZ(*1bz?o!G~NrxLnhs z55^@pI+}n5!(%k_WxYuAn7l|8Dy*(Y(?9%BW9i&E^ z^r1%nxGX!Y1KjdN;GNR}zCmlKnLb7FiD~?-kIt0IF}mD75!SZNl&uWXrD`6115F_3+f1)sFa>f>8NSCl(YWgKP%)rGN);Y~n?(|9GBe_r&ko0v zVM?4ZvkbJYL?Bktqq68`N!Cw$(b=UI6166w{0cX`RJnG+K-I2T zDAGybgP+agZpX}_3r4DNi;I!OE;SqjbmFjb36mYo$VcaDAMkXo;#I@!IakL4=vp?5 zf4a#F?~L3*yCDw@?u^B#%?fVt$N8PDrixU4u-<|19Jpl44tD&(d5nr_V;j@-@616c(HS3y72nCAGLSALBeZopjmnhZhdG&?pPa&_RWM9?W!0*qXOsMsuj8}YEqEa z!Fb|LQk=XVb{7}p!VWb)t?4J!(3|V5^Wz2#yw3{`+8)$z&lNbcdR(^4`W`tNppKJ6 zH{tSEf#k`jQ1(T>k5%hF7dp~JbWd{@7}qM1i1J2>`erZG->iqzd(NZ5TR9}}9P#m? oX5qPxHXVqcOuNt4LP?Ai()!{h;nFME2iSPpf&c&j From 9204fe3f73d089c4fece99bc83bf48e2517f763f Mon Sep 17 00:00:00 2001 From: Hendrik Borras Date: Thu, 4 Nov 2021 12:11:22 +0000 Subject: [PATCH 34/49] Updated KWS notebook for python_speech_featrues and added audio_samples. --- finn_examples/bitfiles/bitfiles.zip.link | 2 +- ..._validation_kws_data_preprocessed.zip.link | 6 +- finn_examples/data/audio_samples.zip.link | 4 + .../notebooks/4_keyword_spotting.ipynb | 86 ++++++++++++++++-- finn_examples/notebooks/images/mfcc_py.png | Bin 0 -> 6903 bytes 5 files changed, 88 insertions(+), 10 deletions(-) create mode 100644 finn_examples/data/audio_samples.zip.link create mode 100644 finn_examples/notebooks/images/mfcc_py.png diff --git a/finn_examples/bitfiles/bitfiles.zip.link b/finn_examples/bitfiles/bitfiles.zip.link index ccafcbc..79cc1aa 100644 --- a/finn_examples/bitfiles/bitfiles.zip.link +++ b/finn_examples/bitfiles/bitfiles.zip.link @@ -1,7 +1,7 @@ { "Pynq-Z1": { "url": "https://github.com/Xilinx/finn-examples/releases/download/kws/Pynq-Z1.zip", - "md5sum": "9d558be328ccc1194b0381d1009a5718" + "md5sum": "bf1df783bae7a1a477797d2eaa61eb9f" }, "Pynq-Z2": { "url": "https://github.com/Xilinx/finn-examples/releases/download/v0.0.1a/Pynq-Z2.zip", diff --git a/finn_examples/data/all_validation_kws_data_preprocessed.zip.link b/finn_examples/data/all_validation_kws_data_preprocessed.zip.link index f5db5f2..1992b00 100644 --- a/finn_examples/data/all_validation_kws_data_preprocessed.zip.link +++ b/finn_examples/data/all_validation_kws_data_preprocessed.zip.link @@ -2,5 +2,7 @@ "url": "https://github.com/Xilinx/finn-examples/releases/download/kws/all_validation_kws_data_preprocessed.zip", "md5sum": "bb314d1aeff7a822a00bc3d98fbf05f7" } - - +{ + "url": "https://github.com/Xilinx/finn-examples/releases/download/kws/python_speech_preprocessing_all_validation_kws_data.zip", + "md5sum": "58d1435354c7ac7ba5ef9bdf5e2b7210" +} diff --git a/finn_examples/data/audio_samples.zip.link b/finn_examples/data/audio_samples.zip.link new file mode 100644 index 0000000..2b8e06e --- /dev/null +++ b/finn_examples/data/audio_samples.zip.link @@ -0,0 +1,4 @@ +{ + "url": "https://github.com/Xilinx/finn-examples/releases/download/kws/audio_samples.zip", + "md5sum": "e1fd31a78001c9d1d9a4ab53283ca5ce" +} \ No newline at end of file diff --git a/finn_examples/notebooks/4_keyword_spotting.ipynb b/finn_examples/notebooks/4_keyword_spotting.ipynb index 9c1f833..90c1ba7 100644 --- a/finn_examples/notebooks/4_keyword_spotting.ipynb +++ b/finn_examples/notebooks/4_keyword_spotting.ipynb @@ -91,11 +91,38 @@ "print(\"Expected output shape and datatype: %s %s\" % (str(accel.oshape_normal), str(accel.odt)))" ] }, + { + "cell_type": "markdown", + "source": [ + "# Validating network accuracy\n", + "In this first part we will be looking at the overall accuracy of the network.\n", + "\n", + "The keyword spotting (KWS) network was trained on the Google Speech Commands v2 dataset, as published here: https://arxiv.org/abs/1804.03209\n", + "\n", + "We then used a feature extraction technique called Mel Frequency Cepstral Coefficients or MFCC for short.\n", + "This method turns audio waveforms into 2D images with one channel. Similar to the one shown below:\n", + "\n", + "![MFCC features produced by python_speech_features](\"images/mfcc_py.png\")\n", + "\n", + "A more in-depth explenation of MFCC features can be found on wikipedia: https://en.wikipedia.org/wiki/Mel-frequency_cepstrum\n", + "\n", + "For this concrete case we used the python library [python_speech_featrues](https://github.com/jameslyons/python_speech_features) to produce these features.\n", + "\n", + "During the training of the KWS network we produce the MFCC features for the training and validation set and then quantize the inputs to the network to eight bit.\n", + "We will load the pre-processed and quantized validation dataset in the next step.\n" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + } + }, { "cell_type": "markdown", "metadata": {}, "source": [ - "# Load preprocessed Google Speech Commands v2 validation data" + "### Load preprocessed Google Speech Commands v2 validation dataset" ] }, { @@ -116,8 +143,8 @@ "import pkg_resources as pk\n", "import numpy as np\n", "\n", - "input_npy = pk.resource_filename(\"finn_examples\", \"data/all_validation_KWS_data_inputs_len_10102.npy\")\n", - "golden_out_npy = pk.resource_filename(\"finn_examples\", \"data/all_validation_KWS_data_outputs_len_10102.npy\")\n", + "input_npy = pk.resource_filename(\"finn_examples\", \"data/python_speech_preprocessing_all_validation_KWS_data_inputs_len_10102.npy\")\n", + "golden_out_npy = pk.resource_filename(\"finn_examples\", \"data/python_speech_preprocessing_all_validation_KWS_data_outputs_len_10102.npy\")\n", "\n", "input_data = np.load(input_npy)\n", "golden_out_data = np.load(golden_out_npy)\n", @@ -131,7 +158,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Validate accuracy" + "### Run validation on the FPGA" ] }, { @@ -176,6 +203,44 @@ "print(\"Accuracy: %f%%\" % (100.0 * score[1][1] / num_samples))" ] }, + { + "cell_type": "markdown", + "source": [ + "Here you should se an accuracy of about 88.76 %." + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "# Assessing network throughput\n", + "\n", + "Now we will take a look at how fast the FPGA can process the whole validation dataset." + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "### Using a naive timing benchmark from the notebook" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + } + }, { "cell_type": "code", "execution_count": 33, @@ -217,14 +282,21 @@ } ], "source": [ - "print(\"%f images per second including data movement\" % (num_samples / float(full_validation_time.best)))" + "print(f\"{(num_samples / float(full_validation_time.best)):.0f} samples per second including data movement\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "# Run built-in performance benchmark" + "While the result of over 140 thousand inferences per second is already very good, this naive benchmark\n", + "also includes data movement from and to the FPGA and it is dificult to assess how much time is spent on\n", + "which part of running the FINN accelerator.\n", + "\n", + "### Using the built-in performance benchmark\n", + "\n", + "To measure the performance of indivudual components of the PYNQ stack and the FINN accelerator on the FPGA,\n", + "FINN comes with a buit-in benchmark. This benchmark computes the throughput of the FINN accelerator as seen on the FPGA." ] }, { @@ -280,4 +352,4 @@ }, "nbformat": 4, "nbformat_minor": 2 -} +} \ No newline at end of file diff --git a/finn_examples/notebooks/images/mfcc_py.png b/finn_examples/notebooks/images/mfcc_py.png new file mode 100644 index 0000000000000000000000000000000000000000..7f24aa89a33bd6a36fb2eaac30a3db14a91eb6e9 GIT binary patch literal 6903 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 literal 0 HcmV?d00001 From 5646cc5a2cc3cd3ca5f4b2900e3e280d3bf5814b Mon Sep 17 00:00:00 2001 From: Hendrik Borras Date: Thu, 4 Nov 2021 12:14:21 +0000 Subject: [PATCH 35/49] Updated KWS build and data download links. --- build/kws/get-kws-data-model.sh | 4 ++-- .../data/all_validation_kws_data_preprocessed.zip.link | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build/kws/get-kws-data-model.sh b/build/kws/get-kws-data-model.sh index 61a54a4..50c2314 100755 --- a/build/kws/get-kws-data-model.sh +++ b/build/kws/get-kws-data-model.sh @@ -28,5 +28,5 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # Download validation data and model -wget https://github.com/Xilinx/finn-examples/releases/download/kws/all_validation_KWS_data.npz -wget https://github.com/Xilinx/finn-examples/releases/download/kws/MLP_W3A3_scale_init-0.1_no_per_channel_scaling_at_output_usigned_non-narrow_relu_act_QONNX.onnx +wget https://github.com/Xilinx/finn-examples/releases/download/kws/python_speech_preprocessing_all_validation_KWS_data.npz +wget https://github.com/Xilinx/finn-examples/releases/download/kws/MLP_W3A3_python_speech_features_pre-processing_QONNX.onnx diff --git a/finn_examples/data/all_validation_kws_data_preprocessed.zip.link b/finn_examples/data/all_validation_kws_data_preprocessed.zip.link index 1992b00..e2961e8 100644 --- a/finn_examples/data/all_validation_kws_data_preprocessed.zip.link +++ b/finn_examples/data/all_validation_kws_data_preprocessed.zip.link @@ -3,6 +3,6 @@ "md5sum": "bb314d1aeff7a822a00bc3d98fbf05f7" } { - "url": "https://github.com/Xilinx/finn-examples/releases/download/kws/python_speech_preprocessing_all_validation_kws_data.zip", + "url": "https://github.com/Xilinx/finn-examples/releases/download/kws/all_validation_kws_data_preprocessed_py_speech.zip", "md5sum": "58d1435354c7ac7ba5ef9bdf5e2b7210" } From cd5eda0fb6941b26ff25f02177c47ca6b0573a74 Mon Sep 17 00:00:00 2001 From: Yaman Umuroglu Date: Thu, 4 Nov 2021 14:21:30 +0100 Subject: [PATCH 36/49] make PyPI publication trigger manually --- .github/workflows/python-publish.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index 9087804..763c70f 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -3,9 +3,7 @@ name: Upload Python Package -on: - release: - types: [created] +on: workflow_dispatch jobs: deploy: From ce89ca4894b4277999262381822e678210db1b54 Mon Sep 17 00:00:00 2001 From: Yaman Umuroglu Date: Thu, 4 Nov 2021 14:22:05 +0100 Subject: [PATCH 37/49] update download path for RadioML VGG10 ONNX model --- build/vgg10/README.md | 6 ++---- build/vgg10/models/download_vgg10.sh | 3 +-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/build/vgg10/README.md b/build/vgg10/README.md index 9ce5bcd..d83bb06 100755 --- a/build/vgg10/README.md +++ b/build/vgg10/README.md @@ -12,9 +12,7 @@ Due to the 1-dimensional topology in VGG10 we use a specialized build script tha 0. Ensure you have performed the *Setup* steps in the top-level README for setting up the FINN requirements and environment variables. -1. Download the pretrained VGG10 ONNX model from the releases page, and extract -the zipfile under `vgg10/models`. You should have e.g. `vgg10/models/radioml_w4a4_small_tidy.onnx` as a result. -You can use the provided `vgg10/models/download_vgg10.sh` script for this. +1. Run the `download_vgg10.sh` script under the `models` directory to download the pretrained VGG10 ONNX model. You should have e.g. `vgg10/models/radioml_w4a4_small_tidy.onnx` as a result. 2. Launch the build as follows: ```SHELL @@ -23,7 +21,7 @@ FINN_EXAMPLES=/path/to/finn-examples # cd into finn submodule cd $FINN_EXAMPLES/build/finn # launch the build on the vgg10 folder -./run-docker.sh build_custom /path/to/finn-examples/build/vgg10 +./run-docker.sh build_custom $FINN_EXAMPLES/build/vgg10 ``` 5. The generated outputs will be under `vgg10/output__`. You can find a description of the generated files [here](https://finn-dev.readthedocs.io/en/latest/command_line.html#simple-dataflow-build-mode). diff --git a/build/vgg10/models/download_vgg10.sh b/build/vgg10/models/download_vgg10.sh index 710e608..1d6bae6 100755 --- a/build/vgg10/models/download_vgg10.sh +++ b/build/vgg10/models/download_vgg10.sh @@ -1,4 +1,3 @@ #!/bin/sh -wget https://github.com/Xilinx/finn-examples/releases/download/*ToDo*/onnx-models-vgg10.zip -unzip onnx-models-vgg10.zip +wget https://github.com/Xilinx/finn-examples/releases/download/radioml/radioml_w4a4_small_tidy.onnx From fad96b7c5dd6d5c7fa22b13c091a0a437830db3d Mon Sep 17 00:00:00 2001 From: Yaman Umuroglu Date: Thu, 4 Nov 2021 14:28:42 +0100 Subject: [PATCH 38/49] vgg10 -> vgg10-radioml for more clarity --- build/{vgg10 => vgg10-radioml}/README.md | 4 ++-- build/{vgg10 => vgg10-radioml}/build.py | 0 build/{vgg10 => vgg10-radioml}/custom_steps.py | 0 .../folding_config/ZCU104_folding_config.json | 0 build/{vgg10 => vgg10-radioml}/models/download_vgg10.sh | 0 finn_examples/models.py | 2 +- 6 files changed, 3 insertions(+), 3 deletions(-) rename build/{vgg10 => vgg10-radioml}/README.md (88%) rename build/{vgg10 => vgg10-radioml}/build.py (100%) rename build/{vgg10 => vgg10-radioml}/custom_steps.py (100%) rename build/{vgg10 => vgg10-radioml}/folding_config/ZCU104_folding_config.json (100%) rename build/{vgg10 => vgg10-radioml}/models/download_vgg10.sh (100%) diff --git a/build/vgg10/README.md b/build/vgg10-radioml/README.md similarity index 88% rename from build/vgg10/README.md rename to build/vgg10-radioml/README.md index d83bb06..17a4524 100755 --- a/build/vgg10/README.md +++ b/build/vgg10-radioml/README.md @@ -12,7 +12,7 @@ Due to the 1-dimensional topology in VGG10 we use a specialized build script tha 0. Ensure you have performed the *Setup* steps in the top-level README for setting up the FINN requirements and environment variables. -1. Run the `download_vgg10.sh` script under the `models` directory to download the pretrained VGG10 ONNX model. You should have e.g. `vgg10/models/radioml_w4a4_small_tidy.onnx` as a result. +1. Run the `download_vgg10.sh` script under the `models` directory to download the pretrained VGG10 ONNX model. You should have e.g. `vgg10-radioml/models/radioml_w4a4_small_tidy.onnx` as a result. 2. Launch the build as follows: ```SHELL @@ -24,7 +24,7 @@ cd $FINN_EXAMPLES/build/finn ./run-docker.sh build_custom $FINN_EXAMPLES/build/vgg10 ``` -5. The generated outputs will be under `vgg10/output__`. You can find a description of the generated files [here](https://finn-dev.readthedocs.io/en/latest/command_line.html#simple-dataflow-build-mode). +5. The generated outputs will be under `vgg10-radioml/output__`. You can find a description of the generated files [here](https://finn-dev.readthedocs.io/en/latest/command_line.html#simple-dataflow-build-mode). ## Where did the ONNX model files come from? diff --git a/build/vgg10/build.py b/build/vgg10-radioml/build.py similarity index 100% rename from build/vgg10/build.py rename to build/vgg10-radioml/build.py diff --git a/build/vgg10/custom_steps.py b/build/vgg10-radioml/custom_steps.py similarity index 100% rename from build/vgg10/custom_steps.py rename to build/vgg10-radioml/custom_steps.py diff --git a/build/vgg10/folding_config/ZCU104_folding_config.json b/build/vgg10-radioml/folding_config/ZCU104_folding_config.json similarity index 100% rename from build/vgg10/folding_config/ZCU104_folding_config.json rename to build/vgg10-radioml/folding_config/ZCU104_folding_config.json diff --git a/build/vgg10/models/download_vgg10.sh b/build/vgg10-radioml/models/download_vgg10.sh similarity index 100% rename from build/vgg10/models/download_vgg10.sh rename to build/vgg10-radioml/models/download_vgg10.sh diff --git a/finn_examples/models.py b/finn_examples/models.py index d00563c..274af04 100644 --- a/finn_examples/models.py +++ b/finn_examples/models.py @@ -287,7 +287,7 @@ def resnet50_w1a2_imagenet(target_platform=None): def vgg10_w4a4_radioml(target_platform=None): target_platform = resolve_target_platform(target_platform) driver_mode = get_driver_mode() - model_name = "vgg10-w4a4" + model_name = "vgg10-radioml-w4a4" filename = find_bitfile(model_name, target_platform) fclk_mhz = 250.0 return FINNExampleOverlay( From a202c4a850db993269511299fc1a7a7103ea2546 Mon Sep 17 00:00:00 2001 From: Yaman Umuroglu Date: Thu, 4 Nov 2021 14:39:56 +0100 Subject: [PATCH 39/49] update ZCU104 bitfiles.zip link --- finn_examples/bitfiles/bitfiles.zip.link | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/finn_examples/bitfiles/bitfiles.zip.link b/finn_examples/bitfiles/bitfiles.zip.link index ccafcbc..0753bb5 100644 --- a/finn_examples/bitfiles/bitfiles.zip.link +++ b/finn_examples/bitfiles/bitfiles.zip.link @@ -12,8 +12,8 @@ "md5sum": "59598d7f36ffdc74a0a0262f5b67423c" }, "ZCU104": { - "url": "https://github.com/Xilinx/finn-examples/releases/download/mnv1-zcu104/ZCU104.zip", - "md5sum": "1ed10d74e85eec70fd094b2947b5b8e3" + "url": "https://github.com/Xilinx/finn-examples/releases/download/radioml/ZCU104.zip", + "md5sum": "9b7edad0511da9cb3c834a289d6797a2" }, "xilinx_u250_xdma_201830_2": { "url": "https://github.com/Xilinx/finn-examples/releases/download/rn50-u250/xilinx_u250_xdma_201830_2.zip", From 40e625bcb819e2d620c53d8f884549eef895f483 Mon Sep 17 00:00:00 2001 From: Yaman Umuroglu Date: Thu, 4 Nov 2021 14:42:16 +0100 Subject: [PATCH 40/49] update FINN commit hash for building --- build/get-finn.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/get-finn.sh b/build/get-finn.sh index b5d29a6..a4a4485 100755 --- a/build/get-finn.sh +++ b/build/get-finn.sh @@ -30,7 +30,7 @@ # URL for git repo to be cloned REPO_URL=https://github.com/Xilinx/finn # commit hash for repo -REPO_COMMIT=918ba0084fee32e340274ad042811e24203de300 +REPO_COMMIT=36d5de9fc7f414f95e31a877e912e6c9e5ce3564 # directory (under the same folder as this script) to clone to REPO_DIR=finn From 1cedb5641920eb72e37b3eb9911b14721b66d6fc Mon Sep 17 00:00:00 2001 From: Hendrik Borras Date: Thu, 4 Nov 2021 14:25:35 +0000 Subject: [PATCH 41/49] Removed old validation data file. --- .../data/all_validation_kws_data_preprocessed.zip.link | 4 ---- 1 file changed, 4 deletions(-) diff --git a/finn_examples/data/all_validation_kws_data_preprocessed.zip.link b/finn_examples/data/all_validation_kws_data_preprocessed.zip.link index e2961e8..5071178 100644 --- a/finn_examples/data/all_validation_kws_data_preprocessed.zip.link +++ b/finn_examples/data/all_validation_kws_data_preprocessed.zip.link @@ -1,7 +1,3 @@ -{ - "url": "https://github.com/Xilinx/finn-examples/releases/download/kws/all_validation_kws_data_preprocessed.zip", - "md5sum": "bb314d1aeff7a822a00bc3d98fbf05f7" -} { "url": "https://github.com/Xilinx/finn-examples/releases/download/kws/all_validation_kws_data_preprocessed_py_speech.zip", "md5sum": "58d1435354c7ac7ba5ef9bdf5e2b7210" From 30c8e34f77c95db9c30146b7ab95cad4e466c6ea Mon Sep 17 00:00:00 2001 From: Hendrik Borras Date: Thu, 4 Nov 2021 14:59:09 +0000 Subject: [PATCH 42/49] Added KWS dataflow parent and renamed kws preprocessed data. --- ...> all_validation_kws_data_preprocessed_py_speech.zip.link} | 0 finn_examples/data/kws_dataflow_parent.link | 4 ++++ 2 files changed, 4 insertions(+) rename finn_examples/data/{all_validation_kws_data_preprocessed.zip.link => all_validation_kws_data_preprocessed_py_speech.zip.link} (100%) create mode 100644 finn_examples/data/kws_dataflow_parent.link diff --git a/finn_examples/data/all_validation_kws_data_preprocessed.zip.link b/finn_examples/data/all_validation_kws_data_preprocessed_py_speech.zip.link similarity index 100% rename from finn_examples/data/all_validation_kws_data_preprocessed.zip.link rename to finn_examples/data/all_validation_kws_data_preprocessed_py_speech.zip.link diff --git a/finn_examples/data/kws_dataflow_parent.link b/finn_examples/data/kws_dataflow_parent.link new file mode 100644 index 0000000..f47c6cc --- /dev/null +++ b/finn_examples/data/kws_dataflow_parent.link @@ -0,0 +1,4 @@ +{ + "url": "https://github.com/Xilinx/finn-examples/releases/download/kws/kws_dataflow_parent.zip", + "md5sum": "0c958a0175306cf8bb15fbcb3b048aee" +} \ No newline at end of file From c85b8b40108d35dd77189feb3cda82e97c19fc57 Mon Sep 17 00:00:00 2001 From: Hendrik Borras Date: Thu, 4 Nov 2021 15:54:51 +0000 Subject: [PATCH 43/49] Updated KWS notebook to classify .wav files. --- .../notebooks/4_keyword_spotting.ipynb | 491 ++++++++++++++---- 1 file changed, 384 insertions(+), 107 deletions(-) diff --git a/finn_examples/notebooks/4_keyword_spotting.ipynb b/finn_examples/notebooks/4_keyword_spotting.ipynb index 90c1ba7..8fc9af8 100644 --- a/finn_examples/notebooks/4_keyword_spotting.ipynb +++ b/finn_examples/notebooks/4_keyword_spotting.ipynb @@ -1,16 +1,78 @@ { "cells": [ + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "# Validating network accuracy\n", + "In this first part we will be looking at the overall accuracy of the network.\n", + "\n", + "The keyword spotting (KWS) network was trained on the Google Speech Commands v2 dataset, as published here: https://arxiv.org/abs/1804.03209\n", + "\n", + "We then used a feature extraction technique called Mel Frequency Cepstral Coefficients or MFCC for short.\n", + "This method turns audio waveforms into 2D images with one channel. Similar to the one shown below:\n", + "\n", + "\n", + "\n", + "A more in-depth explenation of MFCC features can be found on wikipedia: https://en.wikipedia.org/wiki/Mel-frequency_cepstrum\n", + "\n", + "For this concrete case we used the python library [python_speech_featrues](https://github.com/jameslyons/python_speech_features) to produce these features.\n", + "\n", + "During the training of the KWS network we produce the MFCC features for the training and validation set and then quantize the inputs to the network to eight bit.\n", + "We will load the pre-processed and quantized validation dataset in the next step.\n" + ] + }, { "cell_type": "markdown", "metadata": {}, "source": [ - "# Initialize the accelerator" + "### Load preprocessed Google Speech Commands v2 validation dataset" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Input data shape: (10102, 490)\n", + "Label shape: (10102,)\n" + ] + } + ], + "source": [ + "import pkg_resources as pk\n", + "import numpy as np\n", + "\n", + "input_npy = pk.resource_filename(\"finn_examples\", \"data/python_speech_preprocessing_all_validation_KWS_data_inputs_len_10102.npy\")\n", + "golden_out_npy = pk.resource_filename(\"finn_examples\", \"data/python_speech_preprocessing_all_validation_KWS_data_outputs_len_10102.npy\")\n", + "\n", + "input_data = np.load(input_npy)\n", + "golden_out_data = np.load(golden_out_npy)\n", + "num_samples = input_data.shape[0]\n", + "\n", + "print(\"Input data shape: \" + str(input_data.shape))\n", + "print(\"Label shape: \" + str(golden_out_data.shape))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Initialize the accelerator" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, "outputs": [ { "data": { @@ -65,7 +127,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ @@ -74,15 +136,15 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Expected input shape and datatype: (1, 490) DataType.INT8\n", - "Expected output shape and datatype: (1, 1) DataType.UINT8\n" + "Expected input shape and datatype: (1, 490) INT8\n", + "Expected output shape and datatype: (1, 1) UINT8\n" ] } ], @@ -91,69 +153,6 @@ "print(\"Expected output shape and datatype: %s %s\" % (str(accel.oshape_normal), str(accel.odt)))" ] }, - { - "cell_type": "markdown", - "source": [ - "# Validating network accuracy\n", - "In this first part we will be looking at the overall accuracy of the network.\n", - "\n", - "The keyword spotting (KWS) network was trained on the Google Speech Commands v2 dataset, as published here: https://arxiv.org/abs/1804.03209\n", - "\n", - "We then used a feature extraction technique called Mel Frequency Cepstral Coefficients or MFCC for short.\n", - "This method turns audio waveforms into 2D images with one channel. Similar to the one shown below:\n", - "\n", - "![MFCC features produced by python_speech_features](\"images/mfcc_py.png\")\n", - "\n", - "A more in-depth explenation of MFCC features can be found on wikipedia: https://en.wikipedia.org/wiki/Mel-frequency_cepstrum\n", - "\n", - "For this concrete case we used the python library [python_speech_featrues](https://github.com/jameslyons/python_speech_features) to produce these features.\n", - "\n", - "During the training of the KWS network we produce the MFCC features for the training and validation set and then quantize the inputs to the network to eight bit.\n", - "We will load the pre-processed and quantized validation dataset in the next step.\n" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%% md\n" - } - } - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Load preprocessed Google Speech Commands v2 validation dataset" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Input data shape: (10102, 490)\n", - "Label shape: (10102,)\n" - ] - } - ], - "source": [ - "import pkg_resources as pk\n", - "import numpy as np\n", - "\n", - "input_npy = pk.resource_filename(\"finn_examples\", \"data/python_speech_preprocessing_all_validation_KWS_data_inputs_len_10102.npy\")\n", - "golden_out_npy = pk.resource_filename(\"finn_examples\", \"data/python_speech_preprocessing_all_validation_KWS_data_outputs_len_10102.npy\")\n", - "\n", - "input_data = np.load(input_npy)\n", - "golden_out_data = np.load(golden_out_npy)\n", - "num_samples = input_data.shape[0]\n", - "\n", - "print(\"Input data shape: \" + str(input_data.shape))\n", - "print(\"Label shape: \" + str(golden_out_data.shape))" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -163,7 +162,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 5, "metadata": {}, "outputs": [ { @@ -183,16 +182,16 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Correctly predicted: 9070 / 10102 \n", - "Incorrectly predicted: 1032 / 10102 \n", - "Accuracy: 89.784201%\n" + "Correctly predicted: 8967 / 10102 \n", + "Incorrectly predicted: 1135 / 10102 \n", + "Accuracy: 88.764601%\n" ] } ], @@ -205,45 +204,42 @@ }, { "cell_type": "markdown", - "source": [ - "Here you should se an accuracy of about 88.76 %." - ], "metadata": { - "collapsed": false, "pycharm": { "name": "#%% md\n" } - } + }, + "source": [ + "Here you should se an accuracy of about 88.76 %." + ] }, { "cell_type": "markdown", - "source": [ - "# Assessing network throughput\n", - "\n", - "Now we will take a look at how fast the FPGA can process the whole validation dataset." - ], "metadata": { - "collapsed": false, "pycharm": { "name": "#%% md\n" } - } + }, + "source": [ + "# Assessing network throughput\n", + "\n", + "Now we will take a look at how fast the FPGA can process the whole validation dataset." + ] }, { "cell_type": "markdown", - "source": [ - "### Using a naive timing benchmark from the notebook" - ], "metadata": { - "collapsed": false, "pycharm": { "name": "#%% md\n" } - } + }, + "source": [ + "### Using a naive timing benchmark from the notebook" + ] }, { "cell_type": "code", - "execution_count": 33, + "execution_count": 7, "metadata": {}, "outputs": [], "source": [ @@ -253,14 +249,14 @@ }, { "cell_type": "code", - "execution_count": 34, + "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "5 loops, best of 3: 69 ms per loop\n" + "5 loops, best of 3: 70.2 ms per loop\n" ] } ], @@ -270,14 +266,14 @@ }, { "cell_type": "code", - "execution_count": 35, + "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "146301.715477 images per second including data movement\n" + "143976 samples per second including data movement\n" ] } ], @@ -301,27 +297,27 @@ }, { "cell_type": "code", - "execution_count": 36, + "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "{'DRAM_in_bandwidth[Mb/s]': 121.19740179165815,\n", - " 'DRAM_out_bandwidth[Mb/s]': 0.24734163630950642,\n", + "{'DRAM_in_bandwidth[Mb/s]': 121.27598463684475,\n", + " 'DRAM_out_bandwidth[Mb/s]': 0.24750200946294845,\n", " 'batch_size': 10102,\n", - " 'copy_input_data_to_device[ms]': 26.500940322875977,\n", - " 'copy_output_data_from_device[ms]': 0.23293495178222656,\n", + " 'copy_input_data_to_device[ms]': 29.246091842651367,\n", + " 'copy_output_data_from_device[ms]': 0.23031234741210938,\n", " 'fclk[mhz]': 100.0,\n", - " 'fold_input[ms]': 0.16808509826660156,\n", - " 'pack_input[ms]': 0.1747608184814453,\n", - " 'runtime[ms]': 40.842294692993164,\n", - " 'throughput[images/s]': 247341.63630950643,\n", - " 'unfold_output[ms]': 0.19407272338867188,\n", - " 'unpack_output[ms]': 1.2056827545166016}" + " 'fold_input[ms]': 0.1590251922607422,\n", + " 'pack_input[ms]': 0.1087188720703125,\n", + " 'runtime[ms]': 40.81583023071289,\n", + " 'throughput[images/s]': 247502.00946294848,\n", + " 'unfold_output[ms]': 0.1952648162841797,\n", + " 'unpack_output[ms]': 1.1382102966308594}" ] }, - "execution_count": 36, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } @@ -329,6 +325,287 @@ "source": [ "accel.throughput_test()" ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Classifying .wav files with the KWS network\n", + "\n", + "Now we are going to look at how to classify raw .wav files with the KWS network. We include some sample files with finn-examples, but in theory you can also classify your own recordings. To do this one can simply modify where to load the .wav file from. However, one needs to make sure that the file is shorter than one second.\n", + "\n", + "First we will install python_speech_features, to generate the MFCC features later on" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Collecting python_speech_features\n", + " Using cached python_speech_features-0.6-py3-none-any.whl\n", + "Installing collected packages: python-speech-features\n", + "Successfully installed python-speech-features-0.6\n", + "\u001B[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001B[0m\n" + ] + } + ], + "source": [ + "!pip install python_speech_features" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "%matplotlib inline" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "from python_speech_features import mfcc\n", + "import numpy as np\n", + "from scipy import signal\n", + "import scipy.io.wavfile as wav\n", + "from scipy.signal.windows import hann\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "# preprocessing parameters\n", + "tf_desired_samples = 16000\n", + "tf_window_size_samples = 480\n", + "tf_sample_rate = 16000\n", + "tf_window_size_ms = 30.\n", + "tf_window_stride_ms = 20.\n", + "tf_dct_coefficient_count = 10\n", + "\n", + "# Dataset parameter\n", + "tf_dataset_labels = ['down', 'go', 'left', 'no', 'off', 'on', 'right', 'stop', 'up', 'yes', 'SILENCE', 'UNKNOWN']" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "# Convenience functions\n", + "def py_speech_preprocessing(resampled_data, sample_rate,\n", + " tf_desired_samples=tf_desired_samples, \n", + " tf_window_size_samples=tf_window_size_samples, \n", + " tf_sample_rate=tf_sample_rate, \n", + " tf_window_size_ms=tf_window_size_ms, \n", + " tf_dct_coefficient_count=tf_dct_coefficient_count):\n", + " # Resample\n", + " num_target_samples = round(tf_sample_rate / sample_rate * len(raw_signal))\n", + " resampled_data = signal.resample(raw_signal, num_target_samples)\n", + " # Rescale\n", + " rescaled_data = resampled_data / np.max(resampled_data)\n", + " # Pad\n", + " padded_data = np.pad(rescaled_data, [[0, tf_desired_samples - rescaled_data.shape[-1]]], mode=\"constant\")\n", + " # Calculate MFCC features\n", + " nfft = int(2**np.ceil(np.log2(tf_window_size_samples)))\n", + " mfcc_feat_py = mfcc(padded_data, tf_sample_rate, \n", + " winlen = tf_window_size_ms / 1000.,\n", + " winstep = tf_window_stride_ms / 1000.,\n", + " numcep = tf_dct_coefficient_count,\n", + " nfilt = 40,\n", + " nfft = nfft,\n", + " lowfreq = 20.0,\n", + " highfreq = 4000.0,\n", + " winfunc=hann,\n", + " appendEnergy=False,\n", + " preemph=0.,\n", + " ceplifter=0.,\n", + " )\n", + " # Cut and transpose MFCC features\n", + " mfcc_feat_py = mfcc_feat_py[:-1,:].T\n", + " \n", + " return mfcc_feat_py\n", + "\n", + "\n", + "def quantize_input(mfcc_feat_py):\n", + " # Scaling\n", + " quant_mfcc_feat = (mfcc_feat_py*0.8298503756523132)\n", + " # Clamping & rounding\n", + " quant_mfcc_feat = np.where(quant_mfcc_feat > 127., 127., quant_mfcc_feat)\n", + " quant_mfcc_feat = np.where(quant_mfcc_feat < -127., -127., quant_mfcc_feat)\n", + " quant_mfcc_feat = np.round(quant_mfcc_feat)\n", + " quant_mfcc_feat = quant_mfcc_feat.astype(np.int8).reshape((1,490))\n", + " \n", + " return quant_mfcc_feat" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Loading and pre-processing the audio file\n", + "\n", + "The following sample files are included with finn-examples:" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "audio_sample_down.wav audio_sample_off.wav audio_sample_up.wav\r\n", + "audio_sample_go.wav audio_sample_on.wav audio_sample_yes.wav\r\n", + "audio_sample_left.wav audio_sample_right.wav\r\n", + "audio_sample_no.wav audio_sample_stop.wav\r\n" + ] + } + ], + "source": [ + "# Find sample files\n", + "audio_samples_folder = pk.resource_filename(\"finn_examples\", \"data/audio_samples/\")\n", + "!ls $audio_samples_folder" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Change the line below to load your own .wav file or to load a different sample file.\n", + "Make sure that the file is shorter than one second." + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [], + "source": [ + "# Read the audio wave file\n", + "rate, raw_signal = wav.read(f\"{audio_samples_folder}audio_sample_yes.wav\")" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/usr/lib/python3/dist-packages/scipy/signal/signaltools.py:2236: FutureWarning: Using a non-tuple sequence for multidimensional indexing is deprecated; use `arr[tuple(seq)]` instead of `arr[seq]`. In the future this will be interpreted as an array index, `arr[np.array(seq)]`, which will result either in an error or a different result.\n", + " Y[sl] = X[sl]\n", + "/usr/lib/python3/dist-packages/scipy/signal/signaltools.py:2238: FutureWarning: Using a non-tuple sequence for multidimensional indexing is deprecated; use `arr[tuple(seq)]` instead of `arr[seq]`. In the future this will be interpreted as an array index, `arr[np.array(seq)]`, which will result either in an error or a different result.\n", + " Y[sl] = X[sl]\n" + ] + } + ], + "source": [ + "# Run pre-processing\n", + "mfcc_feat_py = py_speech_preprocessing(raw_signal, rate)" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Plot the MFCC features\n", + "plt.matshow(mfcc_feat_py)\n", + "plt.colorbar()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [], + "source": [ + "# Quantize MFCC features\n", + "quant_mfcc_feat = quantize_input(mfcc_feat_py)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Classifying the pre-processed audio on the FPGA" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [], + "source": [ + "# Run inference on the FPGA\n", + "accel.batch_size = 1\n", + "res_acc = accel.execute(quant_mfcc_feat)" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The audio file was classified as: yes\n" + ] + } + ], + "source": [ + "res_label = tf_dataset_labels[res_acc[0,0].astype(np.int)]\n", + "print(f\"The audio file was classified as: {res_label}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If everything went well you should see the audio file being classified correctly.\n", + "\n", + "However,you may notice that the 'down' sample is wrongly classified as 'go'. This is likely a side effect of the KWS network being a very simple architecture. This means that the network works better for some classes than others." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { From c1cffbfc0f88b1a021938c07dc701f3d5dcb66dc Mon Sep 17 00:00:00 2001 From: Hendrik Borras Date: Thu, 4 Nov 2021 15:55:32 +0000 Subject: [PATCH 44/49] Removed unused dataflow parent file. --- finn_examples/data/kws_dataflow_parent.link | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 finn_examples/data/kws_dataflow_parent.link diff --git a/finn_examples/data/kws_dataflow_parent.link b/finn_examples/data/kws_dataflow_parent.link deleted file mode 100644 index f47c6cc..0000000 --- a/finn_examples/data/kws_dataflow_parent.link +++ /dev/null @@ -1,4 +0,0 @@ -{ - "url": "https://github.com/Xilinx/finn-examples/releases/download/kws/kws_dataflow_parent.zip", - "md5sum": "0c958a0175306cf8bb15fbcb3b048aee" -} \ No newline at end of file From 116220c803eb4acd5a33f5fc1fb719ce81319115 Mon Sep 17 00:00:00 2001 From: Yaman Umuroglu Date: Thu, 4 Nov 2021 18:52:50 +0100 Subject: [PATCH 45/49] minor fixes to notebooks --- .../notebooks/0_mnist_with_fc_networks.ipynb | 295 ++++++++-------- .../1_cifar10_with_cnv_networks.ipynb | 295 ++++++++-------- .../3_binarycop_mask_detection.ipynb | 327 +++++++++--------- .../notebooks/5_radioml_with_cnns.ipynb | 312 ++++++++--------- 4 files changed, 576 insertions(+), 653 deletions(-) diff --git a/finn_examples/notebooks/0_mnist_with_fc_networks.ipynb b/finn_examples/notebooks/0_mnist_with_fc_networks.ipynb index 3899427..a9d6cb7 100644 --- a/finn_examples/notebooks/0_mnist_with_fc_networks.ipynb +++ b/finn_examples/notebooks/0_mnist_with_fc_networks.ipynb @@ -2,112 +2,91 @@ "cells": [ { "cell_type": "markdown", - "metadata": {}, "source": [ "# Initialize the accelerator" - ] + ], + "metadata": {} }, { "cell_type": "code", "execution_count": 1, - "metadata": {}, + "source": [ + "from finn_examples import models\n", + "print(list(filter(lambda x: \"mnist\" in x, dir(models))))" + ], "outputs": [ { + "output_type": "display_data", "data": { - "application/javascript": [ - "\n", - "try {\n", - "require(['notebook/js/codecell'], function(codecell) {\n", - " codecell.CodeCell.options_default.highlight_modes[\n", - " 'magic_text/x-csrc'] = {'reg':[/^%%microblaze/]};\n", - " Jupyter.notebook.events.one('kernel_ready.Kernel', function(){\n", - " Jupyter.notebook.get_cells().map(function(cell){\n", - " if (cell.cell_type == 'code'){ cell.auto_highlight(); } }) ;\n", - " });\n", - "});\n", - "} catch (e) {};\n" - ] + "application/javascript": "\ntry {\nrequire(['notebook/js/codecell'], function(codecell) {\n codecell.CodeCell.options_default.highlight_modes[\n 'magic_text/x-csrc'] = {'reg':[/^%%microblaze/]};\n Jupyter.notebook.events.one('kernel_ready.Kernel', function(){\n Jupyter.notebook.get_cells().map(function(cell){\n if (cell.cell_type == 'code'){ cell.auto_highlight(); } }) ;\n });\n});\n} catch (e) {};\n" }, - "metadata": {}, - "output_type": "display_data" + "metadata": {} }, { + "output_type": "display_data", "data": { - "application/javascript": [ - "\n", - "try {\n", - "require(['notebook/js/codecell'], function(codecell) {\n", - " codecell.CodeCell.options_default.highlight_modes[\n", - " 'magic_text/x-csrc'] = {'reg':[/^%%pybind11/]};\n", - " Jupyter.notebook.events.one('kernel_ready.Kernel', function(){\n", - " Jupyter.notebook.get_cells().map(function(cell){\n", - " if (cell.cell_type == 'code'){ cell.auto_highlight(); } }) ;\n", - " });\n", - "});\n", - "} catch (e) {};\n" - ] + "application/javascript": "\ntry {\nrequire(['notebook/js/codecell'], function(codecell) {\n codecell.CodeCell.options_default.highlight_modes[\n 'magic_text/x-csrc'] = {'reg':[/^%%pybind11/]};\n Jupyter.notebook.events.one('kernel_ready.Kernel', function(){\n Jupyter.notebook.get_cells().map(function(cell){\n if (cell.cell_type == 'code'){ cell.auto_highlight(); } }) ;\n });\n});\n} catch (e) {};\n" }, - "metadata": {}, - "output_type": "display_data" + "metadata": {} }, { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "['_mnist_fc_io_shape_dict', 'tfc_w1a1_mnist', 'tfc_w1a2_mnist', 'tfc_w2a2_mnist']\n" ] } ], - "source": [ - "from finn_examples import models\n", - "print(list(filter(lambda x: \"mnist\" in x, dir(models))))" - ] + "metadata": {} }, { "cell_type": "code", "execution_count": 2, - "metadata": {}, - "outputs": [], "source": [ "accel = models.tfc_w1a1_mnist()" - ] + ], + "outputs": [], + "metadata": {} }, { "cell_type": "code", "execution_count": 3, - "metadata": {}, + "source": [ + "print(\"Expected input shape and datatype: %s %s\" % (str(accel.ishape_normal), str(accel.idt)))\n", + "print(\"Expected output shape and datatype: %s %s\" % (str(accel.oshape_normal), str(accel.odt)))" + ], "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "Expected input shape and datatype: (1, 784) DataType.UINT8\n", "Expected output shape and datatype: (1, 1) DataType.UINT8\n" ] } ], - "source": [ - "print(\"Expected input shape and datatype: %s %s\" % (str(accel.ishape_normal), str(accel.idt)))\n", - "print(\"Expected output shape and datatype: %s %s\" % (str(accel.oshape_normal), str(accel.odt)))" - ] + "metadata": {} }, { "cell_type": "markdown", - "metadata": {}, "source": [ "# Load the MNIST dataset\n", "\n", "Use the `dataset_loading` package to get easy Python access to MNIST dataset:" - ] + ], + "metadata": {} }, { "cell_type": "code", "execution_count": 4, - "metadata": {}, + "source": [ + "from dataset_loading import mnist\n", + "trainx, trainy, testx, testy, valx, valy = mnist.load_mnist_data(\"/tmp\", download=True, one_hot=False)" + ], "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "Looking for Train Imgs\n", "Download URL: http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz\n", @@ -128,171 +107,158 @@ ] } ], - "source": [ - "from dataset_loading import mnist\n", - "trainx, trainy, testx, testy, valx, valy = mnist.load_mnist_data(\"/tmp\", download=True, one_hot=False)" - ] + "metadata": {} }, { "cell_type": "code", "execution_count": 5, - "metadata": {}, + "source": [ + "testx.shape" + ], "outputs": [ { + "output_type": "execute_result", "data": { "text/plain": [ "(10000, 28, 28, 1)" ] }, - "execution_count": 5, "metadata": {}, - "output_type": "execute_result" + "execution_count": 5 } ], - "source": [ - "testx.shape" - ] + "metadata": {} }, { "cell_type": "markdown", - "metadata": {}, "source": [ "# Classify a single image" - ] + ], + "metadata": {} }, { "cell_type": "code", "execution_count": 6, - "metadata": {}, - "outputs": [], "source": [ "test_single_x = testx[0].reshape(28, 28)\n", "test_single_y = testy[0]" - ] + ], + "outputs": [], + "metadata": {} }, { "cell_type": "code", "execution_count": 8, - "metadata": {}, + "source": [ + "%matplotlib inline\n", + "from matplotlib import pyplot as plt\n", + "\n", + "plt.imshow(test_single_x, cmap='gray')\n", + "plt.show()" + ], "outputs": [ { + "output_type": "display_data", "data": { - "image/png": "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\n", + "image/png": "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", "text/plain": [ "" ] }, - "metadata": {}, - "output_type": "display_data" + "metadata": {} } ], - "source": [ - "from matplotlib import pyplot as plt\n", - "\n", - "plt.imshow(test_single_x, cmap='gray')\n", - "plt.show()" - ] + "metadata": {} }, { "cell_type": "code", "execution_count": 9, - "metadata": {}, + "source": [ + "print(\"Expected class is %d\" % test_single_y)" + ], "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "Expected class is 7\n" ] } ], - "source": [ - "print(\"Expected class is %d\" % test_single_y)" - ] + "metadata": {} }, { "cell_type": "code", "execution_count": 10, - "metadata": {}, + "source": [ + "accel_in = test_single_x.reshape(accel.ishape_normal)\n", + "print(\"Input buffer shape is %s and datatype is %s\" % (str(accel_in.shape), str(accel_in.dtype)))" + ], "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "Input buffer shape is (1, 784) and datatype is uint8\n" ] } ], - "source": [ - "accel_in = test_single_x.reshape(accel.ishape_normal)\n", - "print(\"Input buffer shape is %s and datatype is %s\" % (str(accel_in.shape), str(accel_in.dtype)))" - ] + "metadata": {} }, { "cell_type": "code", "execution_count": 11, - "metadata": {}, - "outputs": [], "source": [ "accel_out = accel.execute(accel_in)" - ] + ], + "outputs": [], + "metadata": {} }, { "cell_type": "code", "execution_count": 12, - "metadata": {}, + "source": [ + "print(\"Returned class is %d\" % accel_out)" + ], "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "Returned class is 7\n" ] } ], - "source": [ - "print(\"Returned class is %d\" % accel_out)" - ] + "metadata": {} }, { "cell_type": "code", "execution_count": 13, - "metadata": {}, + "source": [ + "%%timeit\n", + "accel_out = accel.execute(accel_in)" + ], "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "1000 loops, best of 3: 808 µs per loop\n" ] } ], - "source": [ - "%%timeit\n", - "accel_out = accel.execute(accel_in)" - ] + "metadata": {} }, { "cell_type": "markdown", - "metadata": {}, "source": [ "# Validate accuracy on entire MNIST test set" - ] + ], + "metadata": {} }, { "cell_type": "code", "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Ready to run validation, test images tensor has shape (10, 1000, 784)\n", - "Accelerator buffer shapes are (1000, 1, 784) for input, (1000, 1, 1) for output\n" - ] - } - ], "source": [ "import numpy as np\n", "batch_size = 1000\n", @@ -305,16 +271,38 @@ "obuf_normal = np.empty_like(accel.obuf_packed_device)\n", "print(\"Ready to run validation, test images tensor has shape %s\" % str(batch_imgs.shape))\n", "print(\"Accelerator buffer shapes are %s for input, %s for output\" % (str(accel.ishape_packed), str(accel.oshape_packed)) )" - ] + ], + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Ready to run validation, test images tensor has shape (10, 1000, 784)\n", + "Accelerator buffer shapes are (1000, 1, 784) for input, (1000, 1, 1) for output\n" + ] + } + ], + "metadata": {} }, { "cell_type": "code", "execution_count": 22, - "metadata": {}, + "source": [ + "ok = 0\n", + "nok = 0\n", + "for i in range(n_batches):\n", + " ibuf_normal = batch_imgs[i].reshape(accel.ishape_normal)\n", + " exp = batch_labels[i]\n", + " obuf_normal = accel.execute(ibuf_normal)\n", + " ret = np.bincount(obuf_normal.flatten() == exp.flatten())\n", + " nok += ret[0]\n", + " ok += ret[1]\n", + " print(\"batch %d / %d : total OK %d NOK %d\" % (i, n_batches, ok, nok))" + ], "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "batch 0 / 10 : total OK 913 NOK 87\n", "batch 1 / 10 : total OK 1800 NOK 200\n", @@ -329,97 +317,89 @@ ] } ], - "source": [ - "ok = 0\n", - "nok = 0\n", - "for i in range(n_batches):\n", - " ibuf_normal = batch_imgs[i].reshape(accel.ishape_normal)\n", - " exp = batch_labels[i]\n", - " obuf_normal = accel.execute(ibuf_normal)\n", - " ret = np.bincount(obuf_normal.flatten() == exp.flatten())\n", - " nok += ret[0]\n", - " ok += ret[1]\n", - " print(\"batch %d / %d : total OK %d NOK %d\" % (i, n_batches, ok, nok))" - ] + "metadata": {} }, { "cell_type": "code", "execution_count": 23, - "metadata": {}, + "source": [ + "acc = 100.0 * ok / (total)\n", + "print(\"Final accuracy: {}%\".format(acc))" + ], "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "Final accuracy: 92.96%\n" ] } ], - "source": [ - "acc = 100.0 * ok / (total)\n", - "print(\"Final accuracy: {}%\".format(acc))" - ] + "metadata": {} }, { "cell_type": "code", "execution_count": 26, - "metadata": {}, - "outputs": [], "source": [ "def run_validation():\n", " for i in range(n_batches):\n", " ibuf_normal = batch_imgs[i].reshape(accel.ishape_normal)\n", " exp = batch_labels[i]\n", " accel.execute(ibuf_normal)" - ] + ], + "outputs": [], + "metadata": {} }, { "cell_type": "code", "execution_count": 27, - "metadata": {}, + "source": [ + "full_validation_time = %timeit -n 5 -o run_validation()" + ], "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "5 loops, best of 3: 22.6 ms per loop\n" ] } ], - "source": [ - "full_validation_time = %timeit -n 5 -o run_validation()" - ] + "metadata": {} }, { "cell_type": "code", "execution_count": 28, - "metadata": {}, + "source": [ + "print(\"%f images per second including data movement\" % (total / float(full_validation_time.best)))" + ], "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "441567.114603 images per second including data movement\n" ] } ], - "source": [ - "print(\"%f images per second including data movement\" % (total / float(full_validation_time.best)))" - ] + "metadata": {} }, { "cell_type": "markdown", - "metadata": {}, "source": [ "## Run some more built-in benchmarks" - ] + ], + "metadata": {} }, { "cell_type": "code", "execution_count": 29, - "metadata": {}, + "source": [ + "accel.throughput_test()" + ], "outputs": [ { + "output_type": "execute_result", "data": { "text/plain": [ "{'DRAM_in_bandwidth[Mb/s]': 656.2231762123328,\n", @@ -436,21 +416,18 @@ " 'unpack_output[ms]': 0.0006036758422851562}" ] }, - "execution_count": 29, "metadata": {}, - "output_type": "execute_result" + "execution_count": 29 } ], - "source": [ - "accel.throughput_test()" - ] + "metadata": {} }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "source": [], "outputs": [], - "source": [] + "metadata": {} } ], "metadata": { @@ -474,4 +451,4 @@ }, "nbformat": 4, "nbformat_minor": 2 -} +} \ No newline at end of file diff --git a/finn_examples/notebooks/1_cifar10_with_cnv_networks.ipynb b/finn_examples/notebooks/1_cifar10_with_cnv_networks.ipynb index 9f6a6f1..af305ff 100644 --- a/finn_examples/notebooks/1_cifar10_with_cnv_networks.ipynb +++ b/finn_examples/notebooks/1_cifar10_with_cnv_networks.ipynb @@ -2,112 +2,91 @@ "cells": [ { "cell_type": "markdown", - "metadata": {}, "source": [ "# Initialize the accelerator" - ] + ], + "metadata": {} }, { "cell_type": "code", "execution_count": 1, - "metadata": {}, + "source": [ + "from finn_examples import models\n", + "print(list(filter(lambda x: \"cifar10\" in x, dir(models))))" + ], "outputs": [ { + "output_type": "display_data", "data": { - "application/javascript": [ - "\n", - "try {\n", - "require(['notebook/js/codecell'], function(codecell) {\n", - " codecell.CodeCell.options_default.highlight_modes[\n", - " 'magic_text/x-csrc'] = {'reg':[/^%%microblaze/]};\n", - " Jupyter.notebook.events.one('kernel_ready.Kernel', function(){\n", - " Jupyter.notebook.get_cells().map(function(cell){\n", - " if (cell.cell_type == 'code'){ cell.auto_highlight(); } }) ;\n", - " });\n", - "});\n", - "} catch (e) {};\n" - ] + "application/javascript": "\ntry {\nrequire(['notebook/js/codecell'], function(codecell) {\n codecell.CodeCell.options_default.highlight_modes[\n 'magic_text/x-csrc'] = {'reg':[/^%%microblaze/]};\n Jupyter.notebook.events.one('kernel_ready.Kernel', function(){\n Jupyter.notebook.get_cells().map(function(cell){\n if (cell.cell_type == 'code'){ cell.auto_highlight(); } }) ;\n });\n});\n} catch (e) {};\n" }, - "metadata": {}, - "output_type": "display_data" + "metadata": {} }, { + "output_type": "display_data", "data": { - "application/javascript": [ - "\n", - "try {\n", - "require(['notebook/js/codecell'], function(codecell) {\n", - " codecell.CodeCell.options_default.highlight_modes[\n", - " 'magic_text/x-csrc'] = {'reg':[/^%%pybind11/]};\n", - " Jupyter.notebook.events.one('kernel_ready.Kernel', function(){\n", - " Jupyter.notebook.get_cells().map(function(cell){\n", - " if (cell.cell_type == 'code'){ cell.auto_highlight(); } }) ;\n", - " });\n", - "});\n", - "} catch (e) {};\n" - ] + "application/javascript": "\ntry {\nrequire(['notebook/js/codecell'], function(codecell) {\n codecell.CodeCell.options_default.highlight_modes[\n 'magic_text/x-csrc'] = {'reg':[/^%%pybind11/]};\n Jupyter.notebook.events.one('kernel_ready.Kernel', function(){\n Jupyter.notebook.get_cells().map(function(cell){\n if (cell.cell_type == 'code'){ cell.auto_highlight(); } }) ;\n });\n});\n} catch (e) {};\n" }, - "metadata": {}, - "output_type": "display_data" + "metadata": {} }, { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "['_cifar10_cnv_io_shape_dict', 'cnv_w1a1_cifar10', 'cnv_w1a2_cifar10', 'cnv_w2a2_cifar10']\n" ] } ], - "source": [ - "from finn_examples import models\n", - "print(list(filter(lambda x: \"cifar10\" in x, dir(models))))" - ] + "metadata": {} }, { "cell_type": "code", "execution_count": 2, - "metadata": {}, - "outputs": [], "source": [ "accel = models.cnv_w1a1_cifar10()" - ] + ], + "outputs": [], + "metadata": {} }, { "cell_type": "code", "execution_count": 3, - "metadata": {}, + "source": [ + "print(\"Expected input shape and datatype: %s %s\" % (str(accel.ishape_normal), str(accel.idt)))\n", + "print(\"Expected output shape and datatype: %s %s\" % (str(accel.oshape_normal), str(accel.odt)))" + ], "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "Expected input shape and datatype: (1, 32, 32, 3) DataType.UINT8\n", "Expected output shape and datatype: (1, 1) DataType.UINT8\n" ] } ], - "source": [ - "print(\"Expected input shape and datatype: %s %s\" % (str(accel.ishape_normal), str(accel.idt)))\n", - "print(\"Expected output shape and datatype: %s %s\" % (str(accel.oshape_normal), str(accel.odt)))" - ] + "metadata": {} }, { "cell_type": "markdown", - "metadata": {}, "source": [ "# Load the CIFAR-10 dataset\n", "\n", "Use the `dataset_loading` package to get easy Python access to CIFAR-10 dataset:" - ] + ], + "metadata": {} }, { "cell_type": "code", "execution_count": 5, - "metadata": {}, + "source": [ + "from dataset_loading import cifar\n", + "trainx, trainy, testx, testy, valx, valy = cifar.load_cifar_data(\"/tmp\", download=True, one_hot=False)" + ], "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "Tar File found in dest_dir. Not Downloading again\n", "Extracting Python CIFAR10 data.\n", @@ -115,172 +94,159 @@ ] } ], - "source": [ - "from dataset_loading import cifar\n", - "trainx, trainy, testx, testy, valx, valy = cifar.load_cifar_data(\"/tmp\", download=True, one_hot=False)" - ] + "metadata": {} }, { "cell_type": "code", "execution_count": 6, - "metadata": {}, + "source": [ + "testx.shape" + ], "outputs": [ { + "output_type": "execute_result", "data": { "text/plain": [ "(10000, 32, 32, 3)" ] }, - "execution_count": 6, "metadata": {}, - "output_type": "execute_result" + "execution_count": 6 } ], - "source": [ - "testx.shape" - ] + "metadata": {} }, { "cell_type": "markdown", - "metadata": {}, "source": [ "# Classify a single image" - ] + ], + "metadata": {} }, { "cell_type": "code", "execution_count": 7, - "metadata": {}, - "outputs": [], "source": [ "test_single_x = testx[0]\n", "test_single_y = testy[0]\n", "cifar10_class_names = ['Airplane', 'Automobile', 'Bird', 'Cat', 'Deer', 'Dog', 'Frog', 'Horse', 'Ship', 'Truck']\n" - ] + ], + "outputs": [], + "metadata": {} }, { "cell_type": "code", "execution_count": 9, - "metadata": {}, + "source": [ + "%matplotlib inline\n", + "from matplotlib import pyplot as plt\n", + "\n", + "plt.imshow(test_single_x)\n", + "plt.show()" + ], "outputs": [ { + "output_type": "display_data", "data": { - "image/png": "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\n", + "image/png": "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", "text/plain": [ "" ] }, - "metadata": {}, - "output_type": "display_data" + "metadata": {} } ], - "source": [ - "from matplotlib import pyplot as plt\n", - "\n", - "plt.imshow(test_single_x)\n", - "plt.show()" - ] + "metadata": {} }, { "cell_type": "code", "execution_count": 10, - "metadata": {}, + "source": [ + "print(\"Expected class is %d (%s)\" % (test_single_y, cifar10_class_names[test_single_y]))" + ], "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "Expected class is 3 (Cat)\n" ] } ], - "source": [ - "print(\"Expected class is %d (%s)\" % (test_single_y, cifar10_class_names[test_single_y]))" - ] + "metadata": {} }, { "cell_type": "code", "execution_count": 11, - "metadata": {}, + "source": [ + "accel_in = test_single_x.reshape(accel.ishape_normal)\n", + "print(\"Input buffer shape is %s and datatype is %s\" % (str(accel_in.shape), str(accel_in.dtype)))" + ], "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "Input buffer shape is (1, 32, 32, 3) and datatype is uint8\n" ] } ], - "source": [ - "accel_in = test_single_x.reshape(accel.ishape_normal)\n", - "print(\"Input buffer shape is %s and datatype is %s\" % (str(accel_in.shape), str(accel_in.dtype)))" - ] + "metadata": {} }, { "cell_type": "code", "execution_count": 12, - "metadata": {}, - "outputs": [], "source": [ "accel_out = accel.execute(accel_in)" - ] + ], + "outputs": [], + "metadata": {} }, { "cell_type": "code", "execution_count": 13, - "metadata": {}, + "source": [ + "print(\"Returned class is %d\" % accel_out)" + ], "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "Returned class is 3\n" ] } ], - "source": [ - "print(\"Returned class is %d\" % accel_out)" - ] + "metadata": {} }, { "cell_type": "code", "execution_count": 14, - "metadata": {}, + "source": [ + "%%timeit\n", + "accel_out = accel.execute(accel_in)" + ], "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "100 loops, best of 3: 2.34 ms per loop\n" ] } ], - "source": [ - "%%timeit\n", - "accel_out = accel.execute(accel_in)" - ] + "metadata": {} }, { "cell_type": "markdown", - "metadata": {}, "source": [ "# Validate accuracy on entire CIFAR-10 test set" - ] + ], + "metadata": {} }, { "cell_type": "code", "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Ready to run validation, test images tensor has shape (10, 1000, 3072)\n", - "Accelerator buffer shapes are (1000, 1, 32, 32, 1, 3) for input, (1000, 1, 1) for output\n" - ] - } - ], "source": [ "import numpy as np\n", "\n", @@ -294,16 +260,38 @@ "obuf_normal = np.empty_like(accel.obuf_packed_device)\n", "print(\"Ready to run validation, test images tensor has shape %s\" % str(batch_imgs.shape))\n", "print(\"Accelerator buffer shapes are %s for input, %s for output\" % (str(accel.ishape_packed), str(accel.oshape_packed)) )" - ] + ], + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Ready to run validation, test images tensor has shape (10, 1000, 3072)\n", + "Accelerator buffer shapes are (1000, 1, 32, 32, 1, 3) for input, (1000, 1, 1) for output\n" + ] + } + ], + "metadata": {} }, { "cell_type": "code", "execution_count": 16, - "metadata": {}, + "source": [ + "ok = 0\n", + "nok = 0\n", + "for i in range(n_batches):\n", + " ibuf_normal = batch_imgs[i].reshape(accel.ishape_normal)\n", + " exp = batch_labels[i]\n", + " obuf_normal = accel.execute(ibuf_normal)\n", + " ret = np.bincount(obuf_normal.flatten() == exp.flatten())\n", + " nok += ret[0]\n", + " ok += ret[1]\n", + " print(\"batch %d / %d : total OK %d NOK %d\" % (i, n_batches, ok, nok))" + ], "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "batch 0 / 10 : total OK 851 NOK 149\n", "batch 1 / 10 : total OK 1683 NOK 317\n", @@ -318,97 +306,89 @@ ] } ], - "source": [ - "ok = 0\n", - "nok = 0\n", - "for i in range(n_batches):\n", - " ibuf_normal = batch_imgs[i].reshape(accel.ishape_normal)\n", - " exp = batch_labels[i]\n", - " obuf_normal = accel.execute(ibuf_normal)\n", - " ret = np.bincount(obuf_normal.flatten() == exp.flatten())\n", - " nok += ret[0]\n", - " ok += ret[1]\n", - " print(\"batch %d / %d : total OK %d NOK %d\" % (i, n_batches, ok, nok))" - ] + "metadata": {} }, { "cell_type": "code", "execution_count": 17, - "metadata": {}, + "source": [ + "acc = 100.0 * ok / (total)\n", + "print(\"Final accuracy: {}%\".format(acc))" + ], "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "Final accuracy: 84.19%\n" ] } ], - "source": [ - "acc = 100.0 * ok / (total)\n", - "print(\"Final accuracy: {}%\".format(acc))" - ] + "metadata": {} }, { "cell_type": "code", "execution_count": 18, - "metadata": {}, - "outputs": [], "source": [ "def run_validation():\n", " for i in range(n_batches):\n", " ibuf_normal = batch_imgs[i].reshape(accel.ishape_normal)\n", " exp = batch_labels[i]\n", " accel.execute(ibuf_normal)" - ] + ], + "outputs": [], + "metadata": {} }, { "cell_type": "code", "execution_count": 20, - "metadata": {}, + "source": [ + "full_validation_time = %timeit -n 1 -o run_validation()" + ], "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "1 loop, best of 3: 3.34 s per loop\n" ] } ], - "source": [ - "full_validation_time = %timeit -n 1 -o run_validation()" - ] + "metadata": {} }, { "cell_type": "code", "execution_count": 21, - "metadata": {}, + "source": [ + "print(\"%f images per second including data movement\" % (total / float(full_validation_time.best)))" + ], "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "2995.076851 images per second including data movement\n" ] } ], - "source": [ - "print(\"%f images per second including data movement\" % (total / float(full_validation_time.best)))" - ] + "metadata": {} }, { "cell_type": "markdown", - "metadata": {}, "source": [ "## More benchmarking" - ] + ], + "metadata": {} }, { "cell_type": "code", "execution_count": 23, - "metadata": {}, + "source": [ + "accel.throughput_test()" + ], "outputs": [ { + "output_type": "execute_result", "data": { "text/plain": [ "{'DRAM_in_bandwidth[Mb/s]': 9.278965852281484,\n", @@ -425,21 +405,18 @@ " 'unpack_output[ms]': 0.0006213188171386719}" ] }, - "execution_count": 23, "metadata": {}, - "output_type": "execute_result" + "execution_count": 23 } ], - "source": [ - "accel.throughput_test()" - ] + "metadata": {} }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "source": [], "outputs": [], - "source": [] + "metadata": {} } ], "metadata": { @@ -463,4 +440,4 @@ }, "nbformat": 4, "nbformat_minor": 2 -} +} \ No newline at end of file diff --git a/finn_examples/notebooks/3_binarycop_mask_detection.ipynb b/finn_examples/notebooks/3_binarycop_mask_detection.ipynb index 1d8f5bf..15688c1 100644 --- a/finn_examples/notebooks/3_binarycop_mask_detection.ipynb +++ b/finn_examples/notebooks/3_binarycop_mask_detection.ipynb @@ -3,85 +3,74 @@ { "cell_type": "code", "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "application/javascript": [ - "\n", - "require(['notebook/js/codecell'], function(codecell) {\n", - " codecell.CodeCell.options_default.highlight_modes[\n", - " 'magic_text/x-csrc'] = {'reg':[/^%%microblaze/]};\n", - " Jupyter.notebook.events.one('kernel_ready.Kernel', function(){\n", - " Jupyter.notebook.get_cells().map(function(cell){\n", - " if (cell.cell_type == 'code'){ cell.auto_highlight(); } }) ;\n", - " });\n", - "});\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], "source": [ "from finn_examples import models\n", "import os\n", "from PIL import Image\n", "import numpy as np\n", "import cv2" - ] + ], + "outputs": [ + { + "output_type": "display_data", + "data": { + "application/javascript": "\nrequire(['notebook/js/codecell'], function(codecell) {\n codecell.CodeCell.options_default.highlight_modes[\n 'magic_text/x-csrc'] = {'reg':[/^%%microblaze/]};\n Jupyter.notebook.events.one('kernel_ready.Kernel', function(){\n Jupyter.notebook.get_cells().map(function(cell){\n if (cell.cell_type == 'code'){ cell.auto_highlight(); } }) ;\n });\n});\n" + }, + "metadata": {} + } + ], + "metadata": {} }, { "cell_type": "markdown", - "metadata": {}, "source": [ "# Initialize the Accelerator" - ] + ], + "metadata": {} }, { "cell_type": "code", "execution_count": 2, - "metadata": { - "scrolled": true - }, - "outputs": [], "source": [ + "# Note: the face mask detection example is only available on Pynq-Z1 at the moment\n", "accel = models.bincop_cnv()" - ] + ], + "outputs": [], + "metadata": { + "scrolled": true + } }, { "cell_type": "code", "execution_count": 3, - "metadata": {}, + "source": [ + "class_dict = {0: \"Correctly Masked\", 1: \"Incorrectly Worn\", 2: \"No Mask\"}\n", + "\n", + "print(\"Expected input shape and datatype: %s %s\" % (str(accel.ishape_normal), str(accel.idt)))\n", + "print(\"Expected output shape and datatype: %s %s\" % (str(accel.oshape_normal), str(accel.odt)))" + ], "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "Expected input shape and datatype: (1, 72, 72, 3) DataType.UINT8\n", "Expected output shape and datatype: (1, 1) DataType.UINT8\n" ] } ], - "source": [ - "class_dict = {0: \"Correctly Masked\", 1: \"Incorrectly Worn\", 2: \"No Mask\"}\n", - "\n", - "print(\"Expected input shape and datatype: %s %s\" % (str(accel.ishape_normal), str(accel.idt)))\n", - "print(\"Expected output shape and datatype: %s %s\" % (str(accel.oshape_normal), str(accel.odt)))" - ] + "metadata": {} }, { "cell_type": "markdown", - "metadata": {}, "source": [ "# Load Mask Examples" - ] + ], + "metadata": {} }, { "cell_type": "code", "execution_count": 4, - "metadata": {}, - "outputs": [], "source": [ "mask_examples_dir = \"/tmp/mask_examples\"\n", "if not os.path.exists(mask_examples_dir):\n", @@ -90,20 +79,20 @@ "for i in range(6):\n", " if \"{}.jpg\".format(i+1) not in os.listdir(mask_examples_dir):\n", " os.system(\"wget -P \" + mask_examples_dir + \" https://github.com/NaelF/BinaryCoP/raw/master/notebook/pictures/{}.jpg\".format(i+1))" - ] + ], + "outputs": [], + "metadata": {} }, { "cell_type": "markdown", - "metadata": {}, "source": [ "# Run Inference" - ] + ], + "metadata": {} }, { "cell_type": "code", "execution_count": 5, - "metadata": {}, - "outputs": [], "source": [ "def resize(img):\n", " img = np.array(img)\n", @@ -111,153 +100,153 @@ " resized_img = cv2.resize(img,(72,72))\n", " return (resized_img) \n", " else: return img" - ] + ], + "outputs": [], + "metadata": {} }, { "cell_type": "code", "execution_count": 6, - "metadata": {}, + "source": [ + "im = Image.open(mask_examples_dir + '/1.jpg')\n", + "im = resize(im)\n", + "accel_in = im.reshape(accel.ishape_normal)\n", + "im = Image.fromarray(im, 'RGB')\n", + "display(im)\n", + "accel_out = accel.execute(accel_in)\n", + "print(\"Returned class is: \" + class_dict[int(accel_out)])\n", + "\n", + "im = Image.open(mask_examples_dir + '/2.jpg')\n", + "im = resize(im)\n", + "accel_in = im.reshape(accel.ishape_normal)\n", + "im = Image.fromarray(im, 'RGB')\n", + "display(im)\n", + "accel_out = accel.execute(accel_in)\n", + "print(\"Returned class is: \" + class_dict[int(accel_out)])\n", + "\n", + "im = Image.open(mask_examples_dir + '/3.jpg')\n", + "im = resize(im)\n", + "accel_in = im.reshape(accel.ishape_normal)\n", + "im = Image.fromarray(im, 'RGB')\n", + "display(im)\n", + "accel_out = accel.execute(accel_in)\n", + "print(\"Returned class is: \" + class_dict[int(accel_out)])\n", + "\n", + "im = Image.open(mask_examples_dir + '/4.jpg')\n", + "im = resize(im)\n", + "accel_in = im.reshape(accel.ishape_normal)\n", + "im = Image.fromarray(im, 'RGB')\n", + "display(im)\n", + "accel_out = accel.execute(accel_in)\n", + "print(\"Returned class is: \" + class_dict[int(accel_out)])\n", + "\n", + "im = Image.open(mask_examples_dir + '/5.jpg')\n", + "im = resize(im)\n", + "accel_in = im.reshape(accel.ishape_normal)\n", + "im = Image.fromarray(im, 'RGB')\n", + "display(im)\n", + "accel_out = accel.execute(accel_in)\n", + "print(\"Returned class is: \" + class_dict[int(accel_out)])" + ], "outputs": [ { + "output_type": "display_data", "data": { - "image/png": "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\n", + "image/png": "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", "text/plain": [ "" ] }, - "metadata": {}, - "output_type": "display_data" + "metadata": {} }, { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "Returned class is: Correctly Masked\n" ] }, { + "output_type": "display_data", "data": { - "image/png": "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\n", + "image/png": "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", "text/plain": [ "" ] }, - "metadata": {}, - "output_type": "display_data" + "metadata": {} }, { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "Returned class is: Correctly Masked\n" ] }, { + "output_type": "display_data", "data": { - "image/png": "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\n", + "image/png": "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", "text/plain": [ "" ] }, - "metadata": {}, - "output_type": "display_data" + "metadata": {} }, { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "Returned class is: Incorrectly Worn\n" ] }, { + "output_type": "display_data", "data": { - "image/png": "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\n", + "image/png": "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", "text/plain": [ "" ] }, - "metadata": {}, - "output_type": "display_data" + "metadata": {} }, { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "Returned class is: Incorrectly Worn\n" ] }, { + "output_type": "display_data", "data": { - "image/png": "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\n", + "image/png": "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", "text/plain": [ "" ] }, - "metadata": {}, - "output_type": "display_data" + "metadata": {} }, { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "Returned class is: No Mask\n" ] } ], - "source": [ - "im = Image.open(mask_examples_dir + '/1.jpg')\n", - "im = resize(im)\n", - "accel_in = im.reshape(accel.ishape_normal)\n", - "im = Image.fromarray(im, 'RGB')\n", - "display(im)\n", - "accel_out = accel.execute(accel_in)\n", - "print(\"Returned class is: \" + class_dict[int(accel_out)])\n", - "\n", - "im = Image.open(mask_examples_dir + '/2.jpg')\n", - "im = resize(im)\n", - "accel_in = im.reshape(accel.ishape_normal)\n", - "im = Image.fromarray(im, 'RGB')\n", - "display(im)\n", - "accel_out = accel.execute(accel_in)\n", - "print(\"Returned class is: \" + class_dict[int(accel_out)])\n", - "\n", - "im = Image.open(mask_examples_dir + '/3.jpg')\n", - "im = resize(im)\n", - "accel_in = im.reshape(accel.ishape_normal)\n", - "im = Image.fromarray(im, 'RGB')\n", - "display(im)\n", - "accel_out = accel.execute(accel_in)\n", - "print(\"Returned class is: \" + class_dict[int(accel_out)])\n", - "\n", - "im = Image.open(mask_examples_dir + '/4.jpg')\n", - "im = resize(im)\n", - "accel_in = im.reshape(accel.ishape_normal)\n", - "im = Image.fromarray(im, 'RGB')\n", - "display(im)\n", - "accel_out = accel.execute(accel_in)\n", - "print(\"Returned class is: \" + class_dict[int(accel_out)])\n", - "\n", - "im = Image.open(mask_examples_dir + '/5.jpg')\n", - "im = resize(im)\n", - "accel_in = im.reshape(accel.ishape_normal)\n", - "im = Image.fromarray(im, 'RGB')\n", - "display(im)\n", - "accel_out = accel.execute(accel_in)\n", - "print(\"Returned class is: \" + class_dict[int(accel_out)])" - ] + "metadata": {} }, { "cell_type": "markdown", - "metadata": {}, "source": [ "# Run Webcam" - ] + ], + "metadata": {} }, { "cell_type": "code", "execution_count": 7, - "metadata": {}, - "outputs": [], "source": [ "from IPython.display import clear_output\n", "\n", @@ -288,24 +277,13 @@ " img_resized = cv2.resize(img_cropped,(72,72))\n", " img_rev = cv2.cvtColor(img_resized, cv2.COLOR_BGR2RGB)\n", " return img_rev" - ] + ], + "outputs": [], + "metadata": {} }, { "cell_type": "code", "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], "source": [ "cap = cv2.VideoCapture(0)\n", "while not cap.isOpened():\n", @@ -316,11 +294,23 @@ "# set small capture resolution for faster processing\n", "cap.set(cv2.CAP_PROP_FRAME_WIDTH, 160)\n", "cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 120)" - ] + ], + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "True" + ] + }, + "metadata": {}, + "execution_count": 8 + } + ], + "metadata": {} }, { "cell_type": "markdown", - "metadata": {}, "source": [ "# Classify Webcam Input\n", "* Make sure you are in a well-lit environment\n", @@ -328,118 +318,119 @@ "* Position your face in the center of the frame, close to camera (see examples)\n", "\n", "This notebook is a basic proof-of-concept. Model was trained on simple blue-mask augmentation of Flickr-Faces-HQ (FFHQ). For better results, more mask-types can be supported (e.g. https://github.com/aqeelanwar/MaskTheFace)" - ] + ], + "metadata": {} }, { "cell_type": "code", "execution_count": 9, - "metadata": { - "scrolled": true - }, + "source": [ + "clear_output()\n", + "frame, img = producer_live(cap)\n", + "consumer_live(accel, frame)\n", + "img" + ], "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "Class name: Correctly Masked\n" ] }, { + "output_type": "execute_result", "data": { - "image/png": "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\n", + "image/png": "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", "text/plain": [ "" ] }, - "execution_count": 9, "metadata": {}, - "output_type": "execute_result" + "execution_count": 9 } ], + "metadata": { + "scrolled": true + } + }, + { + "cell_type": "code", + "execution_count": 10, "source": [ "clear_output()\n", "frame, img = producer_live(cap)\n", "consumer_live(accel, frame)\n", "img" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, + ], "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "Class name: Incorrectly Worn\n" ] }, { + "output_type": "execute_result", "data": { - "image/png": "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\n", + "image/png": "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", "text/plain": [ "" ] }, - "execution_count": 10, "metadata": {}, - "output_type": "execute_result" + "execution_count": 10 } ], + "metadata": {} + }, + { + "cell_type": "code", + "execution_count": 11, "source": [ "clear_output()\n", "frame, img = producer_live(cap)\n", "consumer_live(accel, frame)\n", "img" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, + ], "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "Class name: No Mask\n" ] }, { + "output_type": "execute_result", "data": { - "image/png": "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Erwfc8qqZGYGQiBqo2RwTMyugKkaITgiMyPzZGCghlC07FqviQDMPBMjJLGzx9t3fuv125/7uMXgVLUfW3735Df+zsU7H9z4zL9yUc+mCsYR7PDg3/j5/+Qr/+Bv3n/nW4fVgfYl+PLkcy89970/cXeajQ5ghEJ27wNM90+a09e7k6+049cr3pwc55PX17x2FlgCj+kYicRQiqqamRKzJNVAQ8qTakBMpRSRYppFppIpepeswKUjCGygBo6cmgLRbmcjqkweQREohphHKMLv3blXB5g9eZUOD3ogy44pbb/5v/zBe9988cf+QplfCx4GgrsZPvWln31xLu994w9OT6frN59ZV8vvTFDt43KC00eWi23vfbd69H8dlNeqfJK5fu9hf/z63cVmEwoKx9J0m2FY1EEEiuzEYsOdjGOUBNQIEHLOKmKmpppSqgDdpBPpznsAR4xqKmpmhDv1w4qZZzBllRxCxVOOpYiVb751/2BTrj812l7cxj3RxoXTsH337V/7766+8PnmU/9qCfHRCs4E3niXnm4+3lX9sblHE0+Ip++abqb+/B4df+Pa9K253kW8WJucvv1o/c67cXM+UVAfZpar6ex4HJazToqI6u4DO0Zm74ppQRQk21liZqA7DRdLzv8fz6kM7g19L04AAAAASUVORK5CYII=\n", + "image/png": "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Erwfc8qqZGYGQiBqo2RwTMyugKkaITgiMyPzZGCghlC07FqviQDMPBMjJLGzx9t3fuv125/7uMXgVLUfW3735Df+zsU7H9z4zL9yUc+mCsYR7PDg3/j5/+Qr/+Bv3n/nW4fVgfYl+PLkcy89970/cXeajQ5ghEJ27wNM90+a09e7k6+049cr3pwc55PX17x2FlgCj+kYicRQiqqamRKzJNVAQ8qTakBMpRSRYppFppIpepeswKUjCGygBo6cmgLRbmcjqkweQREohphHKMLv3blXB5g9eZUOD3ogy44pbb/5v/zBe9988cf+QplfCx4GgrsZPvWln31xLu994w9OT6frN59ZV8vvTFDt43KC00eWi23vfbd69H8dlNeqfJK5fu9hf/z63cVmEwoKx9J0m2FY1EEEiuzEYsOdjGOUBNQIEHLOKmKmpppSqgDdpBPpznsAR4xqKmpmhDv1w4qZZzBllRxCxVOOpYiVb751/2BTrj812l7cxj3RxoXTsH337V/7766+8PnmU/9qCfHRCs4E3niXnm4+3lX9sblHE0+Ip++abqb+/B4df+Pa9K253kW8WJucvv1o/c67cXM+UVAfZpar6ex4HJazToqI6u4DO0Zm74ppQRQk21liZqA7DRdLzv8fz6kM7g19L04AAAAASUVORK5CYII=", "text/plain": [ "" ] }, - "execution_count": 11, "metadata": {}, - "output_type": "execute_result" + "execution_count": 11 } ], - "source": [ - "clear_output()\n", - "frame, img = producer_live(cap)\n", - "consumer_live(accel, frame)\n", - "img" - ] + "metadata": {} }, { "cell_type": "markdown", - "metadata": {}, "source": [ "# Release Webcam" - ] + ], + "metadata": {} }, { "cell_type": "code", "execution_count": 12, - "metadata": {}, - "outputs": [], "source": [ "cap.release()" - ] + ], + "outputs": [], + "metadata": {} } ], "metadata": { @@ -463,4 +454,4 @@ }, "nbformat": 4, "nbformat_minor": 1 -} +} \ No newline at end of file diff --git a/finn_examples/notebooks/5_radioml_with_cnns.ipynb b/finn_examples/notebooks/5_radioml_with_cnns.ipynb index 56e15d4..ed3093b 100755 --- a/finn_examples/notebooks/5_radioml_with_cnns.ipynb +++ b/finn_examples/notebooks/5_radioml_with_cnns.ipynb @@ -2,126 +2,93 @@ "cells": [ { "cell_type": "markdown", - "metadata": {}, "source": [ "# Initialize the accelerator" - ] + ], + "metadata": {} }, { "cell_type": "code", "execution_count": 1, - "metadata": {}, - "outputs": [], "source": [ "# remember to install the following dependencies\n", "#! apt-get install libhdf5-dev -y\n", - "#! pip install versioned-hdf5" - ] + "#! pip3 install versioned-hdf5" + ], + "outputs": [], + "metadata": {} }, { "cell_type": "code", "execution_count": 2, - "metadata": {}, + "source": [ + "from finn_examples import models\n", + "print(list(filter(lambda x: \"radioml\" in x, dir(models))))" + ], "outputs": [ { + "output_type": "display_data", "data": { - "application/javascript": [ - "\n", - "try {\n", - "require(['notebook/js/codecell'], function(codecell) {\n", - " codecell.CodeCell.options_default.highlight_modes[\n", - " 'magic_text/x-csrc'] = {'reg':[/^%%microblaze/]};\n", - " Jupyter.notebook.events.one('kernel_ready.Kernel', function(){\n", - " Jupyter.notebook.get_cells().map(function(cell){\n", - " if (cell.cell_type == 'code'){ cell.auto_highlight(); } }) ;\n", - " });\n", - "});\n", - "} catch (e) {};\n" - ] + "application/javascript": "\ntry {\nrequire(['notebook/js/codecell'], function(codecell) {\n codecell.CodeCell.options_default.highlight_modes[\n 'magic_text/x-csrc'] = {'reg':[/^%%microblaze/]};\n Jupyter.notebook.events.one('kernel_ready.Kernel', function(){\n Jupyter.notebook.get_cells().map(function(cell){\n if (cell.cell_type == 'code'){ cell.auto_highlight(); } }) ;\n });\n});\n} catch (e) {};\n" }, - "metadata": {}, - "output_type": "display_data" + "metadata": {} }, { + "output_type": "display_data", "data": { - "application/javascript": [ - "\n", - "try {\n", - "require(['notebook/js/codecell'], function(codecell) {\n", - " codecell.CodeCell.options_default.highlight_modes[\n", - " 'magic_text/x-csrc'] = {'reg':[/^%%pybind11/]};\n", - " Jupyter.notebook.events.one('kernel_ready.Kernel', function(){\n", - " Jupyter.notebook.get_cells().map(function(cell){\n", - " if (cell.cell_type == 'code'){ cell.auto_highlight(); } }) ;\n", - " });\n", - "});\n", - "} catch (e) {};\n" - ] + "application/javascript": "\ntry {\nrequire(['notebook/js/codecell'], function(codecell) {\n codecell.CodeCell.options_default.highlight_modes[\n 'magic_text/x-csrc'] = {'reg':[/^%%pybind11/]};\n Jupyter.notebook.events.one('kernel_ready.Kernel', function(){\n Jupyter.notebook.get_cells().map(function(cell){\n if (cell.cell_type == 'code'){ cell.auto_highlight(); } }) ;\n });\n});\n} catch (e) {};\n" }, - "metadata": {}, - "output_type": "display_data" + "metadata": {} }, { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "['_radioml_io_shape_dict', 'vgg10_w4a4_radioml']\n" ] } ], - "source": [ - "from finn_examples import models\n", - "print(list(filter(lambda x: \"radioml\" in x, dir(models))))" - ] + "metadata": {} }, { "cell_type": "code", "execution_count": 3, - "metadata": {}, - "outputs": [], "source": [ + "# Note: the RadioML example is only available on the ZCU104 at the moment\n", "accel = models.vgg10_w4a4_radioml()" - ] + ], + "outputs": [], + "metadata": {} }, { "cell_type": "code", "execution_count": 4, - "metadata": {}, + "source": [ + "print(\"Expected input shape and datatype: %s %s\" % (str(accel.ishape_normal), str(accel.idt)))\n", + "print(\"Expected output shape and datatype: %s %s\" % (str(accel.oshape_normal), str(accel.odt)))" + ], "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "Expected input shape and datatype: (1, 1024, 1, 2) DataType.INT8\n", "Expected output shape and datatype: (1, 1) DataType.UINT8\n" ] } ], - "source": [ - "print(\"Expected input shape and datatype: %s %s\" % (str(accel.ishape_normal), str(accel.idt)))\n", - "print(\"Expected output shape and datatype: %s %s\" % (str(accel.oshape_normal), str(accel.odt)))" - ] + "metadata": {} }, { "cell_type": "markdown", - "metadata": {}, "source": [ "# Load RadioML 2018 dataset" - ] + ], + "metadata": {} }, { "cell_type": "code", "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "/home/xilinx/datasets/radioml_2018\n" - ] - } - ], "source": [ "import numpy as np\n", "import math\n", @@ -131,13 +98,21 @@ "\n", "dataset_dir = \"/home/xilinx/datasets/radioml_2018\"\n", "print(dataset_dir)" - ] + ], + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "/home/xilinx/datasets/radioml_2018\n" + ] + } + ], + "metadata": {} }, { "cell_type": "code", "execution_count": 6, - "metadata": {}, - "outputs": [], "source": [ "h5_file = h5py.File(dataset_dir + \"/GOLD_XYZ_OSC.0001_1024.hdf5\",'r')\n", "data_h5 = h5_file['X']\n", @@ -167,16 +142,23 @@ "'16APSK','32APSK','64APSK','128APSK','16QAM','32QAM','64QAM','128QAM','256QAM',\n", "'AM-SSB-WC','AM-SSB-SC','AM-DSB-WC','AM-DSB-SC','FM','GMSK','OQPSK']\n", "snr_classes = np.arange(-20., 32., 2) # -20dB to 30dB" - ] + ], + "outputs": [], + "metadata": {} }, { "cell_type": "code", "execution_count": 7, - "metadata": {}, + "source": [ + "print(data_h5.shape)\n", + "print(label_mod.shape)\n", + "print(label_snr.shape)\n", + "print(len(test_indices))" + ], "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "(2555904, 1024, 2)\n", "(2555904,)\n", @@ -185,34 +167,20 @@ ] } ], - "source": [ - "print(data_h5.shape)\n", - "print(label_mod.shape)\n", - "print(label_snr.shape)\n", - "print(len(test_indices))" - ] + "metadata": {} }, { "cell_type": "markdown", - "metadata": {}, "source": [ "# Inspect a single frame" - ] + ], + "metadata": {} }, { "cell_type": "code", "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Modulation: 16QAM, SNR: 30.0 dB\n" - ] - } - ], "source": [ + "%matplotlib inline\n", "from matplotlib import pyplot as plt\n", "\n", "# Inspect a frame\n", @@ -225,21 +193,29 @@ "plt.figure()\n", "plt.plot(data)\n", "print(\"Modulation: %s, SNR: %.1f dB\" % (mod_classes[mod], snr))" - ] + ], + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Modulation: 16QAM, SNR: 30.0 dB\n" + ] + } + ], + "metadata": {} }, { "cell_type": "markdown", - "metadata": {}, "source": [ "# Input quantization\n", "Quantize input data on-the-fly in software before feeding it to the accelerator. Use the uniform quantization range on which the model was trained." - ] + ], + "metadata": {} }, { "cell_type": "code", "execution_count": 9, - "metadata": {}, - "outputs": [], "source": [ "def quantize(data):\n", " quant_min = -2.0\n", @@ -250,94 +226,102 @@ " data_quant = np.clip(data_quant, -128, 127)\n", " data_quant = data_quant.astype(np.int8)\n", " return data_quant" - ] + ], + "outputs": [], + "metadata": {} }, { "cell_type": "markdown", - "metadata": {}, "source": [ "# Classify a single frame" - ] + ], + "metadata": {} }, { "cell_type": "code", "execution_count": 10, - "metadata": {}, + "source": [ + "accel_in = quantize(data).reshape(accel.ishape_normal)\n", + "print(\"Input buffer shape is %s and datatype is %s\" % (str(accel_in.shape), str(accel_in.dtype)))" + ], "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "Input buffer shape is (1, 1024, 1, 2) and datatype is int8\n" ] } ], - "source": [ - "accel_in = quantize(data).reshape(accel.ishape_normal)\n", - "print(\"Input buffer shape is %s and datatype is %s\" % (str(accel_in.shape), str(accel_in.dtype)))" - ] + "metadata": {} }, { "cell_type": "code", "execution_count": 11, - "metadata": {}, - "outputs": [], "source": [ "accel_out = accel.execute(accel_in)" - ] + ], + "outputs": [], + "metadata": {} }, { "cell_type": "code", "execution_count": 12, - "metadata": {}, + "source": [ + "print(\"Result: \" + str(accel_out))\n", + "print(\"Top-1 class predicted by the accelerator: \" + mod_classes[int(accel_out)])" + ], "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "Result: [[12.]]\n", "Top-1 class predicted by the accelerator: 16QAM\n" ] } ], - "source": [ - "print(\"Result: \" + str(accel_out))\n", - "print(\"Top-1 class predicted by the accelerator: \" + mod_classes[int(accel_out)])" - ] + "metadata": {} }, { "cell_type": "code", "execution_count": 13, - "metadata": {}, + "source": [ + "%%timeit\n", + "accel_out = accel.execute(accel_in)" + ], "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "1000 loops, best of 3: 822 µs per loop\n" ] } ], - "source": [ - "%%timeit\n", - "accel_out = accel.execute(accel_in)" - ] + "metadata": {} }, { "cell_type": "markdown", - "metadata": {}, "source": [ "# Validate accuracy on entire test set" - ] + ], + "metadata": {} }, { "cell_type": "code", "execution_count": 14, - "metadata": {}, + "source": [ + "batch_size = 1024\n", + "accel.batch_size = batch_size\n", + "print(\"Accelerator buffer shapes are %s for input, %s for output\" % (str(accel.ishape_packed), str(accel.oshape_packed)) )\n", + "print(\"Accelerator buffer shapes are %s for input, %s for output\" % (str(accel.ishape_folded), str(accel.oshape_folded)) )\n", + "print(\"Accelerator buffer shapes are %s for input, %s for output\" % (str(accel.ishape_normal), str(accel.oshape_normal)) )" + ], "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "Accelerator buffer shapes are (1024, 1024, 1, 1, 2) for input, (1024, 1, 1) for output\n", "Accelerator buffer shapes are (1024, 1024, 1, 1, 2) for input, (1024, 1, 1) for output\n", @@ -345,38 +329,11 @@ ] } ], - "source": [ - "batch_size = 1024\n", - "accel.batch_size = batch_size\n", - "print(\"Accelerator buffer shapes are %s for input, %s for output\" % (str(accel.ishape_packed), str(accel.oshape_packed)) )\n", - "print(\"Accelerator buffer shapes are %s for input, %s for output\" % (str(accel.ishape_folded), str(accel.oshape_folded)) )\n", - "print(\"Accelerator buffer shapes are %s for input, %s for output\" % (str(accel.ishape_normal), str(accel.oshape_normal)) )" - ] + "metadata": {} }, { "cell_type": "code", "execution_count": 15, - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "batch 0 : total OK 1018 NOK 6\n", - "batch 1 : total OK 2041 NOK 7\n", - "batch 2 : total OK 3059 NOK 13\n", - "batch 3 : total OK 4082 NOK 14\n", - "batch 4 : total OK 4948 NOK 172\n", - "batch 5 : total OK 5682 NOK 462\n", - "batch 6 : total OK 6314 NOK 854\n", - "batch 7 : total OK 7039 NOK 1153\n", - "batch 8 : total OK 8024 NOK 1192\n", - "batch 9 : total OK 8648 NOK 1192\n" - ] - } - ], "source": [ "ok = 0\n", "nok = 0\n", @@ -398,39 +355,64 @@ " nok += np.not_equal(pred, mod).sum().item()\n", " \n", " print(\"batch %d : total OK %d NOK %d\" % (i_batch, ok, nok))" - ] + ], + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "batch 0 : total OK 1018 NOK 6\n", + "batch 1 : total OK 2041 NOK 7\n", + "batch 2 : total OK 3059 NOK 13\n", + "batch 3 : total OK 4082 NOK 14\n", + "batch 4 : total OK 4948 NOK 172\n", + "batch 5 : total OK 5682 NOK 462\n", + "batch 6 : total OK 6314 NOK 854\n", + "batch 7 : total OK 7039 NOK 1153\n", + "batch 8 : total OK 8024 NOK 1192\n", + "batch 9 : total OK 8648 NOK 1192\n" + ] + } + ], + "metadata": { + "scrolled": true + } }, { "cell_type": "code", "execution_count": 16, - "metadata": {}, + "source": [ + "acc = 100.0 * ok / (total)\n", + "print(\"Overall top-1 accuracy: {}%\".format(acc))" + ], "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "Overall top-1 accuracy: 87.88617886178862%\n" ] } ], - "source": [ - "acc = 100.0 * ok / (total)\n", - "print(\"Overall top-1 accuracy: {}%\".format(acc))" - ] + "metadata": {} }, { "cell_type": "markdown", - "metadata": {}, "source": [ "## More benchmarking" - ] + ], + "metadata": {} }, { "cell_type": "code", "execution_count": 17, - "metadata": {}, + "source": [ + "accel.batch_size = 1024\n", + "accel.throughput_test()" + ], "outputs": [ { + "output_type": "execute_result", "data": { "text/plain": [ "{'DRAM_in_bandwidth[Mb/s]': 473.18806940706867,\n", @@ -447,22 +429,18 @@ " 'unpack_output[ms]': 0.6284713745117188}" ] }, - "execution_count": 17, "metadata": {}, - "output_type": "execute_result" + "execution_count": 17 } ], - "source": [ - "accel.batch_size = 1024\n", - "accel.throughput_test()" - ] + "metadata": {} }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "source": [], "outputs": [], - "source": [] + "metadata": {} } ], "metadata": { @@ -486,4 +464,4 @@ }, "nbformat": 4, "nbformat_minor": 2 -} +} \ No newline at end of file From 4b4124c768ea27454cd6d02509fe750aa84bb1d2 Mon Sep 17 00:00:00 2001 From: Hendrik Borras Date: Thu, 4 Nov 2021 21:32:40 +0000 Subject: [PATCH 46/49] Fixed a bug in the quantization and added support for playing the sample files. --- .../notebooks/4_keyword_spotting.ipynb | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/finn_examples/notebooks/4_keyword_spotting.ipynb b/finn_examples/notebooks/4_keyword_spotting.ipynb index 8fc9af8..3145636 100644 --- a/finn_examples/notebooks/4_keyword_spotting.ipynb +++ b/finn_examples/notebooks/4_keyword_spotting.ipynb @@ -378,7 +378,8 @@ "from scipy import signal\n", "import scipy.io.wavfile as wav\n", "from scipy.signal.windows import hann\n", - "import matplotlib.pyplot as plt" + "import matplotlib.pyplot as plt\n", + "import IPython" ] }, { @@ -442,7 +443,7 @@ "\n", "def quantize_input(mfcc_feat_py):\n", " # Scaling\n", - " quant_mfcc_feat = (mfcc_feat_py*0.8298503756523132)\n", + " quant_mfcc_feat = (mfcc_feat_py / 0.8298503756523132)\n", " # Clamping & rounding\n", " quant_mfcc_feat = np.where(quant_mfcc_feat > 127., 127., quant_mfcc_feat)\n", " quant_mfcc_feat = np.where(quant_mfcc_feat < -127., -127., quant_mfcc_feat)\n", @@ -487,10 +488,25 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "#### Change the line below to load your own .wav file or to load a different sample file.\n", + "#### Change sample_path variable in the line below to load your own .wav file or to load a different sample file.\n", "Make sure that the file is shorter than one second." ] }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": [ + "sample_path = f\"{audio_samples_folder}audio_sample_yes.wav\"\n", + "IPython.display.Audio(sample_path)" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, { "cell_type": "code", "execution_count": 17, @@ -498,7 +514,7 @@ "outputs": [], "source": [ "# Read the audio wave file\n", - "rate, raw_signal = wav.read(f\"{audio_samples_folder}audio_sample_yes.wav\")" + "rate, raw_signal = wav.read(sample_path)" ] }, { From 62e34a38458f50c5ac24a7ddfdfb2813c7a9c6bf Mon Sep 17 00:00:00 2001 From: Yaman Umuroglu Date: Thu, 4 Nov 2021 22:59:40 +0100 Subject: [PATCH 47/49] minor fixes and additions to KWS notebook --- .../notebooks/4_keyword_spotting.ipynb | 364 +++++++++--------- 1 file changed, 175 insertions(+), 189 deletions(-) diff --git a/finn_examples/notebooks/4_keyword_spotting.ipynb b/finn_examples/notebooks/4_keyword_spotting.ipynb index 3145636..860d626 100644 --- a/finn_examples/notebooks/4_keyword_spotting.ipynb +++ b/finn_examples/notebooks/4_keyword_spotting.ipynb @@ -2,11 +2,6 @@ "cells": [ { "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, "source": [ "# Validating network accuracy\n", "In this first part we will be looking at the overall accuracy of the network.\n", @@ -24,29 +19,23 @@ "\n", "During the training of the KWS network we produce the MFCC features for the training and validation set and then quantize the inputs to the network to eight bit.\n", "We will load the pre-processed and quantized validation dataset in the next step.\n" - ] + ], + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + } }, { "cell_type": "markdown", - "metadata": {}, "source": [ "### Load preprocessed Google Speech Commands v2 validation dataset" - ] + ], + "metadata": {} }, { "cell_type": "code", "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Input data shape: (10102, 490)\n", - "Label shape: (10102,)\n" - ] - } - ], "source": [ "import pkg_resources as pk\n", "import numpy as np\n", @@ -60,134 +49,126 @@ "\n", "print(\"Input data shape: \" + str(input_data.shape))\n", "print(\"Label shape: \" + str(golden_out_data.shape))" - ] + ], + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Input data shape: (10102, 490)\n", + "Label shape: (10102,)\n" + ] + } + ], + "metadata": {} }, { "cell_type": "markdown", - "metadata": {}, "source": [ "### Initialize the accelerator" - ] + ], + "metadata": {} }, { "cell_type": "code", "execution_count": 2, - "metadata": {}, + "source": [ + "from finn_examples import models\n", + "print(list(filter(lambda x: \"kws\" in x, dir(models))))" + ], "outputs": [ { + "output_type": "display_data", "data": { - "application/javascript": [ - "\n", - "try {\n", - "require(['notebook/js/codecell'], function(codecell) {\n", - " codecell.CodeCell.options_default.highlight_modes[\n", - " 'magic_text/x-csrc'] = {'reg':[/^%%microblaze/]};\n", - " Jupyter.notebook.events.one('kernel_ready.Kernel', function(){\n", - " Jupyter.notebook.get_cells().map(function(cell){\n", - " if (cell.cell_type == 'code'){ cell.auto_highlight(); } }) ;\n", - " });\n", - "});\n", - "} catch (e) {};\n" - ] + "application/javascript": "\ntry {\nrequire(['notebook/js/codecell'], function(codecell) {\n codecell.CodeCell.options_default.highlight_modes[\n 'magic_text/x-csrc'] = {'reg':[/^%%microblaze/]};\n Jupyter.notebook.events.one('kernel_ready.Kernel', function(){\n Jupyter.notebook.get_cells().map(function(cell){\n if (cell.cell_type == 'code'){ cell.auto_highlight(); } }) ;\n });\n});\n} catch (e) {};\n" }, - "metadata": {}, - "output_type": "display_data" + "metadata": {} }, { + "output_type": "display_data", "data": { - "application/javascript": [ - "\n", - "try {\n", - "require(['notebook/js/codecell'], function(codecell) {\n", - " codecell.CodeCell.options_default.highlight_modes[\n", - " 'magic_text/x-csrc'] = {'reg':[/^%%pybind11/]};\n", - " Jupyter.notebook.events.one('kernel_ready.Kernel', function(){\n", - " Jupyter.notebook.get_cells().map(function(cell){\n", - " if (cell.cell_type == 'code'){ cell.auto_highlight(); } }) ;\n", - " });\n", - "});\n", - "} catch (e) {};\n" - ] + "application/javascript": "\ntry {\nrequire(['notebook/js/codecell'], function(codecell) {\n codecell.CodeCell.options_default.highlight_modes[\n 'magic_text/x-csrc'] = {'reg':[/^%%pybind11/]};\n Jupyter.notebook.events.one('kernel_ready.Kernel', function(){\n Jupyter.notebook.get_cells().map(function(cell){\n if (cell.cell_type == 'code'){ cell.auto_highlight(); } }) ;\n });\n});\n} catch (e) {};\n" }, - "metadata": {}, - "output_type": "display_data" + "metadata": {} }, { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "['kws_mlp']\n" ] } ], - "source": [ - "from finn_examples import models\n", - "print(list(filter(lambda x: \"kws\" in x, dir(models))))" - ] + "metadata": {} }, { "cell_type": "code", "execution_count": 3, - "metadata": {}, - "outputs": [], "source": [ "accel = models.kws_mlp()" - ] + ], + "outputs": [], + "metadata": {} }, { "cell_type": "code", "execution_count": 4, - "metadata": {}, + "source": [ + "print(\"Expected input shape and datatype: %s %s\" % (str(accel.ishape_normal), str(accel.idt)))\n", + "print(\"Expected output shape and datatype: %s %s\" % (str(accel.oshape_normal), str(accel.odt)))" + ], "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "Expected input shape and datatype: (1, 490) INT8\n", "Expected output shape and datatype: (1, 1) UINT8\n" ] } ], - "source": [ - "print(\"Expected input shape and datatype: %s %s\" % (str(accel.ishape_normal), str(accel.idt)))\n", - "print(\"Expected output shape and datatype: %s %s\" % (str(accel.oshape_normal), str(accel.odt)))" - ] + "metadata": {} }, { "cell_type": "markdown", - "metadata": {}, "source": [ "### Run validation on the FPGA" - ] + ], + "metadata": {} }, { "cell_type": "code", "execution_count": 5, - "metadata": {}, + "source": [ + "accel.batch_size = num_samples\n", + "accel_out_data = accel.execute(input_data)\n", + "\n", + "print(\"Accelerator output shape: \" + str(accel_out_data.shape))" + ], "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "Accelerator output shape: (10102, 1)\n" ] } ], - "source": [ - "accel.batch_size = num_samples\n", - "accel_out_data = accel.execute(input_data)\n", - "\n", - "print(\"Accelerator output shape: \" + str(accel_out_data.shape))" - ] + "metadata": {} }, { "cell_type": "code", "execution_count": 6, - "metadata": {}, + "source": [ + "score = np.unique(accel_out_data.flatten() == golden_out_data.flatten(), return_counts=True)\n", + "print(\"Correctly predicted: %d / %d \" % (score[1][1], num_samples))\n", + "print(\"Incorrectly predicted: %d / %d \" % (score[1][0], num_samples))\n", + "print(\"Accuracy: %f%%\" % (100.0 * score[1][1] / num_samples))" + ], "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "Correctly predicted: 8967 / 10102 \n", "Incorrectly predicted: 1135 / 10102 \n", @@ -195,95 +176,89 @@ ] } ], - "source": [ - "score = np.unique(accel_out_data.flatten() == golden_out_data.flatten(), return_counts=True)\n", - "print(\"Correctly predicted: %d / %d \" % (score[1][1], num_samples))\n", - "print(\"Incorrectly predicted: %d / %d \" % (score[1][0], num_samples))\n", - "print(\"Accuracy: %f%%\" % (100.0 * score[1][1] / num_samples))" - ] + "metadata": {} }, { "cell_type": "markdown", + "source": [ + "Here you should see an accuracy of about 88.76 %." + ], "metadata": { "pycharm": { "name": "#%% md\n" } - }, - "source": [ - "Here you should se an accuracy of about 88.76 %." - ] + } }, { "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, "source": [ "# Assessing network throughput\n", "\n", "Now we will take a look at how fast the FPGA can process the whole validation dataset." - ] + ], + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + } }, { "cell_type": "markdown", + "source": [ + "### Using a naive timing benchmark from the notebook" + ], "metadata": { "pycharm": { "name": "#%% md\n" } - }, - "source": [ - "### Using a naive timing benchmark from the notebook" - ] + } }, { "cell_type": "code", "execution_count": 7, - "metadata": {}, - "outputs": [], "source": [ "def run_validation():\n", " accel_out_data = accel.execute(input_data)" - ] + ], + "outputs": [], + "metadata": {} }, { "cell_type": "code", "execution_count": 8, - "metadata": {}, + "source": [ + "full_validation_time = %timeit -n 5 -o run_validation()" + ], "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "5 loops, best of 3: 70.2 ms per loop\n" ] } ], - "source": [ - "full_validation_time = %timeit -n 5 -o run_validation()" - ] + "metadata": {} }, { "cell_type": "code", "execution_count": 9, - "metadata": {}, + "source": [ + "print(f\"{(num_samples / float(full_validation_time.best)):.0f} samples per second including data movement\")" + ], "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "143976 samples per second including data movement\n" ] } ], - "source": [ - "print(f\"{(num_samples / float(full_validation_time.best)):.0f} samples per second including data movement\")" - ] + "metadata": {} }, { "cell_type": "markdown", - "metadata": {}, "source": [ "While the result of over 140 thousand inferences per second is already very good, this naive benchmark\n", "also includes data movement from and to the FPGA and it is dificult to assess how much time is spent on\n", @@ -293,14 +268,18 @@ "\n", "To measure the performance of indivudual components of the PYNQ stack and the FINN accelerator on the FPGA,\n", "FINN comes with a buit-in benchmark. This benchmark computes the throughput of the FINN accelerator as seen on the FPGA." - ] + ], + "metadata": {} }, { "cell_type": "code", "execution_count": 10, - "metadata": {}, + "source": [ + "accel.throughput_test()" + ], "outputs": [ { + "output_type": "execute_result", "data": { "text/plain": [ "{'DRAM_in_bandwidth[Mb/s]': 121.27598463684475,\n", @@ -317,61 +296,56 @@ " 'unpack_output[ms]': 1.1382102966308594}" ] }, - "execution_count": 10, "metadata": {}, - "output_type": "execute_result" + "execution_count": 10 } ], - "source": [ - "accel.throughput_test()" - ] + "metadata": {} }, { "cell_type": "markdown", - "metadata": {}, "source": [ "# Classifying .wav files with the KWS network\n", "\n", "Now we are going to look at how to classify raw .wav files with the KWS network. We include some sample files with finn-examples, but in theory you can also classify your own recordings. To do this one can simply modify where to load the .wav file from. However, one needs to make sure that the file is shorter than one second.\n", "\n", "First we will install python_speech_features, to generate the MFCC features later on" - ] + ], + "metadata": {} }, { "cell_type": "code", "execution_count": 11, - "metadata": {}, + "source": [ + "!pip3 install python_speech_features" + ], "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "Collecting python_speech_features\n", " Using cached python_speech_features-0.6-py3-none-any.whl\n", "Installing collected packages: python-speech-features\n", "Successfully installed python-speech-features-0.6\n", - "\u001B[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001B[0m\n" + "\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\n" ] } ], - "source": [ - "!pip install python_speech_features" - ] + "metadata": {} }, { "cell_type": "code", "execution_count": 12, - "metadata": {}, - "outputs": [], "source": [ "%matplotlib inline" - ] + ], + "outputs": [], + "metadata": {} }, { "cell_type": "code", "execution_count": 13, - "metadata": {}, - "outputs": [], "source": [ "from python_speech_features import mfcc\n", "import numpy as np\n", @@ -380,13 +354,13 @@ "from scipy.signal.windows import hann\n", "import matplotlib.pyplot as plt\n", "import IPython" - ] + ], + "outputs": [], + "metadata": {} }, { "cell_type": "code", "execution_count": 14, - "metadata": {}, - "outputs": [], "source": [ "# preprocessing parameters\n", "tf_desired_samples = 16000\n", @@ -398,13 +372,13 @@ "\n", "# Dataset parameter\n", "tf_dataset_labels = ['down', 'go', 'left', 'no', 'off', 'on', 'right', 'stop', 'up', 'yes', 'SILENCE', 'UNKNOWN']" - ] + ], + "outputs": [], + "metadata": {} }, { "cell_type": "code", "execution_count": 15, - "metadata": {}, - "outputs": [], "source": [ "# Convenience functions\n", "def py_speech_preprocessing(resampled_data, sample_rate,\n", @@ -451,25 +425,31 @@ " quant_mfcc_feat = quant_mfcc_feat.astype(np.int8).reshape((1,490))\n", " \n", " return quant_mfcc_feat" - ] + ], + "outputs": [], + "metadata": {} }, { "cell_type": "markdown", - "metadata": {}, "source": [ "## Loading and pre-processing the audio file\n", "\n", "The following sample files are included with finn-examples:" - ] + ], + "metadata": {} }, { "cell_type": "code", "execution_count": 16, - "metadata": {}, + "source": [ + "# Find sample files\n", + "audio_samples_folder = pk.resource_filename(\"finn_examples\", \"data/audio_samples/\")\n", + "!ls $audio_samples_folder" + ], "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "audio_sample_down.wav audio_sample_off.wav audio_sample_up.wav\r\n", "audio_sample_go.wav audio_sample_on.wav audio_sample_yes.wav\r\n", @@ -478,28 +458,24 @@ ] } ], - "source": [ - "# Find sample files\n", - "audio_samples_folder = pk.resource_filename(\"finn_examples\", \"data/audio_samples/\")\n", - "!ls $audio_samples_folder" - ] + "metadata": {} }, { "cell_type": "markdown", - "metadata": {}, "source": [ "#### Change sample_path variable in the line below to load your own .wav file or to load a different sample file.\n", "Make sure that the file is shorter than one second." - ] + ], + "metadata": {} }, { "cell_type": "code", "execution_count": null, - "outputs": [], "source": [ "sample_path = f\"{audio_samples_folder}audio_sample_yes.wav\"\n", "IPython.display.Audio(sample_path)" ], + "outputs": [], "metadata": { "collapsed": false, "pycharm": { @@ -510,21 +486,24 @@ { "cell_type": "code", "execution_count": 17, - "metadata": {}, - "outputs": [], "source": [ "# Read the audio wave file\n", "rate, raw_signal = wav.read(sample_path)" - ] + ], + "outputs": [], + "metadata": {} }, { "cell_type": "code", "execution_count": 18, - "metadata": {}, + "source": [ + "# Run pre-processing\n", + "mfcc_feat_py = py_speech_preprocessing(raw_signal, rate)" + ], "outputs": [ { - "name": "stderr", "output_type": "stream", + "name": "stderr", "text": [ "/usr/lib/python3/dist-packages/scipy/signal/signaltools.py:2236: FutureWarning: Using a non-tuple sequence for multidimensional indexing is deprecated; use `arr[tuple(seq)]` instead of `arr[seq]`. In the future this will be interpreted as an array index, `arr[np.array(seq)]`, which will result either in an error or a different result.\n", " Y[sl] = X[sl]\n", @@ -533,95 +512,102 @@ ] } ], - "source": [ - "# Run pre-processing\n", - "mfcc_feat_py = py_speech_preprocessing(raw_signal, rate)" - ] + "metadata": {} }, { "cell_type": "code", "execution_count": 19, - "metadata": {}, + "source": [ + "# Plot the MFCC features\n", + "plt.matshow(mfcc_feat_py)\n", + "plt.colorbar()\n", + "plt.show()" + ], "outputs": [ { + "output_type": "display_data", "data": { - "image/png": "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\n", + "image/png": "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", "text/plain": [ "" ] }, - "metadata": {}, - "output_type": "display_data" + "metadata": {} } ], - "source": [ - "# Plot the MFCC features\n", - "plt.matshow(mfcc_feat_py)\n", - "plt.colorbar()\n", - "plt.show()" - ] + "metadata": {} }, { "cell_type": "code", "execution_count": 20, - "metadata": {}, - "outputs": [], "source": [ "# Quantize MFCC features\n", "quant_mfcc_feat = quantize_input(mfcc_feat_py)" - ] + ], + "outputs": [], + "metadata": {} }, { "cell_type": "markdown", - "metadata": {}, "source": [ "## Classifying the pre-processed audio on the FPGA" - ] + ], + "metadata": {} }, { "cell_type": "code", "execution_count": 21, - "metadata": {}, - "outputs": [], "source": [ "# Run inference on the FPGA\n", "accel.batch_size = 1\n", "res_acc = accel.execute(quant_mfcc_feat)" - ] + ], + "outputs": [], + "metadata": {} }, { "cell_type": "code", "execution_count": 22, - "metadata": {}, + "source": [ + "res_label = tf_dataset_labels[res_acc[0,0].astype(np.int)]\n", + "print(f\"The audio file was classified as: {res_label}\")" + ], "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "The audio file was classified as: yes\n" ] } ], - "source": [ - "res_label = tf_dataset_labels[res_acc[0,0].astype(np.int)]\n", - "print(f\"The audio file was classified as: {res_label}\")" - ] + "metadata": {} }, { "cell_type": "markdown", - "metadata": {}, "source": [ "If everything went well you should see the audio file being classified correctly.\n", "\n", "However,you may notice that the 'down' sample is wrongly classified as 'go'. This is likely a side effect of the KWS network being a very simple architecture. This means that the network works better for some classes than others." - ] + ], + "metadata": {} }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "source": [ + "sample_classes = ['down', 'go', 'left', 'no', 'off', 'on', 'right', 'stop', 'up', 'yes']\n", + "for sample_class in sample_classes:\n", + " rate, raw_signal = wav.read(f\"{audio_samples_folder}audio_sample_{sample_class}.wav\")\n", + " mfcc_feat_py = py_speech_preprocessing(raw_signal, rate)\n", + " quant_mfcc_feat = quantize_input(mfcc_feat_py)\n", + " accel.batch_size = 1\n", + " res_acc = accel.execute(quant_mfcc_feat)\n", + " res_label = tf_dataset_labels[res_acc[0,0].astype(np.int)]\n", + " print(f\"The audio file for {sample_class} was classified as: {res_label}\")" + ], "outputs": [], - "source": [] + "metadata": {} } ], "metadata": { From 40c69de99d85e8aa0c44f893a3646b341fd4b0d8 Mon Sep 17 00:00:00 2001 From: Mirza Mrahorovic Date: Fri, 5 Nov 2021 12:34:17 +0000 Subject: [PATCH 48/49] Generate HLS files after (potentially) resetting nodes --- build/resnet50/custom_steps.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/build/resnet50/custom_steps.py b/build/resnet50/custom_steps.py index 86484eb..afa1693 100644 --- a/build/resnet50/custom_steps.py +++ b/build/resnet50/custom_steps.py @@ -308,6 +308,13 @@ def step_resnet50_set_fifo_depths(model: ModelWrapper, cfg: DataflowBuildConfig) model, cfg.output_dir + "/final_hw_config.json", hw_attrs ) + # after FIFOs are ready to go, call PrepareIP and HLSSynthIP again + # this will only run for the new nodes (e.g. FIFOs and DWCs) + model = model.transform( + PrepareIP(cfg._resolve_fpga_part(), cfg._resolve_hls_clk_period()) + ) + model = model.transform(HLSSynthIP()) + model = model.transform(ReplaceVerilogRelPaths()) return model From a3ffcecb4ea886a1226fc6a8475f98cd13a8e688 Mon Sep 17 00:00:00 2001 From: Yaman Umuroglu Date: Fri, 5 Nov 2021 15:55:34 +0100 Subject: [PATCH 49/49] bump version number+finn-base+finn ver for builds --- build/get-finn.sh | 2 +- setup.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build/get-finn.sh b/build/get-finn.sh index a4a4485..c0b41b8 100755 --- a/build/get-finn.sh +++ b/build/get-finn.sh @@ -30,7 +30,7 @@ # URL for git repo to be cloned REPO_URL=https://github.com/Xilinx/finn # commit hash for repo -REPO_COMMIT=36d5de9fc7f414f95e31a877e912e6c9e5ce3564 +REPO_COMMIT=d1cc9cf94f1c33354cc169c5a6517314d0e94e3b # directory (under the same folder as this script) to clone to REPO_DIR=finn diff --git a/setup.py b/setup.py index 31baa02..cc741fb 100644 --- a/setup.py +++ b/setup.py @@ -91,7 +91,7 @@ def extend_package(path): setup( name=module_name, - version="0.0.3b", + version="0.0.4", description="FINN Examples on PYNQ for Zynq and Alveo", long_description=long_description, long_description_content_type="text/markdown", @@ -109,7 +109,7 @@ def extend_package(path): setup_requires=["pynq>=2.5.1"], install_requires=[ "pynq>=2.5.1", - "finn-base==0.0.2b0", + "finn-base==0.0.3", "finn-dataset_loading==0.0.5", # noqa ], extras_require={