提交 20bcca35 authored 作者: Razvan Pascanu's avatar Razvan Pascanu

Merge pull request #212 from dwf/rebased_new_lazy_ifelse

Rebased new lazy ifelse
......@@ -19,7 +19,7 @@ Conditions
.. code-block:: python
from theano import tensor as T
from theano.lazycond import ifelse
from theano.ifelse import ifelse
import theano, time, numpy
a,b = T.scalars('a','b')
......
......@@ -18,7 +18,7 @@ Conditions
.. code-block:: python
from theano import tensor as T
from theano.lazycond import ifelse
from theano.ifelse import ifelse
import theano, time, numpy
a,b = T.scalars('a','b')
......
......@@ -94,7 +94,7 @@ class NotImplementedOp(PureOp):
def test_ifelse():
a = generic()
a = T.scalar()
b = generic()
c = generic()
......@@ -105,15 +105,15 @@ def test_ifelse():
try:
print "case 1"
f( True, 'a', 'b')
f( 1, 'a', 'b')
assert False
except NotImplementedOp.E:
pass
print "... passed"
print "case 2"
print f( False, 'a', 'b')
assert f( False, 'a', 'b') == 'b'
print f( 0, 'a', 'b')
assert f( 0, 'a', 'b') == 'b'
print "... passed"
......@@ -123,8 +123,8 @@ def more_complex_test():
x1 = T.scalar('x1')
x2 = T.scalar('x2')
c1 = generic('c1')
c2 = generic('c2')
c1 = T.scalar('c1')
c2 = T.scalar('c2')
t1 = ifelse(c1,x1,notimpl(x2))
t1.name = 't1'
t2 = t1*10
......
差异被折叠。
"""
IfElse is an Op that works with the LazyLinker to support conditional graph evaluation.
:TODO: Add text to library documentation describing the IfElse Op.
"""
from copy import deepcopy
import logging
from theano.gof import PureOp, Apply, generic, Container
import theano.tensor
import gof
from compile import optdb
from tensor import opt
_logger = logging.getLogger('theano.lazycond')
@gof.local_optimizer([None])
def ifelse_make_inplace(node):
op = node.op
if isinstance(op, IfElse) and not op.as_view :
_logger.debug('ifelse_make_inplace applied')
return IfElse(as_view = True,
gpu = op.gpu, name=op.name).make_node(*node.inputs).outputs
return False
optdb.register('ifelse_make_inplace', opt.in2out(ifelse_make_inplace,
ignore_newtrees=True), 95, 'fast_run', 'inplace')
class IfElse(PureOp):
"""
Op that works with LazyLinker to support conditional graph evaluation.
Example usage:
``rval = ifelse(tf, rval_if_true, rval_if_false)``
:type tf: symbolic tensor
:param tf: boolean variable representing a condition
:type rval_if_true: symbolic tensor
:param rval_if_false: symbolic variable to compute if tf is True
:type rval_if_false: symbolic tensor
:param rval_if_false: symbolic variable to compute if tf is False
:return: tensor corresponding to rval_if_true if tf is True or
rval_if_false if tf is False
While the switch function computes both values (rval_if_true and rval_if_false),
the ifelse op only computes one e.g rval_if_true is computed if tf is True.
:note:
Other Linkers (ALL other linkers right now) are INCOMPATIBLE with this
Op, they will produce functions that FAIL TO EXECUTE.
"""
def __init__(self, as_view=False, gpu = False, name = None):
if as_view:
# check destroyhandler and others to ensure that a view_map with
# multiple inputs can work
view_map = {}
view_map[0] = [1]
self.view_map = view_map
#raise NotImplementedError('IfElse must copy for now')
else:
self.view_map = {}
self.as_view=as_view
self.gpu = gpu
self.name = name
def __eq__(self, other):
return (type(self)==type(other) and
self.as_view == other.as_view and
# view_map included in as_view
#self.view_map == other.view_map and
self.gpu == other.gpu and
self.name == other.name)
def __hash__(self):
return (hash(type(self)) ^
# view_map included in as_view
# and dict are not hashable
#hash(self.view_map) ^
hash(self.as_view) ^
hash(self.gpu) ^
hash(self.name))
def make_node(self, c, t, f):
if t.type != f.type:
raise TypeError(
'IfElse requires same types for true and false args',
(t.type, f.type))
return Apply(self, [c,t,f], [t.type()])
def make_thunk(self, node, storage_map, compute_map, no_recycling):
outtype = node.outputs[0].type
c,t,f = node.inputs
output = node.outputs[0]
def thunk():
if not compute_map[c][0]:
return [0]
else:
truthval = storage_map[c][0]
if truthval:
if not compute_map[t][0]:
return [1]
else:
compute_map[output][0]=1
if self.as_view:
oval = outtype.filter(storage_map[t][0])
else:
oval = outtype.filter(
deepcopy(storage_map[t][0]))
storage_map[output][0] = oval
return []
else:
if not compute_map[f][0]:
return [2]
else:
# can't view both outputs unless destroyhandler
# improves
compute_map[output][0]=1
oval = outtype.filter(
deepcopy(storage_map[f][0]))
storage_map[output][0]=oval
return []
thunk.lazy = True
thunk.inputs = [storage_map[v] for v in node.inputs]
thunk.outputs = [storage_map[v] for v in node.outputs]
return thunk
ifelse = IfElse()
"""
Tests fof the lazy conditiona
"""
__docformat__ = 'restructedtext en'
__authors__ = ("Razvan Pascanu ")
__copyright__ = "(c) 2010, Universite de Montreal"
__contact__ = "Razvan Pascanu <r.pascanu@gmail>"
import unittest
import numpy
from nose.plugins.skip import SkipTest
import theano
from theano import tensor
from theano.ifelse import IfElse, ifelse
from theano.tests import unittest_tools as utt
class test_ifelse(unittest.TestCase):
def test_lazy_if(self):
# Tests that lazy if works .. even if the two results have different
# shapes but the same type (i.e. both vectors, or matrices or
# whatnot of same dtype
x = tensor.vector('x')
y = tensor.vector('y')
c = tensor.iscalar('c')
f = theano.function([c, x, y], ifelse(c, x, y))
rng = numpy.random.RandomState(utt.fetch_seed())
xlen = rng.randint(200)
ylen = rng.randint(200)
vx = numpy.asarray(rng.uniform(size=(xlen,)), theano.config.floatX)
vy = numpy.asarray(rng.uniform(size=(ylen,)), theano.config.floatX)
assert numpy.allclose(vx, f(1, vx, vy))
assert numpy.allclose(vy, f(0, vx, vy))
def test_lazy_if_on_generics(self):
x = theano.generic()
y = theano.generic()
c = tensor.iscalar('c')
f = theano.function([c, x, y], ifelse(c, x, y))
vx = ['testX']
vy = ['testY']
assert f(1, vx, vy) == vx
assert f(0, vx, vy) == vy
def test_grad_lazy_if(self):
# Tests that we can compute the gradients through lazy if
x = tensor.vector('x')
y = tensor.vector('y')
c = tensor.iscalar('c')
z = ifelse(c, x, y)
gx, gy = tensor.grad(z.sum(), [x, y])
f = theano.function([c, x, y], [gx, gy])
rng = numpy.random.RandomState(utt.fetch_seed())
xlen = rng.randint(200)
ylen = rng.randint(200)
vx = numpy.asarray(rng.uniform(size=(xlen,)), theano.config.floatX)
vy = numpy.asarray(rng.uniform(size=(ylen,)), theano.config.floatX)
gx0, gy0 = f(1, vx, vy)
assert numpy.allclose(gx0.shape, vx.shape)
assert numpy.allclose(gy0.shape, vy.shape)
assert numpy.all(gx0 == 1.)
assert numpy.all(gy0 == 0.)
gx0, gy0 = f(0, vx, vy)
assert numpy.allclose(gx0.shape, vx.shape)
assert numpy.allclose(gy0.shape, vy.shape)
assert numpy.all(gx0 == 0.)
assert numpy.all(gy0 == 1.)
def test_merge(self):
raise SkipTest("Optimization temporarily disabled")
x = tensor.vector('x')
y = tensor.vector('y')
c = tensor.iscalar('c')
z1 = ifelse(c, x + 1, y + 1)
z2 = ifelse(c, x + 2, y + 2)
z = z1 + z2
f = theano.function([c, x, y], z)
assert len([x for x in f.maker.env.toposort()
if isinstance(x.op, IfElse)]) == 1
def test_remove_useless_inputs1(self):
raise SkipTest("Optimization temporarily disabled")
x = tensor.vector('x')
y = tensor.vector('y')
c = tensor.iscalar('c')
z = ifelse(c, (x, x), (y, y))
f = theano.function([c, x, y], z)
ifnode = [x for x in f.maker.env.toposort()
if isinstance(x.op, IfElse)][0]
assert len(ifnode.inputs) == 3
def test_remove_useless_inputs2(self):
raise SkipTest("Optimization temporarily disabled")
x1 = tensor.vector('x1')
x2 = tensor.vector('x2')
y1 = tensor.vector('y1')
y2 = tensor.vector('y2')
c = tensor.iscalar('c')
z = ifelse(c, (x1, x1, x1, x2, x2), (y1, y1, y2, y2, y2))
f = theano.function([c, x1, x2, y1, y2], z)
ifnode = [x for x in f.maker.env.toposort()
if isinstance(x.op, IfElse)][0]
assert len(ifnode.outputs) == 3
def test_pushout1(self):
raise SkipTest("Optimization temporarily disabled")
x1 = tensor.scalar('x1')
x2 = tensor.scalar('x2')
y1 = tensor.scalar('y1')
y2 = tensor.scalar('y2')
w1 = tensor.scalar('w1')
w2 = tensor.scalar('w2')
c = tensor.iscalar('c')
x, y = ifelse(c, (x1, y1), (x2, y2), name='f1')
z = ifelse(c, w1, w2, name='f2')
out = x * z * y
f = theano.function([x1, x2, y1, y2, w1, w2, c], out,
allow_input_downcast=True)
assert isinstance(f.maker.env.toposort()[-1].op, IfElse)
rng = numpy.random.RandomState(utt.fetch_seed())
vx1 = rng.uniform()
vx2 = rng.uniform()
vy1 = rng.uniform()
vy2 = rng.uniform()
vw1 = rng.uniform()
vw2 = rng.uniform()
assert numpy.allclose(f(vx1, vx2, vy1, vy2, vw1, vw2, 1),
vx1 * vy1 * vw1)
assert numpy.allclose(f(vx1, vx2, vy1, vy2, vw1, vw2, 0),
vx2 * vy2 * vw2)
def test_pushout3(self):
raise SkipTest("Optimization temporarily disabled")
x1 = tensor.scalar('x1')
y1 = tensor.scalar('x2')
y2 = tensor.scalar('y2')
c = tensor.iscalar('c')
two = numpy.asarray(2, dtype=theano.config.floatX)
x, y = ifelse(c, (x1, y1), (two, y2), name='f1')
o3 = numpy.asarray(0.3, dtype=theano.config.floatX)
o2 = numpy.asarray(0.2, dtype=theano.config.floatX)
z = ifelse(c, o3, o2, name='f2')
out = x * z * y
f = theano.function([x1, y1, y2, c], out,
allow_input_downcast=True)
assert isinstance(f.maker.env.toposort()[-1].op, IfElse)
rng = numpy.random.RandomState(utt.fetch_seed())
vx1 = rng.uniform()
vy1 = rng.uniform()
vy2 = rng.uniform()
assert numpy.allclose(f(vx1, vy1, vy2, 1), vx1 * vy1 * 0.3)
assert numpy.allclose(f(vx1, vy1, vy2, 0), 2 * vy2 * 0.2)
def test_pushout2(self):
raise SkipTest("Optimization temporarily disabled")
x1 = tensor.scalar('x1')
x2 = tensor.scalar('x2')
y1 = tensor.scalar('y1')
y2 = tensor.scalar('y2')
w1 = tensor.scalar('w1')
w2 = tensor.scalar('w2')
c = tensor.iscalar('c')
x, y = ifelse(c, (x1, y1), (x2, y2), name='f1')
z = ifelse(x > y, w1, w2, name='f2')
out = x * z * y
f = theano.function([x1, x2, y1, y2, w1, w2, c], out,
allow_input_downcast=True)
assert isinstance(f.maker.env.toposort()[-1].op, IfElse)
rng = numpy.random.RandomState(utt.fetch_seed())
vx1 = rng.uniform()
vx2 = rng.uniform()
vy1 = rng.uniform()
vy2 = rng.uniform()
vw1 = rng.uniform()
vw2 = rng.uniform()
if vx1 > vy1:
vw = vw1
else:
vw = vw2
assert numpy.allclose(f(vx1, vx2, vy1, vy2, vw1, vw2, 1),
vx1 * vy1 * vw)
if vx2 > vy2:
vw = vw1
else:
vw = vw2
assert numpy.allclose(f(vx1, vx2, vy1, vy2, vw1, vw2, 0),
vx2 * vy2 * vw)
def test_merge_ifs_true_false(self):
raise SkipTest("Optimization temporarily disabled")
x1 = tensor.scalar('x1')
x2 = tensor.scalar('x2')
y1 = tensor.scalar('y1')
y2 = tensor.scalar('y2')
w1 = tensor.scalar('w1')
w2 = tensor.scalar('w2')
c = tensor.iscalar('c')
out = ifelse(c,
ifelse(c, x1, x2) + ifelse(c, y1, y2) + w1,
ifelse(c, x1, x2) + ifelse(c, y1, y2) + w2)
f = theano.function([x1, x2, y1, y2, w1, w2, c], out,
allow_input_downcast=True)
assert len([x for x in f.maker.env.toposort()
if isinstance(x.op, IfElse)]) == 1
rng = numpy.random.RandomState(utt.fetch_seed())
vx1 = rng.uniform()
vx2 = rng.uniform()
vy1 = rng.uniform()
vy2 = rng.uniform()
vw1 = rng.uniform()
vw2 = rng.uniform()
assert numpy.allclose(f(vx1, vx2, vy1, vy2, vw1, vw2, 1),
vx1 + vy1 + vw1)
assert numpy.allclose(f(vx1, vx2, vy1, vy2, vw1, vw2, 0),
vx2 + vy2 + vw2)
if __name__ == '__main__':
print ' Use nosetests to run these tests '
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论