提交 a660ffd0 authored 作者: Olivier Breuleux's avatar Olivier Breuleux

dimensions_to_reduce -> axis

上级 41cd2224
...@@ -135,7 +135,7 @@ class _test_CAReduce(unittest.TestCase): ...@@ -135,7 +135,7 @@ class _test_CAReduce(unittest.TestCase):
((2, 3, 4, 5), (0, 1, 3)), ((2, 3, 4, 5), (0, 1, 3)),
((), ())]: ((), ())]:
x = modes.build(Tensor('float64', [1 * (entry == 1) for entry in xsh], name = 'x')) x = modes.build(Tensor('float64', [1 * (entry == 1) for entry in xsh], name = 'x'))
e = CAReduce(Add, [x], dimensions_to_reduce = tosum).out e = CAReduce(Add, [x], axis = tosum).out
f = linker(env([x], [e])).make_function(inplace = False) f = linker(env([x], [e])).make_function(inplace = False)
xv = numpy.asarray(numpy.random.rand(*xsh)) xv = numpy.asarray(numpy.random.rand(*xsh))
zv = xv zv = xv
......
...@@ -460,15 +460,16 @@ def wrap_broadcast(op): ...@@ -460,15 +460,16 @@ def wrap_broadcast(op):
class CAReduce(Op): class CAReduce(Op):
""" """
Usage: CAReduce(scalar_opclass, inputs, dimensions_to_reduce = None) Usage: CAReduce(scalar_opclass, inputs, axis = None)
* scalar_opclass: a binary scalar op with only one output. * scalar_opclass: a binary scalar op with only one output.
It will be instantiated as such: It will be instantiated as such:
scalar_opclass.__init__([Scalar(t.dtype) for t in inputs]) scalar_opclass.__init__([Scalar(t.dtype) for t in inputs])
It must be commutative and associative. It must be commutative and associative.
* inputs: list of Tensor instances * inputs: list of Tensor instances
* dimensions_to_reduce: list of dimensions that we want to reduce * axis: - the dimension along which we want to reduce
if None, all dimensions are reduced - list of dimensions that we want to reduce
- if None, all dimensions are reduced
The output will have the same shape as the input minus the reduced The output will have the same shape as the input minus the reduced
dimensions. It will contain the result of accumulating all values dimensions. It will contain the result of accumulating all values
...@@ -489,7 +490,7 @@ class CAReduce(Op): ...@@ -489,7 +490,7 @@ class CAReduce(Op):
or/and/xor - but not subtract, divide or power). or/and/xor - but not subtract, divide or power).
""" """
def __init__(self, scalar_opclass, inputs, dimensions_to_reduce = None): def __init__(self, scalar_opclass, inputs, axis = None):
inputs = map(astensor, inputs) inputs = map(astensor, inputs)
self.shadow = scalar_opclass(*[Scalar(dtype = inputs[0].dtype) for i in xrange(len(inputs) + 1)]) self.shadow = scalar_opclass(*[Scalar(dtype = inputs[0].dtype) for i in xrange(len(inputs) + 1)])
...@@ -498,32 +499,34 @@ class CAReduce(Op): ...@@ -498,32 +499,34 @@ class CAReduce(Op):
raise NotImplementedError("CAReduce only supports binary functions with a single output.") raise NotImplementedError("CAReduce only supports binary functions with a single output.")
if len(inputs) != 1: if len(inputs) != 1:
raise TypeError("Only one argument expected.") raise TypeError("Only one argument expected.")
if dimensions_to_reduce is None: if axis is None:
dimensions_to_reduce = range(len(inputs[0].broadcastable)) axis = range(len(inputs[0].broadcastable))
elif isinstance(axis, int):
axis = [axis]
self.inputs = inputs self.inputs = inputs
self.outputs = [Tensor(dtype = inputs[0].dtype, self.outputs = [Tensor(dtype = inputs[0].dtype,
broadcastable = [x for i, x in enumerate(inputs[0].broadcastable) if i not in dimensions_to_reduce])] broadcastable = [x for i, x in enumerate(inputs[0].broadcastable) if i not in axis])]
self.dimensions_to_reduce = dimensions_to_reduce self.axis = axis
self.scalar_opclass = scalar_opclass self.scalar_opclass = scalar_opclass
self.ufunc = numpy.frompyfunc(self.shadow.impl, self.shadow.nin, self.shadow.nout) self.ufunc = numpy.frompyfunc(self.shadow.impl, self.shadow.nin, self.shadow.nout)
def desc(self): def desc(self):
return (self.__class__, self.scalar_opclass, tuple(self.dimensions_to_reduce)) return (self.__class__, self.scalar_opclass, tuple(self.axis))
def strdesc(self): def strdesc(self):
if set(self.dimensions_to_reduce) != set(xrange(len(self.inputs[0].broadcastable))): if set(self.axis) != set(xrange(len(self.inputs[0].broadcastable))):
return "Reduce{%s}{%s}" % (self.scalar_opclass.__name__, "".join(str(x) for x in self.dimensions_to_reduce)) return "Reduce{%s}{%s}" % (self.scalar_opclass.__name__, "".join(str(x) for x in self.axis))
else: else:
return "Reduce{%s}" % self.scalar_opclass.__name__ return "Reduce{%s}" % self.scalar_opclass.__name__
def clone_with_new_inputs(self, *new_inputs): def clone_with_new_inputs(self, *new_inputs):
return CAReduce(self.scalar_opclass, new_inputs, self.dimensions_to_reduce) return CAReduce(self.scalar_opclass, new_inputs, self.axis)
def perform(self): def perform(self):
result = self.inputs[0].data result = self.inputs[0].data
to_reduce = reversed(sorted(self.dimensions_to_reduce)) to_reduce = reversed(sorted(self.axis))
if to_reduce: if to_reduce:
for dimension in to_reduce: for dimension in to_reduce:
result = self.ufunc.reduce(result, dimension) result = self.ufunc.reduce(result, dimension)
...@@ -542,7 +545,7 @@ class CAReduce(Op): ...@@ -542,7 +545,7 @@ class CAReduce(Op):
idtype = input.dtype_specs()[1] idtype = input.dtype_specs()[1]
odtype = output.dtype_specs()[1] odtype = output.dtype_specs()[1]
tosum = self.dimensions_to_reduce tosum = self.axis
if tosum == (): if tosum == ():
return Broadcast(scalar.Identity, (input, ))._c_all(inames, onames, sub) return Broadcast(scalar.Identity, (input, ))._c_all(inames, onames, sub)
...@@ -604,7 +607,7 @@ class CAReduce(Op): ...@@ -604,7 +607,7 @@ class CAReduce(Op):
def __str__(self): def __str__(self):
input = self.inputs[0] input = self.inputs[0]
if len(input.broadcastable) == len(self.dimensions_to_reduce): if len(input.broadcastable) == len(self.axis):
return "%s:%s(%s)" % (self.__class__.__name__, return "%s:%s(%s)" % (self.__class__.__name__,
self.scalar_opclass.__name__, self.scalar_opclass.__name__,
str(input)) str(input))
...@@ -612,7 +615,7 @@ class CAReduce(Op): ...@@ -612,7 +615,7 @@ class CAReduce(Op):
return "%s:%s(%s, axis = %s)" % (self.__class__.__name__, return "%s:%s(%s, axis = %s)" % (self.__class__.__name__,
self.scalar_opclass.__name__, self.scalar_opclass.__name__,
str(input), str(input),
self.dimensions_to_reduce) self.axis)
...@@ -645,16 +648,16 @@ def make_reduce(scalar_opclass, name = None): ...@@ -645,16 +648,16 @@ def make_reduce(scalar_opclass, name = None):
def __init__(self, *inputs, **kwargs): def __init__(self, *inputs, **kwargs):
reducer.__init__(self, scalar_opclass, inputs, kwargs.get('axis', None)) reducer.__init__(self, scalar_opclass, inputs, kwargs.get('axis', None))
def clone_with_new_inputs(self, *new_inputs): def clone_with_new_inputs(self, *new_inputs):
return New(*new_inputs, **dict(axis = self.dimensions_to_reduce)) return New(*new_inputs, **dict(axis = self.axis))
def __str__(self): def __str__(self):
input = self.inputs[0] input = self.inputs[0]
if len(input.broadcastable) == len(self.dimensions_to_reduce): if len(input.broadcastable) == len(self.axis):
return "%s(%s)" % (self.__class__.__name__, return "%s(%s)" % (self.__class__.__name__,
str(input)) str(input))
else: else:
return "%s(%s, axis = %s)" % (self.__class__.__name__, return "%s(%s, axis = %s)" % (self.__class__.__name__,
str(input), str(input),
self.dimensions_to_reduce) self.axis)
New.__name__ = name New.__name__ = name
return New return New
...@@ -662,12 +665,12 @@ _Sum = make_reduce(scalar.Add, '_Sum') ...@@ -662,12 +665,12 @@ _Sum = make_reduce(scalar.Add, '_Sum')
class Sum(_Sum): class Sum(_Sum):
__doc__ = _Sum.__doc__ __doc__ = _Sum.__doc__
def grad(self, (x, ), (gz, )): def grad(self, (x, ), (gz, )):
if self.dimensions_to_reduce == (): if self.axis == ():
return gz, return gz,
new_dims = [] new_dims = []
i = 0 i = 0
for j, _ in enumerate(x.broadcastable): for j, _ in enumerate(x.broadcastable):
if j in self.dimensions_to_reduce: if j in self.axis:
new_dims.append('x') new_dims.append('x')
else: else:
new_dims.append(i) new_dims.append(i)
...@@ -681,7 +684,7 @@ def reduce(op): ...@@ -681,7 +684,7 @@ def reduce(op):
else: else:
raise NotImplementedError("The scalar op class to reduce must be commutative and associative.") raise NotImplementedError("The scalar op class to reduce must be commutative and associative.")
def instantiate(*inputs): def instantiate(*inputs):
return reducer(op, inputs, dimensions_to_reduce) return reducer(op, inputs, axis)
return instantiate return instantiate
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论