Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
P
pytensor
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
testgroup
pytensor
Commits
fa75ad6e
提交
fa75ad6e
authored
8月 12, 2015
作者:
Iban Harlouchet
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
numpydoc for theano/gof/graph.py
上级
75e573d1
显示空白字符变更
内嵌
并排
正在显示
1 个修改的文件
包含
384 行增加
和
261 行删除
+384
-261
graph.py
theano/gof/graph.py
+384
-261
没有找到文件。
theano/gof/graph.py
浏览文件 @
fa75ad6e
...
@@ -26,68 +26,74 @@ NoContext = object()
...
@@ -26,68 +26,74 @@ NoContext = object()
class
Node
(
utils
.
object2
):
class
Node
(
utils
.
object2
):
"""A Node in a theano graph.
"""
Graphs contain two kinds of Nodes--
A Node in a theano graph.
Variable and Apply.
Graphs contain two kinds of Nodes -- Variable and Apply.
Edges in the graph are not explicitly represented.
Edges in the graph are not explicitly represented.
Instead each Node keeps track of its parents via
Instead each Node keeps track of its parents via
Variable.owner / Apply.inputs and its children
Variable.owner / Apply.inputs and its children
via Variable.clients / Apply.outputs.
via Variable.clients / Apply.outputs.
"""
"""
def
get_parents
(
self
):
def
get_parents
(
self
):
""" Return a list of the parents of this node.
"""
Return a list of the parents of this node.
Should return a copy--i.e., modifying the return
Should return a copy--i.e., modifying the return
value should not modify the graph structure.
"""
value should not modify the graph structure.
"""
raise
NotImplementedError
()
raise
NotImplementedError
()
class
Apply
(
Node
):
class
Apply
(
Node
):
"""
"""
An :term:`Apply` instance is a node in an expression graph which represents the application
An :term:`Apply` instance is a node in an expression graph which represents
of an `Op` to some input `Variable` nodes, producing some output `Variable` nodes.
the application of an `Op` to some input `Variable` nodes, producing some
output `Variable` nodes.
This class is typically instantiated by an Op's make_node() function, which
is typically
This class is typically instantiated by an Op's make_node() function, which
called by that Op's __call__() function.
is typically
called by that Op's __call__() function.
An Apply instance serves as a simple structure with three important attributes:
An Apply instance serves as a simple structure with three important
attributes:
- :literal:`inputs` : a list of `Variable` nodes that represent the arguments of the expression,
- :literal:`inputs` : a list of `Variable` nodes that represent the
arguments of the expression,
- :literal:`outputs` : a list of `Variable` nodes that represent the variable of the expression, and
- :literal:`outputs` : a list of `Variable` nodes that represent the
variable of the expression, and
- :literal:`op` : an `Op` instance that determines the nature of the expression being applied.
- :literal:`op` : an `Op` instance that determines the nature of the
expression being applied.
The driver `compile.function` uses Apply's inputs attribute together with
Variable's owner
The driver `compile.function` uses Apply's inputs attribute together with
attribute to search the expression graph and determine which inputs are necessary to
Variable's owner attribute to search the expression graph and determine
compute the function's outputs.
which inputs are necessary to
compute the function's outputs.
A `Linker` uses the Apply instance's `op` field to compute the variables.
A `Linker` uses the Apply instance's `op` field to compute the variables.
Comparing with the Python language, an `Apply` instance is theano's version of a function
Comparing with the Python language, an `Apply` instance is theano's version
call (or expression instance) whereas `Op` is theano's version of a function definition.
of a function call (or expression instance) whereas `Op` is theano's version
of a function definition.
"""
def
__init__
(
self
,
op
,
inputs
,
outputs
):
Parameters
"""Initialize attributes
----------
op : `Op` instance
:Parameters:
inputs : list of Variable instances
`op` : `Op` instance
outputs : list of Variable instances
initialize self.op
`inputs` : list of Variable instances
initialize self.inputs
`outputs` : list of Variable instances
initialize self.outputs
:note:
Notes
-----
The owner field of each output in the outputs list will be set to self.
The owner field of each output in the outputs list will be set to self.
:note:
If an output element has an owner that is neither None nor self, then a
If an output element has an owner that is neither None nor self, then a ValueError
ValueError exception will be raised.
exception will be raised.
"""
"""
def
__init__
(
self
,
op
,
inputs
,
outputs
):
self
.
op
=
op
self
.
op
=
op
self
.
inputs
=
[]
self
.
inputs
=
[]
self
.
tag
=
utils
.
scratchpad
()
self
.
tag
=
utils
.
scratchpad
()
...
@@ -118,27 +124,29 @@ class Apply(Node):
...
@@ -118,27 +124,29 @@ class Apply(Node):
raise
TypeError
(
"The 'outputs' argument to Apply must contain Variable instances with no owner, not
%
s"
%
output
)
raise
TypeError
(
"The 'outputs' argument to Apply must contain Variable instances with no owner, not
%
s"
%
output
)
def
run_context
(
self
):
def
run_context
(
self
):
"""Returns the context for the node, or NoContext if no context is set.
"""
Returns the context for the node, or NoContext if no context is set.
"""
"""
if
hasattr
(
self
.
op
,
'get_context'
):
if
hasattr
(
self
.
op
,
'get_context'
):
return
self
.
op
.
get_context
(
self
)
return
self
.
op
.
get_context
(
self
)
return
NoContext
return
NoContext
def
default_output
(
self
):
def
default_output
(
self
):
"""Returns the default output for this node.
"""
Returns the default output for this node.
:rtype:
Returns
-------
Variable instance
Variable instance
An element of self.outputs, typically self.outputs[0].
:return:
Notes
an element of self.outputs, typically self.outputs[0].
-----
May raise AttributeError self.op.default_output is out of range, or if
:note:
there are multiple outputs and self.op.default_output does not exist.
may raise AttributeError self.op.default_output is out of range, or if there are
multiple outputs and self.op.default_output does not exist.
"""
"""
do
=
getattr
(
self
.
op
,
'default_output'
,
None
)
do
=
getattr
(
self
.
op
,
'default_output'
,
None
)
if
do
is
None
:
if
do
is
None
:
if
len
(
self
.
outputs
)
==
1
:
if
len
(
self
.
outputs
)
==
1
:
...
@@ -156,7 +164,10 @@ class Apply(Node):
...
@@ -156,7 +164,10 @@ class Apply(Node):
out
=
property
(
default_output
,
out
=
property
(
default_output
,
doc
=
"alias for self.default_output()"
)
doc
=
"alias for self.default_output()"
)
"""Alias for self.default_output()"""
"""
Alias for self.default_output().
"""
def
__str__
(
self
):
def
__str__
(
self
):
return
op_as_string
(
self
.
inputs
,
self
)
return
op_as_string
(
self
.
inputs
,
self
)
...
@@ -168,13 +179,18 @@ class Apply(Node):
...
@@ -168,13 +179,18 @@ class Apply(Node):
return
self
return
self
def
clone
(
self
):
def
clone
(
self
):
"""Duplicate this Apply instance with inputs = self.inputs.
"""
Duplicate this Apply instance with inputs = self.inputs.
:return:
Returns
a new Apply instance (or subclass instance) with new outputs.
-------
object
A new Apply instance (or subclass instance) with new outputs.
Notes
-----
Tags are copied from self to the returned instance.
:note:
tags are copied from self to the returned instance.
"""
"""
cp
=
self
.
__class__
(
self
.
op
,
self
.
inputs
,
cp
=
self
.
__class__
(
self
.
op
,
self
.
inputs
,
[
output
.
clone
()
for
output
in
self
.
outputs
])
[
output
.
clone
()
for
output
in
self
.
outputs
])
...
@@ -182,13 +198,14 @@ class Apply(Node):
...
@@ -182,13 +198,14 @@ class Apply(Node):
return
cp
return
cp
def
clone_with_new_inputs
(
self
,
inputs
,
strict
=
True
):
def
clone_with_new_inputs
(
self
,
inputs
,
strict
=
True
):
"""Duplicate this Apply instance in a new graph.
"""
Duplicate this Apply instance in a new graph.
:param inputs: list of Variable instances to use as inputs.
:type strict: Bool
:param strict:
Parameters
----------
inputs
List of Variable instances to use as inputs.
strict : bool
If True, the type fields of all the inputs must be equal
If True, the type fields of all the inputs must be equal
to the current ones (or compatible, for instance Tensor /
to the current ones (or compatible, for instance Tensor /
CudaNdarray of the same dtype and broadcastable patterns,
CudaNdarray of the same dtype and broadcastable patterns,
...
@@ -198,7 +215,10 @@ class Apply(Node):
...
@@ -198,7 +215,10 @@ class Apply(Node):
clone's outputs will have the same types as self.outputs,
clone's outputs will have the same types as self.outputs,
and cloning may not even be possible (it depends on the Op).
and cloning may not even be possible (it depends on the Op).
:returns: an Apply instance with the same op but different outputs.
Returns
-------
object
An Apply instance with the same op but different outputs.
"""
"""
assert
isinstance
(
inputs
,
(
list
,
tuple
))
assert
isinstance
(
inputs
,
(
list
,
tuple
))
...
@@ -224,62 +244,90 @@ class Apply(Node):
...
@@ -224,62 +244,90 @@ class Apply(Node):
# convenience properties
# convenience properties
nin
=
property
(
lambda
self
:
len
(
self
.
inputs
),
doc
=
'same as len(self.inputs)'
)
nin
=
property
(
lambda
self
:
len
(
self
.
inputs
),
doc
=
'same as len(self.inputs)'
)
"""property: Number of inputs"""
"""
Property: Number of inputs.
"""
nout
=
property
(
lambda
self
:
len
(
self
.
outputs
),
doc
=
'same as len(self.outputs)'
)
nout
=
property
(
lambda
self
:
len
(
self
.
outputs
),
doc
=
'same as len(self.outputs)'
)
"""property: Number of outputs"""
"""
Property: Number of outputs.
"""
context_type
=
property
(
lambda
self
:
self
.
op
.
context_type
,
doc
=
'type to use for the context'
)
context_type
=
property
(
lambda
self
:
self
.
op
.
context_type
,
doc
=
'type to use for the context'
)
class
Variable
(
Node
):
class
Variable
(
Node
):
"""
"""
A :term:`Variable` is a node in an expression graph that represents a variable.
A :term:`Variable` is a node in an expression graph that represents a
variable.
The inputs and outputs of every `Apply` (theano.gof.Apply) are `Variable` instances.
The input and output arguments to create a `function` are also `Variable` instances.
The inputs and outputs of every `Apply` (theano.gof.Apply) are `Variable`
A `Variable` is like a strongly-typed variable in some other languages; each `Variable` contains a
instances. The input and output arguments to create a `function` are also
reference to a `Type` instance that defines the kind of value the `Variable` can take in a
`Variable` instances. A `Variable` is like a strongly-typed variable in
some other languages; each `Variable` contains a reference to a `Type`
instance that defines the kind of value the `Variable` can take in a
computation.
computation.
A `Variable` is a container for four important attributes:
A `Variable` is a container for four important attributes:
- :literal:`type` a `Type` instance defining the kind of value this `Variable` can have,
- :literal:`type` a `Type` instance defining the kind of value this
`Variable` can have,
- :literal:`owner` either None (for graph roots) or the `Apply` instance of which `self` is an output,
- :literal:`owner` either None (for graph roots) or the `Apply` instance
of which `self` is an output,
- :literal:`index` the integer such that :literal:`owner.outputs[index] is this_variable` (ignored if `owner` is None)
- :literal:`index` the integer such that :literal:`owner.outputs[index] is
this_variable` (ignored if `owner` is None),
- :literal:`name` a string to use in pretty-printing and debugging.
- :literal:`name` a string to use in pretty-printing and debugging.
There are a few kinds of Variables to be aware of: A Variable which is the output of a symbolic
There are a few kinds of Variables to be aware of: A Variable which is the
computation has a reference to the Apply instance to which it belongs (property: owner) and
output of a symbolic computation has a reference to the Apply instance to
the position of itself in the owner's output list (property: index).
which it belongs (property: owner) and the position of itself in the owner's
output list (property: index).
- `Variable` (this base type) is typically the output of a symbolic computation,
- `Variable` (this base type) is typically the output of a symbolic
computation.
- `Constant` (a subclass) which adds a default and un-replaceable
:literal:`value`, and
- `Constant` (a subclass) which adds a default and un-replaceable
requires that owner is None
:literal:`value`, and requires that owner is None.
- `TensorVariable` subclass of Variable that represents a numpy.ndarray object
- `TensorVariable` subclass of Variable that represents a numpy.ndarray
object.
- `TensorSharedVariable` Shared version of TensorVariable
- `TensorSharedVariable` Shared version of TensorVariable
.
- `SparseVariable` subclass of Variable that represents a scipy.sparse.{csc,csr}_matrix object
- `SparseVariable` subclass of Variable that represents
a scipy.sparse.{csc,csr}_matrix object.
- `CudaNdarrayVariable` subclass of Variable that represents our object on the GPU that is a subset of numpy.ndarray
- `CudaNdarrayVariable` subclass of Variable that represents our object on
the GPU that is a subset of numpy.ndarray.
- `RandomVariable`
- `RandomVariable`
.
A Variable which is the output of a symbolic computation will have an owner
A Variable which is the output of a symbolic computation will have an owner
not equal to None.
not equal to None.
Using the Variables' owner field and the Apply nodes' inputs fields, one can navigate a graph
Using the Variables' owner field and the Apply nodes' inputs fields, one can
from an output all the way to the inputs. The opposite direction is not possible until an
navigate a graph from an output all the way to the inputs. The opposite
FunctionGraph has annotated the Variables with the clients field, ie, before the compilation process
direction is not possible until a FunctionGraph has annotated the Variables
has begun a Variable does not know which Apply nodes take it as input.
with the clients field, ie, before the compilation process has begun a
Variable does not know which Apply nodes take it as input.
**Code Example**
Parameters
----------
type : a Type instance
The type governs the kind of data that can be associated with this
variable.
owner : None or Apply instance
The Apply instance which computes the value for this variable.
index : None or int
The position of this Variable in owner.outputs.
name : None or str
A string for pretty-printing and debugging.
Examples
--------
.. code-block:: python
.. code-block:: python
...
@@ -303,32 +351,20 @@ class Variable(Node):
...
@@ -303,32 +351,20 @@ class Variable(Node):
e = d + b
e = d + b
theano.function([d,b], [e]) # this works. d's default value of 1.5 is ignored.
theano.function([d,b], [e]) # this works. d's default value of 1.5 is ignored.
The python variables :literal:`a,b,c` all refer to instances of type `Variable`.
The python variables :literal:`a,b,c` all refer to instances of type
The `Variable` refered to by `a` is also an instance of `Constant`.
`Variable`. The `Variable` refered to by `a` is also an instance of
`Constant`.
`compile.function` uses each `Apply` instance's `inputs` attribute together
with each Variable's `owner` field to determine which inputs are necessary
to compute the function's outputs.
`compile.function` uses each `Apply` instance's `inputs` attribute
together with each Variable's `owner` field to determine which inputs are necessary to compute the function's outputs.
"""
"""
# __slots__ = ['type', 'owner', 'index', 'name']
# __slots__ = ['type', 'owner', 'index', 'name']
__count__
=
count
(
0
)
__count__
=
count
(
0
)
def
__init__
(
self
,
type
,
owner
=
None
,
index
=
None
,
name
=
None
):
def
__init__
(
self
,
type
,
owner
=
None
,
index
=
None
,
name
=
None
):
"""Initialize type, owner, index, name.
:type type: a Type instance
:param type:
the type governs the kind of data that can be associated with this variable
:type owner: None or Apply instance
:param owner: the Apply instance which computes the value for this variable
:type index: None or int
:param index: the position of this Variable in owner.outputs
:type name: None or str
:param name: a string for pretty-printing and debugging
"""
super
(
Variable
,
self
)
.
__init__
()
super
(
Variable
,
self
)
.
__init__
()
self
.
tag
=
utils
.
scratchpad
()
self
.
tag
=
utils
.
scratchpad
()
...
@@ -345,7 +381,10 @@ class Variable(Node):
...
@@ -345,7 +381,10 @@ class Variable(Node):
self
.
auto_name
=
'auto_'
+
str
(
next
(
self
.
__count__
))
self
.
auto_name
=
'auto_'
+
str
(
next
(
self
.
__count__
))
def
__str__
(
self
):
def
__str__
(
self
):
"""WRITEME"""
"""
WRITEME
"""
if
self
.
name
is
not
None
:
if
self
.
name
is
not
None
:
return
self
.
name
return
self
.
name
if
self
.
owner
is
not
None
:
if
self
.
owner
is
not
None
:
...
@@ -361,13 +400,21 @@ class Variable(Node):
...
@@ -361,13 +400,21 @@ class Variable(Node):
return
str
(
self
)
return
str
(
self
)
def
clone
(
self
):
def
clone
(
self
):
"""Return a new Variable like self.
"""
Return a new Variable like self.
:rtype: Variable instance
Returns
:return: a new Variable instance (or subclass instance) with no owner or index.
-------
Variable instance
A new Variable instance (or subclass instance) with no owner or
index.
Notes
-----
Tags are copied to the returned instance.
Name is copied to the returned instance.
:note: tags are copied to the returned instance.
:note: name is copied to the returned instance.
"""
"""
# return copy(self)
# return copy(self)
cp
=
self
.
__class__
(
self
.
type
,
None
,
None
,
self
.
name
)
cp
=
self
.
__class__
(
self
.
type
,
None
,
None
,
self
.
name
)
...
@@ -396,9 +443,14 @@ class Variable(Node):
...
@@ -396,9 +443,14 @@ class Variable(Node):
return
[]
return
[]
def
eval
(
self
,
inputs_to_values
=
None
):
def
eval
(
self
,
inputs_to_values
=
None
):
""" Evaluates this variable.
"""
Evaluates this variable.
Parameters
----------
inputs_to_values
A dictionary mapping theano Variables to values.
inputs_to_values: a dictionary mapping theano Variables to values.
"""
"""
if
inputs_to_values
is
None
:
if
inputs_to_values
is
None
:
...
@@ -424,21 +476,23 @@ class Variable(Node):
...
@@ -424,21 +476,23 @@ class Variable(Node):
class
Constant
(
Variable
):
class
Constant
(
Variable
):
"""
"""
A :term:`Constant` is a `Variable` with a `value` field that cannot be changed at runtime.
A :term:`Constant` is a `Variable` with a `value` field that cannot be
changed at runtime.
Constant nodes make eligible numerous optimizations: constant inlining in C code, constant folding, etc.
Constant nodes make eligible numerous optimizations: constant inlining in
"""
C code, constant folding, etc.
# __slots__ = ['data']
def
__init__
(
self
,
type
,
data
,
name
=
None
):
"""Initialize self.
:note:
Notes
The data field is filtered by what is provided in the constructor for the Constant's
-----
type field.
The data field is filtered by what is provided in the constructor for the
Constant's type field.
WRITEME
WRITEME
"""
"""
# __slots__ = ['data']
def
__init__
(
self
,
type
,
data
,
name
=
None
):
Variable
.
__init__
(
self
,
type
,
None
,
None
,
name
)
Variable
.
__init__
(
self
,
type
,
None
,
None
,
name
)
self
.
data
=
type
.
filter
(
data
)
self
.
data
=
type
.
filter
(
data
)
...
@@ -463,18 +517,23 @@ class Constant(Variable):
...
@@ -463,18 +517,23 @@ class Constant(Variable):
def
clone
(
self
):
def
clone
(
self
):
"""
"""
We clone this object, but we don't clone the data to lower memory requirement
We clone this object, but we don't clone the data to lower memory
We suppose that the data will never change.
requirement. We suppose that the data will never change.
"""
"""
cp
=
self
.
__class__
(
self
.
type
,
self
.
data
,
self
.
name
)
cp
=
self
.
__class__
(
self
.
type
,
self
.
data
,
self
.
name
)
cp
.
tag
=
copy
(
self
.
tag
)
cp
.
tag
=
copy
(
self
.
tag
)
return
cp
return
cp
def
__set_owner
(
self
,
value
):
def
__set_owner
(
self
,
value
):
"""WRITEME
"""
WRITEME
Raises
------
ValueError
If `value` is not `None`.
:Exceptions:
- `ValueError`: if `value` is not `None`
"""
"""
if
value
is
not
None
:
if
value
is
not
None
:
raise
ValueError
(
"Constant instances cannot have an owner."
)
raise
ValueError
(
"Constant instances cannot have an owner."
)
...
@@ -486,19 +545,25 @@ class Constant(Variable):
...
@@ -486,19 +545,25 @@ class Constant(Variable):
def
stack_search
(
start
,
expand
,
mode
=
'bfs'
,
build_inv
=
False
):
def
stack_search
(
start
,
expand
,
mode
=
'bfs'
,
build_inv
=
False
):
"""Search through a graph, either breadth- or depth-first
"""
Search through a graph, either breadth- or depth-first.
:type start: deque
:param start: search from these nodes
Parameters
:type expand: callable
----------
:param expand:
start : deque
when we get to a node, add expand(node) to the list of nodes to visit.
Search from these nodes.
This function should return a list, or None
expand : callable
:rtype: list of `Variable` or `Apply` instances (depends on `expend`)
When we get to a node, add expand(node) to the list of nodes to visit.
:return: the list of nodes in order of traversal.
This function should return a list, or None.
:note:
Returns
a node will appear at most once in the return value, even if it
-------
list of `Variable` or `Apply` instances (depends on `expend`)
The list of nodes in order of traversal.
Notes
-----
A node will appear at most once in the return value, even if it
appears multiple times in the start parameter.
appears multiple times in the start parameter.
:postcondition: every element of start is transferred to the returned list.
:postcondition: every element of start is transferred to the returned list.
...
@@ -533,15 +598,20 @@ def stack_search(start, expand, mode='bfs', build_inv=False):
...
@@ -533,15 +598,20 @@ def stack_search(start, expand, mode='bfs', build_inv=False):
def
ancestors
(
variable_list
,
blockers
=
None
):
def
ancestors
(
variable_list
,
blockers
=
None
):
"""Return the variables that contribute to those in variable_list (inclusive).
"""
Return the variables that contribute to those in variable_list (inclusive).
Parameters
----------
variable_list : list of `Variable` instances
Output `Variable` instances from which to search backward through
owners.
:type variable_list: list of `Variable` instances
Returns
:param variable_list:
-------
output `Variable` instances from which to search backward through owners
list of `Variable` instances
:rtype: list of `Variable` instances
All input nodes, in the order found by a left-recursive depth-first
:returns:
search started at the nodes in `variable_list`.
all input nodes, in the order found by a left-recursive depth-first search
started at the nodes in `variable_list`.
"""
"""
def
expand
(
r
):
def
expand
(
r
):
...
@@ -552,15 +622,20 @@ def ancestors(variable_list, blockers=None):
...
@@ -552,15 +622,20 @@ def ancestors(variable_list, blockers=None):
def
inputs
(
variable_list
,
blockers
=
None
):
def
inputs
(
variable_list
,
blockers
=
None
):
"""Return the inputs required to compute the given Variables.
"""
Return the inputs required to compute the given Variables.
Parameters
----------
variable_list : list of `Variable` instances
Output `Variable` instances from which to search backward through
owners.
:type variable_list: list of `Variable` instances
Returns
:param variable_list:
-------
output `Variable` instances from which to search backward through owners
list of `Variable` instances
:rtype: list of `Variable` instances
Input nodes with no owner, in the order found by a left-recursive
:returns:
depth-first search started at the nodes in `variable_list`.
input nodes with no owner, in the order found by a left-recursive depth-first search
started at the nodes in `variable_list`.
"""
"""
vlist
=
ancestors
(
variable_list
,
blockers
)
vlist
=
ancestors
(
variable_list
,
blockers
)
...
@@ -569,7 +644,9 @@ def inputs(variable_list, blockers=None):
...
@@ -569,7 +644,9 @@ def inputs(variable_list, blockers=None):
def
variables_and_orphans
(
i
,
o
):
def
variables_and_orphans
(
i
,
o
):
"""WRITEME
"""
WRITEME
"""
"""
def
expand
(
r
):
def
expand
(
r
):
if
r
.
owner
and
r
not
in
i
:
if
r
.
owner
and
r
not
in
i
:
...
@@ -582,17 +659,24 @@ def variables_and_orphans(i, o):
...
@@ -582,17 +659,24 @@ def variables_and_orphans(i, o):
def
ops
(
i
,
o
):
def
ops
(
i
,
o
):
""" WRITEME
"""
WRITEME
:type i: list
Parameters
:param i: input L{Variable}s
----------
:type o: list
i : list
:param o: output L{Variable}s
Input L{Variable}s.
o : list
Output L{Variable}s.
Returns
-------
object
The set of ops that are contained within the subgraph that lies
between i and o, including the owners of the L{Variable}s in o and
intermediary ops between i and o, but not the owners of the L{Variable}s
in i.
:returns:
the set of ops that are contained within the subgraph that lies between i and o,
including the owners of the L{Variable}s in o and intermediary ops between i and o, but
not the owners of the L{Variable}s in i.
"""
"""
ops
=
set
()
ops
=
set
()
variables
,
orphans
=
variables_and_orphans
(
i
,
o
)
variables
,
orphans
=
variables_and_orphans
(
i
,
o
)
...
@@ -604,33 +688,48 @@ def ops(i, o):
...
@@ -604,33 +688,48 @@ def ops(i, o):
def
variables
(
i
,
o
):
def
variables
(
i
,
o
):
""" WRITEME
"""
WRITEME
:type i: list
Parameters
:param i: input L{Variable}s
----------
:type o: list
i : list
:param o: output L{Variable}s
Input L{Variable}s.
o : list
Output L{Variable}s.
Returns
-------
object
The set of Variables that are involved in the subgraph that lies
between i and o. This includes i, o, orphans(i, o) and all values of
all intermediary steps from i to o.
:returns:
the set of Variables that are involved in the subgraph that lies between i and o. This
includes i, o, orphans(i, o) and all values of all intermediary steps from i to o.
"""
"""
return
variables_and_orphans
(
i
,
o
)[
0
]
return
variables_and_orphans
(
i
,
o
)[
0
]
def
orphans
(
i
,
o
):
def
orphans
(
i
,
o
):
""" WRITEME
"""
WRITEME
Parameters
----------
i : list
Input L{Variable}s.
o : list
Output L{Variable}s.
:type i: list
Returns
:param i: input L{Variable}s
-------
:type o: list
object
:param o: output L{Variable}s
The set of Variables which one or more Variables in o depend on but are
neither in i nor in the subgraph that lies between i and o.
:returns:
Examples
the set of Variables which one or more Variables in o depend on but are neither in i nor in
--------
the subgraph that lies between i and o.
orphans([x], [(x+y).out]) => [y]
e.g. orphans([x], [(x+y).out]) => [y]
"""
"""
return
variables_and_orphans
(
i
,
o
)[
1
]
return
variables_and_orphans
(
i
,
o
)[
1
]
...
@@ -639,14 +738,20 @@ def clone(i, o, copy_inputs=True):
...
@@ -639,14 +738,20 @@ def clone(i, o, copy_inputs=True):
"""
"""
Copies the subgraph contained between i and o.
Copies the subgraph contained between i and o.
:type i: list
Parameters
:param i: input L{Variable}s
----------
:type o: list
i : list
:param o: output L{Variable}s
Input L{Variable}s.
:type copy_inputs: bool
o : list
:param copy_inputs: if True, the inputs will be copied (defaults to True)
Output L{Variable}s.
copy_inputs : bool
If True, the inputs will be copied (defaults to True).
Returns
-------
object
The inputs and outputs of that copy.
Returns the inputs and outputs of that copy.
"""
"""
equiv
=
clone_get_equiv
(
i
,
o
,
copy_inputs
)
equiv
=
clone_get_equiv
(
i
,
o
,
copy_inputs
)
return
[
equiv
[
input
]
for
input
in
i
],
[
equiv
[
output
]
for
output
in
o
]
return
[
equiv
[
input
]
for
input
in
i
],
[
equiv
[
output
]
for
output
in
o
]
...
@@ -662,20 +767,19 @@ def clone_get_equiv(inputs, outputs, copy_inputs_and_orphans=True, memo=None):
...
@@ -662,20 +767,19 @@ def clone_get_equiv(inputs, outputs, copy_inputs_and_orphans=True, memo=None):
Parameters
Parameters
----------
----------
inputs: a list of Variables
inputs
: a list of Variables
outputs: a list of Variables
outputs
: a list of Variables
copy_inputs_and_orphans: bool
copy_inputs_and_orphans
: bool
True means to create the cloned graph from new input and constant
True means to create the cloned graph from new input and constant
nodes (the bottom of a feed-upward graph),
nodes (the bottom of a feed-upward graph).
False means to clone a graph that is rooted at the original input
False means to clone a graph that is rooted at the original input
nodes.
nodes.
memo: None or dict
memo
: None or dict
Optionally start with a partly-filled dictionary for the return value.
Optionally start with a partly-filled dictionary for the return value.
If a dictionary is passed, this function will work in-place on that
If a dictionary is passed, this function will work in-place on that
dictionary and return it.
dictionary and return it.
"""
"""
if
memo
is
None
:
if
memo
is
None
:
memo
=
{}
memo
=
{}
...
@@ -714,29 +818,33 @@ def clone_get_equiv(inputs, outputs, copy_inputs_and_orphans=True, memo=None):
...
@@ -714,29 +818,33 @@ def clone_get_equiv(inputs, outputs, copy_inputs_and_orphans=True, memo=None):
def
general_toposort
(
r_out
,
deps
,
debug_print
=
False
,
def
general_toposort
(
r_out
,
deps
,
debug_print
=
False
,
compute_deps_cache
=
None
,
deps_cache
=
None
):
compute_deps_cache
=
None
,
deps_cache
=
None
):
"""WRITEME
"""
WRITEME
:note:
Parameters
deps(i) should behave like a pure function (no funny business with internal state)
----------
deps
A python function that takes a node as input and returns its dependence.
compute_deps_cache : optional
If provided deps_cache should also be provided. This is a function like
deps, but that also cache its results in a dict passed as deps_cache.
deps_cache : dict
Must be used with compute_deps_cache.
:note:
Notes
deps(i) will be cached by this function (to be fast)
-----
deps(i) should behave like a pure function (no funny business with
internal state).
:note:
deps(i) will be cached by this function (to be fast).
The order of the return value list is determined by the order of nodes returned by the deps() function.
:param deps: a python function that take a node as input and
The order of the return value list is determined by the order of nodes
return its dependence.
returned by the deps() function.
:param compute_deps_cache: Optional,
if provided deps_cache should also be provided. This is a
function like deps, but that also cache its results in a dict
passed as deps_cache.
:param deps_cache: a dict. Must be used with compute_deps_cache.
:note: deps should be provided or can be None and the caller
deps should be provided or can be None and the caller provides
provide compute_deps_cache and deps_cache. The second opti
on
compute_deps_cache and deps_cache. The second option removes a Pyth
on
remove a Python function call, and allow for more specialized
function call, and allows for more specialized code, so it can be
code, so it can be
faster.
faster.
"""
"""
if
compute_deps_cache
is
None
:
if
compute_deps_cache
is
None
:
...
@@ -788,18 +896,17 @@ def general_toposort(r_out, deps, debug_print=False,
...
@@ -788,18 +896,17 @@ def general_toposort(r_out, deps, debug_print=False,
def
io_toposort
(
inputs
,
outputs
,
orderings
=
None
):
def
io_toposort
(
inputs
,
outputs
,
orderings
=
None
):
"""WRITEME
"""
WRITEME
inputs: a list or tuple of Variable instances
outputs: a list or tuple of Apply instances
orderings: a dictionary
key: Apply instance
value: list of Apply instance
it is important that the value be
Parameters
a container with a deterministic iteration
----------
order. no sets allowed!
inputs : list or tuple of Variable instances
outputs : list or tuple of Apply instances
orderings: dict
Key: Apply instance. Value: list of Apply instance.
It is important that the value be a container with a deterministic
iteration order. No sets allowed!
"""
"""
# the inputs are used only here in the function that decides what 'predecessors' to explore
# the inputs are used only here in the function that decides what 'predecessors' to explore
...
@@ -864,9 +971,9 @@ def default_node_formatter(op, argstrings):
...
@@ -864,9 +971,9 @@ def default_node_formatter(op, argstrings):
def
io_connection_pattern
(
inputs
,
outputs
):
def
io_connection_pattern
(
inputs
,
outputs
):
"""
"""
Returns the connection pattern of a subgraph defined by given
Returns the connection pattern of a subgraph defined by given
inputs and outputs
inputs and outputs.
"""
"""
inner_nodes
=
io_toposort
(
inputs
,
outputs
)
inner_nodes
=
io_toposort
(
inputs
,
outputs
)
# Initialize 'connect_pattern_by_var' by establishing each input as
# Initialize 'connect_pattern_by_var' by establishing each input as
...
@@ -941,22 +1048,26 @@ def is_same_graph(var1, var2, givens=None, debug=False):
...
@@ -941,22 +1048,26 @@ def is_same_graph(var1, var2, givens=None, debug=False):
return the same output. The goal is to verify this assumption, to
return the same output. The goal is to verify this assumption, to
eventually get rid of one of them in the future.
eventually get rid of one of them in the future.
:param var1: The first Variable to compare.
Parameters
----------
:param var2: The second Variable to compare.
var1
The first Variable to compare.
:param givens: Similar to the `givens` argument of `theano.function`, it
var2
can be used to perform substitutions in the computational graph of `var1`
The second Variable to compare.
and `var2`. This argument is associated to neither `var1` nor `var2`:
givens
substitutions may affect both graphs if the substituted variable is present
Similar to the `givens` argument of `theano.function`, it can be used
in both.
to perform substitutions in the computational graph of `var1` and
`var2`. This argument is associated to neither `var1` nor `var2`:
:param debug: If True, then an exception is raised when we are in a
substitutions may affect both graphs if the substituted variable
situation where the `equal_computations` implementation cannot be called.
is present in both.
debug : bool
If True, then an exception is raised when we are in a situation where
the `equal_computations` implementation cannot be called.
This parameter is intended to be used in tests only, to make sure we
This parameter is intended to be used in tests only, to make sure we
properly test both implementations.
properly test both implementations.
Examples:
Examples
--------
====== ====== ====== ======
====== ====== ====== ======
var1 var2 givens output
var1 var2 givens output
...
@@ -965,6 +1076,7 @@ def is_same_graph(var1, var2, givens=None, debug=False):
...
@@ -965,6 +1076,7 @@ def is_same_graph(var1, var2, givens=None, debug=False):
x + 1 y + 1 {} False
x + 1 y + 1 {} False
x + 1 y + 1 {x: y} True
x + 1 y + 1 {x: y} True
====== ====== ====== ======
====== ====== ====== ======
"""
"""
# Lazy import.
# Lazy import.
if
givens
is
None
:
if
givens
is
None
:
...
@@ -1040,7 +1152,10 @@ def is_same_graph(var1, var2, givens=None, debug=False):
...
@@ -1040,7 +1152,10 @@ def is_same_graph(var1, var2, givens=None, debug=False):
def
op_as_string
(
i
,
op
,
def
op_as_string
(
i
,
op
,
leaf_formatter
=
default_leaf_formatter
,
leaf_formatter
=
default_leaf_formatter
,
node_formatter
=
default_node_formatter
):
node_formatter
=
default_node_formatter
):
"""WRITEME"""
"""
WRITEME
"""
strs
=
as_string
(
i
,
op
.
inputs
,
leaf_formatter
,
node_formatter
)
strs
=
as_string
(
i
,
op
.
inputs
,
leaf_formatter
,
node_formatter
)
return
node_formatter
(
op
,
strs
)
return
node_formatter
(
op
,
strs
)
...
@@ -1048,28 +1163,32 @@ def op_as_string(i, op,
...
@@ -1048,28 +1163,32 @@ def op_as_string(i, op,
def
as_string
(
i
,
o
,
def
as_string
(
i
,
o
,
leaf_formatter
=
default_leaf_formatter
,
leaf_formatter
=
default_leaf_formatter
,
node_formatter
=
default_node_formatter
):
node_formatter
=
default_node_formatter
):
"""WRITEME
:type i: list
:param i: input `Variable` s
:type o: list
:param o: output `Variable` s
:type leaf_formatter: function
:param leaf_formatter: takes a `Variable` and returns a string to describe it
:type node_formatter: function
:param node_formatter:
takes an `Op` and the list of strings corresponding to its arguments and returns a
string to describe it
:rtype: str
:returns:
Returns a string representation of the subgraph between i and o. If the same op is used
by several other ops, the first occurrence will be marked as :literal:`*n ->
description` and all subsequent occurrences will be marked as :literal:`*n`, where n is
an id number (ids are attributed in an unspecified order and only exist for viewing
convenience).
"""
"""
WRITEME
Parameters
----------
i : list
Input `Variable` s.
o : list
Output `Variable` s.
leaf_formatter : function
Takes a `Variable` and returns a string to describe it.
node_formatter : function
Takes an `Op` and the list of strings corresponding to its arguments
and returns a string to describe it.
Returns
-------
str
Returns a string representation of the subgraph between i and o. If the
same op is used by several other ops, the first occurrence will be
marked as :literal:`*n -> description` and all subsequent occurrences
will be marked as :literal:`*n`, where n is an id number (ids are
attributed in an unspecified order and only exist for viewing
convenience).
"""
i
=
set
(
i
)
i
=
set
(
i
)
orph
=
orphans
(
i
,
o
)
orph
=
orphans
(
i
,
o
)
...
@@ -1126,6 +1245,7 @@ def view_roots(r):
...
@@ -1126,6 +1245,7 @@ def view_roots(r):
consecutive view_map()s.
consecutive view_map()s.
WRITEME
WRITEME
"""
"""
owner
=
r
.
owner
owner
=
r
.
owner
if
owner
is
not
None
:
if
owner
is
not
None
:
...
@@ -1147,7 +1267,10 @@ def view_roots(r):
...
@@ -1147,7 +1267,10 @@ def view_roots(r):
def
list_of_nodes
(
inputs
,
outputs
):
def
list_of_nodes
(
inputs
,
outputs
):
""" Return the apply nodes of the graph between inputs and outputs """
"""
Return the apply nodes of the graph between inputs and outputs.
"""
return
stack_search
(
return
stack_search
(
deque
([
o
.
owner
for
o
in
outputs
]),
deque
([
o
.
owner
for
o
in
outputs
]),
lambda
o
:
[
inp
.
owner
for
inp
in
o
.
inputs
lambda
o
:
[
inp
.
owner
for
inp
in
o
.
inputs
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论