diff --git a/tests/fpgadataflow/test_fpgadataflow_fclayer.py b/tests/fpgadataflow/test_fpgadataflow_fclayer.py index 9e174b3d39f35495e0c8f269ad8bd136f288b86c..42a3484667adf0bf8b2abe6a4d91226acb6043fe 100644 --- a/tests/fpgadataflow/test_fpgadataflow_fclayer.py +++ b/tests/fpgadataflow/test_fpgadataflow_fclayer.py @@ -115,7 +115,7 @@ def prepare_inputs(input_tensor, idt, wdt): @pytest.mark.parametrize("mw", [4]) # HLS matrix height (output features) @pytest.mark.parametrize("mh", [4]) -def test_fpgadataflow_fclayer(idt, wdt, act, nf, sf, mw, mh): +def test_fpgadataflow_fclayer_npysim(idt, wdt, act, nf, sf, mw, mh): if nf == -1: nf = mh if sf == -1: @@ -175,6 +175,77 @@ def test_fpgadataflow_fclayer(idt, wdt, act, nf, sf, mw, mh): # execute model y_produced = oxe.execute_onnx(model, input_dict)["outp"] assert (y_produced.reshape(y_expected.shape) == y_expected).all(), "npysim failed" + model = model.transform(CleanUp()) + + +# activation: None or DataType +@pytest.mark.parametrize("act", [None, DataType.BIPOLAR, DataType.INT2]) +# weight datatype +@pytest.mark.parametrize("wdt", [DataType.BIPOLAR, DataType.INT2]) +# input datatype +@pytest.mark.parametrize("idt", [DataType.BIPOLAR, DataType.INT2]) +# neuron folding, -1 is maximum possible +@pytest.mark.parametrize("nf", [-1, 1]) +# synapse folding, -1 is maximum possible +@pytest.mark.parametrize("sf", [-1, 1]) +# HLS matrix width (input features) +@pytest.mark.parametrize("mw", [4]) +# HLS matrix height (output features) +@pytest.mark.parametrize("mh", [4]) +def test_fpgadataflow_fclayer_rtlsim(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) + # 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) # TODO split up into several dependent tests -- need to check how this # works for parametrized tests... model = model.transform(SetSimMode("rtlsim"))