提交 ce1eeab9 authored 作者: abergeron's avatar abergeron

Merge pull request #1797 from nouiz/fast_opt

Make the slow scan test fast!
...@@ -1077,6 +1077,7 @@ class FunctionMaker(object): ...@@ -1077,6 +1077,7 @@ class FunctionMaker(object):
self.mode = mode self.mode = mode
self.accept_inplace = accept_inplace self.accept_inplace = accept_inplace
self.function_builder = function_builder self.function_builder = function_builder
self.on_unused_input = on_unused_input # Used only for the pickling
self.required = [(i.value is None) for i in self.inputs] self.required = [(i.value is None) for i in self.inputs]
self.refeed = [ self.refeed = [
...@@ -1215,6 +1216,7 @@ def _pickle_FunctionMaker(self): ...@@ -1215,6 +1216,7 @@ def _pickle_FunctionMaker(self):
accept_inplace=self.accept_inplace, accept_inplace=self.accept_inplace,
function_builder=self.function_builder, function_builder=self.function_builder,
profile=self.profile, profile=self.profile,
on_unused_input=self.on_unused_input,
) )
return (_constructor_FunctionMaker, (kwargs,)) return (_constructor_FunctionMaker, (kwargs,))
......
...@@ -508,13 +508,31 @@ class EmptyConstantError(NotScalarConstantError): ...@@ -508,13 +508,31 @@ class EmptyConstantError(NotScalarConstantError):
""" """
def numpy_scalar(data):
""" Return a scalar stored in a numpy ndarray, or raise
NotScalarConstantError if the numpy ndarray is not a scalar
"""
# handle case where data is numpy.array([])
if data.ndim > 0 and (len(data.shape) == 0 or
__builtins__['max'](data.shape) == 0):
assert numpy.all(numpy.array([]) == data)
raise EmptyConstantError()
try:
numpy.complex(data) # works for all numeric scalars
return data
except Exception:
raise NotScalarConstantError(
'v.data is non-numeric, non-scalar, or has more than one'
' unique value', data)
get_scalar_constant_value_elemwises = ( get_scalar_constant_value_elemwises = (
scal.Cast, scal.Switch, scal.Cast, scal.Switch,
scal.NEQ, scal.EQ, scal.NEQ, scal.EQ,
scal.LT, scal.GT, scal.LE, scal.GE, scal.LT, scal.GT, scal.LE, scal.GE,
scal.Sub, scal.Add, scal.Mod, scal.Mul, scal.Sub, scal.Add, scal.Mod, scal.Mul,
scal.IntDiv, scal.TrueDiv) scal.IntDiv, scal.TrueDiv)
def get_scalar_constant_value(v): def get_scalar_constant_value(orig_v, elemwise=True):
"""return the constant scalar(0-D) value underlying variable `v` """return the constant scalar(0-D) value underlying variable `v`
If v is the output of dimshuffles, fills, allocs, rebroadcasts, cast If v is the output of dimshuffles, fills, allocs, rebroadcasts, cast
...@@ -523,169 +541,158 @@ def get_scalar_constant_value(v): ...@@ -523,169 +541,158 @@ def get_scalar_constant_value(v):
If `v` is not some view of constant scalar data, then raise a If `v` is not some view of constant scalar data, then raise a
NotScalarConstantError. NotScalarConstantError.
:param elemwise: If False, we won't try to go into elemwise.
So this call is faster.
:note: There may be another function similar to this one in the :note: There may be another function similar to this one in the
code, but I'm not sure where it is. code, but I'm not sure where it is.
""" """
v = orig_v
while True:
if v is None:
# None is not a scalar (and many uses of this function seem to depend
# on passing it None)
raise NotScalarConstantError()
if v is None: if isinstance(v, (numpy.integer, int, float)):
# None is not a scalar (and many uses of this function seem to depend return numpy.asarray(v)
# on passing it None)
raise NotScalarConstantError()
if isinstance(v, (numpy.integer, int, float)):
return numpy.asarray(v)
def numpy_scalar(data):
""" Return a scalar stored in a numpy ndarray, or raise
NotScalarConstantError if the numpy ndarray is not a scalar
"""
# handle case where data is numpy.array([])
if data.ndim > 0 and (len(data.shape) == 0 or
__builtins__['max'](data.shape) == 0):
assert numpy.all(numpy.array([]) == data)
raise EmptyConstantError()
try:
numpy.complex(data) # works for all numeric scalars
return data
except Exception:
raise NotScalarConstantError(
'v.data is non-numeric, non-scalar, or has more than one'
' unique value', data)
if isinstance(v, numpy.ndarray): if isinstance(v, numpy.ndarray):
return numpy_scalar(v) return numpy_scalar(v)
if isinstance(v, Constant): if isinstance(v, Constant):
if getattr(v.tag, 'unique_value', None) is not None: if getattr(v.tag, 'unique_value', None) is not None:
data = v.tag.unique_value data = v.tag.unique_value
else: else:
data = v.data data = v.data
return numpy_scalar(data) return numpy_scalar(data)
if getattr(v, 'owner', None): if getattr(v, 'owner', None):
if isinstance(v.owner.op, (Alloc, DimShuffle, Rebroadcast, if isinstance(v.owner.op, (Alloc, DimShuffle, Rebroadcast,
compile.ops.OutputGuard, compile.ops.OutputGuard,
compile.DeepCopyOp)): compile.DeepCopyOp)):
return get_scalar_constant_value(v.owner.inputs[0]) v = v.owner.inputs[0]
elif (isinstance(v.owner.op, theano.compile.ops.Shape_i) and continue
isinstance(v.owner.inputs[0], Constant)): elif isinstance(v.owner.op, theano.compile.ops.Shape_i):
return v.owner.inputs[0].data.shape[v.owner.op.i] if isinstance(v.owner.inputs[0], Constant):
# Don't act as the constant_folding optimization here as this return v.owner.inputs[0].data.shape[v.owner.op.i]
# fct is used too early in the optimization phase. This would # Don't act as the constant_folding optimization here as this
# mess with the stabilization optimization and be too slow. # fct is used too early in the optimization phase. This would
# We put all the scalar Ops used by get_canonical_form_slice() # mess with the stabilization optimization and be too slow.
# to allow it to determine the broadcast pattern correctly. # We put all the scalar Ops used by get_canonical_form_slice()
elif isinstance(v.owner.op, scal.ScalarOp): # to allow it to determine the broadcast pattern correctly.
if isinstance(v.owner.op, scal.Second): elif isinstance(v.owner.op, scal.ScalarOp):
# We don't need both input to be constant for second if isinstance(v.owner.op, scal.Second):
shape, val = v.owner.inputs # We don't need both input to be constant for second
return get_scalar_constant_value(val) shape, val = v.owner.inputs
if isinstance(v.owner.op, get_scalar_constant_value_elemwises): v = val
const = [get_scalar_constant_value(i) continue
for i in v.owner.inputs] if isinstance(v.owner.op, get_scalar_constant_value_elemwises):
ret = [[None]] const = [get_scalar_constant_value(i)
v.owner.op.perform(v.owner, const, ret) for i in v.owner.inputs]
return ret[0][0] ret = [[None]]
elif isinstance(v.owner.op, Elemwise): v.owner.op.perform(v.owner, const, ret)
if isinstance(v.owner.op.scalar_op, scal.Second): return ret[0][0]
# We don't need both input to be constant for second elif elemwise and isinstance(v.owner.op, Elemwise):
shape, val = v.owner.inputs if isinstance(v.owner.op.scalar_op, scal.Second):
return get_scalar_constant_value(val) # We don't need both input to be constant for second
elif isinstance(v.owner.op.scalar_op, shape, val = v.owner.inputs
get_scalar_constant_value_elemwises): v = val
const = [get_scalar_constant_value(i) for i in v.owner.inputs] continue
ret = [[None]] elif isinstance(v.owner.op.scalar_op,
v.owner.op.perform(v.owner, const, ret) get_scalar_constant_value_elemwises):
return ret[0][0] const = [get_scalar_constant_value(i) for i in v.owner.inputs]
elif isinstance(v.owner.op, theano.tensor.subtensor.Subtensor) and v.ndim == 0: ret = [[None]]
if isinstance(v.owner.inputs[0], TensorConstant): v.owner.op.perform(v.owner, const, ret)
cdata = tuple(v.owner.op.get_constant_idx(v.owner.inputs)) return ret[0][0]
try: elif isinstance(v.owner.op, theano.tensor.subtensor.Subtensor) and v.ndim == 0:
return v.owner.inputs[0].data.__getitem__(cdata) if isinstance(v.owner.inputs[0], TensorConstant):
except IndexError: cdata = tuple(v.owner.op.get_constant_idx(v.owner.inputs))
raise IndexError( try:
str(tuple(v.owner.op.idx_list)) + return v.owner.inputs[0].data.__getitem__(cdata)
" is not a valid index into " + except IndexError:
str(v.owner.inputs[0].data)) raise IndexError(
str(tuple(v.owner.op.idx_list)) +
# The index list 'idx_list' should have length the same " is not a valid index into " +
# shape as the input. str(v.owner.inputs[0].data))
# TODO: implement the case where we take a scalar in a matrix
assert len(v.owner.op.idx_list) == v.owner.inputs[0].ndim # The index list 'idx_list' should have length the same
# shape as the input.
# Needed to make better graph in this test in theano/tensor/tests: # TODO: implement the case where we take a scalar in a matrix
# test_sharedvar.py:test_shared_options.test_specify_shape_partial assert len(v.owner.op.idx_list) == v.owner.inputs[0].ndim
if (v.owner.inputs[0].owner and
isinstance(v.owner.inputs[0].owner.op, Join) and # Needed to make better graph in this test in theano/tensor/tests:
# Ensure the Join is joining only scalar variables (so that # test_sharedvar.py:test_shared_options.test_specify_shape_partial
# the constant value can be found at the same index as the one if (v.owner.inputs[0].owner and
# used in the sub-tensor). isinstance(v.owner.inputs[0].owner.op, Join) and
python_all(var.ndim == 0 for var in # Ensure the Join is joining only scalar variables (so that
v.owner.inputs[0].owner.inputs) and # the constant value can be found at the same index as the one
len(v.owner.op.idx_list) == 1): # used in the sub-tensor).
python_all(var.ndim == 0 for var in
idx = v.owner.op.idx_list[0] v.owner.inputs[0].owner.inputs) and
if isinstance(idx, gof.Type): len(v.owner.op.idx_list) == 1):
idx = get_scalar_constant_value(v.owner.inputs[1])
# Note the '+ 1' is because the first argument to Join is the idx = v.owner.op.idx_list[0]
# axis. if isinstance(idx, gof.Type):
ret = v.owner.inputs[0].owner.inputs[idx + 1] idx = get_scalar_constant_value(v.owner.inputs[1])
ret = get_scalar_constant_value(ret) # Note the '+ 1' is because the first argument to Join is the
# join can cast implicitly its input in some case. # axis.
return theano._asarray(ret, dtype=v.type.dtype) ret = v.owner.inputs[0].owner.inputs[idx + 1]
ret = get_scalar_constant_value(ret)
elif (v.owner.inputs[0].owner and # join can cast implicitly its input in some case.
isinstance(v.owner.inputs[0].owner.op, return theano._asarray(ret, dtype=v.type.dtype)
theano.tensor.opt.MakeVector) and
# MakeVector normally accept only scalar as input. elif (v.owner.inputs[0].owner and
# We put this check in case there is change in the future isinstance(v.owner.inputs[0].owner.op,
python_all(var.ndim == 0 for var in theano.tensor.opt.MakeVector) and
v.owner.inputs[0].owner.inputs) and # MakeVector normally accept only scalar as input.
len(v.owner.op.idx_list) == 1): # We put this check in case there is change in the future
idx = v.owner.op.idx_list[0] python_all(var.ndim == 0 for var in
if isinstance(idx, gof.Type): v.owner.inputs[0].owner.inputs) and
idx = get_scalar_constant_value(v.owner.inputs[1]) len(v.owner.op.idx_list) == 1):
# Python 2.4 does not support indexing with numpy.integer idx = v.owner.op.idx_list[0]
# So we cast it. if isinstance(idx, gof.Type):
idx = int(idx) idx = get_scalar_constant_value(v.owner.inputs[1])
ret = v.owner.inputs[0].owner.inputs[idx] # Python 2.4 does not support indexing with numpy.integer
ret = get_scalar_constant_value(ret) # So we cast it.
# MakeVector can cast implicitly its input in some case. idx = int(idx)
return theano._asarray(ret, dtype=v.type.dtype) ret = v.owner.inputs[0].owner.inputs[idx]
ret = get_scalar_constant_value(ret)
# This is needed when we take the grad as the Shape op # MakeVector can cast implicitly its input in some case.
# are not already changed into MakeVector return theano._asarray(ret, dtype=v.type.dtype)
owner = v.owner
leftmost_parent = owner.inputs[0] # This is needed when we take the grad as the Shape op
if (leftmost_parent.owner and # are not already changed into MakeVector
isinstance(leftmost_parent.owner.op, owner = v.owner
theano.tensor.Shape)): leftmost_parent = owner.inputs[0]
op = owner.op if (leftmost_parent.owner and
idx_list = op.idx_list isinstance(leftmost_parent.owner.op,
idx = idx_list[0] theano.tensor.Shape)):
if isinstance(idx, gof.Type): op = owner.op
idx = get_scalar_constant_value(owner.inputs[1]) idx_list = op.idx_list
grandparent = leftmost_parent.owner.inputs[0] idx = idx_list[0]
gp_broadcastable = grandparent.type.broadcastable if isinstance(idx, gof.Type):
ndim = grandparent.type.ndim idx = get_scalar_constant_value(owner.inputs[1])
grandparent = leftmost_parent.owner.inputs[0]
assert ndim == len(gp_broadcastable) gp_broadcastable = grandparent.type.broadcastable
ndim = grandparent.type.ndim
if not (idx < len(gp_broadcastable)):
msg = ("get_scalar_constant_value detected " + assert ndim == len(gp_broadcastable)
"deterministic IndexError: x.shape[%d] " +
"when x.ndim=%d.") % (ndim, idx) if not (idx < len(gp_broadcastable)):
if config.exception_verbosity == 'high': msg = ("get_scalar_constant_value detected " +
msg += 'x=%s' % min_informative_str(v) "deterministic IndexError: x.shape[%d] " +
else: "when x.ndim=%d.") % (ndim, idx)
msg += 'x=%s' % str(v) if config.exception_verbosity == 'high':
raise ValueError(msg) msg += 'x=%s' % min_informative_str(v)
else:
if gp_broadcastable[idx]: msg += 'x=%s' % str(v)
return numpy.asarray(1) raise ValueError(msg)
raise NotScalarConstantError(v) if gp_broadcastable[idx]:
return numpy.asarray(1)
raise NotScalarConstantError(v)
# Easy constructors # Easy constructors
...@@ -3075,7 +3082,7 @@ pprint.assign(pow, printing.OperatorPrinter('**', 1, 'right')) ...@@ -3075,7 +3082,7 @@ pprint.assign(pow, printing.OperatorPrinter('**', 1, 'right'))
########################## ##########################
def extract_constant(x): def extract_constant(x, elemwise=True):
''' '''
This function is basically a call to tensor.get_scalar_constant_value. The This function is basically a call to tensor.get_scalar_constant_value. The
main difference is the behaviour in case of failure. While main difference is the behaviour in case of failure. While
...@@ -3085,7 +3092,7 @@ def extract_constant(x): ...@@ -3085,7 +3092,7 @@ def extract_constant(x):
ScalarVariable, we convert it to a tensor with tensor_from_scalar. ScalarVariable, we convert it to a tensor with tensor_from_scalar.
''' '''
try: try:
x = get_scalar_constant_value(x) x = get_scalar_constant_value(x, elemwise=elemwise)
except NotScalarConstantError: except NotScalarConstantError:
pass pass
if (isinstance(x, scal.ScalarVariable) or if (isinstance(x, scal.ScalarVariable) or
......
...@@ -1581,7 +1581,7 @@ def local_upcast_elemwise_constant_inputs(node): ...@@ -1581,7 +1581,7 @@ def local_upcast_elemwise_constant_inputs(node):
else: else:
try: try:
# works only for scalars # works only for scalars
cval_i = get_scalar_constant_value(i) cval_i = get_scalar_constant_value(i, elemwise=False)
if all(i.broadcastable): if all(i.broadcastable):
new_inputs.append(T.shape_padleft( new_inputs.append(T.shape_padleft(
T.cast(cval_i, output_dtype), T.cast(cval_i, output_dtype),
...@@ -2327,7 +2327,7 @@ def local_remove_switch_const_cond(node): ...@@ -2327,7 +2327,7 @@ def local_remove_switch_const_cond(node):
""" """
if (isinstance(node.op, T.Elemwise) and if (isinstance(node.op, T.Elemwise) and
isinstance(node.op.scalar_op, scalar.basic.Switch)): isinstance(node.op.scalar_op, scalar.basic.Switch)):
cond = T.extract_constant(node.inputs[0]) cond = T.extract_constant(node.inputs[0], elemwise=False)
if type(cond) is numpy.ndarray and cond.ndim == 0: if type(cond) is numpy.ndarray and cond.ndim == 0:
if cond == 0: if cond == 0:
out = node.inputs[2] out = node.inputs[2]
...@@ -2377,7 +2377,8 @@ def local_mul_switch_sink(node): ...@@ -2377,7 +2377,8 @@ def local_mul_switch_sink(node):
if i.owner and i.owner.op == T.switch: if i.owner and i.owner.op == T.switch:
switch = i.owner switch = i.owner
try: try:
if get_scalar_constant_value(switch.inputs[1]) == 0.: if (isinstance(switch.inputs[0], Constant) and
get_scalar_constant_value(switch.inputs[1]) == 0.):
listmul = node.inputs[:idx] + node.inputs[idx + 1:] listmul = node.inputs[:idx] + node.inputs[idx + 1:]
fct = [T.switch(switch.inputs[0], 0, fct = [T.switch(switch.inputs[0], 0,
T.mul(*(listmul + [switch.inputs[2]])))] T.mul(*(listmul + [switch.inputs[2]])))]
...@@ -2387,7 +2388,8 @@ def local_mul_switch_sink(node): ...@@ -2387,7 +2388,8 @@ def local_mul_switch_sink(node):
except NotScalarConstantError: except NotScalarConstantError:
pass pass
try: try:
if get_scalar_constant_value(switch.inputs[2]) == 0.: if (isinstance(switch.inputs[2], Constant) and
get_scalar_constant_value(switch.inputs[2]) == 0.):
listmul = node.inputs[:idx] + node.inputs[idx + 1:] listmul = node.inputs[:idx] + node.inputs[idx + 1:]
fct = [T.switch(switch.inputs[0], fct = [T.switch(switch.inputs[0],
T.mul(*(listmul + [switch.inputs[1]])), 0)] T.mul(*(listmul + [switch.inputs[1]])), 0)]
...@@ -3784,7 +3786,7 @@ def local_abs_merge(node): ...@@ -3784,7 +3786,7 @@ def local_abs_merge(node):
for i in node.inputs: for i in node.inputs:
if i.owner and i.owner.op == T.abs_: if i.owner and i.owner.op == T.abs_:
inputs.append(i.owner.inputs[0]) inputs.append(i.owner.inputs[0])
else: elif isinstance(i, Constant):
try: try:
const = get_scalar_constant_value(i) const = get_scalar_constant_value(i)
except NotScalarConstantError: except NotScalarConstantError:
...@@ -3792,6 +3794,8 @@ def local_abs_merge(node): ...@@ -3792,6 +3794,8 @@ def local_abs_merge(node):
if not (const >= 0).all(): if not (const >= 0).all():
return False return False
inputs.append(i) inputs.append(i)
else:
return False
return [T.abs_(T.mul(*inputs))] return [T.abs_(T.mul(*inputs))]
if node.op == T.true_div and sum([i.owner.op == T.abs_ for i in if node.op == T.true_div and sum([i.owner.op == T.abs_ for i in
node.inputs if i.owner]) == 2: node.inputs if i.owner]) == 2:
......
...@@ -1495,11 +1495,11 @@ def test_log1p(): ...@@ -1495,11 +1495,11 @@ def test_log1p():
f = function([x], T.log(1 + (x)), mode=m) f = function([x], T.log(1 + (x)), mode=m)
assert [node.op for node in f.maker.fgraph.toposort()] == [T.log1p] assert [node.op for node in f.maker.fgraph.toposort()] == [T.log1p]
f = function([x], T.log(1 + (-x)), mode=m) f = function([x], T.log(1 + (-x)), mode=m)
assert [node.op for node in f.maker.fgraph.toposort()] == [T.neg, assert [node.op for node in f.maker.fgraph.toposort()] == [
inplace.log1p_inplace] T.neg, inplace.log1p_inplace]
f = function([x], -T.log(1 + (-x)), mode=m) f = function([x], -T.log(1 + (-x)), mode=m)
assert [node.op for node in f.maker.fgraph.toposort()] == [T.neg, assert [node.op for node in f.maker.fgraph.toposort()] == [
inplace.log1p_inplace, inplace.neg_inplace] T.neg, inplace.log1p_inplace, inplace.neg_inplace]
# check trickier cases (and use different dtype) # check trickier cases (and use different dtype)
y = fmatrix() y = fmatrix()
...@@ -1507,12 +1507,12 @@ def test_log1p(): ...@@ -1507,12 +1507,12 @@ def test_log1p():
print f.maker.fgraph.toposort() print f.maker.fgraph.toposort()
# the first three ops are Shape_i, Shape_i, and Dimshuffle # the first three ops are Shape_i, Shape_i, and Dimshuffle
theano.printing.debugprint(f) theano.printing.debugprint(f)
assert [node.op for node in f.maker.fgraph.toposort()][3:] \ assert [node.op for node in f.maker.fgraph.toposort()][3:] == [
== [T.log1p, tensor.alloc] T.log1p, tensor.alloc]
f = function([x, y], T.log(0 + (x) + tensor.fill(y, 1.0)), mode=m) f = function([x, y], T.log(0 + (x) + tensor.fill(y, 1.0)), mode=m)
theano.printing.debugprint(f) theano.printing.debugprint(f)
assert [node.op for node in f.maker.fgraph.toposort()][3:] \ assert [node.op for node in f.maker.fgraph.toposort()][3:] == [
== [T.log1p, tensor.alloc] T.log1p, tensor.alloc]
f = function([x, y], T.log(2 + (x) - tensor.fill(y, 1.0)), mode=m) f = function([x, y], T.log(2 + (x) - tensor.fill(y, 1.0)), mode=m)
theano.printing.debugprint(f) theano.printing.debugprint(f)
assert [node.op for node in f.maker.fgraph.toposort()][3:] \ assert [node.op for node in f.maker.fgraph.toposort()][3:] \
...@@ -1611,7 +1611,7 @@ def test_local_useless_subtensor(): ...@@ -1611,7 +1611,7 @@ def test_local_useless_subtensor():
prog = f.maker.fgraph.toposort() prog = f.maker.fgraph.toposort()
if res: if res:
assert isinstance(prog[0].op, theano.tensor.basic. assert isinstance(prog[0].op, theano.tensor.basic.
SpecifyShape), dims SpecifyShape), dims
assert prog[1].op == tensor.exp, dims assert prog[1].op == tensor.exp, dims
assert len(prog) == 2, dims assert len(prog) == 2, dims
else: else:
...@@ -1628,7 +1628,7 @@ def test_local_useless_subtensor(): ...@@ -1628,7 +1628,7 @@ def test_local_useless_subtensor():
((slice(0, x.shape[1]), slice(0, x.shape[1]), ), False), ((slice(0, x.shape[1]), slice(0, x.shape[1]), ), False),
((slice(0, x.shape[1]), 2), False), ((slice(0, x.shape[1]), 2), False),
((slice(0, x.shape[1]), slice(x.shape[0] - x.shape[0], ((slice(0, x.shape[1]), slice(x.shape[0] - x.shape[0],
x.shape[1]),), False), x.shape[1]),), False),
((slice(0, T.scalar_from_tensor(x.shape[0])), ), True), ((slice(0, T.scalar_from_tensor(x.shape[0])), ), True),
]): ]):
f = function([x], tensor.exp(x).__getitem__(dims), mode=mode_opt) f = function([x], tensor.exp(x).__getitem__(dims), mode=mode_opt)
...@@ -1710,7 +1710,7 @@ class test_local_subtensor_lift(unittest.TestCase): ...@@ -1710,7 +1710,7 @@ class test_local_subtensor_lift(unittest.TestCase):
assert isinstance(prog[1].op, tensor.Subtensor) # first subtensor assert isinstance(prog[1].op, tensor.Subtensor) # first subtensor
assert isinstance(prog[2].op, tensor.Subtensor) # first subtensor assert isinstance(prog[2].op, tensor.Subtensor) # first subtensor
assert isinstance(prog[3].op.scalar_op, theano.scalar. assert isinstance(prog[3].op.scalar_op, theano.scalar.
Composite) # Composite{add,add} Composite) # Composite{add,add}
assert len(prog) == 4 assert len(prog) == 4
f([[0, 1], [2, 3]], 4, [[4, 5], [6, 7]]) f([[0, 1], [2, 3]], 4, [[4, 5], [6, 7]])
# let debugmode test something # let debugmode test something
...@@ -1727,7 +1727,7 @@ class test_local_subtensor_lift(unittest.TestCase): ...@@ -1727,7 +1727,7 @@ class test_local_subtensor_lift(unittest.TestCase):
assert isinstance(prog[1].op, tensor.Subtensor) # first subtensor assert isinstance(prog[1].op, tensor.Subtensor) # first subtensor
assert isinstance(prog[2].op, tensor.Subtensor) # first subtensor assert isinstance(prog[2].op, tensor.Subtensor) # first subtensor
assert isinstance(prog[3].op.scalar_op, theano.scalar. assert isinstance(prog[3].op.scalar_op, theano.scalar.
Composite) # Composite{add,add} Composite) # Composite{add,add}
assert len(prog) == 4 assert len(prog) == 4
f([[0, 1], [2, 3]], 4, [[4, 5], [6, 7]]) f([[0, 1], [2, 3]], 4, [[4, 5], [6, 7]])
# let debugmode test something # let debugmode test something
...@@ -1767,12 +1767,12 @@ class test_local_subtensor_lift(unittest.TestCase): ...@@ -1767,12 +1767,12 @@ class test_local_subtensor_lift(unittest.TestCase):
x = tensor.matrix('x') x = tensor.matrix('x')
y = tensor.vector('y') y = tensor.vector('y')
f = function([x, y], [tensor.exp(x + y)[0], tensor.exp(x + y) + x], f = function([x, y], [tensor.exp(x + y)[0], tensor.exp(x + y) + x],
mode=mode_opt) mode=mode_opt)
prog = f.maker.fgraph.toposort() prog = f.maker.fgraph.toposort()
assert isinstance(prog[0].op, tensor.DimShuffle) assert isinstance(prog[0].op, tensor.DimShuffle)
assert isinstance(prog[1].op.scalar_op, theano.scalar. assert isinstance(prog[1].op.scalar_op, theano.scalar.
Composite) # Composite{add,exp} Composite) # Composite{add,exp}
assert prog[2].op == tensor.add assert prog[2].op == tensor.add
assert isinstance(prog[3].op, tensor.Subtensor) # first subtensor assert isinstance(prog[3].op, tensor.Subtensor) # first subtensor
assert len(prog) == 4 assert len(prog) == 4
...@@ -2039,10 +2039,10 @@ class test_local_subtensor_merge(unittest.TestCase): ...@@ -2039,10 +2039,10 @@ class test_local_subtensor_merge(unittest.TestCase):
# Some cases of merge: shape, (start, stop, step) of first, # Some cases of merge: shape, (start, stop, step) of first,
# (start, stop, step) of second subtensor # (start, stop, step) of second subtensor
cases = [ cases = [
((2, 3), (None, None, None), (None, None, -1)), ((2, 3), (None, None, None), (None, None, -1)),
((12, 1), (None, None, -4), (None, None, 1)), ((12, 1), (None, None, -4), (None, None, 1)),
((5, 3), (1, 4, 2), (None, None, -1)), ((5, 3), (1, 4, 2), (None, None, -1)),
] ]
x = tensor.matrix('x') x = tensor.matrix('x')
for shape, sl1, sl2 in cases: for shape, sl1, sl2 in cases:
...@@ -2063,13 +2063,13 @@ class test_local_subtensor_merge(unittest.TestCase): ...@@ -2063,13 +2063,13 @@ class test_local_subtensor_merge(unittest.TestCase):
e2 = tensor.iscalar('e2') e2 = tensor.iscalar('e2')
s2 = tensor.iscalar('s2') s2 = tensor.iscalar('s2')
f = function([x, b1, e1, s1, b2, e2, s2], x[b1:e1:s1][b2:e2:s2], f = function([x, b1, e1, s1, b2, e2, s2], x[b1:e1:s1][b2:e2:s2],
mode=mode_opt) mode=mode_opt)
#theano.printing.debugprint(f, print_type=True) #theano.printing.debugprint(f, print_type=True)
topo = f.maker.fgraph.toposort() topo = f.maker.fgraph.toposort()
#print [t for t in topo if isinstance(t.op, tensor.Subtensor)] #print [t for t in topo if isinstance(t.op, tensor.Subtensor)]
assert len([t for t in topo if isinstance(t.op, tensor. assert len([t for t in topo if isinstance(t.op, tensor.
Subtensor)]) == 1 Subtensor)]) == 1
#print topo[-1].op #print topo[-1].op
assert isinstance(topo[-1].op, DeepCopyOp) assert isinstance(topo[-1].op, DeepCopyOp)
...@@ -2079,9 +2079,9 @@ class test_local_subtensor_merge(unittest.TestCase): ...@@ -2079,9 +2079,9 @@ class test_local_subtensor_merge(unittest.TestCase):
e2r = self.rng.permutation(range(-8, 8))[:2] e2r = self.rng.permutation(range(-8, 8))[:2]
s1r = self.rng.permutation([-7, -6, -5, -4, -3, -2, -1, 1, s1r = self.rng.permutation([-7, -6, -5, -4, -3, -2, -1, 1,
2, 3, 4, 5, 6, 7])[:2] 2, 3, 4, 5, 6, 7])[:2]
s2r = self.rng.permutation([-7, -6, -5, -4, -3, -2, -1, 1, s2r = self.rng.permutation([-7, -6, -5, -4, -3, -2, -1, 1,
2, 3, 4, 5, 6, 7])[:2] 2, 3, 4, 5, 6, 7])[:2]
for x_s in self.x_shapes: for x_s in self.x_shapes:
x_val = self.rng.uniform(size=x_s).astype(config.floatX) x_val = self.rng.uniform(size=x_s).astype(config.floatX)
...@@ -2152,7 +2152,7 @@ class test_local_subtensor_merge(unittest.TestCase): ...@@ -2152,7 +2152,7 @@ class test_local_subtensor_merge(unittest.TestCase):
topo = f.maker.fgraph.toposort() topo = f.maker.fgraph.toposort()
#print [t for t in topo if isinstance(t.op, tensor.Subtensor)] #print [t for t in topo if isinstance(t.op, tensor.Subtensor)]
assert len([t for t in topo if isinstance(t.op, tensor. assert len([t for t in topo if isinstance(t.op, tensor.
Subtensor)]) == 1 Subtensor)]) == 1
#print topo[-1].op #print topo[-1].op
assert isinstance(topo[-1].op, DeepCopyOp) assert isinstance(topo[-1].op, DeepCopyOp)
...@@ -2178,7 +2178,7 @@ class test_local_subtensor_merge(unittest.TestCase): ...@@ -2178,7 +2178,7 @@ class test_local_subtensor_merge(unittest.TestCase):
except IndexError: except IndexError:
n_index_err += 1 n_index_err += 1
self.assertRaises(IndexError, self.assertRaises(IndexError,
f, x_val, b_v, e_v, s_v, i_v) f, x_val, b_v, e_v, s_v, i_v)
else: else:
# Executed if the "try" clause did not raise # Executed if the "try" clause did not raise
# any exception # any exception
...@@ -2241,7 +2241,7 @@ class test_local_subtensor_merge(unittest.TestCase): ...@@ -2241,7 +2241,7 @@ class test_local_subtensor_merge(unittest.TestCase):
topo = f.maker.fgraph.toposort() topo = f.maker.fgraph.toposort()
#print [t for t in topo if isinstance(t.op, tensor.Subtensor)] #print [t for t in topo if isinstance(t.op, tensor.Subtensor)]
assert len([t for t in topo if isinstance(t.op, assert len([t for t in topo if isinstance(t.op,
tensor.Subtensor)]) <= 1 tensor.Subtensor)]) <= 1
assert isinstance(topo[-1].op, DeepCopyOp) assert isinstance(topo[-1].op, DeepCopyOp)
for x_s in self.x_shapes: for x_s in self.x_shapes:
...@@ -2298,7 +2298,7 @@ class test_local_subtensor_merge(unittest.TestCase): ...@@ -2298,7 +2298,7 @@ class test_local_subtensor_merge(unittest.TestCase):
topo = f.maker.fgraph.toposort() topo = f.maker.fgraph.toposort()
#print [t for t in topo if isinstance(t.op, tensor.Subtensor)] #print [t for t in topo if isinstance(t.op, tensor.Subtensor)]
assert len([t for t in topo if isinstance(t.op, assert len([t for t in topo if isinstance(t.op,
tensor.Subtensor)]) <= 1 tensor.Subtensor)]) <= 1
assert isinstance(topo[-1].op, DeepCopyOp) assert isinstance(topo[-1].op, DeepCopyOp)
for x_s in self.x_shapes: for x_s in self.x_shapes:
...@@ -2333,7 +2333,8 @@ class Test_alloc_zero(unittest.TestCase): ...@@ -2333,7 +2333,8 @@ class Test_alloc_zero(unittest.TestCase):
def setUp(self): def setUp(self):
mode = theano.compile.mode.get_default_mode() mode = theano.compile.mode.get_default_mode()
self.mode = mode.including("local_incsubtensor_of_allocs", self.mode = mode.including("local_incsubtensor_of_allocs",
"local_setsubtensor_of_allocs", "local_0_dot_x") "local_setsubtensor_of_allocs",
"local_0_dot_x")
def test_setsubtensor_allocs0(self): def test_setsubtensor_allocs0(self):
x = tensor.matrix() x = tensor.matrix()
...@@ -2343,32 +2344,32 @@ class Test_alloc_zero(unittest.TestCase): ...@@ -2343,32 +2344,32 @@ class Test_alloc_zero(unittest.TestCase):
z = tensor.set_subtensor(x0[:4], y0) z = tensor.set_subtensor(x0[:4], y0)
f = theano.function([x, y], z, mode=self.mode) f = theano.function([x, y], z, mode=self.mode)
assert numpy.all([not isinstance(x.op, tensor.IncSubtensor) for x in assert numpy.all([not isinstance(x.op, tensor.IncSubtensor) for x in
f.maker.fgraph.toposort()]) f.maker.fgraph.toposort()])
def test_setsubtensor_allocs1(self): def test_setsubtensor_allocs1(self):
y = tensor.matrix() y = tensor.matrix()
x0 = tensor.constant(numpy.asarray(numpy.zeros((4, 4)), x0 = tensor.constant(numpy.asarray(numpy.zeros((4, 4)),
dtype=config.floatX)) dtype=config.floatX))
y0 = tensor.zeros_like(y) y0 = tensor.zeros_like(y)
z = tensor.set_subtensor(x0[:4], y0) z = tensor.set_subtensor(x0[:4], y0)
f = theano.function([y], z, mode=self.mode) f = theano.function([y], z, mode=self.mode)
assert numpy.all([not isinstance(x.op, tensor.IncSubtensor) for x in assert numpy.all([not isinstance(x.op, tensor.IncSubtensor) for x in
f.maker.fgraph.toposort()]) f.maker.fgraph.toposort()])
def test_setsubtensor_allocs1t(self): def test_setsubtensor_allocs1t(self):
y = tensor.matrix() y = tensor.matrix()
x0 = tensor.constant(numpy.asarray(numpy.zeros((4, 4)), x0 = tensor.constant(numpy.asarray(numpy.zeros((4, 4)),
dtype=config.floatX)) dtype=config.floatX))
y0 = tensor.zeros_like(y) y0 = tensor.zeros_like(y)
z = tensor.set_subtensor(x0[:4], y0.T) z = tensor.set_subtensor(x0[:4], y0.T)
f = theano.function([y], z, mode=mode_opt) f = theano.function([y], z, mode=mode_opt)
assert numpy.all([not isinstance(x.op, tensor.IncSubtensor) for x in assert numpy.all([not isinstance(x.op, tensor.IncSubtensor) for x in
f.maker.fgraph.toposort()]) f.maker.fgraph.toposort()])
def test_setsubtensor_allocs2(self): def test_setsubtensor_allocs2(self):
x = tensor.matrix() x = tensor.matrix()
y0 = tensor.constant(numpy.asarray(numpy.zeros_like((4, 4)), y0 = tensor.constant(numpy.asarray(numpy.zeros_like((4, 4)),
dtype=config.floatX)) dtype=config.floatX))
x0 = tensor.zeros_like(x) x0 = tensor.zeros_like(x)
z = tensor.set_subtensor(x0[:4], y0) z = tensor.set_subtensor(x0[:4], y0)
f = theano.function([x], z, mode=self.mode) f = theano.function([x], z, mode=self.mode)
...@@ -2382,7 +2383,7 @@ class Test_alloc_zero(unittest.TestCase): ...@@ -2382,7 +2383,7 @@ class Test_alloc_zero(unittest.TestCase):
z = tensor.inc_subtensor(x[:4], y0) z = tensor.inc_subtensor(x[:4], y0)
f = theano.function([x, y], z, mode=self.mode) f = theano.function([x, y], z, mode=self.mode)
assert numpy.all([not isinstance(x.op, tensor.IncSubtensor) for x in assert numpy.all([not isinstance(x.op, tensor.IncSubtensor) for x in
f.maker.fgraph.toposort()]) f.maker.fgraph.toposort()])
def test_incsubtensor_allocs0t(self): def test_incsubtensor_allocs0t(self):
x = tensor.matrix() x = tensor.matrix()
...@@ -2391,12 +2392,12 @@ class Test_alloc_zero(unittest.TestCase): ...@@ -2391,12 +2392,12 @@ class Test_alloc_zero(unittest.TestCase):
z = tensor.inc_subtensor(x[:4], y0.T) z = tensor.inc_subtensor(x[:4], y0.T)
f = theano.function([x, y], z, mode=mode_opt) f = theano.function([x, y], z, mode=mode_opt)
assert numpy.all([not isinstance(x.op, tensor.IncSubtensor) for x in assert numpy.all([not isinstance(x.op, tensor.IncSubtensor) for x in
f.maker.fgraph.toposort()]) f.maker.fgraph.toposort()])
def test_incsubtensor_allocs1(self): def test_incsubtensor_allocs1(self):
x = tensor.matrix() x = tensor.matrix()
y0 = tensor.constant(numpy.asarray(numpy.zeros_like((4, 4)), y0 = tensor.constant(numpy.asarray(numpy.zeros_like((4, 4)),
dtype=config.floatX)) dtype=config.floatX))
z = tensor.inc_subtensor(x[:4], y0) z = tensor.inc_subtensor(x[:4], y0)
f = theano.function([x], z, mode=self.mode) f = theano.function([x], z, mode=self.mode)
assert numpy.all([not isinstance(x.op, tensor.IncSubtensor) for x in assert numpy.all([not isinstance(x.op, tensor.IncSubtensor) for x in
...@@ -2427,7 +2428,7 @@ class Test_alloc_zero(unittest.TestCase): ...@@ -2427,7 +2428,7 @@ class Test_alloc_zero(unittest.TestCase):
f(_e1[1], _e2[1]) f(_e1[1], _e2[1])
f(_e1[2], _e2[2]) f(_e1[2], _e2[2])
assert numpy.all([not isinstance(x.op, tensor.Dot) for x in assert numpy.all([not isinstance(x.op, tensor.Dot) for x in
f.maker.fgraph.toposort() ]) f.maker.fgraph.toposort()])
#test that we don't remove shape errors #test that we don't remove shape errors
self.assertRaises((ValueError, AssertionError), f, self.assertRaises((ValueError, AssertionError), f,
...@@ -2475,7 +2476,7 @@ def test_local_subtensor_of_alloc(): ...@@ -2475,7 +2476,7 @@ def test_local_subtensor_of_alloc():
(slice(1, 3), slice(None, -1)), (slice(1, 3), slice(None, -1)),
(slice(None, None, 2)), (slice(None, None, 2)),
(slice(1, None, 2)), (slice(1, None, 2)),
] ]
for slices in slicess: for slices in slicess:
z = yx.__getitem__(slices) z = yx.__getitem__(slices)
f = theano.function([x], z) f = theano.function([x], z)
...@@ -2809,8 +2810,8 @@ class test_assert(utt.InferShapeTester): ...@@ -2809,8 +2810,8 @@ class test_assert(utt.InferShapeTester):
x = T.scalar() x = T.scalar()
y = T.scalar() y = T.scalar()
f = theano.function([x, y], theano.tensor.opt.assert_(x, y, f = theano.function([x, y], theano.tensor.opt.assert_(x, y, 1),
1), mode=mode) mode=mode)
assert f(1, 1) == 1 assert f(1, 1) == 1
assert f(5, 1) == 5 assert f(5, 1) == 5
topo = f.maker.fgraph.toposort() topo = f.maker.fgraph.toposort()
...@@ -2827,8 +2828,8 @@ class test_assert(utt.InferShapeTester): ...@@ -2827,8 +2828,8 @@ class test_assert(utt.InferShapeTester):
x = T.scalar() x = T.scalar()
y = T.scalar() y = T.scalar()
f = theano.function([x, y], theano.tensor.opt.assert_(x, y, f = theano.function([x, y], theano.tensor.opt.assert_(x, y, 0),
0), mode=mode) mode=mode)
self.assertRaises(AssertionError, f, 1, 0) self.assertRaises(AssertionError, f, 1, 0)
topo = f.maker.fgraph.toposort() topo = f.maker.fgraph.toposort()
assert len(topo) == 2 assert len(topo) == 2
...@@ -2843,14 +2844,14 @@ class test_assert(utt.InferShapeTester): ...@@ -2843,14 +2844,14 @@ class test_assert(utt.InferShapeTester):
bdscal_val = numpy.random.rand() + 1 bdscal_val = numpy.random.rand() + 1
out = theano.tensor.opt.assert_(adscal, bdscal) out = theano.tensor.opt.assert_(adscal, bdscal)
self._compile_and_check([adscal, bdscal], [out], self._compile_and_check([adscal, bdscal], [out],
[adscal_val, bdscal_val], Assert) [adscal_val, bdscal_val], Assert)
admat = dmatrix() admat = dmatrix()
admat_val = numpy.random.rand(3, 4) admat_val = numpy.random.rand(3, 4)
adscal_val += 1 adscal_val += 1
out = theano.tensor.opt.assert_(admat, adscal, bdscal) out = theano.tensor.opt.assert_(admat, adscal, bdscal)
self._compile_and_check([admat, adscal, bdscal], [out], self._compile_and_check([admat, adscal, bdscal], [out],
[admat_val, adscal_val, bdscal_val], Assert) [admat_val, adscal_val, bdscal_val], Assert)
def test_local_mul_specialize(): def test_local_mul_specialize():
...@@ -3177,8 +3178,9 @@ def test_constant_get_stabilized(): ...@@ -3177,8 +3178,9 @@ def test_constant_get_stabilized():
class T_local_switch_sink(unittest.TestCase): class T_local_switch_sink(unittest.TestCase):
def setUp(self): def setUp(self):
# condition values # condition values
self.condm = numpy.asarray([[0.1, 0, 1, -1], [0., 0., 0., self.condm = numpy.asarray([[0.1, 0, 1, -1],
0.], [1, 1, 1, 1]]) [0., 0., 0., 0.],
[1, 1, 1, 1]])
self.condv = numpy.asarray([0.1, 0, 1, -1]) self.condv = numpy.asarray([0.1, 0, 1, -1])
self.conds = [0.1, 0, 1, -1] self.conds = [0.1, 0, 1, -1]
...@@ -3256,14 +3258,14 @@ class T_local_erf(unittest.TestCase): ...@@ -3256,14 +3258,14 @@ class T_local_erf(unittest.TestCase):
f = theano.function([x], 1 + T.erf(x), mode=self.mode) f = theano.function([x], 1 + T.erf(x), mode=self.mode)
print f.maker.fgraph.toposort() print f.maker.fgraph.toposort()
assert [n.op for n in f.maker.fgraph.toposort()] == [T.mul, T. assert [n.op for n in f.maker.fgraph.toposort()] == [
erfc], f.maker.fgraph.toposort() T.mul, T.erfc], f.maker.fgraph.toposort()
f(val) f(val)
f = theano.function([x], T.erf(x) + 1, mode=self.mode) f = theano.function([x], T.erf(x) + 1, mode=self.mode)
print f.maker.fgraph.toposort() print f.maker.fgraph.toposort()
assert [n.op for n in f.maker.fgraph.toposort()] == [T.mul, T. assert [n.op for n in f.maker.fgraph.toposort()] == [
erfc], f.maker.fgraph.toposort() T.mul, T.erfc], f.maker.fgraph.toposort()
f(val) f(val)
f = theano.function([x], T.erf(x) + 2, mode=self.mode) f = theano.function([x], T.erf(x) + 2, mode=self.mode)
...@@ -3277,7 +3279,7 @@ class T_local_erf(unittest.TestCase): ...@@ -3277,7 +3279,7 @@ class T_local_erf(unittest.TestCase):
def test_local_one_minus_erf(self): def test_local_one_minus_erf(self):
val = numpy.asarray([-30, -3, -2, -1, 0, 1, 2, 3, 30], val = numpy.asarray([-30, -3, -2, -1, 0, 1, 2, 3, 30],
dtype=config.floatX) dtype=config.floatX)
x = T.vector() x = T.vector()
f = theano.function([x], 1 - T.erf(x), mode=self.mode) f = theano.function([x], 1 - T.erf(x), mode=self.mode)
...@@ -3305,7 +3307,7 @@ class T_local_erf(unittest.TestCase): ...@@ -3305,7 +3307,7 @@ class T_local_erf(unittest.TestCase):
assert topo[0].op == T.erf, f.maker.fgraph.toposort() assert topo[0].op == T.erf, f.maker.fgraph.toposort()
assert isinstance(topo[1].op, T.Elemwise), f.maker.fgraph.toposort() assert isinstance(topo[1].op, T.Elemwise), f.maker.fgraph.toposort()
assert isinstance(topo[1].op.scalar_op, scal.Add)\ assert isinstance(topo[1].op.scalar_op, scal.Add)\
or isinstance(topo[1].op.scalar_op,scal.Sub), f.maker.fgraph.toposort() or isinstance(topo[1].op.scalar_op, scal.Sub), f.maker.fgraph.toposort()
print f(val) print f(val)
def test_local_erf_minus_one(self): def test_local_erf_minus_one(self):
...@@ -3342,10 +3344,11 @@ class T_local_erf(unittest.TestCase): ...@@ -3342,10 +3344,11 @@ class T_local_erf(unittest.TestCase):
class T_local_erfc(unittest.TestCase): class T_local_erfc(unittest.TestCase):
def setUp(self): def setUp(self):
self.mode_fusion = theano.compile.mode.get_default_mode().including( self.mode_fusion = theano.compile.mode.get_default_mode().including(
'canonicalize').including('fast_run').excluding('gpu') 'canonicalize').including('fast_run').excluding('gpu')
self.mode = self.mode_fusion.excluding('fusion') self.mode = self.mode_fusion.excluding('fusion')
self.mode._optimizer.position_cutoff = 1.50001 self.mode._optimizer.position_cutoff = 1.50001
if theano.config.cxx == '' and not theano.scalar.basic_scipy.imported_scipy_special: if (theano.config.cxx == '' and
not theano.scalar.basic_scipy.imported_scipy_special):
raise SkipTest("erfc need a c++ compiler or scipy") raise SkipTest("erfc need a c++ compiler or scipy")
def test_local_one_minus_erfc(self): def test_local_one_minus_erfc(self):
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论