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

new doc indexes

上级 35f29474
......@@ -102,7 +102,8 @@ html_theme = 'sphinxdoc'
# The name of an image file (within the static path) to place at the top of
# 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
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
......
......@@ -11,15 +11,14 @@ Contents
introduction
LICENSE
install
basic_tutorial/index
advanced_tutorial/index
topics/index
tutorial/index
library/index
extending/index
indexes/index
glossary
links
internal/index
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
understanding of the building blocks of Theano. Through this tutorial
we are going to define one :ref:`type`, ``double``, and basic
arithmetic :ref:`operations <op>` on that Type. We will first define
them using a Python implementation and then we will add a C
implementation.
Along the way, it also introduces many aspects of how Theano works, so it is
also good for you if you are interested in getting more under the hood with
Theano itself.
This tutorial should be of most use to users who want to extend Theano
with custom types and operations related to these types.
It is a good idea to read this tutorial as well since it provides
grounding for fundamental Theano concepts.
Before tackling this tutorial, it is highly recommended to read the
:ref:`basictutorial`.
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::
theano_vs_c
graphstructures
type
op
inplace
ctype
cop
optimization
tips
pipeline
theano_vs_c
graphstructures
type
op
inplace
ctype
cop
optimization
tips
unittest
......@@ -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:
{{{
int failure = 0;
{
<code1>
{
<code2>
.. code-block::
int failure = 0;
{
<code3>
label3:
<cleanup3>
<code1>
{
<code2>
{
<code3>
label3:
<cleanup3>
}
label2:
<cleanup2>
}
label1:
<cleanup1>
}
label2:
<cleanup2>
}
label1:
<cleanup1>
}
return failure;
}}}
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.
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:
{{{
int failure = 0;
<declare input>
<declare output>
{
<extract input>
{
<extract output>
.. code-block::
int failure = 0;
<declare input>
<declare output>
{
<perform>
label3:
<clean up perform>
<extract input>
{
<extract output>
{
<perform>
label3:
<clean up perform>
}
label2:
if (!failure)
<sync output>
<clean up output>
}
label1:
<clean up input>
}
label2:
if (!failure)
<sync output>
<clean up output>
}
label1:
<clean up input>
}
return failure;
}}}
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.
......@@ -124,20 +122,19 @@ Example ResultBase
The following ResultBase represents a double (we only care about the C part).
{{{
class Double(ResultBase):
<snip>
def c_declare(self):
return "double %(name)s;"
def c_init(self):
return "%(name)s = 0.0;"
def c_extract(self):
return "%(name)s = PyFloat_AsDouble(py_%(name)s);"
def c_cleanup(self):
return "" # nothing to do
def c_sync(self):
return "Py_XDECREF(py_%(name)s); py_%(name)s = PyFloat_FromDouble(%(name)s);"
}}}
.. code-block::
class Double(ResultBase):
<snip>
def c_declare(self):
return "double %(name)s;"
def c_init(self):
return "%(name)s = 0.0;"
def c_extract(self):
return "%(name)s = PyFloat_AsDouble(py_%(name)s);"
def c_cleanup(self):
return "" # nothing to do
def c_sync(self):
return "Py_XDECREF(py_%(name)s); py_%(name)s = PyFloat_FromDouble(%(name)s);"
Example Op
......@@ -145,71 +142,69 @@ Example Op
The following ResultBase represents addition of two nonnegative doubles (we only care about the C part).
{{{
class Add(Op):
<snip>
def c_var_names(self):
return "[['x', 'y'], ['z']]"
def c_validate_update(self):
return "if (%(x)s < 0 || %(y)s < 0) %(fail)s" # fail if x or y is negative
def c_validate_update_cleanup(self):
return "" # nothing to do
def c_code(self):
return "%(z)s = %(x)s + %(y)s;"
def c_code_cleanup(self):
return "" # nothing to do
}}}
.. code-block::
class Add(Op):
<snip>
def c_var_names(self):
return "[['x', 'y'], ['z']]"
def c_validate_update(self):
return "if (%(x)s < 0 || %(y)s < 0) %(fail)s" # fail if x or y is negative
def c_validate_update_cleanup(self):
return "" # nothing to do
def c_code(self):
return "%(z)s = %(x)s + %(y)s;"
def c_code_cleanup(self):
return "" # nothing to do
Generating a C function
=======================
For the example Op, the generated C function will typically look like this:
{{{
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_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
failure = 0
double x; // x.c_declare
double y; // y.c_declare
double z; // z.c_declare
{
x = PyFloat_AsDouble(py_x); // x.c_extract
{
y = PyFloat_AsDouble(py_y); // y.c_extract
.. code-block::
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_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
failure = 0
double x; // x.c_declare
double y; // y.c_declare
double z; // z.c_declare
{
# 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
// This is automatically inserted in place of %(fail)s
failure = 4;
goto label_add_validate_update_cleanup;
}
y = PyFloat_AsDouble(py_y); // y.c_extract
{
z = x + y; // add.c_code
label_add_code_cleanup:
# we don't need to use z.c_extract
{
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_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
label_y_cleanup:
Py_XDECREF(py_y); // always done after _.c_cleanup
}
Py_XDECREF(py_z); // always done after _.c_cleanup
label_x_cleanup:
Py_XDECREF(py_x); // always done after _.c_cleanup
}
label_y_cleanup:
Py_XDECREF(py_y); // always done after _.c_cleanup
return failure;
}
label_x_cleanup:
Py_XDECREF(py_x); // always done after _.c_cleanup
}
return failure;
}
}}}
Generating a C struct
=====================
......@@ -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:
{{{
struct add {
PyObject* storage_x;
PyObject* storage_y;
PyObject* storage_z;
double z; // z.c_declare
void init(PyObject* storage_x, PyObject* storage_y, PyObject* storage_z) {
<set the struct members of the same names>
<init the struct members corresponding to z>
}
void cleanup(void) {
<cleanup z>
}
void run(void) {
<same code as before minus z's cleanup>
}
add() { this->init(); }
~add() { this->cleanup(); }
};
}}}
.. code-block::
struct add {
PyObject* storage_x;
PyObject* storage_y;
PyObject* storage_z;
double z; // z.c_declare
void init(PyObject* storage_x, PyObject* storage_y, PyObject* storage_z) {
<set the struct members of the same names>
<init the struct members corresponding to z>
}
void cleanup(void) {
<cleanup z>
}
void run(void) {
<same code as before minus z's cleanup>
}
add() { this->init(); }
~add() { this->cleanup(); }
};
Advantages of using a struct:
* 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
Here is the loop for {{{order == c}}}. Check for errors!
{{{
<initialize iterators>
i1 = -1
while (++i1 < dim1) {
i2 = -1
rank_N-1_accumulator = init
while (++i2 < dim2) {
...
iN = -1
while (++iN < dimN) {
<accumulate rank N input>
<SET rank N output using broadcasted inputs>
<NEXT rank N iterator>
.. code-block::
<initialize iterators>
i1 = -1
while (++i1 < dim1) {
i2 = -1
rank_N-1_accumulator = init
while (++i2 < dim2) {
...
iN = -1
while (++iN < dimN) {
<accumulate rank N input>
<SET rank N output using broadcasted inputs>
<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}}}.
......
.. _basictutorial:
==============
Basic Tutorial
==============
Before doing anything in this tutorial, make sure that Theano is
installed on your system (see :ref:`install`).
Done? Alright!
========
Tutorial
========
Let's start an interactive session and import the package you just
installed:
......@@ -23,11 +16,18 @@ of theano. Let's import that subpackage under a handy name. I like
>>> 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::
adding
examples
tools
adding
debug_faq
debugmode
examples
numpy
profilemode
randomstreams
tools
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论