提交 60bf2afe authored 作者: Nicolas Bouchard's avatar Nicolas Bouchard

Move op and tests out of the sandbox.

上级 3c57118b
...@@ -1508,6 +1508,164 @@ def sp_sum(x, axis=None, sparse_grad=False): ...@@ -1508,6 +1508,164 @@ def sp_sum(x, axis=None, sparse_grad=False):
return SpSum(axis, sparse_grad)(x) return SpSum(axis, sparse_grad)(x)
class Diag(gof.op.Op):
"""Extract the diagonal of a square sparse matrix as a dense
vector.
:param x: A square sparse matrix in csc format.
:return: A dense vector representing the diagonal elements.
:note:
- The grad implemented is regular, i.e. not structured, since
the output is a dense vector.
"""
def __eq__(self, other):
return (type(self) == type(other))
def __hash__(self):
return hash(type(self))
def make_node(self, x):
return gof.Apply(self, [x], [tensor.tensor(broadcastable=(False,),
dtype=x.dtype)])
def perform(self, node, (x,), (z,)):
N, M = x.shape
if N != M:
raise ValueError('Diag only apply on square matrix')
z[0] = x.diagonal()
def grad(self, (x,), (gz,)):
return [square_diagonal(gz)]
def infer_shape(self, nodes, shapes):
return [(tensor.minimum(*shapes[0]), )]
def __str__(self):
return self.__class__.__name__
diag = Diag()
class SquareDiagonal(gof.op.Op):
"""Return a square sparse (csc) matrix whose diagonal
is given by the dense vector argument.
:param x: Dense vector for the diagonal.
:return: A sparse matrix having `x` as diagonal.
:note:
- The grad implemented is regular, i.e. not structured.
"""
def __eq__(self, other):
return type(self) == type(other)
def __hash__(self):
return hash(type(self))
def make_node(self, diag):
diag = tensor.as_tensor_variable(diag)
if diag.type.ndim != 1:
raise TypeError('data argument must be a vector', diag.type)
return gof.Apply(self, [diag],
[SparseType(dtype=diag.dtype, format='csc')()])
def perform(self, node, inputs, (z,)):
diag, o_shape = inputs[0], inputs[0].shape * 2
N = len(diag)
data = diag[:N]
indices = range(N)
indptr = range(N + 1)
tup = (data, indices, indptr)
z[0] = scipy.sparse.csc_matrix(tup, copy=True)
def grad(self, inputs, (gz,)):
return [diag(gz)]
def infer_shape(self, nodes, shapes):
return [(shapes[0][0], shapes[0][0])]
def __str__(self):
return self.__class__.__name__
square_diagonal = SquareDiagonal()
class EnsureSortedIndices(gof.op.Op):
"""Resort indices of a sparse matrix.
CSR column indices are not necessarily sorted. Likewise
for CSC row indices. Use `ensure_sorted_indices` when sorted
indices are required (e.g. when passing data to other
libraries).
:param x: A sparse matrix.
:return: The same as `x` with indices sorted.
:note:
- The grad implemented is regular, i.e. not structured.
"""
def __init__(self, inplace):
self.inplace = inplace
if self.inplace:
self.view_map = {0: [0]}
def __eq__(self, other):
return type(self) == type(other)
def __hash__(self):
return hash(type(self))
def make_node(self, x):
return gof.Apply(self, [x], [x.type()])
def perform(self, node, (x, ), (z, )):
if self.inplace:
z[0] = x.sort_indices()
else:
z[0] = x.sorted_indices()
def grad(self, inputs, output_grad):
return [output_grad[0]]
def infer_shape(self, node, i0_shapes):
return i0_shapes
def __str__(self):
if self.inplace:
return self.__class__.__name__ + "{inplace}"
else:
return self.__class__.__name__ + "{no_inplace}"
ensure_sorted_indices = EnsureSortedIndices(inplace=False)
def clean(x):
"""Remove explicit zeros from a sparse matrix, and
resort indices.
CSR column indices are not necessarily sorted. Likewise
for CSC row indices. Use `clean` when sorted
indices are required (e.g. when passing data to other
libraries) and to ensure there is no zeros in the data.
:param x: A sparse matrix.
:return: The same as `x` with indices sorted and zeros
removed.
:note:
- The grad implemented is regular, i.e. not structured.
"""
return ensure_sorted_indices(remove0(x))
class AddSS(gof.op.Op): class AddSS(gof.op.Op):
'''Add two sparse matrices ''' '''Add two sparse matrices '''
def __eq__(self, other): def __eq__(self, other):
......
...@@ -21,7 +21,9 @@ from theano.sparse.basic import Remove0, remove0 ...@@ -21,7 +21,9 @@ from theano.sparse.basic import Remove0, remove0
# To maintain compatibility # To maintain compatibility
from theano.sparse import ( from theano.sparse import (
SpSum, sp_sum, SpSum, sp_sum,
ColScaleCSC, RowScaleCSC, col_scale, row_scale) ColScaleCSC, RowScaleCSC, col_scale, row_scale,
Diag, diag, SquareDiagonal, square_diagonal,
EnsureSortedIndices, ensure_sorted_indices, clean)
def register_specialize(lopt, *tags, **kwargs): def register_specialize(lopt, *tags, **kwargs):
...@@ -30,164 +32,6 @@ def register_specialize(lopt, *tags, **kwargs): ...@@ -30,164 +32,6 @@ def register_specialize(lopt, *tags, **kwargs):
*tags) *tags)
class Diag(Op):
"""Extract the diagonal of a square sparse matrix as a dense
vector.
:param x: A square sparse matrix in csc format.
:return: A dense vector representing the diagonal elements.
:note:
- The grad implemented is regular, i.e. not structured, since
the output is a dense vector.
"""
def __eq__(self, other):
return (type(self) == type(other))
def __hash__(self):
return hash(type(self))
def make_node(self, x):
return gof.Apply(self, [x], [tensor.tensor(broadcastable=(False,),
dtype=x.dtype)])
def perform(self, node, (x,), (z,)):
N, M = x.shape
if N != M:
raise ValueError('Diag only apply on square matrix')
z[0] = x.diagonal()
def grad(self, (x,), (gz,)):
return [square_diagonal(gz)]
def infer_shape(self, nodes, shapes):
return [(tensor.minimum(*shapes[0]), )]
def __str__(self):
return self.__class__.__name__
diag = Diag()
class SquareDiagonal(Op):
"""Return a square sparse (csc) matrix whose diagonal
is given by the dense vector argument.
:param x: Dense vector for the diagonal.
:return: A sparse matrix having `x` as diagonal.
:note:
- The grad implemented is regular, i.e. not structured.
"""
def __eq__(self, other):
return type(self) == type(other)
def __hash__(self):
return hash(type(self))
def make_node(self, diag):
diag = tensor.as_tensor_variable(diag)
if diag.type.ndim != 1:
raise TypeError('data argument must be a vector', diag.type)
return gof.Apply(self, [diag],
[sparse.SparseType(dtype=diag.dtype, format='csc')()])
def perform(self, node, inputs, (z,)):
diag, o_shape = inputs[0], inputs[0].shape * 2
N = len(diag)
data = diag[:N]
indices = range(N)
indptr = range(N + 1)
tup = (data, indices, indptr)
z[0] = scipy.sparse.csc_matrix(tup, copy=True)
def grad(self, inputs, (gz,)):
return [diag(gz)]
def infer_shape(self, nodes, shapes):
return [(shapes[0][0], shapes[0][0])]
def __str__(self):
return self.__class__.__name__
square_diagonal = SquareDiagonal()
class EnsureSortedIndices(Op):
"""Resort indices of a sparse matrix.
CSR column indices are not necessarily sorted. Likewise
for CSC row indices. Use `ensure_sorted_indices` when sorted
indices are required (e.g. when passing data to other
libraries).
:param x: A sparse matrix.
:return: The same as `x` with indices sorted.
:note:
- The grad implemented is regular, i.e. not structured.
"""
def __init__(self, inplace):
self.inplace = inplace
if self.inplace:
self.view_map = {0: [0]}
def __eq__(self, other):
return type(self) == type(other)
def __hash__(self):
return hash(type(self))
def make_node(self, x):
return gof.Apply(self, [x], [x.type()])
def perform(self, node, (x, ), (z, )):
if self.inplace:
z[0] = x.sort_indices()
else:
z[0] = x.sorted_indices()
def grad(self, inputs, output_grad):
return [output_grad[0]]
def infer_shape(self, node, i0_shapes):
return i0_shapes
def __str__(self):
if self.inplace:
return self.__class__.__name__ + "{inplace}"
else:
return self.__class__.__name__ + "{no_inplace}"
ensure_sorted_indices = EnsureSortedIndices(inplace=False)
def clean(x):
"""Remove explicit zeros from a sparse matrix, and
resort indices.
CSR column indices are not necessarily sorted. Likewise
for CSC row indices. Use `clean` when sorted
indices are required (e.g. when passing data to other
libraries) and to ensure there is no zeros in the data.
:param x: A sparse matrix.
:return: The same as `x` with indices sorted and zeros
removed.
:note:
- The grad implemented is regular, i.e. not structured.
"""
return ensure_sorted_indices(remove0(x))
class ConvolutionIndices(Op): class ConvolutionIndices(Op):
"""Build indices for a sparse CSC matrix that could implement A """Build indices for a sparse CSC matrix that could implement A
(convolve) B. (convolve) B.
......
...@@ -364,158 +364,6 @@ class TestSP(unittest.TestCase): ...@@ -364,158 +364,6 @@ class TestSP(unittest.TestCase):
utt.verify_grad(d, [kvals]) utt.verify_grad(d, [kvals])
class DiagTester(utt.InferShapeTester):
def setUp(self):
super(DiagTester, self).setUp()
self.op_class = sp.Diag
self.op = sp.diag
def test_op(self):
for format in theano.sparse.sparse_formats:
variable, data = sparse_random_inputs(format,
shape=(10, 10))
z = self.op(*variable)
assert z.type.broadcastable == (False, )
f = theano.function(variable, z)
tested = f(*data)
expected = data[0].toarray().diagonal()
assert numpy.allclose(tested, expected)
def test_infer_shape(self):
for format in theano.sparse.sparse_formats:
variable, data = sparse_random_inputs(format,
shape=(10, 10))
self._compile_and_check(variable,
[self.op(*variable)],
data,
self.op_class)
def test_grad(self):
for format in theano.sparse.sparse_formats:
variable, data = sparse_random_inputs(format,
shape=(10, 10))
verify_grad_sparse(
self.op,
data,
structured=False)
class SquareDiagonalTester(utt.InferShapeTester):
def setUp(self):
super(SquareDiagonalTester, self).setUp()
self.op_class = sp.SquareDiagonal
self.op = sp.square_diagonal
def test_op(self):
for format in theano.sparse.sparse_formats:
for size in range(5, 9):
variable = [tensor.vector()]
data = [numpy.random.random(size)]
f = theano.function(variable, self.op(*variable))
tested = f(*data).toarray()
expected = numpy.diag(*data)
assert numpy.allclose(tested, expected)
assert tested.dtype == expected.dtype
assert tested.shape == expected.shape
def test_infer_shape(self):
for format in theano.sparse.sparse_formats:
for size in range(5, 9):
variable = [tensor.vector()]
data = [numpy.random.random(size)]
self._compile_and_check(variable,
[self.op(*variable)],
data,
self.op_class)
def test_grad(self):
for format in theano.sparse.sparse_formats:
for size in range(5, 9):
variable = [tensor.vector()]
data = [numpy.random.random(size)]
verify_grad_sparse(
self.op,
data,
structured=False)
class EnsureSortedIndicesTester(utt.InferShapeTester):
def setUp(self):
super(EnsureSortedIndicesTester, self).setUp()
self.op_class = sp.EnsureSortedIndices
self.op = sp.ensure_sorted_indices
def test_op(self):
for format in theano.sparse.sparse_formats:
for shape in zip(range(5, 9), range(3, 7)[::-1]):
variable, data = sparse_random_inputs(format, shape=shape)
f = theano.function(variable, self.op(*variable))
tested = f(*data).toarray()
expected = data[0].sorted_indices().toarray()
assert numpy.allclose(tested, expected)
def test_infer_shape(self):
for format in theano.sparse.sparse_formats:
for shape in zip(range(5, 9), range(3, 7)[::-1]):
variable, data = sparse_random_inputs(format, shape=shape)
self._compile_and_check(variable,
[self.op(*variable)],
data,
self.op_class)
def test_grad(self):
for format in theano.sparse.sparse_formats:
for shape in zip(range(5, 9), range(3, 7)[::-1]):
variable, data = sparse_random_inputs(format, shape=shape)
verify_grad_sparse(
self.op,
data,
structured=False)
class CleanTester(utt.InferShapeTester):
def setUp(self):
super(CleanTester, self).setUp()
self.op = sp.clean
def test_op(self):
for format in theano.sparse.sparse_formats:
for shape in zip(range(5, 9), range(3, 7)[::-1]):
variable, data = sparse_random_inputs(format, shape=shape)
data[0][0, 0] = data[0][1, 1] = 0
f = theano.function(variable, self.op(*variable))
tested = f(*data)
expected = data[0]
expected.eliminate_zeros()
assert all(tested.data == expected.data)
assert not all(tested.data == 0)
tested = tested.toarray()
expected = expected.toarray()
assert numpy.allclose(tested, expected)
def test_grad(self):
for format in theano.sparse.sparse_formats:
for shape in zip(range(5, 9), range(3, 7)[::-1]):
variable, data = sparse_random_inputs(format, shape=shape)
verify_grad_sparse(
self.op,
data,
structured=False)
if __name__ == '__main__': if __name__ == '__main__':
if 0: if 0:
test_remove0() test_remove0()
......
...@@ -37,7 +37,9 @@ from theano.sparse import ( ...@@ -37,7 +37,9 @@ from theano.sparse import (
structured_sigmoid, structured_exp, structured_log, structured_sigmoid, structured_exp, structured_log,
structured_pow, structured_minimum, structured_maximum, structured_add, structured_pow, structured_minimum, structured_maximum, structured_add,
MulSV, mul_s_v, StructuredAddSV, structured_add_s_v, MulSV, mul_s_v, StructuredAddSV, structured_add_s_v,
SamplingDot, sampling_dot) SamplingDot, sampling_dot,
Diag, diag, SquareDiagonal, square_diagonal,
EnsureSortedIndices, ensure_sorted_indices, clean)
from theano.tests import unittest_tools as utt from theano.tests import unittest_tools as utt
from theano.tensor.basic import _allclose from theano.tensor.basic import _allclose
...@@ -1499,6 +1501,158 @@ class SpSumTester(utt.InferShapeTester): ...@@ -1499,6 +1501,158 @@ class SpSumTester(utt.InferShapeTester):
structured=struct) structured=struct)
class DiagTester(utt.InferShapeTester):
def setUp(self):
super(DiagTester, self).setUp()
self.op_class = Diag
self.op = diag
def test_op(self):
for format in sparse.sparse_formats:
variable, data = sparse_random_inputs(format,
shape=(10, 10))
z = self.op(*variable)
assert z.type.broadcastable == (False, )
f = theano.function(variable, z)
tested = f(*data)
expected = data[0].toarray().diagonal()
assert numpy.allclose(tested, expected)
def test_infer_shape(self):
for format in sparse.sparse_formats:
variable, data = sparse_random_inputs(format,
shape=(10, 10))
self._compile_and_check(variable,
[self.op(*variable)],
data,
self.op_class)
def test_grad(self):
for format in sparse.sparse_formats:
variable, data = sparse_random_inputs(format,
shape=(10, 10))
verify_grad_sparse(
self.op,
data,
structured=False)
class SquareDiagonalTester(utt.InferShapeTester):
def setUp(self):
super(SquareDiagonalTester, self).setUp()
self.op_class = SquareDiagonal
self.op = square_diagonal
def test_op(self):
for format in sparse.sparse_formats:
for size in range(5, 9):
variable = [tensor.vector()]
data = [numpy.random.random(size)]
f = theano.function(variable, self.op(*variable))
tested = f(*data).toarray()
expected = numpy.diag(*data)
assert numpy.allclose(tested, expected)
assert tested.dtype == expected.dtype
assert tested.shape == expected.shape
def test_infer_shape(self):
for format in sparse.sparse_formats:
for size in range(5, 9):
variable = [tensor.vector()]
data = [numpy.random.random(size)]
self._compile_and_check(variable,
[self.op(*variable)],
data,
self.op_class)
def test_grad(self):
for format in sparse.sparse_formats:
for size in range(5, 9):
variable = [tensor.vector()]
data = [numpy.random.random(size)]
verify_grad_sparse(
self.op,
data,
structured=False)
class EnsureSortedIndicesTester(utt.InferShapeTester):
def setUp(self):
super(EnsureSortedIndicesTester, self).setUp()
self.op_class = EnsureSortedIndices
self.op = ensure_sorted_indices
def test_op(self):
for format in sparse.sparse_formats:
for shape in zip(range(5, 9), range(3, 7)[::-1]):
variable, data = sparse_random_inputs(format, shape=shape)
f = theano.function(variable, self.op(*variable))
tested = f(*data).toarray()
expected = data[0].sorted_indices().toarray()
assert numpy.allclose(tested, expected)
def test_infer_shape(self):
for format in sparse.sparse_formats:
for shape in zip(range(5, 9), range(3, 7)[::-1]):
variable, data = sparse_random_inputs(format, shape=shape)
self._compile_and_check(variable,
[self.op(*variable)],
data,
self.op_class)
def test_grad(self):
for format in sparse.sparse_formats:
for shape in zip(range(5, 9), range(3, 7)[::-1]):
variable, data = sparse_random_inputs(format, shape=shape)
verify_grad_sparse(
self.op,
data,
structured=False)
class CleanTester(utt.InferShapeTester):
def setUp(self):
super(CleanTester, self).setUp()
self.op = clean
def test_op(self):
for format in sparse.sparse_formats:
for shape in zip(range(5, 9), range(3, 7)[::-1]):
variable, data = sparse_random_inputs(format, shape=shape)
data[0][0, 0] = data[0][1, 1] = 0
f = theano.function(variable, self.op(*variable))
tested = f(*data)
expected = data[0]
expected.eliminate_zeros()
assert all(tested.data == expected.data)
assert not all(tested.data == 0)
tested = tested.toarray()
expected = expected.toarray()
assert numpy.allclose(tested, expected)
def test_grad(self):
for format in sparse.sparse_formats:
for shape in zip(range(5, 9), range(3, 7)[::-1]):
variable, data = sparse_random_inputs(format, shape=shape)
verify_grad_sparse(
self.op,
data,
structured=False)
class Remove0Tester(utt.InferShapeTester): class Remove0Tester(utt.InferShapeTester):
def setUp(self): def setUp(self):
super(Remove0Tester, self).setUp() super(Remove0Tester, self).setUp()
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论