diff --git a/src/finn/custom_op/fpgadataflow/streamingfclayer_batch.py b/src/finn/custom_op/fpgadataflow/streamingfclayer_batch.py index 29773f297364a1fa299fcf4e618c1c9875793ecd..0ac85daba2424df9d8f87dcaa96dfc1a46a1acb0 100644 --- a/src/finn/custom_op/fpgadataflow/streamingfclayer_batch.py +++ b/src/finn/custom_op/fpgadataflow/streamingfclayer_batch.py @@ -14,8 +14,6 @@ class StreamingFCLayer_Batch(HLSCustomOp): def get_nodeattr_types(self): my_attrs = { - "WMEM": ("i", True, 0), - "TMEM": ("i", True, 0), "PE": ("i", True, 0), "SIMD": ("i", True, 0), "MW": ("i", True, 0), @@ -29,10 +27,30 @@ class StreamingFCLayer_Batch(HLSCustomOp): # use xnor-popcount for binary weights/inputs, thus treating them # as bipolar "binaryXnorMode": ("i", False, 0), + # no-activation mode (produce accumulators) + "noActivation": ("i", False, 0), } my_attrs.update(super().get_nodeattr_types()) return my_attrs + def calc_wmem(self): + mw = self.get_nodeattr("MW") + mh = self.get_nodeattr("MH") + pe = self.get_nodeattr("PE") + simd = self.get_nodeattr("SIMD") + assert mh % pe == 0 + assert mw % simd == 0 + wmem = mw * mh // (pe * simd) + return wmem + + def calc_tmem(self): + if self.get_nodeattr("noActivation") == 1: + return 0 + else: + mh = self.get_nodeattr("MH") + pe = self.get_nodeattr("PE") + return mh // pe + def make_shape_compatible_op(self): pass @@ -106,7 +124,7 @@ class StreamingFCLayer_Batch(HLSCustomOp): mh = self.get_nodeattr("MH") pe = self.get_nodeattr("PE") simd = self.get_nodeattr("SIMD") - wmem = mw * mh // (pe * simd) + wmem = self.calc_wmem() assert orig_weight_matrix.shape == (mw, mh) assert mw % simd == 0 assert mh % pe == 0 @@ -184,15 +202,13 @@ class StreamingFCLayer_Batch(HLSCustomOp): self.get_nodeattr("SIMD"), export_wdt.get_hls_datatype_str(), self.get_nodeattr("PE"), - self.get_nodeattr("WMEM"), + self.calc_wmem(), ) ) else: f_weights.write( "static BinaryWeights<{},{},{}> weights = ".format( - self.get_nodeattr("SIMD"), - self.get_nodeattr("PE"), - self.get_nodeattr("WMEM"), + self.get_nodeattr("SIMD"), self.get_nodeattr("PE"), self.calc_wmem() ) ) f_weights.write(weight_hls_code) @@ -229,7 +245,7 @@ class StreamingFCLayer_Batch(HLSCustomOp): f_thresh.write( "static ThresholdsActivation<{},{},{},{},{},{},{}> threshs \ = ".format( - self.get_nodeattr("TMEM"), + self.calc_tmem(), self.get_nodeattr("PE"), threshold_tensor.shape[-1], tdt_hls, @@ -291,10 +307,8 @@ class StreamingFCLayer_Batch(HLSCustomOp): def global_includes(self): self.code_gen_dict["$GLOBALS$"] = ['#include "weights.hpp"'] self.code_gen_dict["$GLOBALS$"] += ['#include "activations.hpp"'] - if self.get_nodeattr("WMEM") != 0: - # TODO find a better way of checking for no pregenerated weights - self.code_gen_dict["$GLOBALS$"] += ['#include "params.h"'] - if self.get_nodeattr("TMEM") != 0: + self.code_gen_dict["$GLOBALS$"] += ['#include "params.h"'] + if self.calc_tmem() != 0: # TODO find a better way of checking for no pregenerated thresholds self.code_gen_dict["$GLOBALS$"] += ['#include "thresh.h"'] @@ -308,8 +322,8 @@ class StreamingFCLayer_Batch(HLSCustomOp): self.get_nodeattr("MH"), self.get_nodeattr("SIMD"), self.get_nodeattr("PE"), - self.get_nodeattr("WMEM"), - self.get_nodeattr("TMEM"), + self.calc_wmem(), + self.calc_tmem(), numReps, ) ] @@ -344,7 +358,7 @@ class StreamingFCLayer_Batch(HLSCustomOp): def docompute(self): node = self.onnx_node tmpl_args = self.get_template_param_values() - if self.get_nodeattr("TMEM") == 0: + if self.calc_tmem() == 0: odtype_hls_str = self.get_output_datatype().get_hls_datatype_str() threshs = "PassThroughActivation<%s>()" % odtype_hls_str else: diff --git a/tests/fpgadataflow/test_code_gen_trafo.py b/tests/fpgadataflow/test_code_gen_trafo.py index 53f74ffcbd72cb1338bc39cbe012880b892fc737..533710605e2bc514ba0fb0c8784c378d07451951 100644 --- a/tests/fpgadataflow/test_code_gen_trafo.py +++ b/tests/fpgadataflow/test_code_gen_trafo.py @@ -15,12 +15,9 @@ def test_code_gen_trafo(): mh = 8 pe = 4 simd = 4 - wmem = mw * mh // (pe * simd) - nf = mh // pe - sf = mw // simd - inp = helper.make_tensor_value_info("inp", TensorProto.FLOAT, [1, sf, simd]) - outp = helper.make_tensor_value_info("outp", TensorProto.FLOAT, [1, nf, pe]) + inp = helper.make_tensor_value_info("inp", TensorProto.FLOAT, [1, mw]) + outp = helper.make_tensor_value_info("outp", TensorProto.FLOAT, [1, mh]) node_inp_list = ["inp", "weights", "thresh"] FCLayer_node = helper.make_node( "StreamingFCLayer_Batch", @@ -35,11 +32,10 @@ def test_code_gen_trafo(): MH=mh, SIMD=simd, PE=pe, - WMEM=wmem, - TMEM=0, inputDataType=idt.name, weightDataType=wdt.name, outputDataType=odt.name, + noActivation=1, ) graph = helper.make_graph( nodes=[FCLayer_node], name="fclayer_graph", inputs=[inp], outputs=[outp] diff --git a/tests/fpgadataflow/test_compilation_trafo.py b/tests/fpgadataflow/test_compilation_trafo.py index fd4174f27b2b9db1fae4f95589a5c9832679cc32..f84ce34b54b3496f7e277e55ac574124e09c25d3 100644 --- a/tests/fpgadataflow/test_compilation_trafo.py +++ b/tests/fpgadataflow/test_compilation_trafo.py @@ -16,12 +16,9 @@ def test_compilation_trafo(): mh = 8 pe = 4 simd = 4 - wmem = mw * mh // (pe * simd) - nf = mh // pe - sf = mw // simd - inp = helper.make_tensor_value_info("inp", TensorProto.FLOAT, [1, sf, simd]) - outp = helper.make_tensor_value_info("outp", TensorProto.FLOAT, [1, nf, pe]) + inp = helper.make_tensor_value_info("inp", TensorProto.FLOAT, [1, mw]) + outp = helper.make_tensor_value_info("outp", TensorProto.FLOAT, [1, mh]) node_inp_list = ["inp", "weights", "thresh"] FCLayer_node = helper.make_node( "StreamingFCLayer_Batch", @@ -36,11 +33,10 @@ def test_compilation_trafo(): MH=mh, SIMD=simd, PE=pe, - WMEM=wmem, - TMEM=0, inputDataType=idt.name, weightDataType=wdt.name, outputDataType=odt.name, + noActivation=1, ) graph = helper.make_graph( nodes=[FCLayer_node], name="fclayer_graph", inputs=[inp], outputs=[outp] diff --git a/tests/fpgadataflow/test_fpgadataflow_fclayer.py b/tests/fpgadataflow/test_fpgadataflow_fclayer.py index 5ce7d9ff23c3877791a3d825ebe91cab9af56e92..0df66c4af2cfbadead8e95322c433cf69d4d2715 100644 --- a/tests/fpgadataflow/test_fpgadataflow_fclayer.py +++ b/tests/fpgadataflow/test_fpgadataflow_fclayer.py @@ -19,13 +19,6 @@ def make_single_fclayer_modelwrapper(W, pe, simd, wdt, idt, odt, T=None, tdt=Non mh = W.shape[1] assert mh % pe == 0 assert mw % simd == 0 - wmem = mw * mh // (pe * simd) - assert mw * mh == wmem * pe * simd - nf = mh // pe - if T is not None: - tmem = nf - else: - tmem = 0 # there are two ways to implement bipolar weights and inputs for # StreamingFC: @@ -45,6 +38,7 @@ def make_single_fclayer_modelwrapper(W, pe, simd, wdt, idt, odt, T=None, tdt=Non inp = helper.make_tensor_value_info("inp", TensorProto.FLOAT, [1, mw]) outp = helper.make_tensor_value_info("outp", TensorProto.FLOAT, [1, mh]) if T is not None: + no_act = 0 node_inp_list = ["inp", "weights", "thresh"] if odt == DataType.BIPOLAR: actval = 0 @@ -54,6 +48,7 @@ def make_single_fclayer_modelwrapper(W, pe, simd, wdt, idt, odt, T=None, tdt=Non # no thresholds node_inp_list = ["inp", "weights"] actval = 0 + no_act = 1 FCLayer_node = helper.make_node( "StreamingFCLayer_Batch", node_inp_list, @@ -65,13 +60,12 @@ def make_single_fclayer_modelwrapper(W, pe, simd, wdt, idt, odt, T=None, tdt=Non MH=mh, SIMD=simd, PE=pe, - WMEM=wmem, - TMEM=tmem, inputDataType=export_idt.name, weightDataType=export_wdt.name, outputDataType=odt.name, ActVal=actval, binaryXnorMode=binary_xnor_mode, + noActivation=no_act, ) graph = helper.make_graph( nodes=[FCLayer_node], name="fclayer_graph", inputs=[inp], outputs=[outp] diff --git a/tests/test_set_attribute.py b/tests/test_set_attribute.py index 43688f212c612959291938e44d34f6badedb6396..7e56fdbb938441115bf458532560af8ac803b4f9 100644 --- a/tests/test_set_attribute.py +++ b/tests/test_set_attribute.py @@ -10,13 +10,10 @@ def test_set_attribute(): mh = 8 pe = 4 simd = 4 - wmem = mw * mh // (pe * simd) - nf = mh // pe - sf = mw // simd idt = odt = wdt = DataType.BIPOLAR - inp = helper.make_tensor_value_info("inp", TensorProto.FLOAT, [1, sf, simd]) - outp = helper.make_tensor_value_info("outp", TensorProto.FLOAT, [1, nf, pe]) + inp = helper.make_tensor_value_info("inp", TensorProto.FLOAT, [1, mw]) + outp = helper.make_tensor_value_info("outp", TensorProto.FLOAT, [1, mh]) node_inp_list = ["inp", "weights"] FCLayer_node = helper.make_node( @@ -32,7 +29,6 @@ def test_set_attribute(): MH=mh, SIMD=simd, PE=pe, - WMEM=wmem, inputDataType=idt.name, weightDataType=wdt.name, outputDataType=odt.name,