提交 685f5fd8 authored 作者: nouiz's avatar nouiz

Merge pull request #780 from bouchnic/sparse

Sparse
差异被折叠。
...@@ -9,6 +9,7 @@ U{http://www-users.cs.umn.edu/~saad/software/SPARSKIT/paper.ps}. ...@@ -9,6 +9,7 @@ U{http://www-users.cs.umn.edu/~saad/software/SPARSKIT/paper.ps}.
#### COPIED FROM hpu/icml09/sp.py #### COPIED FROM hpu/icml09/sp.py
import numpy import numpy
import scipy
from scipy import sparse as scipy_sparse from scipy import sparse as scipy_sparse
import theano import theano
...@@ -18,7 +19,11 @@ from theano.gof.python25 import all, any ...@@ -18,7 +19,11 @@ from theano.gof.python25 import all, any
from theano.sparse.basic import Remove0, remove0 from theano.sparse.basic import Remove0, remove0
# To maintain compatibility # To maintain compatibility
from theano.sparse import SpSum, sp_sum from theano.sparse import (
SpSum, sp_sum,
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):
...@@ -27,206 +32,6 @@ def register_specialize(lopt, *tags, **kwargs): ...@@ -27,206 +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.
"""
def __eq__(self, other):
return (type(self) == type(other))
def __hash__(self):
return hash(type(self))
def __str__(self):
return "Diag"
def make_node(self, x):
return gof.Apply(self, [x], [tensor.tensor(broadcastable=(False,),
dtype=x.dtype)])
def perform(self, node, (x,), (z,)):
M, N = x.shape
if M != N:
raise ValueError("DenseDiag argument not square. Shape:", x.shape)
assert x.format == 'csc'
data = x.data
indices = x.indices
indptr = x.indptr
diag = numpy.zeros(N, x.dtype)
#TODO: try using ndarrays and then prune() on the result
# it could be optimized in the case the sparse structure
# does not allow index duplication
for j in xrange(0, N):
for i_idx in xrange(indptr[j], indptr[j + 1]):
if indices[i_idx] == j:
diag[j] += data[i_idx]
z[0] = diag
def grad(self, (diag,), (gz,)):
return [square_diagonal(gz)]
def infer_shape(self, nodes, shapes):
matrix_shape = shapes[0]
diag_length = matrix_shape[0]
return [(diag_length,)]
diag = Diag()
class SquareDiagonal(Op):
"""
Return a square sparse (csc) matrix whose diagonal
is given by the dense vector argument.
"""
def __eq__(self, other):
return (type(self) == type(other))
def __hash__(self):
return hash(type(self))
def __str__(self):
return "SquareDiagonal"
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, (diag,), (z,)):
N, = diag.shape
indptr = range(N + 1)
indices = indptr[0:N]
z[0] = scipy_sparse.csc_matrix((diag, indices, indptr),
(N, N), copy=True)
def grad(self, input, (gz,)):
return [diag(gz)]
def infer_shape(self, nodes, shapes):
diag_length = shapes[0][0]
return [(diag_length, diag_length)]
square_diagonal = SquareDiagonal()
class ColScaleCSC(Op):
"""
Scale each columns of a sparse matrix by the corresponding element
of a dense vector
"""
def make_node(self, x, s):
if x.format != 'csc':
raise ValueError('x was not a csc matrix')
return gof.Apply(self, [x, s], [x.type()])
def perform(self, node, (x, s), (z,)):
M, N = x.shape
assert x.format == 'csc'
assert s.shape == (N,)
y = x.copy()
for j in xrange(0, N):
y.data[y.indptr[j]: y.indptr[j + 1]] *= s[j]
z[0] = y
def grad(self, (x, s), (gz,)):
return [col_scale(gz, s), sp_sum(x * gz, axis=0)]
class RowScaleCSC(Op):
"""
Scale each row of a sparse matrix by the corresponding element of
a dense vector
"""
def make_node(self, x, s):
return gof.Apply(self, [x, s], [x.type()])
def perform(self, node, (x, s), (z,)):
M, N = x.shape
assert x.format == 'csc'
assert s.shape == (M,)
indices = x.indices
indptr = x.indptr
y_data = x.data.copy()
for j in xrange(0, N):
for i_idx in xrange(indptr[j], indptr[j + 1]):
y_data[i_idx] *= s[indices[i_idx]]
z[0] = scipy_sparse.csc_matrix((y_data, indices, indptr), (M, N))
def grad(self, (x, s), (gz,)):
return [row_scale(gz, s), sp_sum(x * gz, axis=1)]
def col_scale(x, s):
if x.format == 'csc':
return ColScaleCSC()(x, s)
elif x.format == 'csr':
return RowScaleCSC()(x.T, s).T
else:
raise NotImplementedError()
def row_scale(x, s):
return col_scale(x.T, s).T
class EnsureSortedIndices(Op):
"""
Remove explicit zeros from a sparse matrix, and resort indices
"""
def __init__(self, inplace):
self.inplace = inplace
if self.inplace:
self.view_map = {0: [0]}
def make_node(self, x):
return gof.Apply(self, [x], [x.type()])
def perform(self, node, inputs, output_storage):
x = inputs[0]
z = output_storage[0]
if self.inplace:
x.sort_indices()
z[0] = x
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):
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.
......
...@@ -19,6 +19,7 @@ from theano.sparse.basic import ( ...@@ -19,6 +19,7 @@ from theano.sparse.basic import (
AddSSData, add_s_s_data, AddSSData, add_s_s_data,
MulSDCSC, mul_s_d_csc, MulSDCSR, mul_s_d_csr, MulSDCSC, mul_s_d_csc, MulSDCSR, mul_s_d_csr,
Multinomial, multinomial, Poisson, poisson, Multinomial, multinomial, Poisson, poisson,
Binomial, csr_fbinomial, csc_fbinomial, csr_dbinomial, csc_dbinomial,
structured_monoid, structured_monoid,
structured_sigmoid, structured_exp, structured_log, structured_pow, structured_sigmoid, structured_exp, structured_log, structured_pow,
structured_minimum, structured_maximum, structured_add, structured_minimum, structured_maximum, structured_add,
...@@ -35,71 +36,3 @@ from theano.sparse.opt import ( ...@@ -35,71 +36,3 @@ from theano.sparse.opt import (
# Alias to maintain compatibility # Alias to maintain compatibility
EliminateZeros = Remove0 EliminateZeros = Remove0
eliminate_zeros = remove0 eliminate_zeros = remove0
class Binomial(gof.op.Op):
# TODO This op is not an equivalent of numpy.random.binomial. In
# facts, this does not follow a binomial distribution at all.
# To see it, just try with p = 1.
"""Return a sparse matrix having random values from a binomial
density having number of experiment `n` and probability of succes
`p`.
.. warning::
For now, this op does not return a true binomial
distribution. It is a random disposition of ones
in a sparse matrix.
:param n: Tensor scalar representing the number of experiment.
:param p: Tensor scalar representing the probability of success.
:param shape: Tensor vector for the output shape.
:return: A sparse matrix of integers representing the number
of success.
"""
def __init__(self, format, dtype):
self.format = format
self.dtype = dtype
def __eq__(self, other):
return ((type(self) == type(other)) and
self.format == other.format and
self.dtype == other.dtype)
def __hash__(self):
return hash(type(self)) ^ hash(self.format) ^ hash(self.dtype)
def make_node(self, n, p, shape):
n = tensor.as_tensor_variable(n)
p = tensor.as_tensor_variable(p)
shape = tensor.as_tensor_variable(shape)
return gof.Apply(self, [n, p, shape], [SparseType(dtype=self.dtype,
format=self.format).make_variable()])
def perform(self, node, (n, p, shape, ), (out, )):
N = n * p * shape[0] * shape[1]
data = numpy.ones(N, dtype=self.dtype)
row = numpy.random.randint(0, shape[0], N)
col = numpy.random.randint(0, shape[1], N)
res = scipy.sparse.coo_matrix((data, (row, col)), shape=shape)
out[0] = getattr(res, 'to' + self.format)()
out[0].data = numpy.ones_like(out[0].data)
def grad(self, (n, p, shape, ), (gz,)):
return None, None, None
def infer_shape(self, node, ins_shapes):
return [(node.inputs[2][0], node.inputs[2][1])]
def __str__(self):
return self.__class__.__name__
csr_fbinomial = Binomial('csr', 'float32')
csc_fbinomial = Binomial('csc', 'float32')
csr_dbinomial = Binomial('csr', 'float64')
csc_dbinomial = Binomial('csc', 'float64')
...@@ -18,6 +18,7 @@ from theano.sparse.sandbox import sp ...@@ -18,6 +18,7 @@ from theano.sparse.sandbox import sp
from theano.sparse.tests.test_basic import random_lil from theano.sparse.tests.test_basic import random_lil
from theano.tests import unittest_tools as utt from theano.tests import unittest_tools as utt
from theano.sparse import verify_grad_sparse from theano.sparse import verify_grad_sparse
from theano.sparse.tests.test_basic import sparse_random_inputs
class TestSP(unittest.TestCase): class TestSP(unittest.TestCase):
...@@ -363,121 +364,6 @@ class TestSP(unittest.TestCase): ...@@ -363,121 +364,6 @@ class TestSP(unittest.TestCase):
utt.verify_grad(d, [kvals]) utt.verify_grad(d, [kvals])
def test_diag():
m = theano.sparse.csc_matrix()
d = sp.diag(m)
f = theano.function([m], d)
f2 = theano.function([m], d.shape)
for K in 1, 5:
np_matrix = numpy.asarray(numpy.reshape(range(K**2),(K,K)),
dtype=theano.config.floatX)
diag = numpy.diagonal(np_matrix)
sp_matrix = scipy.sparse.csc_matrix(np_matrix)
assert numpy.all(diag == f(sp_matrix))
assert f2(sp_matrix) == diag.shape
def test_square_diagonal():
for K in 1, 5:
d = tensor.ivector()
sd = sp.square_diagonal(d)
f = theano.function([d], sd)
n = numpy.zeros((K,K), dtype='int32')
for i in range(K):
n[i,i] = i
assert numpy.all(n == f(range(K)).toarray())
def test_ensure_sorted_indices():
x = 2000
y = 2000
sparsity = 1000
for i in range(2):
# testing both csc and csr
if i is 0:
# csc
input_tensor = theano.sparse.csc_dmatrix()
sample = scipy.sparse.csc_matrix(random_lil((x,y),'float64',sparsity))
else:
# csr
input_tensor = theano.sparse.csr_dmatrix()
sample = scipy.sparse.csr_matrix(random_lil((x,y),'float64',sparsity))
sort_op = sp.ensure_sorted_indices(input_tensor)
f = theano.function([input_tensor], sort_op)
sorted_scipy = sample.sorted_indices()
sorted_theano = f(sample)
assert numpy.all(sorted_theano.todense() == sorted_scipy.todense())
def test_square_diagonal_grad():
def d(x):
return sp.sp_sum(sp.square_diagonal(x), sparse_grad=True)
utt.verify_grad(d, [[0.0, 0.1, 0.2, 0.3]],
mode=theano.Mode(linker='py', optimizer='fast_compile'))
def test_diag_grad():
def d(x):
sp_x = theano.sparse.csc_from_dense(x)
diag_x = sp.diag(sp_x)
return diag_x.sum()
diag_mat = numpy.zeros((4,4))
for idx in xrange(4):
diag_mat[idx, idx] += idx * 0.1
utt.verify_grad(d, [diag_mat],
mode=theano.Mode(linker='py', optimizer='fast_compile'))
def test_row_scale():
x = theano.sparse.csc_dmatrix()
s = theano.tensor.dvector()
rng = numpy.random.RandomState(8723)
R = 5
C = 8
x_val_dense = numpy.zeros((R, C), dtype='d')
for idx in [(0, 0), (4, 1), (2, 1), (3, 3), (4, 4), (3, 7), (2, 7)]:
x_val_dense.__setitem__(idx, rng.randn())
x_val = scipy.sparse.csc_matrix(x_val_dense)
s_val = rng.randn(R)
f = theano.function([x, s], sp.row_scale(x, s))
# print 'A', f(x_val, s_val).toarray()
# print 'B', (x_val_dense.T * s_val).T
assert numpy.all(f(x_val, s_val).toarray() == (x_val_dense.T * s_val).T)
verify_grad_sparse(sp.row_scale, [x_val, s_val], structured=False)
def test_col_scale():
x = theano.sparse.csc_dmatrix()
s = theano.tensor.dvector()
rng = numpy.random.RandomState(8723)
R = 5
C = 8
x_val_dense = numpy.zeros((R, C), dtype='d')
for idx in [(0, 0), (4, 1), (2, 1), (3, 3), (4, 4), (3, 7), (2, 7)]:
x_val_dense.__setitem__(idx, rng.randn())
x_val = scipy.sparse.csc_matrix(x_val_dense)
s_val = rng.randn(C)
f = theano.function([x, s], sp.col_scale(x, s))
# print 'A', f(x_val, s_val).toarray()
# print 'B', (x_val_dense * s_val)
assert numpy.all(f(x_val, s_val).toarray() == (x_val_dense * s_val))
verify_grad_sparse(sp.col_scale, [x_val, s_val], structured=False)
if __name__ == '__main__': if __name__ == '__main__':
if 0: if 0:
test_remove0() test_remove0()
......
...@@ -22,45 +22,5 @@ from theano.tests import unittest_tools as utt ...@@ -22,45 +22,5 @@ from theano.tests import unittest_tools as utt
from theano.sparse.basic import verify_grad_sparse from theano.sparse.basic import verify_grad_sparse
class BinomialTester(utt.InferShapeTester):
n = tensor.scalar()
p = tensor.scalar()
shape = tensor.lvector()
_n = 5
_p = .25
_shape = np.asarray([3, 5], dtype='int64')
inputs = [n, p, shape]
_inputs = [_n, _p, _shape]
def setUp(self):
super(BinomialTester, self).setUp()
self.op_class = S2.Binomial
def test_op(self):
for sp_format in sparse.sparse_formats:
for o_type in sparse.float_dtypes:
f = theano.function(
self.inputs,
S2.Binomial(sp_format, o_type)(*self.inputs))
tested = f(*self._inputs)
assert tested.shape == tuple(self._shape)
assert tested.format == sp_format
assert tested.dtype == o_type
assert np.allclose(np.floor(tested.todense()),
tested.todense())
def test_infer_shape(self):
for sp_format in sparse.sparse_formats:
for o_type in sparse.float_dtypes:
self._compile_and_check(
self.inputs,
[S2.Binomial(sp_format, o_type)(*self.inputs)],
self._inputs,
self.op_class)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论