diff --git a/src/finn/qnn-data/test_ext_weights/tfc-w1a1-extw.json b/src/finn/qnn-data/test_ext_weights/tfc-w1a1-extw.json new file mode 100644 index 0000000000000000000000000000000000000000..1476e3df8a6cbfed7312a17cfb25e75516099cac --- /dev/null +++ b/src/finn/qnn-data/test_ext_weights/tfc-w1a1-extw.json @@ -0,0 +1,30 @@ +{ + "Defaults": {}, + "Thresholding_Batch_0": { + "PE": 49, + "ram_style": "distributed" + }, + "StreamingFCLayer_Batch_0": { + "PE": 16, + "SIMD": 49, + "ram_style": "block" + }, + "StreamingFCLayer_Batch_1": { + "PE": 8, + "SIMD": 8, + "mem_mode": "external" + }, + "StreamingFCLayer_Batch_2": { + "PE": 8, + "SIMD": 8, + "ram_style": "auto" + }, + "StreamingFCLayer_Batch_3": { + "PE": 10, + "SIMD": 8, + "ram_style": "distributed" + }, + "LabelSelect_Batch_0": { + "PE": 1 + } + } diff --git a/tests/end2end/test_ext_weights.py b/tests/end2end/test_ext_weights.py index b98494cd3cc6b0157506a55a3a2e7dfd7b0bc38d..de0dfd86c7b75d4bf60bdad3878107127e3919ba 100644 --- a/tests/end2end/test_ext_weights.py +++ b/tests/end2end/test_ext_weights.py @@ -26,15 +26,6 @@ # 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 torch -from brevitas.nn import QuantLinear, QuantReLU -import torch.nn as nn -import numpy as np -from brevitas.core.quant import QuantType -from brevitas.nn import QuantIdentity -import brevitas.onnx as bo -from finn.core.modelwrapper import ModelWrapper -from finn.core.datatype import DataType import finn.builder.build_dataflow as build import finn.builder.build_dataflow_config as build_cfg import os @@ -43,20 +34,24 @@ from finn.util.test import get_build_env, load_test_checkpoint_or_skip import pytest from finn.util.basic import make_build_dir import pkg_resources as pk -import json import wget import subprocess target_clk_ns = 10 build_kind = "zynq" build_dir = os.environ["FINN_BUILD_DIR"] -onnx_zip_url = "https://github.com/Xilinx/finn-examples/releases/download/v0.0.1a/onnx-models-bnn-pynq.zip" +onnx_zip_url = "https://github.com/Xilinx/finn-examples" +onnx_zip_url += "/releases/download/v0.0.1a/onnx-models-bnn-pynq.zip" onnx_zip_local = build_dir + "/onnx-models-bnn-pynq.zip" +onnx_dir_local = build_dir + "/onnx-models-bnn-pynq" + def get_checkpoint_name(step): if step == "build": # checkpoint for build step is an entire dir return build_dir + "/end2end_ext_weights_build" + elif step == "download": + return onnx_dir_local + "/tfc-w1a1.onnx" else: # other checkpoints are onnx files return build_dir + "/end2end_ext_weights_%s.onnx" % (step) @@ -66,4 +61,93 @@ def test_end2end_ext_weights_download(): if not os.path.isfile(onnx_zip_local): wget.download(onnx_zip_url, out=onnx_zip_local) assert os.path.isfile(onnx_zip_local) - subprocess.check_output(['unzip', onnx_zip_local]) + subprocess.check_output(["unzip", "-o", onnx_zip_local, "-d", onnx_dir_local]) + assert os.path.isfile(get_checkpoint_name("download")) + + +def test_end2end_ext_weights_build(): + model_file = get_checkpoint_name("download") + load_test_checkpoint_or_skip(model_file) + build_env = get_build_env(build_kind, target_clk_ns) + folding_config_file = pk.resource_filename( + "finn.qnn-data", "test_ext_weights/tfc-w1a1-extw.json" + ) + output_dir = make_build_dir("test_end2end_ext_weights_build") + cfg = build.DataflowBuildConfig( + output_dir=output_dir, + folding_config_file=folding_config_file, + synth_clk_period_ns=target_clk_ns, + board=build_env["board"], + shell_flow_type=build_cfg.ShellFlowType.VIVADO_ZYNQ, + generate_outputs=[ + build_cfg.DataflowOutputType.ESTIMATE_REPORTS, + build_cfg.DataflowOutputType.BITFILE, + build_cfg.DataflowOutputType.PYNQ_DRIVER, + build_cfg.DataflowOutputType.DEPLOYMENT_PACKAGE, + ], + ) + build.build_dataflow_cfg(model_file, cfg) + assert os.path.isfile(output_dir + "/deploy/bitfile/finn-accel.bit") + assert os.path.isfile(output_dir + "/deploy/bitfile/finn-accel.hwh") + assert os.path.isfile(output_dir + "/deploy/driver/driver.py") + assert os.path.isfile(output_dir + "/deploy/driver/runtime_weights/idma0.npy") + shutil.copytree(output_dir + "/deploy", get_checkpoint_name("build")) + + +def test_end2end_ext_weights_run_on_hw(): + build_env = get_build_env(build_kind, target_clk_ns) + deploy_dir = get_checkpoint_name("build") + if not os.path.isdir(deploy_dir): + pytest.skip(deploy_dir + " not found from previous test step, skipping") + driver_dir = deploy_dir + "/driver" + assert os.path.isdir(driver_dir) + # create a shell script for running validation: 10 batches x 10 imgs + with open(driver_dir + "/validate.sh", "w") as f: + f.write( + """#!/bin/bash +cd %s/driver +echo %s | sudo -S python3.6 validate.py --dataset mnist --bitfile %s + """ + % ( + build_env["target_dir"] + "/end2end_ext_weights_build", + build_env["password"], + "../bitfile/finn-accel.bit", + ) + ) + # set up rsync command + remote_target = "%s@%s:%s" % ( + build_env["username"], + build_env["ip"], + build_env["target_dir"], + ) + rsync_res = subprocess.run( + [ + "sshpass", + "-p", + build_env["password"], + "rsync", + "-avz", + deploy_dir, + remote_target, + ] + ) + assert rsync_res.returncode == 0 + remote_verif_cmd = [ + "sshpass", + "-p", + build_env["password"], + "ssh", + "%s@%s" % (build_env["username"], build_env["ip"]), + "sh", + build_env["target_dir"] + "/end2end_ext_weights_build/driver/validate.sh", + ] + verif_res = subprocess.run( + remote_verif_cmd, + stdout=subprocess.PIPE, + universal_newlines=True, + input=build_env["password"], + ) + assert verif_res.returncode == 0 + log_output = verif_res.stdout.split("\n") + assert log_output[-3] == "batch 100 / 100 : total OK 9296 NOK 704" + assert log_output[-2] == "Final accuracy: 92.960000"