|
2 | 2 | Optimizer Passes and Flows |
3 | 3 | ========================== |
4 | 4 |
|
5 | | -The ``hls4ml`` package internally represents the model graph with the :py:class:`~hls4ml.model.graph.ModelGraph` class. |
6 | | -The nodes in this graph are represented by classes derived from the :py:class:`~hls4ml.model.layers.Layer` base class. |
| 5 | +The ``hls4ml`` library will parse models from Keras, PyTorch or ONNX into an internal execution graph. This model graph is represented with the |
| 6 | +:py:class:`~hls4ml.model.graph.ModelGraph` class. The nodes in this graph, corresponding to the layer and operations of the input model are represented |
| 7 | +by classes derived from the :py:class:`~hls4ml.model.layers.Layer` base class. |
7 | 8 |
|
8 | | -Layers have only inputs, outputs and attributes. |
9 | | -All information about the layer's state and configuration is stored in the attributes. |
10 | | -All weights, variables and data types are attributes and there are mapping views to sort through them. |
| 9 | +Layers are required to have defined inputs and outputs that define how they are connected in the graph and what is the shape of their output. All information |
| 10 | +about the layer's state and configuration is stored in its attributes. All weights, variables and data types are attributes and there are mapping views to sort through them. |
11 | 11 | Layers can define expected attributes and can be verified for correctness, or to produce a list of configurable attributes that user can tweak. |
12 | 12 |
|
13 | 13 | Optimizer passes |
14 | 14 | ---------------- |
15 | 15 |
|
16 | | -An :py:class:`~hls4ml.model.optimizer.optimizer.OptimizerPass` transforms a model graph. |
17 | | -All model/layer transformations should happen in these optimizer passes. |
18 | | -There are a number of types of optimizer passes: |
| 16 | +To reach a state from which the code can be generated, internal model graph will undergo a series of optimizations (transformations), dubbed *optimization passes*. |
| 17 | +All transformations of the model and any modification to any layer's attributes must be implemented through an optimization pass. All optimizer passes derive from |
| 18 | +the :py:class:`~hls4ml.model.optimizer.optimizer.OptimizerPass` class. Optimizer passes are applied at the level of nodes/layers, however a special class |
| 19 | +:py:class:`~hls4ml.model.optimizer.optimizer.ModelOptimizerPass` exists that is applied on the full model. Subclasses of |
| 20 | +:py:class:`~hls4ml.model.optimizer.optimizer.OptimizerPass` must provide a criteria in ``match`` function that, if satisfied, will perform the transformation from |
| 21 | +``transform`` function. The boolean return value of ``transform`` indicates if the optimizer pass made changes to the model graph, requiring running the optimizers again. |
| 22 | +Example of an optimizer pass that runs on the full model, is :py:class:`~hls4ml.model.optimizer.passes.stamp.MakeStamp`, while an example of the layer optimizer is |
| 23 | +:py:class:`~hls4ml.model.optimizer.passes.fuse_biasadd` class that adds a bias to a :py:class:`~hls4ml.model.layers.Dense`, |
| 24 | +:py:class:`~hls4ml.model.layers.Conv1D`, or :py:class:`~hls4ml.model.layers.Conv2D` layer. |
19 | 25 |
|
20 | | - * layer-specific: These are special optimizations for a given layer. |
21 | | - An example is the :py:class:`~hls4ml.model.optimizer.passes.fuse_biasadd` class that adds a bias to a :py:class:`~hls4ml.model.layers.Dense`, :py:class:`~hls4ml.model.layers.Conv1D`, or :py:class:`~hls4ml.model.layers.Conv2D` layer. |
22 | | - * backend-specific: These are only used for particular backends. An example is :py:class:`~hls4ml.backends.vivado.passes.repack_stream.ReshapeStream`. |
23 | | - * model-level: These model-level optimizer passes are run on every type of layer. |
24 | | - * templates: These add the HLS code for a particular backend, e.g., :py:class:`~hls4ml.backends.vivado.passes.core_templates.DenseFunctionTemplate`. |
25 | | - * decorators |
| 26 | +Optimizers can be general, independent of the backend, in which case they are located in :py:mod:`hls4ml.model.optimizer.passes`, or they may be backend-specific, |
| 27 | +in which case they are located in a folder dependent on the backend, e.g., :py:mod:`hls4ml.backends.vivado.passes` or |
| 28 | +:py:mod:`hls4ml.backends.quartus.passes`. A common set of optimizers that are used by FPGA backends are located in :py:mod:`hls4ml.backends.fpga.passes`. |
| 29 | + |
| 30 | +Certain optimizers are used frequently enough that it makes sense to define special classes, which inherit from :py:class:`~hls4ml.model.optimizer.optimizer.OptimizerPass` |
| 31 | + |
| 32 | + * :py:class:`~hls4ml.model.optimizer.optimizer.GlobalOptimizerPass`: An optimizer pass that matches each node. This is useful, for example, |
| 33 | + to transform the types for a particular backend. |
| 34 | + * :py:class:`~hls4ml.model.optimizer.optimizer.LayerOptimizerPass`: An optimizer pass that matches each node of a particular layer type. This is |
| 35 | + useful, for example, to write out the HLS code for a particular node that remains in the final graph. |
| 36 | + * :py:class:`~hls4ml.model.optimizer.optimizer.ConfigurableOptimizerPass`: An optimizer pass that has some configurable parameters. |
| 37 | + * :py:class:`~hls4ml.backends.template.Template`: An optimizer pass that populates a code template and assigns it to an attribute of a given layer. This is commonly used |
| 38 | + to generate code blocks in later stages of the conversion. |
| 39 | + |
| 40 | +Note that :py:class:`~hls4ml.model.optimizer.optimizer.LayerOptimizerPass` and :py:class:`~hls4ml.model.optimizer.optimizer.ModelOptimizerPass` |
| 41 | +also exist as decorators that wrap a function. |
| 42 | + |
| 43 | +New optimizers can be registered with the :py:func:`~hls4ml.model.optimizer.optimizer.register_pass`. Optimizers should be assigned to a flow (see below). |
26 | 44 |
|
27 | 45 | Flows |
28 | 46 | ----- |
29 | | -A :py:class:`~hls4ml.model.flow.flow.Flow` is an ordered set of optimizers that may depend on other flows. |
| 47 | +A :py:class:`~hls4ml.model.flow.flow.Flow` is an ordered set of optimizers that represent a single stage in the conversion process. The optimizers from a flow are applied |
| 48 | +until they no longer make changes to the model graph after which the next flow (stage) can start. Flows may depend on other flows being applied before them, |
| 49 | +ensuring the model graph is in a desired state before a flow starts. The function :py:func:`~hls4ml.model.flow.flow.register_flow` is used to register a new flow. Flows |
| 50 | +are applied on a model graph with :py:func:`~hls4ml.model.graph.ModelGraph.apply_flow`. |
| 51 | + |
30 | 52 | There are common model-level flows that can run regardless of the backend, and there are backend-specific flows. |
31 | | -Each backend provides provides a default flow for processing. |
32 | | -For example, the Vivado backend defaults to an `IP flow <https://github.com/fastmachinelearning/hls4ml/blob/7c0a065935904f50bd7e4c547f85354b36276092/hls4ml/backends/vivado/vivado_backend.py#L148-L160>`_ that requires additional flows and produces an IP. |
| 53 | +The `convert and optimize <https://github.com/fastmachinelearning/hls4ml/blob/7c0a065935904f50bd7e4c547f85354b36276092/hls4ml/model/optimizer/__init__.py#L14-L20>`_ |
| 54 | +flows do not depend on a backend. |
| 55 | + |
| 56 | +Each backend provides provides a default flow that defines the default target for that backend. For example, the Vivado backend defaults to an |
| 57 | +`IP flow <https://github.com/fastmachinelearning/hls4ml/blob/7c0a065935904f50bd7e4c547f85354b36276092/hls4ml/backends/vivado/vivado_backend.py#L148-L160>`_ |
| 58 | +that requires additional flows and produces an IP. It runs no optimizers itself, but it requires that many other flows (sub-flows) to have run. |
| 59 | +The convert and optimize flows defined above are some of these required sub-flows. |
| 60 | + |
33 | 61 | Another example is FIFO buffer depth optimization explained in the :ref:`FIFO Buffer Depth Optimization` section. |
0 commit comments