Ejemplo n.º 1
0
 def test_skiphole(self):
     x,y,z = inputs()
     a = add(x,y)
     r = raise_err(a)
     e = add(r,a)
     fn = perform_linker(Env(*graph.clone([x, y,r], [e]))).make_function()
     assert fn(1.0,2.0,4.5) == 7.5
Ejemplo n.º 2
0
 def test_input_dependency0(self):
     x, y, z = inputs()
     a, d = add(x, y), div(x, y)
     e = mul(a, d)
     fn = perform_linker(FunctionGraph(*graph.clone([x, y, a],
                                                    [e]))).make_function()
     assert fn(1.0, 2.0, 9.0) == 4.5
Ejemplo n.º 3
0
 def test_skiphole(self):
     x, y, z = inputs()
     a = add(x, y)
     r = raise_err(a)
     e = add(r, a)
     fn = perform_linker(FunctionGraph(*graph.clone([x, y, r], [e]))).make_function()
     assert fn(1.0, 2.0, 4.5) == 7.5
Ejemplo n.º 4
0
 def test_input_dependency0(self):
     x, y, z = inputs()
     a, d = add(x, y), div(x, y)
     e = mul(a, d)
     fn = perform_linker(
         FunctionGraph(*graph.clone([x, y, a], [e]))).make_function()
     assert fn(1.0, 2.0, 9.0) == 4.5
Ejemplo n.º 5
0
    def __init__(self, inputs, outputs, features=None, clone=True):
        """
        Create an FunctionGraph which operates on the subgraph bound by the inputs and
        outputs sets.

        This class keeps a pointer to the inputs and outputs, and also modifies
        them.

        #TODO: document what variables are[not] set in the FunctionGraph when a feature
        is added via the constructor.  How constructed is the FunctionGraph?

        :param clone: If true, we will clone the graph. This is
        useful to remove the constant cache problem.

        """
        if clone:
            inputs, outputs = graph.clone(inputs, outputs)

        self.execute_callbacks_time = 0
        self.execute_callbacks_times = {}

        if features is None:
            features = []

        # XXX: Unless I'm missing something (but there's no documentation,
        # so I probably am) this should be a set.
        self._features = []

        # All apply nodes in the subgraph defined by inputs and
        # outputs are cached in this field
        self.apply_nodes = set()

        # Ditto for variable nodes
        self.variables = set()

        self.inputs = list(inputs)
        self.outputs = outputs

        for f in features:
            self.attach_feature(f)
        self.attach_feature(toolbox.ReplaceValidate())

        for input in self.inputs:
            if input.owner is not None:
                raise ValueError("One of the provided inputs is the output of"
                                 "an already existing node. "
                                 "If that is okay, either discard that "
                                 "input's owner or use graph.clone.")
            self.__setup_r__(input)
            self.variables.add(input)

        self.__import_r__(outputs, reason="init")
        for i, output in enumerate(outputs):
            output.clients.append(('output', i))

        self.node_locks = {}
        self.variable_locks = {}
        self.profile = None
Ejemplo n.º 6
0
 def test_not_destructive(self):
     # Checks that manipulating a cloned graph leaves the original unchanged.
     r1, r2, r5 = MyVariable(1), MyVariable(2), MyVariable(5)
     node = MyOp.make_node(MyOp.make_node(r1, r2).outputs[0], r5)
     _, new = clone([r1, r2, r5], node.outputs, False)
     new_node = new[0].owner
     new_node.inputs = MyVariable(7), MyVariable(8)
     assert self.str(inputs(new_node.outputs), new_node.outputs) == ["MyOp(R7, R8)"]
     assert self.str(inputs(node.outputs), node.outputs) == ["MyOp(MyOp(R1, R2), R5)"]
Ejemplo n.º 7
0
 def test_copy(self):
     r1, r2, r5 = MyVariable(1), MyVariable(2), MyVariable(5)
     node = MyOp.make_node(r1, r2)
     node2 = MyOp.make_node(node.outputs[0], r5)
     _, new = clone([r1, r2, r5], node2.outputs, False)
     assert node2.outputs[0].type == new[0].type and node2.outputs[0] is not new[0] # the new output is like the old one but not the same object
     assert node2 is not new[0].owner # the new output has a new owner
     assert new[0].owner.inputs[1] is r5 # the inputs are not copied
     assert new[0].owner.inputs[0].type == node.outputs[0].type and new[0].owner.inputs[0] is not node.outputs[0] # check that we copied deeper too
Ejemplo n.º 8
0
 def test_not_destructive(self):
     # Checks that manipulating a cloned graph leaves the original unchanged.
     r1, r2, r5 = MyVariable(1), MyVariable(2), MyVariable(5)
     node = MyOp.make_node(MyOp.make_node(r1, r2).outputs[0], r5)
     _, new = clone([r1, r2, r5], node.outputs, False)
     new_node = new[0].owner
     new_node.inputs = MyVariable(7), MyVariable(8)
     assert self.str(inputs(new_node.outputs), new_node.outputs) == ["MyOp(R7, R8)"]
     assert self.str(inputs(node.outputs), node.outputs) == ["MyOp(MyOp(R1, R2), R5)"]
Ejemplo n.º 9
0
 def test_copy(self):
     r1, r2, r5 = MyVariable(1), MyVariable(2), MyVariable(5)
     node = MyOp.make_node(r1, r2)
     node2 = MyOp.make_node(node.outputs[0], r5)
     _, new = clone([r1, r2, r5], node2.outputs, False)
     assert node2.outputs[0].type == new[0].type and node2.outputs[0] is not new[0] # the new output is like the old one but not the same object
     assert node2 is not new[0].owner # the new output has a new owner
     assert new[0].owner.inputs[1] is r5 # the inputs are not copied
     assert new[0].owner.inputs[0].type == node.outputs[0].type and new[0].owner.inputs[0] is not node.outputs[0] # check that we copied deeper too
Ejemplo n.º 10
0
    def test_constant(self):
        r1, r2, r5 = MyVariable(1), MyVariable(2), MyVariable(5)
        node = MyOp.make_node(MyOp.make_node(r1, r2).outputs[0], r5)
        _, new = clone([r1, r2, r5], node.outputs, False)
        new_node = new[0].owner
        new_node.inputs = MyVariable(7), MyVariable(8)
        c1 = tensor.constant(1.5)

        i, o = clone([c1], [c1])
        assert i[0] is not c1 and o[0] is not c1

        i, o = clone([c1], [c1], False)
        assert i[0] is c1 and o[0] is c1

        i, o = clone([c1], [c1], True, False)
        assert i[0] is not c1 and o[0] is not c1

        i, o = clone([c1], [c1], False, True)
        assert i[0] is c1 and o[0] is c1
Ejemplo n.º 11
0
    def test_constant(self):
        r1, r2, r5 = MyVariable(1), MyVariable(2), MyVariable(5)
        node = MyOp.make_node(MyOp.make_node(r1, r2).outputs[0], r5)
        _, new = clone([r1, r2, r5], node.outputs, False)
        new_node = new[0].owner
        new_node.inputs = [MyVariable(7), MyVariable(8)]
        c1 = tensor.constant(1.5)

        i, o = clone([c1], [c1])
        assert i[0] is not c1 and o[0] is not c1

        i, o = clone([c1], [c1], False)
        assert i[0] is c1 and o[0] is c1

        i, o = clone([c1], [c1], True, False)
        assert i[0] is not c1 and o[0] is not c1

        i, o = clone([c1], [c1], False, True)
        assert i[0] is c1 and o[0] is c1
Ejemplo n.º 12
0
def test_long_destroyers_loop():
    x, y, z = inputs()
    e = dot(dot(add_in_place(x,y), add_in_place(y,z)), add(z,x))
    g = Env([x,y,z], [e])
    consistent(g)
    OpSubOptimizer(add, add_in_place).optimize(g)
    consistent(g)
    assert str(g) != "[Dot(Dot(AddInPlace(x, y), AddInPlace(y, z)), AddInPlace(z, x))]" # we don't want to see that!
    e2 = dot(dot(add_in_place(x,y), add_in_place(y,z)), add_in_place(z,x))
    try:
        g2 = Env(*graph.clone([x,y,z], [e2]))
        raise Exception("Shouldn't have reached this point.")
    except InconsistencyError:
        pass
Ejemplo n.º 13
0
def test_long_destroyers_loop():
    x, y, z = inputs()
    e = dot(dot(add_in_place(x, y), add_in_place(y, z)), add(z, x))
    g = Env([x, y, z], [e])
    assert g.consistent()
    OpSubOptimizer(add, add_in_place).optimize(g)
    assert g.consistent()
    # we don't want to see that!
    assert str(
        g
    ) != "[Dot(Dot(AddInPlace(x, y), AddInPlace(y, z)), AddInPlace(z, x))]"
    e2 = dot(dot(add_in_place(x, y), add_in_place(y, z)), add_in_place(z, x))
    with pytest.raises(InconsistencyError):
        Env(*graph.clone([x, y, z], [e2]))
Ejemplo n.º 14
0
    def __init__(self, inputs, outputs, features=None, clone=True):

        if clone:
            inputs, outputs = graph.clone(inputs, outputs)

        self.execute_callbacks_time = 0
        self.execute_callbacks_times = {}

        if features is None:
            features = []

        # XXX: Unless I'm missing something (but there's no documentation,
        # so I probably am) this should be a set.
        self._features = []

        # All apply nodes in the subgraph defined by inputs and
        # outputs are cached in this field
        self.apply_nodes = set()

        # Ditto for variable nodes.
        # It must contain all fgraph.inputs and all apply_nodes
        # outputs even if they aren't used in the graph.
        self.variables = set()

        self.inputs = list(inputs)
        self.outputs = outputs

        for f in features:
            self.attach_feature(f)
        self.attach_feature(toolbox.ReplaceValidate())

        for input in self.inputs:
            if input.owner is not None:
                raise ValueError("One of the provided inputs is the output of"
                                 "an already existing node. "
                                 "If that is okay, either discard that "
                                 "input's owner or use graph.clone.")
            self.__setup_r__(input)
            self.variables.add(input)

        for output in outputs:
            self.__import_r__(output, reason="init")
        for i, output in enumerate(outputs):
            output.clients.append(('output', i))

        self.node_locks = {}
        self.variable_locks = {}
        self.profile = None
Ejemplo n.º 15
0
Archivo: fg.py Proyecto: zhqi77/Theano
    def __init__(self, inputs, outputs, features=None, clone=True):

        if clone:
            inputs, outputs = graph.clone(inputs, outputs)

        self.execute_callbacks_time = 0
        self.execute_callbacks_times = {}

        if features is None:
            features = []

        # XXX: Unless I'm missing something (but there's no documentation,
        # so I probably am) this should be a set.
        self._features = []

        # All apply nodes in the subgraph defined by inputs and
        # outputs are cached in this field
        self.apply_nodes = set()

        # Ditto for variable nodes.
        # It must contain all fgraph.inputs and all apply_nodes
        # outputs even if they aren't used in the graph.
        self.variables = set()

        self.inputs = list(inputs)
        self.outputs = outputs

        for f in features:
            self.attach_feature(f)
        self.attach_feature(toolbox.ReplaceValidate())

        for input in self.inputs:
            if input.owner is not None:
                raise ValueError("One of the provided inputs is the output of"
                                 "an already existing node. "
                                 "If that is okay, either discard that "
                                 "input's owner or use graph.clone.")
            self.__setup_r__(input)
            self.variables.add(input)

        for output in outputs:
            self.__import_r__(output, reason="init")
        for i, output in enumerate(outputs):
            output.clients.append(('output', i))

        self.node_locks = {}
        self.variable_locks = {}
        self.profile = None
Ejemplo n.º 16
0
 def test_accurate(self):
     r1, r2 = MyVariable(1), MyVariable(2)
     node = MyOp.make_node(r1, r2)
     _, new = clone([r1, r2], node.outputs, False)
     assert self.str([r1, r2], new) == ["MyOp(R1, R2)"]
Ejemplo n.º 17
0
    def __init__(self,
                 inputs,
                 outputs,
                 features=None,
                 clone=True,
                 update_mapping=None):
        """
        Create an FunctionGraph which operates on the subgraph bound by the
        inputs and outputs sets.

        Parameters
        ----------
        inputs : list of variables
            Inputs nodes of the graph, usually declared by the user
        outputs : list of variables
            Outputs nodes of the graph.
        clone : boolean
            If true, we will clone the graph. This is useful to remove the
            constant cache problem.
        update_mapping : dictionary
            Mapping between the inputs with updates and the outputs
            corresponding to their updates.
        """

        if clone:
            inputs, outputs = graph.clone(inputs, outputs)

        self.execute_callbacks_time = 0
        self.execute_callbacks_times = {}

        if features is None:
            features = []

        # XXX: Unless I'm missing something (but there's no documentation,
        # so I probably am) this should be a set.
        self._features = []

        # All apply nodes in the subgraph defined by inputs and
        # outputs are cached in this field
        self.apply_nodes = set()

        # Ditto for variable nodes.
        # It must contain all fgraph.inputs and all apply_nodes
        # outputs even if they aren't used in the graph.
        self.variables = set()

        self.inputs = list(inputs)
        self.outputs = outputs

        for f in features:
            self.attach_feature(f)
        self.attach_feature(toolbox.ReplaceValidate())

        for input in self.inputs:
            if input.owner is not None:
                raise ValueError("One of the provided inputs is the output of"
                                 "an already existing node. "
                                 "If that is okay, either discard that "
                                 "input's owner or use graph.clone.")
            self.__setup_r__(input)
            self.variables.add(input)

        for output in outputs:
            self.__import_r__(output, reason="init")
        for i, output in enumerate(outputs):
            output.clients.append(("output", i))

        self.profile = None
        self.update_mapping = update_mapping
Ejemplo n.º 18
0
    def make_thunk(self, node, storage_map, compute_map, no_recycling):
        """
        :param node: something previously returned by self.make_node

        :param storage_map: dict variable -> one-element-list where a computed
                value for this variable may be found.

        :param compute_map: dict variable -> one-element-list where a boolean
                value will be found.  The boolean indicates whether the
                variable's storage_map container contains a valid value (True)
                or if it has not been computed yet (False).

        :param no_recycling: list of variables for which it is forbidden to
                reuse memory allocated by a previous call.

        :note: If the thunk consults the storage_map on every call, it is safe
            for it to ignore the no_recycling argument, because elements of the
            no_recycling list will have a value of None in the storage map.  If
            the thunk can potentially cache return values (like CLinker does),
            then it must not do so for variables in the no_recycling list.
        """
        logger = logging.getLogger('theano.gof.op.Op')

        node_input_storage = [storage_map[r] for r in node.inputs]
        node_output_storage = [storage_map[r] for r in node.outputs]
        node_input_compute = [compute_map[r] for r in node.inputs]
        node_output_compute = [compute_map[r] for r in node.outputs]
        #logger.debug('Compiling node %i of graph' % node_idx)
        if self._op_use_c_code:
            try:
                e = FunctionGraph(*graph.clone(node.inputs, node.outputs))

                e_no_recycling = [new_o
                        for (new_o, old_o) in zip(e.outputs, node.outputs)
                        if old_o in no_recycling]
                cl = theano.gof.cc.CLinker().accept(e,
                        no_recycling=e_no_recycling)

                logger.debug('Trying CLinker.make_thunk')
                outputs = cl.make_thunk(input_storage=node_input_storage,
                                        output_storage=node_output_storage)
                fill_storage, node_input_filters, node_output_filters = outputs

                def rval():
                    fill_storage()
                    for o in node.outputs:
                        compute_map[o][0] = True

                rval.cthunk = fill_storage.cthunk
                rval.inputs = node_input_storage
                rval.outputs = node_output_storage
                rval.lazy = False
                return rval
                # the next line does nothing, but pyflakes is too
                # stupid to realize the def rval below is not a
                # redefinition unless I include this
                del rval
            except (NotImplementedError, utils.MethodNotDefined):
                logger.debug('Falling back on perform')

        # condition: either there was no c_code, or it failed

        p = node.op.perform
        # default arguments are stored in the closure of `rval`

        def rval(p=p, i=node_input_storage, o=node_output_storage, n=node):
            r = p(n, [x[0] for x in i], o)
            for o in node.outputs:
                compute_map[o][0] = True
            return r

        rval.inputs = node_input_storage
        rval.outputs = node_output_storage
        rval.perform = p
        rval.lazy = False
        return rval
Ejemplo n.º 19
0
    def __init__(self, inputs, outputs, features=None, clone=True,
                 update_mapping=None):
        """
        Create an FunctionGraph which operates on the subgraph bound by the
        inputs and outputs sets.

        Parameters
        ----------
        inputs : list of variables
            Inputs nodes of the graph, usually declared by the user
        outputs : list of variables
            Outputs nodes of the graph.
        clone : boolean
            If true, we will clone the graph. This is useful to remove the
            constant cache problem.
        update_mapping : dictionnary
            Mapping between the inputs with updates and the outputs
            corresponding to their updates.
        """

        if clone:
            inputs, outputs = graph.clone(inputs, outputs)

        self.execute_callbacks_time = 0
        self.execute_callbacks_times = {}

        if features is None:
            features = []

        # XXX: Unless I'm missing something (but there's no documentation,
        # so I probably am) this should be a set.
        self._features = []

        # All apply nodes in the subgraph defined by inputs and
        # outputs are cached in this field
        self.apply_nodes = set()

        # Ditto for variable nodes.
        # It must contain all fgraph.inputs and all apply_nodes
        # outputs even if they aren't used in the graph.
        self.variables = set()

        self.inputs = list(inputs)
        self.outputs = outputs

        for f in features:
            self.attach_feature(f)
        self.attach_feature(toolbox.ReplaceValidate())

        for input in self.inputs:
            if input.owner is not None:
                raise ValueError("One of the provided inputs is the output of"
                                 "an already existing node. "
                                 "If that is okay, either discard that "
                                 "input's owner or use graph.clone.")
            self.__setup_r__(input)
            self.variables.add(input)

        for output in outputs:
            self.__import_r__(output, reason="init")
        for i, output in enumerate(outputs):
            output.clients.append(('output', i))

        self.profile = None
        self.update_mapping = update_mapping
Ejemplo n.º 20
0
    def make_thunk(self, node, storage_map, compute_map, no_recycling):
        """
        :param node: something previously returned by self.make_node

        :param storage_map: dict variable -> one-element-list where a computed
                value for this variable may be found.

        :param compute_map: dict variable -> one-element-list where a boolean
                value will be found.  The boolean indicates whether the
                variable's storage_map container contains a valid value (True)
                or if it has not been computed yet (False).

        :param no_recycling: list of variables for which it is forbidden to
                reuse memory allocated by a previous call.

        :note: If the thunk consults the storage_map on every call, it is safe
            for it to ignore the no_recycling argument, because elements of the
            no_recycling list will have a value of None in the storage map.  If
            the thunk can potentially cache return values (like CLinker does),
            then it must not do so for variables in the no_recycling list.
        """
        logger = logging.getLogger('theano.gof.op.Op')

        node_input_storage = [storage_map[r] for r in node.inputs]
        node_output_storage = [storage_map[r] for r in node.outputs]
        node_input_compute = [compute_map[r] for r in node.inputs]
        node_output_compute = [compute_map[r] for r in node.outputs]
        #logger.debug('Compiling node %i of graph' % node_idx)
        if self._op_use_c_code:
            try:
                e = FunctionGraph(*graph.clone(node.inputs, node.outputs))

                e_no_recycling = [
                    new_o for (new_o, old_o) in zip(e.outputs, node.outputs)
                    if old_o in no_recycling
                ]
                cl = theano.gof.cc.CLinker().accept(
                    e, no_recycling=e_no_recycling)

                logger.debug('Trying CLinker.make_thunk')
                outputs = cl.make_thunk(input_storage=node_input_storage,
                                        output_storage=node_output_storage)
                fill_storage, node_input_filters, node_output_filters = outputs

                def rval():
                    fill_storage()
                    for o in node.outputs:
                        compute_map[o][0] = True

                rval.cthunk = fill_storage.cthunk
                rval.inputs = node_input_storage
                rval.outputs = node_output_storage
                rval.lazy = False
                return rval
                # the next line does nothing, but pyflakes is too
                # stupid to realize the def rval below is not a
                # redefinition unless I include this
                del rval
            except (NotImplementedError, utils.MethodNotDefined):
                logger.debug('Falling back on perform')

        # condition: either there was no c_code, or it failed

        p = node.op.perform

        # default arguments are stored in the closure of `rval`

        def rval(p=p, i=node_input_storage, o=node_output_storage, n=node):
            r = p(n, [x[0] for x in i], o)
            for o in node.outputs:
                compute_map[o][0] = True
            return r

        rval.inputs = node_input_storage
        rval.outputs = node_output_storage
        rval.perform = p
        rval.lazy = False
        return rval
Ejemplo n.º 21
0
 def test_accurate(self):
     r1, r2 = MyVariable(1), MyVariable(2)
     node = MyOp.make_node(r1, r2)
     _, new = clone([r1, r2], node.outputs, False)
     assert self.str([r1, r2], new) == ["MyOp(R1, R2)"]