提交 9bd84310 authored 作者: nouiz's avatar nouiz

Merge pull request #615 from npinto/refactor/basic

WIP: refactor basic.py, extract sorting functions in {test,_}sort.py
"""Define the tensor toplevel""" """Define the tensor toplevel"""
__docformat__ = "restructuredtext en" __docformat__ = "restructuredtext en"
import warnings import warnings
from basic import * from basic import *
...@@ -31,6 +30,7 @@ import sharedvar # adds shared-variable constructors ...@@ -31,6 +30,7 @@ import sharedvar # adds shared-variable constructors
# `theano.shared` and `tensor._shared`. # `theano.shared` and `tensor._shared`.
from sharedvar import tensor_constructor as _shared from sharedvar import tensor_constructor as _shared
def shared(*args, **kw): def shared(*args, **kw):
""" """
Backward-compatibility wrapper around `tensor._shared`. Backward-compatibility wrapper around `tensor._shared`.
...@@ -52,3 +52,5 @@ import nnet # used for softmax, sigmoid, etc. ...@@ -52,3 +52,5 @@ import nnet # used for softmax, sigmoid, etc.
from theano.gradient import Rop, Lop, grad, numeric_grad, verify_grad, \ from theano.gradient import Rop, Lop, grad, numeric_grad, verify_grad, \
jacobian, hessian jacobian, hessian
from theano.tensor.sort import sort
...@@ -6267,164 +6267,3 @@ def any(x, axis=None): ...@@ -6267,164 +6267,3 @@ def any(x, axis=None):
def all(x, axis=None): def all(x, axis=None):
return elemwise.All(axis)(x) return elemwise.All(axis)(x)
class SortOp(theano.Op):
"""
This class is a wrapper for numpy sort function
"""
def __init__(self, kind, order=None):
self.kind = kind
self.order = order
def __eq__(self, other):
return (type(self) == type(other) and self.order == other.order and
self.kind == other.kind)
def __hash__(self):
return hash(type(self)) ^ hash(self.order) ^ hash(self.kind)
def __str__(self):
return self.__class__.__name__ + "{%s, %s}" % (self.kind,
str(self.order))
def make_node(self, input, axis=-1):
input = theano.tensor.as_tensor_variable(input)
if axis is None:
axis = Constant(gof.generic, None)
# axis=None flattens the array before sorting
out_type = tensor(dtype=input.dtype, broadcastable=[False])
else:
axis = theano.tensor.as_tensor_variable(axis)
out_type = input.type()
return theano.Apply(self, [input, axis], [out_type])
def perform(self, node, inputs, output_storage):
a = inputs[0]
axis = inputs[1]
z = output_storage[0]
z[0] = numpy.sort(a, axis, self.kind, self.order)
def infer_shape(self, node, inputs_shapes):
if (isinstance(node.inputs[1], Constant) and
node.inputs[1].data is None):
# That means axis = None,
# So the array is flattened before being sorted
return [(mul(*inputs_shapes[0]),)]
# axis should not be None
# So there should be the same number of dimensions
# in the input and output
assert node.inputs[0].ndim == node.outputs[0].ndim
assert inputs_shapes[1] == ()
return [inputs_shapes[0]]
#**** It need the argsort, so we can't do it now.
#def grad(self, inputs, output_grads):
"""
def R_op(self, inputs, eval_points):
# R_op can receive None as eval_points.
# That mean there is no diferientiable path through that input
# If this imply that you cannot compute some outputs,
# return None for those.
if eval_points[0] is None:
return eval_points
return self.grad(inputs, eval_points)
"""
def sort(a, axis=-1, kind='quicksort', order=None):
"""
Return a sorted copy of an array.
a : Tensor
Tensor to be sorted
axis : Tensor
Axis along which to sort. If None, the array is
flattened before sorting.
kind : {'quicksort', 'mergesort', 'heapsort'}, optional
Sorting algorithm. Default is 'quicksort'.
order : list, optional
When `a` is a structured array, this argument specifies which
fields to compare first, second, and so on. This list does not
need to include all of the fields.
"""
return SortOp(kind, order)(a, axis)
class ArgSortOp(theano.Op):
"""
This class is a wrapper for numpy argsort function
"""
def __init__(self, kind, order=None):
self.kind = kind
self.order = order
def __eq__(self, other):
return (type(self) == type(other) and
self.order == other.order and
self.kind == other.kind)
def __hash__(self):
return hash(type(self)) ^ hash(self.order) ^ hash(self.kind)
def __str__(self):
return (self.__class__.__name__
+ "{%s, %s}" % (self.kind, str(self.order)))
def make_node(self, input, axis=-1):
input = theano.tensor.as_tensor_variable(input)
if axis is None:
axis = Constant(gof.generic, None)
bcast = [False]
else:
axis = theano.tensor.as_tensor_variable(axis)
bcast = input.type.broadcastable
return theano.Apply(self, [input, axis],
[theano.tensor.TensorType(dtype="int64", broadcastable=bcast)()])
def perform(self, node, inputs, output_storage):
a = inputs[0]
axis = inputs[1]
z = output_storage[0]
z[0] = numpy.argsort(a, axis, self.kind, self.order)
def infer_shape(self, node, inputs_shapes):
if (isinstance(node.inputs[1], Constant) and
node.inputs[1].data is None):
return [(mul(*inputs_shapes[0]),)]
# axis should not be None, so there should be the same number of
# dimensions in the input and output
assert node.inputs[0].ndim == node.outputs[0].ndim
assert inputs_shapes[1] == ()
return [inputs_shapes[0]]
def grad(self, inputs, output_grads):
#No grad defined for intergers.
return [None, None]
"""
def R_op(self, inputs, eval_points):
# R_op can receive None as eval_points.
# That mean there is no diferientiable path through that input
# If this imply that you cannot compute some outputs,
# return None for those.
if eval_points[0] is None:
return eval_points
return self.grad(inputs, eval_points)
"""
def argsort(a, axis=-1, kind='quicksort', order=None):
"""
Returns the indices that would sort an array.
Perform an indirect sort along the given axis using the algorithm
specified by the kind keyword. It returns an array of indices of
the same shape as a that index data along the given axis in sorted
order.
"""
return ArgSortOp(kind, order)(a, axis)
import numpy as np
import theano
from theano.tensor import tensor
from basic import mul
class SortOp(theano.Op):
"""
This class is a wrapper for numpy sort function
"""
def __init__(self, kind, order=None):
self.kind = kind
self.order = order
def __eq__(self, other):
return (type(self) == type(other) and self.order == other.order and
self.kind == other.kind)
def __hash__(self):
return hash(type(self)) ^ hash(self.order) ^ hash(self.kind)
def __str__(self):
return self.__class__.__name__ + "{%s, %s}" % (self.kind,
str(self.order))
def make_node(self, input, axis=-1):
input = theano.tensor.as_tensor_variable(input)
if axis is None:
axis = theano.Constant(theano.gof.generic, None)
# axis=None flattens the array before sorting
out_type = tensor(dtype=input.dtype, broadcastable=[False])
else:
axis = theano.tensor.as_tensor_variable(axis)
out_type = input.type()
return theano.Apply(self, [input, axis], [out_type])
def perform(self, node, inputs, output_storage):
a = inputs[0]
axis = inputs[1]
z = output_storage[0]
z[0] = np.sort(a, axis, self.kind, self.order)
def infer_shape(self, node, inputs_shapes):
if (isinstance(node.inputs[1], theano.Constant) and
node.inputs[1].data is None):
# That means axis = None,
# So the array is flattened before being sorted
return [(mul(*inputs_shapes[0]),)]
# axis should not be None
# So there should be the same number of dimensions
# in the input and output
assert node.inputs[0].ndim == node.outputs[0].ndim
assert inputs_shapes[1] == ()
return [inputs_shapes[0]]
#**** It need the argsort, so we can't do it now.
#def grad(self, inputs, output_grads):
"""
def R_op(self, inputs, eval_points):
# R_op can receive None as eval_points.
# That mean there is no diferientiable path through that input
# If this imply that you cannot compute some outputs,
# return None for those.
if eval_points[0] is None:
return eval_points
return self.grad(inputs, eval_points)
"""
def sort(a, axis=-1, kind='quicksort', order=None):
"""
Return a sorted copy of an array.
a : Tensor
Tensor to be sorted
axis : Tensor
Axis along which to sort. If None, the array is
flattened before sorting.
kind : {'quicksort', 'mergesort', 'heapsort'}, optional
Sorting algorithm. Default is 'quicksort'.
order : list, optional
When `a` is a structured array, this argument specifies which
fields to compare first, second, and so on. This list does not
need to include all of the fields.
"""
return SortOp(kind, order)(a, axis)
class ArgSortOp(theano.Op):
"""
This class is a wrapper for numpy argsort function
"""
def __init__(self, kind, order=None):
self.kind = kind
self.order = order
def __eq__(self, other):
return (type(self) == type(other) and
self.order == other.order and
self.kind == other.kind)
def __hash__(self):
return hash(type(self)) ^ hash(self.order) ^ hash(self.kind)
def __str__(self):
return (self.__class__.__name__
+ "{%s, %s}" % (self.kind, str(self.order)))
def make_node(self, input, axis=-1):
input = theano.tensor.as_tensor_variable(input)
if axis is None:
axis = theano.Constant(theano.gof.generic, None)
bcast = [False]
else:
axis = theano.tensor.as_tensor_variable(axis)
bcast = input.type.broadcastable
return theano.Apply(self, [input, axis],
[theano.tensor.TensorType(dtype="int64", broadcastable=bcast)()])
def perform(self, node, inputs, output_storage):
a = inputs[0]
axis = inputs[1]
z = output_storage[0]
z[0] = np.argsort(a, axis, self.kind, self.order)
def infer_shape(self, node, inputs_shapes):
if (isinstance(node.inputs[1], theano.Constant) and
node.inputs[1].data is None):
return [(mul(*inputs_shapes[0]),)]
# axis should not be None, so there should be the same number of
# dimensions in the input and output
assert node.inputs[0].ndim == node.outputs[0].ndim
assert inputs_shapes[1] == ()
return [inputs_shapes[0]]
def grad(self, inputs, output_grads):
#No grad defined for intergers.
return [None, None]
"""
def R_op(self, inputs, eval_points):
# R_op can receive None as eval_points.
# That mean there is no diferientiable path through that input
# If this imply that you cannot compute some outputs,
# return None for those.
if eval_points[0] is None:
return eval_points
return self.grad(inputs, eval_points)
"""
def argsort(a, axis=-1, kind='quicksort', order=None):
"""
Returns the indices that would sort an array.
Perform an indirect sort along the given axis using the algorithm
specified by the kind keyword. It returns an array of indices of
the same shape as a that index data along the given axis in sorted
order.
"""
return ArgSortOp(kind, order)(a, axis)
import unittest
from numpy.testing import assert_allclose
from theano.tests import unittest_tools as utt
import numpy as np
import theano
from theano import tensor
from theano.tensor.sort import sort, SortOp
from theano.tensor.sort import argsort, ArgSortOp
class test_sort(unittest.TestCase):
def setUp(self):
self.rng = np.random.RandomState(seed=utt.fetch_seed())
self.m_val = self.rng.rand(3, 2)
self.v_val = self.rng.rand(4)
def test1(self):
a = tensor.dmatrix()
w = sort(a)
f = theano.function([a], w)
assert_allclose(f(self.m_val), np.sort(self.m_val))
def test2(self):
a = tensor.dmatrix()
axis = tensor.scalar()
w = sort(a, axis)
f = theano.function([a, axis], w)
for axis_val in 0, 1:
gv = f(self.m_val, axis_val)
gt = np.sort(self.m_val, axis_val)
assert_allclose(gv, gt)
def test3(self):
a = tensor.dvector()
w2 = sort(a)
f = theano.function([a], w2)
gv = f(self.v_val)
gt = np.sort(self.v_val)
assert_allclose(gv, gt)
def test4(self):
a = tensor.dmatrix()
axis = tensor.scalar()
l = sort(a, axis, "mergesort")
f = theano.function([a, axis], l)
for axis_val in 0, 1:
gv = f(self.m_val, axis_val)
gt = np.sort(self.m_val, axis_val)
assert_allclose(gv, gt)
def test5(self):
a1 = SortOp("mergesort", [])
a2 = SortOp("quicksort", [])
#All the below should give true
assert a1 != a2
assert a1 == SortOp("mergesort", [])
assert a2 == SortOp("quicksort", [])
def test_None(self):
a = tensor.dmatrix()
l = sort(a, None)
f = theano.function([a], l)
gv = f(self.m_val)
gt = np.sort(self.m_val, None)
assert_allclose(gv, gt)
class TensorInferShapeTester(utt.InferShapeTester):
def test_sort(self):
x = tensor.matrix()
self._compile_and_check(
[x],
[sort(x)],
[np.random.randn(10, 40).astype(theano.config.floatX)],
SortOp)
self._compile_and_check(
[x],
[sort(x, axis=None)],
[np.random.randn(10, 40).astype(theano.config.floatX)],
SortOp)
def test_argsort():
#Set up
rng = np.random.RandomState(seed=utt.fetch_seed())
m_val = rng.rand(3, 2)
v_val = rng.rand(4)
#Example 1
a = tensor.dmatrix()
w = argsort(a)
f = theano.function([a], w)
gv = f(m_val)
gt = np.argsort(m_val)
assert_allclose(gv, gt)
#Example 2
a = tensor.dmatrix()
axis = tensor.scalar()
w = argsort(a, axis)
f = theano.function([a, axis], w)
for axis_val in 0, 1:
gv = f(m_val, axis_val)
gt = np.argsort(m_val, axis_val)
assert_allclose(gv, gt)
#Example 3
a = tensor.dvector()
w2 = argsort(a)
f = theano.function([a], w2)
gv = f(v_val)
gt = np.argsort(v_val)
assert_allclose(gv, gt)
#Example 4
a = tensor.dmatrix()
axis = tensor.scalar()
l = argsort(a, axis, "mergesort")
f = theano.function([a, axis], l)
for axis_val in 0, 1:
gv = f(m_val, axis_val)
gt = np.argsort(m_val, axis_val)
assert_allclose(gv, gt)
#Example 5
a = tensor.dmatrix()
axis = tensor.scalar()
a1 = ArgSortOp("mergesort", [])
a2 = ArgSortOp("quicksort", [])
#All the below should give true
assert a1 != a2
assert a1 == ArgSortOp("mergesort", [])
assert a2 == ArgSortOp("quicksort", [])
#Example 6: Testing axis=None
a = tensor.dmatrix()
w2 = argsort(a, None)
f = theano.function([a], w2)
gv = f(m_val)
gt = np.argsort(m_val, None)
assert_allclose(gv, gt)
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论