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

Updated beginning of advanced tutorial

上级 c2dbdddf
......@@ -11,7 +11,6 @@ Structure
.. toctree::
:maxdepth: 2
graphstructures
env
features
optimization
......
......@@ -24,10 +24,10 @@ that declares the right data types and that contains the right number
of loops over the dimensions.
Note that a Theano :ref:`type` is not equivalent to a Python type or
class. Indeed, in Theano, :ref:`irow <predefinedtypes>` and
:ref:`dmatrix <predefinedtypes>` both use ``numpy.ndarray`` as the
working data type, yet they are different Theano Types. Indeed, the
constraints set by ``dmatrix`` are:
class. Indeed, in Theano, :ref:`irow <predefinedtypes>` and :ref:`dmatrix
<predefinedtypes>` both use ``numpy.ndarray`` as the underlying type
for doing computations and storing data, yet they are different Theano
Types. Indeed, the constraints set by ``dmatrix`` are:
#. 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'``
......@@ -45,13 +45,21 @@ Theano Type.
Type's contract
===============
In Theano's framework, a Type is any object which
defines the following methods:
In Theano's framework, a Type is any object which defines the following
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
casted/wrapped value. If ``value`` is incompatible with the Type,
- **filter(value, strict=False)**
- 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
reference to ``value`` (i.e. casting prohibited)
......@@ -61,41 +69,51 @@ defines the following methods:
- **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)**
- Returns True iff ``a`` and ``b`` are valid values of this Type and
are equal.
- Returns True iff ``a`` and ``b`` are equal.
- *Default*: a == b
- *Default*: ``a == b``
- **values_eq_approx(a, b)**
- Returns True iff ``a`` and ``b`` are valid values of this Type and
are approximately equal, for a definition of approximately which
- Returns True iff ``a`` and ``b``
are approximately equal, for a definition of "approximately" which
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
Result will have its ``type`` field set to the Type object.
- Makes a :term:`Result` of this Type with the specified name, if
``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
means you will rarely need to define all of these methods.
For each method, the *default* is what :api:``theano.gof.Type`` defines
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`.
......@@ -103,7 +121,7 @@ For more details you can go see the documentation for :ref:`type`.
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``.
......@@ -111,10 +129,16 @@ must define ``filter`` and shall override ``values_eq_approx``.
.. code-block:: python
def filter(x, strict=False):
if strict and not isinstance(x, float):
raise TypeError('Expected a float!')
return float(x)
# Note that we shadow Python's function ``filter`` with this
# definition.
def filter(x, strict=False):
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
``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),
but with ``values_eq_approx`` we with don't necessarily mind.
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.
.. 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**
......@@ -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
sublcass of ``Type``.
There is a small issue with defining ``double`` that way in that all
instances of ``Double`` are technically the same Type. Indeed, they all
filter in the same way. This is relevant because Theano often compares
Types using ``==`` to see if they are the same. For example, if the
inputs of two different :ref:`applications <apply>` have the same
Type and the operation applied on them is the same, they can be
:term:`merged <merge>`. The workarounds are to define
``Double.__eq__`` so that all instances of Double are equal *or* to
override ``Double.__new__`` to always return the same instance *or* to
hide Double and only publish a single instance of it.
There is a small issue with defining ``double`` this way. All
instances of ``Double`` are technically the same Type. However, different
``Double`` Type instances do not compare the same:
>>> double1 = Double()
>>> double2 = Double()
>>> double1 == double2
False
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
......
......@@ -26,6 +26,7 @@ concepts at work here.
.. toctree::
graphstructures
ex1/type
ex1/op
ex1/ctype
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论