From 2ceb009736498fd735346c95441785a9ba7adaa9 Mon Sep 17 00:00:00 2001 From: Yaman Umuroglu <maltanar@gmail.com> Date: Tue, 3 Dec 2019 00:09:53 +0000 Subject: [PATCH] [CustomOp] remove non-batch StreamingMaxPool for now --- .../fpgadataflow/streamingmaxpool.py | 191 ------------------ src/finn/custom_op/registry.py | 4 +- .../test_layer_streaming_maxpool.py | 80 -------- 3 files changed, 1 insertion(+), 274 deletions(-) delete mode 100644 src/finn/custom_op/fpgadataflow/streamingmaxpool.py delete mode 100644 tests/fpgadataflow/test_layer_streaming_maxpool.py diff --git a/src/finn/custom_op/fpgadataflow/streamingmaxpool.py b/src/finn/custom_op/fpgadataflow/streamingmaxpool.py deleted file mode 100644 index ee35b476a..000000000 --- a/src/finn/custom_op/fpgadataflow/streamingmaxpool.py +++ /dev/null @@ -1,191 +0,0 @@ -import os -import subprocess -import tempfile as tmp - -import numpy as np - -from finn.custom_op.fpgadataflow import HLSCustomOp - - -class StreamingMaxPool(HLSCustomOp): - def get_nodeattr_types(self): - my_attrs = { - "ImgDim": ("i", True, 0), - "PoolDim": ("i", True, 0), - "NumChannels": ("i", True, 0), - } - my_attrs.update(super().get_nodeattr_types()) - return my_attrs - - def make_shape_compatible_op(self): - pass - - def infer_node_datatype(self, model): - pass - - def execute_node(self, context, graph): - node = self.onnx_node - # make temporary directory for generated files - self.tmp_dir = tmp.mkdtemp(prefix=str(node.op_type) + "_") - - # create empty list for temporary files to enable the option - # to delete the files after the execution - temp_files = [] - - # create a npy file fore each input of the node (in_ind is input index) - in_ind = 0 - for inputs in node.input: - np.save( - os.path.join(self.tmp_dir, "input_{}.npy".format(in_ind)), - context[inputs], - ) - temp_files.append("{}/input_{}.npy".format(self.tmp_dir, in_ind)) - in_ind += 1 - - # code generation - self.code_generation() - - # c++ compilation and execution flow - temp_files.append("{}/execute_{}.cpp".format(self.tmp_dir, node.op_type)) - bash_compile = """g++ -o {}/execute_{} {}/execute_{}.cpp - /workspace/cnpy/cnpy.cpp -I/workspace/cnpy/ - -I/workspace/finn-hlslib -I/workspace/vivado-hlslib - --std=c++11 -lz""".format( - self.tmp_dir, node.op_type, self.tmp_dir, node.op_type - ) - process_compile = subprocess.Popen(bash_compile.split(), stdout=subprocess.PIPE) - process_compile.communicate() - bash_execute = "{}/execute_{}".format(self.tmp_dir, node.op_type) - process_execute = subprocess.Popen(bash_execute.split(), stdout=subprocess.PIPE) - process_execute.communicate() - temp_files.append("{}/execute_{}".format(self.tmp_dir, node.op_type)) - temp_files.append("{}/output.npy".format(self.tmp_dir)) - - # load output npy file - output = np.load("{}/output.npy".format(self.tmp_dir)) - context[node.output[0]] = output - # deleting temporary files - # for temp_file in temp_files: - # os.remove(temp_file) - - def global_includes(self): - self.code_gen_dict["$GLOBALS$"] = ['#include "maxpool.h"'] - - def defines(self): - self.code_gen_dict["$DEFINES$"] = [ - "#define ImgDim {}\n #define PoolDim {}\n #define NumChannels {}".format( - self.get_nodeattr("ImgDim"), - self.get_nodeattr("PoolDim"), - self.get_nodeattr("NumChannels"), - ) - ] - - def read_npy_data(self): - node = self.onnx_node - # c++ code to read out an npy file - # and put it in hls::stream in the correct order - self.code_gen_dict["$READNPYDATA$"] = [] - input_ind = 0 - input_file_names = [] - for inputs in node.input: - input_file_names.append("{}/input_{}.npy".format(self.tmp_dir, input_ind)) - input_ind += 1 - - input_ind = 0 - for input_file in input_file_names: - self.code_gen_dict["$READNPYDATA$"].append( - """cnpy::NpyArray arr = cnpy::npy_load("{}");\n - float* loaded_data{} = arr.data<float>();""".format( - input_file, input_ind - ) - ) - self.code_gen_dict["$READNPYDATA$"].append( - """int num_values = 1; \n - for(int i = 0; i < arr.shape.size(); i++){\n - num_values *= arr.shape[i]; \n }""" - ) - self.code_gen_dict["$READNPYDATA$"].append( - "ap_uint<{}> dat;".format(self.get_nodeattr("NumChannels")) - ) - self.code_gen_dict["$READNPYDATA$"].append( - "for(int i=0; i < num_values/{}; i++){{".format( - self.get_nodeattr("NumChannels") - ) - ) - for channel in range(self.get_nodeattr("NumChannels")): - self.code_gen_dict["$READNPYDATA$"].append( - "dat.range({},{}) = loaded_data{}[i+((num_values/{})*{})];".format( - channel, - channel, - input_ind, - self.get_nodeattr("NumChannels"), - channel, - ) - ) - self.code_gen_dict["$READNPYDATA$"].append("in{} << dat;".format(input_ind)) - self.code_gen_dict["$READNPYDATA$"].append("}") - input_ind += 1 - - def strm_decl(self): - node = self.onnx_node - self.code_gen_dict["$STREAMDECLARATIONS$"] = [] - input_ind = 0 - for inputs in node.input: - self.code_gen_dict["$STREAMDECLARATIONS$"].append( - 'hls::stream<ap_uint<{}>> in{} ("in{}");'.format( - self.get_nodeattr("NumChannels"), input_ind, input_ind - ) - ) - input_ind += 1 - self.code_gen_dict["$STREAMDECLARATIONS$"].append( - 'hls::stream<ap_uint<{}>> out ("out");'.format( - self.get_nodeattr("NumChannels") - ) - ) - - def docompute(self): - node = self.onnx_node - self.code_gen_dict["$DOCOMPUTE$"] = [ - "{}<ImgDim, PoolDim, NumChannels>(in0, out);".format(node.op_type) - ] - - def dataoutstrm(self): - self.code_gen_dict["$DATAOUTSTREAM$"] = [ - "ap_uint<{}> out_data;\n std::vector<ap_uint<{}>> out_data_vector;".format( - self.get_nodeattr("NumChannels"), self.get_nodeattr("NumChannels") - ) - ] - self.code_gen_dict["$DATAOUTSTREAM$"].append("while(out.read_nb(out_data)){") - self.code_gen_dict["$DATAOUTSTREAM$"].append( - "out_data_vector.push_back(out_data);\n}" - ) - self.code_gen_dict["$DATAOUTSTREAM$"].append( - "std::vector<float> output_data_vector;" - ) - self.code_gen_dict["$DATAOUTSTREAM$"].append( - """for(std::vector<ap_uint<{}>>::iterator it = out_data_vector.begin(); - it != out_data_vector.end(); ++it){{""".format( - self.get_nodeattr("NumChannels") - ) - ) - self.code_gen_dict["$DATAOUTSTREAM$"].append( - "ap_uint<{}> output_data = *it;".format(self.get_nodeattr("NumChannels")) - ) - for channel in range(self.get_nodeattr("NumChannels")): - self.code_gen_dict["$DATAOUTSTREAM$"].append( - "output_data_vector.push_back(output_data.range({},{}));".format( - channel, channel - ) - ) - self.code_gen_dict["$DATAOUTSTREAM$"].append("}") - - def save_as_npy(self): - self.code_gen_dict["$SAVEASCNPY$"] = [ - """cnpy::npy_save("{}/output.npy",&output_data_vector[0], - {{{},{},{}}},"w");""".format( - self.tmp_dir, - self.get_nodeattr("NumChannels"), - int(self.get_nodeattr("ImgDim") / self.get_nodeattr("PoolDim")), - int(self.get_nodeattr("ImgDim") / self.get_nodeattr("PoolDim")), - ) - ] diff --git a/src/finn/custom_op/registry.py b/src/finn/custom_op/registry.py index 38e7ef807..4b8f4d649 100644 --- a/src/finn/custom_op/registry.py +++ b/src/finn/custom_op/registry.py @@ -1,8 +1,7 @@ # 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.streamingmaxpool import StreamingMaxPool -from finn.custom_op.fpgadataflow.streamingmaxpool_batch import StreamingMaxPool_Batch from finn.custom_op.fpgadataflow.streamingfclayer_batch import StreamingFCLayer_Batch +from finn.custom_op.fpgadataflow.streamingmaxpool_batch import StreamingMaxPool_Batch from finn.custom_op.multithreshold import MultiThreshold from finn.custom_op.xnorpopcount import XnorPopcountMatMul @@ -11,6 +10,5 @@ custom_op = {} custom_op["MultiThreshold"] = MultiThreshold custom_op["XnorPopcountMatMul"] = XnorPopcountMatMul -custom_op["StreamingMaxPool"] = StreamingMaxPool custom_op["StreamingMaxPool_Batch"] = StreamingMaxPool_Batch custom_op["StreamingFCLayer_Batch"] = StreamingFCLayer_Batch diff --git a/tests/fpgadataflow/test_layer_streaming_maxpool.py b/tests/fpgadataflow/test_layer_streaming_maxpool.py deleted file mode 100644 index 4c9806a35..000000000 --- a/tests/fpgadataflow/test_layer_streaming_maxpool.py +++ /dev/null @@ -1,80 +0,0 @@ -# import onnx -import numpy as np -from onnx import TensorProto, helper - -import finn.core.onnx_exec as oxe -from finn.core.datatype import DataType -from finn.core.modelwrapper import ModelWrapper - - -def test_layer_streaming_maxpool(): - inp = helper.make_tensor_value_info("in", TensorProto.FLOAT, [2, 4, 4]) - outp = helper.make_tensor_value_info("out", TensorProto.FLOAT, [2, 2, 2]) - - MaxPool_node = helper.make_node( - "StreamingMaxPool", - ["in"], - ["out"], - domain="finn", - backend="fpgadataflow", - ImgDim=4, - PoolDim=2, - NumChannels=2, - ) - - graph = helper.make_graph( - nodes=[MaxPool_node], name="max_pool_graph", inputs=[inp], outputs=[outp], - ) - model = helper.make_model(graph, producer_name="finn-hls-onnx-model") - model = ModelWrapper(model) - - # set the tensor datatypes (in this case: all to bipolar) - for tensor in graph.input: - model.set_tensor_datatype(tensor.name, DataType["BIPOLAR"]) - for tensor in graph.output: - model.set_tensor_datatype(tensor.name, DataType["BIPOLAR"]) - - # onnx.save(model.model, "max-pool-model.onnx") - - input_tensor = np.asarray( - [ - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - ], - dtype=np.float32, - ).reshape(2, 4, 4) - print(input_tensor) - - input_dict = {"in": input_tensor} - output_dict = oxe.execute_onnx(model, input_dict) - print(output_dict) -- GitLab