提交 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:
acceptable_ops = (theano.tensor.basic.Dot,
theano.tensor.basic.Reshape,
theano.tensor.basic.Shape,
theano.tensor.basic.SpecifyShape,
theano.tensor.SpecifyShape,
theano.tensor.basic.MaxAndArgmax,
theano.tensor.Subtensor,
theano.tensor.IncSubtensor,
......
......@@ -65,3 +65,6 @@ from theano.tensor.sort import sort, argsort
from theano.tensor.extra_ops import (DiffOp, bincount, squeeze,
repeat, bartlett, fill_diagonal, fill_diagonal_offset,
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
from itertools import izip
import numpy
from copy import copy as python_copy
import theano
from theano.configparser import config
......@@ -26,7 +25,7 @@ from theano.gof.utils import hashtype
from theano import compile, printing
from theano.printing import pprint, min_informative_str
#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.
......@@ -138,7 +137,8 @@ def as_tensor_variable(x, name=None, ndim=None):
:Exceptions:
- `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'):
......@@ -166,11 +166,12 @@ def as_tensor_variable(x, name=None, ndim=None):
if (x.type.ndim > ndim):
# strip off leading broadcastable dimensions
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:])
if x.ndim > ndim:
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
elif (x.type.ndim < ndim):
......@@ -251,9 +252,9 @@ class NumpyAutocaster(object):
return numpy.asarray(x)
elif config.cast_policy == 'numpy+floatX':
rval = numpy.asarray(x)
if (rval.dtype == 'float64' and # numpy wants float64
config.floatX == 'float32' and # but we prefer float32
not hasattr(x, 'dtype')): # and `x` was not typed
if ((rval.dtype == 'float64' and # numpy wants float64
config.floatX == 'float32' and # but we prefer float32
not hasattr(x, 'dtype'))): # and `x` was not typed
rval = theano._asarray(rval, dtype='float32')
return rval
......@@ -275,9 +276,9 @@ class NumpyAutocaster(object):
# unsafe downcast of float64 variables when config.floatX == 'float32'
# recall: float is numpy.float
if (isinstance(x, float) and
config.floatX in self.dtypes and
config.floatX == 'float32'):
if ((isinstance(x, float) and
config.floatX in self.dtypes and
config.floatX == 'float32')):
return theano._asarray(x, dtype='float32')
......@@ -313,7 +314,7 @@ class autocast_float_as(object):
For example:
>>> 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
This class might be convenient in some code, but it definitely
......@@ -395,9 +396,9 @@ def constant_or_value(x, rtype, name=None, ndim=None, dtype=None):
try:
if rtype is TensorConstant:
rval = rtype(
TensorType(dtype=x_.dtype, broadcastable=bcastable),
x_.copy(),
name=name)
TensorType(dtype=x_.dtype, broadcastable=bcastable),
x_.copy(),
name=name)
return rval
else:
# leave the shape out of the type
......@@ -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))
constant_cache = {}
def constant(x, name=None, ndim=None, dtype=None):
ret = constant_or_value(x, rtype=TensorConstant, name=name, ndim=ndim,
dtype=dtype)
#We create a small cache of frequently used constant.
#This speed up the Merge optimization for big graph.
#We want to cache all scalar to don't merge as frequently constants.
#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
#We want to cache all broadcast pattern for scalar.
dtype=dtype)
# We create a small cache of frequently used constant.
# This speed up the Merge optimization for big graph.
# We want to cache all scalar to don't merge as frequently constants.
# 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
# We want to cache all broadcast pattern for scalar.
if not constant.enable:
return ret
sig = ret.signature()
......@@ -431,6 +432,7 @@ def constant(x, name=None, ndim=None, dtype=None):
return constant_cache.get(sig, ret)
constant.enable = True
constant_cache = {}
def _obj_is_wrappable_as_tensor(x):
......@@ -520,8 +522,9 @@ def numpy_scalar(data):
"""
# handle case where data is numpy.array([])
if data.ndim > 0 and (len(data.shape) == 0 or
__builtins__['max'](data.shape) == 0):
if (data.ndim > 0 and
(len(data.shape) == 0 or
__builtins__['max'](data.shape) == 0)):
assert numpy.all(numpy.array([]) == data)
raise EmptyConstantError()
try:
......@@ -539,6 +542,8 @@ get_scalar_constant_value_elemwises = (
scal.LT, scal.GT, scal.LE, scal.GE,
scal.Sub, scal.Add, scal.Mod, scal.Mul,
scal.IntDiv, scal.TrueDiv, scal.Minimum, scal.Maximum)
def get_scalar_constant_value(orig_v, elemwise=True):
"""return the constant scalar(0-D) value underlying variable `v`
......@@ -557,8 +562,8 @@ def get_scalar_constant_value(orig_v, elemwise=True):
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)
# None is not a scalar (and many uses of this function seem
# to depend on passing it None)
raise NotScalarConstantError()
if isinstance(v, (numpy.integer, int, float)):
......@@ -591,7 +596,7 @@ def get_scalar_constant_value(orig_v, elemwise=True):
elif isinstance(v.owner.op, scal.ScalarOp):
if isinstance(v.owner.op, scal.Second):
# We don't need both input to be constant for second
shape, val = v.owner.inputs
shp, val = v.owner.inputs
v = val
continue
if isinstance(v.owner.op, get_scalar_constant_value_elemwises):
......@@ -603,46 +608,49 @@ def get_scalar_constant_value(orig_v, elemwise=True):
elif elemwise and isinstance(v.owner.op, Elemwise):
if isinstance(v.owner.op.scalar_op, scal.Second):
# We don't need both input to be constant for second
shape, val = v.owner.inputs
shp, val = v.owner.inputs
v = val
continue
elif isinstance(v.owner.op.scalar_op,
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]]
v.owner.op.perform(v.owner, const, ret)
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):
cdata = tuple(v.owner.op.get_constant_idx(v.owner.inputs))
try:
return v.owner.inputs[0].data.__getitem__(cdata)
except IndexError:
raise IndexError(
str(tuple(v.owner.op.idx_list)) +
" is not a valid index into " +
str(v.owner.inputs[0].data))
str(tuple(v.owner.op.idx_list)) +
" is not a valid index into " +
str(v.owner.inputs[0].data))
# The index list 'idx_list' should have length the same
# shape as the input.
# TODO: implement the case where we take a scalar in a matrix
assert len(v.owner.op.idx_list) == v.owner.inputs[0].ndim
# Needed to make better graph in this test in theano/tensor/tests:
# test_sharedvar.py:test_shared_options.test_specify_shape_partial
if (v.owner.inputs[0].owner and
isinstance(v.owner.inputs[0].owner.op, Join) and
len(v.owner.op.idx_list) == 1):
# Needed to make better graph in this test in
# theano/tensor/tests/test_sharedvar.py:
# test_shared_options.test_specify_shape_partial
if ((v.owner.inputs[0].owner and
isinstance(v.owner.inputs[0].owner.op, Join) and
len(v.owner.op.idx_list) == 1)):
# Ensure the Join is joining only scalar variables (so that
# the constant value can be found at the same index as the one
# used in the sub-tensor).
# the constant value can be found at the same index as the
# one used in the sub-tensor).
if python_all(var.ndim == 0 for var in
v.owner.inputs[0].owner.inputs[1:]):
idx = v.owner.op.idx_list[0]
if isinstance(idx, gof.Type):
idx = get_scalar_constant_value(v.owner.inputs[1])
# Note the '+ 1' is because the first argument to Join is the
# axis.
# Note the '+ 1' is because the first argument to Join
# is the axis.
ret = v.owner.inputs[0].owner.inputs[idx + 1]
ret = get_scalar_constant_value(ret)
# join can cast implicitly its input in some case.
......@@ -658,7 +666,8 @@ def get_scalar_constant_value(orig_v, elemwise=True):
for joined in v.owner.inputs[0].owner.inputs[1:]:
ll = get_vector_length(joined)
if idx < length + ll:
return get_scalar_constant_value(joined[idx-length])
return get_scalar_constant_value(
joined[idx - length])
length += ll
except TypeError:
pass
......@@ -666,13 +675,14 @@ def get_scalar_constant_value(orig_v, elemwise=True):
pass
elif (v.owner.inputs[0].owner and
isinstance(v.owner.inputs[0].owner.op,
theano.tensor.opt.MakeVector) and
# MakeVector normally accept only scalar as input.
# We put this check in case there is change in the future
python_all(var.ndim == 0 for var in
v.owner.inputs[0].owner.inputs) and
len(v.owner.op.idx_list) == 1):
isinstance(v.owner.inputs[0].owner.op,
theano.tensor.opt.MakeVector) and
# MakeVector normally accept only scalar as input.
# We put this check in case there is change in the future
python_all(var.ndim == 0 for var in
v.owner.inputs[0].owner.inputs) and
len(v.owner.op.idx_list) == 1):
idx = v.owner.op.idx_list[0]
if isinstance(idx, gof.Type):
idx = get_scalar_constant_value(v.owner.inputs[1])
......@@ -773,7 +783,7 @@ def scalar(name=None, dtype=None):
return type(name)
scalars, fscalars, dscalars, iscalars, lscalars = _multi(
scalar, fscalar, dscalar, iscalar, lscalar)
scalar, fscalar, dscalar, iscalar, lscalar)
int_types = bscalar, wscalar, iscalar, lscalar
float_types = fscalar, dscalar
......@@ -803,7 +813,7 @@ def vector(name=None, dtype=None):
return type(name)
vectors, fvectors, dvectors, ivectors, lvectors = _multi(
vector, fvector, dvector, ivector, lvector)
vector, fvector, dvector, ivector, lvector)
int_vector_types = bvector, wvector, ivector, lvector
float_vector_types = fvector, dvector
......@@ -830,7 +840,7 @@ def matrix(name=None, dtype=None):
return type(name)
matrices, fmatrices, dmatrices, imatrices, lmatrices = _multi(
matrix, fmatrix, dmatrix, imatrix, lmatrix)
matrix, fmatrix, dmatrix, imatrix, lmatrix)
int_matrix_types = bmatrix, wmatrix, imatrix, lmatrix
float_matrix_types = fmatrix, dmatrix
......@@ -899,7 +909,7 @@ def tensor3(name=None, dtype=None):
return type(name)
tensor3s, ftensor3s, dtensor3s, itensor3s, ltensor3s = _multi(
tensor3, ftensor3, dtensor3, itensor3, ltensor3)
tensor3, ftensor3, dtensor3, itensor3, ltensor3)
ctensor4 = TensorType('complex64', ((False,) * 4))
ztensor4 = TensorType('complex128', ((False,) * 4))
......@@ -921,7 +931,7 @@ def tensor4(name=None, dtype=None):
type = TensorType(dtype, (False, False, False, False))
return type(name)
tensor4s, ftensor4s, dtensor4s, itensor4s, ltensor4s = _multi(
tensor4, ftensor4, dtensor4, itensor4, ltensor4)
tensor4, ftensor4, dtensor4, itensor4, ltensor4)
Tensor = TensorType
......@@ -1039,7 +1049,8 @@ class ScalarFromTensor(Op):
assert t.type.broadcastable == ()
return Apply(self,
[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_):
s, = inp
......@@ -1091,66 +1102,66 @@ def _conversion(real_value, name):
# `cast()` function below.
_convert_to_int8 = _conversion(
elemwise.Elemwise(scal.convert_to_int8), 'int8')
elemwise.Elemwise(scal.convert_to_int8), 'int8')
"""Cast to 8-bit integer"""
_convert_to_int16 = _conversion(
elemwise.Elemwise(scal.convert_to_int16), 'int16')
elemwise.Elemwise(scal.convert_to_int16), 'int16')
"""Cast to 16-bit integer"""
_convert_to_int32 = _conversion(
elemwise.Elemwise(scal.convert_to_int32), 'int32')
elemwise.Elemwise(scal.convert_to_int32), 'int32')
"""Cast to 32-bit integer"""
_convert_to_int64 = _conversion(
elemwise.Elemwise(scal.convert_to_int64), 'int64')
elemwise.Elemwise(scal.convert_to_int64), 'int64')
"""Cast to 64-bit integer"""
_convert_to_uint8 = _conversion(
elemwise.Elemwise(scal.convert_to_uint8), 'uint8')
elemwise.Elemwise(scal.convert_to_uint8), 'uint8')
"""Cast to unsigned 8-bit integer"""
_convert_to_uint16 = _conversion(
elemwise.Elemwise(scal.convert_to_uint16), 'uint16')
elemwise.Elemwise(scal.convert_to_uint16), 'uint16')
"""Cast to unsigned 16-bit integer"""
_convert_to_uint32 = _conversion(
elemwise.Elemwise(scal.convert_to_uint32), 'uint32')
elemwise.Elemwise(scal.convert_to_uint32), 'uint32')
"""Cast to unsigned 32-bit integer"""
_convert_to_uint64 = _conversion(
elemwise.Elemwise(scal.convert_to_uint64), 'uint64')
elemwise.Elemwise(scal.convert_to_uint64), 'uint64')
"""Cast to unsigned 64-bit integer"""
_convert_to_float32 = _conversion(
elemwise.Elemwise(scal.convert_to_float32), 'float32')
elemwise.Elemwise(scal.convert_to_float32), 'float32')
"""Cast to single-precision floating point"""
_convert_to_float64 = _conversion(
elemwise.Elemwise(scal.convert_to_float64), 'float64')
elemwise.Elemwise(scal.convert_to_float64), 'float64')
"""Cast to double-precision floating point"""
_convert_to_complex64 = _conversion(
elemwise.Elemwise(scal.convert_to_complex64), 'complex64')
elemwise.Elemwise(scal.convert_to_complex64), 'complex64')
"""Cast to single-precision complex"""
_convert_to_complex128 = _conversion(
elemwise.Elemwise(scal.convert_to_complex128), 'complex128')
elemwise.Elemwise(scal.convert_to_complex128), 'complex128')
"""Cast to double-precision complex"""
_cast_mapping = {
'int8': _convert_to_int8,
'int16': _convert_to_int16,
'int32': _convert_to_int32,
'int64': _convert_to_int64,
'uint8': _convert_to_uint8,
'uint16': _convert_to_uint16,
'uint32': _convert_to_uint32,
'uint64': _convert_to_uint64,
'float32': _convert_to_float32,
'float64': _convert_to_float64,
'complex64': _convert_to_complex64,
'complex128': _convert_to_complex128}
'int8': _convert_to_int8,
'int16': _convert_to_int16,
'int32': _convert_to_int32,
'int64': _convert_to_int64,
'uint8': _convert_to_uint8,
'uint16': _convert_to_uint16,
'uint32': _convert_to_uint32,
'uint64': _convert_to_uint64,
'float32': _convert_to_float32,
'float64': _convert_to_float64,
'complex64': _convert_to_complex64,
'complex128': _convert_to_complex128}
@constructor
......@@ -1235,7 +1246,8 @@ class MaxAndArgmax(Op):
elif isinstance(axis, Variable):
if not isinstance(axis, TensorConstant):
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)
# we make the axis all positive to make the infer_shape work
# with negative axis
......@@ -1249,8 +1261,8 @@ class MaxAndArgmax(Op):
if axis is not None:
if axis < 0 or axis >= x.type.ndim:
raise ValueError(
'Invalid axis: %s (the number of dimensions of the '
'input is: %s)' % (axis, x.type.ndim))
'Invalid axis: %s (the number of dimensions of the '
'input is: %s)' % (axis, x.type.ndim))
all_axes.add(axis)
else:
all_axes = range(x.ndim)
......@@ -1342,7 +1354,7 @@ class MaxAndArgmax(Op):
if node.inputs[1].data is None:
return [(), ()]
rval = tuple([ishape[i] for (i, b) in enumerate(
node.inputs[0].type.broadcastable) if i != axis.data])
node.inputs[0].type.broadcastable) if i != axis.data])
return [rval, rval]
def R_op(self, inputs, eval_points):
......@@ -1389,9 +1401,10 @@ class MaxAndArgmax(Op):
if g_max_disconnected and g_max_idx_disconnected:
return [DisconnectedType()(), DisconnectedType()()]
axis_grad = grad_undefined(self, 1, axis,
"argmax is not defined for non-integer axes so"
" argmax(x, axis+eps) is undefined")
axis_grad = grad_undefined(
self, 1, axis,
"argmax is not defined for non-integer axes so"
" argmax(x, axis+eps) is undefined")
# if the max is disconnected but the argmax is not,
# the gradient on its inputs is zero
......@@ -1449,7 +1462,8 @@ def makeKeepDims(x, y, axis):
newaxis = []
for a in axis:
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:
a += x.type.ndim
newaxis.append(a)
......@@ -1931,6 +1945,7 @@ def gammaln(a):
def psi(a):
"""derivative of log gamma function"""
@_scal_elemwise
def chi2sf(x, k):
"""chi squared survival function"""
......@@ -2001,26 +2016,26 @@ def zeros_like(model, dtype=None):
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``.
"""
if not isinstance(shape, (list, tuple, TensorVariable)):
shape = [shape]
if not isinstance(shp, (list, tuple, TensorVariable)):
shp = [shp]
if dtype is None:
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``.
"""
if not isinstance(shape, (list, tuple, TensorVariable)):
shape = [shape]
if not isinstance(shp, (list, tuple, TensorVariable)):
shp = [shp]
if dtype is None:
dtype = config.floatX
return alloc(numpy.array(1, dtype=dtype), *shape)
return alloc(numpy.array(1, dtype=dtype), *shp)
class Nonzero(gof.Op):
......@@ -2198,8 +2213,10 @@ class Tri(gof.Op):
N = as_tensor_variable(N)
M = as_tensor_variable(M)
k = as_tensor_variable(k)
return gof.Apply(self, [N, M, k],
[TensorType(dtype=self.dtype, broadcastable=(False, False))()])
return gof.Apply(
self,
[N, M, k],
[TensorType(dtype=self.dtype, broadcastable=(False, False))()])
def perform(self, node, inp, out_):
N, M, k = inp
......@@ -2307,8 +2324,10 @@ class Eye(gof.Op):
assert n.ndim == 0
assert m.ndim == 0
assert k.ndim == 0
return gof.Apply(self, [n, m, k],
[TensorType(dtype=self.dtype, broadcastable=(False, False))()])
return gof.Apply(
self,
[n, m, k],
[TensorType(dtype=self.dtype, broadcastable=(False, False))()])
def perform(self, node, inp, out_):
n, m, k = inp
......@@ -2370,8 +2389,9 @@ class Alloc(gof.Op):
Returns an N-dimensional tensor initialized by `value` using something
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
broadcasting value over the output ndarray.
......@@ -2555,25 +2575,25 @@ class Alloc(gof.Op):
# If the output is a constant, it will have to be deepcopied
# each time the function is called. So we do not fold.
return False
elif (#The following ops work inplace of their input id 0.
client[1] == 0 and
isinstance(client[0].op, (
#Ops that will work inplace on the Alloc. So if they
#get constant_folded, they would copy the
#constant and this is less efficients.
#Not doing the constant folding could also lower
#the peak memory usage, as we the "constant" won't
#always exists.
theano.tensor.subtensor.IncSubtensor,
theano.tensor.subtensor.AdvancedIncSubtensor1,
theano.tensor.subtensor.AdvancedIncSubtensor,
theano.tensor.blas.Gemv,
theano.tensor.blas_c.CGemv,
theano.tensor.blas.Ger,
theano.tensor.blas_c.CGer,
theano.tensor.blas_scipy.ScipyGer
))):
elif (
# The following ops work inplace of their input id 0.
client[1] == 0 and
isinstance(client[0].op, (
# Ops that will work inplace on the Alloc. So if they
# get constant_folded, they would copy the
# constant and this is less efficients.
# Not doing the constant folding could also lower
# the peak memory usage, as we the "constant" won't
# always exists.
theano.tensor.subtensor.IncSubtensor,
theano.tensor.subtensor.AdvancedIncSubtensor1,
theano.tensor.subtensor.AdvancedIncSubtensor,
theano.tensor.blas.Gemv,
theano.tensor.blas_c.CGemv,
theano.tensor.blas.Ger,
theano.tensor.blas_c.CGer,
theano.tensor.blas_scipy.ScipyGer))):
return False
#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
......@@ -2687,7 +2707,7 @@ class Mean(elemwise.CAReduce):
@constructor
def mean(input, axis=None, dtype=None, op=False, keepdims=False,
acc_dtype=None):
acc_dtype=None):
"""
Computes the mean value along the given axis(es) of a tensor `input`
......@@ -2719,16 +2739,16 @@ def mean(input, axis=None, dtype=None, op=False, keepdims=False,
if op:
if dtype not in (None, 'float64'):
raise NotImplementedError(
'The Mean op does not support the dtype argument, '
'and will always use float64. If you want to specify '
'the dtype, call tensor.mean(..., op=False).',
dtype)
'The Mean op does not support the dtype argument, '
'and will always use float64. If you want to specify '
'the dtype, call tensor.mean(..., op=False).',
dtype)
if acc_dtype not in (None, 'float64'):
raise NotImplementedError(
'The Mean op does not support the acc_dtype argument, '
'and will always use float64. If you want to specify '
'acc_dtype, call tensor.mean(..., op=False).',
dtype)
'The Mean op does not support the acc_dtype argument, '
'and will always use float64. If you want to specify '
'acc_dtype, call tensor.mean(..., op=False).',
dtype)
out = Mean(axis)(input)
if keepdims:
out = makeKeepDims(input, out, axis)
......@@ -2848,9 +2868,9 @@ class Default(gof.Op):
def make_node(self, x, default):
x, default = as_tensor_variable(x), as_tensor_variable(default)
if x.type != default.type:
if x.type != default.type:
raise TypeError('Both default() arguments must have same type',
x, default)
x, default)
return gof.Apply(self, [x, default], [default.type()])
def perform(self, node, inp, out_):
......@@ -2951,8 +2971,8 @@ def ceil_intdiv(a, b):
def mod_check(x, y):
"""Make sure we do not try to use complex numbers."""
if (as_tensor_variable(x).dtype in complex_dtypes or
as_tensor_variable(y).dtype in complex_dtypes):
if ((as_tensor_variable(x).dtype in complex_dtypes or
as_tensor_variable(y).dtype in complex_dtypes)):
# Currently forbidden.
raise scal.Mod.complex_error
else:
......@@ -2982,7 +3002,7 @@ def clip(x, min, max):
pprint.assign(add, printing.OperatorPrinter('+', -2, 'either'))
pprint.assign(mul, printing.OperatorPrinter('*', -1, 'either'))
pprint.assign(sub, printing.OperatorPrinter('-', -2, 'left'))
pprint.assign(neg, printing.OperatorPrinter('-', 0, 'either'))
pprint.assign(neg, printing.OperatorPrinter('-', 0, 'either'))
pprint.assign(true_div, printing.OperatorPrinter('/', -1, 'left'))
pprint.assign(int_div, printing.OperatorPrinter('//', -1, 'left'))
pprint.assign(pow, printing.OperatorPrinter('**', 1, 'right'))
......@@ -3006,8 +3026,8 @@ def extract_constant(x, elemwise=True):
x = get_scalar_constant_value(x, elemwise=elemwise)
except NotScalarConstantError:
pass
if (isinstance(x, scal.ScalarVariable) or
isinstance(x, scal.sharedvar.ScalarSharedVariable)):
if ((isinstance(x, scal.ScalarVariable) or
isinstance(x, scal.sharedvar.ScalarSharedVariable))):
if x.owner and isinstance(x.owner.op, ScalarFromTensor):
x = x.owner.inputs[0]
else:
......@@ -3046,11 +3066,12 @@ def batched_dot(x, y):
But numpy einsum is slower than dot or tensordot:
http://mail.scipy.org/pipermail/numpy-discussion/2012-October/064259.html
"""
result, updates = theano.scan(fn=lambda x_mat, y_mat:
theano.tensor.dot(x_mat, y_mat),
outputs_info=None,
sequences=[x, y],
non_sequences=None)
result, updates = theano.scan(
fn=lambda x_mat, y_mat:
theano.tensor.dot(x_mat, y_mat),
outputs_info=None,
sequences=[x, y],
non_sequences=None)
return result
......@@ -3059,42 +3080,45 @@ def batched_tensordot(x, y, axes=2):
:param x: A Tensor with sizes e.g.: for 3D (dim1, dim3, dim2)
:param y: A Tensor with sizes e.g.: for 3D (dim1, dim2, dim4)
:param axes: an integer or array. If an integer, the number of axes
to sum over. If an array, it must have two array
elements containing the axes to sum over in each tensor.
If an integer i, it is converted to an array containing
the last i dimensions of the first tensor and the first
i dimensions of the second tensor (excluding the first
(batch) dimension):
axes = [range(a.ndim - i, b.ndim), range(1,i+1)]
If an array, its two elements must contain compatible axes
of the two tensors. For example, [[1, 2], [2, 4]] means sum
over the 2nd and 3rd axes of a and the 3rd and 5th axes of b.
(Remember axes are zero-indexed!) The 2nd axis of a and the
3rd axis of b must have the same shape; the same is true for
the 3rd axis of a and the 5th axis of b.
to sum over. If an array, it must have two array
elements containing the axes to sum over in each tensor.
If an integer i, it is converted to an array containing
the last i dimensions of the first tensor and the first
i dimensions of the second tensor (excluding the first
(batch) dimension):
axes = [range(a.ndim - i, b.ndim), range(1,i+1)]
If an array, its two elements must contain compatible axes
of the two tensors. For example, [[1, 2], [2, 4]] means sum
over the 2nd and 3rd axes of a and the 3rd and 5th axes of b.
(Remember axes are zero-indexed!) The 2nd axis of a and the
3rd axis of b must have the same shape; the same is true for
the 3rd axis of a and the 5th axis of b.
:type axes: int or array-like of length 2
A hybrid of batch_dot and tensordot, this function computes the
tensordot product between the two tensors, by iterating over the
first dimension using scan to perform a sequence of tensordots.
A hybrid of batch_dot and tensordot, this function computes the
tensordot product between the two tensors, by iterating over the
first dimension using scan to perform a sequence of tensordots.
"""
if isinstance(axes, (list, numpy.ndarray)):
if isinstance(axes, list):
axes = numpy.asarray(axes)
else:
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
result, updates = theano.scan(fn=lambda x_mat, y_mat:
theano.tensor.tensordot(x_mat, y_mat, axes),
outputs_info=None,
sequences=[x, y],
non_sequences=None)
result, updates = theano.scan(
fn=lambda x_mat, y_mat:
theano.tensor.tensordot(x_mat, y_mat, axes),
outputs_info=None,
sequences=[x, y],
non_sequences=None)
return result
def split(x, splits_size, n_splits, axis=0):
the_split = Split(n_splits)
......@@ -3174,10 +3198,10 @@ class Split(Op):
except:
raise ValueError('Split.perform() with axis=(%s) is invalid'
' for x.shape==(%s)'
% (axis, x.shape))
% (axis, x.shape))
if len(splits) != self.len_splits:
raise ValueError('In Split.perform(), len(splits) != len_splits.',
(len(splits), self.len_splits))
(len(splits), self.len_splits))
if numpy.sum(splits) != len_along_axis:
raise ValueError('The splits sum to %s, expected %s' %
......@@ -3233,7 +3257,7 @@ class Split(Op):
grad_undefined(self, 2, n)]
def R_op(self, inputs, eval_points):
if eval_points[0] is None:
if eval_points[0] is None:
return [None for i in self.len_splits]
return self.make_node(eval_points[0], *inputs[1:]).outputs
......@@ -3327,11 +3351,11 @@ class Join(Op):
output_maker = lambda bcastable: tensor(dtype=out_dtype,
broadcastable=bcastable)
return self._make_node_internal(axis, tensors,
as_tensor_variable_args, output_maker)
return self._make_node_internal(
axis, tensors, as_tensor_variable_args, output_maker)
def _make_node_internal(self, axis, tensors,
as_tensor_variable_args, output_maker):
as_tensor_variable_args, output_maker):
if not python_all(targs.type.ndim for targs
in as_tensor_variable_args):
raise TypeError('Join cannot handle arguments of dimension 0.'
......@@ -3387,7 +3411,8 @@ class Join(Op):
if not python_all([x.ndim == len(bcastable)
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)
if inputs[0].type not in int_types:
......@@ -3403,7 +3428,7 @@ class Join(Op):
out, = out_
axis, tensors = axis_and_tensors[0], axis_and_tensors[1:]
out[0] = theano._asarray(numpy.concatenate(tensors, axis=axis),
dtype=node.outputs[0].type.dtype)
dtype=node.outputs[0].type.dtype)
def c_code_cache_version(self):
return (2,)
......@@ -3617,14 +3642,14 @@ def stack(*tensors):
# And DebugMode can't detect error in this code as it is not in an
# optimization.
# See ticket #660
if numpy.all([
# in case there is direct int in tensors.
isinstance(t, (numpy.number, float, int, python_complex,
long)) or
(isinstance(t, Variable) and
isinstance(t.type, TensorType) and
t.ndim == 0)
for t in tensors]):
if numpy.all(
[ # in case there is direct int in tensors.
isinstance(t, (numpy.number, float, int, python_complex,
long)) or
(isinstance(t, Variable) and
isinstance(t.type, TensorType) and
t.ndim == 0)
for t in tensors]):
# in case there is direct int
tensors = map(as_tensor_variable, tensors)
dtype = scal.upcast(*[i.dtype for i in tensors])
......@@ -3649,9 +3674,10 @@ def concatenate(tensor_list, axis=0):
# instead of
# c = concatenate((x, y))
if not isinstance(tensor_list, (tuple, list)):
raise TypeError("The 'tensors' argument must be either a tuple "
"or a list, make sure you did not forget () or [] around "
"arguments of concatenate.", tensor_list)
raise TypeError(
"The 'tensors' argument must be either a tuple "
"or a list, make sure you did not forget () or [] around "
"arguments of concatenate.", tensor_list)
return join(axis, *tensor_list)
......@@ -3682,10 +3708,10 @@ def get_vector_length(v):
if v.owner and isinstance(v.owner.op, Shape):
return v.owner.inputs[0].type.ndim
# If we take this slice: var[:0], we know it will have 0 elements.
if (v.owner and
isinstance(v.owner.op, theano.tensor.subtensor.Subtensor) and
isinstance(v.owner.op.idx_list[0], slice) and
v.owner.op.idx_list[0].start in [None, 0]):
if ((v.owner and
isinstance(v.owner.op, theano.tensor.subtensor.Subtensor) and
isinstance(v.owner.op.idx_list[0], slice) and
v.owner.op.idx_list[0].start in [None, 0])):
stop = theano.tensor.subtensor.get_idx_list(
v.owner.inputs, v.owner.op.idx_list)[0].stop
if extract_constant(stop) == 0:
......@@ -3767,8 +3793,8 @@ class Reshape(Op):
# If so, that dimension should be broadcastable.
try:
bcasts[index] = (
hasattr(y, 'get_scalar_constant_value') and
y.get_scalar_constant_value() == 1)
hasattr(y, 'get_scalar_constant_value') and
y.get_scalar_constant_value() == 1)
except NotScalarConstantError:
pass
return gof.Apply(self, [x, shp], [tensor(x.type.dtype, bcasts)])
......@@ -3843,7 +3869,7 @@ class Reshape(Op):
requ = [mul(*ishapes[0])]
elif crit > 1:
raise ValueError('shape argument to Reshape.perform'
' must have at most one entry equal to -1')
' must have at most one entry equal to -1')
return [requ]
else:
oshape = []
......@@ -3911,11 +3937,12 @@ def reshape(x, newshape, ndim=None, name=None):
try:
ndim = get_vector_length(newshape)
except ValueError:
raise ValueError("The length of the provided shape (%s) cannot "
"be automatically determined, so Theano is not able "
"to know what the number of dimensions of the reshaped "
"variable will be. You can provide the 'ndim' keyword "
"argument to 'reshape' to avoid this problem." % newshape)
raise ValueError(
"The length of the provided shape (%s) cannot "
"be automatically determined, so Theano is not able "
"to know what the number of dimensions of the reshaped "
"variable will be. You can provide the 'ndim' keyword "
"argument to 'reshape' to avoid this problem." % newshape)
op = Reshape(ndim, name)
rval = op(x, newshape)
return rval
......@@ -4223,15 +4250,16 @@ def arange(start, stop=None, step=1, dtype=None):
# `numpy.arange` returns an int64 array (on 64-bit platforms),
# while the upcast above returns int32.
numpy_dtype = numpy.arange(
start=numpy.array(0, dtype=start.dtype),
stop=numpy.array(1, dtype=stop.dtype),
step=numpy.array(1, dtype=step.dtype)).dtype
start=numpy.array(0, dtype=start.dtype),
stop=numpy.array(1, dtype=stop.dtype),
step=numpy.array(1, dtype=step.dtype)).dtype
if numpy_dtype != dtype:
if (config.cast_policy == 'numpy+floatX' and
config.floatX == 'float32' and
numpy_dtype == 'float64' and
# 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)])):
# We use float32 instead.
assert dtype != 'float64'
......@@ -4283,9 +4311,9 @@ class PermuteRowElements(Op):
assert (y.type.dtype.startswith('int') or
y.type.dtype.startswith('uint'))
# Inverse should be an integer scalar
assert inverse.type.ndim == 0 and\
(inverse.type.dtype.startswith('int') or\
inverse.type.dtype.startswith('uint'))
assert (inverse.type.ndim == 0 and
(inverse.type.dtype.startswith('int') or
inverse.type.dtype.startswith('uint')))
# Match shapes of x and y
x_dim = x.type.ndim
......@@ -4331,11 +4359,11 @@ class PermuteRowElements(Op):
if (numpy.__version__ <= '1.6.1' and
out.size != numpy.uint32(out.size)):
warnings.warn(
'Numpy versions 1.6.1 and below have a bug preventing '
'advanced indexing from correctly filling arrays that '
'are too big (>= 2^32 elements). It is possible that '
'out (%s), with shape %s, is not correctly filled.'
% (out, out.shape))
'Numpy versions 1.6.1 and below have a bug preventing '
'advanced indexing from correctly filling arrays that '
'are too big (>= 2^32 elements). It is possible that '
'out (%s), with shape %s, is not correctly filled.'
% (out, out.shape))
else:
xs0 = x.shape[0]
ys0 = y.shape[0]
......@@ -4447,9 +4475,9 @@ def inverse_permutation(perm):
Each row of input should contain a permutation of the first integers.
"""
return permute_row_elements(
arange(perm.shape[-1], dtype=perm.dtype),
perm,
inverse=True)
arange(perm.shape[-1], dtype=perm.dtype),
perm,
inverse=True)
#########################
......@@ -4571,7 +4599,6 @@ class Dot(Op):
# R_op for a \dot b evaluted at c for a and d for b is
# simply c \dot b + a \dot d
assert len(inputs) == 2
assert len(eval_points) == 2
if eval_points[0] is None and eval_points[1] is None:
......@@ -4599,14 +4626,16 @@ class Dot(Op):
ev0 = gof.op.get_test_value(eval_points[0])
except AttributeError:
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
if eval_points[1]:
try:
ev1 = gof.op.get_test_value(eval_points[1])
except AttributeError:
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
if debugger_available:
......@@ -4616,11 +4645,10 @@ class Dot(Op):
for i in xrange(2):
if eval_point_values[i] is not None and \
input_values[i].shape != eval_point_values[i].shape:
raise ValueError('input ' + str(i) + ' and eval_point ' +
str(i) + ' to Dot.R_op '
'should have the '
'same shape, but their shapes are'
' %s and %s, respectively' % (
raise ValueError(
'input ' + str(i) + ' and eval_point ' + str(i)
+ ' to Dot.R_op should have the same shape, but '
'their shapes are %s and %s, respectively' % (
str(input_values[i].shape),
str(eval_point_values[i].shape)))
if eval_points[0]:
......@@ -4658,7 +4686,7 @@ class Dot(Op):
_dot = Dot()
pprint.assign(_dot, printing.OperatorPrinter(printing.special['middle_dot'],
-1, 'left'))
-1, 'left'))
def dot(a, b):
......@@ -4814,7 +4842,7 @@ def tensordot(a, b, axes=2):
# check if axes is valid given the dimension of a and b
if axes > a.ndim:
raise ValueError('axes can not be larger than the dimension of '
'a (a.ndim=%i, axes=%i)' % (a.ndim, axes))
'a (a.ndim=%i, axes=%i)' % (a.ndim, axes))
if axes > b.ndim:
raise ValueError('axes can not be larger than than the dimension '
'of b (b.ndim=%i, axes=%i)' % (b.ndim, axes))
......@@ -4887,9 +4915,10 @@ def tensordot(a, b, axes=2):
(b.ndim, numpy.max(numpy.array(b_axes))))
a_order = (tuple(x for x in tuple(xrange(a.ndim)) if x not in a_axes)
+ a_axes)
b_order = (b_axes
+ tuple(x for x in tuple(xrange(b.ndim)) if x not in b_axes))
+ a_axes)
b_order = (b_axes + tuple(x
for x in tuple(xrange(b.ndim))
if x not in b_axes))
a_shuffled = a.dimshuffle(a_order)
b_shuffled = b.dimshuffle(b_order)
......@@ -4908,8 +4937,8 @@ def outer(x, y):
if y.ndim != 1:
y = y.flatten()
return dot(
x.dimshuffle(0, 'x'),
y.dimshuffle('x', 0))
x.dimshuffle(0, 'x'),
y.dimshuffle('x', 0))
def any(x, axis=None, keepdims=False):
......@@ -5082,7 +5111,7 @@ def ptp(a, axis=None):
def power(x, y):
return x**y
return x ** y
def swapaxes(y, axis1, axis2):
......@@ -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.
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)]).
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:
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;
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.
: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.
:Parameters: *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``.
:Parameters: *out* - array, optional
If provided, the result will be inserted into this array. It should be of the appropriate shape and dtype.
:Parameters: *mode* - {``raise`` (default), ``wrap``, ``clip``}, optional
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:
- 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;
- 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:
``raise`` : an exception is raised
``wrap`` : value becomes value mod n
......@@ -5145,17 +5197,18 @@ class Choose(Op):
return[(shapes[0])]
else:
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")
shape = shapes[0]
for i in range(len(shapes[0])-1):
for i in range(len(shapes[0]) - 1):
shape[i] = shapes[1][i]
return [(shape)]
def make_node(self, a, choices):
# Import here as it isn't imported by default and we can't
# import at the top as it would cause circular import.
from theano import typed_list
import theano.typed_list
a = as_tensor_variable(a)
if isinstance(choices, (tuple, list)):
choice = theano.typed_list.make_list(choices)
......
......@@ -1650,8 +1650,7 @@ def test_local_useless_subtensor():
#theano.printing.debugprint(f)
prog = f.maker.fgraph.toposort()
if res:
assert isinstance(prog[0].op, theano.tensor.basic.
SpecifyShape), dims
assert isinstance(prog[0].op, theano.tensor.SpecifyShape), dims
assert prog[1].op == tensor.exp, dims
assert len(prog) == 2, dims
else:
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论