提交 2c26f2f5 authored 作者: nouiz's avatar nouiz

Merge pull request #1248 from delallea/minor

Minor stuff
...@@ -420,8 +420,8 @@ else: ...@@ -420,8 +420,8 @@ else:
" want theano to use.") " want theano to use.")
default_openmp = count > 1 default_openmp = count > 1
# Disable it by default for now as currently only the ConvOp support # Disable it by default for now as currently only the ConvOp supports
# it And this cause slow down by default as we do not disable it for # it, and this causes slowdown by default as we do not disable it for
# too small convolution. # too small convolution.
default_openmp = False default_openmp = False
......
...@@ -472,19 +472,22 @@ class NotScalarConstantError(Exception): ...@@ -472,19 +472,22 @@ class NotScalarConstantError(Exception):
not a scalar constant. not a scalar constant.
""" """
class EmptyConstantError(NotScalarConstantError): class EmptyConstantError(NotScalarConstantError):
""" """
Raised by get_scalar_const_value if called on something that is a Raised by get_scalar_const_value if called on something that is a
zero dimensional constant. zero dimensional constant.
""" """
def get_scalar_constant_value(v): def get_scalar_constant_value(v):
"""return the constant scalar(0-D) value underlying variable `v` """return the constant scalar(0-D) value underlying variable `v`
If v is the output of dimshuffles, fills, allocs, rebroadcasts, cast If v is the output of dimshuffles, fills, allocs, rebroadcasts, cast
this function digs through them. this function digs through them.
If `v` is not some view of constant scalar data, then raise a NotScalarConstantError. If `v` is not some view of constant scalar data, then raise a
NotScalarConstantError.
:note: There may be another function similar to this one in the :note: There may be another function similar to this one in the
code, but I'm not sure where it is. code, but I'm not sure where it is.
...@@ -550,17 +553,19 @@ def get_scalar_constant_value(v): ...@@ -550,17 +553,19 @@ def get_scalar_constant_value(v):
return ret[0][0] return ret[0][0]
if isinstance(v.owner.op, Subtensor) and v.ndim == 0: if isinstance(v.owner.op, Subtensor) and v.ndim == 0:
# This condition depends on Subtensor always embedding constant # This condition depends on Subtensor always embedding constant
# indices in the Op rather than making them inputs to the Apply node # indices in the Op rather than making them inputs to the Apply
# node.
if isinstance(v.owner.inputs[0], TensorConstant) and \ if isinstance(v.owner.inputs[0], TensorConstant) and \
len(v.owner.inputs) == 1: len(v.owner.inputs) == 1:
try: try:
return v.owner.inputs[0].data.__getitem__( return v.owner.inputs[0].data.__getitem__(
tuple(v.owner.op.idx_list)) tuple(v.owner.op.idx_list))
except IndexError: except IndexError:
raise IndexError(str(tuple(v.owner.op.idx_list))+" is not a valid index into " + \ raise IndexError(
str(tuple(v.owner.op.idx_list)) +
" is not a valid index into " +
str(v.owner.inputs[0].data)) str(v.owner.inputs[0].data))
# The index list 'idx_list' should have length the same # The index list 'idx_list' should have length the same
# shape as the input. # shape as the input.
# TODO: implement the case where we take a scalar in a matrix # TODO: implement the case where we take a scalar in a matrix
...@@ -624,8 +629,6 @@ def get_scalar_constant_value(v): ...@@ -624,8 +629,6 @@ def get_scalar_constant_value(v):
msg += 'x=%s' % str(x) msg += 'x=%s' % str(x)
raise ValueError(msg) raise ValueError(msg)
if gp_broadcastable[idx]: if gp_broadcastable[idx]:
return numpy.asarray(1) return numpy.asarray(1)
...@@ -1064,7 +1067,8 @@ class TensorType(Type): ...@@ -1064,7 +1067,8 @@ class TensorType(Type):
PyErr_Format(PyExc_NotImplementedError, PyErr_Format(PyExc_NotImplementedError,
"expected an aligned array of type %%ld " "expected an aligned array of type %%ld "
"(%(type_num)s), got non-aligned array of type %%ld" "(%(type_num)s), got non-aligned array of type %%ld"
" with %%ld dimensions, with 3 last dims %%ld, %%ld, %%ld" " with %%ld dimensions, with 3 last dims "
"%%ld, %%ld, %%ld"
" and 3 last strides %%ld %%ld, %%ld.", " and 3 last strides %%ld %%ld, %%ld.",
(long int) %(type_num)s, (long int) %(type_num)s,
(long int) type_num_%(name)s, (long int) type_num_%(name)s,
...@@ -1124,7 +1128,8 @@ class TensorType(Type): ...@@ -1124,7 +1128,8 @@ class TensorType(Type):
PyErr_Format(PyExc_NotImplementedError, PyErr_Format(PyExc_NotImplementedError,
"c_sync: expected an aligned array of type %%ld " "c_sync: expected an aligned array of type %%ld "
"(%(type_num)s), got non-aligned array of type %%ld" "(%(type_num)s), got non-aligned array of type %%ld"
" with %%ld dimensions, with 3 last dims %%ld, %%ld, %%ld" " with %%ld dimensions, with 3 last dims "
"%%ld, %%ld, %%ld"
" and 3 last strides %%ld %%ld, %%ld.", " and 3 last strides %%ld %%ld, %%ld.",
(long int) %(type_num)s, (long int) %(type_num)s,
(long int) type_num_%(name)s, (long int) type_num_%(name)s,
...@@ -1751,7 +1756,7 @@ class _tensor_py_operators: ...@@ -1751,7 +1756,7 @@ class _tensor_py_operators:
if advanced: if advanced:
if (axis is not None if (axis is not None
and numpy.all(a == slice(None) for a in args[:axis]) and numpy.all(a == slice(None) for a in args[:axis])
and numpy.all(a == slice(None) for a in args[axis+1:]) and numpy.all(a == slice(None) for a in args[axis + 1:])
and isinstance(args[axis], ( and isinstance(args[axis], (
numpy.ndarray, numpy.ndarray,
list, list,
...@@ -2417,7 +2422,8 @@ class SpecifyShape(Op): ...@@ -2417,7 +2422,8 @@ class SpecifyShape(Op):
@note: Maybe in the future we will never do the assert! @note: Maybe in the future we will never do the assert!
@note: We currently don't support specifying partial shape information. @note: We currently don't support specifying partial shape information.
@todo: test this op with sparse and cuda ndarray. Do c code for them too. @todo: test this op with sparse and cuda ndarray.
Do C code for them too.
""" """
view_map = {0: [0]} view_map = {0: [0]}
...@@ -3184,11 +3190,13 @@ def real(z): ...@@ -3184,11 +3190,13 @@ def real(z):
"""Return real component of complex-valued tensor `z`""" """Return real component of complex-valued tensor `z`"""
_tensor_py_operators.real = property(real) _tensor_py_operators.real = property(real)
@_scal_elemwise_with_nfunc('imag', 1, -1) @_scal_elemwise_with_nfunc('imag', 1, -1)
def imag(z): def imag(z):
"""Return imaginary component of complex-valued tensor `z`""" """Return imaginary component of complex-valued tensor `z`"""
_tensor_py_operators.imag = property(imag) _tensor_py_operators.imag = property(imag)
@_scal_elemwise_with_nfunc('angle', 1, -1) @_scal_elemwise_with_nfunc('angle', 1, -1)
def angle(z): def angle(z):
"""Return polar-coordinate angle of complex-valued tensor `z`""" """Return polar-coordinate angle of complex-valued tensor `z`"""
...@@ -3308,8 +3316,10 @@ class Nonzero(gof.Op): ...@@ -3308,8 +3316,10 @@ class Nonzero(gof.Op):
def grad(self, inp, grads): def grad(self, inp, grads):
return [grad_undefined(self, 0, inp[0])] return [grad_undefined(self, 0, inp[0])]
_nonzero = Nonzero() _nonzero = Nonzero()
def nonzero(a, return_matrix=False): def nonzero(a, return_matrix=False):
""" """
Returns one of the following: Returns one of the following:
...@@ -3354,6 +3364,7 @@ def nonzero(a, return_matrix=False): ...@@ -3354,6 +3364,7 @@ def nonzero(a, return_matrix=False):
tuple_result = tuple([matrix_result[0]]) tuple_result = tuple([matrix_result[0]])
return tuple_result return tuple_result
def flatnonzero(a): def flatnonzero(a):
""" """
Return a vector of indices that are non-zero in the flattened version of a. Return a vector of indices that are non-zero in the flattened version of a.
...@@ -3380,6 +3391,7 @@ def flatnonzero(a): ...@@ -3380,6 +3391,7 @@ def flatnonzero(a):
raise ValueError('Nonzero only supports non-scalar arrays.') raise ValueError('Nonzero only supports non-scalar arrays.')
return nonzero(a.flatten(), return_matrix=True)[0] return nonzero(a.flatten(), return_matrix=True)[0]
def nonzero_values(a): def nonzero_values(a):
""" """
Return a vector of non-zero elements contained in the input array. Return a vector of non-zero elements contained in the input array.
...@@ -3416,6 +3428,7 @@ def nonzero_values(a): ...@@ -3416,6 +3428,7 @@ def nonzero_values(a):
""" """
return a.flatten()[flatnonzero(a)] return a.flatten()[flatnonzero(a)]
class Tri(gof.Op): class Tri(gof.Op):
def __init__(self, dtype=None): def __init__(self, dtype=None):
if dtype is None: if dtype is None:
...@@ -3519,7 +3532,7 @@ def triu(m, k=0): ...@@ -3519,7 +3532,7 @@ def triu(m, k=0):
-------- --------
tril : lower triangle of an array tril : lower triangle of an array
""" """
return m * (1 - tri(m.shape[0], m.shape[1], k=k-1, dtype=m.dtype)) return m * (1 - tri(m.shape[0], m.shape[1], k=k - 1, dtype=m.dtype))
class Eye(gof.Op): class Eye(gof.Op):
...@@ -3964,9 +3977,10 @@ def var(input, axis=None, keepdims=False): ...@@ -3964,9 +3977,10 @@ def var(input, axis=None, keepdims=False):
left in the result as dimensions with size one. With this option, left in the result as dimensions with size one. With this option,
the result will broadcast correctly against the original tensor. the result will broadcast correctly against the original tensor.
:note: It use the two-pass algorithm for more stable results. :note: It uses the two-pass algorithm for more stable results.
https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Two-pass_algorithm https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Two-pass_algorithm
It exist other implementation that are even more stable, but probably slower. There exist other implementations that are even more stable, but
probably slower.
""" """
input_ndim = input.type.ndim input_ndim = input.type.ndim
...@@ -4003,9 +4017,11 @@ def std(input, axis=None, keepdims=False): ...@@ -4003,9 +4017,11 @@ def std(input, axis=None, keepdims=False):
the result will broadcast correctly against the the result will broadcast correctly against the
original tensor. original tensor.
:note: It call var and var use the two-pass algorithm for more stable results. :note: It calls `var()` and `var()` uses the two-pass algorithm for more
stable results.
https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Two-pass_algorithm https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Two-pass_algorithm
It exist other implementation that are even more stable, but probably slower. There exist other implementations that are even more stable, but
probably slower.
""" """
return sqrt(var(input=input, axis=axis, keepdims=keepdims)) return sqrt(var(input=input, axis=axis, keepdims=keepdims))
...@@ -4354,8 +4370,6 @@ class Subtensor(Op): ...@@ -4354,8 +4370,6 @@ class Subtensor(Op):
if cond is true for an entry, does not flatten it. if cond is true for an entry, does not flatten it.
""" """
ret = [] ret = []
def helper(entry): def helper(entry):
...@@ -4369,7 +4383,6 @@ class Subtensor(Op): ...@@ -4369,7 +4383,6 @@ class Subtensor(Op):
for idx in idxs: for idx in idxs:
helper(idx) helper(idx)
return ret return ret
@staticmethod @staticmethod
...@@ -4603,16 +4616,15 @@ class Subtensor(Op): ...@@ -4603,16 +4616,15 @@ class Subtensor(Op):
""" """
return { return {
"c_prefix" : "PyArray", "c_prefix": "PyArray",
"update_flags": ("PyArray_UpdateFlags(%(view_name)s," "update_flags": ("PyArray_UpdateFlags(%(view_name)s,"
" NPY_ARRAY_C_CONTIGUOUS|" " NPY_ARRAY_C_CONTIGUOUS|"
"NPY_ARRAY_F_CONTIGUOUS);"), "NPY_ARRAY_F_CONTIGUOUS);"),
"set_data" : "PyArray_set_data", "set_data": "PyArray_set_data",
"set_dim" : "PyArray_set_dim", "set_dim": "PyArray_set_dim",
"set_stride" : "PyArray_set_stride", "set_stride": "PyArray_set_stride",
"strides_mul" : 1, "strides_mul": 1,
"view_name" : "xview" } "view_name": "xview"}
@staticmethod @staticmethod
def helper_c_code(node, name, inputs, outputs, sub, idx_list, def helper_c_code(node, name, inputs, outputs, sub, idx_list,
...@@ -5070,7 +5082,7 @@ def inc_subtensor(x, y, inplace=False, set_instead_of_inc=False, ...@@ -5070,7 +5082,7 @@ def inc_subtensor(x, y, inplace=False, set_instead_of_inc=False,
if (x.broadcastable[dim + dim_offset] if (x.broadcastable[dim + dim_offset]
and not y.broadcastable[dim]): and not y.broadcastable[dim]):
# It is acceptable to try to increment a subtensor with a # It is acceptable to try to increment a subtensor with a
# a broadcastable dim with a tensor that is not broadcastable # broadcastable dim with a tensor that is not broadcastable
# on that dimension. However, its length must then be 1. # on that dimension. However, its length must then be 1.
# We insert a Rebroadcast Op to make sure it is the case. # We insert a Rebroadcast Op to make sure it is the case.
y = addbroadcast(y, dim) y = addbroadcast(y, dim)
...@@ -5106,6 +5118,7 @@ def inc_subtensor(x, y, inplace=False, set_instead_of_inc=False, ...@@ -5106,6 +5118,7 @@ def inc_subtensor(x, y, inplace=False, set_instead_of_inc=False,
else: else:
raise TypeError('x must be result of a subtensor operation') raise TypeError('x must be result of a subtensor operation')
class IncSubtensor(Op): class IncSubtensor(Op):
"""Increment a subtensor. """Increment a subtensor.
...@@ -5306,7 +5319,7 @@ class IncSubtensor(Op): ...@@ -5306,7 +5319,7 @@ class IncSubtensor(Op):
alloc_zview = self.make_view_array(z, view_ndim) alloc_zview = self.make_view_array(z, view_ndim)
# On GPU, it takes two steps to make a view # On GPU, it takes two steps to make a view
link_zview = self.link_view_array(z, fail); link_zview = self.link_view_array(z, fail)
#Make a first view on the output, as we will write into it. #Make a first view on the output, as we will write into it.
build_view = """ build_view = """
...@@ -5367,8 +5380,6 @@ class IncSubtensor(Op): ...@@ -5367,8 +5380,6 @@ class IncSubtensor(Op):
if not isinstance(node.inputs[0].type, TensorType): if not isinstance(node.inputs[0].type, TensorType):
raise NotImplementedError() raise NotImplementedError()
def c_code_cache_version(self): def c_code_cache_version(self):
hv = Subtensor.helper_c_code_cache_version() hv = Subtensor.helper_c_code_cache_version()
if hv: if hv:
...@@ -5826,8 +5837,8 @@ class Join(Op): ...@@ -5826,8 +5837,8 @@ class Join(Op):
# Axis can also be a constant # Axis can also be a constant
if not isinstance(axis, int): if not isinstance(axis, int):
try: try:
# Note : `get_scalar_constant_value` returns a ndarray not a # Note : `get_scalar_constant_value` returns a ndarray not
# int # an int
axis = int(get_scalar_constant_value(axis)) axis = int(get_scalar_constant_value(axis))
except NotScalarConstantError: except NotScalarConstantError:
...@@ -6197,7 +6208,8 @@ class Reshape(Op): ...@@ -6197,7 +6208,8 @@ class Reshape(Op):
# Try to see if we can infer that y has a constant value of 1. # Try to see if we can infer that y has a constant value of 1.
# If so, that dimension should be broadcastable. # If so, that dimension should be broadcastable.
try: try:
bcasts[index] = (hasattr(y, 'get_scalar_constant_value') and bcasts[index] = (
hasattr(y, 'get_scalar_constant_value') and
y.get_scalar_constant_value() == 1) y.get_scalar_constant_value() == 1)
except NotScalarConstantError: except NotScalarConstantError:
pass pass
...@@ -6317,7 +6329,9 @@ class Reshape(Op): ...@@ -6317,7 +6329,9 @@ class Reshape(Op):
%(fail)s; %(fail)s;
} }
if (!PyArray_ISALIGNED(%(z)s)) { if (!PyArray_ISALIGNED(%(z)s)) {
PyErr_Format(PyExc_RuntimeError, "PyArray_Newshape returned an object that isn't aligned!"); PyErr_Format(
PyExc_RuntimeError,
"PyArray_Newshape returned an object that isn't aligned!");
%(fail)s; %(fail)s;
} }
""" % locals() """ % locals()
...@@ -6917,9 +6931,11 @@ class AdvancedSubtensor1(Op): ...@@ -6917,9 +6931,11 @@ class AdvancedSubtensor1(Op):
if sparse_module_ref is None: if sparse_module_ref is None:
import theano.sparse as sparse_module_ref import theano.sparse as sparse_module_ref
rval1 = [sparse_module_ref.ConstructSparseFromList()((inputs[0]), gz, inputs[1])] rval1 = [sparse_module_ref.ConstructSparseFromList()(
(inputs[0]), gz, inputs[1])]
else: else:
rval1 = [advanced_inc_subtensor1(zeros_like(inputs[0]), gz, inputs[1])] rval1 = [advanced_inc_subtensor1(
zeros_like(inputs[0]), gz, inputs[1])]
return rval1 + [DisconnectedType()()] * (len(inputs) - 1) return rval1 + [DisconnectedType()()] * (len(inputs) - 1)
def R_op(self, inputs, eval_points): def R_op(self, inputs, eval_points):
...@@ -7246,6 +7262,7 @@ class AdvancedIncSubtensor(Op): ...@@ -7246,6 +7262,7 @@ class AdvancedIncSubtensor(Op):
*inputs[2:]).outputs *inputs[2:]).outputs
advanced_inc_subtensor = AdvancedIncSubtensor() advanced_inc_subtensor = AdvancedIncSubtensor()
def take(a, indices, axis=None, mode='raise'): def take(a, indices, axis=None, mode='raise'):
a = as_tensor_variable(a) a = as_tensor_variable(a)
indices = as_tensor_variable(indices) indices = as_tensor_variable(indices)
...@@ -7480,6 +7497,7 @@ _dot = Dot() ...@@ -7480,6 +7497,7 @@ _dot = Dot()
pprint.assign(_dot, printing.OperatorPrinter(printing.special['middle_dot'], pprint.assign(_dot, printing.OperatorPrinter(printing.special['middle_dot'],
-1, 'left')) -1, 'left'))
def dot(a, b): def dot(a, b):
""" """
Computes the dot product of two variables. For two matrices, this is Computes the dot product of two variables. For two matrices, this is
...@@ -7525,12 +7543,11 @@ def dot(a, b): ...@@ -7525,12 +7543,11 @@ def dot(a, b):
return _dot(a, b) return _dot(a, b)
######################### #########################
# Linalg : TensorDot # Linalg : TensorDot
######################### #########################
def tensordot(a, b, axes = 2): def tensordot(a, b, axes=2):
""" """
Given two tensors a and b,tensordot computes a generalized dot product over Given two tensors a and b,tensordot computes a generalized dot product over
the provided axes. Theano's implementation reduces all expressions to the provided axes. Theano's implementation reduces all expressions to
...@@ -7652,8 +7669,8 @@ def tensordot(a, b, axes = 2): ...@@ -7652,8 +7669,8 @@ def tensordot(a, b, axes = 2):
for s1 in range(axes, b.ndim): for s1 in range(axes, b.ndim):
b_shape_1 *= b.shape[s1] b_shape_1 *= b.shape[s1]
a_reshaped = a.reshape((a_shape_0, a_shape_1), ndim = 2) a_reshaped = a.reshape((a_shape_0, a_shape_1), ndim=2)
b_reshaped = b.reshape((b_shape_0, b_shape_1), ndim = 2) b_reshaped = b.reshape((b_shape_0, b_shape_1), ndim=2)
return _dot(a_reshaped, b_reshaped).reshape(outshape, outndim) return _dot(a_reshaped, b_reshaped).reshape(outshape, outndim)
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论