提交 2ac39b3e authored 作者: Pascal Lamblin's avatar Pascal Lamblin

Move Sparse random Ops back to sandbox, see gh-993.

上级 ef44c58e
...@@ -2316,158 +2316,6 @@ class Remove0(gof.Op): ...@@ -2316,158 +2316,6 @@ class Remove0(gof.Op):
remove0 = Remove0() remove0 = Remove0()
# Probability
class Poisson(gof.op.Op):
"""Return a sparse having random values from a Poisson density
with mean from the input.
:param x: Sparse matrix.
:return: A sparse matrix of random integers of a Poisson density
with mean of `x` element wise.
"""
def __eq__(self, other):
return (type(self) == type(other))
def __hash__(self):
return hash(type(self))
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.copy()
out[0].data = numpy.asarray(numpy.random.poisson(out[0].data),
dtype=x.dtype)
out[0].eliminate_zeros()
def grad(self, inputs, outputs_gradients):
return [None]
def infer_shape(self, node, ins_shapes):
return ins_shapes
def __str__(self):
return self.__class__.__name__
poisson = Poisson()
class Binomial(gof.op.Op):
"""Return a sparse matrix having random values from a binomial
density having number of experiment `n` and probability of succes
`p`.
: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, )):
binomial = numpy.random.binomial(n, p, size=shape)
csx_matrix = getattr(scipy.sparse, self.format + '_matrix')
out[0] = csx_matrix(binomial, dtype=self.dtype)
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')
class Multinomial(gof.op.Op):
"""Return a sparse matrix having random values from a multinomial
density having number of experiment `n` and probability of succes
`p`.
:param n: Tensor type vector or scalar representing the number of
experiment for each row. If `n` is a scalar, it will be
used for each row.
:param p: Sparse matrix of probability where each row is a probability
vector representing the probability of succes. N.B. Each row
must sum to one.
:return: A sparse matrix of random integers from a multinomial density
for each row.
:note: It will works only if `p` have csr format.
"""
def __eq__(self, other):
return (type(self) == type(other))
def __hash__(self):
return hash(type(self))
def make_node(self, n, p):
n = tensor.as_tensor_variable(n)
p = as_sparse_variable(p)
return gof.Apply(self, [n, p], [p.type()])
def perform(self, node, (n, p), (out, )):
assert _is_sparse(p)
if p.format != 'csr':
raise NotImplemented()
out[0] = p.copy()
if n.ndim == 0:
for i in xrange(p.shape[0]):
k, l = p.indptr[i], p.indptr[i + 1]
out[0].data[k:l] = numpy.random.multinomial(n, p.data[k:l])
elif n.ndim == 1:
if n.shape[0] != p.shape[0]:
raise ValueError('The number of element of n must be '
'the same as the number of row of p.')
for i in xrange(p.shape[0]):
k, l = p.indptr[i], p.indptr[i + 1]
out[0].data[k:l] = numpy.random.multinomial(n[i], p.data[k:l])
def grad(self, inputs, outputs_gradients):
return [None, None]
def infer_shape(self, node, ins_shapes):
return [ins_shapes[1]]
def __str__(self):
return self.__class__.__name__
multinomial = Multinomial()
# Structured monoid # Structured monoid
def structured_monoid(tensor_op): def structured_monoid(tensor_op):
# Generic operation to perform many kinds of monoid element-wise # Generic operation to perform many kinds of monoid element-wise
......
...@@ -18,14 +18,20 @@ from theano.sparse.basic import ( ...@@ -18,14 +18,20 @@ from theano.sparse.basic import (
HStack, hstack, VStack, vstack, HStack, hstack, VStack, vstack,
AddSSData, add_s_s_data, AddSSData, add_s_s_data,
MulSV, mul_s_v, MulSV, mul_s_v,
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,
StructuredAddSV, structured_add_s_v, StructuredAddSV, structured_add_s_v,
SamplingDot, sampling_dot) SamplingDot, sampling_dot)
# Probability Ops are currently back in sandbox, because they do not respect
# Theano's Op contract, as their behaviour is not reproducible: calling
# the perform() method twice with the same argument will yield different
# results.
#from theano.sparse.basic import (
# Multinomial, multinomial, Poisson, poisson,
# Binomial, csr_fbinomial, csc_fbinomial, csr_dbinomial, csc_dbinomial)
# Also for compatibility # Also for compatibility
from theano.sparse.opt import ( from theano.sparse.opt import (
MulSDCSC, mul_s_d_csc, MulSDCSR, mul_s_d_csr, MulSDCSC, mul_s_d_csc, MulSDCSR, mul_s_d_csr,
...@@ -38,3 +44,167 @@ from theano.sparse.opt import ( ...@@ -38,3 +44,167 @@ from theano.sparse.opt import (
# Alias to maintain compatibility # Alias to maintain compatibility
EliminateZeros = Remove0 EliminateZeros = Remove0
eliminate_zeros = remove0 eliminate_zeros = remove0
# Probability
class Poisson(gof.op.Op):
"""Return a sparse having random values from a Poisson density
with mean from the input.
WARNING: This Op is NOT deterministic, as calling it twice with the
same inputs will NOT give the same result. This is a violation of
Theano's contract for Ops
:param x: Sparse matrix.
:return: A sparse matrix of random integers of a Poisson density
with mean of `x` element wise.
"""
def __eq__(self, other):
return (type(self) == type(other))
def __hash__(self):
return hash(type(self))
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.copy()
out[0].data = numpy.asarray(numpy.random.poisson(out[0].data),
dtype=x.dtype)
out[0].eliminate_zeros()
def grad(self, inputs, outputs_gradients):
return [None]
def infer_shape(self, node, ins_shapes):
return ins_shapes
def __str__(self):
return self.__class__.__name__
poisson = Poisson()
class Binomial(gof.op.Op):
"""Return a sparse matrix having random values from a binomial
density having number of experiment `n` and probability of succes
`p`.
WARNING: This Op is NOT deterministic, as calling it twice with the
same inputs will NOT give the same result. This is a violation of
Theano's contract for Ops
: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, )):
binomial = numpy.random.binomial(n, p, size=shape)
csx_matrix = getattr(scipy.sparse, self.format + '_matrix')
out[0] = csx_matrix(binomial, dtype=self.dtype)
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')
class Multinomial(gof.op.Op):
"""Return a sparse matrix having random values from a multinomial
density having number of experiment `n` and probability of succes
`p`.
WARNING: This Op is NOT deterministic, as calling it twice with the
same inputs will NOT give the same result. This is a violation of
Theano's contract for Ops
:param n: Tensor type vector or scalar representing the number of
experiment for each row. If `n` is a scalar, it will be
used for each row.
:param p: Sparse matrix of probability where each row is a probability
vector representing the probability of succes. N.B. Each row
must sum to one.
:return: A sparse matrix of random integers from a multinomial density
for each row.
:note: It will works only if `p` have csr format.
"""
def __eq__(self, other):
return (type(self) == type(other))
def __hash__(self):
return hash(type(self))
def make_node(self, n, p):
n = tensor.as_tensor_variable(n)
p = as_sparse_variable(p)
return gof.Apply(self, [n, p], [p.type()])
def perform(self, node, (n, p), (out, )):
assert _is_sparse(p)
if p.format != 'csr':
raise NotImplemented()
out[0] = p.copy()
if n.ndim == 0:
for i in xrange(p.shape[0]):
k, l = p.indptr[i], p.indptr[i + 1]
out[0].data[k:l] = numpy.random.multinomial(n, p.data[k:l])
elif n.ndim == 1:
if n.shape[0] != p.shape[0]:
raise ValueError('The number of element of n must be '
'the same as the number of row of p.')
for i in xrange(p.shape[0]):
k, l = p.indptr[i], p.indptr[i + 1]
out[0].data[k:l] = numpy.random.multinomial(n[i], p.data[k:l])
def grad(self, inputs, outputs_gradients):
return [None, None]
def infer_shape(self, node, ins_shapes):
return [ins_shapes[1]]
def __str__(self):
return self.__class__.__name__
multinomial = Multinomial()
...@@ -34,7 +34,6 @@ from theano.sparse import ( ...@@ -34,7 +34,6 @@ from theano.sparse import (
Dot, Usmm, sp_ones_like, GetItemScalar, Dot, Usmm, sp_ones_like, GetItemScalar,
SparseFromDense, SparseFromDense,
Cast, cast, HStack, VStack, AddSSData, add_s_s_data, Cast, cast, HStack, VStack, AddSSData, add_s_s_data,
Poisson, poisson, Binomial, Multinomial, multinomial,
structured_sigmoid, structured_exp, structured_log, structured_sigmoid, structured_exp, structured_log,
structured_pow, structured_minimum, structured_maximum, structured_add, structured_pow, structured_minimum, structured_maximum, structured_add,
MulSV, mul_s_v, StructuredAddSV, structured_add_s_v, MulSV, mul_s_v, StructuredAddSV, structured_add_s_v,
...@@ -42,6 +41,10 @@ from theano.sparse import ( ...@@ -42,6 +41,10 @@ from theano.sparse import (
Diag, diag, SquareDiagonal, square_diagonal, Diag, diag, SquareDiagonal, square_diagonal,
EnsureSortedIndices, ensure_sorted_indices, clean) EnsureSortedIndices, ensure_sorted_indices, clean)
# Probability distributions are currently tested in test_sp2.py
#from theano.sparse import (
# Poisson, poisson, Binomial, Multinomial, multinomial)
from theano.sparse.opt import (StructuredDotCSC, UsmmCscDense, CSMGradC) from theano.sparse.opt import (StructuredDotCSC, UsmmCscDense, CSMGradC)
from theano.tests import unittest_tools as utt from theano.tests import unittest_tools as utt
...@@ -2141,122 +2144,6 @@ class AddSSDataTester(utt.InferShapeTester): ...@@ -2141,122 +2144,6 @@ class AddSSDataTester(utt.InferShapeTester):
structured=True) structured=True)
class PoissonTester(utt.InferShapeTester):
x = {}
a = {}
for format in sparse.sparse_formats:
variable = getattr(theano.sparse, format + '_matrix')
rand = numpy.array(numpy.random.random_integers(3, size=(3, 4)) - 1,
dtype=theano.config.floatX)
x[format] = variable()
a[format] = as_sparse_format(rand, format)
def setUp(self):
super(PoissonTester, self).setUp()
self.op_class = Poisson
def test_op(self):
for format in sparse.sparse_formats:
f = theano.function(
[self.x[format]],
poisson(self.x[format]))
tested = f(self.a[format])
assert tested.format == format
assert tested.dtype == self.a[format].dtype
assert numpy.allclose(numpy.floor(tested.data), tested.data)
assert tested.shape == self.a[format].shape
def test_infer_shape(self):
for format in sparse.sparse_formats:
self._compile_and_check([self.x[format]],
[poisson(self.x[format])],
[self.a[format]],
self.op_class)
class BinomialTester(utt.InferShapeTester):
n = tensor.scalar()
p = tensor.scalar()
shape = tensor.lvector()
_n = 5
_p = .25
_shape = numpy.asarray([3, 5], dtype='int64')
inputs = [n, p, shape]
_inputs = [_n, _p, _shape]
def setUp(self):
super(BinomialTester, self).setUp()
self.op_class = Binomial
def test_op(self):
for sp_format in sparse.sparse_formats:
for o_type in sparse.float_dtypes:
f = theano.function(
self.inputs,
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 numpy.allclose(numpy.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,
[Binomial(sp_format, o_type)(*self.inputs)],
self._inputs,
self.op_class)
class MultinomialTester(utt.InferShapeTester):
p = sparse.csr_matrix()
_p = sp.csr_matrix(numpy.asarray([[0.0, 0.5, 0.0, 0.5],
[0.1, 0.2, 0.3, 0.4],
[0.0, 1.0, 0.0, 0.0],
[0.3, 0.3, 0.0, 0.4]],
dtype=config.floatX))
def setUp(self):
super(MultinomialTester, self).setUp()
self.op_class = Multinomial
def test_op(self):
n = tensor.lscalar()
f = theano.function([self.p, n], multinomial(n, self.p))
_n = 5
tested = f(self._p, _n)
assert tested.shape == self._p.shape
assert numpy.allclose(numpy.floor(tested.todense()), tested.todense())
assert tested[2, 1] == _n
n = tensor.lvector()
f = theano.function([self.p, n], multinomial(n, self.p))
_n = numpy.asarray([1, 2, 3, 4], dtype='int64')
tested = f(self._p, _n)
assert tested.shape == self._p.shape
assert numpy.allclose(numpy.floor(tested.todense()), tested.todense())
assert tested[2, 1] == _n[2]
def test_infer_shape(self):
self._compile_and_check([self.p],
[multinomial(5, self.p)],
[self._p],
self.op_class)
def elemwise_checker(op, expected_f, gap=None, test_dtypes=None, def elemwise_checker(op, expected_f, gap=None, test_dtypes=None,
grad_test=True, name=None): grad_test=True, name=None):
"""Return the appropriate test class for the elemwise on sparse. """Return the appropriate test class for the elemwise on sparse.
......
...@@ -2,7 +2,7 @@ import time ...@@ -2,7 +2,7 @@ import time
import unittest import unittest
from nose.plugins.skip import SkipTest from nose.plugins.skip import SkipTest
import numpy as np import numpy
try: try:
import scipy.sparse as sp import scipy.sparse as sp
import scipy.sparse import scipy.sparse
...@@ -10,16 +10,134 @@ except ImportError: ...@@ -10,16 +10,134 @@ 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 config
from theano import tensor from theano import tensor
from theano import sparse from theano import sparse
if not theano.sparse.enable_sparse: if not theano.sparse.enable_sparse:
raise SkipTest('Optional package sparse disabled') raise SkipTest('Optional package sparse disabled')
from theano.sparse.sandbox import sp2 as S2 from theano.sparse.sandbox.sp2 import (
Poisson, poisson, Binomial, Multinomial, multinomial)
from theano.tests import unittest_tools as utt from theano.tests import unittest_tools as utt
from theano.sparse.basic import verify_grad_sparse from theano.sparse.tests.test_basic import as_sparse_format
class PoissonTester(utt.InferShapeTester):
x = {}
a = {}
for format in sparse.sparse_formats:
variable = getattr(theano.sparse, format + '_matrix')
rand = numpy.array(numpy.random.random_integers(3, size=(3, 4)) - 1,
dtype=theano.config.floatX)
x[format] = variable()
a[format] = as_sparse_format(rand, format)
def setUp(self):
super(PoissonTester, self).setUp()
self.op_class = Poisson
def test_op(self):
for format in sparse.sparse_formats:
f = theano.function(
[self.x[format]],
poisson(self.x[format]))
tested = f(self.a[format])
assert tested.format == format
assert tested.dtype == self.a[format].dtype
assert numpy.allclose(numpy.floor(tested.data), tested.data)
assert tested.shape == self.a[format].shape
def test_infer_shape(self):
for format in sparse.sparse_formats:
self._compile_and_check([self.x[format]],
[poisson(self.x[format])],
[self.a[format]],
self.op_class)
class BinomialTester(utt.InferShapeTester):
n = tensor.scalar()
p = tensor.scalar()
shape = tensor.lvector()
_n = 5
_p = .25
_shape = numpy.asarray([3, 5], dtype='int64')
inputs = [n, p, shape]
_inputs = [_n, _p, _shape]
def setUp(self):
super(BinomialTester, self).setUp()
self.op_class = Binomial
def test_op(self):
for sp_format in sparse.sparse_formats:
for o_type in sparse.float_dtypes:
f = theano.function(
self.inputs,
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 numpy.allclose(numpy.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,
[Binomial(sp_format, o_type)(*self.inputs)],
self._inputs,
self.op_class)
class MultinomialTester(utt.InferShapeTester):
p = sparse.csr_matrix()
_p = sp.csr_matrix(numpy.asarray([[0.0, 0.5, 0.0, 0.5],
[0.1, 0.2, 0.3, 0.4],
[0.0, 1.0, 0.0, 0.0],
[0.3, 0.3, 0.0, 0.4]],
dtype=config.floatX))
def setUp(self):
super(MultinomialTester, self).setUp()
self.op_class = Multinomial
def test_op(self):
n = tensor.lscalar()
f = theano.function([self.p, n], multinomial(n, self.p))
_n = 5
tested = f(self._p, _n)
assert tested.shape == self._p.shape
assert numpy.allclose(numpy.floor(tested.todense()), tested.todense())
assert tested[2, 1] == _n
n = tensor.lvector()
f = theano.function([self.p, n], multinomial(n, self.p))
_n = numpy.asarray([1, 2, 3, 4], dtype='int64')
tested = f(self._p, _n)
assert tested.shape == self._p.shape
assert numpy.allclose(numpy.floor(tested.todense()), tested.todense())
assert tested[2, 1] == _n[2]
def test_infer_shape(self):
self._compile_and_check([self.p],
[multinomial(5, self.p)],
[self._p],
self.op_class)
if __name__ == '__main__': if __name__ == '__main__':
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论