提交 2b350631 authored 作者: Frederic Bastien's avatar Frederic Bastien

add optimization -max(-x) -> min(x). Add test for min() and the new optimization.

上级 e032bb8f
...@@ -27,23 +27,12 @@ from basic import get_constant_value ...@@ -27,23 +27,12 @@ from basic import get_constant_value
from theano.tensor.opt import register_uncanonicalize from theano.tensor.opt import register_uncanonicalize
from theano import scalar as scal from theano import scalar as scal
@register_uncanonicalize
@gof.local_optimizer([T._shape])
def local_max_and_argmax_specialize(node):
if node.op == T._max_and_argmax:
if len(node.outputs[1].clients)==0:
import pdb;pdb.set_trace()
try:
axis=get_constant_value(node.inputs[1])
except ValueError:
return False
return [CAReduce(scal.maximum,axis)(node.inputs[0]), T.as_tensor_variable(0)]
return False
class MaxAndArgmaxOptimizer(Optimizer): class MaxAndArgmaxOptimizer(Optimizer):
"""Graph optimizer for Fusion of elemwise operations""" """Replace MaxAndArgmax by CAReduce when the argmax is not used
This is faster as MaxAndArgmax don't have c code and execute it
in two pass.
"""
def add_requirements(self, env): def add_requirements(self, env):
env.extend(toolbox.ReplaceValidate()) env.extend(toolbox.ReplaceValidate())
...@@ -73,3 +62,16 @@ class MaxAndArgmaxOptimizer(Optimizer): ...@@ -73,3 +62,16 @@ class MaxAndArgmaxOptimizer(Optimizer):
register_uncanonicalize(MaxAndArgmaxOptimizer(),name='MaxAndArgmaxOptimizer') register_uncanonicalize(MaxAndArgmaxOptimizer(),name='MaxAndArgmaxOptimizer')
@register_uncanonicalize
@gof.local_optimizer([T._shape])
def local_max_to_min(node):
if node.op == T.neg and node.inputs[0].owner:
max = node.inputs[0]
if max.owner and isinstance(max.owner.op, CAReduce) and max.owner.op.scalar_op==scal.maximum:
neg = max.owner.inputs[0]
if neg.owner and neg.owner.op == T.neg:
return [CAReduce(scal.minimum,max.owner.op.axis)(neg.owner.inputs[0])]
return False
...@@ -821,8 +821,10 @@ class T_max_and_argmax(unittest.TestCase): ...@@ -821,8 +821,10 @@ class T_max_and_argmax(unittest.TestCase):
n = as_tensor_variable(numpy.random.rand(2,3)) n = as_tensor_variable(numpy.random.rand(2,3))
v,i = eval_outputs(max_and_argmax(n,-1)) v,i = eval_outputs(max_and_argmax(n,-1))
self.failUnless(v.shape == (2,)) self.failUnless(v.shape == (2,))
self.failUnless(numpy.all(v == numpy.max(n.value,-1)))
v,i = eval_outputs(max_and_argmax(n,-2)) v,i = eval_outputs(max_and_argmax(n,-2))
self.failUnless(v.shape == (3,)) self.failUnless(v.shape == (3,))
self.failUnless(numpy.all(v == numpy.max(n.value,-2)))
v = eval_outputs(max_and_argmax(n,-1)[0].shape) v = eval_outputs(max_and_argmax(n,-1)[0].shape)
assert v==(2) assert v==(2)
v = eval_outputs(max_and_argmax(n,-2)[0].shape) v = eval_outputs(max_and_argmax(n,-2)[0].shape)
...@@ -846,21 +848,6 @@ class T_max_and_argmax(unittest.TestCase): ...@@ -846,21 +848,6 @@ class T_max_and_argmax(unittest.TestCase):
v = eval_outputs(max_and_argmax(n,2)[0].shape) v = eval_outputs(max_and_argmax(n,2)[0].shape)
assert tuple(v)==(2,3) assert tuple(v)==(2,3)
def test_optimization(self):
#If we use only the max output, we should replace this op with a faster one.
data = numpy.asarray(numpy.random.rand(2,3),dtype=config.floatX)
n = matrix()
f = function([n],max_and_argmax(n,0)[0])
topo = f.maker.env.toposort()
assert len(topo)==1
assert isinstance(topo[0].op,CAReduce)
f = function([n],max_and_argmax(n,0))
topo = f.maker.env.toposort()
assert len(topo)==1
assert isinstance(topo[0].op,MaxAndArgmax)
def test_grad(self): def test_grad(self):
data = numpy.random.rand(2,3) data = numpy.random.rand(2,3)
n = as_tensor_variable(data) n = as_tensor_variable(data)
...@@ -897,131 +884,136 @@ class T_max_and_argmax(unittest.TestCase): ...@@ -897,131 +884,136 @@ class T_max_and_argmax(unittest.TestCase):
utt.verify_grad(lambda v: max_and_argmax(v.flatten())[1], [data]) utt.verify_grad(lambda v: max_and_argmax(v.flatten())[1], [data])
check_grad_max(data,eval_outputs(grad(max_and_argmax(n.flatten())[0],n))) check_grad_max(data,eval_outputs(grad(max_and_argmax(n.flatten())[0],n)))
class T_max(unittest.TestCase): class T_min_max(unittest.TestCase):
def setUp(self): def setUp(self):
utt.seed_rng() utt.seed_rng()
MaxAndArgmax.debug = 0 MaxAndArgmax.debug = 0
def _test0(self): def test0(self):
n = as_tensor_variable(5.0) for fct in [max,min]:
v = eval_outputs(max(n)) n = as_tensor_variable(5.0)
self.failUnless(v == 5.0) v = eval_outputs(fct(n))
v = eval_outputs(max(n)[0].shape) self.failUnless(v == 5.0)
assert len(v)==0
v = eval_outputs(fct(n).shape)
assert len(v)==0
def test1(self): def test1(self):
n = as_tensor_variable([1,2,3,2,-6]) for fct,nfct in [(max,numpy.max),(min,numpy.min)]:
v = eval_outputs([max(n)]) n = as_tensor_variable([1,2,3,2,-6])
self.failUnless(v == 3) v = eval_outputs([fct(n)])
v = eval_outputs(max(n).shape) self.failUnless(v == nfct(n.value))
assert len(v)==0
v = eval_outputs(fct(n).shape)
assert len(v)==0
def test2(self): def test2(self):
data = numpy.random.rand(2,3) for fct,nfct in [(max,numpy.max),(min,numpy.min)]:
n = as_tensor_variable(data) data = numpy.random.rand(2,3)
v = eval_outputs(max(n,-1)) n = as_tensor_variable(data)
self.failUnless(numpy.all(v == numpy.max(data,-1))) v = eval_outputs(fct(n,-1))
v = eval_outputs(max(n).shape) self.failUnless(numpy.all(v == nfct(data,-1)))
assert v==(2)
v = eval_outputs(fct(n).shape)
assert v==(2)
def test2b(self): def test2b(self):
data = numpy.random.rand(2,3) for fct,nfct in [(max,numpy.max),(min,numpy.min)]:
n = as_tensor_variable(data) data = numpy.random.rand(2,3)
v = eval_outputs(max(n,0)) n = as_tensor_variable(data)
self.failUnless(numpy.all(v == numpy.max(data,0))) v = eval_outputs(fct(n,0))
v = eval_outputs(max(n,0).shape) self.failUnless(numpy.all(v == nfct(data,0)))
assert v==(3)
v = eval_outputs(max(n,1).shape) v = eval_outputs(fct(n,0).shape)
assert v==(2) assert v==(3)
v = eval_outputs(max(n,[0,1]).shape) v = eval_outputs(fct(n,1).shape)
assert v.size==0 assert v==(2)
v = eval_outputs(fct(n,[0,1]).shape)
assert v.size==0
def test2_invalid(self): def test2_invalid(self):
n = as_tensor_variable(numpy.random.rand(2,3)) for fct in [max,min]:
# Silence expected error messages n = as_tensor_variable(numpy.random.rand(2,3))
_logger = logging.getLogger('theano.gof.opt') # Silence expected error messages
oldlevel = _logger.getEffectiveLevel() _logger = logging.getLogger('theano.gof.opt')
_logger.setLevel(logging.CRITICAL) oldlevel = _logger.getEffectiveLevel()
try: _logger.setLevel(logging.CRITICAL)
try: try:
eval_outputs(max(n,3)) try:
assert False eval_outputs(fct(n,3))
except ValueError, e: assert False
pass except ValueError, e:
finally: pass
_logger.setLevel(oldlevel) finally:
_logger.setLevel(oldlevel)
def test2_invalid_neg(self): def test2_invalid_neg(self):
n = as_tensor_variable(numpy.random.rand(2,3)) for fct in [max,min]:
old_stderr = sys.stderr n = as_tensor_variable(numpy.random.rand(2,3))
sys.stderr = StringIO.StringIO() old_stderr = sys.stderr
try: sys.stderr = StringIO.StringIO()
try: try:
eval_outputs(max(n,-3)) try:
assert False eval_outputs(fct(n,-3))
except ValueError, e: assert False
pass except ValueError, e:
finally: pass
sys.stderr = old_stderr finally:
sys.stderr = old_stderr
def test2_valid_neg(self): def test2_valid_neg(self):
n = as_tensor_variable(numpy.random.rand(2,3)) for fct,nfct in [(max,numpy.max),(min,numpy.min)]:
v = eval_outputs(max(n,-1)) n = as_tensor_variable(numpy.random.rand(2,3))
self.failUnless(v.shape == (2,)) v = eval_outputs(fct(n,-1))
v = eval_outputs(max(n,-2)) self.failUnless(v.shape == (2,))
self.failUnless(v.shape == (3,)) self.failUnless(numpy.all(v == nfct(n.value,-1)))
v = eval_outputs(max(n,-1).shape) v = eval_outputs(fct(n,-2))
assert v==(2) self.failUnless(v.shape == (3,))
v = eval_outputs(max(n,-2).shape) self.failUnless(numpy.all(v == nfct(n.value,-2)))
assert v==(3)
v = eval_outputs(fct(n,-1).shape)
assert v==(2)
v = eval_outputs(fct(n,-2).shape)
assert v==(3)
def test3(self): def test3(self):
n = as_tensor_variable(numpy.random.rand(2,3,4)) for fct,nfct in [(max,numpy.max),(min,numpy.min)]:
v = eval_outputs(max(n,0)) n = as_tensor_variable(numpy.random.rand(2,3,4))
self.failUnless(v.shape == (3,4)) v = eval_outputs(fct(n,0))
self.failUnless(numpy.all(v == numpy.max(n.value,0))) self.failUnless(v.shape == (3,4))
v = eval_outputs(max(n,1)) self.failUnless(numpy.all(v == nfct(n.value,0)))
self.failUnless(v.shape == (2,4)) v = eval_outputs(fct(n,1))
self.failUnless(numpy.all(v == numpy.max(n.value,1))) self.failUnless(v.shape == (2,4))
v = eval_outputs(max(n,2)) self.failUnless(numpy.all(v == nfct(n.value,1)))
self.failUnless(v.shape == (2,3)) v = eval_outputs(fct(n,2))
self.failUnless(numpy.all(v == numpy.max(n.value,2))) self.failUnless(v.shape == (2,3))
v = eval_outputs(max(n,[0,1])) self.failUnless(numpy.all(v == nfct(n.value,2)))
self.failUnless(v.shape == (4,)) v = eval_outputs(fct(n,[0,1]))
self.failUnless(numpy.all(v == numpy.max(n.value,1).max(0))) self.failUnless(v.shape == (4,))
v = eval_outputs(max(n,[0,2])) self.failUnless(numpy.all(v == nfct(nfct(n.value,1),0)))
self.failUnless(v.shape == (3,)) v = eval_outputs(fct(n,[0,2]))
self.failUnless(numpy.all(v == numpy.max(n.value,2).max(0))) self.failUnless(v.shape == (3,))
v = eval_outputs(max(n,[1,2])) self.failUnless(numpy.all(v == nfct(nfct(n.value,2),0)))
self.failUnless(v.shape == (2,)) v = eval_outputs(fct(n,[1,2]))
self.failUnless(numpy.all(v == numpy.max(n.value,2).max(1))) self.failUnless(v.shape == (2,))
v = eval_outputs(max(n,[0,1,2])) self.failUnless(numpy.all(v == nfct(nfct(n.value,2),1)))
self.failUnless(v.shape == ()) v = eval_outputs(fct(n,[0,1,2]))
self.failUnless(v.shape == ())
v = eval_outputs(max(n,0).shape)
assert tuple(v)==(3,4) v = eval_outputs(fct(n,0).shape)
v = eval_outputs(max(n,1).shape) assert tuple(v)==(3,4)
assert tuple(v)==(2,4) v = eval_outputs(fct(n,1).shape)
v = eval_outputs(max(n,2).shape) assert tuple(v)==(2,4)
assert tuple(v)==(2,3) v = eval_outputs(fct(n,2).shape)
v = eval_outputs(max(n,[0,1]).shape) assert tuple(v)==(2,3)
self.failUnless(v == (4,)) v = eval_outputs(fct(n,[0,1]).shape)
v = eval_outputs(max(n,[0,2]).shape) self.failUnless(v == (4,))
self.failUnless(v == (3,)) v = eval_outputs(fct(n,[0,2]).shape)
v = eval_outputs(max(n,[1,2]).shape) self.failUnless(v == (3,))
self.failUnless(v == (2,)) v = eval_outputs(fct(n,[1,2]).shape)
v = eval_outputs(max(n,[0,1,2]).shape) self.failUnless(v == (2,))
self.failUnless(v.size == 0) v = eval_outputs(fct(n,[0,1,2]).shape)
self.failUnless(v.size == 0)
def test_optimization(self):
data = numpy.asarray(numpy.random.rand(2,3),dtype=config.floatX) def test_grad_max(self):
n = matrix()
f = function([n],max(n,0))
topo = f.maker.env.toposort()
assert len(topo)==1
assert isinstance(topo[0].op,CAReduce)
f(data)
def test_grad(self):
data = numpy.random.rand(2,3) data = numpy.random.rand(2,3)
n = as_tensor_variable(data) n = as_tensor_variable(data)
...@@ -1045,18 +1037,51 @@ class T_max(unittest.TestCase): ...@@ -1045,18 +1037,51 @@ class T_max(unittest.TestCase):
utt.verify_grad(lambda v: max(v), [data]) utt.verify_grad(lambda v: max(v), [data])
utt.verify_grad(lambda v: max(v,axis=[0]), [data]) utt.verify_grad(lambda v: max(v,axis=[0]), [data])
check_grad_max(data,eval_outputs(grad(max_and_argmax(n,axis=0)[0],n)),axis=0) check_grad_max(data,eval_outputs(grad(max(n,axis=0),n)),axis=0)
utt.verify_grad(lambda v: max(v,axis=[1]), [data]) utt.verify_grad(lambda v: max(v,axis=[1]), [data])
#check_grad_max(data,eval_outputs(grad(max_and_argmax(n,axis=1)[0],n)),axis=1) #check_grad_max(data,eval_outputs(grad(max(n,axis=1),n)),axis=1)
utt.verify_grad(lambda v: max(v.flatten()), [data]) utt.verify_grad(lambda v: max(v.flatten()), [data])
check_grad_max(data,eval_outputs(grad(max_and_argmax(n.flatten())[0],n))) check_grad_max(data,eval_outputs(grad(max(n.flatten()),n)))
def test_grad_min(self):
data = numpy.random.rand(2,3)
n = as_tensor_variable(data)
def check_grad_min(data, min_grad_data, axis=None):
#This work only for axis in [0,None]
assert axis in [0,None]
z = numpy.zeros_like(data)
z = z.flatten()
argmin=numpy.argmin(data,axis=axis)
if argmin.ndim==0:
z[numpy.argmin(data,axis=axis)]+=1
else:
for id,v in enumerate(argmin):
z[v*numpy.prod(data.shape[data.ndim-1:axis:-1])+id]+=1
z = z.reshape(data.shape)
assert numpy.all(min_grad_data == z)
#test grad of min
#axis is the last one
utt.verify_grad(lambda v: min(v), [data])
utt.verify_grad(lambda v: min(v,axis=[0]), [data])
check_grad_min(data,eval_outputs(grad(min(n,axis=0),n)),axis=0)
utt.verify_grad(lambda v: min(v,axis=[1]), [data])
#check_grad_min(data,eval_outputs(grad(min(n,axis=1),n)),axis=1)
utt.verify_grad(lambda v: min(v.flatten()), [data])
check_grad_min(data,eval_outputs(grad(min(n.flatten()),n)))
@dec.knownfailureif(True, @dec.knownfailureif(True,
"We don't implement the gradient of max with multiple axis as the same time") "We don't implement the gradient of max with multiple axis as the same time")
def test_grad_list(self): def test_grad_list(self):
utt.verify_grad(lambda v: max(v,axis=[0,1]), [data]) for fct in [max,min]:
utt.verify_grad(lambda v: fct(v,axis=[0,1]), [data])
#check_grad_max(data,eval_outputs(grad(max_and_argmax(n,axis=1)[0],n)),axis=1) #check_grad_max(data,eval_outputs(grad(max_and_argmax(n,axis=1)[0],n)),axis=1)
class T_subtensor(unittest.TestCase): class T_subtensor(unittest.TestCase):
......
import unittest
import numpy
from theano import function,config
import theano.tensor as tensor
#from theano.tensor import matrix,max_and_argmax,MaaxAndArgmax,neg
from theano.tensor.elemwise import CAReduce
from theano.tests import unittest_tools as utt
class T_max_and_argmax(unittest.TestCase):
def test_optimization(self):
#If we use only the max output, we should replace this op with a faster one.
data = numpy.asarray(numpy.random.rand(2,3),dtype=config.floatX)
n = tensor.matrix()
f = function([n], tensor.max_and_argmax(n,0)[0])
topo = f.maker.env.toposort()
assert len(topo)==1
assert isinstance(topo[0].op, CAReduce)
f = function([n], tensor.max_and_argmax(n,0))
topo = f.maker.env.toposort()
assert len(topo)==1
assert isinstance(topo[0].op, tensor.MaxAndArgmax)
class T_min_max(unittest.TestCase):
def setUp(self):
utt.seed_rng()
def test_optimization_max(self):
data = numpy.asarray(numpy.random.rand(2,3),dtype=config.floatX)
n = tensor.matrix()
f = function([n],tensor.max(n,0))
topo = f.maker.env.toposort()
assert len(topo)==1
assert isinstance(topo[0].op,CAReduce)
f(data)
f = function([n],tensor.max(-n,0))
topo = f.maker.env.toposort()
assert len(topo)==2
assert topo[0].op==tensor.neg
assert isinstance(topo[1].op,CAReduce)
f(data)
f = function([n],-tensor.max(n,0))
topo = f.maker.env.toposort()
assert len(topo)==2
assert isinstance(topo[0].op,CAReduce)
assert topo[1].op==tensor.neg
f(data)
f = function([n],-tensor.max(-n,0))
topo = f.maker.env.toposort()
assert len(topo)==1
assert isinstance(topo[0].op,CAReduce)#min
f(data)
def test_optimization_min(self):
data = numpy.asarray(numpy.random.rand(2,3),dtype=config.floatX)
n = tensor.matrix()
f = function([n],tensor.min(n,0))
topo = f.maker.env.toposort()
assert len(topo)==1
assert isinstance(topo[0].op,CAReduce)
f(data)
#test variant with neg to make sure we optimize correctly
f = function([n],tensor.min(-n,0))
topo = f.maker.env.toposort()
assert len(topo)==2
assert isinstance(topo[0].op,CAReduce)#max
assert topo[1].op==tensor.neg
f(data)
f = function([n],-tensor.min(n,0))
topo = f.maker.env.toposort()
assert len(topo)==2
assert topo[0].op==tensor.neg
assert isinstance(topo[1].op,CAReduce)#max
f(data)
f = function([n],-tensor.min(-n,0))
topo = f.maker.env.toposort()
assert len(topo)==1
assert isinstance(topo[0].op,CAReduce)#max
f(data)
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论