提交 d414b298 authored 作者: Ian Goodfellow's avatar Ian Goodfellow

updates to doc

上级 eca8a715
...@@ -35,6 +35,13 @@ class Env(utils.object2): ...@@ -35,6 +35,13 @@ class Env(utils.object2):
variable in the subgraph by another, e.g. replace (x + x).out by (2 variable in the subgraph by another, e.g. replace (x + x).out by (2
* x).out. This is the basis for optimization in theano. * x).out. This is the basis for optimization in theano.
This class is also reponsible for verifying that a graph is valid
(ie, all the dtypes and broadcast patterns are compatible with the
way the the Variables are used) and for annotating the Variables with
a .clients field that specifies which Apply nodes use the variable.
The .clients field combined with the .owner field and the Apply nodes'
.inputs field allows the graph to be traversed in both directions.
It can also be "extended" using env.extend(some_object). See the It can also be "extended" using env.extend(some_object). See the
toolbox and ext modules for common extensions. toolbox and ext modules for common extensions.
......
...@@ -195,7 +195,7 @@ class Variable(utils.object2): ...@@ -195,7 +195,7 @@ class Variable(utils.object2):
""" """
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` are `Variable` instances. 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 input and output arguments to create a `function` are also `Variable` instances.
A `Variable` is like a strongly-typed variable in some other languages; each `Variable` contains a 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 reference to a `Type` instance that defines the kind of value the `Variable` can take in a
...@@ -222,8 +222,23 @@ class Variable(utils.object2): ...@@ -222,8 +222,23 @@ class Variable(utils.object2):
- `Constant` (a subclass) which adds a default and un-replaceable :literal:`value`, and - `Constant` (a subclass) which adds a default and un-replaceable :literal:`value`, and
requires that owner is None requires that owner is None
- `TensorVariable`
- `SharedTensorVariable`
- `SparseVariable`
- `CudaVariable`
- `RandomVariable`
A Variable which is the output of a symbolic computation will have an owner != None. A Variable which is the output of a symbolic computation will have an owner != None.
Using the Variables' owner field and the Apply nodes' inputs fields, one can navigate a graph
from an output all the way to the inputs. The opposite direction is not possible until an
Env has annotated the Variables 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** **Code Example**
.. code-block:: python .. code-block:: python
......
"""
If you have two expressions
containing unification variables, these expressions can be "unified"
if there exists an assignment to all unification variables such that
the two expressions are equal. For instance, [5, A, B] and [A, C, 9]
can be unified if A=C=5 and B=9, yielding [5, 5, 9]. [5, [A, B]] and
[A, [1, 2]] cannot be unified because there is no value for A that
satisfies the constraints. That's useful for pattern matching.
"""
from copy import copy from copy import copy
from utils import * from utils import *
...@@ -10,8 +18,18 @@ from utils import * ...@@ -10,8 +18,18 @@ from utils import *
class Variable: class Variable:
""" """
Serves as a base class of variables for the purpose of unification. Serves as a base class of variables for the purpose of unification.
"Unification" here basically means matching two patterns, see the
module-level docstring.
Behavior for unifying various types of variables should be added as Behavior for unifying various types of variables should be added as
overloadings of the 'unify' function. overloadings of the 'unify' function.
Note: there are two Variable classes in theano and this is the
more rarely used one.
This class is used internally by the PatternSub optimization,
and possibly other subroutines that have to perform graph queries.
If that doesn't sound like what you're doing, the Variable class you
want is probably theano.gof.graph.Variable
""" """
def __init__(self, name = "?"): def __init__(self, name = "?"):
self.name = name self.name = name
...@@ -166,7 +184,7 @@ def unify_walk(a, b, U): ...@@ -166,7 +184,7 @@ def unify_walk(a, b, U):
be added if required) be added if required)
Here is a list of unification rules with their associated behavior: Here is a list of unification rules with their associated behavior:
""" """
if a.__class__ != b.__class__: if a.__class__ != b.__class__:
return False return False
......
""" """
VMs that run Theano graph computations. VMs that run Theano graph computations.
A VM is not actually different from a Linker, we just decided
VM was a better name at some point
""" """
import logging import logging
import sys import sys
...@@ -26,7 +28,22 @@ raise_with_op = link.raise_with_op ...@@ -26,7 +28,22 @@ raise_with_op = link.raise_with_op
class VM(object): class VM(object):
""" """
A VM object evaluates a Theano program with its __call__ method. A VM object's __call__ method evaluates a Theano program.
The Stack should be considered the reference VM/Linker implementation.
It can correctly evaluate all graphs and is the easiest to read. The CVM
is a port of Stack, and should have the same behavior, but run faster.
Its code is harder to read though.
The other python VMs are maybe not necessary anymore, and don't take
advantage of lazy computation, though they still produce the correct
output for lazy nodes It can correctly evaluate all graphs and is the easiest to read. The CVM
is a port of Stack, and should have the same behavior, but run faster.
Its code is harder to read though.
The other python VMs are maybe not necessary anymore, and don't take
advantage of lazy computation, though they still produce the correct
output for lazy nodes.
Attributes: Attributes:
...@@ -184,6 +201,23 @@ class Stack(VM): ...@@ -184,6 +201,23 @@ class Stack(VM):
This supports lazy evaluation of subtrees and partial This supports lazy evaluation of subtrees and partial
computations of graphs when only some inputs have changed. computations of graphs when only some inputs have changed.
At a pseudo-code level, the basic idea is the following:
def recursively_evaluate(var):
if var is up to date:
return
if var.owner.inputs are up to date:
update var
return
for input in var.owner.unputs:
recursively_evaluate(var)
for output in outputs:
recursively_evaluate(output)
The actual logic is more complex to support intermediate
garbage collection, lazily-evaluated nodes, and better speed.
""" """
def __init__(self, nodes, thunks, pre_call_clear, def __init__(self, nodes, thunks, pre_call_clear,
......
...@@ -128,7 +128,15 @@ class Print(Op): ...@@ -128,7 +128,15 @@ class Print(Op):
their return value printed. their return value printed.
:note: WARNING. This can disable some optimizations! :note: WARNING. This can disable some optimizations!
(speed and/pr stabilization) (speed and/or stabilization)
Detailed explanation:
As of 2012-06-21 the Print op is not known by any optimization.
Setting a Print op in the middle of a pattern that is usually
optimized out will block the optimization. for example, log(1+x)
optimizes to log1p(x) but log(1+Print(x)) is unaffected by
optimizations.
""" """
view_map = {0: [0]} view_map = {0: [0]}
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论