def make_single_maxpool_modelwrapper(k, stride, pad, ifm_ch, ifm_dim, ofm_dim, idt): odt = idt inp = helper.make_tensor_value_info("inp", TensorProto.FLOAT, [1, ifm_ch, ifm_dim, ifm_dim]) outp = helper.make_tensor_value_info("outp", TensorProto.FLOAT, [1, ifm_ch, ofm_dim, ofm_dim]) mp_node = helper.make_node( "MaxPool", ["inp"], ["outp"], kernel_shape=[k, k], pads=[pad, pad, pad, pad], strides=[stride, stride], ) graph = helper.make_graph(nodes=[mp_node], name="mp_graph", inputs=[inp], outputs=[outp]) model = helper.make_model(graph, producer_name="mp-model") model = ModelWrapper(model) model.set_tensor_datatype("inp", idt) model.set_tensor_datatype("outp", odt) model = model.transform(InferShapes()) return model
def make_single_im2col_modelwrapper( k, ifm_ch, ifm_dim, ofm_dim, simd, stride, dilation, idt ): odt = idt inp = helper.make_tensor_value_info( "inp", TensorProto.FLOAT, [1, ifm_dim, ifm_dim, ifm_ch] ) outp = helper.make_tensor_value_info( "outp", TensorProto.FLOAT, [1, ofm_dim, ofm_dim, k * k * ifm_ch] ) im2col_node = helper.make_node( "Im2Col", ["inp"], ["outp"], domain="finn.custom_op.general", stride=[stride, stride], kernel_size=[k, k], input_shape=str((1, ifm_dim, ifm_dim, ifm_ch)), pad_amount=[0, 0, 0, 0], pad_value=0, dilations=[dilation, 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) model.set_tensor_datatype("outp", odt) return model
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 make_single_fifo_modelwrapper(Shape, Depth, fld_shape, finn_dtype): inp = helper.make_tensor_value_info("inp", TensorProto.FLOAT, Shape) outp = helper.make_tensor_value_info("outp", TensorProto.FLOAT, Shape) FIFO_node = helper.make_node( "StreamingFIFO", ["inp"], ["outp"], domain="finn", backend="fpgadataflow", depth=Depth, folded_shape=fld_shape, dataType=str(finn_dtype.name), ) graph = helper.make_graph( nodes=[FIFO_node], name="fifo_graph", inputs=[inp], outputs=[outp] ) model = helper.make_model(graph, producer_name="fifo-model") model = ModelWrapper(model) model.set_tensor_datatype("inp", finn_dtype) model.set_tensor_datatype("outp", finn_dtype) return model
def make_single_quantavpool_modelwrapper(k, stride, ifm_ch, ifm_dim, ofm_dim, idt, odt): inp = helper.make_tensor_value_info("inp", TensorProto.FLOAT, [1, ifm_ch, ifm_dim, ifm_dim]) outp = helper.make_tensor_value_info("outp", TensorProto.FLOAT, [1, ifm_ch, ofm_dim, ofm_dim]) mp_node = helper.make_node( "QuantAvgPool2d", ["inp"], ["outp"], domain="finn.custom_op.general", stride=stride, kernel=k, ibits=idt.bitwidth(), obits=odt.bitwidth(), signed=1 if idt.signed() else 0, data_layout="NCHW", ) graph = helper.make_graph(nodes=[mp_node], name="mp_graph", inputs=[inp], outputs=[outp]) model = helper.make_model(graph, producer_name="mp-model") model = ModelWrapper(model) model.set_tensor_datatype("inp", idt) model.set_tensor_datatype("outp", odt) model = model.transform(InferShapes()) return model
def make_single_im2col_modelwrapper(k, ifm_ch, ifm_dim, ofm_dim, simd, stride, idt): odt = idt inp = helper.make_tensor_value_info("inp", TensorProto.FLOAT, [1, ifm_dim, ifm_dim, ifm_ch]) outp = helper.make_tensor_value_info("outp", TensorProto.FLOAT, [1, ofm_dim, ofm_dim, k * k * ifm_ch]) im2col_node = helper.make_node( "Im2Col", ["inp"], ["outp"], domain="finn", backend="fpgadataflow", stride=stride, kernel_size=k, input_shape=str((1, ifm_dim, ifm_dim, ifm_ch)), pad_amount=0, pad_value=0, ) 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) model.set_tensor_datatype("outp", odt) return model
def test_round_thresholds(): v = helper.make_tensor_value_info("v", TensorProto.FLOAT, [1, 4]) thresholds = helper.make_tensor_value_info("thresholds", TensorProto.FLOAT, [4, 1]) out = helper.make_tensor_value_info("out", TensorProto.FLOAT, [1, 4]) node_def = helper.make_node("MultiThreshold", ["v", "thresholds"], ["out"], domain="finn") graph_def = helper.make_graph([node_def], "test_model", [v, thresholds], [out]) model_def = helper.make_model(graph_def) model = ModelWrapper(model_def) threshold_val = np.asarray([[-1.1], [0.7], [2.3], [5.1]], dtype=np.float32) model.set_initializer("thresholds", threshold_val) model.set_tensor_datatype("v", DataType.INT8) inp_dict_f = {"v": np.floor(threshold_val).T} inp_dict_n = {"v": np.round(threshold_val).T} inp_dict_c = {"v": np.ceil(threshold_val).T} orig_f = oxe.execute_onnx(model, inp_dict_f)["out"] orig_n = oxe.execute_onnx(model, inp_dict_n)["out"] orig_c = oxe.execute_onnx(model, inp_dict_c)["out"] assert model.get_tensor_datatype("thresholds") == DataType.FLOAT32 new_model = model.transform(RoundAndClipThresholds()) # rounded up thresholds should have same dtype as input assert new_model.get_tensor_datatype("thresholds") == DataType.INT8 new_f = oxe.execute_onnx(new_model, inp_dict_f)["out"] new_n = oxe.execute_onnx(new_model, inp_dict_n)["out"] new_c = oxe.execute_onnx(new_model, inp_dict_c)["out"] assert np.isclose(orig_f, new_f, atol=1e-3).all() assert np.isclose(orig_n, new_n, atol=1e-3).all() assert np.isclose(orig_c, new_c, atol=1e-3).all()
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_single_streamingmaxpool_modelwrapper(k, ifm_ch, ifm_dim, ofm_dim, idt): odt = idt inp = helper.make_tensor_value_info("inp", TensorProto.FLOAT, [1, ifm_dim, ifm_dim, ifm_ch]) outp = helper.make_tensor_value_info("outp", TensorProto.FLOAT, [1, ofm_dim, ofm_dim, ifm_ch]) smp_node = helper.make_node( "StreamingMaxPool_Batch", ["inp"], ["outp"], domain="finn", backend="fpgadataflow", PoolDim=k, NumChannels=ifm_ch, ImgDim=ifm_dim, dataType=idt.name, ) graph = helper.make_graph(nodes=[smp_node], name="smp_graph", inputs=[inp], outputs=[outp]) model = helper.make_model(graph, producer_name="smp-model") model = ModelWrapper(model) model.set_tensor_datatype("inp", idt) model.set_tensor_datatype("outp", odt) return model
def make_labelselect_modelwrapper(labels, pe, k, idt): inp = helper.make_tensor_value_info("inp", TensorProto.FLOAT, [1, labels]) outp = helper.make_tensor_value_info("outp", TensorProto.FLOAT, [1, k]) labelselect_node = helper.make_node( "LabelSelect_Batch", ["inp"], ["outp"], domain="finn", backend="fpgadataflow", Labels=labels, PE=pe, K=k, inputDataType=idt.name, ) graph = helper.make_graph( nodes=[labelselect_node], name="graph", inputs=[inp], outputs=[outp], ) model = helper.make_model(graph, producer_name="thresholding-model") model = ModelWrapper(model) model.set_tensor_datatype("inp", idt) odt = DataType.get_smallest_possible(labels - 1) model.set_tensor_datatype("outp", odt) return model
def make_single_dwc_modelwrapper(Shape, INWidth, OUTWidth, finn_dtype): inp = helper.make_tensor_value_info("inp", TensorProto.FLOAT, Shape) outp = helper.make_tensor_value_info("outp", TensorProto.FLOAT, Shape) DWC_node = helper.make_node( "StreamingDataWidthConverter_Batch", ["inp"], ["outp"], domain="finn", backend="fpgadataflow", shape=Shape, inWidth=INWidth, outWidth=OUTWidth, dataType=str(finn_dtype.name), ) graph = helper.make_graph(nodes=[DWC_node], name="dwc_graph", inputs=[inp], outputs=[outp]) model = helper.make_model(graph, producer_name="dwc-model") model = ModelWrapper(model) model.set_tensor_datatype("inp", finn_dtype) model.set_tensor_datatype("outp", finn_dtype) return model
def make_single_maxpoolnhwc_modelwrapper(k, ifm_ch, ifm_dim, ofm_dim, idt): odt = idt inp = helper.make_tensor_value_info("inp", TensorProto.FLOAT, [1, ifm_dim, ifm_dim, ifm_ch]) outp = helper.make_tensor_value_info("outp", TensorProto.FLOAT, [1, ofm_dim, ofm_dim, ifm_ch]) mp_node = helper.make_node( "MaxPoolNHWC", ["inp"], ["outp"], domain="finn", kernel_shape=[k, k], strides=[k, k], pads=[0, 0, 0, 0], ) graph = helper.make_graph(nodes=[mp_node], name="mp_graph", inputs=[inp], outputs=[outp]) model = helper.make_model(graph, producer_name="mp-model") model = ModelWrapper(model) model.set_tensor_datatype("inp", idt) model.set_tensor_datatype("outp", odt) return model
def make_dupstreams_modelwrapper(ch, pe, idim, idt): shape = [1, idim, idim, ch] inp = helper.make_tensor_value_info("inp", TensorProto.FLOAT, shape) outp0 = helper.make_tensor_value_info("outp0", TensorProto.FLOAT, shape) outp1 = helper.make_tensor_value_info("outp1", TensorProto.FLOAT, shape) dupstrm_node = helper.make_node( "DuplicateStreams_Batch", ["inp"], ["outp0", "outp1"], domain="finn.custom_op.fpgadataflow", backend="fpgadataflow", NumChannels=ch, PE=pe, inputDataType=idt.name, numInputVectors=[1, idim, idim], ) graph = helper.make_graph(nodes=[dupstrm_node], name="graph", inputs=[inp], outputs=[outp0, outp1]) model = helper.make_model(graph, producer_name="addstreams-model") model = ModelWrapper(model) model.set_tensor_datatype("inp", idt) model = model.transform(InferShapes()) model = model.transform(InferDataTypes()) return model
def test_modelwrapper_setting_unsetting_datatypes(): # Set and unset some datatypes and check for expected return values raw_m = get_data("finn.data", "onnx/mnist-conv/model.onnx") model = ModelWrapper(raw_m) test_node = model.graph.node[0] test_tensor = test_node.output[0] ret = model.get_tensor_datatype(test_tensor) assert (ret == DataType["FLOAT32"] ), "Tensor datatype should be float32 for no initalization." model.set_tensor_datatype(test_tensor, None) ret = model.get_tensor_datatype(test_tensor) assert ret == DataType[ "FLOAT32"], "An unset datatype should return float32." model.set_tensor_datatype(test_tensor, DataType["INT3"]) ret = model.get_tensor_datatype(test_tensor) assert ret == DataType["INT3"], "Tensor datatype should follow setting." model.set_tensor_datatype(test_tensor, DataType["UINT4"]) ret = model.get_tensor_datatype(test_tensor) assert ret == DataType["UINT4"], "Tensor datatype should follow setting." model.set_tensor_datatype(test_tensor, None) ret = model.get_tensor_datatype(test_tensor) assert ret == DataType[ "FLOAT32"], "An unset datatype should return float32." model.set_tensor_datatype(test_tensor, DataType["BIPOLAR"]) ret = model.get_tensor_datatype(test_tensor) assert ret == DataType["BIPOLAR"], "Tensor datatype should follow setting."
def make_accpool_modelwrapper(ch, pe, idim, idt): inp = helper.make_tensor_value_info("inp", TensorProto.FLOAT, [1, idim, idim, ch]) outp = helper.make_tensor_value_info("outp", TensorProto.FLOAT, [1, 1, 1, ch]) accpool_node = helper.make_node( "GlobalAccPool_Batch", ["inp"], ["outp"], domain="finn.custom_op.fpgadataflow", backend="fpgadataflow", NumChannels=ch, PE=pe, inputDataType=idt.name, numInputVectors=[1, idim, idim], ) graph = helper.make_graph(nodes=[accpool_node], name="graph", inputs=[inp], outputs=[outp]) model = helper.make_model(graph, producer_name="thresholding-model") model = ModelWrapper(model) model.set_tensor_datatype("inp", idt) return model
def make_addstreams_modelwrapper(ch, pe, idt): inp1 = helper.make_tensor_value_info("inp1", TensorProto.FLOAT, [1, ch]) inp2 = helper.make_tensor_value_info("inp2", TensorProto.FLOAT, [1, ch]) outp = helper.make_tensor_value_info("outp", TensorProto.FLOAT, [1, ch]) addstreams_node = helper.make_node( "AddStreams_Batch", ["inp1", "inp2"], ["outp"], domain="finn", backend="fpgadataflow", NumChannels=ch, PE=pe, inputDataType=idt.name, ) graph = helper.make_graph( nodes=[addstreams_node], name="graph", inputs=[inp1, inp2], outputs=[outp], ) model = helper.make_model(graph, producer_name="addstreams-model") model = ModelWrapper(model) model.set_tensor_datatype("inp1", idt) model.set_tensor_datatype("inp2", idt) return model
def test_onnx_exec_internal_rounding(): inp0 = onnx.helper.make_tensor_value_info("inp0", onnx.TensorProto.FLOAT, [2, 2]) inp1 = onnx.helper.make_tensor_value_info("inp1", onnx.TensorProto.FLOAT, [1]) outp = onnx.helper.make_tensor_value_info("outp", onnx.TensorProto.FLOAT, [2, 2]) mul_node = onnx.helper.make_node("Mul", inputs=["inp0", "inp1"], outputs=["outp"]) graph = onnx.helper.make_graph(nodes=[mul_node], name="mul_graph", inputs=[inp0, inp1], outputs=[outp]) model = onnx.helper.make_model(graph, producer_name="mul-model") model = ModelWrapper(model) idt = DataType.INT2 model.set_tensor_datatype("inp0", idt) model.set_tensor_datatype("inp1", idt) model.transform(InferShapes()) mul_value = np.asarray([-1], dtype=np.float32) inp_int = gen_finn_dt_tensor(idt, [2, 2]) scale = np.random.uniform(low=0, high=1, size=(2, 2)).astype(np.float32) inp_rounded = (inp_int * scale) / (scale + 1e-7) input_dict = {"inp0": inp_rounded, "inp1": mul_value} output_dict = oxe.execute_onnx(model, input_dict) produced = output_dict["outp"] expected = np.multiply(inp_int, mul_value) assert (produced == expected).all()
def test_move_flatten_past_affine(data_layout, batch_size): if data_layout == DataLayout.NHWC: ishape = [batch_size, 1, 1, 1024] oshape = [batch_size, 1000] else: ishape = [batch_size, 1024, 1, 1] oshape = [batch_size, 1000] inp = helper.make_tensor_value_info("inp", TensorProto.FLOAT, ishape) a0 = helper.make_tensor_value_info("a1", TensorProto.FLOAT, [1024, 1000]) a1 = helper.make_tensor_value_info("a2", TensorProto.FLOAT, []) a2 = helper.make_tensor_value_info("a3", TensorProto.FLOAT, [1000]) outp = helper.make_tensor_value_info("outp", TensorProto.FLOAT, oshape) flatten_node = helper.make_node("Flatten", ["inp"], ["flatten_out"]) matmul_node = helper.make_node("MatMul", ["flatten_out", "a0"], ["matmul_out"]) mul_node = helper.make_node("Mul", ["matmul_out", "a1"], ["mul_out"]) add_node = helper.make_node("Add", ["mul_out", "a2"], ["outp"]) graph = helper.make_graph( nodes=[flatten_node, matmul_node, mul_node, add_node], name="move-reshape-graph", inputs=[inp], outputs=[outp], value_info=[a0, a1, a2], ) model = helper.make_model(graph, producer_name="move_reshape_model") model = ModelWrapper(model) # initialize values a0_values = gen_finn_dt_tensor(DataType["TERNARY"], [1024, 1000]) model.set_initializer("a0", a0_values) a1_values = np.random.uniform(low=0.1, high=0.99, size=(1)).astype(np.float32) model.set_initializer("a1", a1_values) a2_values = np.random.uniform(low=-1, high=1, size=(1000)).astype(np.float32) model.set_initializer("a2", a2_values) model.set_tensor_datatype("inp", DataType["INT2"]) model.set_tensor_layout("inp", data_layout) model = model.transform(InferShapes()) model = model.transform(InferDataTypes()) model = model.transform(InferDataLayouts()) model = model.transform(GiveUniqueNodeNames()) model = model.transform(GiveReadableTensorNames()) # compare execution before and after transformation inp_values = gen_finn_dt_tensor(DataType["INT2"], ishape) idict = {model.graph.input[0].name: inp_values} model_transformed = model.transform(MoveFlattenPastAffine()) assert oxe.compare_execution(model, model_transformed, idict) # depending on data layout check if graph is transformed or not if data_layout == DataLayout.NHWC: # check if nodes have new order in transformed graph assert model.graph != model_transformed.graph assert model_transformed.graph.node[-1].op_type == "Flatten" else: assert model.graph == model_transformed.graph
def make_single_slidingwindow_modelwrapper(k, ifm_ch, ifm_dim, ofm_dim, simd, stride, dilation, idt, dw=0): k_h, k_w = k ifm_dim_h, ifm_dim_w = ifm_dim stride_h, stride_w = stride dilation_h, dilation_w = dilation ofm_dim_h, ofm_dim_w = ofm_dim odt = idt 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]) SlidingWindow_node = helper.make_node( "ConvolutionInputGenerator1D", ["inp"], ["outp"], domain="finn.custom_op.fpgadataflow", backend="fpgadataflow", ConvKernelDim=[k_h, k_w], IFMChannels=ifm_ch, IFMDim=[ifm_dim_h, ifm_dim_w], OFMDim=[ofm_dim_h, ofm_dim_w], SIMD=simd, Stride=[stride_h, stride_w], Dilation=[dilation_h, dilation_w], inputDataType=idt.name, outputDataType=odt.name, depthwise=dw, ) graph = helper.make_graph( nodes=[SlidingWindow_node], name="slidingwindow_graph", inputs=[inp], outputs=[outp], ) model = helper.make_model(graph, producer_name="slidingwindow-model") model = ModelWrapper(model) model.set_tensor_datatype("inp", idt) model.set_tensor_datatype("outp", odt) return model
def test_end2end_mobilenet_export(): # export preprocessing preproc_onnx = build_dir + "/end2end_mobilenet_preproc.onnx" mean = [0.485, 0.456, 0.406] std = 0.226 ch = 3 preproc = NormalizePreProc(mean, std, ch) bo.export_finn_onnx(preproc, (1, 3, 224, 224), preproc_onnx) preproc_model = ModelWrapper(preproc_onnx) # set input finn datatype to UINT8 preproc_model.set_tensor_datatype(preproc_model.graph.input[0].name, DataType["UINT8"]) preproc_model = preproc_model.transform(InferShapes()) preproc_model = preproc_model.transform(FoldConstants()) preproc_model = preproc_model.transform(GiveUniqueNodeNames()) preproc_model = preproc_model.transform(GiveUniqueParameterTensors()) preproc_model = preproc_model.transform(GiveReadableTensorNames()) preproc_model.save(build_dir + "/end2end_mobilenet_preproc.onnx") # export mobilenet finn_onnx = build_dir + "/end2end_mobilenet_export.onnx" mobilenet = get_test_model_trained("mobilenet", 4, 4) bo.export_finn_onnx(mobilenet, (1, 3, 224, 224), finn_onnx) # calculate golden output with pytorch/brevitas and save as .npy # get single image as input and prepare image img = Image.open("/workspace/finn/tests/brevitas/king_charles.jpg") # resize smallest side of the image to 256 pixels and resize larger side # with same ratio img = resize_smaller_side(256, img) # crop central 224*224 window img = crop_center(224, img) # save image as numpy array and as torch tensor to enable testing in # brevitas/pytorch and finn and transpose from (H, W, C) to (C, H, W) img_np = np.asarray(img).copy().astype(np.float32).transpose(2, 0, 1) img_np = img_np.reshape(1, 3, 224, 224) np.save(build_dir + "/end2end_mobilenet_input.npy", img_np) img_torch = torch.from_numpy(img_np).float() # do forward pass in PyTorch/Brevitas input_tensor = preproc.forward(img_torch) golden = mobilenet.forward(input_tensor).detach().numpy() golden_topk = golden.flatten() golden_top5 = np.argsort(golden_topk)[-5:] golden_top5 = np.flip(golden_top5) golden_top5_prob = [] for index in golden_top5: golden_top5_prob.append(golden_topk[index]) # save golden output values np.save(build_dir + "/end2end_mobilenet_golden_top5.npy", golden_top5) np.save(build_dir + "/end2end_mobilenet_golden_top5_prob.npy", golden_top5_prob) assert os.path.isfile(finn_onnx) assert os.path.isfile(build_dir + "/end2end_mobilenet_preproc.onnx")
def _make_single_vvau_modelwrapper( W, pe, k_h, k_w, channels, dim_h, dim_w, wdt, idt, odt, T=None, tdt=None ): in_shape = [1, dim_h, dim_w, k_h * k_w * channels] # [N, H, W, K*K*CH] out_shape = [ 1, dim_h, dim_w, channels, ] # [N, H, W, OFM_CH] (OFM_CH=IFM_CH because depthwise convolution) inp = helper.make_tensor_value_info("inp", TensorProto.FLOAT, in_shape) outp = helper.make_tensor_value_info("outp", TensorProto.FLOAT, out_shape) if T is not None: no_act = 0 node_inp_list = ["inp", "weights", "thresh"] actval = odt.min() else: no_act = 1 node_inp_list = ["inp", "weights"] actval = 0 VVAU_node = helper.make_node( "Vector_Vector_Activate_Batch", node_inp_list, ["outp"], domain="finn.custom_op.fpgadataflow", backend="fpgadataflow", PE=pe, Dim=[dim_h, dim_w], Channels=channels, Kernel=[k_h, k_w], resType="lut", ActVal=actval, inputDataType=idt.name, weightDataType=wdt.name, outputDataType=odt.name, noActivation=no_act, ) graph = helper.make_graph( nodes=[VVAU_node], name="vvau_graph", inputs=[inp], outputs=[outp] ) model = helper.make_model(graph, producer_name="vvau-model") model = ModelWrapper(model) model.set_tensor_datatype("inp", idt) model.set_tensor_datatype("outp", odt) model.set_tensor_datatype("weights", wdt) model.set_initializer("weights", W) model.set_tensor_shape("weights", (channels, 1, k_h, k_w)) if T is not None: model.set_tensor_datatype("thresh", tdt) model.set_initializer("thresh", T) return model
def test_infer_datatypes(): raw_m = get_data("finn.data", "onnx/mnist-conv/model.onnx") model = ModelWrapper(raw_m) model = model.transform(InferShapes()) model = model.transform(FoldConstants()) model = model.transform(GiveUniqueNodeNames()) model = model.transform(GiveReadableTensorNames()) # this model has no DataType info, so add some DataType annotation # to make things a bit more exciting model.set_tensor_datatype("global_in", DataType["UINT8"]) # Conv with int weights + inputs will have int output datatype model.set_tensor_datatype("Conv_0_param0", DataType["INT4"]) model = model.transform(InferDataTypes()) assert model.get_tensor_datatype("global_in") == DataType["UINT8"] assert model.get_tensor_datatype("Conv_0_out0") == DataType["INT32"] assert model.get_tensor_datatype("Relu_0_out0") == DataType["FLOAT32"] assert model.get_tensor_datatype("global_out") == DataType["FLOAT32"]
def test_move_flatten_past_affine(data_layout, batch_size): if data_layout == DataLayout.NHWC: ishape = [batch_size, 1, 1, 1024] oshape = [batch_size, 1024] else: ishape = [batch_size, 1024, 1, 1] oshape = [batch_size, 1024] inp = helper.make_tensor_value_info("inp", TensorProto.FLOAT, ishape) outp = helper.make_tensor_value_info("outp", TensorProto.FLOAT, oshape) flatten_node = helper.make_node("Flatten", ["inp"], ["outp"]) graph = helper.make_graph( nodes=[flatten_node], name="move-flatten-graph", inputs=[inp], outputs=[outp], ) model = helper.make_model(graph, producer_name="move_flatten_model") model = ModelWrapper(model) model.set_tensor_datatype("inp", DataType.INT2) model.set_tensor_layout("inp", data_layout) model = model.transform(InsertTopK()) model = model.transform(InferShapes()) model = model.transform(InferDataTypes()) model = model.transform(InferDataLayouts()) model = model.transform(GiveUniqueNodeNames()) model = model.transform(GiveReadableTensorNames()) # compare execution before and after transformation inp_values = gen_finn_dt_tensor(DataType.INT2, ishape) idict = {model.graph.input[0].name: inp_values} model_transformed = model.transform(MoveFlattenPastTopK()) assert oxe.compare_execution(model, model_transformed, idict) # depending on data layout check if graph is transformed or not if data_layout == DataLayout.NHWC: # check if nodes have new order in transformed graph assert model.graph != model_transformed.graph assert model_transformed.graph.node[-1].op_type == "Flatten" else: assert model.graph == model_transformed.graph
def make_single_slidingwindow_modelwrapper(k, ifm_ch, ifm_dim, ofm_dim, simd, stride, idt, dw=0): odt = idt inp = helper.make_tensor_value_info("inp", TensorProto.FLOAT, [1, ifm_dim, ifm_dim, ifm_ch]) outp = helper.make_tensor_value_info("outp", TensorProto.FLOAT, [1, ofm_dim, ofm_dim, k * k * ifm_ch]) SlidingWindow_node = helper.make_node( "ConvolutionInputGenerator", ["inp"], ["outp"], domain="finn", backend="fpgadataflow", ConvKernelDim=k, IFMChannels=ifm_ch, IFMDim=ifm_dim, OFMDim=ofm_dim, SIMD=simd, Stride=stride, inputDataType=idt.name, outputDataType=odt.name, depthwise=dw, ) graph = helper.make_graph( nodes=[SlidingWindow_node], name="slidingwindow_graph", inputs=[inp], outputs=[outp], ) model = helper.make_model(graph, producer_name="slidingwindow-model") model = ModelWrapper(model) model.set_tensor_datatype("inp", idt) model.set_tensor_datatype("outp", odt) return model
def make_single_fmpadding_modelwrapper(idim, padding, num_ch, simd, idt, pad_style): pad_h = padding[0] + padding[2] pad_w = padding[1] + padding[3] idim_h, idim_w = idim assert pad_style == 2, "only pad_style == 2 supported in hlslib" assert pad_h > 0 or pad_w > 0, "Output dim should be greater than input dim" odim_h = idim_h + pad_h odim_w = idim_w + pad_w inp = helper.make_tensor_value_info( "inp", TensorProto.FLOAT, [1, idim_h, idim_w, num_ch] ) outp = helper.make_tensor_value_info( "outp", TensorProto.FLOAT, [1, odim_h, odim_w, num_ch] ) FMPadding = helper.make_node( "FMPadding_Batch", ["inp"], ["outp"], domain="finn.custom_op.fpgadataflow", backend="fpgadataflow", ImgDim=idim, Padding=padding, NumChannels=num_ch, inputDataType=str(idt.name), PaddingStyle=pad_style, numInputVectors=1, SIMD=simd, ) graph = helper.make_graph( nodes=[FMPadding], name="fmpadding_graph", inputs=[inp], outputs=[outp] ) model = helper.make_model(graph, producer_name="fmpadding-model") model = ModelWrapper(model) model.set_tensor_datatype("inp", idt) model.set_tensor_datatype("outp", idt) return model
def make_single_maxpool_modelwrapper(onnx_op_name, ishape, idt, pdt, pshape): inp = helper.make_tensor_value_info("inp", TensorProto.FLOAT, ishape) outp = helper.make_tensor_value_info("outp", TensorProto.FLOAT, ishape) p0 = helper.make_tensor_value_info("p0", TensorProto.FLOAT, pshape) model = helper.make_model( helper.make_graph( name="test", inputs=[inp], outputs=[outp], value_info=[p0], nodes=[helper.make_node(onnx_op_name, ["inp", "p0"], ["outp"])], )) model = ModelWrapper(model) model.set_initializer("p0", gen_finn_dt_tensor(pdt, pshape)) model.set_tensor_datatype("inp", idt) model.transform(InferDataLayouts(), make_deepcopy=False) model.transform(InferShapes(), make_deepcopy=False) return model
def make_modelwrapper(C, pe, idt, odt, pdt, func, vecs): NumChannels = C.shape[0] inp = helper.make_tensor_value_info("inp", TensorProto.FLOAT, vecs + [NumChannels]) outp = helper.make_tensor_value_info( "outp", TensorProto.FLOAT, vecs + [NumChannels] ) node_inp_list = ["inp", "const"] node = helper.make_node( "ChannelwiseOp_Batch", node_inp_list, ["outp"], domain="finn.custom_op.fpgadataflow", backend="fpgadataflow", NumChannels=NumChannels, Func=func, PE=pe, inputDataType=idt.name, outputDataType=odt.name, paramDataType=pdt.name, numInputVectors=vecs, ) graph = helper.make_graph(nodes=[node], name="graph", inputs=[inp], outputs=[outp]) model = helper.make_model(graph, producer_name="model") model = ModelWrapper(model) model.set_tensor_datatype("inp", idt) model.set_tensor_datatype("outp", odt) model.set_tensor_datatype("const", idt) model.set_initializer("const", C) return model
def step_resnet50_convert_to_hls(model: ModelWrapper, cfg: DataflowBuildConfig): model.set_tensor_datatype(model.graph.input[0].name, DataType["UINT8"]) model = model.transform(InferDataLayouts()) try: from finn.transformation.fpgadataflow.infer_doublepacked_dsp import InferDoublePackedConv model = model.transform(InferDoublePackedConv([1])) except: print( " FINN Experimental not available. Using non-packed convolution ") model = model.transform(DoubleToSingleFloat()) model = model.transform(InferDataTypes()) model = model.transform(SortGraph()) to_hls_transformations = [ to_hls.InferAddStreamsLayer, LowerConvsToMatMul, to_hls.InferChannelwiseLinearLayer, to_hls.InferPool_Batch, AbsorbTransposeIntoMultiThreshold, RoundAndClipThresholds, to_hls.InferQuantizedStreamingFCLayer, to_hls.InferThresholdingLayer, AbsorbConsecutiveTransposes, to_hls.InferConvInpGen, to_hls.InferDuplicateStreamsLayer, to_hls.InferLabelSelectLayer ] for trn in to_hls_transformations: model = model.transform(trn()) model = model.transform(InferDataLayouts()) model = model.transform(GiveUniqueNodeNames()) model = model.transform(InferDataTypes()) model = model.transform(RemoveCNVtoFCFlatten()) model = model.transform(GiveReadableTensorNames()) model = model.transform(RemoveUnusedTensors()) model = model.transform(SortGraph()) return model
def test_res_estimate(): mw = mh = 4 simd = 1 pe = 1 idt = DataType.INT2 wdt = DataType.INT2 odt = DataType.INT32 actval = odt.min() 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", resType="ap_resource_lut()", MW=mw, MH=mh, SIMD=simd, PE=pe, inputDataType=idt.name, weightDataType=wdt.name, outputDataType=odt.name, ActVal=actval, binaryXnorMode=0, noActivation=0, ) 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) model = model.transform(GiveUniqueNodeNames()) prod_resource_estimation = model.analysis(res_estimation) expect_resource_estimation = { "StreamingFCLayer_Batch_0": { "BRAM_18K": 1, 'BRAM_efficiency': 0.001736111111111111, "LUT": 304.4 } } assert check_two_dict_for_equality( prod_resource_estimation, expect_resource_estimation), """The produced output of
def test_depthwise_conv_lowering(idt, k, ifm_dim, ifm_ch, stride, padding): wdt = idt odt = DataType.INT32 ofm_ch = ifm_ch ofm_dim = compute_conv_output_dim(ifm_dim, k, stride, pad=padding[0]) # set up onnx model inp = oh.make_tensor_value_info("inp", TensorProto.FLOAT, [1, ifm_ch, ifm_dim, ifm_dim]) outp = oh.make_tensor_value_info("outp", TensorProto.FLOAT, [1, ofm_ch, ofm_dim, ofm_dim]) W = oh.make_tensor_value_info("W", TensorProto.FLOAT, [ofm_ch, 1, k, k]) dw_cnv = oh.make_node( "Conv", inputs=["inp", "W"], outputs=["outp"], kernel_shape=[k, k], pads=padding, strides=[stride, stride], group=ifm_ch, ) graph = oh.make_graph( nodes=[dw_cnv], name="dw_cnv_graph", inputs=[inp], outputs=[outp], value_info=[W], ) model = oh.make_model(graph, producer_name="dws_cnv-model") model = ModelWrapper(model) model.set_tensor_datatype("inp", idt) model.set_tensor_datatype("outp", odt) model.set_tensor_datatype("W", wdt) w_tensor = gen_finn_dt_tensor(wdt, [ofm_ch, 1, k, k]) model.set_initializer("W", w_tensor) model = model.transform(InferShapes()) input_tensor = gen_finn_dt_tensor(idt, [1, ifm_ch, ifm_dim, ifm_dim]) input_dict = {"inp": input_tensor} output_dict = oxe.execute_onnx(model, input_dict) expected = output_dict["outp"] model = model.transform(LowerConvsToMatMul()) output_dict = oxe.execute_onnx(model, input_dict) produced = output_dict["outp"] assert (produced == expected).all() # check if created nodes have attributes that indicate depthwise conv assert model.get_tensor_sparsity("W") is not None im2col_node = getCustomOp(model.graph.node[1]) assert im2col_node.get_nodeattr("depthwise") == 1