提交 b8ecaae2 authored 作者: nouiz's avatar nouiz

Merge pull request #462 from abergeron/sparse_verify

Sparse verify
...@@ -17,6 +17,7 @@ from theano import gof, tensor, compile, scalar, config ...@@ -17,6 +17,7 @@ from theano import gof, tensor, compile, scalar, config
from theano.gof.python25 import all from theano.gof.python25 import all
from theano.tensor import blas from theano.tensor import blas
from theano.sparse.utils import hash_from_sparse from theano.sparse.utils import hash_from_sparse
import theano.tests.unittest_tools as utt
sparse_formats = ['csc', 'csr'] sparse_formats = ['csc', 'csr']
...@@ -140,6 +141,62 @@ def as_sparse_or_tensor_variable(x, name=None): ...@@ -140,6 +141,62 @@ def as_sparse_or_tensor_variable(x, name=None):
return theano.tensor.as_tensor_variable(x, name) return theano.tensor.as_tensor_variable(x, name)
def verify_grad_sparse(op, pt, structured=False, *args, **kwargs):
"""
Wrapper for theano.test.unittest_tools.py:verify_grad
Converts sparse variables back and forth.
"""
conv_none = lambda x: x
def conv_csr(ind, indptr, shp):
def f(spdata):
return CSR(spdata, ind, indptr, shp)
return f
def conv_csc(ind, indptr, shp):
def f(spdata):
return CSC(spdata, ind, indptr, shp)
return f
iconv = []
dpt = []
for p in pt:
if _is_sparse(p):
if structured:
dpt.append(p.data)
else:
dpt.append(p.toarray())
if p.format == 'csr':
if structured:
iconv.append(conv_csr(p.indices[:p.size], p.indptr,
p.shape))
else:
iconv.append(csr_from_dense)
elif p.format == 'csc':
if structured:
iconv.append(conv_csc(p.indices[:p.size], p.indptr,
p.shape))
else:
iconv.append(csc_from_dense)
else:
raise NotImplementedError("No conv for %s" % (p.format,))
else:
dpt.append(p)
iconv.append(conv_none)
output = op(*[as_sparse_or_tensor_variable(p) for p in pt])
if isinstance(output, (list, tuple)):
raise NotImplementedError("verify_grad can't deal with "
"multiple outputs")
if _is_sparse_variable(output):
oconv = DenseFromSparse(structured=structured)
else:
oconv = conv_none
def conv_op(*inputs):
ipt = [conv(i) for i, conv in zip(inputs, iconv)]
out = op(*ipt)
return oconv(out)
return utt.verify_grad(conv_op, dpt, *args, **kwargs)
verify_grad_sparse.E_grad = utt.verify_grad.E_grad
def constant(x, name=None): def constant(x, name=None):
if not isinstance(x, scipy.sparse.spmatrix): if not isinstance(x, scipy.sparse.spmatrix):
raise TypeError("sparse.constant must be called on a " raise TypeError("sparse.constant must be called on a "
...@@ -694,13 +751,15 @@ class DenseFromSparse(gof.op.Op): ...@@ -694,13 +751,15 @@ class DenseFromSparse(gof.op.Op):
""" """
Convert a sparse matrix to an `ndarray`. Convert a sparse matrix to an `ndarray`.
""" """
sparse_grad = True def __init__(self, structured=True):
"""WRITEME""" self.sparse_grad = structured
def __eq__(self, other): def __eq__(self, other):
return (type(self) == type(other)) return (type(self) == type(other)) and \
(self.sparse_grad == other.sparse_grad)
def __hash__(self): def __hash__(self):
return hash(type(self)) return hash(type(self))^hash(self.sparse_grad)
def make_node(self, x): def make_node(self, x):
x = as_sparse_variable(x) x = as_sparse_variable(x)
......
...@@ -10,7 +10,7 @@ except ImportError: ...@@ -10,7 +10,7 @@ except ImportError:
pass # The variable enable_sparse will be used to disable the test file. pass # The variable enable_sparse will be used to disable the test file.
import theano import theano
from theano import compile, config from theano import compile, config, gof
from theano.sparse import enable_sparse from theano.sparse import enable_sparse
from theano.gof.python25 import all, any, product from theano.gof.python25 import all, any, product
...@@ -19,13 +19,14 @@ if enable_sparse == False: ...@@ -19,13 +19,14 @@ if enable_sparse == False:
from theano.sparse.basic import _is_dense, _is_sparse, _mtypes from theano.sparse.basic import _is_dense, _is_sparse, _mtypes
from theano.sparse.basic import _is_dense_variable, _is_sparse_variable from theano.sparse.basic import _is_dense_variable, _is_sparse_variable
from theano.sparse.basic import verify_grad_sparse
from theano.sparse import as_sparse_variable, CSC, CSR, CSM, CSMProperties from theano.sparse import as_sparse_variable, CSC, CSR, CSM, CSMProperties
from theano.sparse import SparseType, StructuredDotCSC, CSMGrad from theano.sparse import SparseType, StructuredDotCSC, CSMGrad
from theano.sparse import AddSS, AddSD, MulSS, MulSD, Transpose, Neg from theano.sparse import AddSS, AddSD, MulSS, MulSD, Transpose, Neg
from theano.sparse import add, mul, structured_dot, transpose from theano.sparse import add, mul, structured_dot, transpose
from theano.sparse import (csc_from_dense, csr_from_dense, dense_from_sparse, from theano.sparse import (csc_from_dense, csr_from_dense, dense_from_sparse,
SparseFromDense) SparseFromDense)
from theano.sparse import Dot, Usmm, UsmmCscDense from theano.sparse import Dot, Usmm, UsmmCscDense, sp_ones_like
#from theano.sparse import get_item_2d, get_item_scalar #from theano.sparse import get_item_2d, get_item_scalar
from theano.tests import unittest_tools as utt from theano.tests import unittest_tools as utt
...@@ -61,6 +62,49 @@ def random_lil(shape, dtype, nnz): ...@@ -61,6 +62,49 @@ def random_lil(shape, dtype, nnz):
value) value)
return rval return rval
class T_verify_grad_sparse(unittest.TestCase):
class FailOp(gof.op.Op):
def __init__(self, structured):
self.structured = structured
def __eq__(self, other):
return (type(self) == type(other)) and \
self.structured == other.structured
def __hash__(self):
return hash(type(self)) ^ hash(self.structured)
def make_node(self, x):
x = as_sparse_variable(x)
return gof.Apply(self, [x], [x.type()])
def perform(self, node, (x, ), (out, )):
assert _is_sparse(x)
out[0] = -x
def grad(self, (x,), (gz,)):
assert _is_sparse_variable(x) and _is_sparse_variable(gz)
if self.structured:
return sp_ones_like(x)*dense_from_sparse(gz),
else:
return gz,
def infer_shape(self, node, shapes):
return [shapes[0]]
def test_grad_fail(self):
self.assertRaises(verify_grad_sparse.E_grad,
verify_grad_sparse,
self.FailOp(structured=False),
[sp.csr_matrix(random_lil((10, 40),
config.floatX, 3))])
self.assertRaises(verify_grad_sparse.E_grad,
verify_grad_sparse,
self.FailOp(structured=True),
[sp.csr_matrix(random_lil((10, 40),
config.floatX, 3))])
class T_transpose(unittest.TestCase): class T_transpose(unittest.TestCase):
def setUp(self): def setUp(self):
...@@ -251,6 +295,7 @@ class T_AddMul(unittest.TestCase): ...@@ -251,6 +295,7 @@ class T_AddMul(unittest.TestCase):
self.assertTrue(numpy.all(val.todense() == (a + b).todense())) self.assertTrue(numpy.all(val.todense() == (a + b).todense()))
ans = numpy.array([[1., 2], [3, 4], [5, 6]]) ans = numpy.array([[1., 2], [3, 4], [5, 6]])
self.assertTrue(numpy.all(val.todense() == ans)) self.assertTrue(numpy.all(val.todense() == ans))
verify_grad_sparse(op, [a, b], structured=False)
elif op is mul: elif op is mul:
self.assertTrue(numpy.all(val.todense() self.assertTrue(numpy.all(val.todense()
== (a.multiply(b)).todense())) == (a.multiply(b)).todense()))
...@@ -462,27 +507,12 @@ class test_structureddot(unittest.TestCase): ...@@ -462,27 +507,12 @@ class test_structureddot(unittest.TestCase):
mat = numpy.asarray(numpy.random.randn(3, 2), 'float32') mat = numpy.asarray(numpy.random.randn(3, 2), 'float32')
def buildgraphCSC(spdata, sym_mat): verify_grad_sparse(structured_dot, [spmat, mat], structured=True)
csc = CSC(spdata, spmat.indices[:spmat.size],
spmat.indptr, spmat.shape)
assert csc.type.dtype == 'float32'
rval = structured_dot(csc, sym_mat)
assert rval.type.dtype == 'float32'
return rval
utt.verify_grad(buildgraphCSC,
[spmat.data, mat])
def buildgraphCSC_T(spdata, sym_mat): def buildgraph_T(spmat, mat):
csc = CSC(spdata, spmat.indices[:spmat.size], return structured_dot(mat.T, spmat.T)
spmat.indptr, spmat.shape)
assert csc.type.dtype == 'float32'
rval = structured_dot(sym_mat.T, csc.T)
assert rval.type.dtype == 'float32'
return rval
utt.verify_grad(buildgraphCSC_T, verify_grad_sparse(buildgraph_T, [spmat, mat], structured=True)
[spmat.data, mat])
def test_structureddot_csr_grad(self): def test_structureddot_csr_grad(self):
...@@ -493,27 +523,12 @@ class test_structureddot(unittest.TestCase): ...@@ -493,27 +523,12 @@ class test_structureddot(unittest.TestCase):
mat = numpy.asarray(numpy.random.randn(3, 2), 'float64') mat = numpy.asarray(numpy.random.randn(3, 2), 'float64')
def buildgraph(spdata, sym_mat): verify_grad_sparse(structured_dot, [spmat, mat], structured=True)
csr = CSR(spdata, spmat.indices[:spmat.size],
spmat.indptr, spmat.shape)
assert csr.type.dtype == 'float64'
rval = structured_dot(csr, sym_mat)
assert rval.type.dtype == 'float64'
return rval
utt.verify_grad(buildgraph,
[spmat.data, mat])
def buildgraph_T(spdata, sym_mat): def buildgraph_T(spmat, mat):
csr = CSR(spdata, spmat.indices[:spmat.size], return structured_dot(mat.T, spmat.T)
spmat.indptr, spmat.shape)
assert csr.type.dtype == 'float64'
rval = structured_dot(sym_mat.T, csr.T)
assert rval.type.dtype == 'float64'
return rval
utt.verify_grad(buildgraph, verify_grad_sparse(buildgraph_T, [spmat, mat], structured=True)
[spmat.data, mat])
def test_infer_shape_csr_csc_grad(self): def test_infer_shape_csr_csc_grad(self):
for sparsetype in ('csr', 'csc'): for sparsetype in ('csr', 'csc'):
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论