def test_opwiseclinker_constant(): x, y, z = inputs() x = Constant(tdouble, 7.2, name="x") e = add(mul(x, y), mul(y, z)) lnk = OpWiseCLinker().accept(Env([y, z], [e])) fn = lnk.make_function() res = fn(1.5, 3.0) assert res == 15.3
def test_c_fail_error(): x, y, z = inputs() x = Constant(tdouble, 7.2, name="x") e = add_fail(mul(x, y), mul(y, z)) lnk = OpWiseCLinker().accept(Env([y, z], [e])) fn = lnk.make_function() with pytest.raises(RuntimeError): fn(1.5, 3.0)
def test_opwiseclinker_straightforward(): x, y, z = inputs() e = add(mul(add(x, y), div(x, y)), bad_sub(bad_sub(x, y), z)) lnk = OpWiseCLinker().accept(Env([x, y, z], [e])) fn = lnk.make_function() if theano.config.cxx: assert fn(2.0, 2.0, 2.0) == 2.0 else: # The python version of bad_sub always return -10. assert fn(2.0, 2.0, 2.0) == -6
def __init__(self, pre_func=None, post_func=None, optimizer="default", linker=None): self.pre_func = pre_func self.post_func = post_func wrap_linker = WrapLinkerMany([OpWiseCLinker()], [self.eval]) if optimizer == "default": optimizer = config.optimizer if linker is not None and not isinstance(linker.mode, MonitorMode): raise Exception( "MonitorMode can only use its own linker! You " "should not provide one.", linker, ) super().__init__(wrap_linker, optimizer=optimizer)
def test_sort_schedule_fn(): import theano from theano.gof.sched import make_depends, sort_schedule_fn x = theano.tensor.matrix("x") y = theano.tensor.dot(x[:5] * 2, x.T + 1).T def str_cmp(a, b): return cmp(str(a), str(b)) # lexicographical sort linker = OpWiseCLinker(schedule=sort_schedule_fn(str_cmp)) mode = theano.Mode(linker=linker) f = theano.function((x, ), (y, ), mode=mode) nodes = f.maker.linker.make_all()[-1] depends = make_depends() for a, b in zip(nodes[:-1], nodes[1:]): if not depends((b, a)): assert str(a) < str(b)
def test_duallinker_mismatch(): x, y, z = inputs() # bad_sub is correct in C but erroneous in Python e = bad_sub(mul(x, y), mul(y, z)) g = Env([x, y, z], [e]) lnk = DualLinker(checker=_my_checker).accept(g) fn = lnk.make_function() # good assert CLinker().accept(g).make_function()(1.0, 2.0, 3.0) == -4.0 # good assert OpWiseCLinker().accept(g).make_function()(1.0, 2.0, 3.0) == -4.0 # (purposely) wrong assert PerformLinker().accept(g).make_function()(1.0, 2.0, 3.0) == -10.0 with pytest.raises(MyExc): # this runs OpWiseCLinker and PerformLinker in parallel and feeds # variables of matching operations to _my_checker to verify that they # are the same. fn(1.0, 2.0, 3.0)
from theano import config, gof from theano.compile.function.types import Supervisor from theano.link.basic import PerformLinker from theano.link.c.basic import CLinker, OpWiseCLinker from theano.link.jax import JAXLinker from theano.link.vm import VMLinker _logger = logging.getLogger("theano.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 Theano flag "c": CLinker(), # Don't support gc. so don't check allow_gc "c|py": OpWiseCLinker(), # Use allow_gc Theano flag "c|py_nogc": OpWiseCLinker(allow_gc=False), "vm": VMLinker(use_cloop=False), # Use allow_gc Theano flag "cvm": VMLinker(use_cloop=True), # Use allow_gc Theano flag "vm_nogc": VMLinker(allow_gc=False, use_cloop=False), "cvm_nogc": VMLinker(allow_gc=False, use_cloop=True), "jax": JAXLinker(), } 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
import theano from theano.configdefaults import config from theano.gof.sched import sort_schedule_fn from theano.link.c.basic import OpWiseCLinker from theano.tensor.io import ( MPISend, MPISendWait, mpi_cmps, mpi_enabled, mpi_send_wait_cmp, recv, send, ) mpi_scheduler = sort_schedule_fn(*mpi_cmps) mpi_linker = OpWiseCLinker(schedule=mpi_scheduler) mpi_mode = theano.Mode(linker=mpi_linker) @config.change_flags(compute_test_value="off") def test_recv(): x = recv((10, 10), "float64", 0, 11) assert x.dtype == "float64" assert x.broadcastable == (False, False) recvnode = x.owner.inputs[0].owner assert recvnode.op.source == 0 assert recvnode.op.tag == 11 def test_send():
def test_gc_never_pickles_temporaries(): x = tt.dvector() r = x for i in range(2): # TODO: 30 causes like LONG compilation due to MERGE r = r + r / 10 optimizer = None optimizer = "fast_run" for f_linker, g_linker in [ (PerformLinker(allow_gc=True), PerformLinker(allow_gc=False)), (OpWiseCLinker(allow_gc=True), OpWiseCLinker(allow_gc=False)), ]: # f_linker has garbage collection # g_linker has no garbage collection f = theano.function([x], r, mode=theano.Mode(optimizer=optimizer, linker=f_linker)) g = theano.function([x], r, mode=theano.Mode(optimizer=optimizer, linker=g_linker)) pre_f = pickle.dumps(f) # pre_g = pickle.dumps(g) len_pre_f = len(pre_f) # len_pre_g = len(pre_g) # We can't compare the content or the length of the string # between f and g. 2 reason, we store some timming information # in float. They won't be the same each time. Different float # can have different length when printed. def a(fn): return len(pickle.dumps(fn.maker)) assert a(f) == a(f) # some sanity checks on the pickling mechanism assert a(g) == a(g) # some sanity checks on the pickling mechanism def b(fn): return len( pickle.dumps( theano.compile.function.types._pickle_Function(fn))) assert b(f) == b(f) # some sanity checks on the pickling mechanism def c(fn): return len(pickle.dumps(fn)) assert c(f) == c(f) # some sanity checks on the pickling mechanism assert c(g) == c(g) # some sanity checks on the pickling mechanism # now run the function once to create temporaries within the no-gc # linker f(np.ones(100, dtype="float64")) g(np.ones(100, dtype="float64")) # serialize the functions again post_f = pickle.dumps(f) post_g = pickle.dumps(g) len_post_f = len(post_f) len_post_g = len(post_g) # assert that f() didn't cause the function to grow # allow_gc should leave the function un-changed by calling assert len_pre_f == len_post_f, (len_pre_f, len_post_f) # assert that g() didn't cause g to grow because temporaries # that weren't collected shouldn't be pickled anyway # Allow for a couple of bytes of difference, since timing info, # for instance, can be represented as text of varying size. assert abs(len_post_f - len_post_g) < 256, (f_linker, len_post_f, len_post_g)