1# Export IR Specification 2 3Export IR is an intermediate representation (IR) for the result of 4`torch.export`. To read more on the details of Export IR, please read this 5[document](https://pytorch.org/docs/main/export.ir_spec.html). 6 7The Exported IR is a specification that consists of the following parts: 8 91. A definition of computation graph model. 102. Set of operators allowed in the graph. 11 12A **dialect** is an Exported IR graph composed with the operations defined 13below, but with additional properties (such as restrictions on operator set or 14metadata) that are meant for a specific purpose. 15 16The EXIR dialects that currently exist are: 17 18* [ATen Dialect](#aten-dialect) 19* [Edge Dialect](#edge-dialect) 20* [Backend Dialect](#backend-dialect) 21 22These dialects represent stages that a captured program goes through from 23program capture to conversion into an executable format. For example, the 24ExecuTorch compilation process starts from a Python program capture into ATen 25Dialect, then ATen Dialect is converted to Edge Dialect, Edge to Backend, and 26finally to a binary format for execution. 27 28## ATen Dialect 29 30ATen dialect will be used as the entry point of the ExecuTorch compilation 31pipeline. It is the first time an eager mode PyTorch program becomes an Exported 32IR graph. At this stage, functionalization is performed, removing any tensor 33aliases and mutations, and allowing for more flexible graph transformations to 34be made. Additionally, all tensors are converted to continuous format. 35 36The goal of this dialect is to capture users' programs as faithfully as possible 37(while remaining valid Exported IR). Registered custom operators that user has called 38in eager mode will preserve as-is in ATen dialect. However, we should refrain 39from adding custom ops in the graph via passes. 40 41For now, the function of ATen dialect is to further lower to Edge dialect. 42However, in the future we can see this one as the common integration point for 43other export use cases. 44 45### ATen Dialect Properties 46 47An ATen dialect graph is a valid Export IR graph with the following additional 48properties: 49 501. All operators in `call_function` nodes are either ATen operators (in the 51 `torch.ops.aten` namespace, higher order operators (like control flow 52 operators), or a registered custom operator. A registered custom operator is 53 an operator registered into the current PyTorch eager mode runtime, usually 54 with `TORCH_LIBRARY` call (implies schema). Details for how to register a 55 custom operator can be found 56 [here](https://docs.google.com/document/d/1_W62p8WJOQQUzPsJYa7s701JXt0qf2OfLub2sbkHOaU/edit#heading=h.3rgxk3v387wl). 572. Every operator must also have a meta kernel. A meta kernel is a 58 function that, given the shapes of the input tensors, can return the shape of 59 output tensor. Details on how to write a meta kernel can be found 60 [here](https://docs.google.com/document/d/1GgvOe7C8_NVOMLOCwDaYV1mXXyHMXY7ExoewHqooxrs/edit#heading=h.64r4npvq0w0). 613. Input value type must be “Pytree-able”. As a consequence, the output 62 types are also Pytree-able because all operators output are pytree-able. 634. Ops of ATen dialect can choose to work Dynamic dtypes, implicit type 64 promotions and implicit broadcasting of tensors. 655. All tensors memory formats are in `torch.contiguous_format`. 66 67### ATen Operator Definition 68 69The operator set definition can be found [here](./ir-ops-set-definition.md). 70 71## Edge Dialect 72 73This dialect is meant to introduce specializations that are useful for Edge 74devices but not necessarily for general (server) export. However, we still 75withhold specializing further to each different hardware. In other words, we 76don’t want to introduce any new hardware dependent concepts or data; besides 77those already present in users’ original python program. 78 79### Edge Dialect Properties 80 81An Edge dialect graph is a valid Export IR graph with the following additional 82properties: 83 841. All operators in OpCall nodes are either from a predefined operator set, 85 called **“Edge Operators”**, or a registered custom operator. An Edge operator is a 86 ATen operator with dtype specialization. This allows users to register 87 kernels that only work for certain dtypes to reduce binary size. 882. Input and output of the graph, and as well as to every node, cannot be Scalar. I.e. 89 All scalar types (such as float, int) are converted to Tensor. 90 91### Using the Edge Dialect 92 93The Edge dialect is represented with `exir.EdgeProgramManager` Python class in 94memory. This contains one or multiple `torch.export.ExportedProgram`s which 95contain the graph representation of a method. 96 97```python 98import torch 99from executorch import exir 100 101class MyModule(torch.nn.Module): 102 ... 103 104a = MyModule() 105tracing_inputs = (torch.rand(2, 2),) 106aten_dialect_program = torch.export.export(a, tracing_inputs) 107edge_dialect_program: exir.EdgeProgramManager = exir.to_edge(aten_dialect) 108print(edge_dialect_program.exported_program) 109``` 110 111At this point, user defined graph transformation can be run through 112`edge_dialect_program.transform(pass)`. Order matters. Note: If the custom pass 113is touching `node.target`, be aware that all of the `node.target` at this stage 114are "Edge ops" (more details below) and not torch ops like in the ATen dialect. 115A tutorial on pass writing can be found 116[here](./compiler-custom-compiler-passes.md). After all these passes are 117executed, `to_edge()` will make sure the graph is still valid. 118 119### Edge Operators 120 121As mentioned before, an edge operator is an ATen core operator with type 122specialization. This means an instance of the edge operator contains a set of 123dtype constraints, that describe all the tensor dtypes supported by both the 124ExecuTorch runtime and their ATen kernels. These dtype constraints are expressed 125in a DSL defined in 126[edge.yaml](https://github.com/pytorch/executorch/blob/main/exir/dialects/edge/edge.yaml). 127Here's an example of the dtype constraints: 128 129``` 130- func: sigmoid 131 namespace: edge 132 inherits: aten::sigmoid 133 type_alias: 134 T0: [Bool, Byte, Char, Int, Long, Short] 135 T1: [Double, Float] 136 T2: [Float] 137 type_constraint: 138 - self: T0 139 __ret_0: T2 140 - self: T1 141 __ret_0: T1 142``` 143This is saying if `self` tensor is one of the type `Bool, Byte, Char, Int, Long, Short`, then the return tensor would be `Float`. If `self` is one of `Double, Float`, the return tensor will be the same dtype. 144 145After these dtype constraints are collected and documented in edge.yaml, EXIR 146consumes the file, and loads the constraints into EXIR Edge operators. This 147makes it convenient for developers to learn the supported dtypes of any argument 148in the Edge op schema. For example we can do: 149 150 151```python 152from executorch.exir.dialects._ops import ops as exir_ops # import dialects ops 153sigmoid = exir_ops.edge.aten.sigmoid.default 154print(sigmoid._schema) 155# aten::sigmoid(Tensor self) -> Tensor 156self_arg = sigmoid._schema.arguments[0] 157_return = sigmoid._schema.returns[0] 158 159print(self_arg.allowed_types) 160# {torch.float32, torch.int8, torch.float64, torch.int16, torch.int32, torch.int64, torch.uint8, torch.bool} 161 162print(_return.allowed_types) 163# {torch.float32, torch.float64} 164``` 165 166These constraints are helpful for someone who wants to write a custom kernel for this operator. Also inside EXIR, we offer a validator to check if the graph is still complying with these dtype constraints, after custom transformations. 167 168### Op Set (WIP) 169 170Check out 171[edge.yaml](https://github.com/pytorch/executorch/blob/main/exir/dialects/edge/edge.yaml) 172for the complete list of operators having dtype constraints specified. We are 173gradually expanding this operator set and targeting to provide dtype constraints 174for all core ATen ops. 175 176## Backend Dialect 177 178See this [doc](./compiler-backend-dialect.md) 179