提交 79460528 authored 作者: James Bergstra's avatar James Bergstra

merge

......@@ -20,5 +20,6 @@ Structure
ccodegen
function
module
pipeline
profilemode
unittest
.. _pipeline:
====================================
Overview of the compilation pipeline
====================================
The purpose of this page is to explain each step of defining and
compiling a Theano function.
Definition of the computation graph
===================================
By creating Theano :ref:`Variables <variable>` using
``theano.tensor.lscalar`` or ``theano.tensor.dmatrix`` or by using
Theano functions such as ``theano.tensor.sin`` or
``theano.tensor.log``, the user builds a computation graph. The
structure of that graph and details about its components can be found
in the :ref:`graphstructures` article.
Compilation of the computation graph
====================================
Once the user has built a computation graph, he can use
``theano.function`` or a ``theano.Method`` in a ``theano.module`` in
order to make one or more functions that operate on real data. Both
function and Method take a list of input :ref:`Variables <variable>`
as well as a list of output Variables that define a precise subgraph
corresponding to the function(s) we want to define, compile that
subgraph and produce a callable.
Here is an overview of the various steps that are done with the
computation graph in the compilation phase:
Step 1 - Create an Env
======================
The subgraph given by the end user is wrapped in a structure called
:ref:`env`. That structure defines several hooks on adding and
removing (pruning) nodes as well as on modifying links between nodes
(for example, modifying an input of an :ref:`apply` node) (see the
article about :ref:`env` for more information).
Env provides a method to change the input of an Apply node from one
Variable to another and a more high-level method to replace a Variable
with another. This is the structure that :ref:`Optimizers
<optimization>` work on.
Some relevant :ref:`Features <envfeature>` are typically added to the
Env, namely to prevent any optimization from operating inplace on
inputs declared as immutable.
Step 2 - Execute main Optimizer
===============================
Once the Env is made, an :ref:`optimizer <optimization>` is produced
by the :ref:`mode` passed to ``function`` or to the Method/Module's
``make`` (the Mode basically has two important fields, ``linker`` and
``optimizer``). That optimizer is applied on the Env using its
optimize() method.
The optimizer is typically obtained through :ref:`optdb <optdb>`.
Step 3 - Execute linker to obtain a thunk
=========================================
Once the computation graph is optimized, the :ref:`linker` is
extracted from the Mode. It is then called with the Env as argument to
produce a ``thunk``, which is a function with no arguments that
returns nothing. Along with the thunk, one list of input containers (a
theano.gof.Container is a sort of object that wraps another and does
type casting) and one list of output containers are produced,
corresponding to the input and output Variables as well as the updates
defined for the inputs when applicable. To perform the computations,
the inputs must be placed in the input containers, the thunk must be
called, and the outputs must be retrieved from the output containers
where the thunk put them.
Typically, the linker calls the ``toposort`` method in order to obtain
a linear sequence of operations to perform. How they are linked
together depends on the Linker used. The CLinker produces a single
block of C code for the whole computation, whereas the OpWiseCLinker
produces one thunk for each individual operation and calls them in
sequence.
The linker is where some options take effect: the ``strict`` flag of
an input makes the associated input container do type checking. The
``borrow`` flag of an output, if False, adds the output to a
``no_recycling`` list, meaning that when the thunk is called the
output containers will be cleared (if they stay there, as would be the
case if ``borrow`` was True, the thunk would be allowed to reuse (or
"recycle") the storage).
Step 4 - Wrap the thunk in a pretty package
===========================================
The thunk returned by the linker along with input and output
containers is unwieldy. ``function`` and ``Method`` hide that
complexity away so that it can be used like a normal function with
arguments and return values.
......@@ -227,6 +227,11 @@ The local version of the above code would be the following:
elif y == b:
return [a]
return False
def tracks(self):
# This should be needed for the EquilibriumOptimizer
# but it isn't now
# TODO: do this and explain it
return [] # that's not what you should do
local_simplify = LocalSimplify()
......@@ -256,6 +261,61 @@ subset of them) and applies one or several local optimizers on them.
TODO: test this.
OpSub, OpRemove, PatternSub
+++++++++++++++++++++++++++
Theano defines some shortcuts to make LocalOptimizers:
* **OpSub(op1, op2)**: replaces all uses of op1 by op2. In other
words, the outputs of all :ref:`apply` involving op1 by the outputs
of Apply nodes involving op2, where their inputs are the same.
* **OpRemove(op)**: removes all uses of op in the following way: if y
= op(x) then y is replaced by x. The op must have as many outputs as
it has inputs. The first output becomes the first input, the second
output becomes the second input, and so on.
* **PatternSub(pattern1, pattern2)**: replaces all occurrences of the
first pattern by the second pattern. See the api for
:api:`theano.gof.opt.PatternSub`.
.. code-block:: python
from theano.gof.opt import OpSub, OpRemove, PatternSub
# Replacing add by mul (this is not recommended for primarily
# mathematical reasons):
add_to_mul = OpSub(add, mul)
# Removing identity
remove_identity = OpRemove(identity)
# The "simplify" operation we've been defining in the past few
# sections. Note that we need two patterns to account for the
# permutations of the arguments to mul.
local_simplify_1 = PatternSub((div, (mul, 'x', 'y'), 'y'),
'x')
local_simplify_2 = PatternSub((div, (mul, 'x', 'y'), 'x'),
'y')
.. note::
OpSub, OpRemove and PatternSub produce local optimizers, which
means that everything we said previously about local optimizers
apply: they need to be wrapped in a Navigator, etc.
When an optimization can be naturally expressed using OpSub, OpRemove
or PatternSub, it is highly recommended to use them. Do note that they
WRITEME: more about using PatternSub (syntax for the patterns, how to
use constraints, etc. - there's some decent doc in the api
:api:`theano.gof.opt.PatternSub` for those interested)
.. _optdb:
The optimization database (optdb)
=================================
......@@ -265,14 +325,212 @@ you must insert it at the proper place in the database. Furthermore,
you can give each optimization in the database a set of tags that can
serve as a basis for filtering.
The point of optdb is that you might want to apply many optimizations
to a computation graph in many unique patterns. For example, you might
want to do optimization X, then optimization Y, then optimization
Z. And then maybe optimization Y is an EquilibriumOptimizer containing
LocalOptimizers A, B and C which are applied on every node of the
graph until they all fail to change it. If some optimizations act up,
we want an easy way to turn them off. Ditto if some optimizations are
very CPU-intensive and we don't want to take the time to apply them.
The optdb system allows us to tag each optimization with a unique name
as well as informative tags such as 'stable', 'buggy' or
'cpu_intensive', all this without compromising the structure of the
optimizations.
Definition of optdb
-------------------
optdb is an object which is an instance of ``theano.gof.SequenceDB``,
itself a subclass of ``theano.gof.DB``. There exist (for now) two
types of DB, SequenceDB and EquilibriumDB. When given an appropriate
Query, DB objects build an Optimizer matching the query.
A SequenceDB contains Optimizer or DB objects. Each of them has a
name, an arbitrary number of tags and an integer representing their
order in the sequence. When a Query is applied to a SequenceDB, all
Optimizers whose tags match the query are inserted in proper order in
a SequenceOptimizer, which is returned. If the SequenceDB contains DB
instances, the Query will be passed to them as well and the optimizers
they return will be put in their places.
An EquilibriumDB contains LocalOptimizer or DB objects. Each of them
has a name and an arbitrary number of tags. When a Query is applied to
an EquilibriumDB, all LocalOptimizers that match the query are
inserted into an EquilibriumOptimizer, which is returned. If the
SequenceDB contains DB instances, the Query will be passed to them as
well and the LocalOptimizers they return will be put in their places
(note that as of yet no DB can produce LocalOptimizer objects, so this
is a moot point).
Theano contains one principal DB object, ``theano.optdb`` which
contains all of Theano's optimizers with proper tags. It is
recommended to insert new Optimizers in it. As mentioned previously,
optdb is a SequenceDB, so at the top level Theano applies a sequence
of global optimizations to the computation graphs.
Query
-----
A Query is built by the following call:
theano.gof.Query(include, require = None, exclude = None, subquery = None)
* **include**: a set of tags (a tag being a string) such that every
optimization obtained through this Query must have **one** of the
tags listed. This field is required and basically acts as a
starting point for the search.
* **require**: a set of tags such that every optimization obtained
through this Query must have **all** of these tags.
* **exclude**: a set of tags such that every optimization obtained
through this Query must have **none** of these tags.
* **subquery**: optdb can contain sub-databases; subquery is a
dictionary mapping the name of a sub-database to a special Query.
If no subquery is given for a sub-database, the original Query
will be used again.
Furthermore, a Query object includes three methods, ``including``,
``requiring`` and ``excluding`` which each produce a new Query object
with include, require and exclude sets refined to contain the new
Examples
--------
Here are a few examples of how to use a Query on optdb to produce an
Optimizer:
.. code-block:: python
# This is how the optimizer for the fast_run mode is defined
fast_run = optdb.query(Query(include = ['fast_run']))
# This is how the optimizer for the fast_compile mode is defined
fast_compile = optdb.query(Query(include = ['fast_compile']))
# This is the same as fast_run but no optimizations will replace
# any operation by an inplace version. This assumes, of course,
# that all inplace operations are tagged as 'inplace' (as they
# should!)
fast_run_no_inplace = optdb.query(Query(include = ['fast_run'], exclude = ['inplace']))
fast_run_no_inplace = fast_run.excluding('inplace')
Registering an Optimizer
------------------------
Let's say we have a global optimizer called ``simplify``. We can add
it to ``optdb`` as follows:
.. code-block:: python
# optdb.register(name, optimizer, order, *tags)
optdb.register('simplify', simplify, 0.5, 'fast_run')
Once this is done, the FAST_RUN mode will automatically include your
optimization (since you gave it the 'fast_run' tag). Of course,
already-compiled functions will see no change. The 'order' parameter
(what it means and how to choose it) will be explained in another
section below.
Registering a LocalOptimizer
----------------------------
LocalOptimizers may be registered in two ways:
* Wrap them in a Navigator and insert them like a global optimizer
(see previous section).
* Put them in an EquilibriumDB.
Theano defines two EquilibriumDBs where you can put local
optimizations:
* **canonicalize**: this contains optimizations that aim to *simplify*
the graph:
* Replace rare or esoterical operations with their equivalents using
elementary operations.
* Order operations in a canonical way (any sequence of
multiplications and divisions can be rewritten to contain at most
one division, for example; x*x can be rewritten x**2; etc.)
* Fold constants (Constant(2)*Constant(2) becomes Constant(4))
* **specialize**: this contains optimizations that aim to *specialize*
the graph:
* Replace a combination of operations with a special operation that
does the same thing (but better).
For each group, all optimizations of the group that are selected by
the Query will be applied on the graph over and over again until none
of them is applicable, so keep that in mind when designing it: check
carefully that your optimization leads to a fixpoint (a point where it
cannot apply anymore) at which point it returns False to indicate its
job is done. Also be careful not to undo the work of another local
optimizer in the group, because then the graph will oscillate between
two or more states and nothing will get done.
optdb structure
---------------
optdb contains the following Optimizers and sub-DBs, with the given
priorities and tags:
+-------+---------------------+------------------------------+
| Order | Name | Description |
+=======+=====================+==============================+
| 0 | merge1 | First merge operation |
+-------+---------------------+------------------------------+
| 1 | canonicalize | Simplify the graph |
+-------+---------------------+------------------------------+
| 2 | specialize | Add specialized operations |
+-------+---------------------+------------------------------+
| 49 | merge2 | Second merge operation |
+-------+---------------------+------------------------------+
| 49.5 | add_destroy_handler | Enable inplace optimizations |
+-------+---------------------+------------------------------+
| 100 | merge3 | Third merge operation |
+-------+---------------------+------------------------------+
The merge operations are meant to put together parts of the graph that
represent the same computation. Since optimizations can modify the
graph in such a way that two previously different-looking parts of the
graph become similar, we merge at the beginning, in the middle and at
the very end. Technically, we only really need to do it at the end,
but doing it in previous steps reduces the size of the graph and
therefore increases the efficiency of the process.
See previous section for more information about the canonicalize and
specialize steps.
The ``add_destroy_handler`` step is not really an optimization. It is
a marker. Basically:
.. warning::
Using PatternSub
================
Any optimization which inserts inplace operations in the
computation graph must appear **after** the ``add_destroy_handler``
"optimizer". In other words, the priority of any such optimization
must be **>= 50**. Failure to comply by this restriction can lead
to the creation of incorrect computation graphs.
The reason the destroy handler is not inserted at the beginning is
that it is costly to run. It is cheaper to run most optimizations
under the assumption there are no inplace operations.
Inplace optimizations
=====================
......@@ -47,6 +47,9 @@ Glossary of terminology
constant
WRITEME
dynamic
WRITEME
elementwise
An elementwise operation ``f`` on two matrices ``M`` and ``N``
is one such that:
......@@ -84,6 +87,9 @@ Glossary of terminology
pure
WRITEME
static
WRITEME
type
WRITEME
......@@ -208,11 +214,11 @@ Glossary of terminology
compilation stage
:term:`Env`, in particular `replace()
<http://lgcm.iro.umontreal.ca/epydoc/theano.gof.env.Env-class.html#replace
<http://pylearn.org/epydoc/theano.gof.env.Env-class.html#replace
replace()>`_
See also `Optimizer
<http://lgcm.iro.umontreal.ca/epydoc/theano.gof.opt.Optimizer-class.html>`_,
<http://pylearn.org/epydoc/theano.gof.opt.Optimizer-class.html>`_,
which is the base interface for writing transformers, such as
:term:`optimizations <Optimization>` and :term:`stabilizations
<Stabilization>`.
......@@ -236,12 +242,12 @@ Glossary of terminology
a type of operation. Instance is TOI
:term:`Op` is an abstract class (`Op API
<http://lgcm.iro.umontreal.ca/epydoc/theano.gof.op.Op-class.html>`_)
<http://pylearn.org/epydoc/theano.gof.op.Op-class.html>`_)
that documents the interface for theano's data
transformations. It has many subclasses, such as `sparse Dot
<http://lgcm.iro.umontreal.ca/epydoc/theano.sparse.Dot-class.html>`_.
<http://pylearn.org/epydoc/theano.sparse.Dot-class.html>`_.
and `Shape
<http://lgcm.iro.umontreal.ca/epydoc/theano.tensor.Shape-class.html>`_.
<http://pylearn.org/epydoc/theano.tensor.Shape-class.html>`_.
Comparing with the Python language, :term:`Op` is theano's
......@@ -270,7 +276,7 @@ Glossary of terminology
a Type-related graph node (a variable)
A Variable
(`Variable API <http://lgcm.iro.umontreal.ca/epydoc/theano.gof.graph.Variable-class.html>`_)
(`Variable API <http://pylearn.org/epydoc/theano.gof.graph.Variable-class.html>`_)
is theano's variable. It symbolically represents a value (which
can be a number, vector, matrix, tensor, etc.).
The inputs and outputs of every :term:`Op` are Variable instances.
......@@ -351,7 +357,7 @@ Glossary of terminology
Tensor
Type for vectors, matrices, etc.
Tensor (`Tensor API <http://lgcm.iro.umontreal.ca/epydoc/theano.tensor.Tensor-class.html doc>`_) is a class
Tensor (`Tensor API <http://pylearn.org/epydoc/theano.tensor.Tensor-class.html doc>`_) is a class
that derives from :term:`Type`. It is the symbolic type for ``numpy.ndarray``.
The main properties that distinguish one Tensor instance from another are:
......@@ -363,7 +369,7 @@ Glossary of terminology
TensorVariable
:term:`Variables <Variable>` of type :term:`Tensor` are of class
TensorVariable (`TensorVariable API <http://lgcm.iro.umontreal.ca/epydoc/theano.tensor.TensorVariable-class.html>`_).
TensorVariable (`TensorVariable API <http://pylearn.org/epydoc/theano.tensor.TensorVariable-class.html>`_).
``TensorVariable`` adds operator overloading so that ``TensorVariable`` instances can be used
in mathematical expressions. When any input to an expression is a ``TensorVariable`` then the
expression will evaluate to an ``TensorVariable`` and a :term:`graph` corresponding to
......@@ -416,7 +422,7 @@ Glossary of terminology
Type
:term:`Variables <Variable>` are strongly typed by :term:`Type` instances
`theano.Type <http://lgcm.iro.umontreal.ca/epydoc/theano.gof.type.Type-class.html>`_
`theano.Type <http://pylearn.org/epydoc/theano.gof.type.Type-class.html>`_
is an important abstract class in the creation and compilation of theano graphs.
Type instances are mainly responsible for two things:
......@@ -427,15 +433,15 @@ Glossary of terminology
Theano comes with several subclasses of ``theano.type`` such as:
* Generic (`Generic API <http://lgcm.iro.umontreal.ca/epydoc/theano.gof.type.Generic-class.html>`_) - for any python type
* Generic (`Generic API <http://pylearn.org/epydoc/theano.gof.type.Generic-class.html>`_) - for any python type
* :term:`Tensor` - for numpy.ndarray
* Sparse (`Sparse API <http://lgcm.iro.umontreal.ca/epydoc/theano.sparse.Sparse-class.html>`_) - for scipy.sparse
* Sparse (`Sparse API <http://pylearn.org/epydoc/theano.sparse.Sparse-class.html>`_) - for scipy.sparse
You can create more type instances if you like (see :ref:`HowtoCreateType`).
The C code interface methods of
``theano.Type`` are described in `docstrings
<http://lgcm.iro.umontreal.ca/epydoc/theano.gof.type.Type-class.html>`_,
<http://pylearn.org/epydoc/theano.gof.type.Type-class.html>`_,
see :ref:`CodeGeneration` for a more general intro to how C code is generated.
See also :term:`Theano type instance (TTI) <TTI>`.
......@@ -444,7 +450,7 @@ Glossary of terminology
Value
:term:`Value` (`Value API <http://lgcm.iro.umontreal.ca/epydoc/theano.gof.graph.Value-class.html doc>`_)
:term:`Value` (`Value API <http://pylearn.org/epydoc/theano.gof.graph.Value-class.html doc>`_)
and :term:`Constant` are subclasses of
:term:`Variable`, which means they serve more or less the
same purpose. There is however one important difference:
......
......@@ -74,7 +74,7 @@ Hacking Theano
- Send us your work as a patch to `theano-dev`_ or commit directly to the trunk.
.. _theano-dev: http://groups.google.com/group/theano-dev?pli=1
.. _task list: http://lgcm.iro.umontreal.ca/theano/query?status=accepted&status=assigned&status=new&status=reopened&group=milestone&max=200&col=id&col=summary&col=status&col=owner&col=type&col=priority&col=component&col=time&report=9&order=priority
.. _task list: http://pylearn.org/theano/query?status=accepted&status=assigned&status=new&status=reopened&group=milestone&max=200&col=id&col=summary&col=status&col=owner&col=type&col=priority&col=component&col=time&report=9&order=priority
.. _reStructuredText: http://docutils.sourceforge.net/rst.html
......
......@@ -64,10 +64,10 @@ I advise to never import theano's files from outside theano itself (and I think
When you install a package, only the package name can be imported directly. If you want a sub-package, you must import it from the main package. That's how it will work in 99.9% of installs because it is the default. Therefore, if you stray from this practice, your code will not be portable. Also, some ways to circumvent circular dependencies might make it so you have to import files in a certain order, which is best handled by the package's own __init__.py.
.. _non-basic python: http://lgcm.iro.umontreal.ca/theano/wiki/NonbasicPython
.. _non-basic python: http://pylearn.org/theano/wiki/NonbasicPython
.. _reStructuredText: http://docutils.sourceforge.net/rst.html
.. _epydoc: http://epydoc.sourceforge.net/
.. _basicnumpy: http://lgcm.iro.umontreal.ca/theano/wiki/BasicNumpy
.. _basicnumpy: http://pylearn.org/theano/wiki/BasicNumpy
.. _README: ../README.html
......@@ -75,6 +75,6 @@ When you install a package, only the package name can be imported directly. If y
.. _Documentation: index.html
.. _Wiki: http://pylearn.org/theano
.. _TRAC: http://trac.edgewall.org/
.. _task list: http://lgcm.iro.umontreal.ca/theano/query?status=accepted&status=assigned&status=new&status=reopened&group=milestone&max=200&col=id&col=summary&col=status&col=owner&col=type&col=priority&col=component&col=time&report=9&order=priority
.. _task list: http://pylearn.org/theano/query?status=accepted&status=assigned&status=new&status=reopened&group=milestone&max=200&col=id&col=summary&col=status&col=owner&col=type&col=priority&col=component&col=time&report=9&order=priority
......@@ -75,7 +75,7 @@ How documentation is auto-built on push
When you push to the main repository, the following file is run::
projects@lgcm:~/repos/theano/.hg/refresh-epydoc.sh
projects@pylearn.org:~/repos/theano/.hg/refresh-epydoc.sh
It calls ``epydoc`` and ``sphinx`` on the code.
......
......@@ -167,6 +167,6 @@ mailing list.
.. _theano-users: http://groups.google.com/group/theano-users?pli=1
.. _theano-dev: http://groups.google.com/group/theano-dev?pli=1
.. _task list: http://lgcm.iro.umontreal.ca/theano/query?status=accepted&status=assigned&status=new&status=reopened&group=milestone&max=200&col=id&col=summary&col=status&col=owner&col=type&col=priority&col=component&col=time&report=9&order=priority
.. _task list: http://pylearn.org/theano/query?status=accepted&status=assigned&status=new&status=reopened&group=milestone&max=200&col=id&col=summary&col=status&col=owner&col=type&col=priority&col=component&col=time&report=9&order=priority
......@@ -498,21 +498,21 @@ class PatternSub(LocalOptimizer):
arbitrary criterion.
Examples:
PatternOptimizer((add, 'x', 'y'), (add, 'y', 'x'))
PatternOptimizer((multiply, 'x', 'x'), (square, 'x'))
PatternOptimizer((subtract, (add, 'x', 'y'), 'y'), 'x')
PatternOptimizer((power, 'x', Constant(double, 2.0)), (square, 'x'))
PatternOptimizer((boggle, {'pattern': 'x',
PatternSub((add, 'x', 'y'), (add, 'y', 'x'))
PatternSub((multiply, 'x', 'x'), (square, 'x'))
PatternSub((subtract, (add, 'x', 'y'), 'y'), 'x')
PatternSub((power, 'x', Constant(double, 2.0)), (square, 'x'))
PatternSub((boggle, {'pattern': 'x',
'constraint': lambda env, expr: expr.type == scrabble}),
(scrabble, 'x'))
"""
def __init__(self, in_pattern, out_pattern, allow_multiple_clients = False):
"""
Creates a PatternOptimizer that replaces occurrences of
Creates a PatternSub that replaces occurrences of
in_pattern by occurrences of out_pattern.
If allow_multiple_clients is False, he pattern matching will
If allow_multiple_clients is False, the pattern matching will
fail if one of the subpatterns has more than one client.
"""
self.in_pattern = in_pattern
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论