提交 f5ca76a8 authored 作者: Olivier Breuleux's avatar Olivier Breuleux

merge

.. _function:
==================
function interface
==================
WRITEME
.. _advanced: .. _advanced:
=============== ====================================
Advanced Topics Advanced Topics (under construction)
=============== ====================================
.. toctree:: .. toctree::
:maxdepth: 2 :maxdepth: 2
pipeline env
unittest features
profilemode optimization
debug_faq compilation
debugmode ccodegen
module_vs_op function
randomstreams module
.. env
.. features
.. optimization
.. compilation
.. ccodegen
.. function
.. module
====================
Making the cons type
====================
WRITEME
...@@ -26,21 +26,23 @@ What needs to be defined ...@@ -26,21 +26,23 @@ What needs to be defined
There are less methods to define for an Op than for a Type: There are less methods to define for an Op than for a Type:
- **c_code(node, name, input_names, output_names, sub)** .. function:: c_code(node, name, input_names, output_names, sub)
- This must return C code that carries the computation we want to This must return C code that carries the computation we want to do.
do.
- **c_code_cleanup(node, name, input_names, output_names, sub)** .. function:: c_code_cleanup(node, name, input_names, output_names, sub)
- This must return C code that cleans up whatever c_code allocated This must return C code that cleans up whatever c_code allocated and
and that we must free. that we must free.
- *Default* The default behavior is to do nothing. *Default* The default behavior is to do nothing.
- **c_compile_args(), c_headers(), c_libraries(), c_support_code()** .. function:: c_compile_args()
c_headers()
c_libraries()
c_support_code()
- Allows you to specify headers, libraries, special g++ arguments or Allows you to specify headers, libraries, special g++ arguments or
helper functions/structs that the type needs. See :ref:`op`. helper functions/structs that the type needs. See :ref:`op`.
......
...@@ -46,37 +46,40 @@ be found in the documentation for :ref:`type`. Here, we'll focus on ...@@ -46,37 +46,40 @@ be found in the documentation for :ref:`type`. Here, we'll focus on
the most important ones: the most important ones:
- **c_declare(name, sub)** .. function:: c_declare(name, sub)
- This must return C code which declares variables. These variables This must return C code which declares variables. These variables
will be available to operations defined in C. You may also write will be available to operations defined in C. You may also write
typedefs. typedefs.
- **c_init(name, sub)** .. function:: c_init(name, sub)
- This must return C code which initializes the variables declared This must return C code which initializes the variables declared in
in c_declare. Either this or c_extract will be called. c_declare. Either this or c_extract will be called.
- **c_extract(name, sub)** .. function:: c_extract(name, sub)
- This must return C code which takes a reference to a Python object This must return C code which takes a reference to a Python object
and initializes the variables declared in c_declare to match the and initializes the variables declared in c_declare to match the
Python object's data. Either this or c_init will be called. Python object's data. Either this or c_init will be called.
- **c_sync(name, sub)** .. function:: c_sync(name, sub)
- When the computations are done, transfer the variables from the C When the computations are done, transfer the variables from the C
structure we put them in to the destination Python object. This structure we put them in to the destination Python object. This will
will only be called for the outputs. only be called for the outputs.
- **c_cleanup(name, sub)** .. function:: c_cleanup(name, sub)
- When we are done using the data, clean up whatever we allocated When we are done using the data, clean up whatever we allocated and
and decrease the appropriate reference counts. decrease the appropriate reference counts.
- **c_compile_args(), c_headers(), c_libraries(), c_support_code()** .. function:: c_compile_args()
c_headers()
c_libraries()
c_support_code()
- Allows you to specify headers, libraries, special g++ arguments or Allows you to specify headers, libraries, special g++ arguments or
helper functions/structs that the type needs. See :ref:`type`. helper functions/structs that the type needs. See :ref:`type`.
......
...@@ -24,7 +24,7 @@ grounding for fundamental Theano concepts. ...@@ -24,7 +24,7 @@ grounding for fundamental Theano concepts.
.. toctree:: .. toctree::
theano_vs_python theano_vs_c
graphstructures graphstructures
type type
op op
......
...@@ -14,44 +14,46 @@ Op's contract ...@@ -14,44 +14,46 @@ Op's contract
An Op (:api:`gof.op.Op`) is any object which defines the following methods: An Op (:api:`gof.op.Op`) is any object which defines the following methods:
- **make_node(*inputs)**
- This method is responsible for creating output Variables of a suitable Type .. function:: make_node(*inputs)
to serve as the outputs of this Op's application. This method should put these
outputs into an Apply instance, and return the Apply instance.
- This method creates an Apply node representing the This method is responsible for creating output Variables of a
application of the Op on the inputs provided. If the Op cannot be suitable Type to serve as the outputs of this Op's application.
applied on these inputs, it must raise an appropriate This method should put these outputs into an Apply instance, and
exception. return the Apply instance.
- The inputs of the Apply instance returned by this call must be ordered This method creates an Apply node representing the application of
correctly: a subsequent ``self.make_node(*apply.inputs)`` must produce the Op on the inputs provided. If the Op cannot be applied on
something equivalent to the first ``apply``. these inputs, it must raise an appropriate exception.
- default_output The inputs of the Apply instance returned by this call must be
ordered correctly: a subsequent ``self.make_node(*apply.inputs)``
must produce something equivalent to the first ``apply``.
- *Default*: None ``default_output``
- If this member variable is an integer, then the default implementation of *Default*: None
``__call__`` will return `node.outputs[self.default_output]``, where
`node` was returned by ``make_node``. Otherwise, the entire list of
outputs will be returned.
- **__call__(*inputs)** If this member variable is an integer, then the default
implementation of ``__call__`` will return
`node.outputs[self.default_output]``, where `node` was returned
by ``make_node``. Otherwise, the entire list of outputs will be
returned.
- Syntactic shortcut to make_node which returns the output Variables .. function:: __call__(*inputs)
of the Op.
- *Default*: this is done for you by Op. Syntactic shortcut to make_node which returns the output
Variables of the Op.
- **perform(node, inputs, output_storage)** *Default*: this is done for you by Op.
- This method computes the function associated to this Op. The .. function:: perform(node, inputs, output_storage)
This method computes the function associated to this Op. The
``node`` is an Apply node created by the Op's ``make_node`` ``node`` is an Apply node created by the Op's ``make_node``
method, ``inputs`` is a list of references to data to operate on, method, ``inputs`` is a list of references to data to operate on,
and ``output_storage`` is a list of storage cells where the variables of and ``output_storage`` is a list of storage cells where the
the computation must be put. More specifically: variables of the computation must be put. More specifically:
- ``node``: This is a reference to an Apply node which was previously - ``node``: This is a reference to an Apply node which was previously
obtained via ``mul``'s ``make_node`` method. It is typically not obtained via ``mul``'s ``make_node`` method. It is typically not
...@@ -74,108 +76,70 @@ An Op (:api:`gof.op.Op`) is any object which defines the following methods: ...@@ -74,108 +76,70 @@ An Op (:api:`gof.op.Op`) is any object which defines the following methods:
None. This feature can allow perform to reuse memory between calls, for None. This feature can allow perform to reuse memory between calls, for
example. example.
- This method must be determined by the inputs. That is to say, if it is This method must be determined by the inputs. That is to say, if
evaluated once on inputs A and returned B, then if ever inputs C, equal to it is evaluated once on inputs A and returned B, then if ever
A, are presented again, then outputs equal to B must be returned again. inputs C, equal to A, are presented again, then outputs equal to
B must be returned again.
- You must be careful about aliasing outputs to inputs, and making
modifications to any of the inputs. See `Views and inplace operations
<views_and_inplace>`_
before writing a ``perform`` implementation that does either of these
things.
- **__eq__(self, other)** You must be careful about aliasing outputs to inputs, and making
modifications to any of the inputs. See `Views and inplace
operations <views_and_inplace>`_ before writing a ``perform``
implementation that does either of these things.
- ``other`` is also an Op. .. function:: __eq__(other)
- Returning ``True`` here is a promise to the optimization system that the other ``other`` is also an Op.
Op will produce exactly the same graph effects (from perform) as this one,
given identical inputs. This means it will produce the same output values,
it will destroy the same inputs (same destroy_map), and will alias outputs
to the same inputs (same view_map).
- **__hash__(self)** Returning ``True`` here is a promise to the optimization system
that the other Op will produce exactly the same graph effects
(from perform) as this one, given identical inputs. This means it
will produce the same output values, it will destroy the same
inputs (same destroy_map), and will alias outputs to the same
inputs (same view_map).
- If two Op instances compare equal, then they **must** return the same hash .. function:: __hash__()
value.
- Equally important, this hash value must not change during the lifetime of If two Op instances compare equal, then they **must** return the
self. Op instances should be immutable in this sense. same hash value.
- **__ne__(self, other)** Equally important, this hash value must not change during the
lifetime of self. Op instances should be immutable in this
sense.
- Recommended .. function:: __ne__(other)
- Default: ``(not (self==other))`` Default: ``(not (self==other))``
- **grad(inputs, output_gradients)** .. function:: grad(inputs, output_gradients)
- Optional. Optional.
- If the Op you are defining is differentiable, you can define its If the Op you are defining is differentiable, you can define its
gradient symbolically in this method. gradient symbolically in this method.
- Both the ``inputs`` and ``output_gradients`` will be Variables. This Both the ``inputs`` and ``output_gradients`` will be
method must return a list containing one Variable (or None) for each Variables. This method must return a list containing one Variable
input. Each returned Variable represents the gradient with respect to (or None) for each input. Each returned Variable represents the
that input given the symbolic gradients with respect to each output. gradient with respect to that input given the symbolic gradients
with respect to each output.
- If the output is not differentiable with respect to any inputs, then this If the output is not differentiable with respect to any inputs,
method should be defined to return [None for i in inputs]. then this method should be defined to return [None for i in
inputs].
- If this method is not defined, then theano assumes it has been forgotten. If this method is not defined, then theano assumes it has been
Symbolic differentiation will fail on a graph that includes this Op. forgotten. Symbolic differentiation will fail on a graph that
includes this Op.
- For more information on the use of this method, see ``grad``. For more information on the use of this method, see ``grad``.
For each method, the *default* is what :api:`theano.gof.op.Op` defines For each method, the *default* is what :api:`theano.gof.op.Op` defines
for you. At a bare minimum, a new Op must define ``make_node`` and for you. At a bare minimum, a new Op must define ``make_node`` and
``perform``, which have no defaults. ``perform``, which have no defaults.
For more details, including the interface for providing a C implementation of For more details, including the interface for providing a C
perform(), refer to the documentation for :ref:`op`. implementation of perform(), refer to the documentation for :ref:`op`.
Checklist
---------
Use this list to make sure that you defined everything you need for your Op:
* Are there parameters that are not inputs but parametrize the behavior of your Op? (see parametrization section below)
* Yes?
* Define ``__init__`` with those parameters. They will be instance variables.
* Override ``__eq__``, ``__ne__`` and ``__hash__`` (optional)
* Consider making pre-made instances for common parameters. This will simplify usage.
* No? (usual case for simple Ops)
* Consider making a singleton of your Op (this can be as simple as
``my_op = MyOp()``). This will save you from having to implement __eq__
and company. The singleton approach does not work when an Op instance
has parameters (Did you pass anything to __init__?)
* Always define *make_node* (see make_node section below).
* Always define *perform* (see perform section below).
* Do you need performance only C can offer?
* Define *c_code* and *c_code_cleanup* (see HowtoMakeCeeOps)
* Remember to use the 'c' or 'c|py' linker on graphs using your Op! [*This is described where?*]
* Is your Op differentiable? Do you want to use it in differentiable
expressions?
* Define *grad* (see grad section below)
* Does your Op modify any of its inputs?
* *IMPORTANT:* read the destroyers and viewers section.
* Does any output from the Op share any sort of state with an input?
* *IMPORTANT:* read the destroyers and viewers section.
* Does your Op have more than one output?
* Consider setting the default_output attribute to the index of that output. (It will make your Op usable in ``PatternOptimizers``, and make user code look like the Op has only that output.)
[*Consider changing the order of the checklist above and the sections below such that the stuff you ALWAYS have to do, which is the most basic stuff anyhow, goes towards the top.*]
Defining an Op: ``mul`` Defining an Op: ``mul``
...@@ -259,28 +223,6 @@ Here, ``z`` is a list of one element. By default, ``z == [None]``. ...@@ -259,28 +223,6 @@ Here, ``z`` is a list of one element. By default, ``z == [None]``.
that a Python ``float`` must be put there. You should not put, say, an that a Python ``float`` must be put there. You should not put, say, an
``int`` in ``z[0]`` because Theano assumes Ops handle typing properly. ``int`` in ``z[0]`` because Theano assumes Ops handle typing properly.
**eq** and **hash**
Correct implementations of eq and hash permit Theano to recognize one
of the most obvious opportunities
for optimization: not repeatedly computing the same thing.
.. code-block:: python
def __eq__(self, other):
return type(self) == type(other) and (self.name == other.name) and (self.fn == other.fn)
def __hash__(self):
return hash(type(self)) ^ hash(self.name) ^ hash(self.fn)
When theano compiles a graph, most Modes first :term:`merge` the graph (this is
done by the :api:`MergeOptimizer`.) The principle of merging is that if the
inputs to two different :ref:`Applies <apply>` are identical and the :ref:`op`s
applied to them compare equal, then those two Apply instances are guaranteed to
produce the same outputs.
So Theano will only compute one of them.
Trying out our new Op Trying out our new Op
===================== =====================
......
...@@ -38,23 +38,23 @@ Global optimization ...@@ -38,23 +38,23 @@ Global optimization
A global optimization (or optimizer) is an object which defines the following A global optimization (or optimizer) is an object which defines the following
methods: methods:
- **apply(env)** .. function:: apply(env)
- This method takes an Env object which contains the computation This method takes an Env object which contains the computation graph
graph and does modifications in line with what the optimization is and does modifications in line with what the optimization is meant
meant to do. This is of the main method of the optimizer. to do. This is of the main method of the optimizer.
- **add_requirements(env)** .. function:: add_requirements(env)
- This method takes an Env object and adds :ref:`features This method takes an Env object and adds :ref:`features
<envfeature>` to it. These features are "plugins" that are needed <envfeature>` to it. These features are "plugins" that are needed
for the apply method to do its job properly. for the apply method to do its job properly.
- **optimize(env)** .. function:: optimize(env)
- This is the interface function called by Theano. This is the interface function called by Theano.
- *Default:* this is defined by Optimizer as ``add_requirement(env); *Default:* this is defined by Optimizer as ``add_requirement(env);
apply(env)``. apply(env)``.
See the section about :ref:`env` to understand how to define these See the section about :ref:`env` to understand how to define these
...@@ -66,9 +66,9 @@ Local optimization ...@@ -66,9 +66,9 @@ Local optimization
A local optimization is an object which defines the following methods: A local optimization is an object which defines the following methods:
- **transform(node)** .. function:: transform(node)
- This method takes an :ref:`apply` node and returns either False to This method takes an :ref:`apply` node and returns either False to
signify that no changes are to be done or a list of Variables which signify that no changes are to be done or a list of Variables which
matches the length of the node's ``outputs`` list. When the matches the length of the node's ``outputs`` list. When the
LocalOptimizer is applied by a Navigator, the outputs of the node LocalOptimizer is applied by a Navigator, the outputs of the node
...@@ -380,21 +380,21 @@ A Query is built by the following call: ...@@ -380,21 +380,21 @@ A Query is built by the following call:
theano.gof.Query(include, require = None, exclude = None, subquery = None) theano.gof.Query(include, require = None, exclude = None, subquery = None)
* **include**: a set of tags (a tag being a string) such that every **include**: a set of tags (a tag being a string) such that every
optimization obtained through this Query must have **one** of the optimization obtained through this Query must have **one** of the tags
tags listed. This field is required and basically acts as a listed. This field is required and basically acts as a starting point
starting point for the search. for the search.
* **require**: a set of tags such that every optimization obtained **require**: a set of tags such that every optimization obtained
through this Query must have **all** of these tags. through this Query must have **all** of these tags.
* **exclude**: a set of tags such that every optimization obtained **exclude**: a set of tags such that every optimization obtained
through this Query must have **none** of these tags. through this Query must have **none** of these tags.
* **subquery**: optdb can contain sub-databases; subquery is a **subquery**: optdb can contain sub-databases; subquery is a
dictionary mapping the name of a sub-database to a special Query. dictionary mapping the name of a sub-database to a special Query. If
If no subquery is given for a sub-database, the original Query no subquery is given for a sub-database, the original Query will be
will be used again. used again.
Furthermore, a Query object includes three methods, ``including``, Furthermore, a Query object includes three methods, ``including``,
``requiring`` and ``excluding`` which each produce a new Query object ``requiring`` and ``excluding`` which each produce a new Query object
...@@ -454,8 +454,8 @@ Theano defines two EquilibriumDBs where you can put local ...@@ -454,8 +454,8 @@ Theano defines two EquilibriumDBs where you can put local
optimizations: optimizations:
* **canonicalize**: this contains optimizations that aim to *simplify* **canonicalize**: this contains optimizations that aim to *simplify*
the graph: the graph:
* Replace rare or esoterical operations with their equivalents using * Replace rare or esoterical operations with their equivalents using
elementary operations. elementary operations.
...@@ -467,8 +467,8 @@ optimizations: ...@@ -467,8 +467,8 @@ optimizations:
* Fold constants (Constant(2)*Constant(2) becomes Constant(4)) * Fold constants (Constant(2)*Constant(2) becomes Constant(4))
* **specialize**: this contains optimizations that aim to *specialize* **specialize**: this contains optimizations that aim to *specialize*
the graph: the graph:
* Replace a combination of operations with a special operation that * Replace a combination of operations with a special operation that
does the same thing (but better). does the same thing (but better).
......
.. _theano_vs_python: .. _theano_vs_c:
====================== ============
Theano vs. Python Theano vs. C
====================== ============
We describe some of the patterns in Theano, and present their closest We describe some of the patterns in Theano, and present their closest
analogue in Python: analogue in a statically typed language such as C:
=============== =========================================================== =============== ===========================================================
Theano Python Theano C
=============== =========================================================== =============== ===========================================================
Apply function application / function call Apply function application / function call
Variable function data / variable Variable function data / variable
...@@ -17,3 +17,25 @@ Op operations carried out in computation / function definition ...@@ -17,3 +17,25 @@ Op operations carried out in computation / function definition
Type data types Type data types
Module ??? class? Module ??? class?
=============== =========================================================== =============== ===========================================================
For example:
.. code-block:: c
int main(int a) {
int b = 3;
int c = f(b)
return g(a, c);
}
Based on this code snippet, we can relate f and g to Ops, a, b and c
to Variables, g(a, c) and f(b) (taken as meaning the action of
computing f or g on their respective inputs) to Applies. Lastly, int
could be interpreted as the Theano Type of the Variables a and b.
...@@ -22,9 +22,9 @@ i.e. the same default argument names and values. If you wish to add ...@@ -22,9 +22,9 @@ i.e. the same default argument names and values. If you wish to add
extra arguments to any of these methods, these extra arguments must have extra arguments to any of these methods, these extra arguments must have
default values. default values.
- **filter(value, strict=False)** .. function:: filter(value, strict=False)
- This casts a value to match the Type and returns the This casts a value to match the Type and returns the
casted value. If ``value`` is incompatible with the Type, casted value. If ``value`` is incompatible with the Type,
the method must raise an exception. If ``strict`` is True, ``filter`` must return a the method must raise an exception. If ``strict`` is True, ``filter`` must return a
reference to ``value`` (i.e. casting prohibited) reference to ``value`` (i.e. casting prohibited)
...@@ -33,58 +33,58 @@ default values. ...@@ -33,58 +33,58 @@ default values.
must be called ``strict`` (Theano often calls it by keyword) and must must be called ``strict`` (Theano often calls it by keyword) and must
have a default value of ``False``. have a default value of ``False``.
- **is_valid_value(value)** .. function:: is_valid_value(value)
- Returns True iff the value is compatible with the Type. If Returns True iff the value is compatible with the Type. If
``filter(value, strict = True)`` does not raise an exception, the ``filter(value, strict = True)`` does not raise an exception, the
value is compatible with the Type. value is compatible with the Type.
- *Default*: True iff ``filter(value, strict = True)`` does not raise an *Default*: True iff ``filter(value, strict = True)`` does not raise
exception. an exception.
- **values_eq(a, b)** .. function:: values_eq(a, b)
- Returns True iff ``a`` and ``b`` are equal. Returns True iff ``a`` and ``b`` are equal.
- *Default*: ``a == b`` *Default*: ``a == b``
- **values_eq_approx(a, b)** .. function:: values_eq_approx(a, b)
- Returns True iff ``a`` and ``b`` Returns True iff ``a`` and ``b`` are approximately equal, for a
are approximately equal, for a definition of "approximately" which definition of "approximately" which varies from Type to Type.
varies from Type to Type.
- *Default*: ``values_eq(a, b)`` *Default*: ``values_eq(a, b)``
- **make_variable(name=None)** .. function:: make_variable(name=None)
- Makes a :term:`Variable` of this Type with the specified name, if Makes a :term:`Variable` of this Type with the specified name, if
``name is not None``. If ``name is ``None``, then the Variable does ``name is not None``. If ``name is ``None``, then the Variable does
not have a name. The Variable will have its ``type`` field set to the not have a name. The Variable will have its ``type`` field set to
Type object. the Type object.
- *Default*: there is a generic definition of this in Type. The Variable's *Default*: there is a generic definition of this in Type. The
``type`` will be the object that defines this method (in other words, Variable's ``type`` will be the object that defines this method (in
``self``). other words, ``self``).
- **__call__(name=None)**: .. function:: __call__(name=None)
- Syntactic shortcut to ``make_variable``. Syntactic shortcut to ``make_variable``.
- *Default*: ``make_variable`` *Default*: ``make_variable``
- **__eq__(self, other)**: .. function:: __eq__(other)
- Used to compare Type instances themselves Used to compare Type instances themselves
- *Default*: ``object.__eq__`` *Default*: ``object.__eq__``
- **__hash__(self)**: .. function:: __hash__()
- Types should not be mutable, so it should be Ok to define a hash function. Types should not be mutable, so it should be Ok to define a hash
Typically this function should hash all of the terms involved in ``__eq__``. function. Typically this function should hash all of the terms
involved in ``__eq__``.
- *Default*: ``id(self)`` *Default*: ``id(self)``
For each method, the *default* is what ``Type`` defines For each method, the *default* is what ``Type`` defines
for you. So, if you create an instance of ``Type`` or an for you. So, if you create an instance of ``Type`` or an
......
...@@ -153,15 +153,16 @@ one. You can do it like this: ...@@ -153,15 +153,16 @@ one. You can do it like this:
>>> x, y = T.dscalars('x', 'y') >>> x, y = T.dscalars('x', 'y')
>>> z = x + y >>> z = x + y
>>> f = function([x, (y, 1)], z) >>> f = function([x, In(y, value = 1)], z)
>>> f(33) >>> f(33)
array(34.0) array(34.0)
>>> f(33, 2) >>> f(33, 2)
array(35.0) array(35.0)
The syntax is that if one of the elements in the list of inputs is a This makes use of the :ref:`In <function_inputs>` class which allows
pair, the input is the first element of the pair and the second you to specify properties of your inputs with greater detail. Here we
element is its default value. Here ``y``'s default value is set to 1. give a default value of 1 for ``y`` by creating an In instance with
its value field set to 1.
Inputs with default values should (must?) follow inputs without default Inputs with default values should (must?) follow inputs without default
values. There can be multiple inputs with default values. Defaults can values. There can be multiple inputs with default values. Defaults can
...@@ -169,7 +170,7 @@ be set positionally or by name, as in standard Python: ...@@ -169,7 +170,7 @@ be set positionally or by name, as in standard Python:
>>> x, y, w = T.dscalars('x', 'y', 'w') >>> x, y, w = T.dscalars('x', 'y', 'w')
>>> z = (x + y) * w >>> z = (x + y) * w
>>> f = function([x, (y, 1), (w, 2)], z) >>> f = function([x, In(y, value = 1), In(w, value = 2)], z)
>>> f(33) >>> f(33)
array(68.0) array(68.0)
>>> f(33, 2) >>> f(33, 2)
...@@ -180,8 +181,6 @@ array(33.0) ...@@ -180,8 +181,6 @@ array(33.0)
array(34.0) array(34.0)
>>> f(33, w=1, y=0) >>> f(33, w=1, y=0)
array(33.0) array(33.0)
>>> f(33, w=1, 2)
<type 'exceptions.SyntaxError'>: non-keyword arg after keyword arg (<ipython console>, line 1)
.. _functionstateexample: .. _functionstateexample:
...@@ -200,26 +199,21 @@ First let's define the accumulator function: ...@@ -200,26 +199,21 @@ First let's define the accumulator function:
>>> inc = T.scalar('inc') >>> inc = T.scalar('inc')
>>> state = T.scalar('state_name') >>> state = T.scalar('state_name')
>>> new_state = state + inc >>> new_state = state + inc
>>> accumulator = function([(inc, 1), ((state, new_state), 0)], new_state) >>> accumulator = function([In(inc, value = 1), In(state, value = 0, update = new_state)], new_state)
The first argument is a pair. As we saw in the previous section, this The first argument, as seen in the previous section, defines a default
means that ``inc`` is an input with a default value of 1. The second value of 1 for ``inc``. The second argument adds another argument to
argument has syntax that creates an internal state. The syntax is In, ``update``, which works as follows: every time ``accumulator`` is
``((state_variable, new_state_variable), initial_value)``. called, the value of the internal ``state`` will be replaced by the
The internal storage associated with ``state_variable`` is initialized to value computed as ``new_state``. In this case, the state will be
``initial_value``. Every time ``accumulator`` is called, the value replaced by the result of incrementing it by ``inc``.
of the internal ``state`` will be replaced by the value computed as
``new_state``. In this case, the state will be replaced by the variable
of incrementing it by ``inc``.
.. We recommend (insist?) that internal state arguments occur after any plain .. We recommend (insist?) that internal state arguments occur after any plain
arguments and arguments with default values. arguments and arguments with default values.
There is no limit to how many states you can have. You can add an There is no limit to how many states you can have and you can name
arbitrary number of elements to the input list which correspond to the them however you like as long as the name does not conflict with the
syntax described in the previous paragraph. You can name the states names of other inputs.
however you like as long as the name does not conflict with the names
of other inputs.
Anyway, let's try it out! The state can be accessed using the square Anyway, let's try it out! The state can be accessed using the square
brackets notation ``[]``. You may access the state either by using brackets notation ``[]``. You may access the state either by using
...@@ -255,5 +249,31 @@ array(5.9000000000000004) ...@@ -255,5 +249,31 @@ array(5.9000000000000004)
array(5.9000000000000004) array(5.9000000000000004)
Mode
====
The ``mode`` parameter to ``theano.function`` controls how the
inputs-to-outputs graph is transformed into a callable object.
Theano defines the following modes by name:
- ``FAST_COMPILE``: Apply just a few optimizations, but use C op implementations where possible.
- ``FAST_RUN``: Apply all optimizations, and use C op implementations where possible.
- ``DEBUG_MODE``: Verify the correctness of all optimizations, and compare C and python
implementations. This mode can take much longer than the other modes,
but can identify many kinds of problems.
The default mode is typically 'FAST_RUN', but it can be controlled via
the environment variable 'THEANO_DEFAULT_MODE', which can in turn be
overridden by setting ``theano.compile.mode.default_mode`` directly,
which can in turn be overridden by passing the keyword argument to
``theano.function``.
For a finer level of control over which optimizations are applied, and
whether C or python implementations are used, read
:api:`compile.mode.Mode`.
.. _automatic differentiation: http://en.wikipedia.org/wiki/Automatic_differentiation .. _automatic differentiation: http://en.wikipedia.org/wiki/Automatic_differentiation
...@@ -30,6 +30,5 @@ Now we're ready for the tour: ...@@ -30,6 +30,5 @@ Now we're ready for the tour:
adding adding
examples examples
function
module module
tools tools
...@@ -8,12 +8,13 @@ Contents ...@@ -8,12 +8,13 @@ Contents
.. toctree:: .. toctree::
:maxdepth: 2 :maxdepth: 2
LICENSE index
introduction introduction
LICENSE
install install
numpy
basic_tutorial/index basic_tutorial/index
advanced_tutorial/index advanced_tutorial/index
topics/index
advanced/index advanced/index
indexes/index indexes/index
glossary glossary
......
...@@ -144,9 +144,9 @@ Generating the documentation ...@@ -144,9 +144,9 @@ Generating the documentation
---------------------------- ----------------------------
You can read the latest HTML documentation `here You can read the latest HTML documentation `here
<http://pylearn.org/theano/contents.html>`_. <http://pylearn.org/theano/contents.html>`__.
You can download the latest PDF documentation `here You can download the latest PDF documentation `here
<http://pylearn.org/theano/theano.pdf`_. <http://pylearn.org/theano/theano.pdf`__.
We recommend you look at the documentation on the website, since it We recommend you look at the documentation on the website, since it
will be more current than the documentation included with the package. will be more current than the documentation included with the package.
......
...@@ -6,30 +6,32 @@ Introduction ...@@ -6,30 +6,32 @@ Introduction
============ ============
Theano is a Python library that allows you to define, optimize, and Theano is a Python library that allows you to define, optimize, and
efficiently evaluate mathematical expressions involving multi-dimensional efficiently evaluate mathematical expressions involving
arrays. Using Theano, it is not uncommon to see speed improvements of multi-dimensional arrays. Using Theano, for problems involving large
ten-fold over using pure NumPy. amounts of data, it is possible to attain speeds that are only a few
percentage points slower than hand-crafted C implementations.
Theano melds some aspects of a computer algebra system (CAS) with Theano melds some aspects of a computer algebra system (CAS) with
aspects of an optimizing compiler. It can even transform some or aspects of an optimizing compiler. It can even transform some or all
all of the mathematical expression into C code and compile it into of the mathematical expression into C code and compile it into native
native machine instructions. This combination of CAS with optimizing machine instructions. This combination of CAS with optimizing
compilation is particularly useful for computational fields in which compilation is particularly useful for tasks in which complicated
complicated mathematical expressions are evaluated repeatedly and evaluation mathematical expressions are evaluated repeatedly and evaluation speed
speed is critical. is critical.
Theano supports a range of numerical types in multiple dimensions and Theano supports a range of numerical types in multiple dimensions and
a number of well-tested operations. It also allows you to compute the a number of well-tested operations. It also allows you to compute the
gradient of an expression with respect to another. Symbolic expressions gradient of an expression with respect to another. Symbolic
may be compiled into functions, which work on the same data structures expressions may be compiled into functions, which work on the same
as numpy_, allowing for easy interoperability. data structures as numpy_, allowing for easy interoperability.
Theano's compiler applies many optimizations of varying complexity Theano's compiler applies many optimizations of varying complexity to
to these symbolic expressions. These optimizations include, but are these symbolic expressions. These optimizations include, but are not
not limited to: limited to:
* constant folding * constant folding
* merging of similar subgraphs, to avoid calculating the same values more than once * merging of similar subgraphs, to avoid calculating the same values
more than once
* arithmetic simplification (``x*y/x -> y``) * arithmetic simplification (``x*y/x -> y``)
* inserting efficient BLAS_ operations * inserting efficient BLAS_ operations
* using inplace operations wherever it is safe to do so. * using inplace operations wherever it is safe to do so.
...@@ -37,20 +39,18 @@ not limited to: ...@@ -37,20 +39,18 @@ not limited to:
Theano defines several optimizations which improve the numerical Theano defines several optimizations which improve the numerical
stability of computations. stability of computations.
Theano was written at the LISA_ lab to support the development Theano was written at the LISA_ lab to support the development of
of efficient machine learning algorithms while minimizing human time. We efficient machine learning algorithms while minimizing human time. We
use it especially in gradient-based learning techniques. use it especially in gradient-based learning techniques. Theano is
Theano is named after the `Greek mathematician`_, who may have named after the `Greek mathematician`_, who may have been Pythagoras'
been Pythagoras' wife. wife. Theano is released under a BSD license (:ref:`link <license>`)
Theano is released under a BSD license (:ref:`link <license>`)
Sneak peek Sneak peek
========== ==========
Here is an example of how to use Theano. It doesn't show Here is an example of how to use Theano. It doesn't show off many of
off many of Theano's features, but it illustrates concretely what Theano's features, but it illustrates concretely what Theano is.
Theano is.
.. code-block:: python .. code-block:: python
...@@ -73,8 +73,8 @@ Theano is. ...@@ -73,8 +73,8 @@ Theano is.
Theano is not a programming language in the normal sense because you Theano is not a programming language in the normal sense because you
write a program in Python that builds expressions for Theano. Still write a program in Python that builds expressions for Theano. Still it
it is like a programming language in the sense that you have to is like a programming language in the sense that you have to
- declare variables (``a,b``) and give their types - declare variables (``a,b``) and give their types
...@@ -119,7 +119,6 @@ Theano is a sort of hybrid of the two which tries to make the best of ...@@ -119,7 +119,6 @@ Theano is a sort of hybrid of the two which tries to make the best of
both worlds. both worlds.
Getting started Getting started
=============== ===============
...@@ -152,8 +151,8 @@ Questions, comments, praise, criticism as well as bug reports should ...@@ -152,8 +151,8 @@ Questions, comments, praise, criticism as well as bug reports should
be submitted to these mailing lists. be submitted to these mailing lists.
We welcome all kinds of contributions. If you have any questions We welcome all kinds of contributions. If you have any questions
regarding how to extend Theano, please feel free to ask on the theano-dev_ regarding how to extend Theano, please feel free to ask on the
mailing list. theano-dev_ mailing list.
......
...@@ -56,8 +56,9 @@ something that you're not seeing. ...@@ -56,8 +56,9 @@ something that you're not seeing.
I wrote a new optimization, but it's not getting used... I wrote a new optimization, but it's not getting used...
--------------------------------------------------------- ---------------------------------------------------------
Remember that you have to register optimizations with the OptDb, for them to get Remember that you have to register optimizations with the :ref:`optdb`
used by the normal modes like FAST_COMPILE, FAST_RUN, and DEBUG_MODE. for them to get used by the normal modes like FAST_COMPILE, FAST_RUN,
and DEBUG_MODE.
I wrote a new optimization, and it changed my results even though I'm pretty sure it is correct. I wrote a new optimization, and it changed my results even though I'm pretty sure it is correct.
...@@ -71,11 +72,13 @@ something that you're not seeing. ...@@ -71,11 +72,13 @@ something that you're not seeing.
The function I compiled is too slow, what's up? The function I compiled is too slow, what's up?
----------------------------------------------- -----------------------------------------------
First, make sure you're running in FAST_RUN mode, by passing ``mode='FAST_RUN'`` First, make sure you're running in FAST_RUN mode, by passing
to ``theano.function`` or ``theano.make``. ``mode='FAST_RUN'`` to ``theano.function`` or ``theano.make``. Some
operations have excruciatingly slow Python implementations and that
can negatively effect the performance of FAST_COMPILE.
Second, try the theano :ref:`profilemode`. This will tell you which Apply nodes, Second, try the theano :ref:`profilemode`. This will tell you which
and which Ops are eating up your CPU cycles. Apply nodes, and which Ops are eating up your CPU cycles.
.. _faq_wraplinker: .. _faq_wraplinker:
......
...@@ -41,6 +41,7 @@ In the example above, there is no way to guarantee that a future call to say, ...@@ -41,6 +41,7 @@ In the example above, there is no way to guarantee that a future call to say,
There following are DebugMode exceptions you might encounter: There following are DebugMode exceptions you might encounter:
BadCLinkerOutput BadCLinkerOutput
---------------- ----------------
...@@ -116,6 +117,7 @@ performed, but the plan is that it will be. (see ticket #320) ...@@ -116,6 +117,7 @@ performed, but the plan is that it will be. (see ticket #320)
For detailed documentation see :api:`FloatError`. For detailed documentation see :api:`FloatError`.
InvalidValueError InvalidValueError
----------------- -----------------
...@@ -126,6 +128,7 @@ Type. ...@@ -126,6 +128,7 @@ Type.
For detailed documentation see :api:`InvalidValueError`. For detailed documentation see :api:`InvalidValueError`.
DebugModeError DebugModeError
-------------- --------------
......
.. _function: .. _usingfunction:
=============== =====================
theano.function Using theano.function
=============== =====================
This page is about ``theano.function``, the interface for compiling graphs into callable objects. This page is about ``theano.function``, the interface for compiling graphs into callable objects.
...@@ -31,47 +31,35 @@ Inputs ...@@ -31,47 +31,35 @@ Inputs
The ``inputs`` argument to ``theano.function`` is a list, containing the ``Variable`` instances for which values will be specified at the time of the function call. But inputs can be more than just Variables. The ``inputs`` argument to ``theano.function`` is a list, containing the ``Variable`` instances for which values will be specified at the time of the function call. But inputs can be more than just Variables.
``In`` instances let us attach properties to ``Variables`` to tell function more about how to use them. ``In`` instances let us attach properties to ``Variables`` to tell function more about how to use them.
**In(variable, name=None, value=None, update=None, mutable=False)** returns an ``In`` instance:
- ``variable``: a Variable instance. .. class:: In
This will be assigned a value before running the function, .. function:: __init__(variable, name=None, value=None, update=None, mutable=False)
not computed from its owner.
- ``name``: Any type. (If autoname_input=True, defaults to variable.name). ``variable``: a Variable instance. This will be assigned a value
before running the function, not computed from its owner.
If name is a valid Python identifier, this input can be set by ``name``: Any type. (If autoname_input=True, defaults to
``kwarg``, and its value can be accessed by ``self.<name>``. variable.name). If name is a valid Python identifier, this input
can be set by ``kwarg``, and its value can be accessed by
``self.<name>``. The default value is ``None``
Default: ``None`` ``value``: literal or Container. This is the default value of
the Input. The default value of this parameter is ``None``
- ``value``: literal or Container ``update``: Variable instance. This expression Variable will
replace ``value`` after each function call. The default value is
``None``, indicating that no update is to be done.
This is the default value of the Input. ``mutable``: Bool (requires value). If ``True``, permit the
compiled function to modify the python object being used as the
default value. The default value is ``False``.
Default: ``None`` ``autoname``: Bool. If set to ``True``, if ``name`` is None and
the Variable has a name, it will be taken as the input's
name. If autoname is set to ``False``, the name is the exact
value passed as the name parameter (possibly ``None``).
- ``update``: Variable instance
This expression Variable will replace ``value`` after each function call.
Default: ``None``
- ``mutable``: Bool (requires value)
If ``True``, permit the compiled function to modify the python object being used as the default value.
Default: ``False``
- ``autoname``: Bool
``True``: if ``name`` is None and the Variable has a name, it will be taken
as the input's name.
``False``: the name is the exact value passed as the name parameter
(possibly ``None``).
Default: ???
Value: initial and default values Value: initial and default values
--------------------------------- ---------------------------------
......
.. _topics:
======
Topics
======
.. toctree::
:maxdepth: 2
function
pipeline
unittest
profilemode
debugmode
debug_faq
randomstreams
...@@ -17,20 +17,31 @@ First create a ProfileMode instance. ...@@ -17,20 +17,31 @@ First create a ProfileMode instance.
>>> from theano import ProfileMode >>> from theano import ProfileMode
>>> profmode = theano.ProfileMode(optimizer='fast_run', linker=theano.gof.OpWiseCLinker()) >>> profmode = theano.ProfileMode(optimizer='fast_run', linker=theano.gof.OpWiseCLinker())
The ProfileMode constructor takes as input an optimizer and a linker. Which optimizer The ProfileMode constructor takes as input an optimizer and a
and linker to use will depend on the application. For example, a user wanting linker. Which optimizer and linker to use will depend on the
to profile the Python implementation only, should use the gof.PerformLinker (or application. For example, a user wanting to profile the Python
"py" for short). On the other hand, a user wanting to profile his graph using implementation only, should use the gof.PerformLinker (or "py" for
c-implementations wherever possible should use the ``gof.OpWiseCLinker`` (or "c|py"). short). On the other hand, a user wanting to profile his graph using C
implementations wherever possible should use the ``gof.OpWiseCLinker``
(or "c|py").
In the same manner, modifying which optimizer is passed to ProfileMode In the same manner, modifying which optimizer is passed to ProfileMode
will decide which optimizations are applied to the graph, prior to will decide which optimizations are applied to the graph, prior to
profiling. Changing the optimizer should be especially useful when developing profiling. Changing the optimizer should be especially useful when
new graph optimizations, in order to evaluate their impact on performance. developing new graph optimizations, in order to evaluate their impact
on performance. Also keep in mind that optimizations might change the
Note that most users will want to use ProfileMode to optimize their graph and computation graph a lot, meaning that you might not recognize some of
find where most of the computation time is being spent. In this context, the operations that are profiled (you did not use them explicitly but
'fast_run' optimizer and ``gof.OpWiseCLinker`` are the most appropriate choices. an optimizer decided to use it to improve performance or numerical
stability). If you cannot easily relate the output of ProfileMode with
the computations you defined, you might want to try setting optimizer
to None (but keep in mind the computations will be slower than if they
were optimized).
Note that most users will want to use ProfileMode to optimize their
graph and find where most of the computation time is being spent. In
this context, 'fast_run' optimizer and ``gof.OpWiseCLinker`` are the
most appropriate choices.
Compiling your Graph with ProfileMode Compiling your Graph with ProfileMode
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...@@ -107,16 +118,20 @@ generates the following output: ...@@ -107,16 +118,20 @@ generates the following output:
""" """
The summary has two components to it. In the first section called the Apply-wise The summary has two components to it. In the first section called the
summary, timing information is provided for the worst offending Apply nodes. This Apply-wise summary, timing information is provided for the worst
corresponds to individual nodes within your graph which take the longest to offending Apply nodes. This corresponds to individual Op applications
execute. In the second portion, the Op-wise summary, the execution time of within your graph which take the longest to execute (so if you use
all Apply nodes executing the same Op are grouped together and the total ``dot`` twice, you will see two entries there). In the second portion,
execution time per Op is shown. the Op-wise summary, the execution time of all Apply nodes executing
the same Op are grouped together and the total execution time per Op
is shown (so if you use ``dot`` twice, you will see only one entry
there corresponding to the sum of the time spent in each of them).
Note that the ProfileMode also shows which Ops were running a c implementation. Note that the ProfileMode also shows which Ops were running a c
implementation.
Developers wishing to optimize the performance of their graph, should focus on the Developers wishing to optimize the performance of their graph, should
worst offending Ops. If no c-implementation exists for this op, consider writing focus on the worst offending Ops. If no C implementation exists for
a c-implementation yourself or use the mailing list, to suggest that a c-implementation this op, consider writing a C implementation yourself or use the
be provided. mailing list, to suggest that a C implementation be provided.
.. _unittest: .. _unittest:
=============== ============
Unit Testing Unit Testing
=============== ============
Theano relies heavily on unit testing. Its importance cannot be stressed enough ! Theano relies heavily on unit testing. Its importance cannot be
stressed enough!
Unit Testing revolves around the following principles: Unit Testing revolves around the following principles:
* ensuring correctness: making sure that your Op, Type or Optimization works in the way you intended it to work. It is important for this testing to be as thorough as possible: test not only the obvious cases, but more importantly the corner cases which are more likely to trigger bugs down the line. * ensuring correctness: making sure that your Op, Type or Optimization
* test all possible failure paths. This means testing that your code fails in the appropriate manner, by raising the correct errors when in certain situations. works in the way you intended it to work. It is important for this
* sanity check: making sure that everything still runs after you've done your modification. If your changes cause unit tests to start failing, it could be that you've changed an API on which other users rely on. It is therefore your responsibility to either a) provide the fix or b) inform the author of your changes and coordinate with that person to produce a fix. If this sounds like too much of a burden... then good ! APIs aren't meant to be changed on a whim ! testing to be as thorough as possible: test not only the obvious
cases, but more importantly the corner cases which are more likely
This page is in no way meant to replace tutorials on Python's unittest module, for this we refer the reader to the `official documentation <http://docs.python.org/library/unittest.html>`_. We will however adress certain specificities about how unittests relate to theano. to trigger bugs down the line.
* test all possible failure paths. This means testing that your code
fails in the appropriate manner, by raising the correct errors when
in certain situations.
* sanity check: making sure that everything still runs after you've
done your modification. If your changes cause unit tests to start
failing, it could be that you've changed an API on which other users
rely on. It is therefore your responsibility to either a) provide
the fix or b) inform the author of your changes and coordinate with
that person to produce a fix. If this sounds like too much of a
burden... then good! APIs aren't meant to be changed on a whim!
This page is in no way meant to replace tutorials on Python's unittest
module, for this we refer the reader to the `official documentation
<http://docs.python.org/library/unittest.html>`_. We will however
adress certain specificities about how unittests relate to theano.
Unittest Primer Unittest Primer
=============== ===============
A unittest is a subclass of ``unittest.TestCase``, with member functions with A unittest is a subclass of ``unittest.TestCase``, with member
names that start with the string ``test``. For example: functions with names that start with the string ``test``. For
example:
>>> class MyTestCase(unittest.TestCase): >>> class MyTestCase(unittest.TestCase):
>>> def test0(self): >>> def test0(self):
...@@ -34,15 +53,16 @@ names that start with the string ``test``. For example: ...@@ -34,15 +53,16 @@ names that start with the string ``test``. For example:
How to Run Unit Tests ? How to Run Unit Tests ?
----------------------- -----------------------
Two options are avaiable. Two options are available:
Nosetests Nosetests
~~~~~~~~~ ~~~~~~~~~
The easiest by far is to use ``nosetests`` which The easiest by far is to use ``nosetests`` which is a command line
is a command line utility that recurses through a given directory, finds all utility that recurses through a given directory, finds all unittests
unittests matching a specific criteria and executes them. By default, it will matching a specific criteria and executes them. By default, it will
find & execute tests case in test*.py files whose method name starts with 'test'. find & execute tests case in test*.py files whose method name starts
with 'test'.
Running all unit tests Running all unit tests
...@@ -64,11 +84,12 @@ Running a specific unit test ...@@ -64,11 +84,12 @@ Running a specific unit test
Using unittest module Using unittest module
~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~
To launch tests cases from within python, you can also use the functionality To launch tests cases from within python, you can also use the
offered by the ``unittest`` module. The simplest thing is to run all the tests in a file functionality offered by the ``unittest`` module. The simplest thing
using ``unittest.main()``. Python's built-in unittest module uses metaclasses is to run all the tests in a file using ``unittest.main()``. Python's
to know about all the ``unittest.TestCase`` classes you have created. This built-in unittest module uses metaclasses to know about all the
call will run them all, printing '.' for passed tests, and a stack trace for ``unittest.TestCase`` classes you have created. This call will run
them all, printing '.' for passed tests, and a stack trace for
exceptions. The standard footer code in theano's test files is: exceptions. The standard footer code in theano's test files is:
>>> if __name__ == '__main__': >>> if __name__ == '__main__':
...@@ -92,13 +113,15 @@ To run just a single ``MyTestCase`` member test function called ``test0``: ...@@ -92,13 +113,15 @@ To run just a single ``MyTestCase`` member test function called ``test0``:
Folder Layout Folder Layout
------------- -------------
"tests" directories are scattered throughout theano. Each tests subfolder is "tests" directories are scattered throughout theano. Each tests
meant to contain the unittests which validate the .py files in the parent folder. subfolder is meant to contain the unittests which validate the .py
files in the parent folder.
Files containing unittests should be prefixed with the word "test". Files containing unittests should be prefixed with the word "test".
Optimally every python module should have a unittest file associated with it, Optimally every python module should have a unittest file associated
as shown below. Unittests testing functionality of module <module>.py should therefore be stored in tests/test_<module>.py with it, as shown below. Unittests testing functionality of module
<module>.py should therefore be stored in tests/test_<module>.py
>>> Theano/theano/tensor/basic.py >>> Theano/theano/tensor/basic.py
>>> Theano/theano/tensor/elemwise.py >>> Theano/theano/tensor/elemwise.py
...@@ -112,20 +135,22 @@ How to Write a Unittest ...@@ -112,20 +135,22 @@ How to Write a Unittest
Test Cases and Methods Test Cases and Methods
---------------------- ----------------------
Unittests should be grouped "logically" into test cases, which are meant to Unittests should be grouped "logically" into test cases, which are
group all unittests operating on the same element and/or concept. Test cases meant to group all unittests operating on the same element and/or
are implemented as Python classes which inherit from unittest.TestCase concept. Test cases are implemented as Python classes which inherit
from unittest.TestCase
Test cases contain multiple test methods. These should be prefixed with the Test cases contain multiple test methods. These should be prefixed
word "test". with the word "test".
Test methods should be as specific as possible and cover a particular aspect Test methods should be as specific as possible and cover a particular
of the problem. For example, when testing the TensorDot Op, one test method aspect of the problem. For example, when testing the TensorDot Op, one
could check for validity, while another could verify that the proper errors test method could check for validity, while another could verify that
are raised when inputs have invalid dimensions. the proper errors are raised when inputs have invalid dimensions.
Test method names should be as explicit as possible, so that users can see at Test method names should be as explicit as possible, so that users can
first glance, what functionality is being tested and what tests need to be added. see at first glance, what functionality is being tested and what tests
need to be added.
Example: Example:
...@@ -136,10 +161,11 @@ Example: ...@@ -136,10 +161,11 @@ Example:
>>> def test_invalid_dims(self): >>> def test_invalid_dims(self):
>>> # do more stuff >>> # do more stuff
Test cases can define a special setUp method, which will get called before Test cases can define a special setUp method, which will get called
each test method is executed. This is a good place to put functionality which before each test method is executed. This is a good place to put
is shared amongst all test methods in the test case (i.e initializing data, functionality which is shared amongst all test methods in the test
parameters, seeding random number generators -- more on this later) case (i.e initializing data, parameters, seeding random number
generators -- more on this later)
>>> class TestTensorDot(unittest.TestCase): >>> class TestTensorDot(unittest.TestCase):
>>> def setUp(self): >>> def setUp(self):
...@@ -147,15 +173,16 @@ parameters, seeding random number generators -- more on this later) ...@@ -147,15 +173,16 @@ parameters, seeding random number generators -- more on this later)
>>> self.avals = numpy.array([[1,5,3],[2,4,1]]) >>> self.avals = numpy.array([[1,5,3],[2,4,1]])
>>> self.bvals = numpy.array([[2,3,1,8],[4,2,1,1],[1,4,8,5]]) >>> self.bvals = numpy.array([[2,3,1,8],[4,2,1,1],[1,4,8,5]])
Similarly, test cases can define a tearDown method, which will be implicitely Similarly, test cases can define a tearDown method, which will be
called at the end of each test method. implicitely called at the end of each test method.
Checking for correctness Checking for correctness
------------------------ ------------------------
When checking for correctness of mathematical expressions, the user should When checking for correctness of mathematical expressions, the user
preferably compare theano's output to the equivalent numpy implementation. should preferably compare theano's output to the equivalent numpy
implementation.
Example: Example:
...@@ -175,26 +202,34 @@ Avoid hard-coding variables, as in the following case: ...@@ -175,26 +202,34 @@ Avoid hard-coding variables, as in the following case:
>>> self.failUnless(numpy.all(f(self.avals,self.bvals)==numpy.array([[25,25,30,28],[21,18,14,25]]))) >>> self.failUnless(numpy.all(f(self.avals,self.bvals)==numpy.array([[25,25,30,28],[21,18,14,25]])))
This makes the test case less manageable and forces the user to update the This makes the test case less manageable and forces the user to update
variables each time the input is changed or possibly when the module being the variables each time the input is changed or possibly when the
tested changes (after a bug fix for example). It also constrains the test case module being tested changes (after a bug fix for example). It also
to specific input/output data pairs. The section on random values covers why this constrains the test case to specific input/output data pairs. The
might not be such a good idea. section on random values covers why this might not be such a good
idea.
Here is a list of useful functions, as defined by TestCase: Here is a list of useful functions, as defined by TestCase:
* checking the state of boolean variables: assert, failUnless, assertTrue, failIf, assertFalse * checking the state of boolean variables: assert, failUnless,
* checking for (in)equality constraints: assertEqual, failUnlessEqual, assertNotEqual, failIfEqual assertTrue, failIf, assertFalse
* checking for (in)equality constraints up to a given precision (very useful in theano): assertAlmostEqual, failUnlessAlmostEqual, assertNotAlmostEqual, failIfAlmostEqual
* checking for (in)equality constraints: assertEqual, failUnlessEqual,
assertNotEqual, failIfEqual
* checking for (in)equality constraints up to a given precision (very
useful in theano): assertAlmostEqual, failUnlessAlmostEqual,
assertNotAlmostEqual, failIfAlmostEqual
Checking for errors Checking for errors
------------------- -------------------
On top of verifying that your code provides the correct output, it is equally On top of verifying that your code provides the correct output, it is
important to test that it fails in the appropriate manner, raising the equally important to test that it fails in the appropriate manner,
appropriate exceptions, etc. Silent failures are deadly, as they can go unnoticed raising the appropriate exceptions, etc. Silent failures are deadly,
for a long time and a hard to detect "after-the-fact". as they can go unnoticed for a long time and a hard to detect
"after-the-fact".
Example: Example:
...@@ -216,7 +251,8 @@ Useful functions, as defined by TestCase: ...@@ -216,7 +251,8 @@ Useful functions, as defined by TestCase:
Test Cases and Theano Modes Test Cases and Theano Modes
--------------------------- ---------------------------
When compiling theano functions or modules, a mode parameter can be given to specify which linker and optimizer to use. When compiling theano functions or modules, a mode parameter can be
given to specify which linker and optimizer to use.
Example: Example:
...@@ -224,9 +260,15 @@ Example: ...@@ -224,9 +260,15 @@ Example:
>>> m = theano.Module() >>> m = theano.Module()
>>> minstance = m.make(mode='DEBUG_MODE') >>> minstance = m.make(mode='DEBUG_MODE')
Whenever possible, unit tests should omit this parameter. Leaving-out the mode will ensure that unit tests use the default mode (defined in compile.mode.default_mode). This default_mode is set to the THEANO_DEFAULT_MODE environment variable, if it is present. If not, it defaults to 'FAST_RUN'. Whenever possible, unit tests should omit this parameter. Leaving-out
the mode will ensure that unit tests use the default mode (defined in
compile.mode.default_mode). This default_mode is set to the
THEANO_DEFAULT_MODE environment variable, if it is present. If not, it
defaults to 'FAST_RUN'.
This allows the user to easily switch the mode in which unittests are run. For example to run all tests in all modes from a BASH script, type this: This allows the user to easily switch the mode in which unittests are
run. For example to run all tests in all modes from a BASH script,
type this:
.. code-block:: bash .. code-block:: bash
...@@ -237,14 +279,15 @@ This allows the user to easily switch the mode in which unittests are run. For e ...@@ -237,14 +279,15 @@ This allows the user to easily switch the mode in which unittests are run. For e
Using Random Values in Test Cases Using Random Values in Test Cases
--------------------------------- ---------------------------------
numpy.random is often used in unit tests to initialize large data structures, numpy.random is often used in unit tests to initialize large data
for use as inputs to the function or module being tested. When structures, for use as inputs to the function or module being
doing this, it is imperative that the random number generator be seeded at the tested. When doing this, it is imperative that the random number
be beginning of each unit test. This will ensure that unittest behaviour is generator be seeded at the be beginning of each unit test. This will
consistent from one execution to another (i.e always pass or always fail). ensure that unittest behaviour is consistent from one execution to
another (i.e always pass or always fail).
Instead of using numpy.random.seed to do this, we encourage users to do the Instead of using numpy.random.seed to do this, we encourage users to
following: do the following:
>>> from theano.tests import unittest_tools >>> from theano.tests import unittest_tools
>>> >>>
...@@ -257,19 +300,24 @@ following: ...@@ -257,19 +300,24 @@ following:
The behaviour of seed_rng is as follows: The behaviour of seed_rng is as follows:
* If an explicit seed is given, it will be used for seending numpy's rng. * If an explicit seed is given, it will be used for seending numpy's rng.
* If not, it will try to get a seed from the THEANO_UNITTEST_SEED variable. * If not, it will try to get a seed from the THEANO_UNITTEST_SEED variable.
* If THEANO_UNITTEST_SEED is set to "random", it will seed the rng. with None, which is equivalent to seeding with a random seed.
* If THEANO_UNITTEST_SEED is set to "random", it will seed the
rng. with None, which is equivalent to seeding with a random seed.
* If THEANO_UNITTEST_SEED is not defined, it will use a default seed of 666. * If THEANO_UNITTEST_SEED is not defined, it will use a default seed of 666.
The main advantage of using unittest_tools.seed_rng is that it allows us to The main advantage of using unittest_tools.seed_rng is that it allows
change the seed used in the unitests, without having to manually edit all the us to change the seed used in the unitests, without having to manually
files. For example, this allows the nightly build to run nosetests repeatedly, edit all the files. For example, this allows the nightly build to run
changing the seed on every run (hence achieving a higher confidence that the nosetests repeatedly, changing the seed on every run (hence achieving
variables are correct), while still making sure unittests are deterministic. a higher confidence that the variables are correct), while still
making sure unittests are deterministic.
Users who prefer their unittests to be random (when run on their local machine) Users who prefer their unittests to be random (when run on their local
can simply set THEANO_UNITTEST_SEED to 'random'. machine) can simply set THEANO_UNITTEST_SEED to 'random'.
Similarly, to provide a seed to numpy.random.RandomState, simply use: Similarly, to provide a seed to numpy.random.RandomState, simply use:
...@@ -277,23 +325,27 @@ Similarly, to provide a seed to numpy.random.RandomState, simply use: ...@@ -277,23 +325,27 @@ Similarly, to provide a seed to numpy.random.RandomState, simply use:
>>> # OR providing an explicit seed >>> # OR providing an explicit seed
>>> rng = numpy.random.RandomState(unittest_tools.fetch_seed(1231)) #again not recommended >>> rng = numpy.random.RandomState(unittest_tools.fetch_seed(1231)) #again not recommended
Note that the ability to change the seed from one nosetest to another, is incompatible with the method of hard-coding the baseline variables (against which we compare the theano outputs). These must then be determined "algorithmically". Although this represents more work, the test suite will be better because of it. Note that the ability to change the seed from one nosetest to another,
is incompatible with the method of hard-coding the baseline variables
(against which we compare the theano outputs). These must then be
determined "algorithmically". Although this represents more work, the
test suite will be better because of it.
Creating an Op UnitTest Creating an Op UnitTest
======================= =======================
A few tools have been developed to help automate the development of unitests A few tools have been developed to help automate the development of
for Theano Ops. unitests for Theano Ops.
Validating the Gradient Validating the Gradient
----------------------- -----------------------
The ``verify_grad`` function can be used to validate that the ``grad`` The ``verify_grad`` function can be used to validate that the ``grad``
function of your Op is properly implemented. ``verify_grad`` is based on the function of your Op is properly implemented. ``verify_grad`` is based
Finite Difference Method where the derivative of function ``f`` at point ``x`` on the Finite Difference Method where the derivative of function ``f``
is approximated as: at point ``x`` is approximated as:
.. math:: .. math::
...@@ -302,8 +354,12 @@ is approximated as: ...@@ -302,8 +354,12 @@ is approximated as:
``verify_grad`` performs the following steps: ``verify_grad`` performs the following steps:
* approximates the gradient numerically using the Finite Difference Method * approximates the gradient numerically using the Finite Difference Method
* calculate the gradient using the symbolic expression provided in the ``grad`` function
* compares the two values. The tests passes if they are equal to within a certain tolerance. * calculate the gradient using the symbolic expression provided in the
``grad`` function
* compares the two values. The tests passes if they are equal to
within a certain tolerance.
Here is the prototype for the verify_grad function. Here is the prototype for the verify_grad function.
...@@ -315,12 +371,17 @@ the given tolerance. ...@@ -315,12 +371,17 @@ the given tolerance.
The parameters are as follows: The parameters are as follows:
* op: something that behaves like an Op instance with a single output (can be a python * op: something that behaves like an Op instance with a single output
function combining multiple ops) (can be a python function combining multiple ops)
* pt: the list of numpy.ndarrays to use as inputs to the op * pt: the list of numpy.ndarrays to use as inputs to the op
* n_tests: number of times to run the test * n_tests: number of times to run the test
* rng: random number generator from which to draw random samples * rng: random number generator from which to draw random samples
* eps: stepsize used in the Finite Difference Method * eps: stepsize used in the Finite Difference Method
* tol: relative tolerance used as threshold for gradient comparison * tol: relative tolerance used as threshold for gradient comparison
Here is an example showing how to use verify_grad: Here is an example showing how to use verify_grad:
...@@ -336,14 +397,15 @@ Here is an example showing how to use verify_grad: ...@@ -336,14 +397,15 @@ Here is an example showing how to use verify_grad:
makeTester and makeBroadcastTester makeTester and makeBroadcastTester
================================== ==================================
Most Op unittests perform the same function. All such tests must verify that Most Op unittests perform the same function. All such tests must
the op generates the proper output, that the gradient is valid, that the Op verify that the op generates the proper output, that the gradient is
fails in known/expected ways. Because so much of this is common, two helper valid, that the Op fails in known/expected ways. Because so much of
functions exists to make your lives easier: ``makeTester`` and this is common, two helper functions exists to make your lives easier:
``makeBroadcastTester`` (defined in module ``theano.tensor.tests.test_basic``). ``makeTester`` and ``makeBroadcastTester`` (defined in module
``theano.tensor.tests.test_basic``).
Here is an example of ``makeTester`` generating testcases for the Dot product Here is an example of ``makeTester`` generating testcases for the Dot
op: product op:
>>> DotTester = makeTester(name = 'DotTester', >>> DotTester = makeTester(name = 'DotTester',
>>> op = dot, >>> op = dot,
...@@ -357,29 +419,34 @@ op: ...@@ -357,29 +419,34 @@ op:
>>> bad2 = (rand(5, 7), rand(8,3))), >>> bad2 = (rand(5, 7), rand(8,3))),
>>> grad = dict()) >>> grad = dict())
In the above example, we provide a name and a reference to the op we want to In the above example, we provide a name and a reference to the op we
test. We then provide in the ``expected`` field, a function which want to test. We then provide in the ``expected`` field, a function
``makeTester`` can use to compute the correct values. The following five which ``makeTester`` can use to compute the correct values. The
parameters are dictionaries which contain: following five parameters are dictionaries which contain:
* checks: dictionary of validation functions (dictionary key is a description * checks: dictionary of validation functions (dictionary key is a
of what each function does). Each function accepts two parameters and description of what each function does). Each function accepts two
performs some sort of validation check on each op-input/op-output value pairs. parameters and performs some sort of validation check on each
If the function returns False, an Exception is raised containing the op-input/op-output value pairs. If the function returns False, an
check's description. Exception is raised containing the check's description.
* good: contains valid input values, for which the output should match the
expected output. Unittest will fail if this is not the case. * good: contains valid input values, for which the output should match
* bad_build: invalid parameters which should generate an Exception when the expected output. Unittest will fail if this is not the case.
attempting to build the graph (call to ``make_node`` should fail).
Fails unless an Exception is raised. * bad_build: invalid parameters which should generate an Exception
* bad_runtime: invalid parameters which should generate an Exception at when attempting to build the graph (call to ``make_node`` should
runtime, when trying to compute the actual output values (call to fail). Fails unless an Exception is raised.
* bad_runtime: invalid parameters which should generate an Exception
at runtime, when trying to compute the actual output values (call to
``perform`` should fail). Fails unless an Exception is raised. ``perform`` should fail). Fails unless an Exception is raised.
* grad: dictionary containing input values which will be used in the call to
``verify_grad`` * grad: dictionary containing input values which will be used in the
call to ``verify_grad``
``makeBroadcastTester`` is a wrapper function for makeTester. ``makeBroadcastTester`` is a wrapper function for makeTester. If an
If an ``inplace=True`` parameter is passed to it, it will take care of adding ``inplace=True`` parameter is passed to it, it will take care of
an entry to the ``checks`` dictionary. This check will ensure that inputs and adding an entry to the ``checks`` dictionary. This check will ensure
outputs are equal, after the Op's perform function has been applied. that inputs and outputs are equal, after the Op's perform function has
been applied.
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论