提交 df1bd762 authored 作者: Frédéric Bastien's avatar Frédéric Bastien

Merge pull request #2216 from sisp/adv_subtensor_opt

Generalize all [Inc]Subtensor optimization to advanced[inc]subtensor[1]
......@@ -28,7 +28,8 @@ from theano.tensor.elemwise import Elemwise, DimShuffle
from theano.tensor.subtensor import (get_idx_list, get_canonical_form_slice,
Subtensor, IncSubtensor, make_constant,
AdvancedIncSubtensor1,
AdvancedIncSubtensor)
AdvancedIncSubtensor,
AdvancedSubtensor1)
from theano import scalar
from theano.tensor import basic as T
from theano import compile # to register the optimizer built by this file
......@@ -1330,52 +1331,71 @@ def local_track_shape_i(node):
@register_specialize
@register_canonicalize('fast_compile_gpu')
@gof.local_optimizer([Subtensor])
@gof.local_optimizer([Subtensor, AdvancedSubtensor1])
def local_subtensor_make_vector(node):
# replace all subtensor(make_vector) like:
# [a,b,c][0] -> a
# [a,b,c][0:2] -> [a,b]
# we can do this for constant indexes
"""
replace all subtensor(make_vector) like:
[a,b,c][0] -> a
[a,b,c][0:2] -> [a,b]
replace all AdvancedSubtensor1(make_vector) like:
[a,b,c][[0,2]] -> [a,c]
we can do this for constant indexes
"""
x = node.inputs[0]
if not x.owner or x.owner.op != make_vector:
return
if isinstance(node.op, Subtensor):
# This optimization needs ShapeOpt and fgraph.shape_feature
x = node.inputs[0]
if x.owner and x.owner.op == make_vector:
try:
idx, = node.op.idx_list
except Exception:
#'how can you have multiple indexes into a shape?'
raise
if isinstance(idx, (scalar.Scalar, T.TensorType)):
# The idx is a Scalar, ie a Type. This means the actual index
# is contained in node.inputs[1]
old_idx, idx = idx, node.inputs[1]
assert idx.type == old_idx
elif isinstance(node.op, AdvancedSubtensor1):
idx = node.inputs[1]
else:
return
if isinstance(idx, (int, numpy.integer)):
return [x.owner.inputs[idx]]
elif isinstance(idx, Variable):
if idx.ndim == 0:
# if it is a constant we can do something with it
try:
idx, = node.op.idx_list
except Exception:
#'how can you have multiple indexes into a shape?'
raise
if isinstance(idx, (scalar.Scalar, T.TensorType)):
# The idx is a Scalar, ie a Type. This means the actual index
# is contained in node.inputs[1]
old_idx, idx = idx, node.inputs[1]
assert idx.type == old_idx
if isinstance(idx, (int, numpy.integer)):
return [x.owner.inputs[idx]]
elif isinstance(idx, Variable):
# if it is a constant we can do something with it
try:
v = get_scalar_constant_value(idx)
if isinstance(v, numpy.integer):
# Python 2.4 wants to index only with Python integers
v = int(v)
return [x.owner.inputs[v]]
except NotScalarConstantError:
pass
else:
# it is a slice of ints and/or Variables
#TODO: check subtensor to see if it can contain
# constant variables, and if it can, then try to
# unpack them.
try:
return [make_vector(*x.owner.inputs.__getitem__(idx))]
except TypeError:
pass
except Exception:
_logger.error('failed to index with "%s"' % str(idx))
raise
v = get_scalar_constant_value(idx)
if isinstance(v, numpy.integer):
# Python 2.4 wants to index only with Python integers
v = int(v)
return [x.owner.inputs[v]]
except NotScalarConstantError:
pass
elif idx.ndim == 1 and isinstance(idx, T.Constant):
values = map(int, list(idx.value))
return [make_vector(*[x.owner.inputs[v] for v in values])]
else:
raise TypeError('case not expected')
elif isinstance(idx, slice):
# it is a slice of ints and/or Variables
# check subtensor to see if it can contain constant variables, and if
# it can, then try to unpack them.
try:
const_slice = node.op.get_constant_idx(node.inputs,
allow_partial=False)[0]
return [make_vector(*x.owner.inputs[const_slice])]
except NotScalarConstantError:
pass
else:
raise TypeError('case not expected')
#TODO: the other optimization for and, or, xor, le and ge see ticket #496.
......@@ -2373,12 +2393,17 @@ compile.optdb.register('local_inplace_incsubtensor1',
# Register old name
@register_canonicalize("local_incsubtensor_of_allocs")
@register_stabilize("local_incsubtensor_of_allocs")
@gof.local_optimizer([IncSubtensor])
@gof.local_optimizer([IncSubtensor,
AdvancedIncSubtensor,
AdvancedIncSubtensor1])
def local_incsubtensor_of_zeros(node):
"""
IncSubtensor(x, zeros, idx) -> x
"""
if isinstance(node.op, IncSubtensor) and not node.op.set_instead_of_inc:
if (isinstance(node.op, (IncSubtensor,
AdvancedIncSubtensor,
AdvancedIncSubtensor1)) and
not node.op.set_instead_of_inc):
x = node.inputs[0]
y = node.inputs[1]
replace = False
......
......@@ -35,7 +35,8 @@ from theano.tensor.opt import (
out2in,
Shape_i,
Assert,
MakeVector
MakeVector,
make_vector
)
from theano import tensor
from theano import tensor as T
......@@ -1712,6 +1713,54 @@ def test_local_useless_subtensor():
f([[1, 2, 3], [4, 5, 6]], 3)
class test_local_subtensor_make_vector(unittest.TestCase):
def test_scalar_idx(self):
x, y, z = tensor.lscalars('xyz')
v = make_vector(x, y, z)
f = function([x, y, z], v[0], mode=mode_opt)
prog = f.maker.fgraph.toposort()
assert len(prog) == 1
assert isinstance(prog[0].op, theano.compile.ops.DeepCopyOp)
assert f(0, 1, 2) == 0
def test_slice_idx_stop(self):
x, y, z = tensor.lscalars('xyz')
v = make_vector(x, y, z)
f = function([x, y, z], v[:2], mode=mode_opt)
prog = f.maker.fgraph.toposort()
assert len(prog) == 1
assert isinstance(prog[0].op, MakeVector)
assert len(prog[0].inputs) == 2
r = f(0, 1, 2)
assert r[0] == 0 and r[1] == 1
def test_slice_idx_step(self):
x, y, z = tensor.lscalars('xyz')
v = make_vector(x, y, z)
f = function([x, y, z], v[::2], mode=mode_opt)
prog = f.maker.fgraph.toposort()
assert len(prog) == 1
assert isinstance(prog[0].op, MakeVector)
assert len(prog[0].inputs) == 2
r = f(0, 1, 2)
assert r[0] == 0 and r[1] == 2
def test_AdvancedSubtensor1_idx(self):
x, y, z = tensor.lscalars('xyz')
v = make_vector(x, y, z)
f = function([x, y, z], v[[0, 2]], mode=mode_opt)
prog = f.maker.fgraph.toposort()
assert len(prog) == 1
assert isinstance(prog[0].op, MakeVector)
assert len(prog[0].inputs) == 2
r = f(0, 1, 2)
assert r[0] == 0 and r[1] == 2
class test_local_subtensor_lift(unittest.TestCase):
def test0(self):
# basic test that the Op works
......@@ -2442,6 +2491,69 @@ class Test_alloc_zero(unittest.TestCase):
assert numpy.all([not isinstance(x.op, tensor.IncSubtensor) for x in
f.maker.fgraph.toposort()])
def test_advancedincsubtensor1_allocs0(self):
x = tensor.matrix()
y = tensor.matrix()
y0 = tensor.zeros_like(y)
z = tensor.inc_subtensor(x[[0, 1, 2, 3]], y0)
f = theano.function([x, y], z, mode=self.mode)
assert numpy.all([not isinstance(x.op, tensor.AdvancedIncSubtensor1)
for x in f.maker.fgraph.toposort()])
def test_advancedincsubtensor1_allocs0t(self):
x = tensor.matrix()
y = tensor.matrix()
y0 = tensor.zeros_like(y)
z = tensor.inc_subtensor(x[[0, 1, 2, 3]], y0.T)
f = theano.function([x, y], z, mode=mode_opt)
assert numpy.all([not isinstance(x.op, tensor.AdvancedIncSubtensor1)
for x in f.maker.fgraph.toposort()])
def test_advancedincsubtensor1_allocs1(self):
x = tensor.matrix()
y0 = tensor.constant(numpy.asarray(numpy.zeros_like((4, 4)),
dtype=config.floatX))
z = tensor.inc_subtensor(x[[0, 1, 2, 3]], y0)
f = theano.function([x], z, mode=self.mode)
assert numpy.all([not isinstance(x.op, tensor.AdvancedIncSubtensor1)
for x in f.maker.fgraph.toposort()])
def test_advancedincsubtensor_allocs0(self):
if tensor.inplace_increment is None:
raise SkipTest('NumPy version >= 1.8 not available')
x = tensor.matrix()
y = tensor.matrix()
y0 = tensor.zeros_like(y)
z = tensor.inc_subtensor(x[[[0, 0], [1, 1]], [[0, 1], [0, 1]]], y0)
f = theano.function([x, y], z, mode=self.mode)
assert numpy.all([not isinstance(x.op, tensor.AdvancedIncSubtensor)
for x in f.maker.fgraph.toposort()])
def test_advancedincsubtensor_allocs0t(self):
if tensor.inplace_increment is None:
raise SkipTest('NumPy version >= 1.8 not available')
x = tensor.matrix()
y = tensor.matrix()
y0 = tensor.zeros_like(y)
z = tensor.inc_subtensor(x[[[0, 0], [1, 1]], [[0, 1], [0, 1]]], y0.T)
f = theano.function([x, y], z, mode=mode_opt)
assert numpy.all([not isinstance(x.op, tensor.AdvancedIncSubtensor)
for x in f.maker.fgraph.toposort()])
def test_advancedincsubtensor_allocs1(self):
if tensor.inplace_increment is None:
raise SkipTest('NumPy version >= 1.8 not available')
x = tensor.matrix()
y0 = tensor.constant(numpy.asarray(numpy.zeros_like((2, 2)),
dtype=config.floatX))
z = tensor.inc_subtensor(x[[[0, 0], [1, 1]], [[0, 1], [0, 1]]], y0)
f = theano.function([x], z, mode=self.mode)
assert numpy.all([not isinstance(x.op, tensor.AdvancedIncSubtensor)
for x in f.maker.fgraph.toposort()])
def test_dot_allocs_0(self):
v1 = tensor.vector('v1')
v2 = tensor.vector('v2')
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论