fixed orphan order bug in Function, continuing to bring Ops back

上级 1e2dd4e6
...@@ -273,39 +273,5 @@ def matrices(n): ...@@ -273,39 +273,5 @@ def matrices(n):
return [matrix() for i in xrange(n)] return [matrix() for i in xrange(n)]
#TODO: move this to the _test_tensor_ops.py
class _testCase_matinv:# (unittest.TestCase):
def setUp(self):
numpy.random.seed(1)
def matinv(self,dim):
# symbolic program
a,b = matrices(2)
ab = T.dot(a,b)
diff = ab - tensor.tensor(numpy.identity(dim))
ssdiff = T.sum((diff**2.0))
g = grad(ssdiff,None, tensor.tensor(numpy.ones(1)))
# compilation to function
fn = compile.Function([a,b], [ssdiff,g(b)])
# use the function
w = numpy.random.rand(dim,dim)
wi = numpy.random.rand(dim,dim)
for i in xrange(300):
ssd, gw = fn(w,wi)
#print ssdiff
if i == 0:
str0 = str(ssd)
wi -= 0.4 * gw
return str0, str(ssd)
def test_matinv(self):
"""Matrix inversion by gradient descent (eval mode)"""
self.assertEqual(('2.67327580893', '0.000438649434819'), self.matinv(3))
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
from tensor import * from tensor import *
import tensor as T import tensor # for hidden symbols
import unittest import unittest
from copy import copy from copy import copy
from compile import Function from compile import Function
import gradient import gradient
import gof import gof, gof.graph
#TODO: consider moving this function / functionality to gradient.py #TODO: consider moving this function / functionality to gradient.py
# rationale: it's tricky, and necessary everytime you want to verify # rationale: it's tricky, and necessary everytime you want to verify
# gradient numerically # gradient numerically
def verify_grad(testcase, op_cls, pt_list, n_tests=1, rng=numpy.random, eps=0.0000001, tol=0.0001): def verify_grad(testcase, op_cls, pt, n_tests=1, rng=numpy.random, eps=0.0000001, tol=0.0001):
"""testcase.failUnless( analytic gradient matches finite-diff gradient) """ """testcase.failUnless( analytic gradient matches finite-diff gradient) """
for test_num in xrange(n_tests): for test_num in xrange(n_tests):
for pt in pt_list: tensor_pt = [tinit(p,name='input %i'%i) for i,p in enumerate(pt)]
tensor_pt = [tensor(p) for p in pt]
o = op_cls(*tensor_pt) o = op_cls(*tensor_pt)
if len(o.outputs) > 1: if len(o.outputs) > 1:
raise NotImplementedError('cant (yet) autotest gradient of op with multiple outputs') raise NotImplementedError('cant (yet) autotest gradient of op with multiple outputs')
# we could make loop over outputs making random projections R for each, # we could make loop over outputs making random projections R for each,
# but this doesn't handle the case where not all the outputs are # but this doesn't handle the case where not all the outputs are
# differentiable... so I leave this as TODO for now -jsb. # differentiable... so I leave this as TODO for now -JB.
o_fn = Function(tensor_pt, o.outputs) o_fn = Function(tensor_pt, o.outputs)
o_fn_out = o_fn(*pt) o_fn_out = o_fn(*pt)
random_projection = rng.rand(*o_fn_out.shape) random_projection = rng.rand(*o_fn_out.shape)
t_r = tensor(random_projection) t_r = tinit(random_projection)
#random projection of o onto t_r #random projection of o onto t_r
cost = sum(t_r * o.outputs[0]) cost = sum(t_r * o.outputs[0])
...@@ -35,9 +34,15 @@ def verify_grad(testcase, op_cls, pt_list, n_tests=1, rng=numpy.random, eps=0.00 ...@@ -35,9 +34,15 @@ def verify_grad(testcase, op_cls, pt_list, n_tests=1, rng=numpy.random, eps=0.00
num_grad = gradient.numeric_grad(cost_fn, pt) num_grad = gradient.numeric_grad(cost_fn, pt)
grad_fn = Function(tensor_pt, gradient.grad(cost, tensor_pt)) symbolic_grad = gradient.grad(cost, tensor_pt,tinit(1.0,name='g_cost'))
if 0:
print '-------'
print '----------'
for op in gof.graph.io_toposort(tensor_pt, symbolic_grad):
print op
grad_fn = Function(tensor_pt, symbolic_grad)
analytic_grad = grad_fn() analytic_grad = grad_fn(*pt)
if not isinstance(analytic_grad, (list, tuple)): if not isinstance(analytic_grad, (list, tuple)):
analytic_grad = [analytic_grad] analytic_grad = [analytic_grad]
...@@ -56,7 +61,7 @@ def check_eq2(self, inputs, output, args_in, arg_out): ...@@ -56,7 +61,7 @@ def check_eq2(self, inputs, output, args_in, arg_out):
val = fn(*args_in) val = fn(*args_in)
self.failUnless( numpy.all(val == arg_out), (val, arg_out)) self.failUnless( numpy.all(val == arg_out), (val, arg_out))
def check_eq2(self, inputs, output, args_in, arg_out): def check_eq2_c(self, inputs, output, args_in, arg_out):
fn = Function(inputs, [output], linker_cls = gof.CLinker) fn = Function(inputs, [output], linker_cls = gof.CLinker)
val = fn(*args_in) val = fn(*args_in)
self.failUnless( numpy.all(val == arg_out), (val, arg_out)) self.failUnless( numpy.all(val == arg_out), (val, arg_out))
...@@ -64,20 +69,21 @@ def check_eq2(self, inputs, output, args_in, arg_out): ...@@ -64,20 +69,21 @@ def check_eq2(self, inputs, output, args_in, arg_out):
class T_abs(unittest.TestCase): class T_abs(unittest.TestCase):
def test_impl(self): def test_impl(self):
t = tensor(1.0) t = tinit(1.0)
check_eq(self, t, abs(t), 1.0, 1.0) check_eq(self, t, abs(t), 1.0, 1.0)
check_eq(self, t, abs(t), -1.0, 1.0) check_eq(self, t, abs(t), -1.0, 1.0)
for shape in (2,), (3,4): for shape in (2,), (3,4):
t = tensor(numpy.ones(shape)) t = tinit(numpy.ones(shape))
d = numpy.random.rand(*shape)*2-1.0 d = numpy.random.rand(*shape)*2-1.0
check_eq(self, t, abs(t), d, abs(d)) check_eq(self, t, abs(t), d, abs(d))
check_eq(self, t, abs(t), -d, abs(-d)) check_eq(self, t, abs(t), -d, abs(-d))
def test_grad(self): def test_grad(self):
verify_grad(self, Abs, [[numpy.ones(())], [numpy.ones(3)]]) verify_grad(self, Abs, [numpy.ones(())])
verify_grad(self, Abs, [numpy.ones(3)])
class AbsBadGrad(T._Elemwise): class AbsBadGrad(tensor._Elemwise):
def impl(self, x): def impl(self, x):
return numpy.abs(x) return numpy.abs(x)
def grad(self, x, gz): def grad(self, x, gz):
...@@ -87,52 +93,137 @@ class T_abs(unittest.TestCase): ...@@ -87,52 +93,137 @@ class T_abs(unittest.TestCase):
def test_badgrad(self): def test_badgrad(self):
try: try:
verify_grad(self, T_abs.AbsBadGrad, [[numpy.ones(())], [numpy.ones(3)]]) verify_grad(self, T_abs.AbsBadGrad, [numpy.ones(())])
self.fail() self.fail()
except Exception, e: except Exception, e:
self.failUnless(str(e) == verify_grad.E_grad, str(e)) self.failUnless(str(e) == verify_grad.E_grad, str(e))
class T_fill(unittest.TestCase):
def test0(self):
t = fill(numpy.asarray([1,2,3]), 9.0)
self.failUnless(t.owner.__class__ == Fill)
o = t.owner
self.failUnless(o.inputs[0].broadcastable == (0,))
self.failUnless(o.inputs[0].dtype[0:3] == 'int')
self.failUnless(o.inputs[1].broadcastable == ())
self.failUnless(o.inputs[1].dtype[0:3] == 'flo')
self.failUnless(o.outputs[0].broadcastable == (0,))
self.failUnless(o.outputs[0].dtype[0:3] == 'flo')
class T_sum(unittest.TestCase): class T_sum(unittest.TestCase):
def test_impl(self): def test_impl(self):
t = tensor(0.0) t = tinit(0.0)
check_eq(self, t, Sum(t).out, 1.0, 1.0) check_eq(self, t, Sum(t).out, 1.0, 1.0)
check_eq(self, t, Sum(t).out, -1.0, -1.0) check_eq(self, t, Sum(t).out, -1.0, -1.0)
t = tensor([0.0, 0.0]) t = tinit([0.0, 0.0])
d = numpy.asarray([-0.4, 1.2]) d = numpy.asarray([-0.4, 1.2])
check_eq(self, t, Sum(t).out, d, numpy.sum(d)) check_eq(self, t, Sum(t).out, d, numpy.sum(d))
check_eq(self, t, Sum(t).out, -d, -numpy.sum(d)) check_eq(self, t, Sum(t).out, -d, -numpy.sum(d))
class T_mul(unittest.TestCase): class T_mul(unittest.TestCase):
def setUp(self):
numpy.random.seed([1,2,3,4])
def test_elemwise(self): def test_elemwise(self):
a = tensor(0.0) a = tinit(0.0)
b = tensor(0.0) b = tinit(0.0)
check_eq2(self, [a,b], mul_elemwise(a,b), [3.0, 4.0], 12.0) check_eq2(self, [a,b], mul_elemwise(a,b), [3.0, 4.0], 12.0)
check_eq2(self, [a,b], mul_elemwise(a,a), [-1.0,2.0], 1.0) check_eq2(self, [a,b], mul_elemwise(b,a), [-1.0,2.0], -2.0)
check_eq2(self, [a,b], mul(a,b), [3.0, 4.0], 12.0) self.failUnless(isinstance(mul(a,b).owner, Scale))
check_eq2(self, [a,b], mul(a,a), [-1.0,2.0], 1.0)
a = tensor(numpy.ones(2)) a = tinit(numpy.ones(2))
b = tensor(numpy.ones(2)) b = tinit(numpy.ones(2))
aa = numpy.asarray([-0.5, 4.0]) aa = numpy.asarray([-0.5, 4.0])
bb = numpy.asarray([-0.5, 2.0]) bb = numpy.asarray([-0.5, 2.0])
check_eq2(self, [a,b], mul_elemwise(a,b), [aa,bb], numpy.asarray([0.25, 8.0])) check_eq2(self, [a,b], mul_elemwise(a,b), [aa,bb], numpy.asarray([0.25, 8.0]))
check_eq2(self, [a,b], mul_elemwise(a,b), [aa,aa], numpy.asarray([0.25, 16.0])) check_eq2(self, [a,b], mul_elemwise(a,b), [bb,aa], numpy.asarray([0.25, 8.0]))
check_eq2(self, [a,b], mul(a,b), [aa,bb], numpy.asarray([0.25, 8.0])) self.failUnless(isinstance(mul(a,b).owner, MulElemwise))
check_eq2(self, [a,b], mul(a,b), [aa,aa], numpy.asarray([0.25, 16.0]))
def test_scalar(self):
r = numpy.random.rand(2,3)
a = tinit(r)
b = tinit(2.0)
check_eq2(self, [a,b], scale(a,b), [r, 2.0], r*2.0)
check_eq2(self, [a,b], scale(a,b), [r, 4.0], r*4.0)
self.failUnless(b.data == 2.0)
def test_operator(self):
a = tinit([1,1])
aa = tinit([1,1])
b = tinit(4.0)
self.failUnless(isinstance((a*b).owner, Scale))
self.failUnless(isinstance((b*a).owner, Scale))
self.failUnless(isinstance((a*aa).owner, MulElemwise))
self.failUnless(isinstance((aa*a).owner, MulElemwise))
def test_wrong_shapes(self): def test_wrong_shapes(self):
a = tensor(numpy.ones(3)) a = tinit(numpy.ones(3))
b = tensor(numpy.ones(4)) b = tinit(numpy.ones(4))
try: try:
check_eq2(self, [a,b], MulElemwise(a,b).out, check_eq2(self, [a,b], MulElemwise(a,b).out,
[numpy.ones(3), numpy.ones(4)], 1.0) [numpy.ones(3), numpy.ones(4)], 1.0)
self.fail() self.fail()
except ValueError, e: except ValueError, e:
self.failUnless(e is T._assert_same_shapes.E_shape) self.failUnless(e is tensor._assert_same_shapes.E_shape)
class T_div(unittest.TestCase):
def setUp(self):
numpy.random.seed(9999)
def test_grad_e(self):
verify_grad(self, DivElemwise, [numpy.ones(()), numpy.ones(())])
verify_grad(self, DivElemwise, [numpy.random.rand(3), numpy.ones(3)])
verify_grad(self, DivElemwise, [numpy.random.rand(3,5), numpy.random.rand(3,5)+0.1])
def test_grad_sl(self):
verify_grad(self, DivElemwise, [numpy.ones(()), numpy.ones(())])
verify_grad(self, DivElemwise, [numpy.random.rand(3), numpy.ones(3)])
verify_grad(self, DivElemwise, [numpy.random.rand(3,5), numpy.random.rand(3,5)+0.1])
class T_pow(unittest.TestCase):
def setUp(self):
numpy.random.seed(9999)
def test_elemwise(self):
verify_grad(self, DivElemwise, [numpy.random.rand(3,4), numpy.random.rand(3,4)+0.1])
verify_grad(self, PowElemwise, [numpy.random.rand(3,4), numpy.random.rand(3,4)])
def test_scalar_l(self):
verify_grad(self, PowScalarL, [numpy.random.rand(3), 3.0])
def test_scalar_r(self):
verify_grad(self, PowScalarR, [numpy.random.rand(3), 3.0])
class _testCase_matinv:#(unittest.TestCase):
def setUp(self):
numpy.random.seed(1)
def mat_recip(self,dim):
# symbolic program
a = Tensor('float64', [0,0], name='a')
b = Tensor('float64', [0,0], name='b')
ab = a*b
diff = ab - tinit(numpy.ones((dim,dim)))
ssdiff = sum((diff**2.0))
g_b = gradient.grad(ssdiff, b, tinit(numpy.ones(1),name='g_cost'))
# compilation to function
fn = Function([a,b], [ssdiff,g_b])
# use the function
w = numpy.random.rand(dim,dim)
wi = numpy.random.rand(dim,dim)
for i in xrange(300):
ssd, gw = fn(w,wi)
#print ssd
if i == 0:
str0 = str(ssd)
wi -= 0.4 * gw
return str0, str(ssd)
def test_recip(self):
"""Matrix reciprocal by gradient descent"""
self.assertEqual(('2.67327580893', '0.000438649434819'), self.mat_recip(3))
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
...@@ -55,7 +55,10 @@ class BaseTensor(ResultBase): ...@@ -55,7 +55,10 @@ class BaseTensor(ResultBase):
if not isinstance(arr, numpy.ndarray): if not isinstance(arr, numpy.ndarray):
arr = numpy.asarray(arr, dtype = self.dtype) arr = numpy.asarray(arr, dtype = self.dtype)
if len(self.broadcastable) != len(arr.shape): if len(self.broadcastable) != len(arr.shape):
raise ValueError(BaseTensor.filter.E_rank) raise ValueError(BaseTensor.filter.E_rank,
self.broadcastable,
arr.shape,
self.owner)
for b, s in zip(self.broadcastable, arr.shape): for b, s in zip(self.broadcastable, arr.shape):
if b and (s != 1): if b and (s != 1):
raise ValueError(BaseTensor.filter.E_shape) raise ValueError(BaseTensor.filter.E_shape)
......
...@@ -71,7 +71,7 @@ class Function: ...@@ -71,7 +71,7 @@ class Function:
#print 'orphans', orphans #print 'orphans', orphans
#print 'ops', gof.graph.ops(inputs, outputs) #print 'ops', gof.graph.ops(inputs, outputs)
env = gof.env.Env(inputs, outputs, features, consistency_check = True) env = gof.env.Env(inputs, outputs, features + [gof.EquivTool], consistency_check = True)
#print 'orphans in env', env.orphans() #print 'orphans in env', env.orphans()
...@@ -79,7 +79,7 @@ class Function: ...@@ -79,7 +79,7 @@ class Function:
#print 'orphans after clone', env.orphans() #print 'orphans after clone', env.orphans()
for d, o in zip(orphan_data, env.orphans()): for d, o in zip(orphan_data, [env.equiv(orphan) for orphan in orphans]):
#print 'assigning orphan value', d #print 'assigning orphan value', d
o.data = d o.data = d
......
...@@ -95,13 +95,13 @@ def grad_sources_inputs(sources, graph_inputs): ...@@ -95,13 +95,13 @@ def grad_sources_inputs(sources, graph_inputs):
gmap[r] = g_r gmap[r] = g_r
return gmap return gmap
def grad(cost, param): def grad(cost, param, g_cost=1.0):
"""Return symbolic expression of gradient of <cost> wrt <param>. """Return symbolic expression of gradient of <cost> wrt <param>.
If <param> is a list, then return a list containing the gradient of cost wrt If <param> is a list, then return a list containing the gradient of cost wrt
each element of the list. each element of the list.
""" """
inputs = gof.graph.inputs([cost]) inputs = gof.graph.inputs([cost])
gmap = grad_sources_inputs([(cost, 1.0)], inputs) gmap = grad_sources_inputs([(cost, g_cost)], inputs)
if isinstance(param, list): if isinstance(param, list):
return [gmap.get(p, None) for p in param] return [gmap.get(p, None) for p in param]
else: else:
...@@ -136,9 +136,9 @@ class numeric_grad: ...@@ -136,9 +136,9 @@ class numeric_grad:
f_eps = f(*pt) f_eps = f(*pt)
gf[idx][i] = numpy.asarray((f_eps - f_pt)/eps) gf[idx][i] = numpy.asarray((f_eps - f_pt)/eps)
pt[idx][i] = orig pt[idx][i] = orig
elif len(args[idx].shape) == 2: elif len(pt[idx].shape) == 2:
for i in xrange(pt[idx].shape[0]): for i in xrange(pt[idx].shape[0]):
for j in xrange(args[idx].shape[1]): for j in xrange(pt[idx].shape[1]):
orig = pt[idx][i,j] orig = pt[idx][i,j]
pt[idx][i,j] = pt[idx][i,j] + eps pt[idx][i,j] = pt[idx][i,j] + eps
f_eps = f(*pt) f_eps = f(*pt)
......
差异被折叠。
...@@ -83,15 +83,6 @@ class InvElemwiseInplace(InvElemwise.inplace_version()): ...@@ -83,15 +83,6 @@ class InvElemwiseInplace(InvElemwise.inplace_version()):
return x return x
class Exp(Elemwise):
def impl(self, x): return numpy.exp(x)
def grad(self, x, gz): return gz * exp(x)
def c_foreach(self, (x_i, ), (z_i, )): return "z_i = exp(x_i);"
class Log(Elemwise):
def impl(self, x): return numpy.log(x)
def grad(self, x, gz): return gz / x
def c_foreach(self, (x_i, ), (z_i, )): return "z_i = log(x_i);"
class Log2(Elemwise): class Log2(Elemwise):
def impl(self, x): return numpy.log2(x) def impl(self, x): return numpy.log2(x)
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论