提交 3c57118b authored 作者: Nicolas Bouchard's avatar Nicolas Bouchard

Review and add tests for EnsureSortedIndices.

上级 8ead8d0f
...@@ -119,8 +119,19 @@ square_diagonal = SquareDiagonal() ...@@ -119,8 +119,19 @@ square_diagonal = SquareDiagonal()
class EnsureSortedIndices(Op): class EnsureSortedIndices(Op):
""" """Resort indices of a sparse matrix.
Remove explicit zeros from a sparse matrix, and resort indices
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): def __init__(self, inplace):
...@@ -128,15 +139,18 @@ class EnsureSortedIndices(Op): ...@@ -128,15 +139,18 @@ class EnsureSortedIndices(Op):
if self.inplace: if self.inplace:
self.view_map = {0: [0]} 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): def make_node(self, x):
return gof.Apply(self, [x], [x.type()]) return gof.Apply(self, [x], [x.type()])
def perform(self, node, inputs, output_storage): def perform(self, node, (x, ), (z, )):
x = inputs[0]
z = output_storage[0]
if self.inplace: if self.inplace:
x.sort_indices() z[0] = x.sort_indices()
z[0] = x
else: else:
z[0] = x.sorted_indices() z[0] = x.sorted_indices()
...@@ -151,11 +165,26 @@ class EnsureSortedIndices(Op): ...@@ -151,11 +165,26 @@ class EnsureSortedIndices(Op):
return self.__class__.__name__ + "{inplace}" return self.__class__.__name__ + "{inplace}"
else: else:
return self.__class__.__name__ + "{no_inplace}" return self.__class__.__name__ + "{no_inplace}"
ensure_sorted_indices = EnsureSortedIndices(inplace=False) ensure_sorted_indices = EnsureSortedIndices(inplace=False)
def clean(x): 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)) return ensure_sorted_indices(remove0(x))
......
...@@ -446,45 +446,75 @@ class SquareDiagonalTester(utt.InferShapeTester): ...@@ -446,45 +446,75 @@ class SquareDiagonalTester(utt.InferShapeTester):
structured=False) structured=False)
def test_ensure_sorted_indices(): class EnsureSortedIndicesTester(utt.InferShapeTester):
x = 2000 def setUp(self):
y = 2000 super(EnsureSortedIndicesTester, self).setUp()
sparsity = 1000 self.op_class = sp.EnsureSortedIndices
for i in range(2): self.op = sp.ensure_sorted_indices
# testing both csc and csr
if i is 0: def test_op(self):
# csc for format in theano.sparse.sparse_formats:
input_tensor = theano.sparse.csc_dmatrix() for shape in zip(range(5, 9), range(3, 7)[::-1]):
sample = scipy.sparse.csc_matrix(random_lil((x,y),'float64',sparsity)) variable, data = sparse_random_inputs(format, shape=shape)
else:
# csr f = theano.function(variable, self.op(*variable))
input_tensor = theano.sparse.csr_dmatrix() tested = f(*data).toarray()
sample = scipy.sparse.csr_matrix(random_lil((x,y),'float64',sparsity)) expected = data[0].sorted_indices().toarray()
sort_op = sp.ensure_sorted_indices(input_tensor) assert numpy.allclose(tested, expected)
f = theano.function([input_tensor], sort_op)
sorted_scipy = sample.sorted_indices() def test_infer_shape(self):
sorted_theano = f(sample) for format in theano.sparse.sparse_formats:
assert numpy.all(sorted_theano.todense() == sorted_scipy.todense()) for shape in zip(range(5, 9), range(3, 7)[::-1]):
variable, data = sparse_random_inputs(format, shape=shape)
def test_square_diagonal_grad(): self._compile_and_check(variable,
def d(x): [self.op(*variable)],
return sp.sp_sum(sp.square_diagonal(x), sparse_grad=True) data,
utt.verify_grad(d, [[0.0, 0.1, 0.2, 0.3]], self.op_class)
mode=theano.Mode(linker='py', optimizer='fast_compile'))
def test_grad(self):
def test_diag_grad(): for format in theano.sparse.sparse_formats:
def d(x): for shape in zip(range(5, 9), range(3, 7)[::-1]):
sp_x = theano.sparse.csc_from_dense(x) variable, data = sparse_random_inputs(format, shape=shape)
diag_x = sp.diag(sp_x) verify_grad_sparse(
return diag_x.sum() self.op,
data,
diag_mat = numpy.zeros((4,4)) structured=False)
for idx in xrange(4):
diag_mat[idx, idx] += idx * 0.1
class CleanTester(utt.InferShapeTester):
utt.verify_grad(d, [diag_mat], def setUp(self):
mode=theano.Mode(linker='py', optimizer='fast_compile')) 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:
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论