woo

上级 14753530
syntax: glob
*.pyc
*.o
*.so
*~
\#*\#
import gof
import opt
#prog(inputs, outputs)
#single(*outputs)
#multi(*output_lists)
import core
def to_func(inputs, outputs):
p = prog(inputs, outputs)
print p.env
def f(*args):
for input, value in zip(inputs, args):
p[input] = value
outputs = p()
if len(outputs) == 1:
return outputs[0]
else:
return outputs
return f
# def prog(inputs, outputs):
# outputs = gof.ext.mark_outputs_as_destroyed(outputs)
# program = gof.Prog(inputs, outputs, opt.optimizer, gof.link.ThunkLinker(), [gof.features.PrintListener])
# for orphan in program.env.orphans():
# if orphan.storage is core.UNCOMPUTED:
# raise Exception("Your program depends on a few uncomputed values.")
# return program
class prog(gof.Prog):
def __init__(self, inputs, outputs):
# core.build_mode()
outputs = gof.ext.mark_outputs_as_destroyed(outputs)
gof.Prog.__init__(self,
inputs,
outputs,
opt.optimizer,
gof.link.thunk_linker,
[])
# core.pop_mode()
def __call__(self, check_uncomputed = True):
if check_uncomputed:
for input in self.env.inputs:
if input.data is core.UNCOMPUTED:
raise Exception("You must provide a value for input %s!" % input)
for orphan in self.env.orphans():
if orphan.data is core.UNCOMPUTED:
raise Exception("Orphan %s is uncomputed but needed to calculate the function. " % input + \
"Try calling prog.compute_orphans() or set it manually.")
return gof.Prog.__call__(self)
def compute_orphans(self):
raise NotImplementedError
def single(*outputs):
return prog(gof.graph.inputs(outputs), outputs)
...@@ -9,26 +9,28 @@ from copy import copy as pycopy ...@@ -9,26 +9,28 @@ from copy import copy as pycopy
_mode = ['eval'] _mode = ['eval']
def set_mode(mode): # def set_mode(mode):
_mode.append(mode) # _mode.append(mode)
def current_mode(): # def current_mode():
return _mode # return _mode[-1]
def build_mode(): # def build_mode():
set_mode('build') # set_mode('build')
def eval_mode(): # def eval_mode():
set_mode('eval') # set_mode('eval')
def pop_mode(): # def pop_mode():
if len(_mode) == 1: # if len(_mode) == 1:
raise Exception("There's only one mode left on the stack.") # raise Exception("There's only one mode left on the stack.")
else: # else:
_mode.pop() # _mode.pop()
# def end_eval():
# set_mode('eval')
def end_eval(): current_mode, set_mode, build_mode, eval_mode, pop_mode = gof.current_mode, gof.set_mode, gof.build_mode, gof.eval_mode, gof.pop_mode
set_mode('eval')
def build(f, *args, **kwargs): def build(f, *args, **kwargs):
build_mode() build_mode()
...@@ -37,23 +39,27 @@ def build(f, *args, **kwargs): ...@@ -37,23 +39,27 @@ def build(f, *args, **kwargs):
return r return r
class Keyword: # class Keyword:
def __init__(self, name, nonzero=True): # def __init__(self, name, nonzero=True):
self.name = name # self.name = name
self.nonzero = nonzero # self.nonzero = nonzero
def __nonzero__(self): # def __nonzero__(self):
return self.nonzero # return self.nonzero
def __str__(self): # def __str__(self):
return "<%s>" % self.name # return "<%s>" % self.name
def __repr__(self): # def __repr__(self):
return str(self) # return str(self)
UNCOMPUTED = gof.UNCOMPUTED
UNDEFINED = gof.UNDEFINED
# UNCOMPUTED = Keyword("UNCOMPUTED", False)
# UNDEFINED = Keyword("UNDEFINED", False)
UNCOMPUTED = Keyword("UNCOMPUTED", False)
UNDEFINED = Keyword("UNDEFINED", False)
class Proxy(object): class Proxy(object):
...@@ -79,62 +85,63 @@ class Proxy(object): ...@@ -79,62 +85,63 @@ class Proxy(object):
delattr(self._obj, attr) delattr(self._obj, attr)
class IViewer(gof.ext.Viewer): # class IViewer(gof.ext.Viewer):
_v_map = {} # _v_map = {}
def view_map(self): # def view_map(self):
rval = {} # rval = {}
for output, inputs in self._v_map.items(): # for output, inputs in self._v_map.items():
if isinstance(inputs, (list, tuple)): # if isinstance(inputs, (list, tuple)):
rval[self.outputs[output]] = [self.inputs[i] for i in inputs] # rval[self.outputs[output]] = [self.inputs[i] for i in inputs]
else: # else:
rval[self.outputs[output]] = self.inputs[inputs] # rval[self.outputs[output]] = self.inputs[inputs]
return rval # return rval
class IDestroyer(gof.ext.Destroyer): # class IDestroyer(gof.ext.Destroyer):
_d_map = {} # _d_map = {}
def destroy_map(self): # def destroy_map(self):
rval = {} # rval = {}
for output, inputs in self._d_map.items(): # for output, inputs in self._d_map.items():
if isinstance(inputs, (list, tuple)): # if isinstance(inputs, (list, tuple)):
rval[self.outputs[output]] = [self.inputs[i] for i in inputs] # rval[self.outputs[output]] = [self.inputs[i] for i in inputs]
else: # else:
rval[self.outputs[output]] = self.inputs[inputs] # rval[self.outputs[output]] = self.inputs[inputs]
return rval # return rval
class PythonR(gof.HolderResult): # class PythonR(gof.HolderResult):
def __init__(self, a = None): # def __init__(self, a = None):
if a is None: # if a is None:
self.storage = UNCOMPUTED # self.storage = UNCOMPUTED
else: # else:
self.storage = a # self.storage = a
def set_value(self, value): # def set_value(self, value):
self.storage = value # self.storage = value
def __str__(self): # def __str__(self):
return str(self.storage) # return str(self.storage)
def __repr__(self): # def __repr__(self):
return repr(self.storage) # return repr(self.storage)
# gof.PythonR = PythonR
class NumpyR(gof.HolderResult): class NumpyR(gof.PythonR):
def __init__(self, a = None): # def __init__(self, a = None):
self.set_value(a) # self.set_value(a)
def set_value(self, value): def set_value(self, value):
if value is None or value is UNCOMPUTED: if value is None or value is UNCOMPUTED:
self.storage = UNCOMPUTED self.data = UNCOMPUTED
elif isinstance(value, numpy.ndarray): elif isinstance(value, numpy.ndarray):
self.storage = value self.data = value
else: else:
self.storage = numpy.array(value) self.data = numpy.array(value)
def __add__(self, y): def __add__(self, y):
return add(self, y) return add(self, y)
...@@ -196,12 +203,7 @@ class NumpyR(gof.HolderResult): ...@@ -196,12 +203,7 @@ class NumpyR(gof.HolderResult):
def __copy__(self): def __copy__(self):
return array_copy(self) return array_copy(self)
def __str__(self):
return str(self.storage)
def __repr__(self):
return repr(self.storage)
#[iadd(iadd(iadd(iadd(<UNCOMPUTED>, itwice(<UNCOMPUTED>)), <UNCOMPUTED>), 1.0), dot(<UNCOMPUTED>, <UNCOMPUTED>))] #[iadd(iadd(iadd(iadd(<UNCOMPUTED>, itwice(<UNCOMPUTED>)), <UNCOMPUTED>), 1.0), dot(<UNCOMPUTED>, <UNCOMPUTED>))]
#[iadd(iadd(iadd(iadd(<UNCOMPUTED>, itwice(<UNCOMPUTED>)), <UNCOMPUTED>), 1.0), dot(<UNCOMPUTED>, <UNCOMPUTED>))] #[iadd(iadd(iadd(iadd(<UNCOMPUTED>, itwice(<UNCOMPUTED>)), <UNCOMPUTED>), 1.0), dot(<UNCOMPUTED>, <UNCOMPUTED>))]
...@@ -220,79 +222,79 @@ def wrap(x): ...@@ -220,79 +222,79 @@ def wrap(x):
if isinstance(x, NumpyR): if isinstance(x, NumpyR):
return x return x
elif isinstance(x, PythonR): elif isinstance(x, gof.PythonR):
return x return x
elif isinstance(x, NumpyOp): elif isinstance(x, omega_op):
return x.out return x.out
elif isinstance(x, Proxy): elif isinstance(x, Proxy):
return wrap(x._obj) return wrap(x._obj)
elif isinstance(x, numpy.ndarray): elif isinstance(x, numpy.ndarray):
return NumpyR(x) return NumpyR(x)
else: else:
return PythonR(x) return gof.PythonR(x)
# else: # else:
# raise TypeError("%s cannot be converted to or encapsulated in a NumpyR instance." % x) # raise TypeError("%s cannot be converted to or encapsulated in a NumpyR instance." % x)
class NumpyOp(gof.Op, gof.ext.BuildableFromInputs): # class NumpyOp(gof.Op, gof.ext.BuildableFromInputs):
nout = 1 # nout = 1
def __init__(self, *args): # def __init__(self, *args):
inputs = [wrap(arg) for arg in args] # inputs = [wrap(arg) for arg in args]
outputs = [NumpyR() for i in xrange(self.nout)] # outputs = [NumpyR() for i in xrange(self.nout)]
gof.Op.__init__(self, inputs, outputs) # gof.Op.__init__(self, inputs, outputs)
@classmethod # @classmethod
def from_inputs(cls, *inputs): # def from_inputs(cls, *inputs):
return cls(*inputs) # return cls(*inputs)
def gen_outputs(self): # def gen_outputs(self):
return [NumpyR() for i in xrange(self.nout)] # return [NumpyR() for i in xrange(self.nout)]
class wrapper: # class wrapper:
__slots__ = ['f', 'opclass'] # __slots__ = ['f', 'opclass']
def __init__(self, name, f, grad, vmap = None, dmap = None, optype = NumpyOp): # def __init__(self, name, f, grad, vmap = None, dmap = None, optype = NumpyOp):
self.f = f # self.f = f
if not callable(f): # if not callable(f):
raise TypeError("Can only wrap a callable.") # raise TypeError("Can only wrap a callable.")
bases = [optype] # bases = [optype]
if vmap: bases.append(IViewer) # if vmap: bases.append(IViewer)
if dmap: bases.append(IDestroyer) # if dmap: bases.append(IDestroyer)
Wrapper = type(name, tuple(bases), {}) # Wrapper = type(name, tuple(bases), {})
if vmap: Wrapper._v_map = vmap # if vmap: Wrapper._v_map = vmap
if dmap: Wrapper._d_map = dmap # if dmap: Wrapper._d_map = dmap
def thunk(self): # def thunk(self):
def ret(): # def ret():
self.outputs[0].set_value(f(*[input.storage for input in self.inputs])) # self.outputs[0].set_value(f(*[input.storage for input in self.inputs]))
return ret # return ret
Wrapper.thunk = thunk # Wrapper.thunk = thunk
if grad is UNDEFINED: # if grad is UNDEFINED:
grad = lambda *_: UNDEFINED # grad = lambda *_: UNDEFINED
Wrapper.grad = staticmethod(grad) # Wrapper.grad = staticmethod(grad)
self.opclass = Wrapper # self.opclass = Wrapper
def __call__(self, *args): # def __call__(self, *args):
op = self.opclass(*args) # op = self.opclass(*args)
if current_mode() == 'eval': # if current_mode() == 'eval':
op.thunk()() # op.thunk()()
outputs = pycopy(op.outputs) # outputs = pycopy(op.outputs)
# outputs = [Proxy(output) for output in op.outputs] # # outputs = [Proxy(output) for output in op.outputs]
if op.nout == 1: # if op.nout == 1:
return outputs[0] # return outputs[0]
else: # else:
return outputs # return outputs
# def wrap_producer(f): # def wrap_producer(f):
...@@ -304,19 +306,11 @@ class wrapper: ...@@ -304,19 +306,11 @@ class wrapper:
# return ret # return ret
def wrap_producer(f): # def wrap_producer(f):
wrapped_f = wrapper(f.__name__, f, UNDEFINED) # wrapped_f = wrapper(f.__name__, f, UNDEFINED)
def ret(dim, dtype = 'float', order = 'C'): # def ret(dim, dtype = 'float', order = 'C'):
return wrapped_f(dim, dtype, order) # return wrapped_f(dim, dtype, order)
return ret # return ret
ndarray = wrap_producer(numpy.ndarray)
array = wrap_producer(numpy.array)
zeros = wrap_producer(numpy.zeros)
ones = wrap_producer(numpy.ones)
inplace = gof.ext.Destroyer inplace = gof.ext.Destroyer
...@@ -331,59 +325,60 @@ class omega_op_metaclass(type): ...@@ -331,59 +325,60 @@ class omega_op_metaclass(type):
class omega_op(gof.Op, gof.ext.BuildableFromInputs): class omega_op(gof.PythonOp): #(gof.Op, gof.ext.BuildableFromInputs):
__metaclass__ = omega_op_metaclass ## __metaclass__ = omega_op_metaclass
nout = 1 ## nout = 1
@classmethod @staticmethod
def __clsinit__(cls, name, bases, dct): def __clsinit__(cls, name, bases, dct):
# make grad and impl static methods # make grad a static method
grad = cls.grad grad = cls.grad
if hasattr(grad, 'im_func'): if hasattr(grad, 'im_func'):
grad = grad.im_func grad = grad.im_func
impl = cls.impl
if hasattr(cls.impl, 'im_func'):
impl = impl.im_func
cls.grad = staticmethod(grad) cls.grad = staticmethod(grad)
cls.impl = staticmethod(impl)
# make impl a static method
gof.PythonOp.__clsinit__(cls, name, bases, dct)
def __new__(cls, *inputs): def __new__(cls, *inputs):
op = gof.Op.__new__(cls) inputs = [wrap(input) for input in inputs]
op.__init__(*[wrap(input) for input in inputs]) return gof.PythonOp.__new__(cls, *inputs)
if current_mode() == 'eval': # op = gof.Op.__new__(cls)
op.thunk()() # op.__init__(*[wrap(input) for input in inputs])
if op.nout == 1: # if cls.current_mode() == 'eval':
return op.out # op.thunk()()
else: # if op.nout == 1:
return op.outputs # return op.out
# else:
# return op.outputs
def __init__(self, *inputs): # def __init__(self, *inputs):
for input in inputs: # for input in inputs:
assert isinstance(input, gof.HolderResult) # assert isinstance(input, gof.HolderResult)
gof.Op.__init__(self, inputs, self.gen_outputs()) # gof.Op.__init__(self, inputs, self.gen_outputs())
@classmethod # @classmethod
def from_inputs(cls, *inputs): # def from_inputs(cls, *inputs):
build_mode() # build_mode()
r = cls(*inputs) # r = cls(*inputs)
pop_mode() # pop_mode()
return r.owner # return r.owner
def gen_outputs(self): def gen_outputs(self):
return [NumpyR() for i in xrange(self.nout)] return [NumpyR() for i in xrange(self.nout)]
def thunk(self): # def thunk(self):
def ret(): # def ret():
results = self.impl(*[input.storage for input in self.inputs]) # results = self.impl(*[input.storage for input in self.inputs])
if self.nout == 1: # if self.nout == 1:
self.out.set_value(results) # self.out.set_value(results)
else: # else:
assert self.nout == len(results) # assert self.nout == len(results)
for result, output in zip(results, self.outputs): # for result, output in zip(results, self.outputs):
output.set_value(result) # output.set_value(result)
return ret # return ret
def update_gradient(self, grad_d): def update_gradient(self, grad_d):
inputgs = self.grad(*(self.inputs + [grad_d[output] for output in self.outputs])) inputgs = self.grad(*(self.inputs + [grad_d[output] for output in self.outputs]))
...@@ -395,8 +390,22 @@ class omega_op(gof.Op, gof.ext.BuildableFromInputs): ...@@ -395,8 +390,22 @@ class omega_op(gof.Op, gof.ext.BuildableFromInputs):
def grad(*args): def grad(*args):
return UNDEFINED return UNDEFINED
def impl(*args): # def impl(*args):
raise NotImplementedError("This op has no implementation.") # raise NotImplementedError("This op has no implementation.")
def wrap_producer(f):
class producer(omega_op):
impl = f
producer.__name__ = f.__name__
def ret(dim, dtype = 'float', order = 'C'):
return producer(dim, dtype, order)
return ret
ndarray = wrap_producer(numpy.ndarray)
array = wrap_producer(numpy.array)
zeros = wrap_producer(numpy.zeros)
ones = wrap_producer(numpy.ones)
...@@ -419,6 +428,7 @@ class proto_twice(omega_op): ...@@ -419,6 +428,7 @@ class proto_twice(omega_op):
class twice(proto_twice): class twice(proto_twice):
def impl(x): def impl(x):
# print x
return x + x return x + x
class itwice(proto_twice, inplace): class itwice(proto_twice, inplace):
...@@ -443,88 +453,90 @@ class isub(proto_sub, inplace): ...@@ -443,88 +453,90 @@ class isub(proto_sub, inplace):
## Element-wise multiplication ## ## Element-wise multiplication ##
def mul_grad(x, y, gz): class proto_mul(omega_op):
return mul(y, gz), mul(x, gz) def grad(x, y, gz):
return mul(y, gz), mul(x, gz)
mul = wrapper("mul", class mul(proto_mul):
numpy.ndarray.__mul__, impl = numpy.ndarray.__mul__
mul_grad)
imul = wrapper("imul", class imul(proto_mul, inplace):
numpy.ndarray.__imul__, impl = numpy.ndarray.__imul__
mul_grad,
dmap = {0: 0})
def sqr_grad(x, gz):
return scal(mul(x, gz), 2.0)
sqr = wrapper("sqr", class proto_sqr(omega_op):
lambda x: numpy.multiply(x, x), def grad(x, gz):
sqr_grad) return scal(mul(x, gz), 2.0)
isqr = wrapper("isqr", class sqr(proto_sqr):
lambda x: x.__imul__(x), impl = lambda x: numpy.multiply(x, x)
sqr_grad,
dmap = {0: 0})
def sqrt_grad(x, gz): class isqr(proto_sqr, inplace):
return scal(div(gz, sqrt(x)), 0.5) impl = lambda x: x.__imul__(x),
sqrt = wrapper("sqrt",
lambda x: numpy.sqrt(x),
sqrt_grad)
isqrt = wrapper("isqrt", class proto_sqrt(omega_op):
lambda x: x.__ipow__(0.5), def grad(x, gz):
sqrt_grad, return scal(div(gz, sqrt(x)), 0.5)
dmap = {0: 0})
class sqrt(proto_sqrt):
impl = numpy.sqrt
class isqrt(proto_sqrt, inplace):
impl = lambda x: x.__ipow__(0.5)
## Exponentiation ##
class exp(omega_op):
impl = numpy.exp
## Element-wise division ## # ## Element-wise division ##
def div_grad(x, y, gz): # def div_grad(x, y, gz):
return div(gz, y), -div(mul(x, gz), sqr(y)) # return div(gz, y), -div(mul(x, gz), sqr(y))
div = wrapper("div", # div = wrapper("div",
numpy.ndarray.__div__, # numpy.ndarray.__div__,
div_grad) # div_grad)
idiv = wrapper("idiv", # idiv = wrapper("idiv",
numpy.ndarray.__idiv__, # numpy.ndarray.__idiv__,
div_grad, # div_grad,
dmap = {0: 0}) # dmap = {0: 0})
## Scaling ## # ## Scaling ##
def scal_grad(x, a, gz): # def scal_grad(x, a, gz):
return scal(a, gz), sum(mul(x, gz)) # return scal(a, gz), sum(mul(x, gz))
scal = wrapper("scal", # scal = wrapper("scal",
numpy.ndarray.__mul__, # numpy.ndarray.__mul__,
scal_grad) # scal_grad)
iscal = wrapper("iscal", # iscal = wrapper("iscal",
numpy.ndarray.__imul__, # numpy.ndarray.__imul__,
scal_grad, # scal_grad,
dmap = {0: 0}) # dmap = {0: 0})
neg = wrapper("neg", # neg = wrapper("neg",
numpy.ndarray.__neg__, # numpy.ndarray.__neg__,
lambda x, gz: -gz) # lambda x, gz: -gz)
ineg = wrapper("ineg", # ineg = wrapper("ineg",
lambda x: x.__imul__(-1), # lambda x: x.__imul__(-1),
lambda x, gz: -gz, # lambda x, gz: -gz,
dmap = {0: 0}) # dmap = {0: 0})
## Dot product ## # ## Dot product ##
dot = wrapper("dot", # dot = wrapper("dot",
numpy.dot, # numpy.dot,
lambda x, y, gz: (dot(gz, transpose(y)), # lambda x, y, gz: (dot(gz, transpose(y)),
dot(transpose(x), gz))) # dot(transpose(x), gz)))
## Transposition ## ## Transposition ##
......
...@@ -3,24 +3,28 @@ from core import * ...@@ -3,24 +3,28 @@ from core import *
import gof import gof
def pattern_opt(in_pattern, out_pattern): # def pattern_opt(in_pattern, out_pattern):
def parse(x): # def parse(x):
if isinstance(x, (list, tuple)): # if isinstance(x, (list, tuple)):
return [parse(y) for y in x] # return [parse(y) for y in x]
elif isinstance(x, wrapper): # elif isinstance(x, wrapper):
return x.opclass # return x.opclass
elif isinstance(x, str) or (hasattr(x, '__bases__') and issubclass(x, gof.op.Op)): # elif isinstance(x, str) or (hasattr(x, '__bases__') and issubclass(x, gof.op.Op)):
return x # return x
else: # else:
raise TypeError("Bad input type for pattern_opt.") # raise TypeError("Bad input type for pattern_opt.")
return gof.opt.PatternOptimizer(parse(in_pattern), parse(out_pattern)) # return gof.opt.PatternOptimizer(parse(in_pattern), parse(out_pattern))
def op_sub(op1, op2): # def op_sub(op1, op2):
if isinstance(op1, wrapper): # if isinstance(op1, wrapper):
op1 = op1.opclass # op1 = op1.opclass
if isinstance(op2, wrapper): # if isinstance(op2, wrapper):
op2 = op2.opclass # op2 = op2.opclass
return gof.opt.OpSubOptimizer(op1, op2) # return gof.opt.OpSubOptimizer(op1, op2)
pattern_opt = gof.opt.PatternOptimizer
op_sub = gof.opt.OpSubOptimizer
#def make_patterns(patterns): #def make_patterns(patterns):
...@@ -67,4 +71,15 @@ opts = [ ...@@ -67,4 +71,15 @@ opts = [
export_opts(opts) # publish the optimizations performed under individual names export_opts(opts) # publish the optimizations performed under individual names
optimizer = gof.opt.MergeOptMerge(gof.opt.SeqOptimizer([opt for name, opt in opts])) # class AAA(gof.opt.Optimizer):
# def __init__(self, opt):
# self.opt = opt
# def optimize(self, env):
# build_mode()
# self.opt.optimize(env)
# pop_mode()
optimizer = gof.lib.PythonOpt(gof.opt.MergeOptMerge(gof.opt.SeqOptimizer([opt for name, opt in opts])))
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论