提交 4830de69 authored 作者: Nicolas Bouchard's avatar Nicolas Bouchard 提交者: Frederic

Add SamplingDotTester and correction to SamplingDot.

上级 5fb309f9
...@@ -1172,15 +1172,15 @@ register_specialize(local_structured_add_s_v) ...@@ -1172,15 +1172,15 @@ register_specialize(local_structured_add_s_v)
class SamplingDot(gof.op.Op): class SamplingDot(gof.op.Op):
"""Operand for calculating the dot product DOT(X, Y) = Z when you """Operand for calculating the dot product dot(`x`, `y`.T) = `z` when you
only want to calculate a subset of Z. only want to calculate a subset of `z`.
It is equivalent to P o (X . Y) where o is the element-wise product, It is equivalent to `p` o (`x` . `y`.T) where o is the element-wise
X and Y operands of the dot product and P is a matrix that contains product, `x` and `y` operands of the dot product and `p` is a matrix that
1 when the corresponding element of Z should be calculated and 0 contains 1 when the corresponding element of `z` should be calculated
when it shouldn't. Note that SamplingDot has a different interface and 0 when it shouldn't. Note that SamplingDot has a different interface
than DOT because SamplingDot requires X to be a MxK matrix while Y than `dot` because SamplingDot requires `x` to be a `m`x`k` matrix while
is a NxK matrix instead of the usual KxN matrix. `y` is a `n`x`k` matrix instead of the usual `k`x`n` matrix.
.. note:: .. note::
...@@ -1189,11 +1189,12 @@ class SamplingDot(gof.op.Op): ...@@ -1189,11 +1189,12 @@ class SamplingDot(gof.op.Op):
then a more optimized dot followed by a normal elemwise then a more optimized dot followed by a normal elemwise
multiplication. multiplication.
:param x: Sparse matrix. :param x: Tensor matrix.
:param y: Sparse matrix. :param y: Tensor matrix.
:param p: Sparse matrix. :param p: Sparse matrix in csr format.
:return: A sparse matrix containing the dot product of `x` by `y`. :return: A dense matrix containing the dot product of `x` by `y`.T only
where `p` is 1.
""" """
def __eq__(self, other): def __eq__(self, other):
...@@ -1205,6 +1206,7 @@ class SamplingDot(gof.op.Op): ...@@ -1205,6 +1206,7 @@ class SamplingDot(gof.op.Op):
def make_node(self, x, y, p): def make_node(self, x, y, p):
x = tensor.as_tensor_variable(x) x = tensor.as_tensor_variable(x)
y = tensor.as_tensor_variable(y) y = tensor.as_tensor_variable(y)
p = sparse.as_sparse_variable(p)
if not _is_sparse_variable(p): if not _is_sparse_variable(p):
raise TypeError(p) raise TypeError(p)
...@@ -1215,30 +1217,28 @@ class SamplingDot(gof.op.Op): ...@@ -1215,30 +1217,28 @@ class SamplingDot(gof.op.Op):
return gof.Apply(self, [x, y, p], [p.type()]) return gof.Apply(self, [x, y, p], [p.type()])
def perform(self, node, (x, y, p), (out,)): def perform(self, node, (x, y, p), (out,)):
if _is_sparse_variable(x): if _is_sparse(x):
raise TypeError(x) raise TypeError(x)
if _is_sparse_variable(y): if _is_sparse(y):
raise TypeError(y) raise TypeError(y)
if not _is_sparse(p): if not _is_sparse(p):
raise TypeError(p) raise TypeError(p)
rval = p.__class__(p.multiply(numpy.dot(x, y.T))) out[0] = p.__class__(p.multiply(numpy.dot(x, y.T)))
out[0] = rval
def grad(self, (x, y, p), (gz,)): def grad(self, (x, y, p), (gz,)):
rval = [ rval = [
dot(p * gz, y), dot(p * gz, y),
dot(p.T * gz.T, x), dot((p * gz).T, x),
None None
] ]
return rval return rval
def infer_shape(self, node, ins_shapes): def infer_shape(self, node, ins_shapes):
return [ins_shapes[0]] return [ins_shapes[2]]
def __str__(self): def __str__(self):
return self.__class__.__name__ return self.__class__.__name__
...@@ -1246,16 +1246,15 @@ sampling_dot = SamplingDot() ...@@ -1246,16 +1246,15 @@ sampling_dot = SamplingDot()
class SamplingDotCsr(gof.Op): class SamplingDotCsr(gof.Op):
"""Operand optimized for calculating the dot product DOT(X, Y) = Z """Operand optimized for calculating the dot product dot(`x`, `y`.T) = `z`
when you only want to calculate a subset of Z and the patternP when you only want to calculate a subset of `z`.
is as csr matrix.
It is equivalent to P o (X . Y) where o is the element-wise product, It is equivalent to `p` o (`x` . `y`.T) where o is the element-wise
X and Y operands of the dot product and P is a matrix that contains product, `x` and `y` operands of the dot product and `p` is a matrix
1 when the corresponding element of Z should be calculated and 0 that contains 1 when the corresponding element of `z` should be calculated
when it shouldn't. Note that SamplingDot has a different interface and 0 when it shouldn't. Note that SamplingDot has a different interface
than DOT because SamplingDot requires X to be a MxK matrix while Y than `dot` because SamplingDot requires `x` to be a `m`x`k` matrix while
is a NxK matrix instead of the usual KxN matrix. `y` is a `n`x`k` matrix instead of the usual `k`x`n` matrix.
.. note:: .. note::
...@@ -1264,11 +1263,15 @@ class SamplingDotCsr(gof.Op): ...@@ -1264,11 +1263,15 @@ class SamplingDotCsr(gof.Op):
then a more optimized dot followed by a normal elemwise then a more optimized dot followed by a normal elemwise
multiplication. multiplication.
:param x: Sparse matrix. :param x: Tensor matrix.
:param y: Sparse matrix. :param y: Tensor matrix.
:param p: Sparse matrix. :param p_data: Sparse matrix data.
:param p_ind: Sparse matrix indices.
:param p_ptr: Sparse matric indptr.
:param p_ncols: Sparse matrix number of columns.
:return: A sparse matrix containing the dot product of `x` by `y`. :return: A dense matrix containing the dot product of `x` by `y`.T only
where `p` is 1.
:note: :note:
- If we have the input of mixed dtype, we insert cast elemwise - If we have the input of mixed dtype, we insert cast elemwise
......
...@@ -394,11 +394,11 @@ class StructuredAddTester(_StructuredMonoidUnaryTester): ...@@ -394,11 +394,11 @@ class StructuredAddTester(_StructuredMonoidUnaryTester):
self.expected_op = lambda x: np.add(x, 2) self.expected_op = lambda x: np.add(x, 2)
class StructuredAddSVTester(unittest.TestCase): class MulSVTester(unittest.TestCase):
def setUp(self): def setUp(self):
utt.seed_rng() utt.seed_rng()
def test_structured_add_s_v_grad(self): def test_mul_s_v_grad(self):
sp_types = {'csc': sp.csc_matrix, sp_types = {'csc': sp.csc_matrix,
'csr': sp.csr_matrix} 'csr': sp.csr_matrix}
...@@ -407,10 +407,10 @@ class StructuredAddSVTester(unittest.TestCase): ...@@ -407,10 +407,10 @@ class StructuredAddSVTester(unittest.TestCase):
spmat = sp_types[format](random_lil((4, 3), dtype, 3)) spmat = sp_types[format](random_lil((4, 3), dtype, 3))
mat = np.asarray(np.random.rand(3), dtype=dtype) mat = np.asarray(np.random.rand(3), dtype=dtype)
theano.sparse.verify_grad_sparse(S2.structured_add_s_v, theano.sparse.verify_grad_sparse(S2.mul_s_v,
[spmat, mat], structured=True) [spmat, mat], structured=True)
def test_structured_add_s_v(self): def test_mul_s_v(self):
sp_types = {'csc': sp.csc_matrix, sp_types = {'csc': sp.csc_matrix,
'csr': sp.csr_matrix} 'csr': sp.csr_matrix}
...@@ -418,19 +418,17 @@ class StructuredAddSVTester(unittest.TestCase): ...@@ -418,19 +418,17 @@ class StructuredAddSVTester(unittest.TestCase):
for dtype in ['float32', 'float64']: for dtype in ['float32', 'float64']:
x = theano.sparse.SparseType(format, dtype=dtype)() x = theano.sparse.SparseType(format, dtype=dtype)()
y = tensor.vector(dtype=dtype) y = tensor.vector(dtype=dtype)
f = theano.function([x, y], S2.structured_add_s_v(x, y)) f = theano.function([x, y], S2.mul_s_v(x, y))
spmat = sp_types[format](random_lil((4, 3), dtype, 3)) spmat = sp_types[format](random_lil((4, 3), dtype, 3))
spones = spmat.copy()
spones.data = np.ones_like(spones.data)
mat = np.asarray(np.random.rand(3), dtype=dtype) mat = np.asarray(np.random.rand(3), dtype=dtype)
out = f(spmat, mat) out = f(spmat, mat)
assert np.allclose(out.toarray(), spones.multiply(spmat + mat)) assert np.allclose(out.toarray(), spmat.toarray() * mat)
class MulSVTester(unittest.TestCase): class StructuredAddSVTester(unittest.TestCase):
def setUp(self): def setUp(self):
utt.seed_rng() utt.seed_rng()
...@@ -443,10 +441,10 @@ class MulSVTester(unittest.TestCase): ...@@ -443,10 +441,10 @@ class MulSVTester(unittest.TestCase):
spmat = sp_types[format](random_lil((4, 3), dtype, 3)) spmat = sp_types[format](random_lil((4, 3), dtype, 3))
mat = np.asarray(np.random.rand(3), dtype=dtype) mat = np.asarray(np.random.rand(3), dtype=dtype)
theano.sparse.verify_grad_sparse(S2.mul_s_v, theano.sparse.verify_grad_sparse(S2.structured_add_s_v,
[spmat, mat], structured=True) [spmat, mat], structured=True)
def test_mul_s_v(self): def test_structured_add_s_v(self):
sp_types = {'csc': sp.csc_matrix, sp_types = {'csc': sp.csc_matrix,
'csr': sp.csr_matrix} 'csr': sp.csr_matrix}
...@@ -454,14 +452,55 @@ class MulSVTester(unittest.TestCase): ...@@ -454,14 +452,55 @@ class MulSVTester(unittest.TestCase):
for dtype in ['float32', 'float64']: for dtype in ['float32', 'float64']:
x = theano.sparse.SparseType(format, dtype=dtype)() x = theano.sparse.SparseType(format, dtype=dtype)()
y = tensor.vector(dtype=dtype) y = tensor.vector(dtype=dtype)
f = theano.function([x, y], S2.mul_s_v(x, y)) f = theano.function([x, y], S2.structured_add_s_v(x, y))
spmat = sp_types[format](random_lil((4, 3), dtype, 3)) spmat = sp_types[format](random_lil((4, 3), dtype, 3))
spones = spmat.copy()
spones.data = np.ones_like(spones.data)
mat = np.asarray(np.random.rand(3), dtype=dtype) mat = np.asarray(np.random.rand(3), dtype=dtype)
out = f(spmat, mat) out = f(spmat, mat)
assert np.allclose(out.toarray(), spmat.toarray() * mat) assert np.allclose(out.toarray(), spones.multiply(spmat + mat))
class SamplingDotTester(utt.InferShapeTester):
x = [tensor.matrix() for t in range(2)]
x.append(sparse.csr_matrix())
a = [np.array(np.random.random_integers(maximum, size=(3, 3)) - 1,
dtype=theano.config.floatX)
for maximum in [5, 5, 2]]
a[2] = sp.csr_matrix(a[2])
def setUp(self):
super(SamplingDotTester, self).setUp()
self.op_class = S2.SamplingDot
def test_op(self):
f = theano.function(
self.x,
S2.sampling_dot(*self.x))
tested = f(*self.a)
x, y, p = self.a
expected = p.multiply(np.dot(x, y.T))
assert np.allclose(tested.toarray(), expected)
assert tested.format == 'csr'
assert tested.dtype == expected.dtype
def test_infer_shape(self):
self._compile_and_check(self.x,
[S2.sampling_dot(*self.x)],
self.a,
self.op_class,
excluding=['local_sampling_dot_csr'])
def test_grad(self):
def _helper(x, y):
return S2.sampling_dot(x, y, self.a[2])
verify_grad_sparse(_helper, self.a[:2])
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论