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

numpydoc for theano/gof/link.py

上级 fa6d41d7
"""WRITEME""" """
WRITEME
"""
from __future__ import print_function from __future__ import print_function
from copy import copy, deepcopy from copy import copy, deepcopy
from sys import getsizeof from sys import getsizeof
...@@ -20,8 +23,10 @@ __excepthook = sys.excepthook ...@@ -20,8 +23,10 @@ __excepthook = sys.excepthook
def log_thunk_trace(value, f=sys.stderr): def log_thunk_trace(value, f=sys.stderr):
"""Log Theano's diagnostic stack trace for an exception """
Log Theano's diagnostic stack trace for an exception
raised by raise_with_op. raised by raise_with_op.
""" """
# in future, consider accepting `write` as arg rather than file # in future, consider accepting `write` as arg rather than file
# to support writing to a logger # to support writing to a logger
...@@ -46,7 +51,9 @@ def log_thunk_trace(value, f=sys.stderr): ...@@ -46,7 +51,9 @@ def log_thunk_trace(value, f=sys.stderr):
def thunk_hook(type, value, trace): def thunk_hook(type, value, trace):
"""WRITEME """
WRITEME
This function is meant to replace excepthook and do some This function is meant to replace excepthook and do some
special work if the exception value has a __thunk_trace__ special work if the exception value has a __thunk_trace__
field. In that case, it retrieves the field, which should field. In that case, it retrieves the field, which should
...@@ -55,7 +62,10 @@ def thunk_hook(type, value, trace): ...@@ -55,7 +62,10 @@ def thunk_hook(type, value, trace):
The normal excepthook is then called. The normal excepthook is then called.
:note: This hook replaced by nosetests, so it does not run in nose tests. Notes
-----
This hook replaced by nosetests, so it does not run in nose tests.
""" """
log_thunk_trace(value) log_thunk_trace(value)
__excepthook(type, value, trace) __excepthook(type, value, trace)
...@@ -82,7 +92,6 @@ def raise_with_op(node, thunk=None, exc_info=None, storage_map=None): ...@@ -82,7 +92,6 @@ def raise_with_op(node, thunk=None, exc_info=None, storage_map=None):
Notes Notes
----- -----
This re-raises the exception described by `exc_info` (or the last This re-raises the exception described by `exc_info` (or the last
one raised, if `exc_info` is omitted) and annotates the exception one raised, if `exc_info` is omitted) and annotates the exception
object with several new members which may be helpful for debugging object with several new members which may be helpful for debugging
...@@ -96,6 +105,7 @@ def raise_with_op(node, thunk=None, exc_info=None, storage_map=None): ...@@ -96,6 +105,7 @@ def raise_with_op(node, thunk=None, exc_info=None, storage_map=None):
to this op in `op.fgraph.toposort()`. to this op in `op.fgraph.toposort()`.
The exception is not annotated if it is of type `KeyboardInterrupt`. The exception is not annotated if it is of type `KeyboardInterrupt`.
""" """
if exc_info is None: if exc_info is None:
exc_info = sys.exc_info() exc_info = sys.exc_info()
...@@ -298,7 +308,10 @@ def raise_with_op(node, thunk=None, exc_info=None, storage_map=None): ...@@ -298,7 +308,10 @@ def raise_with_op(node, thunk=None, exc_info=None, storage_map=None):
class Linker(object): class Linker(object):
"""WRITEME""" """
WRITEME
"""
def clone(self, allow_gc=undef): def clone(self, allow_gc=undef):
new = copy(self) new = copy(self)
...@@ -308,13 +321,15 @@ class Linker(object): ...@@ -308,13 +321,15 @@ class Linker(object):
def make_thunk(self): def make_thunk(self):
""" """
This function must return a triplet (function, input_variables, output_variables) This function must return a triplet (function, input_variables,
where function is a thunk that operates on the returned variables. If inplace output_variables) where function is a thunk that operates on the
is True, the input_variables and output_variables lists will be the same as the returned variables. If inplace is True, the input_variables and
inputs and outputs of the graph provided to the L{Linker}. Else, independent output_variables lists will be the same as the inputs and outputs
of the graph provided to the L{Linker}. Else, independent
variables will be returned. variables will be returned.
Example:: Examples
--------
x, y = Variable(Double), Variable(Double) x, y = Variable(Double), Variable(Double)
e = x + y e = x + y
fgraph = FunctionGraph([x, y], [e]) fgraph = FunctionGraph([x, y], [e])
...@@ -324,6 +339,7 @@ class Linker(object): ...@@ -324,6 +339,7 @@ class Linker(object):
fn() fn()
print new_e.data # 3.0 print new_e.data # 3.0
print e.data # 3.0 iff inplace == True (else unknown) print e.data # 3.0 iff inplace == True (else unknown)
""" """
raise utils.MethodNotDefined("make_thunk", type(self), raise utils.MethodNotDefined("make_thunk", type(self),
self.__class__.__name__) self.__class__.__name__)
...@@ -332,12 +348,13 @@ class Linker(object): ...@@ -332,12 +348,13 @@ class Linker(object):
def make_function(self, unpack_single=True, **kwargs): def make_function(self, unpack_single=True, **kwargs):
""" """
Returns a function that takes values corresponding to the inputs of the Returns a function that takes values corresponding to the inputs of the
fgraph used by this L{Linker} and returns values corresponding the the outputs fgraph used by this L{Linker} and returns values corresponding the the
of that fgraph. If inplace is True, the calculations will operate in the outputs of that fgraph. If inplace is True, the calculations will
same storage the fgraph uses, else independent storage will be allocated operate in the same storage the fgraph uses, else independent storage
for the function. will be allocated for the function.
Example:: Example
-------
e = x + y e = x + y
fgraph = FunctionGraph([x, y], [e]) fgraph = FunctionGraph([x, y], [e])
fn = MyLinker(fgraph).make_function(inplace) fn = MyLinker(fgraph).make_function(inplace)
...@@ -347,6 +364,7 @@ class Linker(object): ...@@ -347,6 +364,7 @@ class Linker(object):
If unpack_single is True (default) and that the function has only one If unpack_single is True (default) and that the function has only one
output, then that output will be returned. Else, a list or tuple of output, then that output will be returned. Else, a list or tuple of
length 1 will be returned. length 1 will be returned.
""" """
thunk, inputs, outputs = self.make_thunk(**kwargs) thunk, inputs, outputs = self.make_thunk(**kwargs)
...@@ -376,24 +394,31 @@ class Linker(object): ...@@ -376,24 +394,31 @@ class Linker(object):
# TODO: Move this class to the compile module, where it is used (and for which it exists). # TODO: Move this class to the compile module, where it is used (and for which it exists).
class Container(object): class Container(object):
"""This class joins a variable with its computed value.
It is used in linkers, especially for the inputs and outputs of a Function.
""" """
def __init__(self, r, storage, readonly=False, strict=False, This class joins a variable with its computed value.
allow_downcast=None, name=None):
"""WRITEME
:Parameters: It is used in linkers, especially for the inputs and outputs of a Function.
`r`: a Variable or a Type
`storage`: a list of length 1, whose element is the value for `r` Parameters
`readonly`: True indicates that this should not be setable by Function[r] = val ----------
`strict`: if True, we don't allow type casting. r : a Variable or a Type
`allow_downcast`: if True (and `strict` is False), allow upcasting storage
of type, but not downcasting. If False, prevent it. If None A list of length 1, whose element is the value for `r`.
(default), allows only downcasting of float to floatX scalar. readonly : bool
`name`: A string (for pretty-printing?) True indicates that this should not be setable by Function[r] = val.
strict : bool
If True, we don't allow type casting.
allow_downcast
If True (and `strict` is False), allow upcasting of type, but not
downcasting. If False, prevent it. If None (default), allows only
downcasting of float to floatX scalar.
name : str
A string (for pretty-printing?)
""" """
def __init__(self, r, storage, readonly=False, strict=False,
allow_downcast=None, name=None):
if not isinstance(storage, list) or not len(storage) >= 1: if not isinstance(storage, list) or not len(storage) >= 1:
raise TypeError("storage must be a list of length at least one") raise TypeError("storage must be a list of length at least one")
# self.r = r # self.r = r
...@@ -472,23 +497,38 @@ class Container(object): ...@@ -472,23 +497,38 @@ class Container(object):
def map_storage(fgraph, order, input_storage, output_storage): def map_storage(fgraph, order, input_storage, output_storage):
"""Ensure there is storage (a length-1 list) for inputs, outputs, and interior nodes. """
Ensure there is storage (a length-1 list) for inputs, outputs, and
:param fgraph: The current fgraph. This function uses the inputs and outputs attributes. interior nodes.
:param order: an iterable over Apply instances (in program running order)
:param input_storage: None or existing input storage (see below)
:param output_storage: None or existing output storage (see below)
:rtype: 3-tuple
:returns: (list of storage for inputs, list of storage for outputs, and the `storage_map`)
Parameters
----------
fgraph
The current fgraph. This function uses the inputs and outputs
attributes.
order
An iterable over Apply instances (in program running order).
input_storage
None or existing input storage (see below).
output_storage
None or existing output storage (see below).
Returns
-------
3-tuple
List of storage for inputs, list of storage for outputs, and
the `storage_map`.
Extended summary
----------------
This function iterates over the nodes in `order` and ensures that for every This function iterates over the nodes in `order` and ensures that for every
input and output `Variable`, there is a unique storage container. This is input and output `Variable`, there is a unique storage container. This is
returned as a dictionary Variable->storage called the `storage_map`. returned as a dictionary Variable -> storage called the `storage_map`.
This function also returns `input_storage` which is a list of storages corresponding to fgraph.inputs. This function also returns `input_storage`, which is a list of storages
This function also returns `output_storage` which is a list of storages corresponding to fgraph.outputs. corresponding to fgraph.inputs.
This function also returns `output_storage`, which is a list of storages
corresponding to fgraph.outputs.
""" """
# each Apply argument's data is stored in a list of length 1 (these lists act like pointers) # each Apply argument's data is stored in a list of length 1 (these lists act like pointers)
...@@ -531,23 +571,28 @@ def map_storage(fgraph, order, input_storage, output_storage): ...@@ -531,23 +571,28 @@ def map_storage(fgraph, order, input_storage, output_storage):
def streamline(fgraph, thunks, order, post_thunk_old_storage=None, def streamline(fgraph, thunks, order, post_thunk_old_storage=None,
no_recycling=None, nice_errors=True): no_recycling=None, nice_errors=True):
"""WRITEME """
WRITEME
:param fgraph:
:param thunks: the list of program instructions
:param order: the list of apply instances that gave rise to the thunks (same order as thunks)
:param post_thunk_old_storage: a list (corresponding to thunks, order) whose elements are
lists of storage cells, that should be cleared after running the corresponding thunk. A
value of None disables this functionality
:param no_recycling: storage elements that cannot be 'recycled' by repeatedly executing the Parameters
----------
fgraph
thunks
The list of program instructions.
order
The list of apply instances that gave rise to the thunks
(same order as thunks).
post_thunk_old_storage
A list (corresponding to thunks, order) whose elements are lists of
storage cells, that should be cleared after running thecorresponding
thunk. A value of None disables this functionality.
no_recycling
Storage elements that cannot be 'recycled' by repeatedly executing the
program. These storage elements are cleared before re-running. program. These storage elements are cleared before re-running.
nice_errors
:param nice_errors: run in such a way that the double-traceback is printed. This costs a Run in such a way that the double-traceback is printed. This costs a
bit of performance in the inner python loop. bit of performance in the inner python loop.
""" """
if no_recycling is None: if no_recycling is None:
no_recycling = [] no_recycling = []
...@@ -597,9 +642,12 @@ def streamline(fgraph, thunks, order, post_thunk_old_storage=None, ...@@ -597,9 +642,12 @@ def streamline(fgraph, thunks, order, post_thunk_old_storage=None,
class LocalLinker(Linker): class LocalLinker(Linker):
"""WRITEME """
Useful base class for L{Linker}s which keep all nodes in the graph, and run a WRITEME
thunk associated with each node.
Useful base class for L{Linker}s which keep all nodes in the graph, and run
a thunk associated with each node.
""" """
def make_thunk(self, input_storage=None, output_storage=None): def make_thunk(self, input_storage=None, output_storage=None):
...@@ -621,16 +669,25 @@ class LocalLinker(Linker): ...@@ -621,16 +669,25 @@ class LocalLinker(Linker):
def gc_helper(node_list): def gc_helper(node_list):
""" """
:param node_list: list of Apply instances in program execution order
:rtype: a 2-tuple
:returns: FIRST, the set of Variable instances which are computed by node_list, and SECOND a
dictionary that maps each Variable instance to a the last node to use Variable as an input.
Parameters
----------
node_list
List of Apply instances in program execution order.
Returns
-------
2-tuple
FIRST, the set of Variable instances which are computed by node_list,
and SECOND a dictionary that maps each Variable instance to a the last
node to use Variable as an input.
Extended Summary
----------------
This is used to allow garbage collection within graphs. This is used to allow garbage collection within graphs.
It ignore view_map and destroy_map. This isn't needed as python It ignores view_map and destroy_map. This isn't needed as python
have referecence count. In Theano gc, we should not take into have reference count. In Theano gc, we should not take into
account view_map and destroy_map as if the thunk decided to create account view_map and destroy_map as if the thunk decided to create
a new output, we would delay uselessly its gc by Python. a new output, we would delay uselessly its gc by Python.
...@@ -647,10 +704,12 @@ def gc_helper(node_list): ...@@ -647,10 +704,12 @@ def gc_helper(node_list):
class PerformLinker(LocalLinker): class PerformLinker(LocalLinker):
"""WRITEME """
WRITEME
Basic L{Linker} subclass that calls the perform method on each L{Op} in Basic L{Linker} subclass that calls the perform method on each L{Op} in
the L{FunctionGraph} in the order given by L{Linker.schedule}. the L{FunctionGraph} in the order given by L{Linker.schedule}.
""" """
def __init__(self, allow_gc=None, schedule=None): def __init__(self, allow_gc=None, schedule=None):
...@@ -663,11 +722,20 @@ class PerformLinker(LocalLinker): ...@@ -663,11 +722,20 @@ class PerformLinker(LocalLinker):
def accept(self, fgraph, no_recycling=None): def accept(self, fgraph, no_recycling=None):
""" """
:param fgraph: a PerformLinker can have accepted one FunctionGraph instance at a time.
:param no_recycling: WRITEME Parameters
----------
fgraph
A PerformLinker can have accepted one FunctionGraph instance at a
time.
no_recycling
WRITEME
Returns
-------
object
self (TODO: WHY? Who calls this function?)
:returns: self (TODO: WHY? Who calls this function?)
""" """
if no_recycling is None: if no_recycling is None:
no_recycling = [] no_recycling = []
...@@ -680,10 +748,20 @@ class PerformLinker(LocalLinker): ...@@ -680,10 +748,20 @@ class PerformLinker(LocalLinker):
def make_all(self, input_storage=None, output_storage=None): def make_all(self, input_storage=None, output_storage=None):
""" """
:param input_storage: WRITEME
:param output_storage: WRITEME
:returns: function to run all nodes, list of input containers, list of output containers, list of thunks (for all of program), list of nodes (for all of program) Parameters
----------
input_storage
WRITEME
output_storage
WRITEME
Returns
-------
object
Function to run all nodes, list of input containers, list of output
containers, list of thunks (for all programs), list of nodes
(for all programs).
""" """
fgraph = self.fgraph fgraph = self.fgraph
...@@ -764,41 +842,39 @@ def add_clear_storage(f, computed, storage_map): ...@@ -764,41 +842,39 @@ def add_clear_storage(f, computed, storage_map):
class WrapLinker(Linker): class WrapLinker(Linker):
""" """
WRITEME WRITEME
This class makes it easier to run several L{LocalLinker}s in parallel, and This class makes it easier to run several L{LocalLinker}s in parallel, and
offers some control over how each thunk is run. offers some control over how each thunk is run.
A wrapper function must be provided, and it can be used to execute the A wrapper function must be provided, and it can be used to execute the
thunks, inspect the nodes, print stuff out, etc. thunks, inspect the nodes, print stuff out, etc.
@note: The constructor initializes a WrapLinker.
The outputs of the first linker will be returned.
@note:
This linker ensures that each linker has its own storage for
inputs and outputs and intermediate variables. There is no interference
between linkers.
"""
def __init__(self, linkers, wrapper):
"""
Initialize a WrapLinker.
@type linkers: list of L{LocalLinker} subclasses, whose make_all() Parameters
method returns thunks in the same order. ----------
linkers : list of L{LocalLinker} subclasses, whose make_all() method returns
@param linkers: for each node in the graph, each linker will provide a thunks in the same order.
For each node in the graph, each linker will provide a
thunk. This class makes it possible to iterate over each linker's thunk. This class makes it possible to iterate over each linker's
program in parallel. program in parallel.
wrapper : lambda (i, i_node, i_thunk1, i_thunk2, ...) : None
Does some user-defined action for the i'th element of the program.
i_thunk<n> is the thunk returned by the n'th linker. (If you want
to run the program, make sure to call the necessary thunks in this
function.)
@type wrapper: lambda (i, i_node, i_thunk1, i_thunk2, ...) : None Notes
-----
The outputs of the first linker will be returned.
@param wrapper: do some user-defined action for the i'th element of the This linker ensures that each linker has its own storage for inputs and
program. i_thunk<n> is the thunk returned by the n'th linker. (If you outputs and intermediate variables. There is no interference between
want to run the program, make sure to call the necessary thunks in this linkers.
function.)
""" """
def __init__(self, linkers, wrapper):
self.fgraph = None self.fgraph = None
self.linkers = linkers self.linkers = linkers
self.wrapper = wrapper self.wrapper = wrapper
...@@ -807,12 +883,16 @@ class WrapLinker(Linker): ...@@ -807,12 +883,16 @@ class WrapLinker(Linker):
""" """
Shallow copy of a WrapLinker. Shallow copy of a WrapLinker.
@returns: A copy of self, where each of the linkers in self.linkers Returns
-------
object
A copy of self, where each of the linkers in self.linkers
have been shallow-copied. have been shallow-copied.
It is useful because in FunctionMaker, copy.copy is called on the It is useful because in FunctionMaker, copy.copy is called on the
Mode's linker, so that it is not modified inplace when linker.accept() Mode's linker, so that it is not modified inplace when linker.accept()
is called. In this case, we want the wrapped linkers to be copied too. is called. In this case, we want the wrapped linkers to be copied too.
""" """
other = self.__class__( other = self.__class__(
linkers=[copy(l) for l in self.linkers], linkers=[copy(l) for l in self.linkers],
...@@ -826,14 +906,15 @@ class WrapLinker(Linker): ...@@ -826,14 +906,15 @@ class WrapLinker(Linker):
def accept(self, fgraph, no_recycling=None): def accept(self, fgraph, no_recycling=None):
""" """
@type fgraph: gof.FunctionGraph
@param fgraph: the fgraph which we will link
@type no_recycling: a list of Variables that belong to fgraph.
@param no_recycling: If a Variable is in no_recycling, L{WrapLinker} will clear Parameters
the output storage associated to it (for each linker in linkers) during ----------
the computation to avoid reusing it. fgraph : gof.FunctionGraph
The fgraph which we will link.
no_recycling : a list of Variables that belong to fgraph.
If a Variable is in no_recycling, L{WrapLinker} will clear
the output storage associated to it (for each linker in linkers)
during the computation to avoid reusing it.
""" """
if no_recycling is None: if no_recycling is None:
...@@ -905,6 +986,7 @@ def WrapLinkerMany(linkers, wrappers): ...@@ -905,6 +986,7 @@ def WrapLinkerMany(linkers, wrappers):
""" """
Variant on WrapLinker that runs a series of wrapper functions instead of Variant on WrapLinker that runs a series of wrapper functions instead of
just one. just one.
""" """
def wrapper(*args): def wrapper(*args):
for f in wrappers: for f in wrappers:
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论