提交 181b2dbd authored 作者: Joseph Turian's avatar Joseph Turian

Updated beginning of advanced tutorial

上级 c2dbdddf
...@@ -11,7 +11,6 @@ Structure ...@@ -11,7 +11,6 @@ Structure
.. toctree:: .. toctree::
:maxdepth: 2 :maxdepth: 2
graphstructures
env env
features features
optimization optimization
......
...@@ -24,10 +24,10 @@ that declares the right data types and that contains the right number ...@@ -24,10 +24,10 @@ that declares the right data types and that contains the right number
of loops over the dimensions. of loops over the dimensions.
Note that a Theano :ref:`type` is not equivalent to a Python type or Note that a Theano :ref:`type` is not equivalent to a Python type or
class. Indeed, in Theano, :ref:`irow <predefinedtypes>` and class. Indeed, in Theano, :ref:`irow <predefinedtypes>` and :ref:`dmatrix
:ref:`dmatrix <predefinedtypes>` both use ``numpy.ndarray`` as the <predefinedtypes>` both use ``numpy.ndarray`` as the underlying type
working data type, yet they are different Theano Types. Indeed, the for doing computations and storing data, yet they are different Theano
constraints set by ``dmatrix`` are: Types. Indeed, the constraints set by ``dmatrix`` are:
#. Must be an instance of ``numpy.ndarray``: ``isinstance(x, numpy.ndarray)`` #. Must be an instance of ``numpy.ndarray``: ``isinstance(x, numpy.ndarray)``
#. Must be an array of 64-bit floating point numbers: ``str(x.dtype) == 'float64'`` #. Must be an array of 64-bit floating point numbers: ``str(x.dtype) == 'float64'``
...@@ -45,13 +45,21 @@ Theano Type. ...@@ -45,13 +45,21 @@ Theano Type.
Type's contract Type's contract
=============== ===============
In Theano's framework, a Type is any object which In Theano's framework, a Type is any object which defines the following
defines the following methods: methods. To obtain the default methods described below, the Type should
be an instance of :api:``theano.gof.Type`` or should be an instance of a
subclass of :api:``theano.gof.Type``. If you will write all methods yourself,
you need not use an instance of :api:``theano.gof.Type``.
- **filter(value, strict [= False])** Methods with default arguments must be defined with the same signature,
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
default values.
- This casts or wraps a value to match the Type and returns the - **filter(value, strict=False)**
casted/wrapped value. If ``value`` is incompatible with the Type,
- This casts a value to match the Type and returns the
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)
...@@ -61,41 +69,51 @@ defines the following methods: ...@@ -61,41 +69,51 @@ defines the following methods:
- **is_valid_value(value)** - **is_valid_value(value)**
- Returns True iff the value is exactly compatible with the Type. - Returns True iff the value is compatible with the Type. If
``filter(value, strict = True)`` does not raise an exception, the
value is compatible with the Type.
- *Default*: defined in terms of ``filter(value, strict = True)`` - *Default*: True iff ``filter(value, strict = True)`` does not raise an
exception.
- **values_eq(a, b)** - **values_eq(a, b)**
- Returns True iff ``a`` and ``b`` are valid values of this Type and - Returns True iff ``a`` and ``b`` are equal.
are equal.
- *Default*: a == b - *Default*: ``a == b``
- **values_eq_approx(a, b)** - **values_eq_approx(a, b)**
- Returns True iff ``a`` and ``b`` are valid values of this Type and - Returns True iff ``a`` and ``b``
are approximately equal, for a definition of approximately which are approximately equal, for a definition of "approximately" which
varies from Type to Type. varies from Type to Type.
- *Default*: same as ``values_eq`` - *Default*: ``values_eq(a, b)``
- **make_result(name [= None])** - **make_result(name=None)**
- Makes a :term:`Result` of this Type with the specified name. The - Makes a :term:`Result` of this Type with the specified name, if
Result will have its ``type`` field set to the Type object. ``name is not None``. If ``name is ``None``, then the Result does
not have a name. The Result will have its ``type`` field set to the
Type object.
- *Default*: there is a generic definition of this in Type. - *Default*: there is a generic definition of this in Type. The Result's
``type`` will be the object that defines this method (in other words,
``self``).
- **__call__()**: - **__call__(name=None)**:
- Syntactic shortcut to make_result. - Syntactic shortcut to ``make_result``.
- *Default*: this is done for you by Type. - *Default*: ``make_result``
For each method, the *default* is what Type defines for you. This For each method, the *default* is what :api:``theano.gof.Type`` defines
means you will rarely need to define all of these methods. for you. So, if you create an instance of :api:``theano.gof.Type`` or an
instance of a subclass of :api:``theano.gof.Type``, you
must define ``filter``. You might want to override ``values_eq_approx``,
as well as ``values_eq``. The other defaults generally need not be
overridden.
For more details you can go see the documentation for :ref:`type`. For more details you can go see the documentation for :ref:`type`.
...@@ -103,7 +121,7 @@ For more details you can go see the documentation for :ref:`type`. ...@@ -103,7 +121,7 @@ For more details you can go see the documentation for :ref:`type`.
Defining double Defining double
=============== ===============
We are going to piggyback Type ``double`` on Python's ``float``. We are We are going to base Type ``double`` on Python's ``float``. We are
must define ``filter`` and shall override ``values_eq_approx``. must define ``filter`` and shall override ``values_eq_approx``.
...@@ -111,10 +129,16 @@ must define ``filter`` and shall override ``values_eq_approx``. ...@@ -111,10 +129,16 @@ must define ``filter`` and shall override ``values_eq_approx``.
.. code-block:: python .. code-block:: python
def filter(x, strict=False): # Note that we shadow Python's function ``filter`` with this
if strict and not isinstance(x, float): # definition.
raise TypeError('Expected a float!') def filter(x, strict=False):
return float(x) if strict:
if isinstance(x, float):
return x
else:
raise TypeError('Expected a float!')
else:
return float(x)
If ``strict == True`` we need to return ``x``. If ``strict == True`` and ``x`` is not a If ``strict == True`` we need to return ``x``. If ``strict == True`` and ``x`` is not a
``float`` (for example, ``x`` could easily be an ``int``) then it is ``float`` (for example, ``x`` could easily be an ``int``) then it is
...@@ -140,9 +164,14 @@ actually produce the exact same output as ``6 * a`` (try with a=0.1), ...@@ -140,9 +164,14 @@ actually produce the exact same output as ``6 * a`` (try with a=0.1),
but with ``values_eq_approx`` we with don't necessarily mind. but with ``values_eq_approx`` we with don't necessarily mind.
We added an extra ``tolerance`` argument here. Since this argument is We added an extra ``tolerance`` argument here. Since this argument is
not part of the API, it must have a default value which we reasonably not part of the API, it must have a default value which we
chose to be 1e-4. chose to be 1e-4.
.. note::
``values_eq`` is never actually used by Theano, but it might be used
internally in the future. Currently, all equality testing is done
using ``values_eq_approx``.
**Putting them together** **Putting them together**
...@@ -182,16 +211,34 @@ and define ``filter`` and ``values_eq_approx`` in the subclass: ...@@ -182,16 +211,34 @@ and define ``filter`` and ``values_eq_approx`` in the subclass:
``double`` is then an instance of Type ``Double``, which in turn is a ``double`` is then an instance of Type ``Double``, which in turn is a
sublcass of ``Type``. sublcass of ``Type``.
There is a small issue with defining ``double`` that way in that all There is a small issue with defining ``double`` this way. All
instances of ``Double`` are technically the same Type. Indeed, they all instances of ``Double`` are technically the same Type. However, different
filter in the same way. This is relevant because Theano often compares ``Double`` Type instances do not compare the same:
Types using ``==`` to see if they are the same. For example, if the
inputs of two different :ref:`applications <apply>` have the same >>> double1 = Double()
Type and the operation applied on them is the same, they can be >>> double2 = Double()
:term:`merged <merge>`. The workarounds are to define >>> double1 == double2
``Double.__eq__`` so that all instances of Double are equal *or* to False
override ``Double.__new__`` to always return the same instance *or* to
hide Double and only publish a single instance of it. Theano often compares Types using ``==`` to see if they are the same. If
the inputs of two different :ref:`Applies <apply>` have the same Type
and the :ref:`op` applied on them is the same, they can be :term:`merged
<merge>`.
There are several ways to make it that instances of Type ``Double``
compare equal:
#. Define ``Double.__eq__`` so that all instances of type Double
are equal. For example:
.. code-block:: python
def __eq__(self, other):
return type(self) is Double and type(other) is Double
#. Override ``Double.__new__`` to always return the same instance.
#. Hide Double and only publish a single instance of it.
We prefer the final option, because it's the simplest.
Untangling some concepts Untangling some concepts
......
...@@ -26,6 +26,7 @@ concepts at work here. ...@@ -26,6 +26,7 @@ concepts at work here.
.. toctree:: .. toctree::
graphstructures
ex1/type ex1/type
ex1/op ex1/op
ex1/ctype ex1/ctype
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论