def test_fpgadataflow_fclayer_npysim(idt, wdt, act, nf, sf, mw, mh): if nf == -1: nf = mh if sf == -1: sf = mw pe = mh // nf simd = mw // sf assert mh % pe == 0 assert mw % sf == 0 # generate weights W = gen_finn_dt_tensor(wdt, (mw, mh)) # generate input data x = gen_finn_dt_tensor(idt, (1, mw)) if act is None: # no activation, produce accumulators T = None tdt = None if wdt == DataType.BIPOLAR and idt == DataType.BIPOLAR: odt = DataType.UINT32 else: odt = DataType.INT32 else: odt = act (min, max) = calculate_signed_dot_prod_range(idt, wdt, mw) n_steps = act.get_num_possible_values() - 1 T = np.random.randint(min, max - 1, (mh, n_steps)).astype(np.float32) # provide non-decreasing thresholds T = np.sort(T, axis=1) # generate thresholds for activation if wdt == DataType.BIPOLAR and idt == DataType.BIPOLAR: tdt = DataType.UINT32 # bias thresholds to be positive T = np.ceil((T + mw) / 2) assert (T >= 0).all() else: tdt = DataType.INT32 model = make_single_fclayer_modelwrapper(W, pe, simd, wdt, idt, odt, T, tdt) model = model.transform(SetExecMode("npysim")) model = model.transform(CodeGen_npysim()) model = model.transform(Compile()) # prepare input data input_dict = prepare_inputs(x, idt, wdt) if wdt == DataType.BIPOLAR and idt == DataType.BIPOLAR: # convert inputs to binary and use xnorpopcountmatmul y = xp.xnorpopcountmatmul((x + 1) / 2, (W + 1) / 2) else: y = np.matmul(x, W) if T is not None: y = multithreshold(y, T) if act == DataType.BIPOLAR: # binary to bipolar y = 2 * y - 1 else: # signed offset y += act.min() oshape = model.get_tensor_shape("outp") y_expected = y.reshape(oshape) # execute model y_produced = oxe.execute_onnx(model, input_dict)["outp"] assert (y_produced.reshape(y_expected.shape) == y_expected).all(), "npysim failed"
def test_end2end_tfc_w1a2_verify_dataflow_part(): model = ModelWrapper(build_dir + "/end2end_tfc_w1a2_ipstitch.onnx") x = np.zeros((1, 784), dtype=np.float32) inp_name = model.graph.input[0].name out_name = model.graph.output[0].name inp_dict = {inp_name: x} # npysim model = model.transform(CodeGen_npysim()) model = model.transform(Compile()) model = model.transform(SetExecMode("npysim")) model.save(build_dir + "/end2end_tfc_w1a2_ipstitch_npysim.onnx") ret_npysim = execute_onnx(model, inp_dict, True) res_npysim = ret_npysim[out_name] # node-by-node rtlsim model = model.transform(SetExecMode("rtlsim")) getCustomOp(model.graph.node[0]).set_nodeattr("rtlsim_trace", "default") getCustomOp(model.graph.node[1]).set_nodeattr("rtlsim_trace", "default") getCustomOp(model.graph.node[2]).set_nodeattr("rtlsim_trace", "default") getCustomOp(model.graph.node[3]).set_nodeattr("rtlsim_trace", "default") model.save(build_dir + "/end2end_tfc_w1a2_ipstitch_nodebynode_rtlsim.onnx") ret_rtlsim_nodebynode = execute_onnx(model, inp_dict, True) res_rtlsim_nodebynode = ret_rtlsim_nodebynode[out_name] # whole-network (ip-stitched) rtlsim model.set_metadata_prop("exec_mode", "rtlsim") model.set_metadata_prop("rtlsim_trace", "whole_trace.vcd") model.save(build_dir + "/end2end_tfc_w1a2_ipstitch_whole_rtlsim.onnx") ret_rtlsim_whole = execute_onnx(model, inp_dict, True) res_rtlsim_whole = ret_rtlsim_whole[out_name] assert np.isclose(res_npysim, res_rtlsim_nodebynode).all() assert np.isclose(res_npysim, res_rtlsim_whole).all()
def test_fpgadataflow_slidingwindow(idt, k, ifm_dim, ifm_ch, stride): simd = ifm_ch ofm_dim = int(((ifm_dim - k) / stride) + 1) x = gen_finn_dt_tensor(idt, (1, ifm_ch, ifm_dim, ifm_dim)) model = make_single_slidingwindow_modelwrapper(k, ifm_ch, ifm_dim, ofm_dim, simd, stride, idt) model = model.transform(SetExecMode("npysim")) model = model.transform(CodeGen_npysim()) model = model.transform(Compile()) # prepare input data input_dict = prepare_inputs(x, idt) # execute model y_produced = oxe.execute_onnx(model, input_dict)["outp"] y_expected = im2col_indices(x, k, stride) # reshape expected output to match node output oshape = y_produced.shape y_expected = y_expected.reshape(oshape) assert (y_produced == y_expected).all(), "npysim failed" model = model.transform(SetExecMode("rtlsim")) model = model.transform(GiveUniqueNodeNames()) model = model.transform(CodeGen_ipgen("xc7z020clg400-1", 5)) model = model.transform(HLSSynth_IPGen()) y_produced = oxe.execute_onnx(model, input_dict)["outp"] assert (y_produced == y_expected).all(), "rtlsim failed"
def test_code_gen_trafo(): idt = wdt = odt = DataType.BIPOLAR mw = 8 mh = 8 pe = 4 simd = 4 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", node_inp_list, ["outp"], domain="finn", backend="fpgadataflow", code_gen_dir="", executable_path="", resType="ap_resource_lut()", MW=mw, MH=mh, SIMD=simd, PE=pe, 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]) model = helper.make_model(graph, producer_name="fclayer-model") model = ModelWrapper(model) model.set_tensor_datatype("inp", idt) model.set_tensor_datatype("outp", odt) model.set_tensor_datatype("weights", wdt) W = util.gen_finn_dt_tensor(wdt, (mw, mh)) model.set_initializer("weights", W) model = model.transform(CodeGen_npysim()) for node in model.graph.node: code_gen_attribute = util.get_by_name(node.attribute, "code_gen_dir_npysim") tmp_dir = code_gen_attribute.s.decode("UTF-8") assert os.path.isdir( tmp_dir), """Code generation directory of node with op type {} does not exist!""".format(node.op_type) assert (len(os.listdir(tmp_dir)) != 0), """Code generation directory of node with op type {} is empty!""".format(node.op_type)
def test_convert_to_hls_layers_tfc_w1a1(): tfc = get_test_model_trained("TFC", 1, 1) bo.export_finn_onnx(tfc, (1, 1, 28, 28), export_onnx_path) model = ModelWrapper(export_onnx_path) model = model.transform(InferShapes()) model = model.transform(FoldConstants()) model = model.transform(GiveUniqueNodeNames()) model = model.transform(GiveReadableTensorNames()) model = model.transform(Streamline()) model = model.transform(ConvertBipolarMatMulToXnorPopcount()) model = model.transform(absorb.AbsorbAddIntoMultiThreshold()) model = model.transform(absorb.AbsorbMulIntoMultiThreshold()) model = model.transform(RoundAndClipThresholds()) model = model.transform(to_hls.InferBinaryStreamingFCLayer()) fc0 = model.graph.node[2] assert fc0.op_type == "StreamingFCLayer_Batch" assert model.get_tensor_shape(fc0.input[0]) == [1, 784] assert model.get_tensor_shape(fc0.input[1]) == [784, 64] assert model.get_tensor_shape(fc0.input[2]) == [64, 1] fc1 = model.graph.node[3] assert fc1.op_type == "StreamingFCLayer_Batch" assert model.get_tensor_shape(fc1.input[0]) == [1, 64] assert model.get_tensor_shape(fc1.input[1]) == [64, 64] assert model.get_tensor_shape(fc1.input[2]) == [64, 1] fc2 = model.graph.node[4] assert fc2.op_type == "StreamingFCLayer_Batch" assert model.get_tensor_shape(fc2.input[0]) == [1, 64] assert model.get_tensor_shape(fc2.input[1]) == [64, 64] assert model.get_tensor_shape(fc2.input[2]) == [64, 1] fc3 = model.graph.node[5] assert fc3.op_type == "StreamingFCLayer_Batch" assert model.get_tensor_shape(fc3.input[0]) == [1, 64] assert model.get_tensor_shape(fc3.input[1]) == [64, 10] os.remove(export_onnx_path) fc0w = getCustomOp(fc0) fc0w.set_nodeattr("SIMD", 784) fc0w.set_nodeattr("PE", 16) fc1w = getCustomOp(fc1) fc1w.set_nodeattr("SIMD", 16) fc1w.set_nodeattr("PE", 16) fc2w = getCustomOp(fc2) fc2w.set_nodeattr("SIMD", 16) fc2w.set_nodeattr("PE", 16) fc3w = getCustomOp(fc3) fc3w.set_nodeattr("SIMD", 16) fc3w.set_nodeattr("PE", 10) model = model.transform(CodeGen_npysim()) model = model.transform(Compile()) model = model.transform(SetExecMode("npysim")) raw_i = get_data("finn", "data/onnx/mnist-conv/test_data_set_0/input_0.pb") input_tensor = onnx.load_tensor_from_string(raw_i) # run using FINN-based execution input_dict = {"global_in": nph.to_array(input_tensor)} output_dict = oxe.execute_onnx(model, input_dict) produced = output_dict[list(output_dict.keys())[0]] # run using PyTorch/Brevitas input_tensor = torch.from_numpy(nph.to_array(input_tensor)).float() assert input_tensor.shape == (1, 1, 28, 28) # do forward pass in PyTorch/Brevitas expected = tfc.forward(input_tensor).detach().numpy() assert np.isclose(produced, expected, atol=1e-3).all()
def test_convert_to_hls_layers_tfc_w1a2(): tfc = get_test_model_trained("TFC", 1, 2) bo.export_finn_onnx(tfc, (1, 1, 28, 28), export_onnx_path) model = ModelWrapper(export_onnx_path) model = model.transform(InferShapes()) model = model.transform(FoldConstants()) model = model.transform(GiveUniqueNodeNames()) model = model.transform(GiveReadableTensorNames()) model = model.transform(Streamline()) from finn.transformation.fpgadataflow.convert_to_hls_layers import ( InferQuantizedStreamingFCLayer, ) model = model.transform(InferQuantizedStreamingFCLayer()) fc0 = model.graph.node[2] assert fc0.op_type == "StreamingFCLayer_Batch" assert model.get_tensor_shape(fc0.input[0]) == [1, 784] assert model.get_tensor_shape(fc0.input[1]) == [784, 64] assert model.get_tensor_shape(fc0.input[2]) == [64, 2] fc1 = model.graph.node[3] assert fc1.op_type == "StreamingFCLayer_Batch" assert model.get_tensor_shape(fc1.input[0]) == [1, 64] assert model.get_tensor_shape(fc1.input[1]) == [64, 64] assert model.get_tensor_shape(fc1.input[2]) == [64, 2] fc2 = model.graph.node[4] assert fc2.op_type == "StreamingFCLayer_Batch" assert model.get_tensor_shape(fc2.input[0]) == [1, 64] assert model.get_tensor_shape(fc2.input[1]) == [64, 64] assert model.get_tensor_shape(fc2.input[2]) == [64, 2] fc3 = model.graph.node[5] assert fc3.op_type == "StreamingFCLayer_Batch" assert model.get_tensor_shape(fc3.input[0]) == [1, 64] assert model.get_tensor_shape(fc3.input[1]) == [64, 10] fc0w = getCustomOp(fc0) fc0w.set_nodeattr("SIMD", 784) fc0w.set_nodeattr("PE", 16) fc1w = getCustomOp(fc1) fc1w.set_nodeattr("SIMD", 16) fc1w.set_nodeattr("PE", 16) fc2w = getCustomOp(fc2) fc2w.set_nodeattr("SIMD", 16) fc2w.set_nodeattr("PE", 16) fc3w = getCustomOp(fc3) fc3w.set_nodeattr("SIMD", 16) fc3w.set_nodeattr("PE", 10) model = model.transform(CodeGen_npysim()) model = model.transform(Compile()) model = model.transform(SetExecMode("npysim")) raw_i = get_data("finn", "data/onnx/mnist-conv/test_data_set_0/input_0.pb") input_tensor = onnx.load_tensor_from_string(raw_i) # run using FINN-based execution input_dict = {"global_in": nph.to_array(input_tensor)} output_dict = oxe.execute_onnx(model, input_dict, True) produced = output_dict[model.graph.output[0].name] model = ModelWrapper(export_onnx_path) model = model.transform(InferShapes()) model = model.transform(FoldConstants()) model = model.transform(GiveUniqueNodeNames()) model = model.transform(GiveReadableTensorNames()) model = model.transform(Streamline()) golden_output_dict = oxe.execute_onnx(model, input_dict, True) expected = golden_output_dict[model.graph.output[0].name] assert np.isclose(produced, expected, atol=1e-3).all() os.remove(export_onnx_path)
def test_layer_streaming_maxpool_batch(): inp = helper.make_tensor_value_info("in", TensorProto.FLOAT, [2, 2, 4, 4]) outp = helper.make_tensor_value_info("out", TensorProto.FLOAT, [2, 2, 2, 2]) MaxPool_batch_node = helper.make_node( "StreamingMaxPool_Batch", ["in"], ["out"], domain="finn", backend="fpgadataflow", ImgDim=4, PoolDim=2, NumChannels=2, ) graph = helper.make_graph( nodes=[MaxPool_batch_node], name="max_pool_batch_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, 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, 2, 4, 4) model = model.transform(SetExecMode("npysim")) model = model.transform(CodeGen_npysim()) model = model.transform(Compile()) input_dict = {"in": input_tensor} output_dict = oxe.execute_onnx(model, input_dict) # NOQA