提交 ae99f41d authored 作者: Iban Harlouchet's avatar Iban Harlouchet

numpydoc for theano/gof/op.py

上级 24d214fb
"""Defines base classes `Op`, `PureOp`, and `CLinkerOp` """
Defines base classes `Op`, `PureOp`, and `CLinkerOp`.
The `Op` class is the base interface for all operations The `Op` class is the base interface for all operations
compatible with `gof`'s :doc:`graph` routines. compatible with `gof`'s :doc:`graph` routines.
"""
"""
import inspect import inspect
import logging import logging
import numpy import numpy
...@@ -33,122 +34,159 @@ __docformat__ = "restructuredtext en" ...@@ -33,122 +34,159 @@ __docformat__ = "restructuredtext en"
class CLinkerObject(object): class CLinkerObject(object):
"""Standard elements of an Op or Type used with the CLinker """
Standard elements of an Op or Type used with the CLinker.
""" """
def c_headers(self): def c_headers(self):
"""Optional: Return a list of header files required by code returned by """
Optional: Return a list of header files required by code returned by
this class. this class.
For example: return ['<iostream>', '<math.h>', '/full/path/to/header.h'] Examples
--------
return ['<iostream>', '<math.h>', '/full/path/to/header.h']
These strings will be prefixed with "#include " and inserted at the beginning of the c These strings will be prefixed with "#include " and inserted at the
source code. beginning of the c source code.
Strings in this list that start neither with '<' nor '"' will be enclosed in Strings in this list that start neither with '<' nor '"' will be
double-quotes. enclosed in double-quotes.
:Exceptions: Raises
- `MethodNotDefined`: Subclass does not implement this method ------
MethodNotDefined
Subclass does not implement this method.
""" """
raise utils.MethodNotDefined("c_headers", type(self), self.__class__.__name__) raise utils.MethodNotDefined("c_headers", type(self), self.__class__.__name__)
def c_header_dirs(self): def c_header_dirs(self):
"""Optional: Return a list of header search paths required by code returned by """
this class. Optional: Return a list of header search paths required by code
returned by this class.
For example: return ['/usr/local/include', '/opt/weirdpath/src/include']. Examples
--------
return ['/usr/local/include', '/opt/weirdpath/src/include']
Provide search paths for headers, in addition to those in any relevant environment Provides search paths for headers, in addition to those in any relevant
variables. environment variables.
Hint: for unix compilers, these are the things that get '-I' prefixed in the compiler Hint: for unix compilers, these are the things that get '-I' prefixed
cmdline. in the compiler cmdline.
:Exceptions: Raises
- `MethodNotDefined`: Subclass does not implement this method ------
MethodNotDefined
Subclass does not implement this method.
""" """
raise utils.MethodNotDefined("c_header_dirs", type(self), self.__class__.__name__) raise utils.MethodNotDefined("c_header_dirs", type(self), self.__class__.__name__)
def c_libraries(self): def c_libraries(self):
"""Optional: Return a list of libraries required by code returned by """
Optional: Return a list of libraries required by code returned by
this class. this class.
For example: return ['gsl', 'gslcblas', 'm', 'fftw3', 'g2c']. Examples
--------
return ['gsl', 'gslcblas', 'm', 'fftw3', 'g2c'].
The compiler will search the directories specified by the environment The compiler will search the directories specified by the environment
variable LD_LIBRARY_PATH in addition to any returned by `c_lib_dirs`. variable LD_LIBRARY_PATH in addition to any returned by `c_lib_dirs`.
Hint: for unix compilers, these are the things that get '-l' prefixed in the compiler Hint: for unix compilers, these are the things that get '-l' prefixed
cmdline. in the compiler cmdline.
:Exceptions: Raises
- `MethodNotDefined`: Subclass does not implement this method ------
MethodNotDefined
Subclass does not implement this method.
""" """
raise utils.MethodNotDefined("c_libraries", type(self), self.__class__.__name__) raise utils.MethodNotDefined("c_libraries", type(self), self.__class__.__name__)
def c_lib_dirs(self): def c_lib_dirs(self):
"""Optional: Return a list of library search paths required by code returned by """
this class. Optional: Return a list of library search paths required by code
returned by this class.
For example: return ['/usr/local/lib', '/opt/weirdpath/build/libs']. Examples
--------
return ['/usr/local/lib', '/opt/weirdpath/build/libs'].
Provide search paths for libraries, in addition to those in any relevant environment Provides search paths for libraries, in addition to those in any
variables (e.g. LD_LIBRARY_PATH). relevant environment variables (e.g. LD_LIBRARY_PATH).
Hint: for unix compilers, these are the things that get '-L' prefixed in the compiler Hint: for unix compilers, these are the things that get '-L' prefixed
cmdline. in the compiler cmdline.
:Exceptions: Raises
- `MethodNotDefined`: Subclass does not implement this method ------
MethodNotDefined
Subclass does not implement this method.
""" """
raise utils.MethodNotDefined("c_lib_dirs", type(self), self.__class__.__name__) raise utils.MethodNotDefined("c_lib_dirs", type(self), self.__class__.__name__)
def c_support_code(self): def c_support_code(self):
"""Optional: Return utility code for use by a `Variable` or `Op` to be """
Optional: Return utility code for use by a `Variable` or `Op` to be
included at global scope prior to the rest of the code for this class. included at global scope prior to the rest of the code for this class.
QUESTION: How many times will this support code be emitted for a graph QUESTION: How many times will this support code be emitted for a graph
with many instances of the same type? with many instances of the same type?
:Exceptions: Raises
- `MethodNotDefined`: Subclass does not implement this method ------
MethodNotDefined
Subclass does not implement this method.
""" """
raise utils.MethodNotDefined("c_support_code", type(self), self.__class__.__name__) raise utils.MethodNotDefined("c_support_code", type(self), self.__class__.__name__)
def c_code_cache_version(self): def c_code_cache_version(self):
"""Return a tuple of integers indicating the version of this Op. """
Return a tuple of integers indicating the version of this Op.
An empty tuple indicates an 'unversioned' Op that will not be cached between processes. An empty tuple indicates an 'unversioned' Op that will not be cached
between processes.
The cache mechanism may erase cached modules that have been superceded by newer The cache mechanism may erase cached modules that have been superceded
versions. See `ModuleCache` for details. by newer versions. See `ModuleCache` for details.
See Also
--------
c_code_cache_version_apply()
:note: See also `c_code_cache_version_apply()`
""" """
return () return ()
def c_compile_args(self): def c_compile_args(self):
"""Optional: Return a list of compile args recommended to compile the """
Optional: Return a list of compile args recommended to compile the
code returned by other methods in this class. code returned by other methods in this class.
Example: return ['-ffast-math'] Example
-------
return ['-ffast-math']
Compiler arguments related to headers, libraries and search paths should be provided Compiler arguments related to headers, libraries and search paths should
via the functions `c_headers`, `c_libraries`, `c_header_dirs`, and `c_lib_dirs`. be provided via the functions `c_headers`, `c_libraries`,
`c_header_dirs`, and `c_lib_dirs`.
:Exceptions: Raises
- `MethodNotDefined`: Subclass does not implement this method ------
MethodNotDefined
Subclass does not implement this method.
""" """
raise utils.MethodNotDefined("c_compile_args", type(self), self.__class__.__name__) raise utils.MethodNotDefined("c_compile_args", type(self), self.__class__.__name__)
def c_no_compile_args(self): def c_no_compile_args(self):
"""Optional: Return a list of incompatible gcc compiler arguments. """
Optional: return a list of incompatible gcc compiler arguments.
We will remove those arguments from the command line of gcc. So if We will remove those arguments from the command line of gcc. So if
another Op adds a compile arg in the graph that is incompatible another Op adds a compile arg in the graph that is incompatible
...@@ -159,8 +197,10 @@ class CLinkerObject(object): ...@@ -159,8 +197,10 @@ class CLinkerObject(object):
WRITEME WRITEME
:Exceptions: Raises
- `MethodNotDefined`: the subclass does not override this method ------
MethodNotDefined
The subclass does not override this method.
""" """
raise utils.MethodNotDefined("c_no_compile_args", type(self), self.__class__.__name__) raise utils.MethodNotDefined("c_no_compile_args", type(self), self.__class__.__name__)
...@@ -170,8 +210,11 @@ class CLinkerObject(object): ...@@ -170,8 +210,11 @@ class CLinkerObject(object):
Optional: return a list of code snippets to be inserted in module Optional: return a list of code snippets to be inserted in module
initialization. initialization.
:Exceptions: Raises
- `MethodNotDefined`: the subclass does not override this method ------
MethodNotDefined
The subclass does not override this method.
""" """
raise utils.MethodNotDefined("c_init_code", type(self), raise utils.MethodNotDefined("c_init_code", type(self),
self.__class__.__name__) self.__class__.__name__)
...@@ -183,50 +226,56 @@ class CLinkerOp(CLinkerObject): ...@@ -183,50 +226,56 @@ class CLinkerOp(CLinkerObject):
A subclass should implement WRITEME. A subclass should implement WRITEME.
WRITEME: structure of automatically generated C code. Put this in doc/code_structure.txt WRITEME: structure of automatically generated C code.
Put this in doc/code_structure.txt
""" """
def c_code(self, node, name, inputs, outputs, sub): def c_code(self, node, name, inputs, outputs, sub):
"""Required: Return the C implementation of an Op. """
Required: return the C implementation of an Op.
Returns C code that does the computation associated to this `Op`, Returns C code that does the computation associated to this `Op`,
given names for the inputs and outputs. given names for the inputs and outputs.
:Parameters: Parameters
`node` : Apply instance ----------
The node for which we are compiling the current c_code. node : Apply instance
The node for which we are compiling the current c_code.
The same Op may be used in more than one node. The same Op may be used in more than one node.
`name` : A string name : str
A name that is automatically assigned and guaranteed to be A name that is automatically assigned and guaranteed to be
unique. unique.
`inputs` : list of strings inputs : list of strings
There is a string for each input of the function, and the There is a string for each input of the function, and the
string is the name of a C variable pointing to that input. string is the name of a C variable pointing to that input.
The type of the variable depends on the declared type of The type of the variable depends on the declared type of
the input. There is a corresponding python variable that the input. There is a corresponding python variable that
can be accessed by prepending "py_" to the name in the can be accessed by prepending "py_" to the name in the
list. list.
`outputs` : list of strings outputs : list of strings
Each string is the name of a C variable where the Op should Each string is the name of a C variable where the Op should
store its output. The type depends on the declared type of store its output. The type depends on the declared type of
the output. There is a corresponding python variable that the output. There is a corresponding python variable that
can be accessed by prepending "py_" to the name in the can be accessed by prepending "py_" to the name in the
list. In some cases the outputs will be preallocated and list. In some cases the outputs will be preallocated and
the value of the variable may be pre-filled. The value for the value of the variable may be pre-filled. The value for
an unallocated output is type-dependent. an unallocated output is type-dependent.
`sub` : dict of strings sub : dict of strings
extra symbols defined in `CLinker` sub symbols (such as 'fail'). Extra symbols defined in `CLinker` sub symbols (such as 'fail').
WRITEME WRITEME
:Exceptions: Raises
- `MethodNotDefined`: the subclass does not override this method ------
MethodNotDefined
The subclass does not override this method.
""" """
raise utils.MethodNotDefined('%s.c_code' % self.__class__.__name__) raise utils.MethodNotDefined('%s.c_code' % self.__class__.__name__)
def c_code_cache_version_apply(self, node): def c_code_cache_version_apply(self, node):
"""Return a tuple of integers indicating the version of this Op. """
Return a tuple of integers indicating the version of this Op.
An empty tuple indicates an 'unversioned' Op that will not be An empty tuple indicates an 'unversioned' Op that will not be
cached between processes. cached between processes.
...@@ -234,69 +283,82 @@ class CLinkerOp(CLinkerObject): ...@@ -234,69 +283,82 @@ class CLinkerOp(CLinkerObject):
The cache mechanism may erase cached modules that have been The cache mechanism may erase cached modules that have been
superceded by newer versions. See `ModuleCache` for details. superceded by newer versions. See `ModuleCache` for details.
:note: See also `c_code_cache_version()` See Also
--------
c_code_cache_version()
Notes
-----
This function overrides `c_code_cache_version` unless it explicitly
calls `c_code_cache_version`. The default implementation simply
calls `c_code_cache_version` and ignores the `node` argument.
:note: This function overrides `c_code_cache_version` unless
it explicitly calls `c_code_cache_version`. The
default implementation simply calls
`c_code_cache_version` and ignores the `node` argument.
""" """
return self.c_code_cache_version() return self.c_code_cache_version()
def c_code_cleanup(self, node, name, inputs, outputs, sub): def c_code_cleanup(self, node, name, inputs, outputs, sub):
""" """
Optional: Return C code to run after c_code, whether it failed Optional: return C code to run after c_code, whether it failed or not.
or not.
This is a convenient place to clean up things allocated by c_code(). This is a convenient place to clean up things allocated by c_code().
:Parameters: Parameters
`node` : Apply instance ----------
WRITEME node : Apply instance
`name` : A string WRITEME
A name that is automatically assigned and guaranteed to be name : str
unique. A name that is automatically assigned and guaranteed to be
`inputs` : list of strings unique.
There is a string for each input of the function, and the inputs : list of strings
string is the name of a C variable pointing to that input. There is a string for each input of the function, and the
The type of the variable depends on the declared type of string is the name of a C variable pointing to that input.
the input. There is a corresponding python variable that The type of the variable depends on the declared type of
can be accessed by prepending "py_" to the name in the the input. There is a corresponding python variable that
list. can be accessed by prepending "py_" to the name in the
`outputs` : list of strings list.
Each string is the name of a C variable correspoinding to outputs : list of strings
one of the outputs of the Op. The type depends on the Each string is the name of a C variable correspoinding to
declared type of the output. There is a corresponding one of the outputs of the Op. The type depends on the
python variable that can be accessed by prepending "py_" to declared type of the output. There is a corresponding
the name in the list. python variable that can be accessed by prepending "py_" to
`sub` : dict of strings the name in the list.
extra symbols defined in `CLinker` sub symbols (such as 'fail'). sub : dict of strings
WRITEME extra symbols defined in `CLinker` sub symbols (such as 'fail').
WRITEME
:Exceptions:
- `MethodNotDefined`: the subclass does not override this method Raises
------
MethodNotDefined
The subclass does not override this method.
""" """
raise utils.MethodNotDefined('%s.c_code_cleanup' % raise utils.MethodNotDefined('%s.c_code_cleanup' %
self.__class__.__name__) self.__class__.__name__)
def c_support_code_apply(self, node, name): def c_support_code_apply(self, node, name):
"""Optional: Return utility code for use by an `Op` that will be """
Optional: return utility code for use by an `Op` that will be
inserted at global scope, that can be specialized for the inserted at global scope, that can be specialized for the
support of a particular `Apply` node. support of a particular `Apply` node.
:param node: an Apply instance in the graph being compiled Parameters
----------
:param name: a string or number that serves to uniquely node: an Apply instance in the graph being compiled
identify this node. Symbol names defined by this name: str
support code should include the name, so that A string or number that serves to uniquely identify this node.
they can be called from the c_code, and so that Symbol names defined by this support code should include the name,
they do not cause name collisions. so that they can be called from the c_code, and so that they do not
cause name collisions.
:note: This function is called in addition to c_support_code
and will supplement whatever is returned from there. Notes
-----
:Exceptions: This function is called in addition to c_support_code and will
- `MethodNotDefined`: Subclass does not implement this method supplement whatever is returned from there.
Raises
------
MethodNotDefined
Subclass does not implement this method.
""" """
raise utils.MethodNotDefined("c_support_code_apply", raise utils.MethodNotDefined("c_support_code_apply",
...@@ -307,19 +369,25 @@ class CLinkerOp(CLinkerObject): ...@@ -307,19 +369,25 @@ class CLinkerOp(CLinkerObject):
Optional: return a code string specific to the apply Optional: return a code string specific to the apply
to be inserted in the module initialization code. to be inserted in the module initialization code.
:param node: an Apply instance in the graph being compiled Parameters
----------
node : an Apply instance in the graph being compiled
name : str
A string or number that serves to uniquely identify this node.
Symbol names defined by this support code should include the name,
so that they can be called from the c_code, and so that they do not
cause name collisions.
Notes
-----
This function is called in addition to c_init_code and will supplement
whatever is returned from there.
Raises
------
MethodNotDefined
The subclass does not override this method.
:param name: a string or number that serves to uniquely
identify this node. Symbol names defined by this
support code should include the name, so that
they can be called from the c_code, and so that
they do not cause name collisions.
:note: This function is called in addition to c_init_code
and will supplement whatever is returned from there.
:Exceptions:
- `MethodNotDefined`: the subclass does not override this method
""" """
raise utils.MethodNotDefined("c_init_code_apply", type(self), raise utils.MethodNotDefined("c_init_code_apply", type(self),
self.__class__.__name__) self.__class__.__name__)
...@@ -329,34 +397,42 @@ class CLinkerOp(CLinkerObject): ...@@ -329,34 +397,42 @@ class CLinkerOp(CLinkerObject):
Optional: return a code string specific to the apply Optional: return a code string specific to the apply
to be inserted in the struct initialization code. to be inserted in the struct initialization code.
:param node: an Apply instance in the graph being compiled Parameters
----------
:param name: a unique name to distinguish you variables from node : an Apply instance in the graph being compiled
those of other nodes. name : str
A unique name to distinguish variables from those of other nodes.
:param sub: a dictionary of values to substitute in the code. sub
Most notably it contains a 'fail' entry that you A dictionary of values to substitute in the code.
should place in your code after setting a python Most notably it contains a 'fail' entry that you should place in
exception to indicate an error. your code after setting a python exception to indicate an error.
Raises
------
MethodNotDefined
The subclass does not override this method.
:Exceptions:
- `MethodNotDefined`: the subclass does not override this method
""" """
raise utils.MethodNotDefined("c_init_code_apply", type(self), raise utils.MethodNotDefined("c_init_code_apply", type(self),
self.__class__.__name__) self.__class__.__name__)
def c_support_code_struct(self, node, name): def c_support_code_struct(self, node, name):
"""Optional: Return utility code for use by an `Op` that will be """
Optional: return utility code for use by an `Op` that will be
inserted at struct scope, that can be specialized for the inserted at struct scope, that can be specialized for the
support of a particular `Apply` node. support of a particular `Apply` node.
:param node: an Apply instance in the graph being compiled Parameters
----------
:param name: a unique name to distinguish you variables from node : an Apply instance in the graph being compiled
those of other nodes. name : str
A unique name to distinguish you variables from those of other
nodes.
:Exceptions: Raises
- `MethodNotDefined`: Subclass does not implement this method ------
MethodNotDefined
Subclass does not implement this method.
""" """
raise utils.MethodNotDefined("c_support_code_struct", raise utils.MethodNotDefined("c_support_code_struct",
...@@ -367,13 +443,17 @@ class CLinkerOp(CLinkerObject): ...@@ -367,13 +443,17 @@ class CLinkerOp(CLinkerObject):
Optional: return a code string specific to the apply to be Optional: return a code string specific to the apply to be
inserted in the struct cleanup code. inserted in the struct cleanup code.
:param node: an Apply instance in the graph being compiled Parameters
----------
node : an Apply instance in the graph being compiled
name : str
A unique name to distinguish variables from those of other nodes.
:param name: a unique name to distinguish you variables from Raises
those of other nodes. ------
MethodNotDefined
The subclass does not override this method.
:Exceptions:
- `MethodNotDefined`: the subclass does not override this method
""" """
raise utils.MethodNotDefined("c_cleanup_code_struct", type(self), raise utils.MethodNotDefined("c_cleanup_code_struct", type(self),
self.__class__.__name__) self.__class__.__name__)
...@@ -383,31 +463,33 @@ class PureOp(object): ...@@ -383,31 +463,33 @@ class PureOp(object):
""" """
An :term:`Op` is a type of operation. An :term:`Op` is a type of operation.
`Op` is an abstract class that documents the interface for theano's data transformations. `Op` is an abstract class that documents the interface for theano's data
It has many subclasses, such as transformations. It has many subclasses, such as
`sparse dot <http://pylearn.org/epydoc/theano.sparse.Dot-class.html>`__, `sparse dot <http://pylearn.org/epydoc/theano.sparse.Dot-class.html>`__,
and `Shape <http://pylearn.org/epydoc/theano.tensor.Shape-class.html>`__. and `Shape <http://pylearn.org/epydoc/theano.tensor.Shape-class.html>`__.
These subclasses are meant to be instantiated. These subclasses are meant to be instantiated.
An instance has several responsabilities: An instance has several responsabilities:
- making `Apply` instances, which mean "apply this type of operation to some particular inputs" (via `make_node`), - making `Apply` instances, which mean "apply this type of operation to some
particular inputs" (via `make_node`),
- performing the calculation of outputs from given inputs (via the `perform`), - performing the calculation of outputs from given inputs
(via the `perform`),
- [optionally] building gradient-calculating graphs (via `grad`). - [optionally] building gradient-calculating graphs (via `grad`).
To see how `Op`, `Type`, `Variable`, and `Apply` fit together see the page
on :doc:`graph`.
To see how `Op`, `Type`, `Variable`, and `Apply` fit together see the page on :doc:`graph`. For more specifications on how these methods should behave: see the
`Op Contract` in the sphinx docs (advanced tutorial on Op-making).
For more specifications on how these methods should behave: see the `Op Contract` in the
sphinx docs (advanced tutorial on Op-making).
""" """
default_output = None default_output = None
""" """
configuration variable for `__call__` Configuration variable for `__call__`.
A subclass should not change this class variable, but instead over-ride it with a subclass A subclass should not change this class variable, but instead over-ride it with a subclass
variable or an instance variable. variable or an instance variable.
...@@ -425,8 +507,9 @@ class PureOp(object): ...@@ -425,8 +507,9 @@ class PureOp(object):
All subclasses should over-ride this function. All subclasses should over-ride this function.
:Exceptions: Raises
- `MethodNotDefined`: the subclass does not override this method ------
MethodNotDefined : the subclass does not override this method.
""" """
raise utils.MethodNotDefined("make_node", type(self), self.__class__.__name__) raise utils.MethodNotDefined("make_node", type(self), self.__class__.__name__)
...@@ -434,11 +517,13 @@ class PureOp(object): ...@@ -434,11 +517,13 @@ class PureOp(object):
@classmethod @classmethod
def _get_test_value(cls, v): def _get_test_value(cls, v):
""" """
Extract test value from variable v. Raises AttributeError if there is none. Extract test value from variable v.
Raises AttributeError if there is none.
For a Constant, the test value is v.value. For a Constant, the test value is v.value.
For a Shared variable, it is the internal value. For a Shared variable, it is the internal value.
For another Variable, it is the content of v.tag.test_value. For another Variable, it is the content of v.tag.test_value.
""" """
# avoid circular import # avoid circular import
from theano.compile.sharedvalue import SharedVariable from theano.compile.sharedvalue import SharedVariable
...@@ -481,7 +566,8 @@ class PureOp(object): ...@@ -481,7 +566,8 @@ class PureOp(object):
raise AttributeError('%s has no test value' % v) raise AttributeError('%s has no test value' % v)
def __call__(self, *inputs, **kwargs): def __call__(self, *inputs, **kwargs):
"""Optional: Return some or all output[s] of `make_node`. """
Optional: return some or all output[s] of `make_node`.
It is called by code such as: It is called by code such as:
...@@ -489,21 +575,26 @@ class PureOp(object): ...@@ -489,21 +575,26 @@ class PureOp(object):
x = tensor.matrix() x = tensor.matrix()
# tensor.exp is an Op instance, calls Op.__call__(self=<instance of exp>, inputs=(x,)) # tensor.exp is an Op instance, calls
# Op.__call__(self=<instance of exp>, inputs=(x,))
y = tensor.exp(x) y = tensor.exp(x)
This class implements a convenience function (for graph-building) which uses This class implements a convenience function (for graph-building) which
`default_output`, but subclasses are free to override this function and ignore uses `default_output`, but subclasses are free to override this function
`default_output`. and ignore `default_output`.
:param inputs: The Op's inputs, forwarded to the call to `make_node()`.
:param kwargs: Additional keyword arguments to be forwarded to Parameters
----------
inputs
The Op's inputs, forwarded to the call to `make_node()`.
kwargs
Additional keyword arguments to be forwarded to
`make_node()` *except* for optional argument `return_list` (which `make_node()` *except* for optional argument `return_list` (which
defaults to False). If `return_list` is True, then the returned defaults to False). If `return_list` is True, then the returned
value is always a list. Otherwise it is either a single Variable value is always a list. Otherwise it is either a single Variable
when the output of `make_node()` contains a single element, or this when the output of `make_node()` contains a single element, or this
output (unchanged) when it contains multiple elements. output (unchanged) when it contains multiple elements.
""" """
return_list = kwargs.pop('return_list', False) return_list = kwargs.pop('return_list', False)
node = self.make_node(*inputs, **kwargs) node = self.make_node(*inputs, **kwargs)
...@@ -594,25 +685,26 @@ class PureOp(object): ...@@ -594,25 +685,26 @@ class PureOp(object):
def R_op(self, inputs, eval_points): def R_op(self, inputs, eval_points):
""" """
This method is primarily used by tensor.Rop This method is primarily used by tensor.Rop
Suppose the op outputs Suppose the op outputs
[ f_1(inputs), ..., f_n(inputs) ] [ f_1(inputs), ..., f_n(inputs) ]
inputs: a Variable or list of Variables Parameters
eval_points: a Variable or list of Variables with ----------
the same length as inputs. Each element inputs : a Variable or list of Variables
of eval_points specifies the value of eval_points
the corresponding input at the point A Variable or list of Variables with the same length as inputs.
where the R op is to be evaluated. Each element of eval_points specifies the value of the corresponding
input at the point where the R op is to be evaluated.
returns: a list of n elements Returns
rval[i] should be Rop(f=f_i(inputs), -------
wrt=inputs, list of n elements
eval_points=eval_points) rval[i] should be Rop(f=f_i(inputs),
wrt=inputs,
eval_points=eval_points)
""" """
raise NotImplementedError( raise NotImplementedError(
...@@ -624,17 +716,21 @@ class PureOp(object): ...@@ -624,17 +716,21 @@ class PureOp(object):
def perform(self, node, inputs, output_storage): def perform(self, node, inputs, output_storage):
""" """
Required: Calculate the function on the inputs and put the variables in the Required: Calculate the function on the inputs and put the variables in
output storage. Return None. the output storage. Return None.
:Parameters: Parameters
`node` : Apply instance ----------
contains the symbolic inputs and outputs node : Apply instance
`inputs` : list Contains the symbolic inputs and outputs.
sequence of inputs (immutable) inputs : list
`output_storage` : list Sequence of inputs (immutable).
list of mutable 1-element lists (do not change the length of these lists) output_storage : list
List of mutable 1-element lists (do not change the length of
these lists)
Notes
-----
The `output_storage` list might contain data. If an element of The `output_storage` list might contain data. If an element of
output_storage is not None, it has to be of the right type, output_storage is not None, it has to be of the right type,
for instance, for a TensorVariable, it has to be a Numpy ndarray, for instance, for a TensorVariable, it has to be a Numpy ndarray,
...@@ -644,8 +740,10 @@ class PureOp(object): ...@@ -644,8 +740,10 @@ class PureOp(object):
could be allocated by another Op impl is free to reuse it as it could be allocated by another Op impl is free to reuse it as it
sees fit, or to discard it and allocate new memory. sees fit, or to discard it and allocate new memory.
:Exceptions: Raises
- `MethodNotDefined`: the subclass does not override this method ------
MethodNotDefined
The subclass does not override this method.
""" """
raise utils.MethodNotDefined("perform", type(self), self.__class__.__name__) raise utils.MethodNotDefined("perform", type(self), self.__class__.__name__)
...@@ -657,12 +755,16 @@ class PureOp(object): ...@@ -657,12 +755,16 @@ class PureOp(object):
choose where it puts its memory/speed trade-off. Also, it choose where it puts its memory/speed trade-off. Also, it
could make things faster as constants can't be used for inplace could make things faster as constants can't be used for inplace
operations (see *IncSubtensor). operations (see *IncSubtensor).
""" """
return True return True
class Op(utils.object2, PureOp, CLinkerOp): class Op(utils.object2, PureOp, CLinkerOp):
"""Convenience class to bundle `PureOp` and `CLinkerOp`""" """
Convenience class to bundle `PureOp` and `CLinkerOp`.
"""
def __new__(cls, *args, **kwargs): def __new__(cls, *args, **kwargs):
# this function exists to silently and transparently ensure that all # this function exists to silently and transparently ensure that all
# existing Ops get a _op_use_c_code attribute # existing Ops get a _op_use_c_code attribute
...@@ -704,6 +806,7 @@ class Op(utils.object2, PureOp, CLinkerOp): ...@@ -704,6 +806,7 @@ class Op(utils.object2, PureOp, CLinkerOp):
def make_c_thunk(self, node, storage_map, compute_map, no_recycling): def make_c_thunk(self, node, storage_map, compute_map, no_recycling):
""" """
Like make_thunk, but will only try to make a C thunk. Like make_thunk, but will only try to make a C thunk.
""" """
logger = logging.getLogger('theano.gof.op.Op') logger = logging.getLogger('theano.gof.op.Op')
...@@ -747,6 +850,7 @@ class Op(utils.object2, PureOp, CLinkerOp): ...@@ -747,6 +850,7 @@ class Op(utils.object2, PureOp, CLinkerOp):
def make_py_thunk(self, node, storage_map, compute_map, no_recycling): def make_py_thunk(self, node, storage_map, compute_map, no_recycling):
""" """
Like make_thunk() but only makes python thunks. Like make_thunk() but only makes python thunks.
""" """
node_input_storage = [storage_map[r] for r in node.inputs] node_input_storage = [storage_map[r] for r in node.inputs]
node_output_storage = [storage_map[r] for r in node.outputs] node_output_storage = [storage_map[r] for r in node.outputs]
...@@ -780,24 +884,31 @@ class Op(utils.object2, PureOp, CLinkerOp): ...@@ -780,24 +884,31 @@ class Op(utils.object2, PureOp, CLinkerOp):
def make_thunk(self, node, storage_map, compute_map, no_recycling): def make_thunk(self, node, storage_map, compute_map, no_recycling):
""" """
:param node: something previously returned by self.make_node
:param storage_map: dict variable -> one-element-list where a computed
value for this variable may be found.
:param compute_map: dict variable -> one-element-list where a boolean Parameters
value will be found. The boolean indicates whether the ----------
variable's storage_map container contains a valid value (True) node
or if it has not been computed yet (False). Something previously returned by self.make_node.
storage_map
dict variable -> one-element-list where a computed
value for this variable may be found.
compute_map
dict variable -> one-element-list where a boolean
value will be found. The boolean indicates whether the
variable's storage_map container contains a valid value (True)
or if it has not been computed yet (False).
no_recycling
List of variables for which it is forbidden to reuse memory
allocated by a previous call.
Notes
-----
If the thunk consults the storage_map on every call, it is safe
for it to ignore the no_recycling argument, because elements of the
no_recycling list will have a value of None in the storage map. If
the thunk can potentially cache return values (like CLinker does),
then it must not do so for variables in the no_recycling list.
:param no_recycling: list of variables for which it is forbidden to
reuse memory allocated by a previous call.
:note: If the thunk consults the storage_map on every call, it is safe
for it to ignore the no_recycling argument, because elements of the
no_recycling list will have a value of None in the storage map. If
the thunk can potentially cache return values (like CLinker does),
then it must not do so for variables in the no_recycling list.
""" """
logger = logging.getLogger('theano.gof.op.Op') logger = logging.getLogger('theano.gof.op.Op')
...@@ -823,6 +934,7 @@ def get_test_value(v): ...@@ -823,6 +934,7 @@ def get_test_value(v):
For a Constant, the test value is v.value. For a Constant, the test value is v.value.
For a Shared variable, it is the internal value. For a Shared variable, it is the internal value.
For another Variable, it is the content of v.tag.test_value. For another Variable, it is the content of v.tag.test_value.
""" """
if not isinstance(v, graph.Variable): if not isinstance(v, graph.Variable):
v_var = theano.tensor.as_tensor_variable(v) v_var = theano.tensor.as_tensor_variable(v)
...@@ -832,14 +944,20 @@ def get_test_value(v): ...@@ -832,14 +944,20 @@ def get_test_value(v):
def missing_test_message(msg): def missing_test_message(msg):
""" Displays msg, a message saying that some test_value is missing, """
Displays msg, a message saying that some test_value is missing,
in the appropriate form based on config.compute_test_value: in the appropriate form based on config.compute_test_value:
off: the interactive debugger is off, so we do nothing off: The interactive debugger is off, so we do nothing.
ignore: the interactive debugger is set to ignore missing inputs, ignore: The interactive debugger is set to ignore missing inputs,
so do nothing so do nothing.
warn: display msg as a warning warn: Display msg as a warning.
raise: raise an AttributeError with msg as the exception text
Raises
------
AttributeError
With msg as the exception text.
""" """
action = config.compute_test_value action = config.compute_test_value
if action == 'raise': if action == 'raise':
...@@ -851,10 +969,12 @@ def missing_test_message(msg): ...@@ -851,10 +969,12 @@ def missing_test_message(msg):
def debug_error_message(msg): def debug_error_message(msg):
""" Displays a message saying that an error was found in some """
Displays a message saying that an error was found in some
test_values. Becomes a warning or a ValueError depending on test_values. Becomes a warning or a ValueError depending on
config.compute_test_value""" config.compute_test_value.
"""
action = config.compute_test_value action = config.compute_test_value
# this message should never be called when the debugger is off # this message should never be called when the debugger is off
...@@ -900,7 +1020,7 @@ def get_debug_values(*args): ...@@ -900,7 +1020,7 @@ def get_debug_values(*args):
3. If the interactive debugger is on, and some variable does 3. If the interactive debugger is on, and some variable does
not have a debug value, issue a missing_test_message about not have a debug value, issue a missing_test_message about
the variable, and, if still in control of execution, return the variable, and, if still in control of execution, return
an empty list an empty list.
""" """
...@@ -938,11 +1058,13 @@ self.fn, the value will be 'fn'. ...@@ -938,11 +1058,13 @@ self.fn, the value will be 'fn'.
We need that to be able not to run debug checks a number of times that is We need that to be able not to run debug checks a number of times that is
exponential in the nesting level of those ops. exponential in the nesting level of those ops.
For instance, Scan will be registered here. For instance, Scan will be registered here.
""" """
class OpenMPOp(Op): class OpenMPOp(Op):
"""All op using OpenMP code should inherit from this Op. """
All op using OpenMP code should inherit from this Op.
This op will check that the compiler support correctly OpenMP code. This op will check that the compiler support correctly OpenMP code.
If not, it will print a warning and disable openmp for this Op. If not, it will print a warning and disable openmp for this Op.
...@@ -954,9 +1076,11 @@ class OpenMPOp(Op): ...@@ -954,9 +1076,11 @@ class OpenMPOp(Op):
We also add the correct compiler flags in c_compile_args. We also add the correct compiler flags in c_compile_args.
""" """
gxx_support_openmp = None gxx_support_openmp = None
""" """
True/False after we tested this. True/False after we tested this.
""" """
def __init__(self, openmp=None): def __init__(self, openmp=None):
...@@ -1004,7 +1128,8 @@ int main( int argc, const char* argv[] ) ...@@ -1004,7 +1128,8 @@ int main( int argc, const char* argv[] )
def update_self_openmp(self): def update_self_openmp(self):
""" """
Make sure self.openmp is not True if there is no support in gxx Make sure self.openmp is not True if there is no support in gxx.
""" """
if self.openmp: if self.openmp:
if OpenMPOp.gxx_support_openmp is None: if OpenMPOp.gxx_support_openmp is None:
...@@ -1056,13 +1181,16 @@ def apply_meth(tag): ...@@ -1056,13 +1181,16 @@ def apply_meth(tag):
class COp(Op): class COp(Op):
""" Class to allow an op to have an external C implementation. """
Class to allow an op to have an external C implementation.
An op can use this class by inheriting from it and calling its An op can use this class by inheriting from it and calling its
__init__() method, providing it with a path to an external file containing __init__() method, providing it with a path to an external file containing
the C implementation and the name of the function, in that file, to call the C implementation and the name of the function, in that file, to call
to perform the computations for the op. to perform the computations for the op.
""" """
section_re = re.compile(r'^#section ([a-zA-Z0-9_]+)$', re.MULTILINE) section_re = re.compile(r'^#section ([a-zA-Z0-9_]+)$', re.MULTILINE)
backward_re = re.compile(r'^THEANO_(APPLY|SUPPORT)_CODE_SECTION$', re.MULTILINE) backward_re = re.compile(r'^THEANO_(APPLY|SUPPORT)_CODE_SECTION$', re.MULTILINE)
# This is the set of allowed markers # This is the set of allowed markers
...@@ -1078,6 +1206,7 @@ class COp(Op): ...@@ -1078,6 +1206,7 @@ class COp(Op):
Convert a path relative to the location of the class file into Convert a path relative to the location of the class file into
an aboslute path. Paths that are already absolute are passed an aboslute path. Paths that are already absolute are passed
through unchanged. through unchanged.
""" """
if not os.path.isabs(f): if not os.path.isabs(f):
class_file = inspect.getfile(cls) class_file = inspect.getfile(cls)
...@@ -1089,6 +1218,7 @@ class COp(Op): ...@@ -1089,6 +1218,7 @@ class COp(Op):
""" """
Sections are loaded from files in order with sections in later Sections are loaded from files in order with sections in later
files overriding sections in previous files. files overriding sections in previous files.
""" """
if not isinstance(func_files, list): if not isinstance(func_files, list):
func_files = [func_files] func_files = [func_files]
...@@ -1181,6 +1311,7 @@ class COp(Op): ...@@ -1181,6 +1311,7 @@ class COp(Op):
The names must be strings that are not a C keyword and the The names must be strings that are not a C keyword and the
values must be strings of literal C representations. values must be strings of literal C representations.
""" """
return [] return []
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论