提交 4829418f authored 作者: Frédéric Bastien's avatar Frédéric Bastien

Merge pull request #2205 from lamblin/pep8_tensor_basic

PEP8/flake8 fixes in tensor/basic.py
...@@ -435,7 +435,7 @@ where, each of the optimization do the following things: ...@@ -435,7 +435,7 @@ where, each of the optimization do the following things:
acceptable_ops = (theano.tensor.basic.Dot, acceptable_ops = (theano.tensor.basic.Dot,
theano.tensor.basic.Reshape, theano.tensor.basic.Reshape,
theano.tensor.basic.Shape, theano.tensor.basic.Shape,
theano.tensor.basic.SpecifyShape, theano.tensor.SpecifyShape,
theano.tensor.basic.MaxAndArgmax, theano.tensor.basic.MaxAndArgmax,
theano.tensor.Subtensor, theano.tensor.Subtensor,
theano.tensor.IncSubtensor, theano.tensor.IncSubtensor,
......
...@@ -65,3 +65,6 @@ from theano.tensor.sort import sort, argsort ...@@ -65,3 +65,6 @@ from theano.tensor.sort import sort, argsort
from theano.tensor.extra_ops import (DiffOp, bincount, squeeze, from theano.tensor.extra_ops import (DiffOp, bincount, squeeze,
repeat, bartlett, fill_diagonal, fill_diagonal_offset, repeat, bartlett, fill_diagonal, fill_diagonal_offset,
cumsum, cumprod) cumsum, cumprod)
# SpecifyShape is defined in theano.compile, but should be available in tensor
from theano.compile import SpecifyShape, specify_shape
...@@ -7,7 +7,6 @@ import warnings ...@@ -7,7 +7,6 @@ import warnings
from itertools import izip from itertools import izip
import numpy import numpy
from copy import copy as python_copy
import theano import theano
from theano.configparser import config from theano.configparser import config
...@@ -26,7 +25,7 @@ from theano.gof.utils import hashtype ...@@ -26,7 +25,7 @@ from theano.gof.utils import hashtype
from theano import compile, printing from theano import compile, printing
from theano.printing import pprint, min_informative_str from theano.printing import pprint, min_informative_str
#For history #For history
from theano.compile import Rebroadcast, Shape, shape, SpecifyShape, specify_shape from theano.compile import Rebroadcast, Shape, shape
# We use these exceptions as well. # We use these exceptions as well.
...@@ -138,7 +137,8 @@ def as_tensor_variable(x, name=None, ndim=None): ...@@ -138,7 +137,8 @@ def as_tensor_variable(x, name=None, ndim=None):
:Exceptions: :Exceptions:
- `ValueError`: raised if an `Apply` with more then one output is fetched - `ValueError`: raised if an `Apply` with more then one output is fetched
- `AsTensorError`: raised if `x` cannot be converted to a TensorType Variable - `AsTensorError`: raised if `x` cannot be converted to a TensorType
Variable
""" """
if hasattr(x, '_as_TensorVariable'): if hasattr(x, '_as_TensorVariable'):
...@@ -166,11 +166,12 @@ def as_tensor_variable(x, name=None, ndim=None): ...@@ -166,11 +166,12 @@ def as_tensor_variable(x, name=None, ndim=None):
if (x.type.ndim > ndim): if (x.type.ndim > ndim):
# strip off leading broadcastable dimensions # strip off leading broadcastable dimensions
first_non_broadcastable = [idx for idx in range(x.ndim) first_non_broadcastable = [idx for idx in range(x.ndim)
if x.broadcastable[idx] == False][0] if not x.broadcastable[idx]][0]
x = x.dimshuffle(range(x.ndim)[first_non_broadcastable:]) x = x.dimshuffle(range(x.ndim)[first_non_broadcastable:])
if x.ndim > ndim: if x.ndim > ndim:
raise ValueError( raise ValueError(
'TensorType could not be cast to have %i dimensions' % ndim, x.type 'TensorType could not be cast to have %i dimensions'
% ndim, x.type
) )
return x return x
elif (x.type.ndim < ndim): elif (x.type.ndim < ndim):
...@@ -251,9 +252,9 @@ class NumpyAutocaster(object): ...@@ -251,9 +252,9 @@ class NumpyAutocaster(object):
return numpy.asarray(x) return numpy.asarray(x)
elif config.cast_policy == 'numpy+floatX': elif config.cast_policy == 'numpy+floatX':
rval = numpy.asarray(x) rval = numpy.asarray(x)
if (rval.dtype == 'float64' and # numpy wants float64 if ((rval.dtype == 'float64' and # numpy wants float64
config.floatX == 'float32' and # but we prefer float32 config.floatX == 'float32' and # but we prefer float32
not hasattr(x, 'dtype')): # and `x` was not typed not hasattr(x, 'dtype'))): # and `x` was not typed
rval = theano._asarray(rval, dtype='float32') rval = theano._asarray(rval, dtype='float32')
return rval return rval
...@@ -275,9 +276,9 @@ class NumpyAutocaster(object): ...@@ -275,9 +276,9 @@ class NumpyAutocaster(object):
# unsafe downcast of float64 variables when config.floatX == 'float32' # unsafe downcast of float64 variables when config.floatX == 'float32'
# recall: float is numpy.float # recall: float is numpy.float
if (isinstance(x, float) and if ((isinstance(x, float) and
config.floatX in self.dtypes and config.floatX in self.dtypes and
config.floatX == 'float32'): config.floatX == 'float32')):
return theano._asarray(x, dtype='float32') return theano._asarray(x, dtype='float32')
...@@ -313,7 +314,7 @@ class autocast_float_as(object): ...@@ -313,7 +314,7 @@ class autocast_float_as(object):
For example: For example:
>>> with autocast_float_as('float32') as _dummy: >>> with autocast_float_as('float32') as _dummy:
>>> assert (fvector() + 1.1).dtype == 'float32' # temporary downcasting ... assert (fvector() + 1.1).dtype == 'float32' # temporary downcasting
>>> assert (fvector() + 1.1).dtype == 'float64' # back to default behaviour >>> assert (fvector() + 1.1).dtype == 'float64' # back to default behaviour
This class might be convenient in some code, but it definitely This class might be convenient in some code, but it definitely
...@@ -407,17 +408,17 @@ def constant_or_value(x, rtype, name=None, ndim=None, dtype=None): ...@@ -407,17 +408,17 @@ def constant_or_value(x, rtype, name=None, ndim=None, dtype=None):
raise TypeError("Could not convert %s to TensorType" % x, type(x)) raise TypeError("Could not convert %s to TensorType" % x, type(x))
constant_cache = {}
def constant(x, name=None, ndim=None, dtype=None): def constant(x, name=None, ndim=None, dtype=None):
ret = constant_or_value(x, rtype=TensorConstant, name=name, ndim=ndim, ret = constant_or_value(x, rtype=TensorConstant, name=name, ndim=ndim,
dtype=dtype) dtype=dtype)
#We create a small cache of frequently used constant. # We create a small cache of frequently used constant.
#This speed up the Merge optimization for big graph. # This speed up the Merge optimization for big graph.
#We want to cache all scalar to don't merge as frequently constants. # We want to cache all scalar to don't merge as frequently constants.
#But we don't want to cache too much stuff # But we don't want to cache too much stuff
#So we cache integer with dtype [u]int and float where the value is between -10 and 10 # So we cache integer with dtype [u]int and float where the value is
#We want to cache all broadcast pattern for scalar. # between -10 and 10
# We want to cache all broadcast pattern for scalar.
if not constant.enable: if not constant.enable:
return ret return ret
sig = ret.signature() sig = ret.signature()
...@@ -431,6 +432,7 @@ def constant(x, name=None, ndim=None, dtype=None): ...@@ -431,6 +432,7 @@ def constant(x, name=None, ndim=None, dtype=None):
return constant_cache.get(sig, ret) return constant_cache.get(sig, ret)
constant.enable = True constant.enable = True
constant_cache = {}
def _obj_is_wrappable_as_tensor(x): def _obj_is_wrappable_as_tensor(x):
...@@ -520,8 +522,9 @@ def numpy_scalar(data): ...@@ -520,8 +522,9 @@ def numpy_scalar(data):
""" """
# handle case where data is numpy.array([]) # handle case where data is numpy.array([])
if data.ndim > 0 and (len(data.shape) == 0 or if (data.ndim > 0 and
__builtins__['max'](data.shape) == 0): (len(data.shape) == 0 or
__builtins__['max'](data.shape) == 0)):
assert numpy.all(numpy.array([]) == data) assert numpy.all(numpy.array([]) == data)
raise EmptyConstantError() raise EmptyConstantError()
try: try:
...@@ -539,6 +542,8 @@ get_scalar_constant_value_elemwises = ( ...@@ -539,6 +542,8 @@ get_scalar_constant_value_elemwises = (
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.Minimum, scal.Maximum) scal.IntDiv, scal.TrueDiv, scal.Minimum, scal.Maximum)
def get_scalar_constant_value(orig_v, elemwise=True): 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`
...@@ -557,8 +562,8 @@ def get_scalar_constant_value(orig_v, elemwise=True): ...@@ -557,8 +562,8 @@ def get_scalar_constant_value(orig_v, elemwise=True):
v = orig_v v = orig_v
while True: while True:
if v is None: if v is None:
# None is not a scalar (and many uses of this function seem to depend # None is not a scalar (and many uses of this function seem
# on passing it None) # to depend on passing it None)
raise NotScalarConstantError() raise NotScalarConstantError()
if isinstance(v, (numpy.integer, int, float)): if isinstance(v, (numpy.integer, int, float)):
...@@ -591,7 +596,7 @@ def get_scalar_constant_value(orig_v, elemwise=True): ...@@ -591,7 +596,7 @@ def get_scalar_constant_value(orig_v, elemwise=True):
elif isinstance(v.owner.op, scal.ScalarOp): elif isinstance(v.owner.op, scal.ScalarOp):
if isinstance(v.owner.op, scal.Second): if isinstance(v.owner.op, scal.Second):
# We don't need both input to be constant for second # We don't need both input to be constant for second
shape, val = v.owner.inputs shp, val = v.owner.inputs
v = val v = val
continue continue
if isinstance(v.owner.op, get_scalar_constant_value_elemwises): if isinstance(v.owner.op, get_scalar_constant_value_elemwises):
...@@ -603,16 +608,18 @@ def get_scalar_constant_value(orig_v, elemwise=True): ...@@ -603,16 +608,18 @@ def get_scalar_constant_value(orig_v, elemwise=True):
elif elemwise and isinstance(v.owner.op, Elemwise): elif elemwise and isinstance(v.owner.op, Elemwise):
if isinstance(v.owner.op.scalar_op, scal.Second): if isinstance(v.owner.op.scalar_op, scal.Second):
# We don't need both input to be constant for second # We don't need both input to be constant for second
shape, val = v.owner.inputs shp, val = v.owner.inputs
v = val v = val
continue continue
elif isinstance(v.owner.op.scalar_op, elif isinstance(v.owner.op.scalar_op,
get_scalar_constant_value_elemwises): get_scalar_constant_value_elemwises):
const = [get_scalar_constant_value(i) for i in v.owner.inputs] const = [get_scalar_constant_value(i)
for i in v.owner.inputs]
ret = [[None]] ret = [[None]]
v.owner.op.perform(v.owner, const, ret) v.owner.op.perform(v.owner, const, ret)
return ret[0][0] return ret[0][0]
elif isinstance(v.owner.op, theano.tensor.subtensor.Subtensor) and v.ndim == 0: elif (isinstance(v.owner.op, theano.tensor.subtensor.Subtensor)
and v.ndim == 0):
if isinstance(v.owner.inputs[0], TensorConstant): if isinstance(v.owner.inputs[0], TensorConstant):
cdata = tuple(v.owner.op.get_constant_idx(v.owner.inputs)) cdata = tuple(v.owner.op.get_constant_idx(v.owner.inputs))
try: try:
...@@ -628,21 +635,22 @@ def get_scalar_constant_value(orig_v, elemwise=True): ...@@ -628,21 +635,22 @@ def get_scalar_constant_value(orig_v, elemwise=True):
# TODO: implement the case where we take a scalar in a matrix # TODO: implement the case where we take a scalar in a matrix
assert len(v.owner.op.idx_list) == v.owner.inputs[0].ndim assert len(v.owner.op.idx_list) == v.owner.inputs[0].ndim
# Needed to make better graph in this test in theano/tensor/tests: # Needed to make better graph in this test in
# test_sharedvar.py:test_shared_options.test_specify_shape_partial # theano/tensor/tests/test_sharedvar.py:
if (v.owner.inputs[0].owner and # test_shared_options.test_specify_shape_partial
if ((v.owner.inputs[0].owner and
isinstance(v.owner.inputs[0].owner.op, Join) and isinstance(v.owner.inputs[0].owner.op, Join) and
len(v.owner.op.idx_list) == 1): len(v.owner.op.idx_list) == 1)):
# Ensure the Join is joining only scalar variables (so that # Ensure the Join is joining only scalar variables (so that
# the constant value can be found at the same index as the one # the constant value can be found at the same index as the
# used in the sub-tensor). # one used in the sub-tensor).
if python_all(var.ndim == 0 for var in if python_all(var.ndim == 0 for var in
v.owner.inputs[0].owner.inputs[1:]): v.owner.inputs[0].owner.inputs[1:]):
idx = v.owner.op.idx_list[0] idx = v.owner.op.idx_list[0]
if isinstance(idx, gof.Type): if isinstance(idx, gof.Type):
idx = get_scalar_constant_value(v.owner.inputs[1]) idx = get_scalar_constant_value(v.owner.inputs[1])
# Note the '+ 1' is because the first argument to Join is the # Note the '+ 1' is because the first argument to Join
# axis. # is the axis.
ret = v.owner.inputs[0].owner.inputs[idx + 1] ret = v.owner.inputs[0].owner.inputs[idx + 1]
ret = get_scalar_constant_value(ret) ret = get_scalar_constant_value(ret)
# join can cast implicitly its input in some case. # join can cast implicitly its input in some case.
...@@ -658,7 +666,8 @@ def get_scalar_constant_value(orig_v, elemwise=True): ...@@ -658,7 +666,8 @@ def get_scalar_constant_value(orig_v, elemwise=True):
for joined in v.owner.inputs[0].owner.inputs[1:]: for joined in v.owner.inputs[0].owner.inputs[1:]:
ll = get_vector_length(joined) ll = get_vector_length(joined)
if idx < length + ll: if idx < length + ll:
return get_scalar_constant_value(joined[idx-length]) return get_scalar_constant_value(
joined[idx - length])
length += ll length += ll
except TypeError: except TypeError:
pass pass
...@@ -673,6 +682,7 @@ def get_scalar_constant_value(orig_v, elemwise=True): ...@@ -673,6 +682,7 @@ def get_scalar_constant_value(orig_v, elemwise=True):
python_all(var.ndim == 0 for var in python_all(var.ndim == 0 for var in
v.owner.inputs[0].owner.inputs) and v.owner.inputs[0].owner.inputs) and
len(v.owner.op.idx_list) == 1): len(v.owner.op.idx_list) == 1):
idx = v.owner.op.idx_list[0] idx = v.owner.op.idx_list[0]
if isinstance(idx, gof.Type): if isinstance(idx, gof.Type):
idx = get_scalar_constant_value(v.owner.inputs[1]) idx = get_scalar_constant_value(v.owner.inputs[1])
...@@ -1039,7 +1049,8 @@ class ScalarFromTensor(Op): ...@@ -1039,7 +1049,8 @@ class ScalarFromTensor(Op):
assert t.type.broadcastable == () assert t.type.broadcastable == ()
return Apply(self, return Apply(self,
[t], [t],
[scal.get_scalar_type(dtype=t.type.dtype).make_variable()]) [scal.get_scalar_type(dtype=t.type.dtype).make_variable()]
)
def perform(self, node, inp, out_): def perform(self, node, inp, out_):
s, = inp s, = inp
...@@ -1235,7 +1246,8 @@ class MaxAndArgmax(Op): ...@@ -1235,7 +1246,8 @@ class MaxAndArgmax(Op):
elif isinstance(axis, Variable): elif isinstance(axis, Variable):
if not isinstance(axis, TensorConstant): if not isinstance(axis, TensorConstant):
raise TypeError("MaxAndArgmax needs a constant axis") raise TypeError("MaxAndArgmax needs a constant axis")
assert axis.dtype.startswith("int") or axis.dtype.startswith("uint") assert (axis.dtype.startswith("int")
or axis.dtype.startswith("uint"))
axis = int(axis.data) axis = int(axis.data)
# we make the axis all positive to make the infer_shape work # we make the axis all positive to make the infer_shape work
# with negative axis # with negative axis
...@@ -1389,7 +1401,8 @@ class MaxAndArgmax(Op): ...@@ -1389,7 +1401,8 @@ class MaxAndArgmax(Op):
if g_max_disconnected and g_max_idx_disconnected: if g_max_disconnected and g_max_idx_disconnected:
return [DisconnectedType()(), DisconnectedType()()] return [DisconnectedType()(), DisconnectedType()()]
axis_grad = grad_undefined(self, 1, axis, axis_grad = grad_undefined(
self, 1, axis,
"argmax is not defined for non-integer axes so" "argmax is not defined for non-integer axes so"
" argmax(x, axis+eps) is undefined") " argmax(x, axis+eps) is undefined")
...@@ -1449,7 +1462,8 @@ def makeKeepDims(x, y, axis): ...@@ -1449,7 +1462,8 @@ def makeKeepDims(x, y, axis):
newaxis = [] newaxis = []
for a in axis: for a in axis:
if not isinstance(a, int): if not isinstance(a, int):
raise ValueError("keepdims option can be used only with constant axis") raise ValueError(
"keepdims option can be used only with constant axis")
if a < 0: if a < 0:
a += x.type.ndim a += x.type.ndim
newaxis.append(a) newaxis.append(a)
...@@ -1931,6 +1945,7 @@ def gammaln(a): ...@@ -1931,6 +1945,7 @@ def gammaln(a):
def psi(a): def psi(a):
"""derivative of log gamma function""" """derivative of log gamma function"""
@_scal_elemwise @_scal_elemwise
def chi2sf(x, k): def chi2sf(x, k):
"""chi squared survival function""" """chi squared survival function"""
...@@ -2001,26 +2016,26 @@ def zeros_like(model, dtype=None): ...@@ -2001,26 +2016,26 @@ def zeros_like(model, dtype=None):
return fill(model, constant(0.0, dtype=dtype)) return fill(model, constant(0.0, dtype=dtype))
def zeros(shape, dtype=None): def zeros(shp, dtype=None):
""" """
Create a Tensor filled with zeros, closer to Numpy's syntax than ``alloc``. Create a Tensor filled with zeros, closer to Numpy's syntax than ``alloc``.
""" """
if not isinstance(shape, (list, tuple, TensorVariable)): if not isinstance(shp, (list, tuple, TensorVariable)):
shape = [shape] shp = [shp]
if dtype is None: if dtype is None:
dtype = config.floatX dtype = config.floatX
return alloc(numpy.array(0, dtype=dtype), *shape) return alloc(numpy.array(0, dtype=dtype), *shp)
def ones(shape, dtype=None): def ones(shp, dtype=None):
""" """
Create a Tensor filled with ones, closer to Numpy's syntax than ``alloc``. Create a Tensor filled with ones, closer to Numpy's syntax than ``alloc``.
""" """
if not isinstance(shape, (list, tuple, TensorVariable)): if not isinstance(shp, (list, tuple, TensorVariable)):
shape = [shape] shp = [shp]
if dtype is None: if dtype is None:
dtype = config.floatX dtype = config.floatX
return alloc(numpy.array(1, dtype=dtype), *shape) return alloc(numpy.array(1, dtype=dtype), *shp)
class Nonzero(gof.Op): class Nonzero(gof.Op):
...@@ -2198,7 +2213,9 @@ class Tri(gof.Op): ...@@ -2198,7 +2213,9 @@ class Tri(gof.Op):
N = as_tensor_variable(N) N = as_tensor_variable(N)
M = as_tensor_variable(M) M = as_tensor_variable(M)
k = as_tensor_variable(k) k = as_tensor_variable(k)
return gof.Apply(self, [N, M, k], return gof.Apply(
self,
[N, M, k],
[TensorType(dtype=self.dtype, broadcastable=(False, False))()]) [TensorType(dtype=self.dtype, broadcastable=(False, False))()])
def perform(self, node, inp, out_): def perform(self, node, inp, out_):
...@@ -2307,7 +2324,9 @@ class Eye(gof.Op): ...@@ -2307,7 +2324,9 @@ class Eye(gof.Op):
assert n.ndim == 0 assert n.ndim == 0
assert m.ndim == 0 assert m.ndim == 0
assert k.ndim == 0 assert k.ndim == 0
return gof.Apply(self, [n, m, k], return gof.Apply(
self,
[n, m, k],
[TensorType(dtype=self.dtype, broadcastable=(False, False))()]) [TensorType(dtype=self.dtype, broadcastable=(False, False))()])
def perform(self, node, inp, out_): def perform(self, node, inp, out_):
...@@ -2370,8 +2389,9 @@ class Alloc(gof.Op): ...@@ -2370,8 +2389,9 @@ class Alloc(gof.Op):
Returns an N-dimensional tensor initialized by `value` using something Returns an N-dimensional tensor initialized by `value` using something
equivalent to equivalent to
>>> z = numpy.zeros(shape, value.dtype)
>>> z += value z = numpy.zeros(shape, value.dtype)
z += value
The result has N dimensions, has the dtype of `value` and is obtained by The result has N dimensions, has the dtype of `value` and is obtained by
broadcasting value over the output ndarray. broadcasting value over the output ndarray.
...@@ -2555,16 +2575,17 @@ class Alloc(gof.Op): ...@@ -2555,16 +2575,17 @@ class Alloc(gof.Op):
# If the output is a constant, it will have to be deepcopied # If the output is a constant, it will have to be deepcopied
# each time the function is called. So we do not fold. # each time the function is called. So we do not fold.
return False return False
elif (#The following ops work inplace of their input id 0. elif (
# The following ops work inplace of their input id 0.
client[1] == 0 and client[1] == 0 and
isinstance(client[0].op, ( isinstance(client[0].op, (
#Ops that will work inplace on the Alloc. So if they # Ops that will work inplace on the Alloc. So if they
#get constant_folded, they would copy the # get constant_folded, they would copy the
#constant and this is less efficients. # constant and this is less efficients.
#Not doing the constant folding could also lower # Not doing the constant folding could also lower
#the peak memory usage, as we the "constant" won't # the peak memory usage, as we the "constant" won't
#always exists. # always exists.
theano.tensor.subtensor.IncSubtensor, theano.tensor.subtensor.IncSubtensor,
theano.tensor.subtensor.AdvancedIncSubtensor1, theano.tensor.subtensor.AdvancedIncSubtensor1,
theano.tensor.subtensor.AdvancedIncSubtensor, theano.tensor.subtensor.AdvancedIncSubtensor,
...@@ -2572,8 +2593,7 @@ class Alloc(gof.Op): ...@@ -2572,8 +2593,7 @@ class Alloc(gof.Op):
theano.tensor.blas_c.CGemv, theano.tensor.blas_c.CGemv,
theano.tensor.blas.Ger, theano.tensor.blas.Ger,
theano.tensor.blas_c.CGer, theano.tensor.blas_c.CGer,
theano.tensor.blas_scipy.ScipyGer theano.tensor.blas_scipy.ScipyGer))):
))):
return False return False
#If the clients is a transfer to the GPU, we don't want to #If the clients is a transfer to the GPU, we don't want to
#fold. We let the Alloc being moved to the GPU, then we #fold. We let the Alloc being moved to the GPU, then we
...@@ -2951,8 +2971,8 @@ def ceil_intdiv(a, b): ...@@ -2951,8 +2971,8 @@ def ceil_intdiv(a, b):
def mod_check(x, y): def mod_check(x, y):
"""Make sure we do not try to use complex numbers.""" """Make sure we do not try to use complex numbers."""
if (as_tensor_variable(x).dtype in complex_dtypes or if ((as_tensor_variable(x).dtype in complex_dtypes or
as_tensor_variable(y).dtype in complex_dtypes): as_tensor_variable(y).dtype in complex_dtypes)):
# Currently forbidden. # Currently forbidden.
raise scal.Mod.complex_error raise scal.Mod.complex_error
else: else:
...@@ -3006,8 +3026,8 @@ def extract_constant(x, elemwise=True): ...@@ -3006,8 +3026,8 @@ def extract_constant(x, elemwise=True):
x = get_scalar_constant_value(x, elemwise=elemwise) 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
isinstance(x, scal.sharedvar.ScalarSharedVariable)): isinstance(x, scal.sharedvar.ScalarSharedVariable))):
if x.owner and isinstance(x.owner.op, ScalarFromTensor): if x.owner and isinstance(x.owner.op, ScalarFromTensor):
x = x.owner.inputs[0] x = x.owner.inputs[0]
else: else:
...@@ -3046,7 +3066,8 @@ def batched_dot(x, y): ...@@ -3046,7 +3066,8 @@ def batched_dot(x, y):
But numpy einsum is slower than dot or tensordot: But numpy einsum is slower than dot or tensordot:
http://mail.scipy.org/pipermail/numpy-discussion/2012-October/064259.html http://mail.scipy.org/pipermail/numpy-discussion/2012-October/064259.html
""" """
result, updates = theano.scan(fn=lambda x_mat, y_mat: result, updates = theano.scan(
fn=lambda x_mat, y_mat:
theano.tensor.dot(x_mat, y_mat), theano.tensor.dot(x_mat, y_mat),
outputs_info=None, outputs_info=None,
sequences=[x, y], sequences=[x, y],
...@@ -3085,10 +3106,13 @@ def batched_tensordot(x, y, axes=2): ...@@ -3085,10 +3106,13 @@ def batched_tensordot(x, y, axes=2):
axes = numpy.asarray(axes) axes = numpy.asarray(axes)
else: else:
axes = axes.copy() axes = axes.copy()
assert numpy.greater(axes,0).all(), "All axes should be greater than one, as the first axis is iterated over (batch-wise scan)" assert numpy.greater(axes, 0).all(), (
"All axes should be greater than one, as the "
"first axis is iterated over (batch-wise scan)")
axes -= 1 axes -= 1
result, updates = theano.scan(fn=lambda x_mat, y_mat: result, updates = theano.scan(
fn=lambda x_mat, y_mat:
theano.tensor.tensordot(x_mat, y_mat, axes), theano.tensor.tensordot(x_mat, y_mat, axes),
outputs_info=None, outputs_info=None,
sequences=[x, y], sequences=[x, y],
...@@ -3327,8 +3351,8 @@ class Join(Op): ...@@ -3327,8 +3351,8 @@ class Join(Op):
output_maker = lambda bcastable: tensor(dtype=out_dtype, output_maker = lambda bcastable: tensor(dtype=out_dtype,
broadcastable=bcastable) broadcastable=bcastable)
return self._make_node_internal(axis, tensors, return self._make_node_internal(
as_tensor_variable_args, output_maker) axis, tensors, as_tensor_variable_args, output_maker)
def _make_node_internal(self, axis, tensors, def _make_node_internal(self, axis, tensors,
as_tensor_variable_args, output_maker): as_tensor_variable_args, output_maker):
...@@ -3387,7 +3411,8 @@ class Join(Op): ...@@ -3387,7 +3411,8 @@ class Join(Op):
if not python_all([x.ndim == len(bcastable) if not python_all([x.ndim == len(bcastable)
for x in as_tensor_variable_args[1:]]): for x in as_tensor_variable_args[1:]]):
raise TypeError("Join() can only join tensor with the same number of dimensions.") raise TypeError("Join() can only join tensors with the same "
"number of dimensions.")
inputs = [as_tensor_variable(axis)] + list(as_tensor_variable_args) inputs = [as_tensor_variable(axis)] + list(as_tensor_variable_args)
if inputs[0].type not in int_types: if inputs[0].type not in int_types:
...@@ -3617,8 +3642,8 @@ def stack(*tensors): ...@@ -3617,8 +3642,8 @@ def stack(*tensors):
# And DebugMode can't detect error in this code as it is not in an # And DebugMode can't detect error in this code as it is not in an
# optimization. # optimization.
# See ticket #660 # See ticket #660
if numpy.all([ if numpy.all(
# in case there is direct int in tensors. [ # in case there is direct int in tensors.
isinstance(t, (numpy.number, float, int, python_complex, isinstance(t, (numpy.number, float, int, python_complex,
long)) or long)) or
(isinstance(t, Variable) and (isinstance(t, Variable) and
...@@ -3649,7 +3674,8 @@ def concatenate(tensor_list, axis=0): ...@@ -3649,7 +3674,8 @@ def concatenate(tensor_list, axis=0):
# instead of # instead of
# c = concatenate((x, y)) # c = concatenate((x, y))
if not isinstance(tensor_list, (tuple, list)): if not isinstance(tensor_list, (tuple, list)):
raise TypeError("The 'tensors' argument must be either a tuple " raise TypeError(
"The 'tensors' argument must be either a tuple "
"or a list, make sure you did not forget () or [] around " "or a list, make sure you did not forget () or [] around "
"arguments of concatenate.", tensor_list) "arguments of concatenate.", tensor_list)
return join(axis, *tensor_list) return join(axis, *tensor_list)
...@@ -3682,10 +3708,10 @@ def get_vector_length(v): ...@@ -3682,10 +3708,10 @@ def get_vector_length(v):
if v.owner and isinstance(v.owner.op, Shape): if v.owner and isinstance(v.owner.op, Shape):
return v.owner.inputs[0].type.ndim return v.owner.inputs[0].type.ndim
# If we take this slice: var[:0], we know it will have 0 elements. # If we take this slice: var[:0], we know it will have 0 elements.
if (v.owner and if ((v.owner and
isinstance(v.owner.op, theano.tensor.subtensor.Subtensor) and isinstance(v.owner.op, theano.tensor.subtensor.Subtensor) and
isinstance(v.owner.op.idx_list[0], slice) and isinstance(v.owner.op.idx_list[0], slice) and
v.owner.op.idx_list[0].start in [None, 0]): v.owner.op.idx_list[0].start in [None, 0])):
stop = theano.tensor.subtensor.get_idx_list( stop = theano.tensor.subtensor.get_idx_list(
v.owner.inputs, v.owner.op.idx_list)[0].stop v.owner.inputs, v.owner.op.idx_list)[0].stop
if extract_constant(stop) == 0: if extract_constant(stop) == 0:
...@@ -3911,7 +3937,8 @@ def reshape(x, newshape, ndim=None, name=None): ...@@ -3911,7 +3937,8 @@ def reshape(x, newshape, ndim=None, name=None):
try: try:
ndim = get_vector_length(newshape) ndim = get_vector_length(newshape)
except ValueError: except ValueError:
raise ValueError("The length of the provided shape (%s) cannot " raise ValueError(
"The length of the provided shape (%s) cannot "
"be automatically determined, so Theano is not able " "be automatically determined, so Theano is not able "
"to know what the number of dimensions of the reshaped " "to know what the number of dimensions of the reshaped "
"variable will be. You can provide the 'ndim' keyword " "variable will be. You can provide the 'ndim' keyword "
...@@ -4231,7 +4258,8 @@ def arange(start, stop=None, step=1, dtype=None): ...@@ -4231,7 +4258,8 @@ def arange(start, stop=None, step=1, dtype=None):
config.floatX == 'float32' and config.floatX == 'float32' and
numpy_dtype == 'float64' and numpy_dtype == 'float64' and
# No explicit float64 in the three arguments? # No explicit float64 in the three arguments?
python_all(dt != 'float64' python_all(
dt != 'float64'
for dt in [s.dtype for s in (start, stop, step)])): for dt in [s.dtype for s in (start, stop, step)])):
# We use float32 instead. # We use float32 instead.
assert dtype != 'float64' assert dtype != 'float64'
...@@ -4283,9 +4311,9 @@ class PermuteRowElements(Op): ...@@ -4283,9 +4311,9 @@ class PermuteRowElements(Op):
assert (y.type.dtype.startswith('int') or assert (y.type.dtype.startswith('int') or
y.type.dtype.startswith('uint')) y.type.dtype.startswith('uint'))
# Inverse should be an integer scalar # Inverse should be an integer scalar
assert inverse.type.ndim == 0 and\ assert (inverse.type.ndim == 0 and
(inverse.type.dtype.startswith('int') or\ (inverse.type.dtype.startswith('int') or
inverse.type.dtype.startswith('uint')) inverse.type.dtype.startswith('uint')))
# Match shapes of x and y # Match shapes of x and y
x_dim = x.type.ndim x_dim = x.type.ndim
...@@ -4571,7 +4599,6 @@ class Dot(Op): ...@@ -4571,7 +4599,6 @@ class Dot(Op):
# R_op for a \dot b evaluted at c for a and d for b is # R_op for a \dot b evaluted at c for a and d for b is
# simply c \dot b + a \dot d # simply c \dot b + a \dot d
assert len(inputs) == 2 assert len(inputs) == 2
assert len(eval_points) == 2 assert len(eval_points) == 2
if eval_points[0] is None and eval_points[1] is None: if eval_points[0] is None and eval_points[1] is None:
...@@ -4599,14 +4626,16 @@ class Dot(Op): ...@@ -4599,14 +4626,16 @@ class Dot(Op):
ev0 = gof.op.get_test_value(eval_points[0]) ev0 = gof.op.get_test_value(eval_points[0])
except AttributeError: except AttributeError:
gof.op.missing_test_message( gof.op.missing_test_message(
'first eval point passed to Dot.R_op has no test value') 'first eval point passed to Dot.R_op '
'has no test value')
debugger_available = False debugger_available = False
if eval_points[1]: if eval_points[1]:
try: try:
ev1 = gof.op.get_test_value(eval_points[1]) ev1 = gof.op.get_test_value(eval_points[1])
except AttributeError: except AttributeError:
gof.op.missing_test_message( gof.op.missing_test_message(
'second eval point passed to Dot.R_op has no test value') 'second eval point passed to Dot.R_op '
'has no test value')
debugger_available = False debugger_available = False
if debugger_available: if debugger_available:
...@@ -4616,11 +4645,10 @@ class Dot(Op): ...@@ -4616,11 +4645,10 @@ class Dot(Op):
for i in xrange(2): for i in xrange(2):
if eval_point_values[i] is not None and \ if eval_point_values[i] is not None and \
input_values[i].shape != eval_point_values[i].shape: input_values[i].shape != eval_point_values[i].shape:
raise ValueError('input ' + str(i) + ' and eval_point ' + raise ValueError(
str(i) + ' to Dot.R_op ' 'input ' + str(i) + ' and eval_point ' + str(i)
'should have the ' + ' to Dot.R_op should have the same shape, but '
'same shape, but their shapes are' 'their shapes are %s and %s, respectively' % (
' %s and %s, respectively' % (
str(input_values[i].shape), str(input_values[i].shape),
str(eval_point_values[i].shape))) str(eval_point_values[i].shape)))
if eval_points[0]: if eval_points[0]:
...@@ -4888,8 +4916,9 @@ def tensordot(a, b, axes=2): ...@@ -4888,8 +4916,9 @@ def tensordot(a, b, axes=2):
a_order = (tuple(x for x in tuple(xrange(a.ndim)) if x not in a_axes) a_order = (tuple(x for x in tuple(xrange(a.ndim)) if x not in a_axes)
+ a_axes) + a_axes)
b_order = (b_axes b_order = (b_axes + tuple(x
+ tuple(x for x in tuple(xrange(b.ndim)) if x not in b_axes)) for x in tuple(xrange(b.ndim))
if x not in b_axes))
a_shuffled = a.dimshuffle(a_order) a_shuffled = a.dimshuffle(a_order)
b_shuffled = b.dimshuffle(b_order) b_shuffled = b.dimshuffle(b_order)
...@@ -5082,7 +5111,7 @@ def ptp(a, axis=None): ...@@ -5082,7 +5111,7 @@ def ptp(a, axis=None):
def power(x, y): def power(x, y):
return x**y return x ** y
def swapaxes(y, axis1, axis2): def swapaxes(y, axis1, axis2):
...@@ -5098,25 +5127,48 @@ def choose(a, choices, out=None, mode='raise'): ...@@ -5098,25 +5127,48 @@ def choose(a, choices, out=None, mode='raise'):
""" """
Construct an array from an index array and a set of arrays to choose from. Construct an array from an index array and a set of arrays to choose from.
First of all, if confused or uncertain, definitely look at the Examples - in its full generality, this function is less simple than it might seem from the following code description (below ndi = numpy.lib.index_tricks): First of all, if confused or uncertain, definitely look at the Examples -
in its full generality, this function is less simple than it might seem
from the following code description (below ndi = numpy.lib.index_tricks):
np.choose(a,c) == np.array([c[a[I]][I] for I in ndi.ndindex(a.shape)]). np.choose(a,c) == np.array([c[a[I]][I] for I in ndi.ndindex(a.shape)]).
But this omits some subtleties. Here is a fully general summary: But this omits some subtleties. Here is a fully general summary:
Given an ``index`` array (a) of integers and a sequence of n arrays (choices), a and each choice array are first broadcast, as necessary, to arrays of a common shape; calling these Ba and Bchoices[i], i = 0,...,n-1 we have that, necessarily, Ba.shape == Bchoices[i].shape for each i. Then, a new array with shape Ba.shape is created as follows: Given an ``index`` array (a) of integers and a sequence of n arrays
(choices), a and each choice array are first broadcast, as necessary,
if mode=raise (the default), then, first of all, each element of a (and thus Ba) must be in the range [0, n-1]; now, suppose that i (in that range) is the value at the (j0, j1, ..., jm) position in Ba - then the value at the same position in the new array is the value in Bchoices[i] at that same position; to arrays of a common shape; calling these Ba and
if mode=wrap, values in a (and thus Ba) may be any (signed) integer; modular arithmetic is used to map integers outside the range [0, n-1] back into that range; and then the new array is constructed as above; Bchoices[i], i = 0,...,n-1 we have that, necessarily,
if mode=clip, values in a (and thus Ba) may be any (signed) integer; negative integers are mapped to 0; values greater than n-1 are mapped to n-1; and then the new array is constructed as above. Ba.shape == Bchoices[i].shape for each i.
Then, a new array with shape Ba.shape is created as follows:
:Parameters: *a* - int array
This array must contain integers in [0, n-1], where n is the number of choices, unless mode=wrap or mode=clip, in which cases any integers are permissible. - if mode=raise (the default), then, first of all, each element of a
:Parameters: *choices* - sequence of arrays (and thus Ba) must be in the range [0, n-1]; now, suppose that
Choice arrays. a and all of the choices must be broadcastable to the same shape. If choices is itself an array (not recommended), then its outermost dimension (i.e., the one corresponding to choices.shape[0]) is taken as defining the ``sequence``. i (in that range) is the value at the (j0, j1, ..., jm) position in Ba -
:Parameters: *out* - array, optional then the value at the same position in the new array is the value in
If provided, the result will be inserted into this array. It should be of the appropriate shape and dtype. Bchoices[i] at that same position;
:Parameters: *mode* - {``raise`` (default), ``wrap``, ``clip``}, optional
- if mode=wrap, values in a (and thus Ba) may be any (signed) integer;
modular arithmetic is used to map integers outside the range [0, n-1]
back into that range; and then the new array is constructed as above;
- if mode=clip, values in a (and thus Ba) may be any (signed) integer;
negative integers are mapped to 0; values greater than n-1 are mapped
to n-1; and then the new array is constructed as above.
:Parameter: *a* - int array
This array must contain integers in [0, n-1], where n is the number of
choices, unless mode=wrap or mode=clip, in which cases any integers
are permissible.
:Parameter: *choices* - sequence of arrays
Choice arrays. a and all of the choices must be broadcastable to
the same shape. If choices is itself an array (not recommended),
then its outermost dimension (i.e., the one corresponding to
choices.shape[0]) is taken as defining the ``sequence``.
:Parameter: *out* - array, optional
If provided, the result will be inserted into this array.
It should be of the appropriate shape and dtype.
:Parameter: *mode* - {``raise`` (default), ``wrap``, ``clip``}, optional
Specifies how indices outside [0, n-1] will be treated: Specifies how indices outside [0, n-1] will be treated:
``raise`` : an exception is raised ``raise`` : an exception is raised
``wrap`` : value becomes value mod n ``wrap`` : value becomes value mod n
...@@ -5145,17 +5197,18 @@ class Choose(Op): ...@@ -5145,17 +5197,18 @@ class Choose(Op):
return[(shapes[0])] return[(shapes[0])]
else: else:
import theano.typed_list import theano.typed_list
assert isinstance(node.inputs[1], theano.typed_list.TypedListVariable) assert isinstance(node.inputs[1],
theano.typed_list.TypedListVariable)
raise ShapeError("Case not implemented") raise ShapeError("Case not implemented")
shape = shapes[0] shape = shapes[0]
for i in range(len(shapes[0])-1): for i in range(len(shapes[0]) - 1):
shape[i] = shapes[1][i] shape[i] = shapes[1][i]
return [(shape)] return [(shape)]
def make_node(self, a, choices): def make_node(self, a, choices):
# Import here as it isn't imported by default and we can't # Import here as it isn't imported by default and we can't
# import at the top as it would cause circular import. # import at the top as it would cause circular import.
from theano import typed_list import theano.typed_list
a = as_tensor_variable(a) a = as_tensor_variable(a)
if isinstance(choices, (tuple, list)): if isinstance(choices, (tuple, list)):
choice = theano.typed_list.make_list(choices) choice = theano.typed_list.make_list(choices)
......
...@@ -1650,8 +1650,7 @@ def test_local_useless_subtensor(): ...@@ -1650,8 +1650,7 @@ def test_local_useless_subtensor():
#theano.printing.debugprint(f) #theano.printing.debugprint(f)
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.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:
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论