提交 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)
class SamplingDot(gof.op.Op):
"""Operand for calculating the dot product DOT(X, Y) = Z when you
only want to calculate a subset of Z.
"""Operand for calculating the dot product dot(`x`, `y`.T) = `z` when you
only want to calculate a subset of `z`.
It is equivalent to P o (X . Y) where o is the element-wise product,
X and Y operands of the dot product and P is a matrix that contains
1 when the corresponding element of Z should be calculated 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
is a NxK matrix instead of the usual KxN matrix.
It is equivalent to `p` o (`x` . `y`.T) where o is the element-wise
product, `x` and `y` operands of the dot product and `p` is a matrix that
contains 1 when the corresponding element of `z` should be calculated
and 0 when it shouldn't. Note that SamplingDot has a different interface
than `dot` because SamplingDot requires `x` to be a `m`x`k` matrix while
`y` is a `n`x`k` matrix instead of the usual `k`x`n` matrix.
.. note::
......@@ -1189,11 +1189,12 @@ class SamplingDot(gof.op.Op):
then a more optimized dot followed by a normal elemwise
multiplication.
:param x: Sparse matrix.
:param y: Sparse matrix.
:param p: Sparse matrix.
:param x: Tensor matrix.
:param y: Tensor 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):
......@@ -1205,6 +1206,7 @@ class SamplingDot(gof.op.Op):
def make_node(self, x, y, p):
x = tensor.as_tensor_variable(x)
y = tensor.as_tensor_variable(y)
p = sparse.as_sparse_variable(p)
if not _is_sparse_variable(p):
raise TypeError(p)
......@@ -1215,30 +1217,28 @@ class SamplingDot(gof.op.Op):
return gof.Apply(self, [x, y, p], [p.type()])
def perform(self, node, (x, y, p), (out,)):
if _is_sparse_variable(x):
if _is_sparse(x):
raise TypeError(x)
if _is_sparse_variable(y):
if _is_sparse(y):
raise TypeError(y)
if not _is_sparse(p):
raise TypeError(p)
rval = p.__class__(p.multiply(numpy.dot(x, y.T)))
out[0] = rval
out[0] = p.__class__(p.multiply(numpy.dot(x, y.T)))
def grad(self, (x, y, p), (gz,)):
rval = [
dot(p * gz, y),
dot(p.T * gz.T, x),
dot((p * gz).T, x),
None
]
return rval
def infer_shape(self, node, ins_shapes):
return [ins_shapes[0]]
return [ins_shapes[2]]
def __str__(self):
return self.__class__.__name__
......@@ -1246,16 +1246,15 @@ sampling_dot = SamplingDot()
class SamplingDotCsr(gof.Op):
"""Operand optimized for calculating the dot product DOT(X, Y) = Z
when you only want to calculate a subset of Z and the patternP
is as csr matrix.
"""Operand optimized for calculating the dot product dot(`x`, `y`.T) = `z`
when you only want to calculate a subset of `z`.
It is equivalent to P o (X . Y) where o is the element-wise product,
X and Y operands of the dot product and P is a matrix that contains
1 when the corresponding element of Z should be calculated 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
is a NxK matrix instead of the usual KxN matrix.
It is equivalent to `p` o (`x` . `y`.T) where o is the element-wise
product, `x` and `y` operands of the dot product and `p` is a matrix
that contains 1 when the corresponding element of `z` should be calculated
and 0 when it shouldn't. Note that SamplingDot has a different interface
than `dot` because SamplingDot requires `x` to be a `m`x`k` matrix while
`y` is a `n`x`k` matrix instead of the usual `k`x`n` matrix.
.. note::
......@@ -1264,11 +1263,15 @@ class SamplingDotCsr(gof.Op):
then a more optimized dot followed by a normal elemwise
multiplication.
:param x: Sparse matrix.
:param y: Sparse matrix.
:param p: Sparse matrix.
:param x: Tensor matrix.
:param y: Tensor 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:
- If we have the input of mixed dtype, we insert cast elemwise
......
......@@ -394,11 +394,11 @@ class StructuredAddTester(_StructuredMonoidUnaryTester):
self.expected_op = lambda x: np.add(x, 2)
class StructuredAddSVTester(unittest.TestCase):
class MulSVTester(unittest.TestCase):
def setUp(self):
utt.seed_rng()
def test_structured_add_s_v_grad(self):
def test_mul_s_v_grad(self):
sp_types = {'csc': sp.csc_matrix,
'csr': sp.csr_matrix}
......@@ -407,10 +407,10 @@ class StructuredAddSVTester(unittest.TestCase):
spmat = sp_types[format](random_lil((4, 3), dtype, 3))
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)
def test_structured_add_s_v(self):
def test_mul_s_v(self):
sp_types = {'csc': sp.csc_matrix,
'csr': sp.csr_matrix}
......@@ -418,19 +418,17 @@ class StructuredAddSVTester(unittest.TestCase):
for dtype in ['float32', 'float64']:
x = theano.sparse.SparseType(format, 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))
spones = spmat.copy()
spones.data = np.ones_like(spones.data)
mat = np.asarray(np.random.rand(3), dtype=dtype)
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):
utt.seed_rng()
......@@ -443,10 +441,10 @@ class MulSVTester(unittest.TestCase):
spmat = sp_types[format](random_lil((4, 3), dtype, 3))
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)
def test_mul_s_v(self):
def test_structured_add_s_v(self):
sp_types = {'csc': sp.csc_matrix,
'csr': sp.csr_matrix}
......@@ -454,14 +452,55 @@ class MulSVTester(unittest.TestCase):
for dtype in ['float32', 'float64']:
x = theano.sparse.SparseType(format, 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))
spones = spmat.copy()
spones.data = np.ones_like(spones.data)
mat = np.asarray(np.random.rand(3), dtype=dtype)
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__':
unittest.main()
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论