def test_const_folding_shapes(): lfc = get_test_model_untrained("LFC", 1, 1) bo.export_finn_onnx(lfc, (1, 1, 28, 28), export_onnx_path) model = ModelWrapper(export_onnx_path) model = model.transform(InferShapes()) model = model.transform(FoldConstants()) assert model.graph.node[0].op_type == "Reshape" assert list(model.get_tensor_shape("0")) == [1, 1, 28, 28] assert list(model.get_tensor_shape("27")) == [1, 784] os.remove(export_onnx_path)
def test_make_input_chanlast(): # load the onnx model raw_m = get_data("finn.data", "onnx/mnist-conv/model.onnx") model = ModelWrapper(raw_m) iname = model.graph.input[0].name assert tuple(model.get_tensor_shape(iname)) == (1, 1, 28, 28) model = model.transform(MakeInputChannelsLast()) assert model.graph.node[0].op_type == "Transpose" assert tuple(model.get_tensor_shape(iname)) == (1, 28, 28, 1) assert model.get_tensor_layout(iname) == data_layout.NHWC
def test_xnorpopcountmatmul(): M = 1 K = 3 N = 3 x = helper.make_tensor_value_info("x", TensorProto.FLOAT, [M, K]) W = helper.make_tensor_value_info("W", TensorProto.FLOAT, [K, N]) out = helper.make_tensor_value_info("out", TensorProto.FLOAT, ["x", "y"]) node_def = helper.make_node("XnorPopcountMatMul", ["x", "W"], ["out"], domain="finn.custom_op.general") modelproto = helper.make_model( helper.make_graph([node_def], "test_model", [x], [out], value_info=[W])) model = ModelWrapper(modelproto) model.set_tensor_datatype("x", DataType.BINARY) model.set_tensor_datatype("W", DataType.BINARY) W_data = np.asarray([[1, 0, 0], [0, 1, 0], [0, 0, 1]], dtype=np.float32) model.set_initializer("W", W_data) # test shape inference model = model.transform(InferShapes()) assert model.get_tensor_shape("out") == [M, N] # test datatype inference assert model.get_tensor_datatype("out") is DataType.FLOAT32 model = model.transform(InferDataTypes()) assert model.get_tensor_datatype("out") is DataType.UINT32 # test execution x_data = np.asarray([[1, 0, 0]], dtype=np.float32) inp_dict = {"x": x_data} out_dict = oxe.execute_onnx(model, inp_dict) Wb = 2 * W_data - 1 xb = 2 * x_data - 1 rb = np.matmul(xb, Wb) assert (2 * out_dict["out"] - K == rb).all()
def make_lookup_model(embeddings, ishape, idt, edt): num_embeddings, embedding_dim = embeddings.shape class LookupModel(nn.Module): def __init__(self, num_embeddings, embedding_dim): super().__init__() self.lookup = nn.Embedding( num_embeddings=num_embeddings, embedding_dim=embedding_dim ) def forward(self, x): x = self.lookup(x) return x torch_model = LookupModel(num_embeddings, embedding_dim) input_t = torch.zeros(ishape, dtype=torch.int64) ret = FINNManager.export(torch_model, input_t=input_t, opset_version=11) model = ModelWrapper(ret) iname = model.graph.input[0].name ename = model.graph.node[0].input[0] model.set_tensor_datatype(iname, idt) eshape = model.get_tensor_shape(ename) assert tuple(eshape) == embeddings.shape model.set_initializer(ename, embeddings) model.set_tensor_datatype(ename, edt) model = model.transform(InferShapes()) model = model.transform(InferDataTypes()) return model
def test_modelwrapper(): lfc = get_test_model_trained("LFC", 1, 1) bo.export_finn_onnx(lfc, (1, 1, 28, 28), export_onnx_path) model = ModelWrapper(export_onnx_path) assert model.check_all_tensor_shapes_specified() is False inp_name = model.graph.input[0].name inp_shape = model.get_tensor_shape(inp_name) assert inp_shape == [1, 1, 28, 28] # find first matmul node l0_mat_tensor_name = "" l0_inp_tensor_name = "" for node in model.graph.node: if node.op_type == "MatMul": l0_inp_tensor_name = node.input[0] l0_mat_tensor_name = node.input[1] break assert l0_mat_tensor_name != "" l0_weights = model.get_initializer(l0_mat_tensor_name) assert l0_weights.shape == (784, 1024) l0_weights_hist = Counter(l0_weights.flatten()) assert (l0_weights_hist[1.0] + l0_weights_hist[-1.0]) == 784 * 1024 l0_weights_rand = np.random.randn(784, 1024) model.set_initializer(l0_mat_tensor_name, l0_weights_rand) assert (model.get_initializer(l0_mat_tensor_name) == l0_weights_rand).all() assert l0_inp_tensor_name != "" inp_cons = model.find_consumer(l0_inp_tensor_name) assert inp_cons.op_type == "MatMul" out_prod = model.find_producer(l0_inp_tensor_name) assert out_prod.op_type == "Sign" os.remove(export_onnx_path)
def measure_top1_accuracy(model_chkpt, dataset, parent_chkpt=None): if dataset == "cifar10": trainx, trainy, testx, testy, valx, valy = cifar.load_cifar_data( "/workspace/finn/dataset", download=True, one_hot=False ) elif dataset == "mnist": trainx, trainy, testx, testy, valx, valy = mnist.load_mnist_data( "/workspace/finn/dataset", download=True, one_hot=False ) else: raise Exception("Unrecognized dataset") # move from dataset_loader layout to ONNX layout: NHWC -> NCHW testx = testx.transpose(0, 3, 1, 2) model = ModelWrapper(model_chkpt) iname = model.graph.input[0].name oname = model.graph.output[0].name if parent_chkpt is None: ishape = model.get_tensor_shape(iname) else: parent_model = ModelWrapper(parent_chkpt) parent_iname = parent_model.graph.input[0].name ishape = parent_model.get_tensor_shape(parent_iname) ok = 0 nok = 0 n_batches = testx.shape[0] for i in range(n_batches): tdata = testx[i].reshape(ishape).astype(np.float32) exp = testy[i].item() if parent_chkpt is not None: y = execute_parent(parent_chkpt, model_chkpt, tdata) else: y = execute_onnx(model, {iname: tdata}, False)[oname] ret = y.item() if ret == exp: ok += 1 else: nok += 1 if i % 10 == 0: print("%d : OK %d NOK %d " % (i, ok, nok)) acc_top1 = ok * 100.0 / (ok + nok) warnings.warn("Final OK %d NOK %d top-1 %f" % (ok, nok, acc_top1)) return acc_top1
def test_infer_shapes(): # load the onnx model raw_m = get_data("finn.data", "onnx/mnist-conv/model.onnx") model = ModelWrapper(raw_m) graph = model.graph # multi-thresholding node to be inserted between the first Relu and MaxPool node # get Relu node to use data Relu_node = graph.node[3] assert Relu_node.op_type == "Relu", "The wrong model was chosen for the check" # create thresholds tensor as constant mt_thresh0 = helper.make_tensor_value_info("mt_thresh0", TensorProto.FLOAT, [8, 7]) # random numbers for the thresholds # thresholds for one channel have to be sorted to guarantee the correct behavior mt_thresh0_values = np.empty([8, 7], dtype=np.float32) for i in range(len(mt_thresh0_values)): mt_thresh0_values[i] = np.sort(np.random.random_sample(7) * 10) model.set_initializer(mt_thresh0.name, mt_thresh0_values) # add multi-thresholding node and change Relu node mt_node = helper.make_node( "MultiThreshold", ["mt_v0", "mt_thresh0"], [Relu_node.output[0]], domain="finn.custom_op.general", ) Relu_node.output[0] = "mt_v0" # explicitly remove any present shape from ReLU and MultiThreshold outputs util.remove_by_name(model.graph.value_info, Relu_node.output[0]) util.remove_by_name(model.graph.value_info, mt_node.output[0]) graph.node.insert(4, mt_node) # first check routine # check if at least one shape is not specified assert not ( model.check_all_tensor_shapes_specified() ), "All tensors are already specified before the shape inference execution" # perform shape inference on mixed model model = model.transform(InferShapes()) # second check routine # now all shapes should be specified and mt_node output shape is (1,8,28,28) assert (model.check_all_tensor_shapes_specified() ), "There are still tensors that are not specified" assert (model.get_tensor_shape(mt_node.output[0])) == ([ 1, 8, 28, 28 ]), "output of multi-thresholding node has wrong shape"
def test_fpgadataflow_ipstitch_remote_execution(): try: ip = os.environ["PYNQ_IP"] # NOQA if ip == "": pytest.skip("PYNQ board IP address not specified") model = ModelWrapper( ip_stitch_model_dir + "/test_fpgadataflow_ipstitch_pynq_deployment.onnx") iname = "inp" idt = model.get_tensor_datatype(iname) ishape = model.get_tensor_shape(iname) x = gen_finn_dt_tensor(idt, ishape) input_dict = {"inp": x} outp = execute_onnx(model, input_dict) assert np.isclose(outp["outp"], x).all() except KeyError: pytest.skip("PYNQ board IP address not specified")
def test_fpgadataflow_ipstitch_rtlsim(): model = ModelWrapper(ip_stitch_model_dir + "/test_fpgadataflow_ip_stitch.onnx") model.set_metadata_prop("rtlsim_trace", "whole_trace.vcd") sim = pyverilate_stitched_ip(model) exp_io = [ "ap_clk_0", "ap_rst_n_0", "in0_V_V_0_tdata", "in0_V_V_0_tready", "in0_V_V_0_tvalid", "out_r_0_tdata", "out_r_0_tkeep", "out_r_0_tlast", "out_r_0_tready", "out_r_0_tvalid", "s_axi_control_0_araddr", "s_axi_control_0_arready", "s_axi_control_0_arvalid", "s_axi_control_0_awaddr", "s_axi_control_0_awready", "s_axi_control_0_awvalid", "s_axi_control_0_bready", "s_axi_control_0_bresp", "s_axi_control_0_bvalid", "s_axi_control_0_rdata", "s_axi_control_0_rready", "s_axi_control_0_rresp", "s_axi_control_0_rvalid", "s_axi_control_0_wdata", "s_axi_control_0_wready", "s_axi_control_0_wstrb", "s_axi_control_0_wvalid", ] assert dir(sim.io) == exp_io model.set_metadata_prop("exec_mode", "rtlsim") idt = model.get_tensor_datatype("inp") ishape = model.get_tensor_shape("inp") x = gen_finn_dt_tensor(idt, ishape) # x = np.zeros(ishape, dtype=np.float32) # x = np.asarray([[-2, -1, 0, 1]], dtype=np.float32) rtlsim_res = execute_onnx(model, {"inp": x})["outp"] assert (rtlsim_res == x).all()
def test_batchnorm_to_affine_shufflenet(): ureq.urlretrieve(download_url, export_onnx_path) if not os.path.isfile(export_onnx_path): pytest.skip("Couldn't download ONNX model, skipping") model = ModelWrapper(export_onnx_path) model = model.transform(InferShapes()) model = model.transform(FoldConstants()) iname = model.graph.input[0].name oname = model.graph.output[0].name ishape = model.get_tensor_shape(iname) rand_inp = gen_finn_dt_tensor(DataType.INT8, ishape) input_dict = {iname: rand_inp} expected = oxe.execute_onnx(model, input_dict)[oname] new_model = model.transform(BatchNormToAffine()) # check that there are no BN nodes left op_types = list(map(lambda x: x.op_type, new_model.graph.node)) assert "BatchNormalization" not in op_types produced = oxe.execute_onnx(new_model, input_dict)[oname] assert np.isclose(expected, produced).all() os.remove(export_onnx_path)
def test_modelwrapper(): lfc = get_test_model_trained("LFC", 1, 1) bo.export_finn_onnx(lfc, (1, 1, 28, 28), export_onnx_path) model = ModelWrapper(export_onnx_path) assert model.check_all_tensor_shapes_specified() is False inp_shape = model.get_tensor_shape("0") assert inp_shape == [1, 1, 28, 28] l0_mat_tensor_name = "33" l0_weights = model.get_initializer(l0_mat_tensor_name) assert l0_weights.shape == (784, 1024) l0_weights_hist = Counter(l0_weights.flatten()) assert l0_weights_hist[1.0] == 401311 and l0_weights_hist[-1.0] == 401505 l0_weights_rand = np.random.randn(784, 1024) model.set_initializer(l0_mat_tensor_name, l0_weights_rand) assert (model.get_initializer(l0_mat_tensor_name) == l0_weights_rand).all() l0_inp_tensor_name = "32" inp_cons = model.find_consumer(l0_inp_tensor_name) assert inp_cons.op_type == "MatMul" out_prod = model.find_producer(l0_inp_tensor_name) assert out_prod.op_type == "Sign" os.remove(export_onnx_path)
def test_fpgadataflow_ipstitch_rtlsim(): model = ModelWrapper(ip_stitch_model_dir + "/test_fpgadataflow_ip_stitch.onnx") sim = pyverilate_stitched_ip(model) exp_io = [ "ap_clk_0", "ap_rst_n_0", "in0_V_V_0_tdata", "in0_V_V_0_tready", "in0_V_V_0_tvalid", "out_r_0_tdata", "out_r_0_tkeep", "out_r_0_tlast", "out_r_0_tready", "out_r_0_tvalid", ] assert dir(sim.io) == exp_io model.set_metadata_prop("exec_mode", "rtlsim") idt = model.get_tensor_datatype("inp") ishape = model.get_tensor_shape("inp") x = gen_finn_dt_tensor(idt, ishape) rtlsim_res = execute_onnx(model, {"inp": x})["outp"] assert (rtlsim_res == x).all()
def test_modelwrapper(): raw_m = get_data("finn.data", "onnx/mnist-conv/model.onnx") model = ModelWrapper(raw_m) assert model.check_all_tensor_shapes_specified() is True inp_name = model.graph.input[0].name inp_shape = model.get_tensor_shape(inp_name) assert inp_shape == [1, 1, 28, 28] conv_nodes = model.get_nodes_by_op_type("Conv") matmul_nodes = model.get_nodes_by_op_type("MatMul") assert len(conv_nodes) == 2 assert len(matmul_nodes) == 1 first_conv = conv_nodes[0] first_conv_iname = first_conv.input[0] first_conv_wname = first_conv.input[1] first_conv_oname = first_conv.output[0] assert first_conv_iname != "" and (first_conv_iname is not None) assert first_conv_wname != "" and (first_conv_wname is not None) assert first_conv_oname != "" and (first_conv_oname is not None) first_conv_weights = model.get_initializer(first_conv_wname) assert first_conv_weights.shape == (8, 1, 5, 5) first_conv_weights_rand = np.random.randn(8, 1, 5, 5) model.set_initializer(first_conv_wname, first_conv_weights_rand) assert (model.get_initializer(first_conv_wname) == first_conv_weights_rand ).all() inp_cons = model.find_consumer(first_conv_iname) assert inp_cons == first_conv out_prod = model.find_producer(first_conv_oname) assert out_prod == first_conv inp_layout = model.get_tensor_layout(first_conv_iname) assert inp_layout is None inp_layout = DataLayout.NCHW model.set_tensor_layout(first_conv_iname, inp_layout) assert model.get_tensor_layout(first_conv_iname) == inp_layout inp_sparsity = model.get_tensor_sparsity(first_conv_iname) assert inp_sparsity is None inp_sparsity = {"dw": {"kernel_shape": [3, 3]}} model.set_tensor_sparsity(first_conv_iname, inp_sparsity) assert model.get_tensor_sparsity(first_conv_iname) == inp_sparsity
def execution_im2col( x, idt, k_h, k_w, stride, ifm_ch, ifm_dim_h, ifm_dim_w, pad_amt, pad_val=0, dilation=1, ): pad_amt_h = pad_amt[0] + pad_amt[2] pad_amt_w = pad_amt[1] + pad_amt[3] ofm_dim_h = compute_conv_output_dim(ifm_dim_h, k_h, stride, pad_amt_h, dilation) ofm_dim_w = compute_conv_output_dim(ifm_dim_w, k_w, stride, pad_amt_w, dilation) # set up onnx model inp = helper.make_tensor_value_info( "inp", TensorProto.FLOAT, [1, ifm_dim_h, ifm_dim_w, ifm_ch] ) outp = helper.make_tensor_value_info( "outp", TensorProto.FLOAT, [1, ofm_dim_h, ofm_dim_w, k_h * k_w * ifm_ch] ) im2col_node = helper.make_node( "Im2Col", ["inp"], ["outp"], domain="finn.custom_op.general", stride=stride, kernel_size=[k_h, k_w], pad_amount=pad_amt, pad_value=pad_val, input_shape="(1,{},{},{})".format(ifm_dim_h, ifm_dim_w, ifm_ch), dilations=dilation, ) graph = helper.make_graph( nodes=[im2col_node], name="im2col_graph", inputs=[inp], outputs=[outp] ) model = helper.make_model(graph, producer_name="im2col-model") model = ModelWrapper(model) model.set_tensor_datatype("inp", idt) # test shape inference model.transform(InferShapes()) assert model.get_tensor_shape("outp") == [ 1, ofm_dim_h, ofm_dim_w, k_h * k_w * ifm_ch, ] # test datatype inference assert model.get_tensor_datatype("outp") is DataType.FLOAT32 model = model.transform(InferDataTypes()) assert model.get_tensor_datatype("outp") is idt # prepare input data input_dict = {"inp": x} # execute model y_produced = oxe.execute_onnx(model, input_dict)["outp"] return y_produced
def test_im2col_infer_shapes(): idt = DataType.BIPOLAR k_h = 2 k_w = 2 stride = 1 ifm_ch = 1 ifm_dim_h = 4 ifm_dim_w = 4 pad_amt = [0, 0, 0, 0] # default pad_amt_h = pad_amt[0] + pad_amt[2] pad_amt_w = pad_amt[1] + pad_amt[3] dilation = 1 ofm_dim_h = compute_conv_output_dim(ifm_dim_h, k_h, stride, pad_amt_h, dilation) ofm_dim_w = compute_conv_output_dim(ifm_dim_w, k_w, stride, pad_amt_w, dilation) # set up onnx model inp = helper.make_tensor_value_info( "inp", TensorProto.FLOAT, [1, ifm_dim_h, ifm_dim_w, ifm_ch] ) outp = helper.make_tensor_value_info( "outp", TensorProto.FLOAT, [1, ofm_dim_h, ofm_dim_w, k_h * k_w * ifm_ch] ) abs_node = helper.make_node("Abs", inputs=["inp"], outputs=["abs"]) Im2Col_node = helper.make_node( "Im2Col", ["abs"], ["im2col"], domain="finn.custom_op.general", stride=stride, kernel_size=[k_h, k_w], input_shape="(1,{},{},{})".format(ifm_dim_h, ifm_dim_w, ifm_ch), dilations=dilation, ) abs1_node = helper.make_node("Abs", inputs=["im2col"], outputs=["outp"]) graph = helper.make_graph( nodes=[abs_node, Im2Col_node, abs1_node], name="shape_graph", inputs=[inp], outputs=[outp], value_info=[ helper.make_tensor_value_info( "abs", TensorProto.FLOAT, [1, ifm_dim_h, ifm_dim_w, ifm_ch] ), helper.make_tensor_value_info( "im2col", TensorProto.FLOAT, [1, ofm_dim_h, ofm_dim_w, k_h * k_w * ifm_ch], ), ], ) model = helper.make_model(graph, producer_name="shape-model") model = ModelWrapper(model) model.set_tensor_datatype("inp", idt) # test shape inference model.transform(InferShapes()) assert model.get_tensor_shape("im2col") == [ 1, ofm_dim_h, ofm_dim_w, k_h * k_w * ifm_ch, ]
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] 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(PrepareCppSim()) model = model.transform(CompileCppSim()) model = model.transform(SetExecMode("cppsim")) 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() os.remove(export_onnx_path)
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(PrepareCppSim()) model = model.transform(CompileCppSim()) model = model.transform(SetExecMode("cppsim")) 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_end2end_cybsec_mlp_export(): assets_dir = pk.resource_filename("finn.qnn-data", "cybsec-mlp/") # load up trained net in Brevitas input_size = 593 hidden1 = 64 hidden2 = 64 hidden3 = 64 weight_bit_width = 2 act_bit_width = 2 num_classes = 1 model = nn.Sequential( QuantLinear(input_size, hidden1, bias=True, weight_bit_width=weight_bit_width), nn.BatchNorm1d(hidden1), nn.Dropout(0.5), QuantReLU(bit_width=act_bit_width), QuantLinear(hidden1, hidden2, bias=True, weight_bit_width=weight_bit_width), nn.BatchNorm1d(hidden2), nn.Dropout(0.5), QuantReLU(bit_width=act_bit_width), QuantLinear(hidden2, hidden3, bias=True, weight_bit_width=weight_bit_width), nn.BatchNorm1d(hidden3), nn.Dropout(0.5), QuantReLU(bit_width=act_bit_width), QuantLinear(hidden3, num_classes, bias=True, weight_bit_width=weight_bit_width), ) trained_state_dict = torch.load(assets_dir + "/state_dict.pth")["models_state_dict"][0] model.load_state_dict(trained_state_dict, strict=False) W_orig = model[0].weight.data.detach().numpy() # pad the second (593-sized) dimensions with 7 zeroes at the end W_new = np.pad(W_orig, [(0, 0), (0, 7)]) model[0].weight.data = torch.from_numpy(W_new) model_for_export = CybSecMLPForExport(model) export_onnx_path = get_checkpoint_name("export") input_shape = (1, 600) # create a QuantTensor instance to mark the input as bipolar during export input_a = np.random.randint(0, 1, size=input_shape).astype(np.float32) input_a = 2 * input_a - 1 scale = 1.0 input_t = torch.from_numpy(input_a * scale) input_qt = QuantTensor(input_t, scale=torch.tensor(scale), bit_width=torch.tensor(1.0), signed=True) bo.export_finn_onnx(model_for_export, export_path=export_onnx_path, input_t=input_qt) assert os.path.isfile(export_onnx_path) # fix input datatype finn_model = ModelWrapper(export_onnx_path) finnonnx_in_tensor_name = finn_model.graph.input[0].name assert tuple(finn_model.get_tensor_shape(finnonnx_in_tensor_name)) == (1, 600) # verify a few exported ops assert finn_model.graph.node[1].op_type == "Add" assert finn_model.graph.node[2].op_type == "Div" assert finn_model.graph.node[3].op_type == "MatMul" assert finn_model.graph.node[-1].op_type == "MultiThreshold" # verify datatypes on some tensors assert finn_model.get_tensor_datatype( finnonnx_in_tensor_name) == DataType.BIPOLAR first_matmul_w_name = finn_model.graph.node[3].input[1] assert finn_model.get_tensor_datatype(first_matmul_w_name) == DataType.INT2
def test_end2end_cybsec_mlp_export(QONNX_export): assets_dir = pk.resource_filename("finn.qnn-data", "cybsec-mlp/") # load up trained net in Brevitas input_size = 593 hidden1 = 64 hidden2 = 64 hidden3 = 64 weight_bit_width = 2 act_bit_width = 2 num_classes = 1 model = nn.Sequential( QuantLinear(input_size, hidden1, bias=True, weight_bit_width=weight_bit_width), nn.BatchNorm1d(hidden1), nn.Dropout(0.5), QuantReLU(bit_width=act_bit_width), QuantLinear(hidden1, hidden2, bias=True, weight_bit_width=weight_bit_width), nn.BatchNorm1d(hidden2), nn.Dropout(0.5), QuantReLU(bit_width=act_bit_width), QuantLinear(hidden2, hidden3, bias=True, weight_bit_width=weight_bit_width), nn.BatchNorm1d(hidden3), nn.Dropout(0.5), QuantReLU(bit_width=act_bit_width), QuantLinear(hidden3, num_classes, bias=True, weight_bit_width=weight_bit_width), ) trained_state_dict = torch.load(assets_dir + "/state_dict.pth")["models_state_dict"][0] model.load_state_dict(trained_state_dict, strict=False) W_orig = model[0].weight.data.detach().numpy() # pad the second (593-sized) dimensions with 7 zeroes at the end W_new = np.pad(W_orig, [(0, 0), (0, 7)]) model[0].weight.data = torch.from_numpy(W_new) model_for_export = CybSecMLPForExport(model) export_onnx_path = get_checkpoint_name("export", QONNX_export) input_shape = (1, 600) # create a QuantTensor instance to mark the input as bipolar during export input_a = np.random.randint(0, 1, size=input_shape).astype(np.float32) input_a = 2 * input_a - 1 scale = 1.0 input_t = torch.from_numpy(input_a * scale) input_qt = QuantTensor(input_t, scale=torch.tensor(scale), bit_width=torch.tensor(1.0), signed=True) if QONNX_export: # With the BrevitasONNXManager we need to manually set # the FINN DataType at the input BrevitasONNXManager.export(model_for_export, input_shape, export_path=export_onnx_path) model = ModelWrapper(export_onnx_path) model.set_tensor_datatype(model.graph.input[0].name, DataType["BIPOLAR"]) model.save(export_onnx_path) qonnx_cleanup(export_onnx_path, out_file=export_onnx_path) model = ModelWrapper(export_onnx_path) model = model.transform(ConvertQONNXtoFINN()) model.save(export_onnx_path) else: bo.export_finn_onnx(model_for_export, export_path=export_onnx_path, input_t=input_qt) assert os.path.isfile(export_onnx_path) # fix input datatype finn_model = ModelWrapper(export_onnx_path) finnonnx_in_tensor_name = finn_model.graph.input[0].name assert tuple(finn_model.get_tensor_shape(finnonnx_in_tensor_name)) == (1, 600) # verify a few exported ops if QONNX_export: # The first "Mul" node doesn't exist in the QONNX export, # because the QuantTensor scale is not exported. # However, this node would have been unity scale anyways and # the models are still equivalent. assert finn_model.graph.node[0].op_type == "Add" assert finn_model.graph.node[1].op_type == "Div" assert finn_model.graph.node[2].op_type == "MatMul" assert finn_model.graph.node[-1].op_type == "MultiThreshold" else: assert finn_model.graph.node[0].op_type == "Mul" assert finn_model.get_initializer( finn_model.graph.node[0].input[1]) == 1.0 assert finn_model.graph.node[1].op_type == "Add" assert finn_model.graph.node[2].op_type == "Div" assert finn_model.graph.node[3].op_type == "MatMul" assert finn_model.graph.node[-1].op_type == "MultiThreshold" # verify datatypes on some tensors assert (finn_model.get_tensor_datatype(finnonnx_in_tensor_name) == DataType["BIPOLAR"]) first_matmul_w_name = finn_model.get_nodes_by_op_type("MatMul")[0].input[1] assert finn_model.get_tensor_datatype( first_matmul_w_name) == DataType["INT2"]