提交 2d2e548c authored 作者: Olivier Delalleau's avatar Olivier Delalleau

Merged

...@@ -64,7 +64,7 @@ def get_persistent_module_cache(): ...@@ -64,7 +64,7 @@ def get_persistent_module_cache():
if _persistent_module_cache is None: if _persistent_module_cache is None:
_persistent_module_cache = CallCache(os.path.join(config.compiledir, 'persistent_cache')) _persistent_module_cache = CallCache(os.path.join(config.compiledir, 'persistent_cache'))
return _persistent_module_cache return _persistent_module_cache
class CodeBlock: class CodeBlock:
"""WRITEME """WRITEME
Represents a computation unit composed of declare, behavior, and cleanup. Represents a computation unit composed of declare, behavior, and cleanup.
...@@ -511,16 +511,24 @@ class CLinker(link.Linker): ...@@ -511,16 +511,24 @@ class CLinker(link.Linker):
op = node.op op = node.op
# type-specific support code # type-specific support code
try: c_support_code_apply.append(op.c_support_code_apply(node, name)) try:
except utils.MethodNotDefined: pass c_support_code_apply.append(op.c_support_code_apply(node, name))
except utils.MethodNotDefined:
pass
else:
# The following will be executed if the "try" block succeeds
assert isinstance(c_support_code_apply[-1], str), (
str(node.op)+" didn't returned a string for c_support_code_apply")
# emit c_code # emit c_code
try: behavior = op.c_code(node, name, isyms, osyms, sub) try:
behavior = op.c_code(node, name, isyms, osyms, sub)
except utils.MethodNotDefined: except utils.MethodNotDefined:
raise NotImplementedError("%s cannot produce C code" % op) raise NotImplementedError("%s cannot produce C code" % op)
assert isinstance(behavior,str), str(node.op)+" didn't returned a string for c_code" assert isinstance(behavior,str), str(node.op)+" didn't returned a string for c_code"
try: cleanup = op.c_code_cleanup(node, name, isyms, osyms, sub) try:
cleanup = op.c_code_cleanup(node, name, isyms, osyms, sub)
except utils.MethodNotDefined: except utils.MethodNotDefined:
cleanup = "" cleanup = ""
...@@ -611,11 +619,11 @@ class CLinker(link.Linker): ...@@ -611,11 +619,11 @@ class CLinker(link.Linker):
except utils.MethodNotDefined: pass except utils.MethodNotDefined: pass
ret=list(set(ret))#to remove duplicate ret=list(set(ret))#to remove duplicate
for x in [y.type for y in self.variables] + [y.op for y in self.node_order]: for x in [y.type for y in self.variables] + [y.op for y in self.node_order]:
try: try:
for i in x.c_no_compile_args(): for i in x.c_no_compile_args():
try: try:
ret.remove(i) ret.remove(i)
except ValueError: except ValueError:
pass# in case the value is not there pass# in case the value is not there
except utils.MethodNotDefined: pass except utils.MethodNotDefined: pass
return ret return ret
...@@ -734,7 +742,7 @@ class CLinker(link.Linker): ...@@ -734,7 +742,7 @@ class CLinker(link.Linker):
if v in self.orphans and isinstance(v, graph.Constant): if v in self.orphans and isinstance(v, graph.Constant):
try: try:
v.type.c_literal(v.data) #constant will be inlined, no need to get v.type.c_literal(v.data) #constant will be inlined, no need to get
continue continue
except (utils.MethodNotDefined, NotImplementedError): except (utils.MethodNotDefined, NotImplementedError):
pass pass
init_tasks.append((v, 'init', id)) init_tasks.append((v, 'init', id))
...@@ -742,7 +750,7 @@ class CLinker(link.Linker): ...@@ -742,7 +750,7 @@ class CLinker(link.Linker):
id += 2 id += 2
for node in self.node_order: for node in self.node_order:
tasks.append((node, 'code', id)) tasks.append((node, 'code', id))
id += 1 id += 1
return init_tasks, tasks return init_tasks, tasks
def make_thunk(self, input_storage = None, output_storage = None): def make_thunk(self, input_storage = None, output_storage = None):
...@@ -805,7 +813,7 @@ class CLinker(link.Linker): ...@@ -805,7 +813,7 @@ class CLinker(link.Linker):
Each element identifies the type of the node input, and the nature of that input in the Each element identifies the type of the node input, and the nature of that input in the
graph. graph.
The nature of a typical variable is encoded by integer pairs ``((a,b),c)``: The nature of a typical variable is encoded by integer pairs ``((a,b),c)``:
``a`` is the topological position of the input's owner (-1 for graph inputs), ``a`` is the topological position of the input's owner (-1 for graph inputs),
``b`` is the index of the variable in the owner's output list. ``b`` is the index of the variable in the owner's output list.
``c`` is a flag indicating whether the variable is in the no_recycling set. ``c`` is a flag indicating whether the variable is in the no_recycling set.
...@@ -826,10 +834,10 @@ class CLinker(link.Linker): ...@@ -826,10 +834,10 @@ class CLinker(link.Linker):
The outputs of a node are entirely determined by the node's Op and the nature of the The outputs of a node are entirely determined by the node's Op and the nature of the
inputs, but the set of outputs that may be re-used by the computation (the elements of inputs, but the set of outputs that may be re-used by the computation (the elements of
self.no_recycling) can affect the code that is generated. self.no_recycling) can affect the code that is generated.
The format of each Op's output signature is simply a list of booleans, indicating The format of each Op's output signature is simply a list of booleans, indicating
whether each output is in the no_recycling set. whether each output is in the no_recycling set.
""" """
return self.cmodule_key_(self.env, self.no_recycling, return self.cmodule_key_(self.env, self.no_recycling,
compile_args=self.compile_args(), compile_args=self.compile_args(),
...@@ -844,7 +852,7 @@ class CLinker(link.Linker): ...@@ -844,7 +852,7 @@ class CLinker(link.Linker):
order = list(env.toposort()) order = list(env.toposort())
#set of variables that have been computed by nodes we have #set of variables that have been computed by nodes we have
# seen 'so far' in the loop below # seen 'so far' in the loop below
env_computed_set = set() env_computed_set = set()
env_inputs_dict = dict((i, (-1, pos)) for pos, i in enumerate(env.inputs)) env_inputs_dict = dict((i, (-1, pos)) for pos, i in enumerate(env.inputs))
constant_ids = dict() constant_ids = dict()
op_pos = {} # Apply -> topological position op_pos = {} # Apply -> topological position
...@@ -909,13 +917,13 @@ class CLinker(link.Linker): ...@@ -909,13 +917,13 @@ class CLinker(link.Linker):
#add the signature for this node #add the signature for this node
sig.append(( sig.append((
node.op, node.op,
tuple((i.type, in_sig(i, node_pos, ipos)) tuple((i.type, in_sig(i, node_pos, ipos))
for ipos,i in enumerate(node.inputs)), for ipos,i in enumerate(node.inputs)),
tuple(o in no_recycling for o in node.outputs))) tuple(o in no_recycling for o in node.outputs)))
if error_on_play[0]: if error_on_play[0]:
# if one of the signatures is not hashable # if one of the signatures is not hashable
# then bypass the cache mechanism and # then bypass the cache mechanism and
# compile fresh every time # compile fresh every time
return None return None
...@@ -926,8 +934,8 @@ class CLinker(link.Linker): ...@@ -926,8 +934,8 @@ class CLinker(link.Linker):
sig = tuple(sig) sig = tuple(sig)
version = tuple(version) version = tuple(version)
for v in version: for v in version:
if not v: if not v:
# one of the ops or types here is unversioned, # one of the ops or types here is unversioned,
# so this env is entirely unversioned # so this env is entirely unversioned
return ((), sig) return ((), sig)
return version, sig return version, sig
...@@ -1044,7 +1052,7 @@ class CLinker(link.Linker): ...@@ -1044,7 +1052,7 @@ class CLinker(link.Linker):
orphd = [[orphan.data] for orphan in self.orphans] orphd = [[orphan.data] for orphan in self.orphans]
ret = module.instantiate(error_storage, *(in_storage + out_storage + orphd)) ret = module.instantiate(error_storage, *(in_storage + out_storage + orphd))
return ret return ret
def instantiate_code(self, n_args): def instantiate_code(self, n_args):
...@@ -1119,8 +1127,8 @@ class OpWiseCLinker(link.LocalLinker): ...@@ -1119,8 +1127,8 @@ class OpWiseCLinker(link.LocalLinker):
__cache__ = {} __cache__ = {}
def __init__(self, def __init__(self,
fallback_on_perform = True, fallback_on_perform = True,
allow_gc = True, allow_gc = True,
nice_errors = True): nice_errors = True):
self.env = None self.env = None
...@@ -1194,7 +1202,7 @@ class OpWiseCLinker(link.LocalLinker): ...@@ -1194,7 +1202,7 @@ class OpWiseCLinker(link.LocalLinker):
raise raise
if self.allow_gc: if self.allow_gc:
post_thunk_old_storage.append([storage_map[input] post_thunk_old_storage.append([storage_map[input]
for input in node.inputs for input in node.inputs
if (input in computed) and (input not in env.outputs) and node == last_user[input]]) if (input in computed) and (input not in env.outputs) and node == last_user[input]])
...@@ -1204,9 +1212,9 @@ class OpWiseCLinker(link.LocalLinker): ...@@ -1204,9 +1212,9 @@ class OpWiseCLinker(link.LocalLinker):
else: else:
no_recycling = [storage_map[r] for r in no_recycling if r not in env.inputs] no_recycling = [storage_map[r] for r in no_recycling if r not in env.inputs]
f = link.streamline(env, thunks, order, f = link.streamline(env, thunks, order,
post_thunk_old_storage, post_thunk_old_storage,
no_recycling = no_recycling, no_recycling = no_recycling,
nice_errors = self.nice_errors) nice_errors = self.nice_errors)
f.allow_gc = self.allow_gc f.allow_gc = self.allow_gc
...@@ -1305,4 +1313,3 @@ class DualLinker(link.Linker): ...@@ -1305,4 +1313,3 @@ class DualLinker(link.Linker):
link.raise_with_op(node1) link.raise_with_op(node1)
return f, i1, o1 return f, i1, o1
...@@ -42,15 +42,15 @@ class CLinkerType(CLinkerObject): ...@@ -42,15 +42,15 @@ class CLinkerType(CLinkerObject):
:Exceptions: :Exceptions:
- `MethodNotDefined`: Subclass does not implement this method - `MethodNotDefined`: Subclass does not implement this method
""" """
raise MethodNotDefined("c_literal", type(self), self.__class__.__name__) raise MethodNotDefined("c_literal", type(self), self.__class__.__name__)
def c_declare(self, name, sub): def c_declare(self, name, sub):
"""Required: Return c code to declare variables that will be """Required: Return c code to declare variables that will be
instantiated by `c_extract`. instantiated by `c_extract`.
Example: Example:
.. code-block: python .. code-block: python
return "PyObject ** addr_of_%(name)s;" return "PyObject ** addr_of_%(name)s;"
...@@ -82,7 +82,7 @@ class CLinkerType(CLinkerObject): ...@@ -82,7 +82,7 @@ class CLinkerType(CLinkerObject):
"""Required: Return c code to initialize the variables that were declared by """Required: Return c code to initialize the variables that were declared by
self.c_declare() self.c_declare()
Example: Example:
.. code-block: python .. code-block: python
return "addr_of_%(name)s = NULL;" return "addr_of_%(name)s = NULL;"
...@@ -110,7 +110,7 @@ class CLinkerType(CLinkerObject): ...@@ -110,7 +110,7 @@ class CLinkerType(CLinkerObject):
by this function. --jpt by this function. --jpt
Example: Example:
.. code-block: python .. code-block: python
return "if (py_%(name)s == Py_None)" + \\\ return "if (py_%(name)s == Py_None)" + \\\
...@@ -133,7 +133,7 @@ class CLinkerType(CLinkerObject): ...@@ -133,7 +133,7 @@ class CLinkerType(CLinkerObject):
""" """
raise MethodNotDefined("c_extract", type(self), self.__class__.__name__) raise MethodNotDefined("c_extract", type(self), self.__class__.__name__)
def c_cleanup(self, name, sub): def c_cleanup(self, name, sub):
"""Optional: Return c code to clean up after `c_extract`. """Optional: Return c code to clean up after `c_extract`.
...@@ -206,7 +206,7 @@ class PureType(object): ...@@ -206,7 +206,7 @@ class PureType(object):
def filter(self, data, strict=False, allow_downcast=None): def filter(self, data, strict=False, allow_downcast=None):
"""Required: Return data or an appropriately wrapped/converted data. """Required: Return data or an appropriately wrapped/converted data.
Subclass implementation should raise a TypeError exception if the data is not of an Subclass implementation should raise a TypeError exception if the data is not of an
acceptable type. acceptable type.
...@@ -214,8 +214,9 @@ class PureType(object): ...@@ -214,8 +214,9 @@ class PureType(object):
data passed as an argument. If it is False, and allow_downcast data passed as an argument. If it is False, and allow_downcast
is True, filter may cast it to an appropriate type. If is True, filter may cast it to an appropriate type. If
allow_downcast is False, filter may only upcast it, not lose allow_downcast is False, filter may only upcast it, not lose
precision. If allow_downcast is None, only Python float can be precision. If allow_downcast is None, the behaviour can be
downcasted, and only to a floatX scalar. Type-dependant, but for now only Python float can be downcasted,
and only to a floatX scalar.
:Exceptions: :Exceptions:
- `MethodNotDefined`: subclass doesn't implement this function. - `MethodNotDefined`: subclass doesn't implement this function.
...@@ -230,7 +231,7 @@ class PureType(object): ...@@ -230,7 +231,7 @@ class PureType(object):
return True return True
except (TypeError, ValueError): except (TypeError, ValueError):
return False return False
def value_validity_msg(self, a): def value_validity_msg(self, a):
"""Optional: return a message explaining the output of is_valid_value""" """Optional: return a message explaining the output of is_valid_value"""
return "none" return "none"
...@@ -248,7 +249,7 @@ class PureType(object): ...@@ -248,7 +249,7 @@ class PureType(object):
def make_constant(self, value, name=None): def make_constant(self, value, name=None):
return self.Constant(type=self, data=value, name=name) return self.Constant(type=self, data=value, name=name)
def __call__(self, name = None): def __call__(self, name = None):
"""Return a new `Variable` instance of Type `self`. """Return a new `Variable` instance of Type `self`.
...@@ -330,7 +331,7 @@ class Type(object2, PureType, CLinkerType): ...@@ -330,7 +331,7 @@ class Type(object2, PureType, CLinkerType):
class SingletonType(Type): class SingletonType(Type):
"""Convenient Base class for a Type subclass with no attributes """Convenient Base class for a Type subclass with no attributes
It saves having to implement __eq__ and __hash__ It saves having to implement __eq__ and __hash__
""" """
__instance = None __instance = None
...@@ -347,13 +348,13 @@ class Generic(SingletonType): ...@@ -347,13 +348,13 @@ class Generic(SingletonType):
Represents a generic Python object. Represents a generic Python object.
This class implements the `PureType` and `CLinkerType` interfaces for generic PyObject This class implements the `PureType` and `CLinkerType` interfaces for generic PyObject
instances. instances.
EXAMPLE of what this means, or when you would use this type. EXAMPLE of what this means, or when you would use this type.
WRITEME WRITEME
""" """
def filter(self, data, strict=False, allow_downcast=None): def filter(self, data, strict=False, allow_downcast=None):
return data return data
...@@ -375,7 +376,7 @@ class Generic(SingletonType): ...@@ -375,7 +376,7 @@ class Generic(SingletonType):
Py_INCREF(py_%(name)s); Py_INCREF(py_%(name)s);
%(name)s = py_%(name)s; %(name)s = py_%(name)s;
""" % locals() """ % locals()
def c_cleanup(self, name, sub): def c_cleanup(self, name, sub):
return """ return """
Py_XDECREF(%(name)s); Py_XDECREF(%(name)s);
...@@ -390,4 +391,3 @@ class Generic(SingletonType): ...@@ -390,4 +391,3 @@ class Generic(SingletonType):
""" % locals() """ % locals()
generic = Generic() generic = Generic()
...@@ -189,7 +189,7 @@ def local_gpu_dot_to_dot22(node): ...@@ -189,7 +189,7 @@ def local_gpu_dot_to_dot22(node):
# case two: matrix X vector # case two: matrix X vector
elif _is_real_matrix(x) and _is_real_vector(y): elif _is_real_matrix(x) and _is_real_vector(y):
new_op = GpuDimShuffle((False,), [0,'x']) new_op = GpuDimShuffle((False,), [0,'x'])
shape_out = x.shape[1].dimshuffle(['x']) shape_out = x.shape[0].dimshuffle(['x'])
gpu_x = gpu_from_host(x) gpu_x = gpu_from_host(x)
gpu_y = new_op(gpu_from_host(y)) gpu_y = new_op(gpu_from_host(y))
else: else:
...@@ -207,7 +207,7 @@ def local_gpu_dot_to_dot22(node): ...@@ -207,7 +207,7 @@ def local_gpu_dot_to_dot22(node):
elif _is_real_matrix(x) and _is_real_vector(y): elif _is_real_matrix(x) and _is_real_vector(y):
new_op = GpuDimShuffle((False,), [0,'x']) new_op = GpuDimShuffle((False,), [0,'x'])
shape_out = x.shape[1].dimshuffle(['x']) shape_out = x.shape[0].dimshuffle(['x'])
gpu_x = gpu_from_host(x) gpu_x = gpu_from_host(x)
gpu_y = new_op(gpu_from_host(y)) gpu_y = new_op(gpu_from_host(y))
else: else:
......
...@@ -118,7 +118,7 @@ class CudaNdarraySharedVariable(SharedVariable, _operators): ...@@ -118,7 +118,7 @@ class CudaNdarraySharedVariable(SharedVariable, _operators):
It is also worth mentioning that, for efficient transfer to the GPU, Theano will make the new data It is also worth mentioning that, for efficient transfer to the GPU, Theano will make the new data
``c_contiguous``. This can require an extra copy of the data on the host. ``c_contiguous``. This can require an extra copy of the data on the host.
This work what when borrow=True and when borrow=False The inplace on gpu memory work when borrow is either True or False.
""" """
if not borrow: if not borrow:
#TODO: check for cuda_ndarray type #TODO: check for cuda_ndarray type
......
...@@ -340,7 +340,7 @@ class Conv3D(theano.Op): ...@@ -340,7 +340,7 @@ class Conv3D(theano.Op):
codeSource += """ codeSource += """
if (inputChannels > 20 && outputChannels > 20 && ws4 == sizeof(ELEM_AT(%(W)s,0))) if (inputChannels > 20 && outputChannels > 20 && ws4 == sizeof(ELEM_AT(%(W)s,0)))
{ {
std::cout << "lots of channels special case code" << std::endl; //std::cout << "lots of channels special case code" << std::endl;
#define blas_type dtype_ ## %(V)s #define blas_type dtype_ ## %(V)s
const blas_type constant_one = 1.0; const blas_type constant_one = 1.0;
char N = 'T'; char N = 'T';
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论