Exemple #1
0
def test_conv1d():
    """ Test a single 1D convolution """
    eg_vals = xparams({"n": 10, "k": 3, "p": 1})

    s1_ops = [
        pl.OpInfo(
            "MxV",
            [
                RD_a(
                    "[n,k,p] -> { S1[o1] -> in[j] : 0 <= o1 < ((n - k + 2*p) + 1) and o1 <= j < o1 + k }"
                ),
                WR_a(
                    "[n,k,p] -> { S1[o1] -> out[j] : 0 <= o1 < ((n - k + 2*p) + 1) and j = o1 }"
                ),
            ],
        ),
    ]
    stage1 = pl.Stage(pl.StageInfo(s1_ops), eg_vals)
    objs_info = {
        "in": ObjectInfo(shape=(eg_vals.n, ), padding=eg_vals.p),
        "out": ObjectInfo(shape=eg_vals.eval("(n-k+1,)"), padding=eg_vals.p),
    }
    pline = pl.Pipeline([stage1], objs_info, execute_ops=True)

    conv1_ps = conv.Conv1DParams(
        i=conv.Conv1DInParams(w=eg_vals["n"], d=1),
        f=conv.Conv1DFiltParams(w=eg_vals["k"], d=1, l=1),
        p=1,
        s=1,
        p_out=0,
    )

    # Set filters
    filters1 = np.random.rand(*conv1_ps.get_filters_shape())
    filters1_m = filters1.reshape(conv1_ps.eval("(f.l, f.d*f.w)"))
    cconf = pl.CoreConf(filters1_m)

    # Set input
    image1 = np.random.rand(*conv1_ps.get_input_shape())
    image1 = np.pad(image1, conv1_ps.get_input_padding())
    inp = pline.get_object("in")
    inp[...] = image1

    pline.configure([cconf])
    for _ in range(conv1_ps.o.w):
        pline.tick()
    out = pline.get_object("out")

    # Verify results
    output_simple = conv.conv1d_simple(image1, filters1, conv1_ps)
    # NB: conv1d_simple considers the depth dimension while our access
    # relations above do not
    np.testing.assert_allclose(output_simple[0, :], out)
Exemple #2
0
    def process_partitions_2(self):
        # Pass 2: set stage info
        init_tvs = self.init_tvs
        for (pid, part) in enumerate(self.partitions):
            opinfos = []
            for (idx, ni) in enumerate(part.nis):
                oi = None
                node = self.g.node[ni]
                if idx == 0:  # first node!
                    assert getattr(part, "conv_domain", None) is None
                    assert node.op_type == "Conv"
                    (input_name, ) = (x for x in node.input
                                      if x not in init_tvs)
                    (weights_name, ) = (x for x in node.input if x in init_tvs)
                    (output_name, ) = node.output

                    # TODO: The ONNX Conv operator has a batch size. Seems to
                    # me that the best thing to do would be to deal with batch
                    # size externally (i.e., at an external loop that performs
                    # the transfers from/to the accelerator), and transform the
                    # ONNX nodes to have a batch size of 1.
                    assert onnx_conv_get_batch(self.g, node) == 1

                    out_padding = self.objs_info[output_name].padding
                    part.conv_ps.set_p_out_from_padding(out_padding)

                    oi = OpInfo_CONV(
                        part.conv_ps,
                        s_id="S%d" % (pid, ),
                        vin_id=input_name,
                        vout_id=output_name,
                    )
                    part.conv_domain = oi.get_domain()

                elif node.op_type == "Add":
                    assert part.conv_domain is not None
                    (in1, in2) = node.input
                    (out, ) = node.output
                    a_shape = self.get_value_shape(in1)
                    b_shape = self.get_value_shape(in2)
                    y_shape = self.get_value_shape(out)
                    assert a_shape == b_shape
                    assert a_shape == y_shape
                    oi = OpInfo_ADD(part.conv_domain, a_shape, in1, in2, out)
                elif node.op_type == "Conv":
                    raise ValueError(
                        "Conv node can only be the first in a partition")
                else:
                    raise ValueError("Unknown node type %s" % (node.op_type, ))

                assert oi is not None
                opinfos.append(oi)
            part.stage_info = pl.StageInfo(opinfos)
Exemple #3
0
def test_conv2d():
    conv1_ps = conv.Conv2DParams(
        i=conv.Conv2DInParams(w=32, h=32, d=3),
        f=conv.Conv2DFiltParams(w=3, h=3, d=3, l=16),
        p=1,
        s=1,
        p_out=0,
    )

    s1_ops = [OpInfo_CONV(conv1_ps, s_id="S1", vin_id="V1", vout_id="V2")]
    stage1 = pl.Stage(pl.StageInfo(s1_ops))

    objs_info = {
        "V1": conv1_ps.get_input_objectinfo(),
        "V2": conv1_ps.get_output_objectinfo(),
    }

    p = pl.Pipeline([stage1], objs_info, execute_ops=True)

    # Set filters
    filters1 = np.random.rand(*conv1_ps.get_filters_shape())
    filters_m = filters1.reshape(conv1_ps.eval("(f.l, f.d*f.h*f.w)"))
    cconf = pl.CoreConf(filters_m)

    # Set input
    image1 = np.random.rand(*conv1_ps.get_input_shape())
    image1 = np.pad(image1, conv1_ps.get_input_padding())
    vals1 = p.get_object("V1")
    vals1[...] = image1

    # Configure pipeline
    p.configure([cconf])

    # Execute piepline
    for _ in range(conv1_ps.o.h * conv1_ps.o.w):
        p.tick()
    vals2 = p.get_object("V2")

    # Verify results
    output_simple = conv.conv2d_simple(image1, filters1, conv1_ps)
    output_mxv = conv.conv2d_mxv(image1, filters1, conv1_ps)
    np.testing.assert_allclose(output_simple, output_mxv)
    np.testing.assert_array_equal(output_mxv, vals2)
Exemple #4
0
def test_gcu():
    shape = (2, 2, 4)
    objs_info = {
        "I": ObjectInfo(shape=shape),
        "O": ObjectInfo(shape=shape),
    }

    inp = np.random.rand(*shape)
    out = np.zeros(shape)

    gcu = pl.GCU()
    s_ops = [
        OpInfo_ID(shape, s_id="S", inp_id="I", out_id="O"),
    ]
    s = pl.Stage(pl.StageInfo(s_ops))
    pline = pl.Pipeline([s], objs_info, gcu, execute_ops=1, loop_inp_limit=1)

    class Verifier:
        def __init__(self):
            self.verified = False

        def verify_fn(self, xop):
            np.testing.assert_allclose(
                xop.po_inps["I"],
                xop.po_outs["O"],
                err_msg="I does not match O for ID operation",
            )
            self.verified = True

    v = Verifier()
    op = pl.PipelineOp({"I": inp}, {"O": out}, completion_fn=v.verify_fn)

    pline.configure([pl.CoreConf(np.zeros((1, 1)))])
    pline.tick()
    pline.append_op(op)

    try:
        while True:
            pline.tick()
    except StopIteration:
        assert v.verified
Exemple #5
0
def test_mxv():
    """ Test a single MxV operation """
    params = xparams({"n": 128})

    s_ops = [
        pl.OpInfo(
            "MxV",
            [
                RD_a("{{ S[i] -> x[j] : i = 0 and 0 <= j < {n} }}".format(
                    **params)),
                WR_a("{{ S[i] -> y[j] : i = 0 and 0 <= j < {n} }}".format(
                    **params)),
            ],
        )
    ]
    stage = pl.Stage(pl.StageInfo(s_ops))

    # Objects
    objs_info = {
        "x": ObjectInfo(shape=(params.n, )),
        "y": ObjectInfo(shape=(params.n, )),
    }

    # Initialize matrix, and create core configuration
    # np.random.seed(666)
    m_shape = params.eval("(n,n)")
    m = np.random.rand(*m_shape)
    cconf = pl.CoreConf(m)

    # Initalize pipeline
    pline = pl.Pipeline([stage], objs_info, execute_ops=True)
    x = pline.get_object("x")
    x[...] = np.random.rand(params.n)

    # Configure pipeline
    pline.configure([cconf])

    # Execute a single tick and compare results
    pline.tick()
    y = pline.get_object("y")
    assert np.array_equal(y, np.matmul(m, x))
Exemple #6
0
def test_residual_1d():
    #  CONV1D ---> CONV1D ---> ADD
    #          |           ^
    #          |           |
    #          +---------- +
    #
    # Stage S1:
    #  - MxV (CONV1D)
    #     - PARAMS: P1, F1
    #     - INPUT:  IN
    #     - OUTPUT: O1
    #
    # Stage S2:
    #  - MxV (CONV1D)
    #     - PARAMS: P2, F2
    #     - INPUT:  O1
    #     - OUTPUT: O3 (internal)
    #  - ADD:
    #     - INPUT: O1, O3 (internal)
    #     - OUTPUT: OUT
    #
    # cross-stage Objects:
    #  IN: WRITER: NONE,     READER: S1/MxV
    #  O1: WRITER: S1/MxV,   READER: S2/MxV
    # OUT: WRITER: S2/ADD,   READER: NONE
    #
    # Objects have a single writer and reader
    # Stages might read or write more than one objects

    params = get_params()

    s1_ops = [
        pl.OpInfo(
            "MxV",
            [
                RD_a(
                    "{{ S1[s1] -> IN[i1] : 0 <= s1 < {O1} and s1 <= i1 < s1 + {F1} }}"
                    .format(**params)),
                WR_a(
                    "{{ S1[s1] -> O1[o1] : 0 <= s1 < {O1} and o1 = s1 + {P2} }}"
                    .format(**params)),
            ],
        )
    ]

    s2_ops = [
        pl.OpInfo(
            "MxV",
            [
                RD_a(
                    "{{ S2[s2] -> O1[o1] : 0 <= s2 < {O3} and s2 <= o1 < s2 + {F2}}}"
                    .format(**params)),
                WR_a("{{ S2[s2] -> O3[o3] : 0 <= s2 < {O3} and o3 = s2 }}".
                     format(**params)),
            ],
        ),
        pl.OpInfo(
            "ADD",
            [
                RD_a("{{ S2[s2] -> O1[o1]   : 0 <= s2 < {O3} and o1  = s2 }}".
                     format(**params)),
                RD_a("{{ S2[s2] -> O3[o3]   : 0 <= s2 < {O3} and o3  = s2 }}".
                     format(**params)),
                WR_a("{{ S2[s2] -> OUT[out] : 0 <= s2 < {O3} and out = s2 }}".
                     format(**params)),
            ],
        ),
    ]

    s2 = pl.Stage(pl.StageInfo(s2_ops))
    assert s2.si.ro_objs == set(("O1", ))
    assert s2.si.wo_objs == set(("OUT", ))
    assert s2.si.rw_objs == set(("O3", ))

    s1 = pl.Stage(pl.StageInfo(s1_ops))
    assert s1.si.ro_objs == set(("IN", ))
    assert s1.si.wo_objs == set(("O1", ))
    assert s1.si.rw_objs == set()

    conv1_ps = conv.Conv1DParams(
        i=conv.Conv1DInParams(w=params.IN, d=1),
        f=conv.Conv1DFiltParams(w=params.F1, d=1, l=1),
        p=params.P1,
        s=params.S1,
        p_out=params.P2,
    )
    conv2_ps = conv.Conv1DParams(
        i=conv1_ps.o.to_in(),
        f=conv.Conv1DFiltParams(w=params.F2, d=1, l=1),
        p=params.P2,
        s=params.S2,
        p_out=0,
    )

    objs_info = {
        # 'IN':  (params.eval("IN + 2*P1"), ),
        # 'O1':  (params.eval("O1 + 2*P2"), ),
        # 'O3':  (params.O3, ),
        # 'OUT': (params.OUT,),
        "IN": ObjectInfo(shape=(params.IN, ), padding=params.P1),
        "O1": ObjectInfo(shape=(params.O1, ), padding=params.P2),
        "O3": ObjectInfo(shape=(params.O3, ), padding=0),
        "OUT": ObjectInfo(shape=(params.OUT, ), padding=0),
    }
    pprint(objs_info)

    pline = pl.Pipeline([s1, s2],
                        objs_info,
                        execute_ops=True,
                        loop_inp_limit=1)

    pprint(params)
    filters1 = np.random.rand(*conv1_ps.get_filters_shape())
    filters1_m = filters1.reshape(conv1_ps.eval("(f.l, f.d*f.w)"))
    cconf1 = pl.CoreConf(filters1_m)

    filters2 = np.random.rand(*conv2_ps.get_filters_shape())
    filters2_m = filters2.reshape(conv2_ps.eval("(f.l, f.d*f.w)"))
    cconf2 = pl.CoreConf(filters2_m)

    image = np.random.rand(*conv1_ps.get_input_shape())
    image = np.pad(image, conv1_ps.get_input_padding())
    inp = pline.get_object("IN")
    inp[...] = image

    pline.configure([cconf1, cconf2])

    print_info = False
    for iters in pline.tick_gen():
        if print_info:
            print("*" * 80)
        for (s, i) in iters.items():
            if print_info:
                print("%s: %s" % (s, i))
        if print_info:
            print("*" * 80)
    print("%s> DONE" % ("-" * 30, ))

    pline_out = pline.get_object("OUT")
    pline_o1 = pline.get_object("O1")
    pline_o3 = pline.get_object("O3")

    o1 = conv.conv1d_simple(image, filters1, conv1_ps)
    o2 = np.copy(o1)
    o1 = np.pad(o1, conv2_ps.get_input_padding())
    np.testing.assert_allclose(o1[0, :], pline_o1, err_msg="O1 does not match")
    o3 = conv.conv1d_simple(o1, filters2, conv2_ps)
    out = o3 + o2
    np.testing.assert_allclose(o3[0, :], pline_o3, err_msg="O3 does not match")
    np.testing.assert_allclose(out[0, :],
                               pline_out,
                               err_msg="OUT does not match")
Exemple #7
0
def test_conv2d_conv2d():
    conv1_padding = 1
    conv2_padding = 1

    conv1_ps = conv.Conv2DParams(
        i=conv.Conv2DInParams(w=32, h=32, d=3),
        f=conv.Conv2DFiltParams(w=3, h=3, d=3, l=1),
        p=conv1_padding,
        p_out=conv2_padding,
        s=1,
    )

    conv2_ps = conv.Conv2DParams(
        i=conv1_ps.o.to_in(),
        f=conv.Conv2DFiltParams(w=3, h=3, d=conv1_ps.f.l, l=1),
        p=conv2_padding,
        p_out=0,
        s=1,
    )

    s1_ops = [
        OpInfo_CONV(conv1_ps, s_id="S1", vin_id="V1", vout_id="V2"),
    ]
    stage1 = pl.Stage(pl.StageInfo(s1_ops))

    s2_ops = [
        OpInfo_CONV(conv2_ps, s_id="S2", vin_id="V2", vout_id="V3"),
    ]
    stage2 = pl.Stage(pl.StageInfo(s2_ops))

    objs_info = {
        "V1": conv1_ps.get_input_objectinfo(),
        "V2": conv2_ps.get_input_objectinfo(),
        "V3": conv2_ps.get_output_objectinfo(),
    }

    p = pl.Pipeline([stage1, stage2], objs_info, execute_ops=True)

    filters1 = np.random.rand(*conv1_ps.get_filters_shape())
    filters_m1 = filters1.reshape(conv1_ps.eval("(f.l, f.d*f.h*f.w)"))
    cconf1 = pl.CoreConf(filters_m1)

    filters2 = np.random.rand(*conv2_ps.get_filters_shape())
    filters_m2 = filters2.reshape(conv2_ps.eval("(f.l, f.d*f.h*f.w)"))
    cconf2 = pl.CoreConf(filters_m2)

    image = np.random.rand(*conv1_ps.get_input_shape())
    image = np.pad(image, conv1_ps.get_input_padding())

    p.configure([cconf1, cconf2])

    vals1 = p.get_object("V1")
    print("vals1.shape=%s image.shape=%s" % (vals1.shape, image.shape))
    pprint(objs_info)
    vals1[...] = image

    while True:
        iters = p.tick()
        print("*" * 80)
        for (s, i) in iters.items():
            print("%s: %s" % (s, i))
        print("*" * 80)
        # input()
        if iters["S2"] == (0, conv2_ps.o.h - 1, conv2_ps.o.w - 1):
            break

    vals3 = p.get_object("V3")
    pprint(vals3.shape)

    output1 = conv.conv2d_simple(image, filters1, conv1_ps)
    output1 = np.pad(output1, conv2_ps.get_input_padding())
    output2 = conv.conv2d_simple(output1, filters2, conv2_ps)
    np.testing.assert_allclose(output2, vals3)
    print("DONE!")
Exemple #8
0
def test_conv1d_conv1d():
    # TODO: enable execute_ops = True, and compare results

    # A 1D-convolution with one layer (simplest case)
    #
    # For N=12, K=3, zero padding, the code looks simething like this:
    #
    # Stage s1:
    #     for o1 ← range(0, 10) {
    #         in2[o1,:] ← MXV(in1[o1:(o1 + 3),:])
    #     }
    # Stage s2:
    #     for o2 ← range(0, 8) {
    #         out2[o2,:] ← MXV(in2[o2:(o2 + 3),:])
    #     }
    #

    # Example values
    # N: in1 size
    # K: kernel size
    # P: padding
    eg_vals = xparams({"n": 10, "k": 3, "p": 1})

    s1_ops = [
        pl.OpInfo(
            "MxV",
            [
                RD_a(
                    "[n,k,p] -> { S1[o1] -> in1[j] : 0 <= o1 < ((n - k + 2*p) + 1) and o1 <= j < o1 + k }"
                ),
                WR_a(
                    "[n,k,p] -> { S1[o1] -> in2[j] : 0 <= o1 < ((n - k + 2*p) + 1) and j = o1 + p}"
                ),
            ],
        ),
    ]
    stage1 = pl.Stage(pl.StageInfo(s1_ops), eg_vals)

    s2_ops = [
        pl.OpInfo(
            "MxV",
            [
                RD_a(
                    "[n,k,p] -> { S2[o2] -> in2[j] : 0 <= o2 < (n-k+2*p) and  o2 <= j < o2 + k }"
                ),
            ],
        ),
    ]
    stage2 = pl.Stage(pl.StageInfo(s2_ops), eg_vals)

    objs_info = {
        "in1": ObjectInfo(shape=(eg_vals.n, ), padding=eg_vals.p),
        "in2": ObjectInfo(shape=(eg_vals.eval("n-k+2*p+1"), ),
                          padding=eg_vals.p),
    }
    pprint(objs_info)

    pline = pl.Pipeline([stage1, stage2], objs_info)

    for i in range(13):
        pline.tick()