提交 68ec79f5 authored 作者: Frederic Bastien's avatar Frederic Bastien

Move Remove0 outside of the sandbox, and move its optimization to the right

place. Also add the infer_shape method to Remove0
上级 8761d3f7
......@@ -30,6 +30,9 @@ New Features
* If you use Enthought Python Distribution (EPD) now we use its blas
implementation by default.
Sparse Sandbox graduate
* Remove0 op: it remove store element with value 0.
Sparse Sandbox Addition (Not reviewed/documented/tested, but used by some people)
* They are all in the theano.sparse.sandbox.sp2 module
* Op class: Cast, Poisson, Multinomial, EliminateZeros, Sum, Binomial
......
......@@ -16,6 +16,6 @@ except ImportError:
if enable_sparse:
from basic import *
import opt
import sharedvar
from sharedvar import sparse_constructor as shared
......@@ -1316,6 +1316,48 @@ def mul(x, y):
raise NotImplementedError()
class Remove0(gof.Op):
"""
Remove explicit zeros from a sparse matrix, and resort indices
"""
def __init__(self, inplace=False, *args, **kwargs):
gof.Op.__init__(self, *args, **kwargs)
self.inplace = inplace
if self.inplace:
self.destroy_map = {0: [0]}
def __eq__(self, other):
return type(self) == type(other) and self.inplace == other.inplace
def __hash__(self):
return 64153 ^ hash(type(self)) ^ hash(self.inplace)
def __str__(self):
l = []
if self.inplace:
l.append('inplace')
return self.__class__.__name__ + '{%s}' % ', '.join(l)
def make_node(self, x):
return gof.Apply(self, [x], [x.type()])
def perform(self, node, (x,), (z,)):
if self.inplace:
c = x
else:
c = x.copy()
c.eliminate_zeros()
z[0] = c
def grad(self, (x,), (gz,)):
return [gz]
def infer_shape(self, node, i0_shapes):
return i0_shapes
remove0 = Remove0()
###############
#
# StructuredDot
......
import theano
from theano import gof
from theano.sparse import Remove0
@gof.local_optimizer([None])
def local_inplace_remove0(node):
"""
Optimization to insert inplace versions of Remove0.
"""
if isinstance(node.op, Remove0) and not node.op.inplace:
new_op = node.op.__class__(inplace=True)
new_node = new_op(*node.inputs)
return [new_node]
return False
theano.compile.optdb.register('local_inplace_remove0',
gof.TopoOptimizer(local_inplace_remove0,
failure_callback=gof.TopoOptimizer.warn_inplace),
60, 'fast_run', 'inplace')
......@@ -15,7 +15,7 @@ import theano
import theano.sparse
from theano import sparse, gof, Op, tensor
from theano.gof.python25 import all, any
from theano.sparse.basic import Remove0, remove0
def register_specialize(lopt, *tags, **kwargs):
theano.compile.optdb['specialize'].register(
......@@ -279,46 +279,6 @@ def row_scale(x, s):
return col_scale(x.T, s).T
class Remove0(Op):
"""
Remove explicit zeros from a sparse matrix, and resort indices
"""
def __init__(self, inplace=False, *args, **kwargs):
Op.__init__(self, *args, **kwargs)
self.inplace = inplace
if self.inplace:
self.destroy_map = {0: [0]}
def __eq__(self, other):
return type(self) == type(other) and self.inplace == other.inplace
def __hash__(self):
return 64153 ^ hash(type(self)) ^ hash(self.inplace)
def __str__(self):
l = []
if self.inplace:
l.append('inplace')
return self.__class__.__name__ + '{%s}' % ', '.join(l)
def make_node(self, x):
return gof.Apply(self, [x], [x.type()])
def perform(self, node, (x,), (z,)):
if self.inplace:
c = x
else:
c = x.copy()
c.eliminate_zeros()
z[0] = c
def grad(self, (x,), (gz,)):
return [gz]
remove0 = Remove0()
class EnsureSortedIndices(Op):
"""
Remove explicit zeros from a sparse matrix, and resort indices
......
......@@ -427,42 +427,6 @@ class TestSP(unittest.TestCase):
#utt.verify_grad(SpSum(axis=None), [x_val])
print 'ok'
def test_remove0():
print
print 'test_remove0()'
configs=[
# structure type, numpy matching class
('csc',scipy.sparse.csc_matrix),
('csr',scipy.sparse.csr_matrix),
]
for format,matrix_class in configs:
print 'config: format=\'%(format)s\', matrix_class=%(matrix_class)s'%locals()
# real
origin = (numpy.arange(9) + 1).reshape((3, 3)).astype(theano.config.floatX)
mat = matrix_class(origin).astype(theano.config.floatX)
mat[0,1] = mat[1,0] = mat[2,2] = 0
assert mat.size == 9
# symbolic
x = theano.sparse.SparseType(format=format, dtype=theano.config.floatX)()
# the In thingy has to be there because theano has as rule not to optimize inputs
f = theano.function([theano.In(x, borrow=True, mutable=True)], sp.Remove0()(x))
# assert optimization is applied in modes with optimization
if theano.config.mode not in ['FAST_COMPILE']:
# list of apply nodes in the optimized graph.
nodes = f.maker.env.toposort()
v = [True for node in nodes if isinstance(node.op, sp.Remove0) and node.op.inplace]
assert len(v), 'Inplacing optimization should have been applied.'
# checking
# makes sense to change its name
target = mat
result = f(mat)
mat.eliminate_zeros()
assert result.size == target.size, 'Matrices sizes differ. Have zeros been removed ?'
def test_diag():
m = theano.sparse.csc_matrix()
......
......@@ -24,7 +24,7 @@ from theano.sparse import as_sparse_variable, CSC, CSR, CSM, CSMProperties
from theano.sparse import SparseType, CSMGrad
from theano.sparse import StructuredDot, StructuredDotCSC
from theano.sparse import StructuredDotGradCSC, StructuredDotGradCSR
from theano.sparse import AddSS, AddSD, MulSS, MulSD, Transpose, Neg
from theano.sparse import AddSS, AddSD, MulSS, MulSD, Transpose, Neg, Remove0
from theano.sparse import add, mul, structured_dot, transpose
from theano.sparse import (csc_from_dense, csr_from_dense, dense_from_sparse,
SparseFromDense)
......@@ -229,6 +229,14 @@ class SparseInferShapeTester(utt.InferShapeTester):
numpy.random.randn(10, 40).astype(config.floatX)],
MulSD)
def test_remove0(self):
x = SparseType('csr', dtype=config.floatX)()
self._compile_and_check([x],
[Remove0()(x)],
[sp.csr_matrix(random_lil((10, 40),
config.floatX, 3))],
Remove0)
def test_dot(self):
x = SparseType('csc', dtype=config.floatX)()
y = SparseType('csc', dtype=config.floatX)()
......@@ -1160,6 +1168,49 @@ def test_size():
check()
def test_remove0():
print
print 'test_remove0()'
configs = [
# structure type, numpy matching class
('csc', scipy.sparse.csc_matrix),
('csr', scipy.sparse.csr_matrix),
]
for format, matrix_class in configs:
print ('config: format=\'%(format)s\','
' matrix_class=%(matrix_class)s' % locals())
# real
origin = (numpy.arange(9) + 1).reshape((3, 3)).astype(config.floatX)
mat = matrix_class(origin).astype(theano.config.floatX)
mat[0, 1] = mat[1, 0] = mat[2, 2] = 0
assert mat.size == 9
# symbolic
x = theano.sparse.SparseType(format=format, dtype=config.floatX)()
# the In thingy has to be there because theano has as rule not
# to optimize inputs
f = theano.function([theano.In(x, borrow=True, mutable=True)],
Remove0()(x))
# assert optimization is applied in modes with optimization
if theano.config.mode not in ['FAST_COMPILE']:
# list of apply nodes in the optimized graph.
nodes = f.maker.env.toposort()
v = [True for node in nodes
if isinstance(node.op, Remove0) and node.op.inplace]
assert len(v), 'Inplacing optimization should have been applied.'
# checking
# makes sense to change its name
target = mat
result = f(mat)
mat.eliminate_zeros()
msg = 'Matrices sizes differ. Have zeros been removed ?'
assert result.size == target.size, msg
class Test_getitem(unittest.TestCase):
def setUp(self):
self.rng = numpy.random.RandomState(utt.fetch_seed())
......
......@@ -33,9 +33,6 @@ from theano.gof.opt import (Optimizer, pre_constant_merge,
from theano.gof import toolbox, DestroyHandler
from basic import get_constant_value, ShapeError
# Remove0 is lazily imported to avoid circular imports.
Remove0 = None
theano.configparser.AddConfigVar('on_shape_error',
"warn: print a warning and use the default"
......@@ -1974,24 +1971,6 @@ compile.optdb.register('local_inplace_incsubtensor1',
failure_callback=TopoOptimizer.warn_inplace),
60, 'fast_run', 'inplace') # DEBUG
@gof.local_optimizer([None])
def local_inplace_remove0(node):
"""
Optimization to insert inplace versions of Remove0.
"""
global Remove0
if Remove0 is None:
from theano.sparse.sandbox.sp import Remove0
if isinstance(node.op, Remove0) and not node.op.inplace:
new_op = node.op.__class__(inplace=True)
new_node = new_op(*node.inputs)
return [new_node]
return False
compile.optdb.register('local_inplace_remove0',
TopoOptimizer(local_inplace_remove0,
failure_callback=TopoOptimizer.warn_inplace), 60,
'fast_run', 'inplace')
@register_canonicalize
@register_stabilize
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论