提交 2d87330b authored 作者: Frederic Bastien's avatar Frederic Bastien

Enable sparse elemwise multiplication by a something that can be converted to a…

Enable sparse elemwise multiplication by a something that can be converted to a tensor but is not a tensor or a sparse. Test it(and add test for all sparse mul at the same time)
上级 092d52ac
...@@ -101,6 +101,15 @@ def as_sparse_variable(x, name=None): ...@@ -101,6 +101,15 @@ def as_sparse_variable(x, name=None):
as_sparse = as_sparse_variable as_sparse = as_sparse_variable
def as_sparse_or_tensor_variable(x, name=None):
"""
If we can't make a sparse variable, we try to make a tensor variable.
"""
try:
return as_sparse_variable(x,name)
except (ValueError, TypeError):
return theano.tensor.as_tensor_variable(x,name)
def constant(x, name=None): def constant(x, name=None):
if not isinstance(x, scipy.sparse.spmatrix): if not isinstance(x, scipy.sparse.spmatrix):
...@@ -633,7 +642,7 @@ def sub(x,y): ...@@ -633,7 +642,7 @@ def sub(x,y):
class MulSS(gof.op.Op): class MulSS(gof.op.Op):
''' Elementwise multiply a sparse and a ndarray ''' ''' Elementwise multiply a sparse and a sparse '''
def __eq__(self, other): def __eq__(self, other):
return (type(self) == type(other)) return (type(self) == type(other))
def __hash__(self): def __hash__(self):
...@@ -663,6 +672,12 @@ class MulSD(gof.op.Op): ...@@ -663,6 +672,12 @@ class MulSD(gof.op.Op):
return hash(type(self)) return hash(type(self))
def make_node(self, x, y): def make_node(self, x, y):
x, y = as_sparse_variable(x), tensor.as_tensor_variable(y) x, y = as_sparse_variable(x), tensor.as_tensor_variable(y)
#upcast the tensor. Is the cast of sparse done implemented?
dtype = scalar.upcast(x.type.dtype, y.type.dtype)
if y.type.dtype != dtype:
y = tensor.cast(y,dtype)
if x.type.dtype != y.type.dtype: if x.type.dtype != y.type.dtype:
raise NotImplementedError() raise NotImplementedError()
# The magic number two here arises because L{scipy.sparse} # The magic number two here arises because L{scipy.sparse}
...@@ -720,8 +735,8 @@ def mul(x,y): ...@@ -720,8 +735,8 @@ def mul(x,y):
""" """
Multiply (elementwise) two matrices, at least one of which is sparse. Multiply (elementwise) two matrices, at least one of which is sparse.
""" """
if hasattr(x, 'getnnz'): x = as_sparse_variable(x) x = as_sparse_or_tensor_variable(x)
if hasattr(y, 'getnnz'): y = as_sparse_variable(y) y = as_sparse_or_tensor_variable(y)
x_is_sparse_variable = _is_sparse_variable(x) x_is_sparse_variable = _is_sparse_variable(x)
y_is_sparse_variable = _is_sparse_variable(y) y_is_sparse_variable = _is_sparse_variable(y)
......
...@@ -18,7 +18,7 @@ if enable_sparse == False: ...@@ -18,7 +18,7 @@ if enable_sparse == False:
from theano.sparse.basic import _is_dense, _is_sparse, _is_dense_variable, _is_sparse_variable from theano.sparse.basic import _is_dense, _is_sparse, _is_dense_variable, _is_sparse_variable
from theano.sparse.basic import _mtypes from theano.sparse.basic import _mtypes
from theano.sparse import as_sparse_variable, CSC, CSR, CSM, CSMProperties, SparseType, StructuredDotCSC from theano.sparse import as_sparse_variable, CSC, CSR, CSM, CSMProperties, SparseType, StructuredDotCSC
from theano.sparse import add, 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
from theano.tests import unittest_tools as utt from theano.tests import unittest_tools as utt
...@@ -72,22 +72,43 @@ class T_transpose(unittest.TestCase): ...@@ -72,22 +72,43 @@ class T_transpose(unittest.TestCase):
vta = eval_outputs([ta]) vta = eval_outputs([ta])
self.failUnless(vta.shape == (3,5)) self.failUnless(vta.shape == (3,5))
class T_Add(unittest.TestCase): class T_AddMul(unittest.TestCase):
def testSS(self): def testAddSS(self):
self._testSS(add)
def testAddSD(self):
self._testSD(add)
def testAddDS(self):
self._testDS(add)
def testMulSS(self):
self._testSS(mul,
numpy.array([[1., 0], [3, 0], [0, 6]]),
numpy.array([[1., 0], [3, 0], [0, 6]]))
def testMulSD(self):
self._testSD(mul,
numpy.array([[1., 0], [3, 0], [0, 6]]),
numpy.array([[1., 0], [3, 0], [0, 6]]))
def testMulDS(self):
self._testDS(mul,
numpy.array([[1., 0], [3, 0], [0, 6]]),
numpy.array([[1., 0], [3, 0], [0, 6]]))
def _testSS(self, op, array1 = numpy.array([[1., 0], [3, 0], [0, 6]]),
array2 = numpy.asarray([[0, 2.], [0, 4], [5, 0]])):
for mtype in _mtypes: for mtype in _mtypes:
a = mtype(numpy.array([[1., 0], [3, 0], [0, 6]])) a = mtype(array1)
aR = as_sparse_variable(a) aR = as_sparse_variable(a)
self.failIf(aR.data is a) self.failIf(aR.data is a)
self.failUnless(_is_sparse(a)) self.failUnless(_is_sparse(a))
self.failUnless(_is_sparse_variable(aR)) self.failUnless(_is_sparse_variable(aR))
b = mtype(numpy.asarray([[0, 2.], [0, 4], [5, 0]])) b = mtype(array2)
bR = as_sparse_variable(b) bR = as_sparse_variable(b)
self.failIf(bR.data is b) self.failIf(bR.data is b)
self.failUnless(_is_sparse(b)) self.failUnless(_is_sparse(b))
self.failUnless(_is_sparse_variable(bR)) self.failUnless(_is_sparse_variable(bR))
apb = add(aR, bR) apb = op(aR, bR)
self.failUnless(_is_sparse_variable(apb)) self.failUnless(_is_sparse_variable(apb))
self.failUnless(apb.type.dtype == aR.type.dtype, apb.type.dtype) self.failUnless(apb.type.dtype == aR.type.dtype, apb.type.dtype)
...@@ -97,58 +118,77 @@ class T_Add(unittest.TestCase): ...@@ -97,58 +118,77 @@ class T_Add(unittest.TestCase):
val = eval_outputs([apb]) val = eval_outputs([apb])
self.failUnless(val.shape == (3,2)) self.failUnless(val.shape == (3,2))
if op is add:
self.failUnless(numpy.all(val.todense() == (a + b).todense())) self.failUnless(numpy.all(val.todense() == (a + b).todense()))
self.failUnless(numpy.all(val.todense() == numpy.array([[1., 2], [3, 4], [5, 6]]))) self.failUnless(numpy.all(val.todense() == numpy.array([[1., 2], [3, 4], [5, 6]])))
elif op is mul:
self.failUnless(numpy.all(val.todense() == (a.multiply(b)).todense()))
self.failUnless(numpy.all(val.todense() == numpy.array([[1, 0], [9, 0], [0, 36]])))
def testSD(self): def _testSD(self, op, array1 = numpy.array([[1., 0], [3, 0], [0, 6]]),
array2 = numpy.asarray([[0, 2.], [0, 4], [5, 0]])):
for mtype in _mtypes: for mtype in _mtypes:
a = numpy.array([[1., 0], [3, 0], [0, 6]]) a = numpy.array(array1)
aR = tensor.as_tensor_variable(a) aR = tensor.as_tensor_variable(a)
self.failIf(aR.data is a) #constants are copied self.failIf(aR.data is a) #constants are copied
self.failUnless(_is_dense(a)) self.failUnless(_is_dense(a))
self.failUnless(_is_dense_variable(aR)) self.failUnless(_is_dense_variable(aR))
b = mtype(numpy.asarray([[0, 2.], [0, 4], [5, 0]])) b = mtype(array2)
bR = as_sparse_variable(b) bR = as_sparse_variable(b)
self.failIf(bR.data is b) #constants are copied self.failIf(bR.data is b) #constants are copied
self.failUnless(_is_sparse(b)) self.failUnless(_is_sparse(b))
self.failUnless(_is_sparse_variable(bR)) self.failUnless(_is_sparse_variable(bR))
apb = add(aR, bR) apb = op(aR, bR)
self.failUnless(_is_dense_variable(apb))
self.failUnless(apb.type.dtype == aR.type.dtype, apb.type.dtype) self.failUnless(apb.type.dtype == aR.type.dtype, apb.type.dtype)
self.failUnless(apb.type.dtype == bR.type.dtype, apb.type.dtype) self.failUnless(apb.type.dtype == bR.type.dtype, apb.type.dtype)
val = eval_outputs([apb]) val = eval_outputs([apb])
self.failUnless(val.shape == (3, 2)) self.failUnless(val.shape == (3, 2))
if op is add:
self.failUnless(_is_dense_variable(apb))
self.failUnless(numpy.all(val == (a + b))) self.failUnless(numpy.all(val == (a + b)))
self.failUnless(numpy.all(val == numpy.array([[1., 2], [3, 4], [5, 6]]))) self.failUnless(numpy.all(val == numpy.array([[1., 2], [3, 4], [5, 6]])))
elif op is mul:
self.failUnless(_is_sparse_variable(apb))
self.failUnless(numpy.all(val.todense() == (b.multiply(a))))
self.failUnless(numpy.all(val.todense() == numpy.array([[1, 0],
[9, 0], [0, 36]])))
def testDS(self): def _testDS(self, op, array1 = numpy.array([[1., 0], [3, 0], [0, 6]]),
array2 = numpy.asarray([[0, 2.], [0, 4], [5, 0]])):
for mtype in _mtypes: for mtype in _mtypes:
a = mtype(numpy.array([[1., 0], [3, 0], [0, 6]])) a = mtype(array1)
aR = as_sparse_variable(a) aR = as_sparse_variable(a)
self.failIf(aR.data is a) self.failIf(aR.data is a)
self.failUnless(_is_sparse(a)) self.failUnless(_is_sparse(a))
self.failUnless(_is_sparse_variable(aR)) self.failUnless(_is_sparse_variable(aR))
b = numpy.asarray([[0, 2.], [0, 4], [5, 0]]) b = numpy.asarray(array2)
bR = tensor.as_tensor_variable(b) bR = tensor.as_tensor_variable(b)
self.failIf(bR.data is b) self.failIf(bR.data is b)
self.failUnless(_is_dense(b)) self.failUnless(_is_dense(b))
self.failUnless(_is_dense_variable(bR)) self.failUnless(_is_dense_variable(bR))
apb = add(aR, bR) apb = op(aR, bR)
self.failUnless(_is_dense_variable(apb))
self.failUnless(apb.type.dtype == aR.type.dtype, apb.type.dtype) self.failUnless(apb.type.dtype == aR.type.dtype, apb.type.dtype)
self.failUnless(apb.type.dtype == bR.type.dtype, apb.type.dtype) self.failUnless(apb.type.dtype == bR.type.dtype, apb.type.dtype)
val = eval_outputs([apb]) val = eval_outputs([apb])
self.failUnless(val.shape == (3, 2)) self.failUnless(val.shape == (3, 2))
if op is add:
self.failUnless(_is_dense_variable(apb))
self.failUnless(numpy.all(val == (a + b))) self.failUnless(numpy.all(val == (a + b)))
self.failUnless(numpy.all(val == numpy.array([[1., 2], [3, 4], [5, 6]]))) self.failUnless(numpy.all(val == numpy.array([[1., 2], [3, 4], [5, 6]])))
elif op is mul:
self.failUnless(_is_sparse_variable(apb))
self.failUnless(numpy.all(val.todense() == (a.multiply(b))))
self.failUnless(numpy.all(val.todense() == numpy.array([[1, 0],
[9, 0], [0, 36]])))
class T_conversion(unittest.TestCase): class T_conversion(unittest.TestCase):
def setUp(self): def setUp(self):
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论