TorchLean API

NN.Runtime.PyTorch.Export.TorchExport

PyTorch graph capture #

This module generates a Python script that captures an nn.Module and writes a shared tensor-graph artifact. The Lean importer checks it before evaluation:

PyTorch nn.Module
  --torch.export / FX capture-->
TorchLean graph JSON (`torchlean.ir.v2`)
  --Import.IR.parseProgram-->
NN.IR.Program

PyTorch handles capture and shape propagation. The generated script translates supported operations into NN.IR.OpKind and reports an error for unsupported operations or configurations. The importer then checks the graph's edges, shapes, and operation attributes.

Tensor entries also retain their dtypes. Binary constants and linear parameters carry complete interchange words for Import.IR.parseProgram and its typed payload loader. Conversions and pointwise tensor promotions become explicit cast nodes, two of them when an integer, Boolean or binary64 value becomes binary16 or bfloat16, which c10::convert makes from binary32. Pointwise broadcasting is explicit too. Metadata assertions and assumptions needed by a lowering are retained as capture_constraints. For example, partial top-k routing assumes finite scores and a strict gap at the cutoff; capturing one example does not establish those conditions for every input. The CPU reference interpreter does not validate these assumptions or physical device and layout constraints.

example may be one tensor or a tuple of positional tensors. Argument order comes from torch.export's graph signature, not from parameter placeholder order. Unused user arguments remain in the interface; dead parameter values and dead intermediate nodes may be omitted. The artifact lists every input in input_ids, in argument order. Returned containers are flattened to tensor leaves; non-tensor leaves are rejected.

Operator matching uses exact callable or ATen identities. For example, torch.log can become an IR .log node, while torch.log1p needs a different formula and is rejected. Similar names and matching output shapes are insufficient to identify the computation.

Pointwise operators from the core ATen vocabulary (neg, rsqrt, erf, gelu, div, pow and clamp_min with a scalar bound) become IR pointwise nodes in the arithmetic of the vectorized loops of PyTorch's CPU kernels. Operands are converted as PyTorch converts them, Python scalars included, and binary16 and bfloat16 values are widened to binary32 where those loops compute in binary32. A Python scalar operand of add, sub or mul becomes a constant in the same way. For bfloat16 and binary16, a scalar exponent of pow is rounded to the tensor's dtype before PyTorch's dispatch compares it. Exponent 3 is x * x * x, not a rounded cube. The frontend-lowering section of NN/IR/README.md states the rules and the elements PyTorch computes differently.

The script is assembled from one definition per Python section so each piece can be read and changed on its own. Every "kind" string it writes comes from NN.Runtime.PyTorch.Wire, the same table the Lean importer parses with.

References:

Options for the generated PyTorch graph-capture script.

  • functionName : String

    Name of the Python helper function emitted into the script.

  • preferTorchExport : Bool

    If true, use torch.export.export first and fall back to FX symbolic tracing.

  • includeDebugTargets : Bool

    If true, include raw PyTorch target strings in each node for debugging.

Instances For

    Python sections #

    Each section is an array of Python lines ending in one blank separator line. Indentation is applied here so the sections concatenate into a valid module.

    Imports and the artifact format marker.

    Instances For

      Shape readers for FX node metadata plus the getitem/getattr target tests.

      Instances For

        Kind entries for tuple-valued FX nodes; nn.MultiheadAttention carries its payload.

        Instances For

          Model loading, target naming, FX node reference collection, and spatial tuple parsing.

          Instances For

            Parameter payload serialization for linear, attention, and convolution nodes.

            Instances For

              Flatten-versus-reshape selection and axis normalization.

              Instances For

                Python block with @NAME@ placeholders replaced by wire spellings.

                Instances For

                  Python dictionary from pointwise plan names to their wire kinds.

                  Instances For

                    Pointwise operators: recognition, validation, and emission as IR nodes.

                    _pointwise_plan identifies the operator, its attributes and its operands, which may be Python scalars. _arithmetic_kind does the same for add, sub and mul with a scalar operand, and the dtype conversion rule plans a conversion. _emit_pointwise appends the nodes the vectorized loops of PyTorch's CPU kernels compute: scalar constants, conversions to the common dtype and to the computation type, explicit broadcasts, the reduced-precision division and multiplication paths for a one-element right operand, and PyTorch's dispatch of pow with a scalar exponent.

                    Instances For

                      _lower_kind rule for pointwise operators, checked before every other rule.

                      Instances For

                        Opening of _lower_kind: target name, argument, and axis extraction shared by all rules.

                        Instances For

                          Mixture-of-experts routing written as torch.zeros_like(p).scatter(-1, torch.topk(p, k, dim=-1).indices, 1.0), captured as one top_k_mask node over p. TorchLean's mask keeps ties for the lower index; torch.topk documents no tie order. For 0 < k < width, agreement assumes finite scores and different k-th and k + 1-th largest entries in each row. The artifact records these conditions as unchecked capture_constraints; keeping no entries or every entry needs neither condition. The zeros and the mask must have p's dtype, since the mask node inherits it; any other dtype is left to the ordinary operator checks, which reject a zeros_like dtype override. The topk call, its index projection and the zeros exist only to build the mask and are not exported.

                          Instances For

                            _lower_kind rules for call_module nodes, keyed on the nn.Module subclass.

                            Instances For

                              _lower_kind rules for elementwise aten/functional targets that carry no payload.

                              A dtype conversion and arithmetic with a Python scalar operand return a plan for _emit_pointwise, which writes the conversions and constants PyTorch computes.

                              Instances For

                                _lower_kind rules for reductions, softmax, and shape operations.

                                Instances For

                                  _lower_kind rules for functional layers with payloads: layer norm, linear, batch norm.

                                  Instances For

                                    _lower_kind rules for functional convolution and pooling, then the tuple/fallback cases.

                                    Instances For

                                      The complete _lower_kind function.

                                      Instances For

                                        Check captured operations before dropping unused values.

                                        FX records x.relu_(); return x with an unused result for the ReLU call. Skipping that call before checking its contract would erase the update to x. Unsupported calls therefore fail even when their results have no users.

                                        Instances For

                                          Graph capture: torch.export when preferred and lowerable, otherwise FX symbolic tracing.

                                          Instances For

                                            The exported entry point: walk the captured graph and write the artifact.

                                            Instances For

                                              Command-line main for the generated script.

                                              Instances For

                                                Emit a Python script that captures a PyTorch module and writes TorchLean graph JSON.

                                                The generated script expects a Python file containing a zero-argument model constructor or class:

                                                python export_torchlean_graph.py my_model.py MyModel out_graph.json --example-shape 1,4
                                                

                                                The first implementation target is the shared IR subset: elementwise ops, matmul, reductions, reshape/permute/flatten/concat, softmax, layernorm, and simple pooling/conv metadata when PyTorch exposes enough static arguments. Linear layers can appear either as aten.linear or as lower-level matmul/add depending on PyTorch's graph capture.

                                                Instances For