提交 1ddf666e authored 作者: Brandon T. Willard's avatar Brandon T. Willard 提交者: Brandon T. Willard

Add missing documentation formatting and docstrings

上级 f22d3165
...@@ -470,11 +470,7 @@ def get_precision(precision, inputs, for_grad=False): ...@@ -470,11 +470,7 @@ def get_precision(precision, inputs, for_grad=False):
class DnnBase(_NoPythonExternalCOp): class DnnBase(_NoPythonExternalCOp):
"""An `Op` that creates a handle for cudnn and pulls in the cudnn libraries and headers."""
"""
Creates a handle for cudnn and pulls in the cudnn libraries and headers.
"""
# dnn does not know about broadcasting, so we do not need to assert # dnn does not know about broadcasting, so we do not need to assert
# the input broadcasting pattern. # the input broadcasting pattern.
......
差异被折叠。
...@@ -241,9 +241,10 @@ class FunctionGraph(MetaObject): ...@@ -241,9 +241,10 @@ class FunctionGraph(MetaObject):
Parameters Parameters
---------- ----------
var : Variable. var : Variable
The `Variable` to be updated.
new_client : (Apply, int) new_client : (Apply, int)
A `(node, i)` pair such that `node.inputs[i]` is `var`. A ``(node, i)`` pair such that ``node.inputs[i]`` is `var`.
""" """
self.clients[var].append(new_client) self.clients[var].append(new_client)
...@@ -251,7 +252,7 @@ class FunctionGraph(MetaObject): ...@@ -251,7 +252,7 @@ class FunctionGraph(MetaObject):
def remove_client( def remove_client(
self, var: Variable, client_to_remove: Tuple[Apply, int], reason: str = None self, var: Variable, client_to_remove: Tuple[Apply, int], reason: str = None
) -> None: ) -> None:
"""Recursively removes clients of a variable. """Recursively remove clients of a variable.
This is the main method to remove variables or `Apply` nodes from This is the main method to remove variables or `Apply` nodes from
a `FunctionGraph`. a `FunctionGraph`.
...@@ -265,7 +266,7 @@ class FunctionGraph(MetaObject): ...@@ -265,7 +266,7 @@ class FunctionGraph(MetaObject):
var : Variable var : Variable
The clients of `var` that will be removed. The clients of `var` that will be removed.
client_to_remove : pair of (Apply, int) client_to_remove : pair of (Apply, int)
A `(node, i)` pair such that `node.inputs[i]` will no longer be A ``(node, i)`` pair such that ``node.inputs[i]`` will no longer be
`var` in this `FunctionGraph`. `var` in this `FunctionGraph`.
""" """
...@@ -359,11 +360,11 @@ class FunctionGraph(MetaObject): ...@@ -359,11 +360,11 @@ class FunctionGraph(MetaObject):
reason: str = None, reason: str = None,
import_missing: bool = False, import_missing: bool = False,
) -> None: ) -> None:
"""Recursively import everything between an `Apply` node and the `FunctionGraph`'s outputs. """Recursively import everything between an ``Apply`` node and the ``FunctionGraph``'s outputs.
Parameters Parameters
---------- ----------
apply_node : aesara.graph.basic.Apply apply_node : Apply
The node to be imported. The node to be imported.
check : bool check : bool
Check that the inputs for the imported nodes are also present in Check that the inputs for the imported nodes are also present in
...@@ -419,7 +420,7 @@ class FunctionGraph(MetaObject): ...@@ -419,7 +420,7 @@ class FunctionGraph(MetaObject):
def change_input( def change_input(
self, self,
node: Apply, node: Union[Apply, str],
i: int, i: int,
new_var: Variable, new_var: Variable,
reason: str = None, reason: str = None,
...@@ -435,15 +436,15 @@ class FunctionGraph(MetaObject): ...@@ -435,15 +436,15 @@ class FunctionGraph(MetaObject):
Parameters Parameters
---------- ----------
node : aesara.graph.basic.Apply or str node
The node for which an input is to be changed. If the value is The node for which an input is to be changed. If the value is
the string ``"output"`` then the ``self.outputs`` will be used the string ``"output"`` then the ``self.outputs`` will be used
instead of ``node.inputs``. instead of ``node.inputs``.
i : int i
The index in `node.inputs` that we want to change. The index in `node.inputs` that we want to change.
new_var : aesara.graph.basic.Variable new_var
The new variable to take the place of ``node.inputs[i]``. The new variable to take the place of ``node.inputs[i]``.
import_missing : bool import_missing
Add missing inputs instead of raising an exception. Add missing inputs instead of raising an exception.
""" """
# TODO: ERROR HANDLING FOR LISTENERS (should it complete the change or revert it?) # TODO: ERROR HANDLING FOR LISTENERS (should it complete the change or revert it?)
...@@ -494,15 +495,15 @@ class FunctionGraph(MetaObject): ...@@ -494,15 +495,15 @@ class FunctionGraph(MetaObject):
Parameters Parameters
---------- ----------
var : aesara.graph.basic.Variable var
The variable to be replaced. The variable to be replaced.
new_var : aesara.graph.basic.Variable new_var
The variable to replace `var`. The variable to replace `var`.
reason : str reason
The name of the optimization or operation in progress. The name of the optimization or operation in progress.
verbose : bool verbose
Print `reason`, `var`, and `new_var`. Print `reason`, `var`, and `new_var`.
import_missing : bool import_missing
Import missing variables. Import missing variables.
""" """
...@@ -548,12 +549,12 @@ class FunctionGraph(MetaObject): ...@@ -548,12 +549,12 @@ class FunctionGraph(MetaObject):
) )
def replace_all(self, pairs: List[Tuple[Variable, Variable]], **kwargs) -> None: def replace_all(self, pairs: List[Tuple[Variable, Variable]], **kwargs) -> None:
"""Replace variables in the ``FunctionGraph`` according to ``(var, new_var)`` pairs in a list.""" """Replace variables in the `FunctionGraph` according to ``(var, new_var)`` pairs in a list."""
for var, new_var in pairs: for var, new_var in pairs:
self.replace(var, new_var, **kwargs) self.replace(var, new_var, **kwargs)
def attach_feature(self, feature: Feature) -> None: def attach_feature(self, feature: Feature) -> None:
"""Add a ``graph.features.Feature`` to this function graph and trigger its on_attach callback.""" """Add a ``graph.features.Feature`` to this function graph and trigger its ``on_attach`` callback."""
# Filter out literally identical `Feature`s # Filter out literally identical `Feature`s
if feature in self._features: if feature in self._features:
return # the feature is already present return # the feature is already present
...@@ -579,10 +580,9 @@ class FunctionGraph(MetaObject): ...@@ -579,10 +580,9 @@ class FunctionGraph(MetaObject):
self._features.append(feature) self._features.append(feature)
def remove_feature(self, feature: Feature) -> None: def remove_feature(self, feature: Feature) -> None:
""" """Remove a feature from the graph.
Removes the feature from the graph.
Calls feature.on_detach(function_graph) if an on_detach method Calls ``feature.on_detach(function_graph)`` if an ``on_detach`` method
is defined. is defined.
""" """
...@@ -596,9 +596,9 @@ class FunctionGraph(MetaObject): ...@@ -596,9 +596,9 @@ class FunctionGraph(MetaObject):
detach(self) detach(self)
def execute_callbacks(self, name: str, *args, **kwargs) -> None: def execute_callbacks(self, name: str, *args, **kwargs) -> None:
"""Execute callbacks """Execute callbacks.
Calls `getattr(feature, name)(*args)` for each feature which has Calls ``getattr(feature, name)(*args)`` for each feature which has
a method called after name. a method called after name.
""" """
...@@ -619,8 +619,7 @@ class FunctionGraph(MetaObject): ...@@ -619,8 +619,7 @@ class FunctionGraph(MetaObject):
def collect_callbacks(self, name: str, *args) -> Dict[Feature, Any]: def collect_callbacks(self, name: str, *args) -> Dict[Feature, Any]:
"""Collects callbacks """Collects callbacks
Returns a dictionary d such that Returns a dictionary d such that ``d[feature] == getattr(feature, name)(*args)``
`d[feature] == getattr(feature, name)(*args)`
For each feature which has a method called after name. For each feature which has a method called after name.
""" """
d = {} d = {}
...@@ -633,17 +632,17 @@ class FunctionGraph(MetaObject): ...@@ -633,17 +632,17 @@ class FunctionGraph(MetaObject):
return d return d
def toposort(self) -> List[Apply]: def toposort(self) -> List[Apply]:
"""Toposort """Return a toposorted list of the nodes.
Return an ordering of the graph's Apply nodes such that Return an ordering of the graph's ``Apply`` nodes such that:
* All the nodes of the inputs of a node are before that node. * all the nodes of the inputs of a node are before that node and
* Satisfies the orderings provided by each feature that has * they satisfy the orderings provided by each feature that has
an 'orderings' method. an ``orderings`` method.
If a feature has an 'orderings' method, it will be called with If a feature has an ``orderings`` method, it will be called with
this FunctionGraph as sole argument. It should return a dictionary of this `FunctionGraph` as sole argument. It should return a dictionary of
`{node: predecessors}` where predecessors is a list of nodes that ``{node: predecessors}`` where predecessors is a list of nodes that
should be computed before the key node. should be computed before the key node.
""" """
if len(self.apply_nodes) < 2: if len(self.apply_nodes) < 2:
...@@ -661,15 +660,15 @@ class FunctionGraph(MetaObject): ...@@ -661,15 +660,15 @@ class FunctionGraph(MetaObject):
return order return order
def orderings(self) -> Dict[Apply, List[Apply]]: def orderings(self) -> Dict[Apply, List[Apply]]:
"""Return `dict` `d` s.t. `d[node]` is a list of nodes that must be evaluated before `node` itself can be evaluated. """Return ``dict`` ``d`` s.t. ``d[node]`` is a list of nodes that must be evaluated before ``node`` itself can be evaluated.
This is used primarily by the destroy_handler feature to ensure that This is used primarily by the ``destroy_handler`` feature to ensure that
the clients of any destroyed inputs have already computed their the clients of any destroyed inputs have already computed their
outputs. outputs.
Notes Notes
----- -----
This only calls the `orderings()` function on all features. It does not This only calls the ``orderings()`` function on all features. It does not
take care of computing the dependencies by itself. take care of computing the dependencies by itself.
""" """
...@@ -707,10 +706,7 @@ class FunctionGraph(MetaObject): ...@@ -707,10 +706,7 @@ class FunctionGraph(MetaObject):
return ords return ords
def check_integrity(self) -> None: def check_integrity(self) -> None:
""" """Check the integrity of nodes in the graph."""
Call this for a diagnosis if things go awry.
"""
nodes = set(applys_between(self.inputs, self.outputs)) nodes = set(applys_between(self.inputs, self.outputs))
if self.apply_nodes != nodes: if self.apply_nodes != nodes:
missing = nodes.difference(self.apply_nodes) missing = nodes.difference(self.apply_nodes)
...@@ -763,10 +759,7 @@ class FunctionGraph(MetaObject): ...@@ -763,10 +759,7 @@ class FunctionGraph(MetaObject):
return f"FunctionGraph({', '.join(graph_as_string(self.inputs, self.outputs))})" return f"FunctionGraph({', '.join(graph_as_string(self.inputs, self.outputs))})"
def clone(self, check_integrity=True) -> "FunctionGraph": def clone(self, check_integrity=True) -> "FunctionGraph":
""" """Clone the graph."""
Clone the graph and get a memo( a dict )that map old node to new node
"""
return self.clone_get_equiv(check_integrity)[0] return self.clone_get_equiv(check_integrity)[0]
def clone_get_equiv( def clone_get_equiv(
...@@ -806,11 +799,8 @@ class FunctionGraph(MetaObject): ...@@ -806,11 +799,8 @@ class FunctionGraph(MetaObject):
return e, equiv return e, equiv
def __getstate__(self): def __getstate__(self):
""" # This is needed as some features introduce instance methods
This is needed as some features introduce instance methods. # This is not picklable
This is not picklable.
"""
d = self.__dict__.copy() d = self.__dict__.copy()
for feature in self._features: for feature in self._features:
for attr in getattr(feature, "pickle_rm_attr", []): for attr in getattr(feature, "pickle_rm_attr", []):
......
差异被折叠。
差异被折叠。
...@@ -33,11 +33,15 @@ class Type(MetaObject): ...@@ -33,11 +33,15 @@ class Type(MetaObject):
""" """
# the type that will be created by a call to make_variable.
Variable = Variable Variable = Variable
"""
The `Type` that will be created by a call to `Type.make_variable`.
"""
# the type that will be created by a call to make_constant
Constant = Constant Constant = Constant
"""
The `Type` that will be created by a call to `Type.make_constant`.
"""
@abstractmethod @abstractmethod
def filter( def filter(
......
差异被折叠。
...@@ -1845,10 +1845,10 @@ class SamplingDotCSR(_NoPythonCOp): ...@@ -1845,10 +1845,10 @@ class SamplingDotCSR(_NoPythonCOp):
multiplication. multiplication.
If we have the input of mixed dtype, we insert cast elemwise If we have the input of mixed dtype, we insert cast elemwise
in the graph to be able to call blas function as they don't in the graph to be able to call BLAS function as they don't
allow mixed dtype. allow mixed dtype.
This op is used as an optimization for SamplingDot. This `Op` is used as an optimization for `SamplingDot`.
""" """
......
...@@ -216,8 +216,8 @@ def broadcast_like(value, template, fgraph, dtype=None): ...@@ -216,8 +216,8 @@ def broadcast_like(value, template, fgraph, dtype=None):
class InplaceElemwiseOptimizer(GlobalOptimizer): class InplaceElemwiseOptimizer(GlobalOptimizer):
""" r"""
We parametrise it to make it work for Elemwise and GpuElemwise op. This is parameterized so that it works for `Elemwise` and `GpuElemwise` `Op`\s.
""" """
def __init__(self, OP): def __init__(self, OP):
...@@ -1469,7 +1469,7 @@ class ShapeFeature(features.Feature): ...@@ -1469,7 +1469,7 @@ class ShapeFeature(features.Feature):
class ShapeOptimizer(GlobalOptimizer): class ShapeOptimizer(GlobalOptimizer):
"""Optimizer that serves to add ShapeFeature as an fgraph feature.""" """Optimizer that adds `ShapeFeature` as a feature."""
def add_requirements(self, fgraph): def add_requirements(self, fgraph):
fgraph.attach_feature(ShapeFeature()) fgraph.attach_feature(ShapeFeature())
...@@ -1479,7 +1479,7 @@ class ShapeOptimizer(GlobalOptimizer): ...@@ -1479,7 +1479,7 @@ class ShapeOptimizer(GlobalOptimizer):
class UnShapeOptimizer(GlobalOptimizer): class UnShapeOptimizer(GlobalOptimizer):
"""Optimizer remove ShapeFeature as an fgraph feature.""" """Optimizer that removes `ShapeFeature` as a feature."""
def apply(self, fgraph): def apply(self, fgraph):
for feature in fgraph._features: for feature in fgraph._features:
......
差异被折叠。
...@@ -112,7 +112,7 @@ def indices_from_subtensor( ...@@ -112,7 +112,7 @@ def indices_from_subtensor(
def as_index_constant(a): def as_index_constant(a):
r"""Convert Python literals to Aesara constants--when possible--in Subtensor arguments. r"""Convert Python literals to Aesara constants--when possible--in `Subtensor` arguments.
This will leave `Variable`\s untouched. This will leave `Variable`\s untouched.
""" """
......
...@@ -102,7 +102,7 @@ exclude_dirs = ["images", "scripts", "sandbox"] ...@@ -102,7 +102,7 @@ exclude_dirs = ["images", "scripts", "sandbox"]
# The reST default role (used for this markup: `text`) to use for all # The reST default role (used for this markup: `text`) to use for all
# documents. # documents.
# default_role = None default_role = "py:obj"
# If true, '()' will be appended to :func: etc. cross-reference text. # If true, '()' will be appended to :func: etc. cross-reference text.
# add_function_parentheses = True # add_function_parentheses = True
......
...@@ -91,7 +91,7 @@ output. You can now print the name of the op that is applied to get ...@@ -91,7 +91,7 @@ output. You can now print the name of the op that is applied to get
>>> y.owner.op.name >>> y.owner.op.name
'Elemwise{mul,no_inplace}' 'Elemwise{mul,no_inplace}'
Hence, an elementwise multiplication is used to compute *y*. This Hence, an element-wise multiplication is used to compute *y*. This
multiplication is done between the inputs: multiplication is done between the inputs:
>>> len(y.owner.inputs) >>> len(y.owner.inputs)
......
差异被折叠。
...@@ -24,10 +24,10 @@ in the :ref:`graphstructures` article. ...@@ -24,10 +24,10 @@ in the :ref:`graphstructures` article.
Compilation of the computation graph Compilation of the computation graph
------------------------------------ ------------------------------------
Once the user has built a computation graph, she can use Once the user has built a computation graph, they can use
``aesara.function`` in order to make one or more functions that :func:`aesara.function` in order to make one or more functions that
operate on real data. function takes a list of input :ref:`Variables operate on real data. function takes a list of input :ref:`Variables
<variable>` as well as a list of output Variables that define a <variable>` as well as a list of output :class:`Variable`\s that define a
precise subgraph corresponding to the function(s) we want to define, precise subgraph corresponding to the function(s) we want to define,
compile that subgraph and produce a callable. compile that subgraph and produce a callable.
...@@ -35,32 +35,32 @@ Here is an overview of the various steps that are done with the ...@@ -35,32 +35,32 @@ Here is an overview of the various steps that are done with the
computation graph in the compilation phase: computation graph in the compilation phase:
Step 1 - Create a FunctionGraph Step 1 - Create a :class:`FunctionGraph`
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The subgraph given by the end user is wrapped in a structure called The subgraph given by the end user is wrapped in a structure called
*FunctionGraph*. That structure defines several hooks on adding and :class:`FunctionGraph`. That structure defines several hooks on adding and
removing (pruning) nodes as well as on modifying links between nodes removing (pruning) nodes as well as on modifying links between nodes
(for example, modifying an input of an :ref:`apply` node) (see the (for example, modifying an input of an :ref:`apply` node) (see the
article about :ref:`libdoc_graph_fgraph` for more information). article about :ref:`libdoc_graph_fgraph` for more information).
FunctionGraph provides a method to change the input of an Apply node from one :class:`FunctionGraph` provides a method to change the input of an :class:`Apply` node from one
Variable to another and a more high-level method to replace a Variable :class:`Variable` to another and a more high-level method to replace a :class:`Variable`
with another. This is the structure that :ref:`Optimizers with another. This is the structure that :ref:`Optimizers
<optimization>` work on. <optimization>` work on.
Some relevant :ref:`Features <libdoc_graph_fgraphfeature>` are typically added to the Some relevant :ref:`Features <libdoc_graph_fgraphfeature>` are typically added to the
FunctionGraph, namely to prevent any optimization from operating inplace on :class:`FunctionGraph`, namely to prevent any optimization from operating inplace on
inputs declared as immutable. inputs declared as immutable.
Step 2 - Execute main Optimizer Step 2 - Execute main :class:`Optimizer`
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Once the FunctionGraph is made, an :term:`optimizer` is produced by Once the :class:`FunctionGraph` is made, an :term:`optimizer` is produced by
the :term:`mode` passed to ``function`` (the Mode basically has two the :term:`mode` passed to :func:`function` (the :class:`Mode` basically has two
important fields, ``linker`` and ``optimizer``). That optimizer is important fields, :attr:`linker` and :attr:`optimizer`). That optimizer is
applied on the FunctionGraph using its optimize() method. applied on the :class:`FunctionGraph` using its :meth:`Optimizer.optimize` method.
The optimizer is typically obtained through :attr:`optdb`. The optimizer is typically obtained through :attr:`optdb`.
...@@ -69,11 +69,10 @@ Step 3 - Execute linker to obtain a thunk ...@@ -69,11 +69,10 @@ Step 3 - Execute linker to obtain a thunk
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Once the computation graph is optimized, the :term:`linker` is Once the computation graph is optimized, the :term:`linker` is
extracted from the Mode. It is then called with the FunctionGraph as extracted from the :class:`Mode`. It is then called with the :class:`FunctionGraph` as
argument to argument to produce a ``thunk``, which is a function with no arguments that
produce a ``thunk``, which is a function with no arguments that
returns nothing. Along with the thunk, one list of input containers (a returns nothing. Along with the thunk, one list of input containers (a
`aesara.link.basic.Container` is a sort of object that wraps another and does :class:`aesara.link.basic.Container` is a sort of object that wraps another and does
type casting) and one list of output containers are produced, type casting) and one list of output containers are produced,
corresponding to the input and output :class:`Variable`\s as well as the updates corresponding to the input and output :class:`Variable`\s as well as the updates
defined for the inputs when applicable. To perform the computations, defined for the inputs when applicable. To perform the computations,
...@@ -83,18 +82,18 @@ where the thunk put them. ...@@ -83,18 +82,18 @@ where the thunk put them.
Typically, the linker calls the ``toposort`` method in order to obtain Typically, the linker calls the ``toposort`` method in order to obtain
a linear sequence of operations to perform. How they are linked a linear sequence of operations to perform. How they are linked
together depends on the Linker used. The `CLinker` produces a single together depends on the Linker used. The :class:`CLinker` produces a single
block of C code for the whole computation, whereas the `OpWiseCLinker` block of C code for the whole computation, whereas the :class:`OpWiseCLinker`
produces one thunk for each individual operation and calls them in produces one thunk for each individual operation and calls them in
sequence. sequence.
The linker is where some options take effect: the ``strict`` flag of The linker is where some options take effect: the ``strict`` flag of
an input makes the associated input container do type checking. The an input makes the associated input container do type checking. The
``borrow`` flag of an output, if False, adds the output to a ``borrow`` flag of an output, if ``False``, adds the output to a
``no_recycling`` list, meaning that when the thunk is called the ``no_recycling`` list, meaning that when the thunk is called the
output containers will be cleared (if they stay there, as would be the output containers will be cleared (if they stay there, as would be the
case if ``borrow`` was True, the thunk would be allowed to reuse (or case if ``borrow`` was True, the thunk would be allowed to reuse--or
"recycle") the storage). "recycle"--the storage).
.. note:: .. note::
...@@ -119,6 +118,6 @@ Step 4 - Wrap the thunk in a pretty package ...@@ -119,6 +118,6 @@ Step 4 - Wrap the thunk in a pretty package
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The thunk returned by the linker along with input and output The thunk returned by the linker along with input and output
containers is unwieldy. ``function`` hides that complexity away so containers is unwieldy. :func:`aesara.function` hides that complexity away so
that it can be used like a normal function with arguments and return that it can be used like a normal function with arguments and return
values. values.
==== ====
Tips Tips
==== ====
...@@ -8,15 +6,15 @@ Tips ...@@ -8,15 +6,15 @@ Tips
Reusing outputs Reusing outputs
=============== ===============
WRITEME .. todo:: Write this.
Don't define new Ops unless you have to Don't define new :class:`Op`\s unless you have to
======================================= =================================================
It is usually not useful to define Ops that can be easily It is usually not useful to define :class:`Op`\s that can be easily
implemented using other already existing Ops. For example, instead of implemented using other already existing :class:`Op`\s. For example, instead of
writing a "sum_square_difference" Op, you should probably just write a writing a "sum_square_difference" :class:`Op`, you should probably just write a
simple function: simple function:
.. testcode:: .. testcode::
...@@ -33,23 +31,23 @@ a custom implementation would probably only bother to support ...@@ -33,23 +31,23 @@ a custom implementation would probably only bother to support
contiguous vectors/matrices of doubles... contiguous vectors/matrices of doubles...
Use Aesara's high order Ops when applicable Use Aesara's high order :class:`Op`\s when applicable
=========================================== =====================================================
Aesara provides some generic Op classes which allow you to generate a Aesara provides some generic :class:`Op` classes which allow you to generate a
lot of Ops at a lesser effort. For instance, Elemwise can be used to lot of :class:`Op`\s at a lesser effort. For instance, :class:`Elemwise` can be used to
make :term:`elemwise` operations easily whereas DimShuffle can be make :term:`elemwise` operations easily, whereas :class:`DimShuffle` can be
used to make transpose-like transformations. These higher order Ops used to make transpose-like transformations. These higher order :class:`Op`\s
are mostly Tensor-related, as this is Aesara's specialty. are mostly tensor-related, as this is Aesara's specialty.
.. _opchecklist: .. _opchecklist:
Op Checklist :class:`Op` Checklist
============ =====================
Use this list to make sure you haven't forgotten anything when Use this list to make sure you haven't forgotten anything when
defining a new Op. It might not be exhaustive but it covers a lot of defining a new :class:`Op`. It might not be exhaustive but it covers a lot of
common mistakes. common mistakes.
WRITEME .. todo:: Write a list.
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论