4.3. GraphSpec
GraphSpec is TorchLean's typed authoring DSL for architectures whose structure should be explicit: parameter layout, residual sharing, DAG structure, pure semantics, and executable lowering.
The earlier chapters cover the public model-building surface. This page is about the architecture boundary underneath it: the point where a model is still readable as a model, but already carries enough type information to support proofs and lowering.
4.3.1. Why GraphSpec Exists
The TorchLean paper centers the project around a shared SSA/DAG IR with operation tags (NN.IR.Graph) used
by runtime compilation and verification. GraphSpec is not a second copy of that IR. It solves a
different problem:
-
NN.IR.Graphis the shared backend object for verification, inspection, and formal reasoning. -
GraphSpec is the typed model-authoring language when the architecture itself should be a first-class mathematical object.
That distinction matters especially for residual networks, explicit sharing, and model families whose parameter interface should stay stable across lowerings.
4.3.2. What GraphSpec Adds
The graph taxonomy belongs in Graphs and IR. The additional point here is more specific: GraphSpec gives architectures a typed authoring language before they are lowered into a runtime program or the shared op-level IR.
That authoring layer adds three things that a raw IR graph does not try to provide:
-
a parameter ABI in the type, so the order and shapes of trainable tensors are part of the model interface;
-
architecture-level sharing, so residual branches and reused intermediates can be written directly;
-
paired interpreters, so the same architecture object has a pure
Specmeaning and an executable TorchLean program.
In short: GraphSpec records architecture facts before the model becomes a lower-level artifact.
4.3.3. Two Authoring Surfaces
GraphSpec exposes two related surfaces because a linear chain and a general DAG with sharing are different authoring problems.
4.3.3.1. Sequential surface: Graph ps σ τ
The sequential DSL is defined in NN.GraphSpec.Core API.
-
Graph ps σ τmeans: a typed graph from input shapeσto output shapeτ, with parameter tensor shapesps. -
Composition uses
>>>, so straightforward pipelines read like architecture syntax rather than like a manually-assembled IR. -
The core MLP examples live here.
This is the easiest GraphSpec surface for readers coming from nn.Sequential.
The type itself is worth reading carefully:
Graph ps σ τ
means:
-
σis the input shape, -
τis the output shape, -
psis the ordered list of parameter tensor shapes.
For example, a dense layer from Vec inDim to Vec outDim has parameter shapes:
[Mat outDim inDim, Vec outDim]
That list is not just documentation. It is the parameter ABI of the graph: the pure interpreter and the executable compiler both expect parameters in that order.
4.3.3.2. DAG surface: DAG.Model ps ins τ
The GraphSpec DAG API and GraphSpec DAG core define the shared-branch authoring surface.
-
It uses an SSA/A-normal-form term language with explicit binding and sharing.
-
It is the right surface for residual blocks, skip connections, and models such as ResNet-18.
-
GraphSpec's canonical "general model" type is this DAG
Model.
For "use this intermediate twice" or "add a shortcut branch," the DAG layer is the important one.
4.3.4. Parameter ABI
GraphSpec treats parameter layout as part of the architecture. Parameter shapes and ordering live in the type.
That gives the architecture layer two practical benefits:
-
parameter ABI is explicit and stable enough to reason about, and
-
the same model can be interpreted, lowered, and checked against a single declared parameter order.
Many downstream artifacts assume an exact parameter order, so GraphSpec makes that order part of the model interface instead of leaving it implicit in helper code.
4.3.5. Choosing The Right Surface
Use the smallest surface that still says what you need to say.
-
Use
nn.Sequentialfor ordinary tutorials and model training files. -
Use sequential GraphSpec when the model is still a chain, but the parameter ABI and pure semantics should be explicit.
-
Use GraphSpec DAG models when the architecture has sharing, residual branches, or multiple inputs.
-
Use
NN.IR.Graphwhen the consumer is a verifier, exporter, or graph level analysis pass.
This keeps each layer explicit: architecture authoring stays readable, while verifier-facing code still receives a precise op-level graph after lowering.
4.3.6. Two Semantics From One Model
GraphSpec is valuable because it does not force an early choice between a clean mathematical object and an executable object.
For sequential graphs, the main names are:
-
NN.GraphSpec.Interp.spec -
NN.GraphSpec.Compile.torchProgram
For DAG models, the corresponding names are:
-
NN.GraphSpec.Model.specFwd -
NN.GraphSpec.Model.torchProgram
The pattern is the same in both cases:
-
the Spec semantics supplies a pure forward meaning in Lean,
-
the TorchLean compiler supplies an executable program in the runtime layer.
GraphSpec packages this semantic alignment at the architecture-authoring level.
The declarations worth recognizing in the infoview are:
#check NN.GraphSpec.Interp.spec #check NN.GraphSpec.Compile.torchProgram #check NN.GraphSpec.DAG.Model.specFwd #check NN.GraphSpec.DAG.Model.torchProgram #check NN.GraphSpec.Model.specFwd #check NN.GraphSpec.Model.torchProgram #check NN.GraphSpec.ToTorchLean.toSeq
4.3.7. Worked Micro-Example
The smallest useful GraphSpec check sequence is the one from the README:
import NN.Entrypoint.GraphSpec open NN open NN.GraphSpec open Spec def g (inDim hidDim outDim : Nat) := GraphSpec.Models.mlp inDim hidDim outDim -- Pure semantics: parameters to input to output. #check GraphSpec.Interp.spec (g 4 8 2) -- Executable TorchLean program. #check GraphSpec.Compile.torchProgram (g 4 8 2) -- Optional lowering into the general DAG model representation. #check GraphSpec.LowerToDAG.Graph.toDAGModelZeroInit (g 4 8 2)
The important lesson is not just that these names exist. The lesson is that one architecture can be read at three levels:
-
as typed authoring syntax,
-
as pure semantics,
-
and as executable runtime code.
4.3.8. Residual Sharing As A Tiny DAG
A residual block is the first example where the DAG surface is more natural than a chain. The architecture says:
y = f(x) z = y + x
The value x is used twice. In a purely sequential chain, that sharing is awkward because the input
would have to be carried forward as an explicit side value. In a DAG model, the intermediate names
are part of the authoring language.
This is the reason examples such as Models.residualLinear and Models.ResNet18.model use the DAG
surface: their architecture contains skip connections, so shared values should be represented
directly.
4.3.9. Lowering Paths
GraphSpec supports several lowering paths. They are not competing APIs; they answer different questions about the same architecture.
4.3.9.1. Sequential Graph To DAG Model
The relevant definitions are GraphSpec core and GraphSpec DAG core.
Important names:
-
LowerToDAG.Graph.toDAGTerm -
LowerToDAG.Graph.toDAGModelZeroInit -
LowerToDAG.Graph.toDAGModelDetInit?
This path turns a simple pipeline into GraphSpec's general DAG representation.
4.3.9.2. GraphSpec To TorchLean nn.Sequential
The lowering API is GraphSpec to TorchLean.
Important name:
-
NN.GraphSpec.ToTorchLean.toSeq
This path is used by the runnable
GraphSpec tutorial: author once in GraphSpec,
then plug the lowered model into the same train.* API used elsewhere in the guide.
4.3.9.3. DAG Model To Runtime Model Zoo Wrappers
The runtime examples to open are GraphSpec ResNet18 and runtime FNO1D.
These wrappers show how GraphSpec feeds the runtime-facing model zoo:
-
GraphSpec-backed
resnet18Model,resnet18Program,resnet18InitParams -
fno1druntime wrappers for operator learning style work, which sit beside the GraphSpec-backed models in the broader model zoo
4.3.10. Model Zoo Landmarks
For model definitions used in examples and demos, NN.GraphSpec.Models is the most convenient
single import surface.
The current zoo intentionally includes both sequential and DAG-native models:
-
Models.mlpfor the smallest sequential path, -
Models.cnn2andcnn2DAGModelZeroInitfor "same model, different representation" comparisons, -
Models.residualLinearfor a small residual/shared example, -
Models.ResNet18.modelfor a substantial DAG-authored architecture.
The GraphSpec README suggests this order:
-
Models.mlp -
Models.cnn2 -
Models.residualLinear -
Models.ResNet18.model
4.3.11. Reading Rule
When reading a GraphSpec model, look for four things:
-
the input and output shapes;
-
the parameter-shape list;
-
whether the model is sequential or DAG-native;
-
which lowering or theorem cites it.
That is the information GraphSpec contributes beyond the public tutorial syntax. It is not another training API; it is the architecture layer that preserves parameter ABI and sharing before runtime or verification lowering.
4.3.12. Proof Alignment Checks
GraphSpec also has a small but important proof side. The declarations below are compact alignment statements: they connect GraphSpec syntax to reference specs, deterministic parameter initialization, and the embedding of sequential primitives into DAG primitives.
The entrypoint NN.Entrypoint.GraphSpec re-exports the proof-facing names readers are most likely
to check first:
#check NN.GraphSpec.Models.mlp_interp_eq_spec_mlp_forward #check NN.GraphSpec.Models.mlp_detInitParams_eq_torchlean_linear_inits #check NN.GraphSpec.Primitive.toDAGPrimOp_specFwd_eq
These are worth knowing about for two reasons:
-
they confirm that GraphSpec is meant to support theorem statements, not only code generation,
-
and they illustrate the "extend op by op" development style that also shows up in the verified runtime and verification layers.
4.3.13. Best First Path
One concrete reading order:
-
Read the GraphSpec README.
-
Open the GraphSpec tutorial API.
-
Run:
lake exe torchlean graphspec --backend compiled -
Read the residual linear model API.
-
Read the ResNet-18 GraphSpec API.
That path moves from "author a typed MLP and lower it into the training API" to "author a real residual DAG with explicit sharing."
4.3.14. Where It Fits In The System
GraphSpec refines TorchLean's semantic model at the architecture boundary. In a Python codebase, architecture authoring and execution are often collapsed into the same object. GraphSpec separates them just enough to make semantics and proofs easier, without abandoning runnable models.
To inspect the implementation, start with the GraphSpec README, then
move to the sequential and DAG cores, then to the model zoo. The
GraphSpec to TorchLean API gives the lowering path into
TorchLean Seq, and the
GraphSpec TorchLean wrappers expose runtime model wrappers.
Next: Runtime and Autograd (execution), Graphs and IR (shared op-level graph), Verification (certificates and bounds).
4.3.15. References
-
TorchLean paper: https://arxiv.org/abs/2602.22631
-
ResNet reference: He et al., "Deep Residual Learning for Image Recognition" (CVPR 2016). https://arxiv.org/abs/1512.03385