提交 ff2a27d5 authored 作者: Ian Goodfellow's avatar Ian Goodfellow

merged

......@@ -25,7 +25,8 @@ Edit ``setup.py`` to contain the newest version number ::
* Change the ``version`` and ``release`` variables to new version number.
* Change the upper copyright year to the current year if necessary.
* Update the year in the Theano/LICENSE.txt file.
Update the year in the ``Theano/LICENSE.txt`` file too, if necessary.
``NEWS.txt`` usually contains the name and date of the release, change them
too.
......
......@@ -296,8 +296,79 @@ import theano and print the config variable, as in:
Default: False
Remove compiled file when not needed anymore.
This mean it remove file that he tried to compile but failed.
Set to True to keep the source file that failed to compile to
debug them.
If False, source code files are removed when they are not needed anymore.
This means files whose compilation failed are deleted.
Set to True to keep those files in order to debug compilation errors.
.. attribute:: config.DebugMode
This section contains various attributes configuring the behaviour
of mode :class:`~debugmode.DebugMode`.
.. attribute:: config.numpy.seterr_all
String Value: ``'ignore'``, ``'warn'``, ``'raise'``, ``'call'``,
``'print'``, ``'log'``, ``'None'``
Default: ``'ignore'``
Set the default behaviour described by `numpy.seterr
<http://docs.scipy.org/doc/numpy/reference/generated/numpy.seterr.html>`__.
``'None'`` means that numpy's default behaviour will not be changed (unless
one of the other `config.numpy.seterr_*` overrides it), but this behaviour
can change between numpy releases.
This flag sets the default behaviour for all kinds of floating-pont
errors, and it can be overriden for specific errors by setting one
(or more) of the flags below.
This flag's value cannot be modified during the program execution.
.. attribute:: config.numpy.seterr_divide
String Value: ``'None'``, ``'ignore'``, ``'warn'``, ``'raise'``,
``'call'``, ``'print'``, ``'log'``
Default: ``'None'``
Sets numpy's behavior for division by zero. ``'None'`` means using the
default, defined by config.numpy.seterr_all.
This flag's value cannot be modified during the program execution.
.. attribute:: config.numpy.seterr_over
String Value: ``'None'``, ``'ignore'``, ``'warn'``, ``'raise'``,
``'call'``, ``'print'``, ``'log'``
Default: ``'None'``
Sets numpy's behavior for floating-point overflow. ``'None'`` means
using the default, defined by config.numpy.seterr_all.
This flag's value cannot be modified during the program execution.
.. attribute:: config.numpy.seterr_under
String Value: ``'None'``, ``'ignore'``, ``'warn'``, ``'raise'``,
``'call'``, ``'print'``, ``'log'``
Default: ``'None'``
Sets numpy's behavior for floating-point underflow. ``'None'`` means
using the default, defined by config.numpy.seterr_all.
This flag's value cannot be modified during the program execution.
.. attribute:: numpy.seterr_invalid
String Value: ``'None'``, ``'ignore'``, ``'warn'``, ``'raise'``,
``'call'``, ``'print'``, ``'log'``
Default: ``'None'``
Sets numpy's behavior for invalid floating-point operation. ``'None'``
means using the default, defined by :attr:`config.numpy.seterr_all`.
This flag's value cannot be modified during the program execution.
......@@ -38,11 +38,11 @@ output.
Shape inference problem
=======================
Theano do shape information propagation in the graph. Sometimes this
can had error. Example:
Theano propagates shape information in the graph. Sometimes this
can lead to errors. For example:
.. code-block:: python
import numpy
import theano
x = theano.tensor.matrix('x')
......@@ -71,10 +71,10 @@ can had error. Example:
# |Shape_i{1} [@55959184] '' 0
# | |<TensorType(float64, matrix)> [@55583888]
print f(xv,yv)# DONT RAISE AN ERROR AS SHOULD BE.
print f(xv,yv)# DOES NOT RAISE AN ERROR AS SHOULD BE.
#[8,4]
f = theano.function([x,y], z)# Don't take the shape.
f = theano.function([x,y], z)# Do not take the shape.
theano.printing.debugprint(f)
#Join [@44540496] '' 0
# |0 [@44540432]
......@@ -84,22 +84,25 @@ can had error. Example:
f(xv,yv)
# Raise a dimensions mismatch error.
As you see, when you ask for the shape of some computation(join in the
example), we sometimes compute the shape without executing the
computation(there is no join in the first output or debugprint).
As you see, when you ask for the shape of some computation (join in the
example), we sometimes compute an inferred shape directly, without executing
the computation itself (there is no join in the first output or debugprint).
This make the computation of the shape faster, but can hide error. In
This makes the computation of the shape faster, but it can hide errors. In
the example, the computation of the shape of join is done on the first
theano variable in the join, not on the other.
This can probably happen with many other op as elemwise, dot, ...
Indeed, to make some optimizations (for speed or stability, for instance),
Theano can assume that the computation is correct and consistent
in the first place, this is the case here.
You can detect those problem by running the code without this
optimization with the theano flag
optimization, with the Theano flag
`optimizer_excluding=local_shape_to_shape_i`. You can also have the
same effect by running in the mode FAST_COMPILE(won't apply this
optimization and most other optimization too) or DEBUG_MODE(will test
before and after all optimizations(much slower)).
same effect by running in the mode FAST_COMPILE (it will not apply this
optimization, nor most other optimizations) or DEBUG_MODE (it will test
before and after all optimizations (much slower)).
Specifing exact shape
......
......@@ -81,6 +81,36 @@ import gof
if config.device.startswith('gpu') or config.init_gpu_device.startswith('gpu'):
import theano.sandbox.cuda
# Use config.numpy to call numpy.seterr
import numpy
if config.numpy.seterr_all == 'None':
_all = None
else:
_all = config.numpy.seterr_all
if config.numpy.seterr_divide == 'None':
_divide = None
else:
_divide = config.numpy.seterr_divide
if config.numpy.seterr_over == 'None':
_over = None
else:
_over = config.numpy.seterr_over
if config.numpy.seterr_under == 'None':
_under = None
else:
_under = config.numpy.seterr_under
if config.numpy.seterr_invalid == 'None':
_invalid = None
else:
_invalid = config.numpy.seterr_invalid
numpy.seterr(
all=_all,
divide=_divide,
over=_over,
under=_under,
invalid=_invalid)
del _all, _divide, _over, _under, _invalid
## import scalar_opt
### This is defined here because it is designed to work across symbolic datatypes
......
......@@ -535,7 +535,13 @@ def _check_inputs(node, storage_map, r_vals, dr_vals, active_nodes, clobber_dr_v
if warn_input_not_reused and destroyed_res_list:
dmap=getattr(node.op,'destroy_map',{})
for oo,ii in dmap.iteritems():
if storage_map[node.outputs[oo]][0] is not storage_map[node.inputs[ii[0]]][0]:
out_var = storage_map[node.outputs[oo]][0]
in_var = storage_map[node.inputs[ii[0]]][0]
if isinstance (node.op, theano.compile.mode.OutputGuard):
# The point of OutputGuard is to be declared as destructive
# while not destroying anything
continue
if out_var is not in_var:
opt_warning("input idx %d marked as destroyed was not changed for node '%s'"%(ii[0],str(node)))
if warn_input_not_reused:
......
......@@ -190,7 +190,36 @@ class DeepCopyOp(theano.gof.Op):
else:
super(DeepCopyOp, self).c_code(node, name, inames, onames, sub)
class ViewOp(theano.gof.Op):
def __init__(self):
self.view_map={0:[0]}
def __str__(self):
return self.__class__.__name__
def __hash__(self):
return hash(type(self))
def __eq__(self, other):
return type(self) == type(other)
def make_node(self, x):
return theano.gof.Apply(self, [x], [x.type()])
def perform( self, node, args, outs):
outs[0][0] = args[0]
def infer_shape(self, node, input_shapes):
return input_shapes
def grad(self, args, g_outs):
return g_outs
deep_copy_op = DeepCopyOp()
view_op = ViewOp()
DUPLICATE = ['DUPLICATE'] # unique id object used as a placeholder for duplicate entries
class Function(object):
......@@ -771,7 +800,10 @@ def insert_deepcopy(env, wrapped_inputs, wrapped_outputs):
# We could don't put deep copy if both outputs have borrow==True
# and not(wrapped_outputs[i].borrow and wrapped_outputs[j].borrow):
if env.outputs[j] in views_of_output_i:
env.change_input('output', i, deep_copy_op(env.outputs[i]))
if wrapped_outputs[i].borrow and wrapped_outputs[j].borrow:
env.change_input('output',i, view_op(env.outputs[i]))
else:
env.change_input('output', i, deep_copy_op(env.outputs[i]))
copied = True
break
......@@ -784,10 +816,22 @@ def insert_deepcopy(env, wrapped_inputs, wrapped_outputs):
continue
if input_j in updated_env_inputs:
continue
# We could don't put deep_copy_op if the input and the output have borrow==True
if input_j in views_of_output_i:
env.change_input('output', i, deep_copy_op(env.outputs[i]))
break
# We don't put deep_copy_op if the input and the output have borrow==True
if input_j in env.inputs:
j = env.inputs.index(input_j)
if wrapped_outputs[i].borrow and wrapped_inputs[j].borrow:
env.change_input('output',i, view_op(env.outputs[i]))
break
else:
env.change_input('output', i, deep_copy_op(env.outputs[i]))
break
elif wrapped_outputs[i].borrow:
env.change_input('output',i, view_op(env.outputs[i]))
break
else:
env.change_input('output', i, deep_copy_op(env.outputs[i]))
break
NODEFAULT = ['NODEFAULT']
class FunctionMaker(object):
......
......@@ -164,6 +164,11 @@ class In(SymbolicInput):
True: permit the compiled function to modify the python object being passed as the input
False: do not permit the compiled function to modify the python object being passed as the input.
borrow: Bool (default: False if update is None, True if update is not None)
True: permit the output of the compiled function to be aliased to the input
False: do not permit any output to be aliased to the input
strict: Bool (default: False)
True: means that the value you pass for this input must have exactly the right type
False: the value you pass for this input may be cast automatically to the proper type
......@@ -194,7 +199,7 @@ class In(SymbolicInput):
def __init__(self, variable, name=None, value=None, update=None,
mutable=None, strict=False, allow_downcast=None, autoname=True,
implicit=None, borrow=None):
# mutable implies the output can be both aliased to the input and that the input can be
# destroyed. borrow simply implies the output can be aliased to the input. Thus
# mutable=True should require borrow=True. Raise warning when borrow is explicitely set
......@@ -210,7 +215,7 @@ class In(SymbolicInput):
# borrow=None basically means False. We can't set default value to False because of the
# above business with mutable.
if borrow is None:
if borrow is None:
borrow = False
if implicit is None:
......@@ -226,6 +231,7 @@ class In(SymbolicInput):
autoname=autoname,
implicit=implicit)
self.value = value
self.borrow = borrow
if self.implicit and value is None:
raise TypeError('An implicit input must be given a default value')
......
......@@ -244,7 +244,7 @@ def rebuild_collect_shared( outputs
class Param(object):
def __init__(self, variable, default=None, name=None, mutable=False,
strict=False, allow_downcast=None, implicit=None):
strict=False, allow_downcast=None, implicit=None, borrow = False):
"""
:param variable: A variable in an expression graph to use as a compiled-function parameter
......@@ -255,6 +255,11 @@ class Param(object):
:param mutable: True -> function is allowed to modify this argument.
:param borrow: True -> function is allowed to alias some output to
this input
False: do not permit any output to be aliased to the input
:param strict: False -> function arguments may be copied or casted to match the
type required by the parameter `variable`. True -> function arguments must exactly match the type
required by `variable`.
......@@ -271,9 +276,15 @@ class Param(object):
self.default = default
self.name = name
self.mutable = mutable
# Mutable implies borrow. You can get borrow = False because of the
# default and it is a bit annoying to require the user to set both
# borrow and mutable to True
if mutable:
borrow = True
self.strict = strict
self.allow_downcast = allow_downcast
self.implicit = implicit
self.borrow = borrow
def pfunc(params, outputs=None, mode=None, updates=[], givens=[],
no_default_updates=False, accept_inplace=False, name=None,
......@@ -396,6 +407,7 @@ def _pfunc_param_to_in(param, strict=False, allow_downcast=None):
value=param.default,
mutable=param.mutable,
strict=param.strict,
borrow = param.borrow,
allow_downcast=param.allow_downcast,
implicit = param.implicit)
raise TypeError('Unknown parameter type: %s' % type(param))
......
......@@ -304,11 +304,8 @@ class T_function(unittest.TestCase):
assert (out==4).all()
out[0]=3
out2 = f()
# Currently we don't do this optimization!
# As this is a corner case that is not usefull for use
# We probably won't optimize it.
assert out2 is not out
assert (out2==4).all()
assert out2 is out
assert (out2==3).all()
def test_borrow_input(self):
......
......@@ -71,7 +71,7 @@ AddConfigVar('home',
#This expanduser works on windows (see discussion on theano-users, July 13 2010)
AddConfigVar('nocleanup',
"suppress the deletion of code files that did not compile cleanly",
"Suppress the deletion of code files that did not compile cleanly",
BoolParam(False))
AddConfigVar('tensor.cmp_sloppy',
......@@ -115,6 +115,44 @@ AddConfigVar('experimental.mrg',
"Another random number generator that work on the gpu",
BoolParam(False))
AddConfigVar('numpy.seterr_all',
("Sets numpy's behaviour for floating-point errors, ",
"see numpy.seterr. "
"'None' means not to change numpy's default, which can be "
"different for different numpy releases. "
"This flag sets the default behaviour for all kinds of floating-"
"point errors, its effect can be overriden for specific errors "
"by the following flags: seterr_divide, seterr_over, "
"seterr_under and seterr_invalid."),
EnumStr('ignore', 'warn', 'raise', 'call', 'print', 'log', 'None',
allow_override=False))
AddConfigVar('numpy.seterr_divide',
("Sets numpy's behavior for division by zero, see numpy.seterr. "
"'None' means using the default, defined by numpy.seterr_all."),
EnumStr('None', 'ignore', 'warn', 'raise', 'call', 'print', 'log',
allow_override=False))
AddConfigVar('numpy.seterr_over',
("Sets numpy's behavior for floating-point overflow, "
"see numpy.seterr. "
"'None' means using the default, defined by numpy.seterr_all."),
EnumStr('None', 'ignore', 'warn', 'raise', 'call', 'print', 'log',
allow_override=False))
AddConfigVar('numpy.seterr_under',
("Sets numpy's behavior for floating-point underflow, "
"see numpy.seterr. "
"'None' means using the default, defined by numpy.seterr_all."),
EnumStr('None', 'ignore', 'warn', 'raise', 'call', 'print', 'log',
allow_override=False))
AddConfigVar('numpy.seterr_invalid',
("Sets numpy's behavior for invalid floating-point operation, "
"see numpy.seterr. "
"'None' means using the default, defined by numpy.seterr_all."),
EnumStr('None', 'ignore', 'warn', 'raise', 'call', 'print', 'log',
allow_override=False))
###
### To disable some warning about old bug that are fixed now.
......
......@@ -5,10 +5,10 @@ WARNING
This directory is for the internal of Theano.
You are strongly adviced to don't use it except if you know
what you do!
You are strongly advised not to use it, except if you know
what you are doing!
If you want to use scalar variable in a Theano graph,
If you want to use a scalar variable in a Theano graph,
you probably want to use theano.tensor.[c,z,f,d,b,w,i,l,]scalar!
"""
......@@ -113,7 +113,7 @@ class Scalar(Type):
raise TypeError("Could not convert %s (value=%s) to %s" % (type(data), data, self.dtype), e)
def values_eq_approx(self, a, b, tolerance = 1e-4):
return abs(a - b) / (a+b) < tolerance
return abs(a - b) <= ((abs(a)+abs(b)) * tolerance)
def c_headers(self):
l=['<math.h>']
......
......@@ -846,15 +846,7 @@ def scan( fn
info['inplace'] = False
info['gpu'] = False
revised_outs = []
for o in new_outs:
if (o in inner_inputs or
isinstance(o, tensor.Constant)):
revised_outs.append( scan_utils.cloneOp(o))
else:
revised_outs.append(o)
local_op = scan_op.Scan( inner_inputs, revised_outs, info )
local_op = scan_op.Scan( inner_inputs, new_outs, info )
##
### Step 8. Compute the outputs using the scan op
......
......@@ -2007,7 +2007,34 @@ class T_Scan(unittest.TestCase):
assert scan1.owner.op == scan2.owner.op
assert hash(scan1.owner.op) == hash(scan2.owner.op)
def test_same(self):
# This test is checking a bug discovered by Arnaud and it is based
# on his code
x = theano.tensor.fmatrix('x')
mem_val = numpy.zeros((2,), dtype='float32')
memory = theano.shared(mem_val.copy())
W = theano.shared(numpy.random.random((5, 2)).astype('float32'))
def f(inp, mem):
i = theano.tensor.join(0, inp, mem)
d = theano.tensor.dot(i, W)
return d, d
outs, updts = theano.scan(f, sequences=[x],
non_sequences=[],
outputs_info=[None, memory])
f = theano.function([x], outs[0])
f2 = theano.function([x], outs[1])
x_val = numpy.random.random((4, 3)).astype('float32')
f_vals = f(x_val)
memory.set_value(mem_val.copy())
f2_vals = f2(x_val)
assert numpy.allclose(f_vals, f2_vals)
if __name__ == '__main__':
#'''
......
......@@ -190,6 +190,63 @@ class T_AddMul(unittest.TestCase):
self.assertTrue(numpy.all(val.todense() == numpy.array([[1, 0],
[9, 0], [0, 36]])))
def test_upcast(self):
array1 = numpy.array([[1, 0], [3, 0], [0, 6]], dtype='float32')
array2 = numpy.array([[1, 0], [3, 0], [0, 6]], dtype='int32')
array3 = numpy.array([[1, 0], [3, 0], [0, 6]], dtype='int8')
# AddSS and MulSS
for mtype in _mtypes:
a = mtype(array1)
aR = as_sparse_variable(a)
b = mtype(array2)
bR = as_sparse_variable(b)
c = mtype(array3)
cR = as_sparse_variable(c)
# Ops that do not upcast
self.assertRaises(NotImplementedError, add, aR, bR)
self.assertRaises(NotImplementedError, add, bR, aR)
self.assertRaises(NotImplementedError, add, bR, cR)
self.assertRaises(NotImplementedError, add, cR, bR)
self.assertRaises(NotImplementedError, add, aR, cR)
self.assertRaises(NotImplementedError, add, cR, aR)
self.assertRaises(NotImplementedError, mul, aR, bR)
self.assertRaises(NotImplementedError, mul, bR, aR)
self.assertRaises(NotImplementedError, mul, bR, cR)
self.assertRaises(NotImplementedError, mul, cR, bR)
self.assertRaises(NotImplementedError, mul, aR, cR)
self.assertRaises(NotImplementedError, mul, cR, aR)
# AddSD and MulSD
for mtype in _mtypes:
a = mtype(array1)
a_sv = as_sparse_variable(a)
a_dv = tensor.as_tensor_variable(array1)
b = mtype(array2)
b_sv = as_sparse_variable(b)
b_dv = tensor.as_tensor_variable(array2)
c = mtype(array3)
c_sv = as_sparse_variable(c)
c_dv = tensor.as_tensor_variable(array3)
# add does not upcast
self.assertRaises(NotImplementedError, add, a_sv, b_dv)
self.assertRaises(NotImplementedError, add, b_sv, a_dv)
self.assertRaises(NotImplementedError, add, b_sv, c_dv)
self.assertRaises(NotImplementedError, add, c_sv, b_dv)
self.assertRaises(NotImplementedError, add, a_sv, c_dv)
self.assertRaises(NotImplementedError, add, c_sv, a_dv)
# mul upcasts the dense input if needed
self.assertRaises(NotImplementedError, mul, a_sv, b_dv)
self.assertRaises(NotImplementedError, mul, b_sv, a_dv)
assert mul(b_sv, c_dv).dtype == 'int32'
self.assertRaises(NotImplementedError, mul, c_sv, b_dv)
assert mul(a_sv, c_dv).dtype == 'float32'
self.assertRaises(NotImplementedError, mul, c_sv, a_dv)
class T_conversion(unittest.TestCase):
def setUp(self):
......
......@@ -3753,7 +3753,7 @@ class Reshape(Op):
shp_orig = shp
shp = as_tensor_variable(shp, ndim=1)
if not shp.dtype.startswith('int'):
raise TypeError("Shape must be integers")
raise TypeError("Shape must be integers", shp, shp.dtype)
assert shp.ndim == 1
if isinstance(shp, TensorConstant):
bcast = [s==1 for s in shp.data]
......@@ -3788,9 +3788,18 @@ class Reshape(Op):
g_out, = grads
return [reshape(g_out, shape(x), ndim=x.ndim), None]
def infer_shape(self, node, ishapes):
#we can't just put node.inputs[1] as not all op support interation
#and this is needed in the ShapeOptimizer
return [tuple([node.inputs[1][i] for i in range(self.ndim)])]
# inputs[1] can contain at most one value of '-1', meaning the actual
# shape of the output will be automatically computed by reshape, so
# that the total number of elements stays the same.
# TODO: Maybe put that formula here?
# It's not trivial, because we would have to check if the product of
# all the non-minus-one shapes is a divisor of the product of the
# original shapes.
return [tuple([switch(eq(node.inputs[1][i], -1),
theano.tensor.opt.Shape_i(i)(node.outputs[0]),
node.inputs[1][i])
for i in range(self.ndim)]
)]
def reshape(x, newshape, ndim=None, name=None):
if ndim is None:
......@@ -4739,10 +4748,10 @@ def grad(cost, wrt, g_cost=None, consider_constant=[], warn_type=False,
ret = []
for p in wrt:
if p not in gmap and not assume_continuously_differentiable:
raise ValueError(("grad method was asked to compute the graident "
raise ValueError(("grad method was asked to compute the gradient "
"with respect to a variable that is not part of "
"the computational graph of the cost or is used "
"by a non-differentiable operator "),p)
"the computational graph of the cost, or is used "
"by a non-differentiable operator"), p)
else:
ret.append(gmap.get(p, zeros_like(p)))
......
......@@ -3290,79 +3290,102 @@ class T_op_cache(unittest.TestCase):
a = numpy.random.rand(5,2).astype(config.floatX)
self.assertTrue(numpy.all(fn_py(a) == fn_c_or_py(a)))
class T_reshape(unittest.TestCase):
def setUp(self):
utt.seed_rng()
def test_reshape():
a = dvector()
b = dmatrix()
d = dmatrix()
#basic to 1 dim(without list)
c = reshape(b, as_tensor_variable(6), ndim=1)
f = inplace_func([b], c)
assert numpy.all(f(numpy.asarray([[0,1,2],[3,4,5]])) == numpy.asarray([0,1,2,3,4,5]))
#print f.maker.env.toposort()
#check that we remove the useless reshape
#basic to 1 dim(with list)
c = reshape(b, (as_tensor_variable(6),), ndim=1)
f = inplace_func([b], c)
assert numpy.all(f(numpy.asarray([[0,1,2],[3,4,5]])) == numpy.asarray([0,1,2,3,4,5]))
#print f.maker.env.toposort()
#check that we remove the useless reshape
#basic to shape object of same ndim
c = reshape(b,d.shape)
f = inplace_func([b,d], c)
assert numpy.all(f(numpy.asarray([[0,1,2],[3,4,5]]),[[0,1],[2,3],[4,5]]) == numpy.asarray([[0,1],[2,3],[4,5]]))
#basic to 2 dims
c = reshape(a, [2,3])
f = inplace_func([a], c)
assert numpy.all(f(numpy.asarray([0,1,2,3,4,5])) == numpy.asarray([[0,1,2], [3,4,5]]))
#test that it works without inplace operations
a_val = numpy.asarray([0,1,2,3,4,5])
a_val_copy = numpy.asarray([0,1,2,3,4,5])
b_val = numpy.asarray([[0,1,2],[3,4,5]])
def test_reshape(self):
a = dvector()
b = dmatrix()
d = dmatrix()
#basic to 1 dim(without list)
c = reshape(b, as_tensor_variable(6), ndim=1)
f = inplace_func([b], c)
assert numpy.all(f(numpy.asarray([[0,1,2],[3,4,5]])) == numpy.asarray([0,1,2,3,4,5]))
#print f.maker.env.toposort()
#check that we remove the useless reshape
#basic to 1 dim(with list)
c = reshape(b, (as_tensor_variable(6),), ndim=1)
f = inplace_func([b], c)
assert numpy.all(f(numpy.asarray([[0,1,2],[3,4,5]])) == numpy.asarray([0,1,2,3,4,5]))
#print f.maker.env.toposort()
#check that we remove the useless reshape
#basic to shape object of same ndim
c = reshape(b,d.shape)
f = inplace_func([b,d], c)
assert numpy.all(f(numpy.asarray([[0,1,2],[3,4,5]]),[[0,1],[2,3],[4,5]]) == numpy.asarray([[0,1],[2,3],[4,5]]))
#basic to 2 dims
c = reshape(a, [2,3])
f = inplace_func([a], c)
assert numpy.all(f(numpy.asarray([0,1,2,3,4,5])) == numpy.asarray([[0,1,2], [3,4,5]]))
#test that it works without inplace operations
a_val = numpy.asarray([0,1,2,3,4,5])
a_val_copy = numpy.asarray([0,1,2,3,4,5])
b_val = numpy.asarray([[0,1,2],[3,4,5]])
f_sub = inplace_func([a,b], c-b)
assert numpy.all(f_sub(a_val, b_val) == 0.0)
assert numpy.all(a_val == a_val_copy)
#test that it works with inplace operations
a_val = theano._asarray([0,1,2,3,4,5], dtype='float64')
a_val_copy = theano._asarray([0,1,2,3,4,5], dtype='float64')
b_val = theano._asarray([[0,1,2],[3,4,5]], dtype='float64')
f_sub = inplace_func([a,b], c-b)
assert numpy.all(f_sub(a_val, b_val) == 0.0)
assert numpy.all(a_val == a_val_copy)
# verify gradient
def just_vals(v):
return Reshape(2)(v, theano._asarray([2,3], dtype='int32'))
utt.verify_grad(just_vals, [a_val])
#test infer_shape
f_sub = function([a,b], (c-b).shape)
if config.mode=="FAST_COMPILE":
assert len(f_sub.maker.env.toposort())==3
else:
topo = f_sub.maker.env.toposort()
assert len(topo)==1
topo[0].op == theano.compile.function_module.deep_copy_op
#assert numpy.all(f_sub(a_val,numpy.asarray([[0,1],[2,3],[4,5]]))==[2,3])#work in FAST_RUN, but fail on other!
#assert numpy.all(f_sub(a_val,numpy.asarray([[0,1],[2,3],[4,5],[6,7]]))==[2,3])#work in FAST_RUN, but fail on other!
f_sub = inplace_func([a,b], c-b)
assert numpy.all(f_sub(a_val, b_val) == 0.0)
assert numpy.all(a_val == a_val_copy)
# test broadcast flag for constant value of 1
c = reshape(b, (b.shape[0],b.shape[1],1))
f = inplace_func([b], c)
assert numpy.all(f(numpy.asarray([[0,1,2],[3,4,5]])) == numpy.asarray([[[0],[1],[2]],[[3],[4],[5]]]))
assert f.maker.env.toposort()[-2].outputs[0].type.broadcastable==(False, False, True)
#test that it works with inplace operations
a_val = theano._asarray([0,1,2,3,4,5], dtype='float64')
a_val_copy = theano._asarray([0,1,2,3,4,5], dtype='float64')
b_val = theano._asarray([[0,1,2],[3,4,5]], dtype='float64')
assert numpy.all(f_sub(a_val,b_val)==[2,3])
f_sub = inplace_func([a,b], c-b)
assert numpy.all(f_sub(a_val, b_val) == 0.0)
assert numpy.all(a_val == a_val_copy)
def test_infer_shape(self):
a = matrix('a')
shapes = ivector('shapes')
ndim = 2
# verify gradient
def just_vals(v):
return Reshape(2)(v, theano._asarray([2,3], dtype='int32'))
utt.verify_grad(just_vals, [a_val])
r = a.reshape(shapes, ndim=2)
z = zeros_like(r)
#test infer_shape
f_sub = function([a,b], (c-b).shape)
if config.mode=="FAST_COMPILE":
assert len(f_sub.maker.env.toposort())==3
else:
topo = f_sub.maker.env.toposort()
assert len(topo)==1
topo[0].op == theano.compile.function_module.deep_copy_op
#assert numpy.all(f_sub(a_val,numpy.asarray([[0,1],[2,3],[4,5]]))==[2,3])#work in FAST_RUN, but fail on other!
#assert numpy.all(f_sub(a_val,numpy.asarray([[0,1],[2,3],[4,5],[6,7]]))==[2,3])#work in FAST_RUN, but fail on other!
f = function([a, shapes], z.shape)
# test broadcast flag for constant value of 1
c = reshape(b, (b.shape[0],b.shape[1],1))
f = inplace_func([b], c)
assert numpy.all(f(numpy.asarray([[0,1,2],[3,4,5]])) == numpy.asarray([[[0],[1],[2]],[[3],[4],[5]]]))
assert f.maker.env.toposort()[-2].outputs[0].type.broadcastable==(False, False, True)
rng = numpy.random.RandomState(seed=utt.fetch_seed())
a_val = rng.uniform(size=(3,4)).astype(config.floatX)
self.assertTrue((f(a_val, [4, 3]) == [4, 3]).all())
self.assertTrue((f(a_val, [-1, 3]) == [4, 3]).all())
self.assertTrue((f(a_val, [4, -1]) == [4, 3]).all())
self.assertRaises(ValueError, f, a_val, [-1, 5])
self.assertRaises(ValueError, f, a_val, [7, -1])
self.assertRaises(ValueError, f, a_val, [7, 5])
self.assertRaises(ValueError, f, a_val, [-1, -1])
assert numpy.all(f_sub(a_val,b_val)==[2,3])
def test_make_column_matrix_broadcastable():
# The goal of the operation made by `b` is to ensure the second dimension
......
......@@ -2787,11 +2787,6 @@ def test_local_tensor_scalar_tensor():
assert len(cast_nodes) == 0
f(0)
@dec.knownfailureif(
isinstance(theano.compile.mode.get_default_mode(),
theano.compile.debugmode.DebugMode),
("This test fails in DEBUG_MODE, but the generated code is OK. "
"It is actually a problem of DEBUG_MODE, see #624."))
def test_local_scalar_tensor_scalar():
dtypes = ['int8', 'int16', 'int32', 'int64',
'uint8', 'uint16', 'uint32', 'uint64',
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论