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

new doc indexes

上级 35f29474
...@@ -102,7 +102,8 @@ html_theme = 'sphinxdoc' ...@@ -102,7 +102,8 @@ html_theme = 'sphinxdoc'
# The name of an image file (within the static path) to place at the top of # The name of an image file (within the static path) to place at the top of
# the sidebar. # the sidebar.
html_logo = 'images/theano_logo-200x67.png' #html_logo = 'images/theano_logo-200x67.png'
html_logo = 'images/theano_logo_allblue_200x54.png'
# The name of an image file (within the static path) to use as favicon of the # The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
......
...@@ -11,15 +11,14 @@ Contents ...@@ -11,15 +11,14 @@ Contents
introduction introduction
LICENSE LICENSE
install install
basic_tutorial/index tutorial/index
advanced_tutorial/index library/index
topics/index extending/index
indexes/index indexes/index
glossary glossary
links links
internal/index internal/index
NEWS NEWS
examples/index
sandbox/index
.. examples/index
.. advanced/index
.. _advtutorial: .. _extending:
================= ================
Advanced Tutorial Extending Theano
================= ================
Before tackling this tutorial, it is highly recommended to read the
:ref:`basictutorial`.
This documentation is for users who want to extend Theano with new Types, new
Operations (Ops), and new graph optimizations.
The advanced tutorial is meant to give the reader a greater Along the way, it also introduces many aspects of how Theano works, so it is
understanding of the building blocks of Theano. Through this tutorial also good for you if you are interested in getting more under the hood with
we are going to define one :ref:`type`, ``double``, and basic Theano itself.
arithmetic :ref:`operations <op>` on that Type. We will first define
them using a Python implementation and then we will add a C
implementation.
This tutorial should be of most use to users who want to extend Theano Before tackling this tutorial, it is highly recommended to read the
with custom types and operations related to these types. :ref:`basictutorial`.
It is a good idea to read this tutorial as well since it provides
grounding for fundamental Theano concepts.
The first few pages will walk you through the definition of a new :ref:`type`,
``double``, and a basic arithmetic :ref:`operations <op>` on that Type. We
will start by defining them using a Python implementation and then we will add
a C implementation.
.. toctree:: .. toctree::
theano_vs_c pipeline
graphstructures theano_vs_c
type graphstructures
op type
inplace op
ctype inplace
cop ctype
optimization cop
tips optimization
tips
unittest
...@@ -68,53 +68,51 @@ Failure ...@@ -68,53 +68,51 @@ Failure
Besides cleanup code, all code has access to the %(fail)s template. For three code blocks, the generated C code will pretty much look like this: Besides cleanup code, all code has access to the %(fail)s template. For three code blocks, the generated C code will pretty much look like this:
{{{ .. code-block::
int failure = 0; int failure = 0;
{
<code1>
{
<code2>
{ {
<code3> <code1>
label3: {
<cleanup3> <code2>
{
<code3>
label3:
<cleanup3>
}
label2:
<cleanup2>
}
label1:
<cleanup1>
} }
label2: return failure;
<cleanup2>
}
label1:
<cleanup1>
}
return failure;
}}}
And %(fail)s in the nth code block will take the value "{failure = n; goto label<n>;}". This means only the blocks executed up to the failure point are cleaned up and the return value indicates which block failed, which is handy for debugging. And %(fail)s in the nth code block will take the value "{failure = n; goto label<n>;}". This means only the blocks executed up to the failure point are cleaned up and the return value indicates which block failed, which is handy for debugging.
When compiling an Op, we want to sync the outputs so we can get the results from Python. In case of failure, we will not necessarily want to sync. Because of that, typical code will look like this: When compiling an Op, we want to sync the outputs so we can get the results from Python. In case of failure, we will not necessarily want to sync. Because of that, typical code will look like this:
{{{ .. code-block::
int failure = 0; int failure = 0;
<declare input> <declare input>
<declare output> <declare output>
{
<extract input>
{
<extract output>
{ {
<perform> <extract input>
label3: {
<clean up perform> <extract output>
{
<perform>
label3:
<clean up perform>
}
label2:
if (!failure)
<sync output>
<clean up output>
}
label1:
<clean up input>
} }
label2: return failure;
if (!failure)
<sync output>
<clean up output>
}
label1:
<clean up input>
}
return failure;
}}}
Furthermore, is not necessary to extract the output because we mean to overwrite it anyway. In that case, <extract output> will be a no-op, but of course we may still need to clean up or sync what <perform> will put in the declared outputs. Furthermore, is not necessary to extract the output because we mean to overwrite it anyway. In that case, <extract output> will be a no-op, but of course we may still need to clean up or sync what <perform> will put in the declared outputs.
...@@ -124,20 +122,19 @@ Example ResultBase ...@@ -124,20 +122,19 @@ Example ResultBase
The following ResultBase represents a double (we only care about the C part). The following ResultBase represents a double (we only care about the C part).
{{{ .. code-block::
class Double(ResultBase): class Double(ResultBase):
<snip> <snip>
def c_declare(self): def c_declare(self):
return "double %(name)s;" return "double %(name)s;"
def c_init(self): def c_init(self):
return "%(name)s = 0.0;" return "%(name)s = 0.0;"
def c_extract(self): def c_extract(self):
return "%(name)s = PyFloat_AsDouble(py_%(name)s);" return "%(name)s = PyFloat_AsDouble(py_%(name)s);"
def c_cleanup(self): def c_cleanup(self):
return "" # nothing to do return "" # nothing to do
def c_sync(self): def c_sync(self):
return "Py_XDECREF(py_%(name)s); py_%(name)s = PyFloat_FromDouble(%(name)s);" return "Py_XDECREF(py_%(name)s); py_%(name)s = PyFloat_FromDouble(%(name)s);"
}}}
Example Op Example Op
...@@ -145,71 +142,69 @@ Example Op ...@@ -145,71 +142,69 @@ Example Op
The following ResultBase represents addition of two nonnegative doubles (we only care about the C part). The following ResultBase represents addition of two nonnegative doubles (we only care about the C part).
{{{ .. code-block::
class Add(Op): class Add(Op):
<snip> <snip>
def c_var_names(self): def c_var_names(self):
return "[['x', 'y'], ['z']]" return "[['x', 'y'], ['z']]"
def c_validate_update(self): def c_validate_update(self):
return "if (%(x)s < 0 || %(y)s < 0) %(fail)s" # fail if x or y is negative return "if (%(x)s < 0 || %(y)s < 0) %(fail)s" # fail if x or y is negative
def c_validate_update_cleanup(self): def c_validate_update_cleanup(self):
return "" # nothing to do return "" # nothing to do
def c_code(self): def c_code(self):
return "%(z)s = %(x)s + %(y)s;" return "%(z)s = %(x)s + %(y)s;"
def c_code_cleanup(self): def c_code_cleanup(self):
return "" # nothing to do return "" # nothing to do
}}}
Generating a C function Generating a C function
======================= =======================
For the example Op, the generated C function will typically look like this: For the example Op, the generated C function will typically look like this:
{{{ .. code-block::
void add(PyObject* storage_x, PyObject* storage_y, PyObject* storage_z) { void add(PyObject* storage_x, PyObject* storage_y, PyObject* storage_z) {
PyObject* py_x = PyList_GET_ITEM(storage_x, 0); Py_XINCREF(py_x); // automatic PyObject* py_x = PyList_GET_ITEM(storage_x, 0); Py_XINCREF(py_x); // automatic
PyObject* py_y = PyList_GET_ITEM(storage_y, 0); Py_XINCREF(py_y); // automatic PyObject* py_y = PyList_GET_ITEM(storage_y, 0); Py_XINCREF(py_y); // automatic
PyObject* py_z = Py_None; // we don't care what's currently in storage_z PyObject* py_z = Py_None; // we don't care what's currently in storage_z
failure = 0 failure = 0
double x; // x.c_declare double x; // x.c_declare
double y; // y.c_declare double y; // y.c_declare
double z; // z.c_declare double z; // z.c_declare
{
x = PyFloat_AsDouble(py_x); // x.c_extract
{
y = PyFloat_AsDouble(py_y); // y.c_extract
{ {
# we don't need to use z.c_extract x = PyFloat_AsDouble(py_x); // x.c_extract
{ {
if (x < 0 || y < 0) { // add.validate_update y = PyFloat_AsDouble(py_y); // y.c_extract
// This is automatically inserted in place of %(fail)s
failure = 4;
goto label_add_validate_update_cleanup;
}
{ {
z = x + y; // add.c_code # we don't need to use z.c_extract
label_add_code_cleanup: {
if (x < 0 || y < 0) { // add.validate_update
// This is automatically inserted in place of %(fail)s
failure = 4;
goto label_add_validate_update_cleanup;
}
{
z = x + y; // add.c_code
label_add_code_cleanup:
}
label_add_validate_update_cleanup:
}
label_z_sync_or_cleanup:
if (!failure) {
Py_XDECREF(py_z); // z.c_sync
py_z = PyFloat_FromDouble(z); // z.c_sync, the result is now available from Python!
PyList_SET_ITEM(storage_z, 0, py_z); // always done after _.c_sync
}
Py_XDECREF(py_z); // always done after _.c_cleanup
} }
label_add_validate_update_cleanup: label_y_cleanup:
} Py_XDECREF(py_y); // always done after _.c_cleanup
label_z_sync_or_cleanup:
if (!failure) {
Py_XDECREF(py_z); // z.c_sync
py_z = PyFloat_FromDouble(z); // z.c_sync, the result is now available from Python!
PyList_SET_ITEM(storage_z, 0, py_z); // always done after _.c_sync
} }
Py_XDECREF(py_z); // always done after _.c_cleanup label_x_cleanup:
Py_XDECREF(py_x); // always done after _.c_cleanup
} }
label_y_cleanup: return failure;
Py_XDECREF(py_y); // always done after _.c_cleanup
} }
label_x_cleanup:
Py_XDECREF(py_x); // always done after _.c_cleanup
}
return failure;
}
}}}
Generating a C struct Generating a C struct
===================== =====================
...@@ -218,30 +213,29 @@ To accelerate processing a tad, a struct can be generated instead of a function. ...@@ -218,30 +213,29 @@ To accelerate processing a tad, a struct can be generated instead of a function.
Here is a sketch of the struct equivalent of the previous function: Here is a sketch of the struct equivalent of the previous function:
{{{ .. code-block::
struct add { struct add {
PyObject* storage_x; PyObject* storage_x;
PyObject* storage_y; PyObject* storage_y;
PyObject* storage_z; PyObject* storage_z;
double z; // z.c_declare double z; // z.c_declare
void init(PyObject* storage_x, PyObject* storage_y, PyObject* storage_z) { void init(PyObject* storage_x, PyObject* storage_y, PyObject* storage_z) {
<set the struct members of the same names> <set the struct members of the same names>
<init the struct members corresponding to z> <init the struct members corresponding to z>
} }
void cleanup(void) { void cleanup(void) {
<cleanup z> <cleanup z>
} }
void run(void) { void run(void) {
<same code as before minus z's cleanup> <same code as before minus z's cleanup>
} }
add() { this->init(); } add() { this->init(); }
~add() { this->cleanup(); } ~add() { this->cleanup(); }
}; };
}}}
Advantages of using a struct: Advantages of using a struct:
* Can be run several times even if we provide the storage only once. * Can be run several times even if we provide the storage only once.
......
...@@ -33,27 +33,26 @@ Question: does it make sense to apply the order to the loop, or is this broadcas ...@@ -33,27 +33,26 @@ Question: does it make sense to apply the order to the loop, or is this broadcas
Here is the loop for {{{order == c}}}. Check for errors! Here is the loop for {{{order == c}}}. Check for errors!
{{{ .. code-block::
<initialize iterators> <initialize iterators>
i1 = -1 i1 = -1
while (++i1 < dim1) { while (++i1 < dim1) {
i2 = -1 i2 = -1
rank_N-1_accumulator = init rank_N-1_accumulator = init
while (++i2 < dim2) { while (++i2 < dim2) {
... ...
iN = -1 iN = -1
while (++iN < dimN) { while (++iN < dimN) {
<accumulate rank N input> <accumulate rank N input>
<SET rank N output using broadcasted inputs> <SET rank N output using broadcasted inputs>
<NEXT rank N iterator> <NEXT rank N iterator>
}
...
}
<SET rank 1 output using accumulated inputs>
<NEXT rank 1 iterator>
} }
...
}
<SET rank 1 output using accumulated inputs>
<NEXT rank 1 iterator>
}
}}}
When {{{order == f}}}, the iterators ''ideally'' (but not necessarily) iterate in FORTRAN order, i.e. the while loops are on {{{dimN..dim1}}} instead of {{{dim1..dimN}}}. When {{{order == f}}}, the iterators ''ideally'' (but not necessarily) iterate in FORTRAN order, i.e. the while loops are on {{{dimN..dim1}}} instead of {{{dim1..dimN}}}.
......
.. _basictutorial: .. _basictutorial:
============== ========
Basic Tutorial Tutorial
============== ========
Before doing anything in this tutorial, make sure that Theano is
installed on your system (see :ref:`install`).
Done? Alright!
Let's start an interactive session and import the package you just Let's start an interactive session and import the package you just
installed: installed:
...@@ -23,11 +16,18 @@ of theano. Let's import that subpackage under a handy name. I like ...@@ -23,11 +16,18 @@ of theano. Let's import that subpackage under a handy name. I like
>>> import theano.tensor as T >>> import theano.tensor as T
Now we're ready for the tour: If that didn't work, Theano is not installed correctly (see :ref:`install`).
Now we're ready for the tour:
.. toctree:: .. toctree::
adding adding
examples debug_faq
tools debugmode
examples
numpy
profilemode
randomstreams
tools
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论