def register_opt2(tracks, *tags, **kwargs):
'''
Decorator for the new GraphToGPU optimizer.
Takes an extra parameter(Op) compared to register_opt decorator.
Parameters
----------
tracks : List of Op class Or Op instance or None
The Node's Op to which optimization is being applied.
tags : String
The optimization tag to which the optimizer will be registered.
'''
def f(local_opt):
name = (kwargs and kwargs.pop('name')) or local_opt.__name__
opt = theano.gof.local_optimizer(tracks)(local_opt)
gpu_optimizer2.register(name, opt, 'fast_run', 'gpuarray', *tags)
return local_opt
return f
python类gof()的实例源码
def make_node(self, a, val, offset):
a = tensor.as_tensor_variable(a)
val = tensor.as_tensor_variable(val)
offset = tensor.as_tensor_variable(offset)
if a.ndim != 2:
raise TypeError('%s: first parameter must have exactly'
' two dimensions' % self.__class__.__name__)
elif val.ndim != 0:
raise TypeError('%s: second parameter must be a scalar'
% self.__class__.__name__)
elif offset.ndim != 0:
raise TypeError('%s: third parameter must be a scalar'
% self.__class__.__name__)
val = tensor.cast(val, dtype=scalar.upcast(a.dtype, val.dtype))
if val.dtype != a.dtype:
raise TypeError('%s: type of second parameter must be the same'
' as the first\'s' % self.__class__.__name__)
elif offset.dtype[:3] != 'int':
raise TypeError('%s: type of third parameter must be as integer'
' use theano.tensor.cast( input, \'int32/int64\')'
% self.__class__.__name__)
return gof.Apply(self, [a, val, offset], [a.type()])
def test_canonicalize_nan(self):
"""
Regression test for bug in canonicalization of NaN values.
This bug caused an infinite loop which was caught by the equilibrium
optimizer, resulting in an error log message.
"""
sio = StringIO()
handler = logging.StreamHandler(sio)
handler.setLevel(logging.ERROR)
logging.getLogger('theano.gof.opt').addHandler(handler)
try:
x = vector()
f = theano.function([x], x + numpy.nan)
finally:
logging.getLogger('theano.gof.opt').removeHandler(handler)
# Ideally this test would only catch the maxed out equilibrium
# optimizer error message, but to be safe in case this message
# is modified in the future, we assert that there is no error
# at all.
assert not sio.getvalue()
def test_local_reshape_dimshuffle():
reshape_dimshuffle = out2in(local_dimshuffle_alloc)
x = tensor.vector('x')
out = tensor.alloc(x, 3, 2).dimshuffle('x', 'x', 0, 1)
g = FunctionGraph([x], [out])
reshape_dimshuffle(g)
l=theano.gof.PerformLinker()
l.accept(g)
f=l.make_function()
assert f([3, 4]).ndim == 4
topo = g.toposort()
assert any([not isinstance(x, DimShuffle) for x in topo])
def make_node(self, x, axis, splits):
"""WRITEME"""
x = as_tensor_variable(x)
axis = as_tensor_variable(axis)
splits = as_tensor_variable(splits)
if splits.type not in int_vector_types:
raise TypeError('splits must have type tensor.lvector',
splits.type)
if axis.type not in int_types:
raise TypeError('axis must have type lscalar', axis.type)
# # The following lines are necessary if we allow splits of zero
# if isinstance(axis, gof.Constant):
# x = unbroadcast(x, int(axis.data))
# else:
# x = unbroadcast(x, *range(x.type.ndim))
inputs = [x, axis, splits]
outputs = [x.type() for i in xrange(self.len_splits)]
return Apply(self, inputs, outputs)
def make_node(self, x):
t_x = as_tensor_variable(x)
if self.outdim < 1 or (x.ndim and self.outdim > x.ndim):
raise ValueError('invalid output ndimensions (%i) for tensor of '
'rank %i' % (self.outdim, t_x.ndim))
# Infer the broadcastable pattern of the output. For every dimension
# unaffected by the flatten, the broadcast flag should be unchanged.
# For the dimension resulting from the collapse of other dimensions,
# it should be broadcastable iff all the collapsed dimensions were
# broadcastable.
bcast_kept_dims = x.broadcastable[:self.outdim - 1]
bcast_new_dim = python_all(x.broadcastable[self.outdim - 1:])
broadcastable = bcast_kept_dims + (bcast_new_dim,)
return gof.Apply(self, [t_x], [tensor(x.type.dtype,
broadcastable)])
def test_free(self):
"""
Make test on free() function
"""
x = T.vector('x')
func = function([x], x + 1)
func.fn.allow_gc = False
func([1])
check_list = []
for key, val in iteritems(func.fn.storage_map):
if not isinstance(key, theano.gof.Constant):
check_list.append(val)
assert any([val[0] for val in check_list])
func.free()
for key, val in iteritems(func.fn.storage_map):
if not isinstance(key, theano.gof.Constant):
assert (val[0] is None)
def accept(self, fgraph, no_recycling=None, profile=None):
"""
Parameters
----------
fgraph : gof.FunctionGraph
The fgraph which we will link.
no_recycling : a list of Variables that belong to fgraph.
If a Variable is in no_recycling, L{WrapLinker} will clear
the output storage associated to it (for each linker in linkers)
during the computation to avoid reusing it.
"""
if no_recycling is None:
no_recycling = []
if self.fgraph is not None and self.fgraph is not fgraph:
return type(self)(self.linkers, self.wrapper).accept(fgraph,
no_recycling)
self.fgraph = fgraph
self.no_recycling = no_recycling
self.linkers = [linker.accept(fgraph, no_recycling)
for linker in self.linkers]
return self
def test_vm_gc():
"""This already caused a bug in the trunk of Theano.
The bug was introduced in the trunk on July 5th, 2012 and fixed on
July 30th.
"""
x = theano.tensor.vector()
p = RunOnce()(x)
mode = theano.Mode(linker=theano.gof.vm.VM_Linker(lazy=True))
f = theano.function([theano.In(x, mutable=True)], [p + 1, p + 2],
mode=mode)
f([1, 2, 3])
p = RunOnce()(x)
pp = p + p
f = theano.function([x], [pp + pp],
mode=mode)
f([1, 2, 3])
def test_sort_schedule_fn():
import theano
from theano.gof.sched import sort_schedule_fn, make_depends
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 = theano.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_not(self):
x, y, z = ints('xyz')
fn = gof.DualLinker().accept(FunctionGraph([x, y], [invert(x)])).make_function()
for a, b in ((0, 1), (0, 0), (1, 0), (1, 1)):
self.assertTrue(fn(a, b) == ~a, (a,))
x, y, z = ints('xyz')
fn = gof.DualLinker().accept(FunctionGraph([x, y], [~x])).make_function()
for a, b in ((0, 1), (0, 0), (1, 0), (1, 1)):
self.assertTrue(fn(a, b) == ~a, (a,))
# This class does not inherit from unittest.TestCase, because it would
# interfere with the "yield" mechanism that automatically generates test, see
# http://stackoverflow.com/questions/6689537/nose-test-generators-inside-class
# Therefore, it needs to be named "test_..." or "Test_...", so nose can pick
# it up by name, otherwise the tests would not be executed.
def as_scalar(x, name=None):
from ..tensor import TensorType, scalar_from_tensor
if isinstance(x, gof.Apply):
if len(x.outputs) != 1:
raise ValueError("It is ambiguous which output of a multi-output"
" Op has to be fetched.", x)
else:
x = x.outputs[0]
if isinstance(x, Variable):
if isinstance(x.type, Scalar):
return x
elif isinstance(x.type, TensorType) and x.ndim == 0:
return scalar_from_tensor(x)
else:
raise TypeError("Variable type field must be a Scalar.", x, x.type)
try:
return constant(x)
except TypeError:
raise TypeError("Cannot convert %s to Scalar" % x, type(x))
def c_code_contiguous(self, node, name, inputs, outputs, sub):
(x,) = inputs
(z,) = outputs
if (not theano.config.lib.amdlibm or
# We compare the dtype AND the broadcast flag
# as this function do not broadcast
node.inputs[0].type != node.outputs[0].type):
raise theano.gof.utils.MethodNotDefined()
dtype = node.inputs[0].type.dtype_specs()[1]
fct_call = self.c_code_contiguous_raw(dtype, 'n', 'x', 'z')
return """
{
npy_intp n = PyArray_SIZE(%(z)s);
%(dtype)s * x = (%(dtype)s*) PyArray_DATA(%(x)s);
%(dtype)s * z = (%(dtype)s*) PyArray_DATA(%(z)s);
%(fct_call)s;
}
""" % locals()
def c_support_code_apply(self, node, name):
self.init_c_code()
rval = []
for subnode, subnodename in zip(self.fgraph.toposort(), self.nodenames):
try:
subnode_support_code = subnode.op.c_support_code_apply(
subnode,
subnodename % dict(nodename=name))
if subnode_support_code:
rval.append(subnode_support_code)
except gof.utils.MethodNotDefined:
pass
# there should be no need to remove duplicate code blocks because
# each block should have been specialized for the given nodename.
# Any block that isn't specialized should be returned via
# c_support_code instead of c_support_code_apply.
return "\n".join(rval)
def _is_symbolic(v):
r"""Return `True` if any of the arguments are symbolic.
See:
https://github.com/Theano/Theano/wiki/Cookbook
"""
symbolic = False
v = list(v)
for _container, _iter in [(v, xrange(len(v)))]:
for _k in _iter:
_v = _container[_k]
if isinstance(_v, theano.gof.Variable):
symbolic = True
return symbolic
def _is_symbolic(v):
r"""Return `True` if any of the arguments are symbolic.
See:
https://github.com/Theano/Theano/wiki/Cookbook
"""
symbolic = False
v = list(v)
for _container, _iter in [(v, xrange(len(v)))]:
for _k in _iter:
_v = _container[_k]
if isinstance(_v, theano.gof.Variable):
symbolic = True
return symbolic
def make_node(self, x):
x = T.as_tensor_variable(x)
assert x.ndim == 2
o = T.scalar(dtype=x.dtype)
return theano.gof.Apply(self, [x], [o])
def make_node(self, A, b):
A = T.as_tensor_variable(A)
b = T.as_tensor_variable(b)
assert A.ndim == 2
assert b.ndim in [1, 2]
otype = T.tensor(
broadcastable=b.broadcastable,
dtype=(A * b).dtype)
return theano.gof.Apply(self, [A, b], [otype])
def make_node(self, A, B):
A = T.as_tensor_variable(A)
B = T.as_tensor_variable(B)
assert A.ndim in [2, 3]
assert B.ndim in [2, 3]
assert A.ndim == B.ndim
otype = T.tensor(
broadcastable=B.broadcastable,
dtype=(A * B).dtype)
return theano.gof.Apply(self, [A, B], [otype])
def __init__(self, props=None, **more_props):
if props is None:
props = {}
elif isinstance(props, gof.utils.scratchpad):
self.__update__(props)
else:
self.__dict__.update(props)
self.__dict__.update(more_props)
# A dict from the object to print to its string
# representation. If it is a dag and not a tree, it allow to
# parse each node of the graph only once. They will still be
# printed many times
self.memo = {}
def assign(self, condition, printer):
# condition can be a class or an instance of an Op.
if isinstance(condition, (gof.Op, type)):
self.printers_dict[condition] = printer
return
self.printers.insert(0, (condition, printer))
def make_node(self, M):
M = tensor.as_tensor_variable(M)
if M.ndim != 0:
raise TypeError('%s only works on scalar input'
% self.__class__.__name__)
elif (not M.dtype.startswith('int') and
not M.dtype.startswith('uint')):
# dtype is a theano attribute here
raise TypeError('%s only works on integer input'
% self.__class__.__name__)
return gof.Apply(self, [M], [tensor.dvector()])
def make_node(self, a, val):
a = tensor.as_tensor_variable(a)
val = tensor.as_tensor_variable(val)
if a.ndim < 2:
raise TypeError('%s: first parameter must have at least'
' two dimensions' % self.__class__.__name__)
elif val.ndim != 0:
raise TypeError('%s: second parameter must be a scalar'
% self.__class__.__name__)
val = tensor.cast(val, dtype=scalar.upcast(a.dtype, val.dtype))
if val.dtype != a.dtype:
raise TypeError('%s: type of second parameter must be the same as'
' the first\'s' % self.__class__.__name__)
return gof.Apply(self, [a, val], [a.type()])
def __init__(self, type, owner=None, index=None, name=None):
super(TensorVariable, self).__init__(type, owner=owner,
index=index, name=name)
if (config.warn_float64 != 'ignore' and type.dtype == 'float64'):
msg = ('You are creating a TensorVariable '
'with float64 dtype. You requested an action via '
'the Theano flag warn_float64={ignore,warn,raise,pdb}.')
if config.warn_float64 == "warn":
# Get the user stack. We don't want function inside the
# tensor and gof directory to be shown to the user.
x = tb.extract_stack()
nb_rm = 0
while x:
file_path = x[-1][0]
rm = False
for p in ["theano/tensor/", "theano\\tensor\\",
"theano/gof/", "theano\\tensor\\"]:
if p in file_path:
x = x[:-1]
nb_rm += 1
rm = True
break
if not rm:
break
warnings.warn(msg, stacklevel=1 + nb_rm)
elif config.warn_float64 == "raise":
raise Exception(msg)
elif config.warn_float64 == 'pdb':
import pdb
pdb.set_trace()
def speed_fusion(self, shared_fn=shared, gpu=False, s=None):
"""
param type s: a slice object
param s: a slice to apply to the case to execute. If None, exec all case.
"""
shp = (3000, 3000)
shp = (1000, 1000)
nb_repeat = 50
# linker=gof.CLinker
# linker=gof.OpWiseCLinker
mode1 = copy.copy(compile.get_default_mode())
mode1._optimizer = mode1._optimizer.including('local_elemwise_fusion')
# TODO:clinker is much faster... but use to much memory
# Possible cause: as their is do deletion of intermediate value when we don't keep the fct.
# More plausible cause: we keep a link to the output data?
# Follow up. Clinker do the same... second cause?
mode2 = copy.copy(compile.get_default_mode())
mode2._optimizer = mode2._optimizer.excluding('local_elemwise_fusion')
print("test with linker", str(mode1.linker))
times1 = self.do(mode1, shared_fn, shp, gpu=gpu, nb_repeat=nb_repeat,
assert_len_topo=False, slice=s)
times2 = self.do(mode2, shared_fn, shp, gpu=gpu, nb_repeat=nb_repeat,
assert_len_topo=False, slice=s)
print("times1 with local_elemwise_fusion")
print(times1, times1.min(), times1.max(), times1.sum())
print("times2 without local_elemwise_fusion")
print(times2, times2.min(), times2.max(), times2.sum())
d = times2 / times1
print("times2/times1")
print(d)
print("min", d.min(), "argmin", d.argmin(), "max", d.max(), \
"mean", d.mean(), "std", d.std())
def get_idx_list(inputs, idx_list, get_count=False):
"""
Given a list of inputs to the subtensor and its idx_list reorders
the inputs according to the idx list to get the right values.
If get_counts=True, instead returns the number of inputs consumed
during this process.
"""
# The number of indices
n = len(inputs) - 1
# The subtensor (or idx_list) does not depend on the inputs.
if n == 0:
return tuple(idx_list)
indices = list(reversed(list(inputs[1:])))
# General case
def convert(entry):
if isinstance(entry, gof.Type):
return indices.pop()
elif isinstance(entry, slice):
return slice(convert(entry.start),
convert(entry.stop),
convert(entry.step))
else:
return entry
cdata = tuple(map(convert, idx_list))
if get_count:
return n - len(indices)
else:
return cdata
def c_support_code(self):
from theano.gof.cutils import compile_cutils_code
return compile_cutils_code()
def as_index_variable(idx):
if idx is None:
return NoneConst.clone()
if isinstance(idx, slice):
return make_slice(idx)
if isinstance(idx, gof.Variable) and isinstance(idx.type, SliceType):
return idx
if isinstance(idx, gof.Variable) and isinstance(idx.type, NoneTypeT):
return idx
idx = theano.tensor.as_tensor_variable(idx)
if idx.type.dtype[:3] not in ('int', 'uin'):
raise TypeError('index must be integers')
return idx
def adv_index_broadcastable_pattern(a, idx):
"""
This function is only used to determine the broadcast pattern for
AdvancedSubtensor output variable.
For this, we make a fake ndarray and a fake idx and call use ask numpy
the output. From this, we find the output broadcast pattern.
"""
def replace_slice(v):
if isinstance(v, gof.Apply):
if len(v.outputs) != 1:
raise ValueError(
"It is ambiguous which output of a multi-output Op has"
" to be fetched.", v)
else:
v = v.outputs[0]
if NoneConst.equals(v):
return None
if isinstance(v.type, SliceType):
return slice(None, None)
return numpy.zeros((2,) * v.ndim, int)
newidx = tuple(map(replace_slice, idx))
# 2 - True = 1; 2 - False = 2
fakeshape = [2 - bc for bc in a.broadcastable]
retshape = numpy.empty(fakeshape)[newidx].shape
return tuple([dim == 1 for dim in retshape])
def make_node(self, a):
a = as_tensor_variable(a)
if a.ndim == 0:
raise ValueError('Nonzero only supports non-scalar arrays.')
output = [TensorType(dtype='int64', broadcastable=(False, False))()]
return gof.Apply(self, [a], output)