提交 4e7fcf8a authored 作者: Arnaud Bergeron's avatar Arnaud Bergeron

Add a mini-tutorial on how to use op params.

上级 a6e0ff7a
......@@ -33,6 +33,7 @@ a C implementation.
other_ops
ctype
cop
using_params
optimization
tips
unittest
......
.. _extending_op_params:
===============
Using Op params
===============
The Op params is a facility to pass some runtime parameters to the
code of an op without modifying it. It can enable a single instance
of C code to serve different needs and therefore reduce compilation.
I will first introduce the parts involved in actually using this
functionality and then present a simple working example.
The params type
----------------
You can either reuse an existing type such as :class:`Generic` or
:class:`CDataType`, or create your own.
Defining a params type
~~~~~~~~~~~~~~~~~~~~~~~
.. note::
This section is only relevant if you decide to create your own type.
The first thing you need to do is to define a Theano Type for your
params object. It doesn't have to be complete type because only the
following methods will be used for the type:
- :meth:`filter <PureType.filter>`
- :meth:`__eq__ <PureType.__eq__>`
- :meth:`__hash__ <PureType.__hash__>`
- :meth:`values_eq <PureType.values_eq>`
Additionaly if you want to use your params with C code, you need the
following methods:
- :meth:`c_declare <CLinkerType.c_declare>`
- :meth:`c_init <CLinkerType.c_init>`
- :meth:`c_extract <CLinkerType.c_extract>`
- :meth:`c_cleanup <CLinkerType.c_cleanup>`
You can also define other convinience methods such as
:meth:`c_headers <CLinkerType.c_headers>` if you need any special things.
Registering the params with your Op
-----------------------------------
To declare that your op uses params you have to set the class
attribute :attr:`params_type` to an instance of your params Type.
For example if we decide to use a pointer to an int as the params the
following would be appropriate:
.. code-block:: python
class MyOp(Op):
params_type = CDataType('int')
After that you need to define a :meth:`get_params` method on your
class with the following signature:
.. code-block:: python
def get_params(self, node):
pass
This methods must return a valid object for your Type (an object that
passes :meth:`filter`). The `node` parameter is the Apply node for
which we want the params. Therefore the params object can depend on
the inputs and outputs of the node.
.. note::
Due to implementation restrictions, None is not allowed as a
params object and will be taken to mean that the Op doesn't have
parameters.
Since this will change the expected signature of a few methods, it
is strongly discouraged to have your :meth:`get_params` method
return None.
Signature changes from having params
------------------------------------
Having declared a params for you Op will affect the expected signature
of :meth:`perform`. The new expected signature will have an extra
parameter at the end which corresponds to the params object.
.. warning::
If you do not account for this extra parameter, the code will fail
at runtime if it tries to run the python version.
Also, for the C code, the `sub` dictionary will contain an extra entry
`'params'` which will map to the variable name of the params object.
This is true for all methods that recieve a `sub` parameter, so this
means that you can use your params in the :meth:`c_init_code_struct
<Op.c_init_code_struct>` method.
A simple example
----------------
This is a simple example which uses a params object to pass a value.
The value in this case is a python float, hence the choice of Generic
as the params type.
.. testcode::
from theano import Op
from theano.gof.type import Generic
from theano.scalar import as_scalar
class MulOp(Op):
params_type = Generic()
__props__ = ('mul',)
def __init__(self, mul):
self.mul = float(mul)
def get_params(self, node):
return self.mul
def make_node(self, inp):
inp = as_scalar(inp)
return Apply(self, [inp], [inp.type()]
def perform(self, node, inputs, output_storage, params):
# Here params is a python float so this is ok
output_storage[0][0] = inputs[0] * params
def c_code(self, node, name, inputs, outputs, sub):
return ("%(z)s = %(x)s * PyFloat_AsDouble(%(p)s);" %
dict(z=outputs[0], x=inputs[0], p=sub['params']))
.. testoutput::
:hide:
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论