From bb5e4049b250b52d025da44385542604eba8aad3 Mon Sep 17 00:00:00 2001 From: Yaman Umuroglu <maltanar@gmail.com> Date: Thu, 24 Sep 2020 22:26:40 +0200 Subject: [PATCH] [Refactor] path ext in init.py, reg ops in custom_op/__init__.py --- src/finn/custom_op/__init__.py | 146 +++++++----------- src/finn/custom_op/fpgadataflow/__init__.py | 6 +- .../transformation/streamline/__init__.py | 4 + 3 files changed, 64 insertions(+), 92 deletions(-) diff --git a/src/finn/custom_op/__init__.py b/src/finn/custom_op/__init__.py index 4ae7b9ebf..08207a351 100644 --- a/src/finn/custom_op/__init__.py +++ b/src/finn/custom_op/__init__.py @@ -26,101 +26,65 @@ # 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 abc import ABC, abstractmethod -from finn.util.basic import get_by_name -import onnx.helper as helper +from pkgutil import extend_path +__path__ = extend_path(__path__, __name__) -class CustomOp(ABC): - """CustomOp class all custom op nodes are based on. Contains different functions - every custom node should have. Some as abstract methods, these have to be - filled when writing a new custom op node.""" +from finn.custom_op.registry import custom_op - def __init__(self, onnx_node): - super().__init__() - self.onnx_node = onnx_node +# make sure new CustomOp subclasses are imported here so that they get +# registered and plug in correctly into the infrastructure +from finn.custom_op.fpgadataflow.convolutioninputgenerator import ( + ConvolutionInputGenerator, +) +from finn.custom_op.fpgadataflow.downsampler import DownSampler +from finn.custom_op.fpgadataflow.streamingfclayer_batch import StreamingFCLayer_Batch +from finn.custom_op.fpgadataflow.streamingmaxpool_batch import StreamingMaxPool_Batch +from finn.custom_op.fpgadataflow.streamingfifo import StreamingFIFO +from finn.custom_op.fpgadataflow.tlastmarker import TLastMarker +from finn.custom_op.fpgadataflow.streamingdatawidthconverter_batch import ( + StreamingDataWidthConverter_Batch, +) +from finn.custom_op.fpgadataflow.globalaccpool_batch import GlobalAccPool_Batch +from finn.custom_op.fpgadataflow.pool_batch import Pool_Batch +from finn.custom_op.fpgadataflow.fmpadding_batch import FMPadding_Batch +from finn.custom_op.fpgadataflow.thresholding_batch import Thresholding_Batch +from finn.custom_op.fpgadataflow.addstreams_batch import AddStreams_Batch +from finn.custom_op.fpgadataflow.labelselect_batch import LabelSelect_Batch +from finn.custom_op.fpgadataflow.duplicatestreams_batch import DuplicateStreams_Batch +from finn.custom_op.fpgadataflow.vector_vector_activate_batch import ( + Vector_Vector_Activate_Batch, +) +from finn.custom_op.fpgadataflow.channelwise_op_batch import ChannelwiseOp_Batch +from finn.custom_op.fpgadataflow.iodma import IODMA - def get_nodeattr(self, name): - """Get a node attribute by name. Data is stored inside the ONNX node's - AttributeProto container. Attribute must be part of get_nodeattr_types. - Default value is returned if attribute is not set.""" - try: - (dtype, req, def_val) = self.get_nodeattr_types()[name] - attr = get_by_name(self.onnx_node.attribute, name) - if attr is not None: - # dtype indicates which ONNX Attribute member to use - # (such as i, f, s...) - ret = attr.__getattribute__(dtype) - if dtype == "s": - # decode string attributes - ret = ret.decode("utf-8") - return ret - else: - if req: - raise Exception( - """Required attribute %s unspecified in - a %s node""" - % (name, self.onnx_node.op_type) - ) - else: - # not set, return default value - return def_val - except KeyError: - raise AttributeError("Op has no such attribute: " + name) - def set_nodeattr(self, name, value): - """Set a node attribute by name. Data is stored inside the ONNX node's - AttributeProto container. Attribute must be part of get_nodeattr_types.""" - try: - (dtype, req, def_val) = self.get_nodeattr_types()[name] - attr = get_by_name(self.onnx_node.attribute, name) - if attr is not None: - # dtype indicates which ONNX Attribute member to use - # (such as i, f, s...) - if dtype == "s": - # encode string attributes - value = value.encode("utf-8") - attr.__setattr__(dtype, value) - else: - # not set, create and insert AttributeProto - attr_proto = helper.make_attribute(name, value) - self.onnx_node.attribute.append(attr_proto) - except KeyError: - raise AttributeError("Op has no such attribute: " + name) +custom_op["DownSampler"] = DownSampler +custom_op["StreamingMaxPool_Batch"] = StreamingMaxPool_Batch +custom_op["StreamingFCLayer_Batch"] = StreamingFCLayer_Batch +custom_op["ConvolutionInputGenerator"] = ConvolutionInputGenerator +custom_op["TLastMarker"] = TLastMarker +custom_op["StreamingDataWidthConverter_Batch"] = StreamingDataWidthConverter_Batch +custom_op["StreamingFIFO"] = StreamingFIFO +custom_op["GlobalAccPool_Batch"] = GlobalAccPool_Batch +custom_op["Pool_Batch"] = Pool_Batch +custom_op["FMPadding_Batch"] = FMPadding_Batch +custom_op["Thresholding_Batch"] = Thresholding_Batch +custom_op["AddStreams_Batch"] = AddStreams_Batch +custom_op["LabelSelect_Batch"] = LabelSelect_Batch +custom_op["DuplicateStreams_Batch"] = DuplicateStreams_Batch +custom_op["Vector_Vector_Activate_Batch"] = Vector_Vector_Activate_Batch +custom_op["ChannelwiseOp_Batch"] = ChannelwiseOp_Batch +custom_op["IODMA"] = IODMA - @abstractmethod - def get_nodeattr_types(self): - """Returns a dict of permitted attributes for node, where: - returned_dict[attribute_name] = (dtype, require, default_value) - - dtype indicates which member of the ONNX AttributeProto - will be utilized - - require indicates whether this attribute is required - - default_val indicates the default value that will be used if the - attribute is not set - """ - pass - @abstractmethod - def make_shape_compatible_op(self, model): - """Returns a standard ONNX op which is compatible with this CustomOp - for performing shape inference.""" - pass - - @abstractmethod - def infer_node_datatype(self, model): - """Set the DataType annotations corresponding to the outputs of this - node.""" - pass - - @abstractmethod - def execute_node(self, context, graph): - """Execute this CustomOp instance, given the execution context and - ONNX graph.""" - pass - - @abstractmethod - def verify_node(self): - """Verifies that all attributes the node needs are there and - that particular attributes are set correctly. Also checks if - the number of inputs is equal to the expected number.""" - pass +def getCustomOp(node): + "Return a FINN CustomOp instance for the given ONNX node, if it exists." + op_type = node.op_type + try: + # lookup op_type in registry of CustomOps + inst = custom_op[op_type](node) + return inst + except KeyError: + # exception if op_type is not supported + raise Exception("Custom op_type %s is currently not supported." % op_type) diff --git a/src/finn/custom_op/fpgadataflow/__init__.py b/src/finn/custom_op/fpgadataflow/__init__.py index 7de6cce93..df03a036f 100644 --- a/src/finn/custom_op/fpgadataflow/__init__.py +++ b/src/finn/custom_op/fpgadataflow/__init__.py @@ -25,12 +25,16 @@ # 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. +# namespace package, extend path +from pkgutil import extend_path + +__path__ = extend_path(__path__, __name__) from abc import abstractmethod import numpy as np import os import subprocess -from finn.custom_op import CustomOp +from finn.custom_op.custom_op import CustomOp from finn.util.basic import ( CppBuilder, make_build_dir, diff --git a/src/finn/transformation/streamline/__init__.py b/src/finn/transformation/streamline/__init__.py index d7686eaad..bf0307031 100644 --- a/src/finn/transformation/streamline/__init__.py +++ b/src/finn/transformation/streamline/__init__.py @@ -25,6 +25,10 @@ # 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. +# namespace package, extend path +from pkgutil import extend_path + +__path__ = extend_path(__path__, __name__) from finn.transformation import Transformation from finn.transformation.infer_datatypes import InferDataTypes -- GitLab