예제 #1
0
def test_reallocation():
    x = scalar("x")
    y = scalar("y")
    z = tanh(3 * x + y) + cosh(x + 5 * y)
    # The functinality is currently implement for non lazy and non c VM only.
    for linker in [
            VMLinker(allow_gc=False, lazy=False, use_cloop=False),
            VMLinker(allow_gc=True, lazy=False, use_cloop=False),
    ]:
        m = get_mode(Mode(linker=linker))
        m = m.excluding("fusion", "inplace")

        f = function([x, y], z, name="test_reduce_memory", mode=m)
        output = f(1, 2)
        assert output
        storage_map = f.fn.storage_map

        def check_storage(storage_map):
            for i in storage_map:
                if not isinstance(i, TensorConstant):
                    keys_copy = list(storage_map.keys())[:]
                    keys_copy.remove(i)
                    for o in keys_copy:
                        if storage_map[i][
                                0] and storage_map[i][0] is storage_map[o][0]:
                            return [True, storage_map[o][0]]
            return [False, None]

        assert check_storage(storage_map)[0]
        assert len({id(v) for v in storage_map.values()}) < len(storage_map)
예제 #2
0
    def test_no_leak_many_call_nonlazy():
        # Verify no memory leaks when calling a function a lot of times

        # This isn't really a unit test, you have to run it and look at top to
        # see if there's a leak.

        def build_graph(x, depth=5):
            z = x
            for d in range(depth):
                z = sin(-z + 1)
            return z

        def time_linker(name, linker):
            steps_a = 10
            x = dvector()
            a = build_graph(x, steps_a)

            f_a = function([x], a, mode=Mode(optimizer=None, linker=linker()))
            inp = np.random.rand(1000000)
            for i in range(500):
                f_a(inp)

        print(1)
        time_linker("vmLinker_C",
                    lambda: VMLinker(allow_gc=False, use_cloop=True))
        print(2)
        time_linker("vmLinker",
                    lambda: VMLinker(allow_gc=False, use_cloop=False))
예제 #3
0
def test_no_recycling():
    x = vector()
    for lnk in [
            VMLinker(use_cloop=True),
            VMLinker(use_cloop=False, lazy=True),
            VMLinker(use_cloop=False, lazy=False, allow_gc=True),
            VMLinker(use_cloop=False, lazy=False, allow_gc=False),
    ]:

        mode = Mode(optimizer="fast_compile", linker=lnk)
        f = function([x], x + 1, mode=mode)
        f2 = function([x], (x + 1) * 2, mode=mode)
        m1 = f.fn.thunks[0].thunk.module
        m2 = f2.fn.thunks[0].thunk.module
        assert m1 is m2
예제 #4
0
def test_partial_function_with_updates():
    def check_updates(linker_name):
        x = lscalar("input")
        y = shared(np.asarray(1, "int64"), name="global")
        f = function(
            [x],
            [x, x + 34],
            updates=[(y, x + 1)],
            mode=Mode(optimizer=None, linker=linker_name),
        )
        g = function(
            [x],
            [x - 6],
            updates=[(y, y + 3)],
            mode=Mode(optimizer=None, linker=linker_name),
        )

        assert f(3, output_subset=[]) == []
        assert y.get_value() == 4
        assert g(30, output_subset=[0]) == [24]
        assert g(40, output_subset=[]) == []
        assert y.get_value() == 10

    check_updates(VMLinker(allow_partial_eval=True, use_cloop=False))
    check_updates("cvm")
예제 #5
0
def test_VMLinker_make_vm_cvm():
    # We don't want this at module level, since CXX might not be present
    from aesara.link.c.cvm import CVM

    a = scalar()
    linker = VMLinker(allow_gc=False, use_cloop=True)

    f = function([a], a, mode=Mode(optimizer=None, linker=linker))
    assert isinstance(f.fn, CVM)
예제 #6
0
    def test_callback_with_ifelse(self):
        a, b, c = scalars("abc")
        f = function(
            [a, b, c],
            ifelse(a, 2 * b, 2 * c),
            mode=Mode(optimizer=None, linker=VMLinker(callback=self.callback)),
        )

        f(1, 2, 3)
        assert self.n_callbacks["IfElse"] == 2
예제 #7
0
def test_vm_gc():
    x = vector()
    p = RunOnce()(x)
    mode = Mode(linker=VMLinker(lazy=True))
    f = function([In(x, mutable=True)], [p + 1, p + 2], mode=mode)
    f([1, 2, 3])

    p = RunOnce()(x)
    pp = p + p
    f = function([x], [pp + pp], mode=mode)
    f([1, 2, 3])
예제 #8
0
def test_speed_lazy():
    # TODO FIXME: This isn't a real test.

    def build_graph(x, depth=5):
        z = x
        for d in range(depth):
            z = ifelse(z[0] > 0, -z, z)
        return z

    def time_linker(name, linker):
        steps_a = 10
        steps_b = 100
        x = vector()
        a = build_graph(x, steps_a)
        b = build_graph(x, steps_b)

        f_a = function([x], a, mode=Mode(optimizer=None, linker=linker()))
        f_b = function([x], b, mode=Mode(optimizer=None, linker=linker()))

        f_a([2.0])
        t0 = time.time()
        f_a([2.0])
        t1 = time.time()

        f_b([2.0])

        t2 = time.time()
        f_b([2.0])
        t3 = time.time()

        t_a = t1 - t0
        t_b = t3 - t2

        print(
            f"{name} takes {1000 * (t_b - t_a) / (steps_b - steps_a):f} s/Kop")

    time_linker("vmLinker", VMLinker)
    time_linker("vmLinker_nogc", lambda: VMLinker(allow_gc=False))
    if config.cxx:
        time_linker("vmLinker_C",
                    lambda: VMLinker(allow_gc=False, use_cloop=True))
예제 #9
0
    def test_callback(self):
        a, b, c = scalars("abc")
        f = function(
            [a, b, c],
            (a + b) + c,
            mode=Mode(optimizer=None, linker=VMLinker(callback=self.callback)),
        )

        f(1, 2, 3)
        assert sum(self.n_callbacks.values()) == len(f.maker.fgraph.toposort())
        f(1, 2, 3)
        assert sum(
            self.n_callbacks.values()) == len(f.maker.fgraph.toposort()) * 2
예제 #10
0
def test_partial_function_with_output_keys():
    def check_partial_function_output_keys(linker_name):
        x = scalar("input")
        y = 3 * x
        f = function([x], {
            "a": y * 5,
            "b": y - 7
        },
                     mode=Mode(optimizer=None, linker=linker_name))

        assert f(5, output_subset=["a"])["a"] == f(5)["a"]

    check_partial_function_output_keys(
        VMLinker(allow_partial_eval=True, use_cloop=False))
    check_partial_function_output_keys("cvm")
예제 #11
0
    def test_no_leak_many_call_lazy():
        # Verify no memory leaks when calling a function a lot of times

        # This isn't really a unit test, you have to run it and look at top to
        # see if there's a leak

        def build_graph(x, depth=5):
            z = x
            for d in range(depth):
                z = ifelse(z.mean() > 0.5, -z, z)
            return z

        def time_linker(name, linker):
            steps_a = 10
            x = dvector()
            a = build_graph(x, steps_a)

            f_a = function([x], a, mode=Mode(optimizer=None, linker=linker()))
            inp = np.random.rand(1000000)
            for i in range(100):
                f_a(inp)
                # this doesn't seem to work, prints 0 for everything
                # import resource
                #
                # pre = resource.getrusage(resource.RUSAGE_SELF)
                # post = resource.getrusage(resource.RUSAGE_SELF)
                # print(pre.ru_ixrss, post.ru_ixrss)
                # print(pre.ru_idrss, post.ru_idrss)
                # print(pre.ru_maxrss, post.ru_maxrss)

        print(1)
        time_linker("vmLinker_C",
                    lambda: VMLinker(allow_gc=False, use_cloop=True))
        print(2)
        time_linker("vmLinker",
                    lambda: VMLinker(allow_gc=False, use_cloop=False))
예제 #12
0
def test_vm_gc():
    # This already caused a bug in the trunk of Aesara.
    #
    # The bug was introduced in the trunk on July 5th, 2012 and fixed on
    # July 30th.

    x = vector()
    p = RunOnce()(x)
    mode = Mode(linker=VMLinker(lazy=True))
    f = function([In(x, mutable=True)], [p + 1, p + 2], mode=mode)
    f([1, 2, 3])

    p = RunOnce()(x)
    pp = p + p
    f = function([x], [pp + pp], mode=mode)
    f([1, 2, 3])
예제 #13
0
def test_partial_function():
    from tests import unittest_tools as utt

    def check_partial_function(linker_name):
        x = scalar("input")
        y = x**2
        f = function([x], [y + 7, y - 9, y / 14.0],
                     mode=Mode(optimizer=None, linker=linker_name))

        assert f(3, output_subset=[0, 1, 2]) == f(3)
        assert f(4, output_subset=[0, 2]) == [f(4)[0], f(4)[2]]
        utt.assert_allclose(f(5), np.array([32.0, 16.0, 1.7857142857142858]))

    check_partial_function(VMLinker(allow_partial_eval=True, use_cloop=False))
    if not config.cxx:
        pytest.skip("Need cxx for this test")
    check_partial_function("cvm")
예제 #14
0
def test_VMLinker_exception():
    class BadOp(Op):
        def perform(self, node, inputs, outputs):
            pass

        def make_node(self, x):
            return Apply(self, [x], [x.type()])

        def make_thunk(self, *args, **kwargs):
            raise Exception("bad Op")

    a = scalar()
    linker = VMLinker(allow_gc=False, use_cloop=True)

    z = BadOp()(a)

    with pytest.raises(Exception,
                       match=".*Apply node that caused the error.*"):
        function([a], z, mode=Mode(optimizer=None, linker=linker))
예제 #15
0
def test_use_c_thunks():
    a_at = scalars("a")
    b_at = vectors("b")

    a = np.array(0.0).astype(config.floatX)
    b = np.array([2.0]).astype(config.floatX)

    cases = [False]
    if config.cxx:
        cases.append(True)

    for use_c_thunks in cases:
        f = function(
            [a_at, b_at],
            a_at * b_at,
            mode=Mode(optimizer=None,
                      linker=VMLinker(c_thunks=use_c_thunks, use_cloop=False)),
        )
        assert np.array_equal(a * b, f(a, b))
        assert any([hasattr(t, "cthunk") for t in f.fn.thunks]) == use_c_thunks
예제 #16
0
def test_VMLinker_make_vm_no_cvm():
    from importlib import reload
    from unittest.mock import patch

    with config.change_flags(cxx=""):

        # Make sure that GXX isn't present
        with pytest.raises(MissingGXX):
            import aesara.link.c.cvm

            reload(aesara.link.c.cvm)

        # Make sure that `cvm` module is missing
        with patch.dict("sys.modules", {"aesara.link.c.cvm": None}):
            a = scalar()
            linker = VMLinker(allow_gc=False, use_cloop=True)

            with pytest.raises(ModuleNotFoundError):
                import aesara.link.c.cvm

            f = function([a], a, mode=Mode(optimizer=None, linker=linker))
            assert isinstance(f.fn, Loop)
예제 #17
0
파일: test_types.py 프로젝트: mgorny/aesara
class TestFunction:
    @pytest.mark.xfail()
    def test_none(self):
        fn = function([], None)  # ok
        rval = fn()
        assert (
            rval != []
        ), "See #254: Using None as function output leads to [] return value"
        assert rval is None

    def test_empty(self):
        fn = function([], [])  # ok
        assert fn() == []

    def test_extra_inputs(self):
        x, s = scalars("xs")
        fn = function([x], [x])
        with pytest.raises(TypeError):
            fn(1, 2)

    def test_missing_inputs(self):
        def fn():
            x, s = scalars("xs")
            function([], [x])

        with pytest.raises(MissingInputError):
            fn()

        def fn():
            x, s = scalars("xs")
            # Ignore unused input s, as it hides the other error
            function([s], [x], on_unused_input="ignore")

        with pytest.raises(MissingInputError):
            fn()

        def fn():
            x, s = scalars("xs")
            function([s], [x])

        with pytest.raises(UnusedInputError):
            fn()

        def fn():
            x, s = scalars("xs")
            # Ignore unused input s, as it hides the other error
            function([s], x, on_unused_input="ignore")

        with pytest.raises(MissingInputError):
            fn()

        def fn():
            x, s = scalars("xs")
            function([s], x)

        with pytest.raises(UnusedInputError):
            fn()

        def fn():
            x, s = scalars("xs")
            # Ignore unused input s, as it hides the other error
            function([s], Out(x), on_unused_input="ignore")

        with pytest.raises(MissingInputError):
            fn()

        def fn():
            x, s = scalars("xs")
            function([s], Out(x))

        with pytest.raises(UnusedInputError):
            fn()

        def fn():
            x, s = scalars("xs")
            function([In(x, update=s + x)], x)

        with pytest.raises(MissingInputError):
            fn()

        def fn():
            x, s = scalars("xs")
            function([In(x, update=((s * s) + x))], x)

        with pytest.raises(MissingInputError):
            fn()

    def test_input_anon_singleton(self):
        x, s = scalars("xs")
        fn = function([s, x], [x + s])
        assert fn(2, 3) == [5]
        # no state
        assert fn(2, 3) == [5]

    def test_input_anon_unpack(self):
        x, s = scalars("xs")
        fn = function([s, x], x + s)
        assert fn(2, 3) == 5

    def test_naming_rule0(self):
        x, s = scalars("xs")
        f = function([x, s], x / s)
        assert f(1, 2) == 0.5
        assert f(2, 1) == 2.0
        assert f(s=2, x=1) == 0.5
        assert f(x=2, s=1) == 2.0
        assert f(2, s=1) == 2.0

        with pytest.raises(TypeError):
            # got multiple values for keyword argument 'x'
            f(2, x=2.0)
        with pytest.raises(TypeError):
            # takes exactly 2 non-keyword arguments (1 given)
            f(x=1)
        with pytest.raises(TypeError):
            # takes exactly 2 non-keyword arguments (0 given)
            f(s=1)

    def test_naming_rule1(self):
        a = scalar()  # the a is for 'anonymous' (un-named).
        x, s = scalars("xs")
        f = function([a, s], a / s)
        assert f(1, 2) == 0.5
        assert f(2, 1) == 2.0
        assert f(2, s=1) == 2.0

        with pytest.raises(TypeError):
            # got unexpected keyword argument 'q'
            f(q=2, s=1)
        with pytest.raises(TypeError):
            # got unexpected keyword argument 'a'
            f(a=2, s=1)

    def test_naming_rule2(self):
        a = scalar()  # the a is for 'anonymous' (un-named).
        x, s = scalars("xs")

        # x's name is ignored because it is followed by anonymous parameter a.
        # Ignore unused input x, as it hides the other error
        f = function([x, a, s], a / s, on_unused_input="ignore")
        assert f(9, 1, 2) == 0.5
        assert f(9, 2, 1) == 2.0
        assert f(9, 2, s=1) == 2.0

        with pytest.raises(TypeError):
            # got unexpected keyword argument 'x'
            f(x=9, a=2, s=1)
        with pytest.raises(TypeError):
            # got unexpected keyword argument 'x'
            f(5.0, x=9)

    def test_naming_rule3(self):
        a = scalar()  # the a is for 'anonymous' (un-named).
        x, s = scalars("xs")

        # x's name is not ignored (as in test_naming_rule2) because a has a default value.
        f = function([x, In(a, value=1.0), s], a / s + x)
        assert f(9, 2, 4) == 9.5  # can specify all args in order
        assert f(9, 2, s=4) == 9.5  # can give s as kwarg
        assert f(9, s=4) == 9.25  # can give s as kwarg, get default a
        assert f(x=9, s=4) == 9.25  # can give s as kwarg, omit a, x as kw
        with pytest.raises(TypeError):
            # got unexpected keyword argument 'a'
            f(x=9, a=2, s=4)
        with pytest.raises(TypeError):
            # takes exactly 3 non-keyword arguments (0 given)
            f()
        with pytest.raises(TypeError):
            # takes exactly 3 non-keyword arguments (1 given)
            f(x=9)

    def test_naming_rule4(self):
        a = scalar()  # the a is for 'anonymous' (un-named).
        x, s = scalars("xs")

        f = function([x, In(a, value=1.0, name="a"), s], a / s + x)

        assert f(9, 2, 4) == 9.5  # can specify all args in order
        assert f(9, 2, s=4) == 9.5  # can give s as kwarg
        assert f(9, s=4) == 9.25  # can give s as kwarg, get default a
        assert f(9, a=2, s=4) == 9.5  # can give s as kwarg, a as kwarg
        assert f(x=9, a=2, s=4) == 9.5  # can give all kwargs
        assert f(x=9, s=4) == 9.25  # can give all kwargs
        with pytest.raises(TypeError):
            # takes exactly 3 non-keyword arguments (0 given)
            f()
        with pytest.raises(TypeError):
            # got multiple values for keyword argument 'x'
            f(5.0, x=9)

    @pytest.mark.parametrize(
        "mode",
        [
            Mode(
                linker=VMLinker(allow_gc=True, use_cloop=False,
                                c_thunks=False),
                optimizer="fast_compile",
            ),
            Mode(
                linker=VMLinker(allow_gc=True, use_cloop=False,
                                c_thunks=False),
                optimizer="fast_run",
            ),
            Mode(linker="cvm", optimizer="fast_compile"),
            Mode(linker="cvm", optimizer="fast_run"),
        ],
    )
    def test_state_access(self, mode):
        a = scalar()
        x, s = scalars("xs")

        f = function(
            [
                x,
                In(a, value=1.0, name="a"),
                In(s, value=0.0, update=s + a * x)
            ],
            s + a * x,
            mode=mode,
        )

        assert f[a] == 1.0
        assert f[s] == 0.0

        assert f(3.0) == 3.0
        assert f[s] == 3.0
        assert f(3.0, a=2.0) == 9.0  # 3.0 + 2*3.0

        assert (
            f[a] == 1.0
        )  # state hasn't changed permanently, we just overrode it last line
        assert f[s] == 9.0

        f[a] = 5.0
        assert f[a] == 5.0
        assert f(3.0) == 24.0  # 9 + 3*5
        assert f[s] == 24.0

    def test_same_names(self):
        a, x, s = scalars("xxx")
        # implicit names would cause error.  What do we do?
        f = function([a, x, s], a + x + s)
        assert f(1, 2, 3) == 6
        with pytest.raises(TypeError):
            f(1, 2, x=3)

    def test_weird_names(self):
        a, x, s = scalars("xxx")

        with pytest.raises(TypeError):
            function([In(a, name=[])], [])

        def t():
            f = function(
                [
                    In(a, name={"adsf", ()}, value=1.0),
                    In(x, name=(), value=2.0),
                    In(s, name=scalar(), value=3.0),
                ],
                a + x + s,
            )
            return f

        with pytest.raises(TypeError):
            t()

    def test_copy(self):
        a = scalar()
        x, s = scalars("xs")

        f = function(
            [
                x,
                In(a, value=1.0, name="a"),
                In(s, value=0.0, update=s + a * x, mutable=True),
            ],
            s + a * x,
        )

        g = copy.copy(f)

        assert f.unpack_single == g.unpack_single
        assert f.trust_input == g.trust_input

        assert g.container[x].storage is not f.container[x].storage
        assert g.container[a].storage is not f.container[a].storage
        assert g.container[s].storage is not f.container[s].storage

        # Should not have been copied
        assert g.value[a] is f.value[a]

        # Should have been copied because it is mutable
        assert g.value[s] is not f.value[s]

        # Their contents should be equal, though
        assert np.array_equal(g.value[s], f.value[s])

        # They should be in sync, default value should be copied
        assert np.array_equal(f(2, 1), g(2))

        # They should be in sync, default value should be copied
        assert np.array_equal(f(2, 1), g(2))

        # Put them out of sync
        f(1, 2)

        # They should not be equal anymore
        assert not np.array_equal(f(1, 2), g(1, 2))

    def test_copy_share_memory(self):
        x = fscalar("x")
        # SharedVariable for tests, one of them has update
        y = shared(value=1)
        z = shared(value=2)
        out = tanh((x + y + 2) / (x + z - 0.2)**2)

        # Test for different linkers
        for mode in ("FAST_RUN", "FAST_COMPILE"):
            ori = function([x], [out], mode=mode, updates={z: z + 1})
            cpy = ori.copy(share_memory=True)

            # Test if memories shared
            storage_map_ori = ori.vm.storage_map
            storage_map_cpy = cpy.vm.storage_map
            fgraph_cpy = cpy.maker.fgraph

            # Assert intermediate and Constants storages are shared.
            # and output stoarges are not shared
            i_o_variables = fgraph_cpy.inputs + fgraph_cpy.outputs
            ori_storages = storage_map_ori.values()
            l = [
                val for key, val in storage_map_cpy.items()
                if key not in i_o_variables or isinstance(key, Constant)
            ]
            for storage in l:
                assert any(storage is s for s in ori_storages)

            # Assert storages of SharedVariable without updates are shared
            for (input, _1, _2), here, there in zip(ori.indices,
                                                    ori.input_storage,
                                                    cpy.input_storage):
                assert here.data is there.data

    def test_swap_SharedVariable(self):
        i = iscalar()
        x_list = shared(value=np.random.random((10, )).astype(config.floatX))

        x = scalar("x")
        # SharedVariable for tests, one of them has update
        y = shared(value=1, name="y")
        z = shared(value=2, name="z")
        m = shared(value=0, name="m")

        # SharedVariable to replace
        y_rpl = shared(value=3, name="y_rpl")
        z_rpl = shared(value=4, name="z_rpl")
        swap = {y: y_rpl, z: z_rpl}
        map_SV = {"y_rpl": y_rpl, "z_rpl": z_rpl}

        out = x + y + z + m

        # Test for different linkers
        # for mode in ["FAST_RUN","FAST_COMPILE"]:
        second_time = False
        for mode in ("FAST_RUN", "FAST_COMPILE"):
            ori = function(
                [i],
                [out],
                mode=mode,
                updates=[(z, z + 1), (m, m + 2)],
                givens={x: x_list[i]},
            )
            cpy = ori.copy(swap=swap)

            # run function several times
            ori(1), cpy(1), cpy(2)

            # assert same SharedVariable are update in different function
            if not second_time:
                # m should be updated 3 times
                assert m.get_value() == 6
                # z should be updated once
                assert z.get_value() == 3
                # z_rpl should be updated twice
                assert z_rpl.get_value() == 6
                # y and y_rpl should not be updated
                assert y_rpl.get_value() == 3
                assert y.get_value() == 1
            elif second_time:
                # doule update for sharedvariable
                assert m.get_value() == 12
                assert z.get_value() == 4
                assert z_rpl.get_value() == 8
                assert y_rpl.get_value() == 3

            # test cpy function:
            # 2. SharedVariable is updatable -> values did update(z == 5)
            # 1. sharedvariable is swap ->  Rpl sharedvariables share storage
            names = map_SV.keys()
            for key in cpy.vm.storage_map:
                if key.name in names:
                    assert (map_SV[key.name].container.storage[0] ==
                            cpy.vm.storage_map[key][0])

            second_time = True

    def test_swap_SharedVariable_with_given(self):
        # A special testcase for logistic_sgd.py in Deep Learning Tutorial
        # This test assert that SharedVariable in different function have same storage

        train_x = shared(value=np.random.random((10,
                                                 10)).astype(config.floatX))
        test_x = shared(value=np.random.random((10, 10)).astype(config.floatX))

        train_y = shared(value=np.random.random((10, 1)).astype(config.floatX))
        test_y = shared(value=np.random.random((10, 1)).astype(config.floatX))

        i = iscalar("index")
        x = vector("x")
        y = vector("y")
        # this formular has no sense but for a test
        out = (at_sum(x) - y)**2
        train = function(
            [i],
            out,
            givens={
                x: train_x[i],
                y: train_y[i]
            },
            updates={train_x: train_x + 0.1},
        )

        test_def = function([i], out, givens={x: test_x[i], y: test_y[i]})
        test_cpy = train.copy(swap={
            train_x: test_x,
            train_y: test_y
        },
                              delete_updates=True)

        for in1, in2 in zip(test_def.maker.inputs, test_cpy.maker.inputs):
            assert in1.value is in2.value

    def test_copy_delete_updates(self):
        w = iscalar("w")
        x = fscalar("x")
        # SharedVariable for tests, one of them has update
        y = shared(value=1, name="y")
        z = shared(value=2, name="z")
        out = x + y + z

        # Test for different linkers
        # for mode in ["FAST_RUN","FAST_COMPILE"]:
        # second_time = False
        for mode in ("FAST_RUN", "FAST_COMPILE"):
            ori = function([x], out, mode=mode, updates={z: z * 2})
            cpy = ori.copy(delete_updates=True)

            assert cpy(1) == 4
            assert cpy(1) == 4
            assert cpy(1) == 4

        # Test if unused implicit and explicit inputs from delete_updates
        # are ignored as intended.
        for mode in ("FAST_RUN", "FAST_COMPILE"):
            ori = function([x], x, mode=mode, updates={z: z * 2})
            cpy = ori.copy(delete_updates=True)

            ori = function([x, w], x, mode=mode, updates={z: z + w})
            cpy = ori.copy(delete_updates=True)

    def test_shared_state0(self):
        a = scalar()  # the a is for 'anonymous' (un-named).
        x, s = scalars("xs")

        f = function(
            [
                x,
                In(a, value=1.0, name="a"),
                In(s, value=0.0, update=s + a * x, mutable=True),
            ],
            s + a * x,
        )
        g = function(
            [
                x,
                In(a, value=1.0, name="a"),
                In(s, value=f.container[s], update=s - a * x, mutable=True),
            ],
            s + a * x,
        )

        f(1, 2)
        assert f[s] == 2
        assert g[s] == 2
        g(1, 2)
        assert f[s] == 0
        assert g[s] == 0

    def test_shared_state1(self):
        a = scalar()  # the a is for 'anonymous' (un-named).
        x, s = scalars("xs")

        f = function(
            [
                x,
                In(a, value=1.0, name="a"),
                In(s, value=0.0, update=s + a * x, mutable=True),
            ],
            s + a * x,
        )
        g = function(
            [x, In(a, value=1.0, name="a"),
             In(s, value=f.container[s])], s + a * x)

        f(1, 2)
        assert f[s] == 2
        assert g[s] == 2
        f(1, 2)
        g(1, 2)
        assert f[s] == 4
        assert g[s] == 4

    def test_shared_state2(self):
        a = scalar()  # the a is for 'anonymous' (un-named).
        x, s = scalars("xs")

        f = function(
            [
                x,
                In(a, value=1.0, name="a"),
                In(s, value=0.0, update=s + a * x, mutable=False),
            ],
            s + a * x,
        )
        g = function(
            [x, In(a, value=1.0, name="a"),
             In(s, value=f.container[s])], s + a * x)

        f(1, 2)
        assert f[s] == 2
        assert g[s] == 2
        f(1, 2)
        assert f[s] == 4
        assert g[s] == 4
        g(1, 2)  # has no effect on state
        assert f[s] == 4
        assert g[s] == 4

    def test_shared_state_not_implicit(self):
        # This test is taken from the documentation in
        # doc/topics/function.txt. If it does not pass anymore and yet the
        # behavior is still intended the doc and the test should both be
        # updated accordingly.
        x, s = scalars("xs")
        inc = function([x, In(s, update=(s + x), value=10.0)], [])
        dec = function(
            [x,
             In(s, update=(s - x), value=inc.container[s], implicit=False)],
            [])
        assert dec[s] is inc[s]
        inc[s] = 2
        assert dec[s] == 2
        dec(1)
        assert inc[s] == 1
        dec(1, 0)
        assert inc[s] == -1
        assert dec[s] == -1

    def test_constant_output(self):
        # Test that if the output is a constant, we respect the aesara memory interface
        f = function([], at.constant([4]))
        # print f.maker.fgraph.toposort()
        out = f()
        assert (out == 4).all()
        out[0] = 3
        out2 = f()
        # If the following 2 asserts fail it mean Aesara broke it's memory contract.
        assert out2 is not out
        assert (out2 == 4).all()

        # Test that if the output is a constant and borrow, we respect the aesara memory interface
        f = function([], Out(at.constant([4]), borrow=True))
        # print f.maker.fgraph.toposort()
        out = f()
        assert (out == 4).all()
        out[0] = 3
        out2 = f()

        if isinstance(get_default_mode(), DebugMode):
            # In DebugMode, we don't implement optimization based on borrow on the output.
            assert (out2 == 4).all()
        else:
            assert out2 is out
            assert (out2 == 3).all()

    def test_borrow_input(self):
        # Tests that the contract for io.In is respected. When borrow=False, it should be
        # impossible for outputs to be aliased to the input variables provided by the user,
        # either through a view-map or a destroy map. New tests should be added in the future
        # when borrow=True is implemented.

        a = dmatrix()
        aval = np.random.random((3, 3))

        # when borrow=False, test that a destroy map cannot alias output to input
        f = function([In(a, borrow=False)], Out(a + 1, borrow=True))
        assert np.all(f(aval) == aval + 1)
        assert not np.may_share_memory(aval, f(aval))

        # when borrow=False, test that a viewmap cannot alias output to input
        f = function([In(a, borrow=False)], Out(a[0, :], borrow=True))
        assert np.all(f(aval) == aval[0, :])
        assert not np.may_share_memory(aval, f(aval))

    def test_borrow_output(self):
        a = dmatrix()
        f = function([a], Out(a, borrow=False))
        o = np.ones((3, 3))
        assert o is not f(
            o)  # function no longer permits aliasing outputs to inputs

        f = function([a], Out(a * 4, borrow=False))
        o = np.ones((3, 3))
        four = f(o)
        assert np.all(four == 4)
        f(o + 0.1)  # should not clobber the memory used to store four
        assert np.all(four == 4)

        f = function([a],
                     Out(a * 4, borrow=True),
                     mode=Mode("c|py_nogc", "fast_run"))
        o = np.ones((3, 3))
        four = f(o)
        assert np.all(four == 4)
        f(o + 0.1)  # should clobber the memory used to store four
        if config.cxx:
            assert not np.all(four == 4)
        else:
            # The Elemwise.perform method don't reuse memory
            # as some numpy version don't support that correctly.
            assert np.all(four == 4)

    def test_disconnected_input(self):
        a = scalar("a")
        v = vector("v")
        with pytest.raises(UnusedInputError):
            function([a, v], v * 2)

        function([a, v], v * 2, on_unused_input="ignore")

    def test_masked_input(self):
        m = matrix("m")
        mt = m.T
        mt.name = "m.T"
        with pytest.raises(UnusedInputError):
            function([m, mt], mt * 2)
        function([m, mt], mt * 2, on_unused_input="ignore")

    def test_givens_input_var(self):
        # Ensure error is raised when trying to replace an input variable.

        x = scalar("x")
        y = x * 2
        with pytest.raises(RuntimeError):
            function([x], y, givens={x: x + 1})

    def test_free(self):
        # Make test on free() function

        x = vector("x")
        func = function([x], x + 1)
        func.vm.allow_gc = False
        func([1])

        check_list = []
        for key, val in func.vm.storage_map.items():
            if not isinstance(key, Constant):
                check_list.append(val)
        assert any(val[0] for val in check_list)

        func.free()

        for key, val in func.vm.storage_map.items():
            if not isinstance(key, Constant):
                assert val[0] is None

    def test_default_values(self):
        # Check that default values are restored
        # when an exception occurs in interactive mode.

        a, b = dscalars("a", "b")
        c = a + b
        funct = function([In(a, name="first"),
                          In(b, value=1, name="second")], c)
        x = funct(first=1)
        try:
            funct(second=2)
        except TypeError:
            assert funct(first=1) == x

    def test_check_for_aliased_inputs(self):
        b = np.random.random((5, 4))
        s1 = shared(b)
        s2 = shared(b)
        x1 = vector()

        # Assert cases we should not check for aliased inputs
        for d in [
                dict(outputs=[s1 + 1]),
                dict(outputs=[s1 + 1, s2 + 3]),
                dict(outputs=[s1 + 1], updates=[(s2, s2 + 3)]),
                dict(inputs=[x1], outputs=[x1 + 1], updates=[(s2, s2 + 3)]),
        ]:
            if "inputs" not in d:
                d["inputs"] = []
            f = function(**d)
            assert not f._check_for_aliased_inputs, d

        # Assert cases we should check for aliased inputs
        for d in [
                dict(
                    inputs=[In(x1, borrow=True)],
                    outputs=[x1 + 1],
                    updates=[(s2, s2 + 3)],
                ),
                dict(
                    inputs=[In(x1, borrow=True, mutable=True)],
                    outputs=[x1 + 1],
                    updates=[(s2, s2 + 3)],
                ),
                dict(
                    inputs=[In(x1, mutable=True)],
                    outputs=[x1 + 1],
                    updates=[(s2, s2 + 3)],
                ),
        ]:
            if "inputs" not in d:
                d["inputs"] = []
            f = function(**d)

            assert f._check_for_aliased_inputs, d
예제 #18
0
파일: mode.py 프로젝트: mgorny/aesara
from aesara.link.numba.linker import NumbaLinker
from aesara.link.vm import VMLinker


_logger = logging.getLogger("aesara.compile.mode")


# If a string is passed as the linker argument in the constructor for
# Mode, it will be used as the key to retrieve the real linker in this
# dictionary
predefined_linkers = {
    "py": PerformLinker(),  # Use allow_gc Aesara flag
    "c": CLinker(),  # Don't support gc. so don't check allow_gc
    "c|py": OpWiseCLinker(),  # Use allow_gc Aesara flag
    "c|py_nogc": OpWiseCLinker(allow_gc=False),
    "vm": VMLinker(use_cloop=False),  # Use allow_gc Aesara flag
    "cvm": VMLinker(use_cloop=True),  # Use allow_gc Aesara flag
    "vm_nogc": VMLinker(allow_gc=False, use_cloop=False),
    "cvm_nogc": VMLinker(allow_gc=False, use_cloop=True),
    "jax": JAXLinker(),
    "numba": NumbaLinker(),
}


def register_linker(name, linker):
    """Add a `Linker` which can be referred to by `name` in `Mode`."""
    if name in predefined_linkers:
        raise ValueError(f"Linker name already taken: {name}")
    predefined_linkers[name] = linker

예제 #19
0
        print(
            f"{name} takes {1000 * (t_b - t_a) / (steps_b - steps_a):f} s/Kop")

    time_linker("c|py", OpWiseCLinker)
    time_linker("vmLinker", VMLinker)
    time_linker("vmLinker_nogc", lambda: VMLinker(allow_gc=False))
    if config.cxx:
        time_linker("vmLinker_CLOOP",
                    lambda: VMLinker(allow_gc=False, use_cloop=True))
    time_numpy()


@pytest.mark.parametrize(
    "linker",
    [
        VMLinker(),
        VMLinker(allow_gc=False),
        VMLinker(allow_gc=False, use_cloop=True),
    ],
)
def test_speed_lazy(linker):
    # TODO FIXME: This isn't a real test.

    def build_graph(x, depth=5):
        z = x
        for d in range(depth):
            z = ifelse(z[0] > 0, -z, z)
        return z

    steps_a = 10
    steps_b = 100