From 14929f41e948881a0ce20040c25ff2957928c7a0 Mon Sep 17 00:00:00 2001 From: auphelia Date: Wed, 3 Jan 2024 15:43:58 +0000 Subject: [PATCH] [Deconv] Update test and add comments to transformation --- .../infer_pixel_padding_deconv.py | 25 ++++++++++++------- .../fpgadataflow/test_fpgadataflow_deconv.py | 22 +++++++++++----- 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/src/finn/transformation/fpgadataflow/infer_pixel_padding_deconv.py b/src/finn/transformation/fpgadataflow/infer_pixel_padding_deconv.py index 8642f5e0ef..8dbf7071fc 100644 --- a/src/finn/transformation/fpgadataflow/infer_pixel_padding_deconv.py +++ b/src/finn/transformation/fpgadataflow/infer_pixel_padding_deconv.py @@ -7,8 +7,14 @@ class InferPixelPaddingDeconv(Transformation): - def __init__(self): - super().__init__() + """ + Lowering and conversion of ConvTranspose (NCHW) nodes to + FMPadding_Pixel + Im2Col + MatMul (NHWC) surrounded by Transpose nodes + note: this transformation produces a mix of hw layers and non hw layers + to implement this on an FPGA the Im2Col and MatMul nodes need to be converted to hw layers + after applying this transformation and the resulting transpose nodes need to be streamlined. + See deconv test case under tests/fpgadataflow for an example. + """ def apply(self, model): graph = model.graph @@ -17,6 +23,14 @@ def apply(self, model): for n in graph.node: node_ind += 1 if n.op_type == "ConvTranspose": + # conversion currently only supported for group=1 + group = get_by_name(n.attribute, "group").i + if group != 1: + warnings.warn( + "%s : Only group=1 is currently supported. Can't infer PixelPaddingDeconv." + % n.name + ) + continue deconv_input = n.input[0] deconv_output = n.output[0] idt = model.get_tensor_datatype(deconv_input) @@ -25,13 +39,6 @@ def apply(self, model): k_w = get_by_name(n.attribute, "kernel_shape").ints[1] stride_h = get_by_name(n.attribute, "strides").ints[0] stride_w = get_by_name(n.attribute, "strides").ints[1] - group = get_by_name(n.attribute, "group").i - if group != 1: - warnings.warn( - "%s : Only group=1 is currently supported. Can't infer PixelPaddingDeconv." - % n.name - ) - continue weight_name = n.input[1] W_conv = model.get_initializer(weight_name) ifm_ch = model.get_tensor_shape(n.input[0])[1] # assume NCHW diff --git a/tests/fpgadataflow/test_fpgadataflow_deconv.py b/tests/fpgadataflow/test_fpgadataflow_deconv.py index d5edec9b35..6c25be0f85 100644 --- a/tests/fpgadataflow/test_fpgadataflow_deconv.py +++ b/tests/fpgadataflow/test_fpgadataflow_deconv.py @@ -28,6 +28,7 @@ import pytest +import numpy as np import os from onnx import TensorProto, helper from qonnx.core.datatype import DataType @@ -38,6 +39,7 @@ from qonnx.util.basic import gen_finn_dt_tensor, qonnx_make_model import finn.core.onnx_exec as oxe +from finn.analysis.fpgadataflow.exp_cycles_per_layer import exp_cycles_per_layer from finn.transformation.fpgadataflow.compile_cppsim import CompileCppSim from finn.transformation.fpgadataflow.convert_to_hls_layers import ( InferConvInpGen, @@ -177,14 +179,12 @@ def test_fpgadataflow_deconv(idim, stride, ifm_ch, ofm_ch, simd, pe, k, padding, expected_oshape = (1, ofm_ch, odim_h, odim_w) y_expected = oxe.execute_onnx(ref_model, input_dict)["outp"] + # cppsim if exec_mode == "cppsim": model = model.transform(PrepareCppSim()) model = model.transform(CompileCppSim()) model = model.transform(SetExecMode("cppsim")) - y_produced = oxe.execute_onnx(model, input_dict)["outp"] - assert y_produced.shape == expected_oshape - assert (y_produced == y_expected).all() # rtlsim else: @@ -192,6 +192,16 @@ def test_fpgadataflow_deconv(idim, stride, ifm_ch, ofm_ch, simd, pe, k, padding, model = model.transform(HLSSynthIP()) model = model.transform(PrepareRTLSim()) model = model.transform(SetExecMode("rtlsim")) - y_produced = oxe.execute_onnx(model, input_dict)["outp"] - assert y_produced.shape == expected_oshape - assert (y_produced == y_expected).all() + + y_produced = oxe.execute_onnx(model, input_dict)["outp"] + assert y_produced.shape == expected_oshape + assert (y_produced == y_expected).all() + + if exec_mode == "rtlsim": + node = model.get_nodes_by_op_type("FMPadding_Pixel")[0] + inst = getCustomOp(node) + cycles_rtlsim = inst.get_nodeattr("cycles_rtlsim") + exp_cycles_dict = model.analysis(exp_cycles_per_layer) + exp_cycles = exp_cycles_dict[node.name] + assert np.isclose(exp_cycles, cycles_rtlsim, atol=10) + assert exp_cycles != 0