提交 91ebcb3c authored 作者: Brandon T. Willard's avatar Brandon T. Willard 提交者: Brandon T. Willard

Add doc warnings, fix small formatting issues, and remove outdated sections

上级 81da9eb8
...@@ -4,6 +4,10 @@ ...@@ -4,6 +4,10 @@
Developer Start Guide Developer Start Guide
===================== =====================
.. warning::
This document is outdated.
Contributing Contributing
============ ============
...@@ -243,9 +247,6 @@ Documentation and docstrings ...@@ -243,9 +247,6 @@ Documentation and docstrings
`Numpy docstring standard `Numpy docstring standard
<https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt>`_. <https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt>`_.
* Split the docstrings in sections, according to the `Allowed docstring
sections in Napoleon`_
* To cross-reference other objects (e.g. reference other classes or methods) in * To cross-reference other objects (e.g. reference other classes or methods) in
the docstrings, use the the docstrings, use the
`cross-referencing objects <http://www.sphinx-doc.org/en/stable/domains.html#cross-referencing-python-objects>`_ `cross-referencing objects <http://www.sphinx-doc.org/en/stable/domains.html#cross-referencing-python-objects>`_
......
.. _cop: .. _cop:
==================================== =====================================
Implementing the arithmetic COps in C Implementing the arithmetic COps in C
==================================== =====================================
Now that we have set up our ``double`` type properly to allow C Now that we have set up our ``double`` type properly to allow C
implementations for operations that work on it, all we have to do now implementations for operations that work on it, all we have to do now
......
...@@ -7,14 +7,14 @@ Creating a new Op: Python implementation ...@@ -7,14 +7,14 @@ Creating a new Op: Python implementation
So suppose you have looked through the library documentation and you don't see So suppose you have looked through the library documentation and you don't see
a function that does what you want. a function that does what you want.
If you can implement something in terms of existing ``Op``s, you should do that. If you can implement something in terms of an existing ``Op``, you should do that.
Odds are your function that uses existing Aesara expressions is short, Odds are your function that uses existing Aesara expressions is short,
has no bugs, and potentially profits from optimizations that have already been has no bugs, and potentially profits from optimizations that have already been
implemented. implemented.
However, if you cannot implement an ``Op`` in terms of existing ``Op``s, you have to However, if you cannot implement an ``Op`` in terms of an existing ``Op``, you have to
write a new one. Don't worry, Aesara was designed to make it easy to add new write a new one. Don't worry, Aesara was designed to make it easy to add a new
``Op``s, Types, and Optimizations. ``Op``, ``Type``, and ``Optimization``.
.. These first few pages will walk you through the definition of a new :ref:`type`, .. These 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`. .. ``double``, and a basic arithmetic :ref:`operations <op>` on that `Type`.
...@@ -46,7 +46,7 @@ As an illustration, this tutorial shows how to write a simple Python-based ...@@ -46,7 +46,7 @@ As an illustration, this tutorial shows how to write a simple Python-based
Aesara Graphs refresher Aesara Graphs refresher
----------------------- -----------------------
.. image:: ../hpcs2011_tutorial/pics/apply_node.png .. image:: apply.png
:width: 500 px :width: 500 px
Aesara represents symbolic mathematical computations as graphs. Those graphs Aesara represents symbolic mathematical computations as graphs. Those graphs
...@@ -145,9 +145,9 @@ or :func:`make_thunk`. ...@@ -145,9 +145,9 @@ or :func:`make_thunk`.
It takes several arguments: It takes several arguments:
- ``node`` is a reference to an Apply node which was previously - ``node`` is a reference to an Apply node which was previously
obtained via the ``Op``'s :func:`make_node` method. It is typically not obtained via the :func:`make_node` method. It is typically not
used in simple ``Op``s, but it contains symbolic information that used in a simple ``Op``, but it contains symbolic information that
could be required for complex ``Op``s. could be required by a complex ``Op``.
- ``inputs`` is a list of references to data which can be operated on using - ``inputs`` is a list of references to data which can be operated on using
non-symbolic statements, (i.e., statements in Python, Numpy). non-symbolic statements, (i.e., statements in Python, Numpy).
- ``output_storage`` is a list of storage cells where the output - ``output_storage`` is a list of storage cells where the output
......
...@@ -1029,7 +1029,7 @@ an apply-specific function. ...@@ -1029,7 +1029,7 @@ an apply-specific function.
Using GDB to debug COp's C code Using GDB to debug COp's C code
============================== ===============================
When debugging C code, it can be useful to use GDB for code compiled When debugging C code, it can be useful to use GDB for code compiled
by Aesara. by Aesara.
......
...@@ -51,3 +51,4 @@ with Aesara itself. ...@@ -51,3 +51,4 @@ with Aesara itself.
unittest unittest
scan scan
extending_faq extending_faq
jax_op
Tutorial on adding JAX Ops to Aesara Tutorial on adding JAX Ops to Aesara
============================= ====================================
A core feature of Aesara, previously named Aesara, is the JAX Aesara is able to convert its graphs into JAX compiled functions. In order to do
backend. To support the backend JAX ops need be added to Aesara once to this, each ``Op`` in the graph must have a JAX implementation. This tutorial
be supported. This tutorial will explain each step. will explain how JAX implementations are created for an ``Op``.
Step 1: Identify the Aesara Op you’d like to JAXify Step 1: Identify the Aesara Op you’d like to JAXify
=================================================== ===================================================
......
...@@ -137,7 +137,7 @@ You can extract the 4 fields with ...@@ -137,7 +137,7 @@ You can extract the 4 fields with
:func:`Aesara.sparse.basic.csm_shape` to extract the individual :func:`Aesara.sparse.basic.csm_shape` to extract the individual
fields. fields.
You can look at the `AddSD`_ sparse `Op` for an example with C code. It implements You can look at the `AddSD` sparse `Op` for an example with C code. It implements
the addition of a sparse matrix with a dense matrix. the addition of a sparse matrix with a dense matrix.
Sparse Tests Sparse Tests
...@@ -200,7 +200,7 @@ To allow consistent interface of Ops that support OpenMP, we have some ...@@ -200,7 +200,7 @@ To allow consistent interface of Ops that support OpenMP, we have some
helper code. Doing this also allows to enable/disable OpenMP globally helper code. Doing this also allows to enable/disable OpenMP globally
or per op for fine-grained control. or per op for fine-grained control.
Your Op needs to inherit from ``Aesara.graph.op.OpenMPOp``. If it overrides Your Op needs to inherit from ``aesara.graph.op.OpenMPOp``. If it overrides
the ``__init__()`` method, it must have an ``openmp=None`` parameter the ``__init__()`` method, it must have an ``openmp=None`` parameter
and must call ``super(MyOpClass, self).__init__(openmp=openmp)``. and must call ``super(MyOpClass, self).__init__(openmp=openmp)``.
...@@ -263,11 +263,11 @@ along with pointers to the relevant documentation. ...@@ -263,11 +263,11 @@ along with pointers to the relevant documentation.
can split a sparse variable into its parts as TensorVariables. Those can split a sparse variable into its parts as TensorVariables. Those
can then be used as inputs to an op with C code. can then be used as inputs to an op with C code.
* :class:`Generic <Aesara.graph.type.Generic>` : Aesara type that * :class:`Generic <aesara.graph.type.Generic>` : Aesara type that
represents a simple Python Object. Variables of this Aesara type are represents a simple Python Object. Variables of this Aesara type are
represented in C as objects of class `PyObject represented in C as objects of class `PyObject
<https://docs.python.org/2/c-api/structures.html#c.PyObject>`_. <https://docs.python.org/2/c-api/structures.html#c.PyObject>`_.
* :class:`CDataType <Aesara.graph.type.CDataType>` : Aesara type that * :class:`CDataType <aesara.graph.type.CDataType>` : Aesara type that
represents a C data type. The C type associated with this Aesara type represents a C data type. The C type associated with this Aesara type
depends on the data being represented. depends on the data being represented.
...@@ -4,6 +4,9 @@ ...@@ -4,6 +4,9 @@
Unit Testing Unit Testing
============ ============
.. warning::
This document is very outdated.
Aesara relies heavily on unit testing. Its importance cannot be Aesara relies heavily on unit testing. Its importance cannot be
stressed enough! stressed enough!
...@@ -45,20 +48,17 @@ Mostly `pytest aesara/` ...@@ -45,20 +48,17 @@ Mostly `pytest aesara/`
Folder Layout Folder Layout
------------- -------------
"tests" directories are scattered throughout aesara. Each tests
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 Optimally every python module should have a unittest file associated
with it, as shown below. Unittests testing functionality of module with it, as shown below. Unit tests that test functionality of module
<module>.py should therefore be stored in tests/test_<module>.py:: ``<module>.py`` should therefore be stored in
``tests/<sub-package>/test_<module>.py``::
Aesara/aesara/tensor/basic.py Aesara/aesara/tensor/basic.py
Aesara/aesara/tensor/elemwise.py Aesara/aesara/tensor/elemwise.py
Aesara/aesara/tensor/tests/test_basic.py Aesara/tests/tensor/test_basic.py
Aesara/aesara/tensor/tests/test_elemwise.py Aesara/tests/tensor/test_elemwise.py
How to Write a Unittest How to Write a Unittest
...@@ -67,16 +67,14 @@ How to Write a Unittest ...@@ -67,16 +67,14 @@ How to Write a Unittest
Test Cases and Methods Test Cases and Methods
---------------------- ----------------------
Unittests should be grouped "logically" into test cases, which are Unit tests should be grouped "logically" into test cases, which are
meant to group all unittests operating on the same element and/or meant to group all unit tests operating on the same element and/or
concept. Test cases are implemented as Python classes which inherit concept.
from unittest.TestCase
Test cases contain multiple test methods. These should be prefixed Test cases should be functions or classes prefixed with the word "test".
with the word "test".
Test methods should be as specific as possible and cover a particular Test methods should be as specific as possible and cover a particular
aspect of the problem. For example, when testing the TensorDot Op, one aspect of the problem. For example, when testing the ``Dot`` ``Op``, one
test method could check for validity, while another could verify that test method could check for validity, while another could verify that
the proper errors are raised when inputs have invalid dimensions. the proper errors are raised when inputs have invalid dimensions.
...@@ -84,224 +82,30 @@ Test method names should be as explicit as possible, so that users can ...@@ -84,224 +82,30 @@ Test method names should be as explicit as possible, so that users can
see at first glance, what functionality is being tested and what tests see at first glance, what functionality is being tested and what tests
need to be added. need to be added.
Example:
.. code-block:: python
import unittest
class TestTensorDot(unittest.TestCase):
def test_validity(self):
# do stuff
...
def test_invalid_dims(self):
# do more stuff
...
Test cases can define a special setUp method, which will get called
before each test method is executed. This is a good place to put
functionality which is shared amongst all test methods in the test
case (i.e initializing data, parameters, seeding random number
generators -- more on this later)
.. testcode:: writeUnitest
import unittest
class TestTensorDot(unittest.TestCase):
def setUp(self):
# data which will be used in various test methods
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]])
Similarly, test cases can define a tearDown method, which will be
implicitely called at the end of each test method.
Checking for correctness Checking for correctness
------------------------ ------------------------
When checking for correctness of mathematical expressions, the user When checking for correctness of mathematical expressions, the user
should preferably compare aesara's output to the equivalent numpy should preferably compare aesara's output to the equivalent NumPy
implementation. implementation.
Example: Example:
.. code-block:: python .. code-block:: python
class TestTensorDot(unittest.TestCase): def test_dot_validity():
def setUp(self): a = aet.dmatrix('a')
... b = aet.dmatrix('b')
c = aet.dot(a, b)
def test_validity(self): f = aesara.function([a, b], [c])
a = T.dmatrix('a') assert np.array_equal(f(self.avals, self.bvals), numpy.dot(self.avals, self.bvals))
b = T.dmatrix('b')
c = T.dot(a, b)
f = aesara.function([a, b], [c])
cmp = f(self.avals, self.bvals) == numpy.dot(self.avals, self.bvals)
self.assertTrue(numpy.all(cmp))
Avoid hard-coding variables, as in the following case:
.. code-block:: python
self.assertTrue(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 variables each time the input is changed or possibly when the
module being tested changes (after a bug fix for example). It also
constrains the test case to specific input/output data pairs. The
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:
* checking the state of boolean variables: assert,
assertTrue, assertFalse
* checking for (in)equality constraints: assertEqual,
assertNotEqual
* checking for (in)equality constraints up to a given precision (very
useful in aesara): assertAlmostEqual,
assertNotAlmostEqual
Checking for errors
-------------------
On top of verifying that your code provides the correct output, it is
equally important to test that it fails in the appropriate manner,
raising the appropriate exceptions, etc. Silent failures are deadly,
as they can go unnoticed for a long time and a hard to detect
"after-the-fact".
Example:
.. code-block:: python
import unittest
class TestTensorDot(unittest.TestCase):
...
def test_3D_dot_fail(self):
def func():
a = TensorType('float64', (False,False,False)) # create 3d tensor
b = dmatrix()
c = dot(a,b) # we expect this to fail
# above should fail as dot operates on 2D tensors only
self.assertRaises(TypeError, func)
Useful function, as defined by TestCase:
* assertRaises
Test Cases and Aesara Modes
---------------------------
When compiling aesara functions or modules, a mode parameter can be
given to specify which linker and optimizer to use.
Example:
.. code-block:: python
from aesara import function
f = function([a,b],[c],mode='FAST_RUN')
Whenever possible, unit tests should omit this parameter. Leaving
out the mode will ensure that unit tests use the default mode.
This default mode is set to
the configuration variable :attr:`config.mode`, which defaults to
'FAST_RUN', and can be set by various mechanisms (see :mod:`config`).
In particular, the enviromnment variable :envvar:`AESARA_FLAGS`
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
AESARA_FLAGS='mode=FAST_COMPILE' pytest
AESARA_FLAGS='mode=FAST_RUN' pytest
AESARA_FLAGS='mode=DebugMode' pytest
.. _random_value_in_tests:
Using Random Values in Test Cases
---------------------------------
``numpy.random`` is often used in unit tests to initialize large data
structures, for use as inputs to the function or module being
tested. When doing this, it is imperative that the random number
generator be seeded at the be beginning of each unit test. This will
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 following:
.. testcode::
from tests import unittest_tools
class TestTensorDot(unittest.TestCase):
def setUp(self):
unittest_tools.seed_rng()
# OR ... call with an explicit seed
unittest_tools.seed_rng(234234) # use only if really necessary!
The behaviour of ``seed_rng`` is as follows:
* If an explicit seed is given, it will be used for seeding numpy's rng.
* If not, it will use ``config.unittests__rseed`` (its default value is ``666``).
* If ``config.unittests__rseed`` is set to ``"random"``, it will seed the rng with
None, which is equivalent to seeding with a random seed.
The main advantage of using ``unittest_tools.seed_rng`` is that it allows
us to change the seed used in the unitests, without having to manually
edit all the files. For example, this allows the nightly build to run
``pytest`` repeatedly, changing the seed on every run (hence achieving
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) can simply set ``config.unittests__rseed`` to ``'random'`` (see
:mod:`config`).
Similarly, to provide a seed to ``numpy.random.RandomState``, simply use:
.. testcode::
import numpy
rng = numpy.random.RandomState(unittest_tools.fetch_seed())
# OR providing an explicit seed
rng = numpy.random.RandomState(unittest_tools.fetch_seed(1231)) # again not recommended
Note that the ability to change the seed from one test to another,
is incompatible with the method of hard-coding the baseline variables
(against which we compare the aesara outputs). These must then be
determined "algorithmically". Although this represents more work, the
test suite will be better because of it.
To help you check that the boundaries provided to ``numpy.random`` are
correct and your tests will pass those corner cases, you can check
``utt.MockRandomState``. Code using ``utt.MockRandomState`` should not
be committed, it is just a tool to help adjust the sampling range.
Creating an Op UnitTest Creating an Op Unit Test
======================= =======================
A few tools have been developed to help automate the development of A few tools have been developed to help automate the development of
unitests for Aesara Ops. unit tests for Aesara Ops.
.. _validating_grad: .. _validating_grad:
......
...@@ -16,6 +16,11 @@ arrays efficiently. Aesara features: ...@@ -16,6 +16,11 @@ arrays efficiently. Aesara features:
Aesara is based on `Theano`_, which has been powering large-scale computationally Aesara is based on `Theano`_, which has been powering large-scale computationally
intensive scientific investigations since 2007. intensive scientific investigations since 2007.
.. warning::
Much of the documentation hasn't been updated and is simply the old Theano documentation.
Download Download
======== ========
...@@ -69,7 +74,6 @@ Roughly in order of what you'll want to check out: ...@@ -69,7 +74,6 @@ Roughly in order of what you'll want to check out:
:maxdepth: 1 :maxdepth: 1
:hidden: :hidden:
NEWS
introduction introduction
requirements requirements
install install
......
...@@ -12,7 +12,6 @@ Supported platforms: ...@@ -12,7 +12,6 @@ Supported platforms:
install_macos install_macos
install_windows install_windows
install_centos6 install_centos6
install_others
Once your setup is complete and if you installed the GPU libraries, head to :ref:`testing_the_gpu` to find how to verify Once your setup is complete and if you installed the GPU libraries, head to :ref:`testing_the_gpu` to find how to verify
everything is working properly. everything is working properly.
......
...@@ -8,8 +8,5 @@ Internal Documentation ...@@ -8,8 +8,5 @@ Internal Documentation
.. toctree:: .. toctree::
:maxdepth: 2 :maxdepth: 2
release
dev_start_guide
metadocumentation metadocumentation
python
how_to_release how_to_release
...@@ -85,31 +85,3 @@ It will not appear in the output generated. ...@@ -85,31 +85,3 @@ It will not appear in the output generated.
.. TODO: Check it out, this won't appear. .. TODO: Check it out, this won't appear.
.. Nor will this. .. Nor will this.
How documentation is built
----------------------------------------------
TBD
pylint
---------------------------------------
pylint output is not autogenerated anymore.
Pylint documentation is generated using pylintrc file: ``Aesara/doc/pylintrc``
.. _metadocumentation_nightly_build:
The nightly build/tests process
---------------------------------------
We use GitHub Actions to run daily builds and test for Aesara.
TO WRITE
---------------------------------------
*There is other stuff to document here, e.g.:*
* We also want examples of good documentation, to show people how to write ReST.
...@@ -9,8 +9,7 @@ Aesara is a Python library that lets you define, optimize, and evaluate ...@@ -9,8 +9,7 @@ Aesara is a Python library that lets you define, optimize, and evaluate
mathematical expressions, especially ones with multi-dimensional arrays mathematical expressions, especially ones with multi-dimensional arrays
(numpy.ndarray). Using Aesara it is (numpy.ndarray). Using Aesara it is
possible to attain speeds rivaling hand-crafted C implementations for problems possible to attain speeds rivaling hand-crafted C implementations for problems
involving large amounts of data. It can also surpass C on a CPU by many orders involving large amounts of data.
of magnitude by taking advantage of recent GPUs.
Aesara combines aspects of a computer algebra system (CAS) with aspects of an Aesara combines aspects of a computer algebra system (CAS) with aspects of an
optimizing compiler. It can also generate customized C code for many optimizing compiler. It can also generate customized C code for many
...@@ -25,7 +24,6 @@ Aesara's compiler applies many optimizations of varying complexity to ...@@ -25,7 +24,6 @@ Aesara's compiler applies many optimizations of varying complexity to
these symbolic expressions. These optimizations include, but are not these symbolic expressions. These optimizations include, but are not
limited to: limited to:
* use of GPU for computations
* constant folding * constant folding
* merging of similar subgraphs, to avoid redundant calculation * merging of similar subgraphs, to avoid redundant calculation
* arithmetic simplification (e.g. ``x*y/x -> y``, ``--x -> x``) * arithmetic simplification (e.g. ``x*y/x -> y``, ``--x -> x``)
......
...@@ -682,4 +682,4 @@ reference ...@@ -682,4 +682,4 @@ reference
.. autofunction:: aesara.foldl .. autofunction:: aesara.foldl
.. autofunction:: aesara.foldr .. autofunction:: aesara.foldr
.. autofunction:: aesara.scan .. autofunction:: aesara.scan
.. autofunction:: aesara.scan_checkpoints .. autofunction:: aesara.scan.scan_checkpoints
...@@ -465,7 +465,7 @@ TensorVariable ...@@ -465,7 +465,7 @@ TensorVariable
you'll want to call. you'll want to call.
.. autoclass:: _tensor_py_operators .. autoclass:: var._tensor_py_operators
:members: :members:
This mix-in class adds convenient attributes, methods, and support This mix-in class adds convenient attributes, methods, and support
...@@ -1749,7 +1749,7 @@ Linear Algebra ...@@ -1749,7 +1749,7 @@ Linear Algebra
Gradient / Differentiation Gradient / Differentiation
========================== ==========================
.. automodule:: Aesara.gradient .. automodule:: aesara.gradient
:members: grad :members: grad
:noindex: :noindex:
......
File mode changed from 100755 to 100644
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论