Спецификация IR torch.export
Создано: Oct 05, 2023 | Последнее обновление: Dec 09, 2025
Export IR — это промежуточное представление (IR) для компиляторов, имеющее сходство с MLIR и TorchScript. Оно специально разработано для выражения семантики программ PyTorch. Export IR преимущественно представляет вычисления в виде упорядоченного списка операций с ограниченной поддержкой динамических конструкций, таких как потоки управления.
Для создания графа Export IR можно использовать фронтенд, который достоверно фиксирует программу PyTorch с помощью механизма трассировки с учетом специализации. Полученный Export IR затем можно оптимизировать и выполнить с помощью бэкенда. Сегодня это можно сделать с помощью torch.export.export().
В этом документе рассматриваются следующие основные понятия:
- ExportedProgram: структура данных, содержащая программу Export IR
- Graph: состоит из списка узлов.
- Nodes: представляют операции, поток управления и метаданные, хранящиеся в узлах.
- Узлы создают и используют значения.
- Типы связаны со значениями и узлами.
- Также определяются размер и расположение значений в памяти.
Предположения
Предполагается, что читатель достаточно хорошо знаком с PyTorch, в частности с torch.fx и связанными с ним инструментами. Поэтому здесь не будут описываться материалы, уже представленные в документации и статье о torch.fx.
Что такое Export IR
Export IR — это основанное на графах промежуточное представление программ PyTorch. Export IR реализован поверх torch.fx.Graph. Иными словами, все графы Export IR также являются корректными графами FX, и при интерпретации с использованием стандартной семантики FX Export IR можно интерпретировать корректно. Одно из следствий этого — возможность преобразовать экспортированный граф в корректную программу на Python с помощью стандартной генерации кода FX.
В этой документации основное внимание уделяется областям, в которых Export IR отличается от FX большей строгостью; схожие с FX части опускаются.
ExportedProgram
Верхнеуровневая конструкция Export IR — это класс torch.export.ExportedProgram. Он объединяет вычислительный граф модели PyTorch (обычно это torch.nn.Module) с параметрами или весами, которые использует эта модель.
Некоторые важные атрибуты класса torch.export.ExportedProgram:
-
graph_module(torch.fx.GraphModule): структура данных, содержащая уплощенный вычислительный граф модели PyTorch. К графу можно напрямую обратиться черезExportedProgram.graph. -
graph_signature(torch.export.ExportGraphSignature): сигнатура графа, в которой указаны имена параметров и буферов, используемых и изменяемых в графе. Вместо того чтобы хранить параметры и буферы в качестве атрибутов графа, они передаются в граф как входные данные. graph_signature используется для отслеживания дополнительной информации об этих параметрах и буферах. -
state_dict(Dict[str, Union[torch.Tensor, torch.nn.Parameter]]): структура данных, содержащая параметры и буферы. -
range_constraints(Dict[sympy.Symbol, RangeConstraint]): для программ, экспортированных с поведением, зависящим от данных, метаданные каждого узла содержат символьные формы (например,s0,i0). Этот атрибут сопоставляет символьные формы с их нижними и верхними границами.
Граф
Граф Export IR — это программа PyTorch, представленная в виде DAG (ориентированного ациклического графа). Каждый узел этого графа соответствует определенному вычислению или операции, а ребра графа представляют собой ссылки между узлами.
Схему Graph можно представить следующим образом:
class Graph: nodes: List[Node]
На практике граф Export IR реализован как класс Python torch.fx.Graph.
Граф Export IR содержит следующие узлы (узлы подробнее описаны в следующем разделе):
- 0 или более узлов с типом операции
placeholder - 0 или более узлов с типом операции
call_function - ровно 1 узел с типом операции
output
Следствие: минимальный корректный граф состоит из одного узла. То есть список узлов никогда не бывает пустым.
Определение: множество узлов placeholder графа представляет собой входы графа GraphModule. Узел output графа представляет собой выходы графа GraphModule.
Пример:
import torch
from torch import nn
class MyModule(nn.Module):
def forward(self, x, y):
return x + y
example_args = (torch.randn(1), torch.randn(1))
mod = torch.export.export(MyModule(), example_args)
print(mod.graph)
graph():
%x : [num_users=1] = placeholder[target=x]
%y : [num_users=1] = placeholder[target=y]
%add : [num_users=1] = call_function[target=torch.ops.aten.add.Tensor](args = (%x, %y), kwargs = {})
return (add,)
Выше приведено текстовое представление графа, где каждая строка соответствует узлу.
Узел
Узел представляет определенное вычисление или операцию и в Python представлен классом torch.fx.Node. Ребра между узлами представлены прямыми ссылками на другие узлы через свойство args класса Node. Используя тот же механизм FX, можно представлять типичные для вычислительного графа операции: вызовы операторов, заполнители (то есть входные данные), условные операторы и циклы.
Схема узла:
class Node: name: str # name of node op_name: str # type of operation # interpretation of the fields below depends on op_name target: [str|Callable] args: List[object] kwargs: Dict[str, object] meta: Dict[str, object]
Текстовый формат FX
Как видно из приведенного выше примера, каждая строка имеет следующий формат:
%<name>:[...] = <op_name>[target=<target>](args = (%arg1, %arg2, arg3, arg4, …)), kwargs = {"keyword": arg5})
Этот формат в компактном виде содержит всю информацию класса Node, за исключением meta.
В частности:
-
<name> — имя узла, которое отображается в
node.name. -
<op_name> — поле
node.op, значением которого должно быть одно из следующих:<call_function>,<placeholder>,<get_attr>или<output>. -
<target> — целевой объект узла в виде
node.target. Значение этого поля зависит отop_name. -
args1, … args 4… — содержимое кортежа
node.args. Если значение в списке является объектомtorch.fx.Node, это специально обозначается начальным символом %.
Например, вызов оператора add будет выглядеть так:
%add1 = call_function[target = torch.op.aten.add.Tensor](args = (%x, %y), kwargs = {})
Здесь %x и %y — два других узла с именами x и y. Стоит отметить, что строка torch.op.aten.add.Tensor представляет вызываемый объект, фактически хранящийся в поле target, а не только его строковое имя.
Последняя строка этого текстового формата:
return [add]
— это узел с op_name = output, указывающий, что мы возвращаем этот единственный элемент.
call_function
Узел call_function представляет вызов оператора.
Определения
-
Функциональный: вызываемый объект считается «функциональным», если он удовлетворяет всем следующим требованиям:
- Не изменяет данные: оператор не изменяет значение своих входных данных (для тензоров это относится как к метаданным, так и к данным).
- Не имеет побочных эффектов: оператор не изменяет состояния, видимые извне, например значения параметров модуля.
- Оператор: функциональный вызываемый объект с заранее определенной схемой. Примерами таких операторов являются функциональные операторы ATen.
Представление в FX
%name = call_function[target = operator](args = (%x, %y, …), kwargs = {})
Отличия от стандартного call_function в FX
- В графе FX call_function может ссылаться на любой вызываемый объект, тогда как в Export IR он ограничен выбранным набором операторов ATen, пользовательских операторов и операторов потока управления.
- В Export IR аргументы-константы встраиваются в граф.
- В графе FX узел get_attr может представлять чтение любого атрибута, хранящегося в модуле графа. В Export IR чтение ограничено только вложенными модулями, поскольку все параметры и буферы передаются в модуль графа как входные данные.
Метаданные
Node.meta — это словарь, прикрепленный к каждому узлу FX. Однако спецификация FX не определяет, какие метаданные могут или должны в нем содержаться. Export IR предоставляет более строгие гарантии: в частности, все узлы call_function гарантированно содержат только следующие поля метаданных:
-
node.meta["stack_trace"]— строка с трассировкой стека Python, указывающей на исходный код Python. Пример трассировки стека:File "my_module.py", line 19, in forward return x + dummy_helper(y) File "helper_utility.py", line 89, in dummy_helper return y + 1
-
node.meta["val"]описывает результат выполнения операции. Он может иметь тип<symint>,<FakeTensor>,List[Union[FakeTensor, SymInt]]илиNone. -
node.meta["nn_module_stack"]описывает «трассировку стека» объектаtorch.nn.Module, из которого был получен узел, если он появился в результате вызоваtorch.nn.Module. Например, если узел с операторомaddmmбыл вызван из модуляtorch.nn.Linearвнутри модуляtorch.nn.Sequential,nn_module_stackбудет выглядеть примерно так:{'self_linear': ('self.linear', <class 'torch.nn.Linear'>), 'self_sequential': ('self.sequential', <class 'torch.nn.Sequential'>)} -
node.meta["source_fn_stack"]содержит функцию torch или класс конечногоtorch.nn.Module, из которого был вызван этот узел до декомпозиции. Например, узел с операторомaddmm, полученный при вызове модуляtorch.nn.Linear, будет содержатьtorch.nn.Linearв полеsource_fn, а узел с операторомaddmm, полученный при вызове модуляtorch.nn.functional.Linear, будет содержатьtorch.nn.functional.Linearв полеsource_fn.
placeholder
Placeholder представляет вход графа. Его семантика полностью совпадает с семантикой в FX. Узлы placeholder должны быть первыми N узлами в списке узлов графа. N может быть равен нулю.
Представление в FX
%name = placeholder[target = name](args = ())
Поле target представляет собой строку с именем входных данных.
args, если оно не пустое, должно иметь размер 1 и представлять значение входных данных по умолчанию.
Метаданные
Узлы placeholder также содержат meta[‘val’], как и узлы call_function. В этом случае поле val описывает форму и тип данных входного параметра, которые граф ожидает получить.
output
Вызов output представляет оператор return в функции и тем самым завершает текущий граф. Узел output существует в единственном экземпляре и всегда является последним узлом графа.
Представление в FX
output[](args = (%something, …))
Его семантика полностью совпадает с семантикой в torch.fx. args обозначает возвращаемый узел.
Метаданные
Узел output содержит те же метаданные, что и узлы call_function.
get_attr
Узлы get_attr представляют чтение вложенного модуля из содержащего его torch.fx.GraphModule. В отличие от стандартного графа FX, созданного с помощью torch.fx.symbolic_trace(), где узлы get_attr используются для чтения таких атрибутов, как параметры и буферы, из верхнеуровневого torch.fx.GraphModule, в Export IR параметры и буферы передаются в модуль графа как входные данные и хранятся в верхнеуровневом torch.export.ExportedProgram.
Представление в FX
%name = get_attr[target = name](args = ())
Пример
Рассмотрим следующую модель:
from functorch.experimental.control_flow import cond
def true_fn(x):
return x.sin()
def false_fn(x):
return x.cos()
def f(x, y):
return cond(y, true_fn, false_fn, [x])
Граф:
graph():
%x_1 : [num_users=1] = placeholder[target=x_1]
%y_1 : [num_users=1] = placeholder[target=y_1]
%true_graph_0 : [num_users=1] = get_attr[target=true_graph_0]
%false_graph_0 : [num_users=1] = get_attr[target=false_graph_0]
%conditional : [num_users=1] = call_function[target=torch.ops.higher_order.cond](args = (%y_1, %true_graph_0, %false_graph_0, [%x_1]), kwargs = {})
return conditional
Строка %true_graph_0 : [num_users=1] = get_attr[target=true_graph_0] считывает вложенный модуль true_graph_0, содержащий оператор sin.
Справочная информация
SymInt
SymInt — это объект, который может быть либо целочисленным литералом, либо символом, представляющим целое число (в Python он представлен классом sympy.Symbol). Если SymInt является символом, он описывает переменную целочисленного типа, неизвестную графу во время компиляции; ее значение становится известно только во время выполнения.
FakeTensor
FakeTensor — это объект, содержащий метаданные тензора. Его метаданные можно представить следующим образом.
class FakeTensor: size: List[SymInt] dtype: torch.dtype device: torch.device dim_order: List[int] # This doesn't exist yet
Поле size объекта FakeTensor — это список целых чисел или SymInt. Если в нем присутствуют SymInt, это означает, что тензор имеет динамическую форму. Если присутствуют целые числа, предполагается, что тензор будет иметь именно такую статическую форму. Ранг TensorMeta не может быть динамическим. Поле dtype задает тип данных результата этого узла. В Edge IR нет неявного преобразования типов. FakeTensor не содержит сведений о шагах.
Иными словами:
- Если оператор в node.target возвращает Tensor, то
node.meta['val']— это FakeTensor, описывающий этот тензор. - Если оператор в node.target возвращает n-кортеж тензоров, то
node.meta['val']— это n-кортеж объектов FakeTensor, описывающих каждый тензор. - Если оператор в node.target возвращает int/float/скаляр, значение которого известно во время компиляции, то
node.meta['val']равно None. - Если оператор в node.target возвращает int/float/скаляр, значение которого неизвестно во время компиляции, то
node.meta['val']имеет тип SymInt.
Например:
-
aten::addвозвращает Tensor, поэтому его спецификация будет объектом FakeTensor с dtype и size возвращенного этим оператором тензора. -
aten::sym_sizeвозвращает целое число, поэтому его val будет иметь тип SymInt, поскольку значение доступно только во время выполнения. -
max_pool2d_with_indexesвозвращает кортеж (Tensor, Tensor), поэтому спецификация также будет состоять из 2-кортежа объектов FakeTensor; первый TensorMeta описывает первый элемент возвращаемого значения и т. д.
Код Python:
def add_one(x): return torch.ops.aten(x, 1)
Граф:
graph():
%ph_0 : [#users=1] = placeholder[target=ph_0]
%add_tensor : [#users=1] = call_function[target=torch.ops.aten.add.Tensor](args = (%ph_0, 1), kwargs = {})
return [add_tensor]
FakeTensor:
FakeTensor(dtype=torch.int, size=[2,], device=CPU)
Типы, совместимые с Pytree
Тип называется «совместимым с Pytree», если он является либо листовым типом, либо типом-контейнером, содержащим другие типы, совместимые с Pytree.
Примечание:
Понятие pytree совпадает с описанным здесь для JAX:
Следующие типы определены как листовые типы:
Тип | Определение |
|---|---|
Tensor | |
Scalar | Любые числовые типы Python, включая целочисленные типы, типы с плавающей запятой и тензоры нулевой размерности. |
int | Целое число Python (в C++ соответствует int64_t) |
float | Число с плавающей запятой Python (в C++ соответствует double) |
bool | Логическое значение Python |
str | Строка Python |
ScalarType | |
Layout | |
MemoryFormat | |
Device |
Следующие типы определены как типы-контейнеры:
Тип | Определение |
|---|---|
Tuple | Кортеж Python |
List | Список Python |
Dict | Словарь Python с ключами Scalar |
NamedTuple | Именованный кортеж Python |
Dataclass | Должен быть зарегистрирован с помощью register_dataclass |
Пользовательский класс | Любой пользовательский класс, определенный с помощью _register_pytree_node |
© 2026, PyTorch Contributors
PyTorch has a BSD-style license, as found in the LICENSE file.
https://docs.pytorch.org/docs/2.14/user_guide/torch_compiler/export/ir_spec.html