How to add new optimization Pass
Olive provides simple interface to introduce new model optimization techniques. Each optimization technique is represented as a Pass in Olive.
To introduce a new Pass follow these 3 steps.
1. Define a new class
Define a new class using Pass as the base class. For example
from olive.passes import Pass
class NewOptimizationTrick(Pass):
# Add any required data members to the class
2. Define configuration
Next, define the options used to configure this new technique by defining static method _default_config
. This method
takes an AcceleratorSpec
as input and returns Dict[str, PassConfigParam]
.
AcceleratorSpec
is a dataclass that holds the information about the accelerator. The dataclass has the following fields:
accelerator_type
: type of the accelerator. For example,CPU
,GPU
etc.execution_provider
: execution provider for the accelerator. For example,CPUExecutionProvider
,CUDAExecutionProvider
etc. Please note if user specify some execution providers that don’t belong to the installed onnxruntime, these execution providers will be ignored. For example, if user specify CUDA, TensorRT, DML execution provider, but the onnxruntime-gpu is installed then the DML execution provider will be ignored since it is only available in onnxruntime-directml package.
PassConfigParam
is a dataclass that holds the information about the configuration option. The dataclass has the following fields:
type_
: type of the parameterrequired
: whether the parameter is requiredcategory
: The param category. It could be the following values:object
: whether the parameter is an object/function. If so, this parameter accepts the object or a string with the name of the object in the user script. The type must includestr
.path
: whether the parameter is a path. If so, this file/folder will be uploaded to the host system.data
: whether the parameter is a data path, which will be used to do data path normalization based on the data root.
description
: description of the parameterdefault_value
: default value for the parameter. This value is used as the default when not searching or when there are no searchable values. Must be the same type as the parameter or a ConditionalDefault SearchParameter.search_defaults
: default search values for the parameter. This value is used as the default when searching. Must be a Categorical or Conditional SearchParameter.
Example
@classmethod
def _default_config(cls, accelerator_spec: AcceleratorSpec) -> Dict[str, PassConfigParam]:
return {
# required parameter
"param1": PassConfigParam(type_=int, required=True, description="param1 description"),
# optional parameter with default value
"param2": PassConfigParam(type_=int, default_value=1, description="param2 description"),
# optional parameter with default value and searchable values
"param3": PassConfigParam(
type_=int, default_value=1, search_defaults=Categorical([1, 2, 3]), description="param3 description"
),
# optional parameter with `category` set to `object`
# the value of this parameter can be a string or a function that takes a string and returns the object,
# say a class ObjectClass
"param4": PassConfigParam(
type_=Union[str, Callable[[str], Pass]], category=ParamCategory.OBJECT, description="param4 description"
),
# optional parameter with default_value that depends on another parameter value
"param5": PassConfigParam(
type_=int,
default_value=ConditionalDefault(parents="param2", support={(1,): 2, (2,): 3}, default=4),
description="param5 description",
),
# optional parameter with search_defaults that depends on other parameter values
"param6": PassConfigParam(
type_=int,
default_value=1,
search_defaults=Conditional(
parents=("param2", "param3"),
# invalid if (param2, param3) not in [(1, 1), (1, 2)]
support={
(1, 1): Categorical([1, 2, 3]),
(1, 2): Categorical([4, 5, 6]),
},
),
description="param6 description",
),
}
3. Implement the run function
The final step is to implement the _run_for_config
method to optimize the input model. Olive Engine will invoke the
method while auto tuning the model. This method will also receive a search point (one set of configuration option from
the search space created based on the options defined in _default_config(cls, accelerator_spec: AcceleratorSpec)
) along
with output path. The method should return a valid OliveModelHandler which can be used as an input for the next Pass.
def _run_for_config(self, model: ONNXModelHandler, config: Dict[str, Any], output_model_path: str) -> ONNXModelHandler: