OPL is a tract-specific format based on NNEF. Operators can be dumped to OPL and loaded from it. While some operators use standard NNEF forms, many ONNX and TensorFlow operators require extensions within OPL.
Each OPL module (such as nnef, pulse-opl, or onnx-opl) maintains a Registry that contains both OPL loaders and OPL dumpers.
- Dumping: Uses a
from_tract mapping that connects a Rust TypeId (for a TypedOp) to a FromTract function. This function modifies an IntoAst object to store the operator's representation, potentially adding NNEF fragments to the document. - Loading: Uses the registry to find the appropriate loader for the operator defined in the OPL file.
pub struct Registry {
pub id: String,
pub fragments: HashMap<String, FragmentDef>,
pub primitives: HashMap<String, (Vec<ast::Parameter>, ToTract)>,
pub unit_element_wise_ops: Vec<(String, Box<dyn ElementWiseMiniOp>)>,
pub element_wise_ops: Vec<(String, TypeId, FromTract, Vec<ast::Parameter>, ToTract)>,
pub binary_ops: Vec<(String, Box<dyn BinMiniOp>)>,
pub from_tract: HashMap<TypeId, FromTract>,
}
/// Function type for converting a tract model to OPL
pub type ToTract = fn(&mut ModelBuilder, &ResolvedInvocation) -> TractResult<TVec<OutletId>>;
/// Function type for loading an operator from OPL into a tract model
pub type FromTract = fn(&mut IntoAst, node: &TypedNode) -> TractResult<Option<Arc<RValue>>>;