Preserve ExportedProgram dynamic input shape constraints in .pte for runtime/backend validation
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 5k
- Forks
- 1.2k
- Avg merge
- 2d 10h
- Merged PRs (30d)
- 581
Description
🚀 The feature, motivation and pitch
Problem
torch.export can represent a rich input shape contract for dynamic-shape models. This contract is enforced when running:
exported_program.module(check_guards=True)
because the returned module includes guard logic, such as _guards_fn, that validates real inputs before executing the graph.
However, after lowering to ExecuTorch and serializing to .pte, only a much weaker form of shape metadata appears to survive:
- Tensor.sizes
- Tensor.shape_dynamism
- Tensor.dim_order
For DYNAMIC_BOUND, Tensor.sizes stores the upper-bound shape. The richer input shape contract from ExportedProgram does not appear to have an equivalent runtime representation in the .pte.
Example
Given:
half_height = torch.export.Dim("half_height", min=4, max=8)
height = 2 * half_height
dynamic_shapes = (
{
2: height,
3: torch.export.Dim("width", min=8, max=16),
},
)
The exported program contains symbolic placeholder shapes such as:
x: [1, 3, 2*s87, s46]
and range constraints such as:
2*s87: min=8, max=16
s87: min=4, max=8
s46: min=8, max=16
When executing the exported module eagerly, the guard logic rejects invalid inputs. For example, an input with height 9 is rejected because 9 cannot be represented as 2*s87 for an integer s87:
Expected input *args[0].shape[2] = 9 to be of the form 2*s87, where s87 is an integer. However after serializing to .pte, the input tensor metadata contains only:
sizes=[1, 3, 16, 16]
shape_dynamism=DYNAMIC_BOUND
This preserves the upper bound, but not the fact that height must be even, nor the lower bound, symbolic expression, or root-symbol range.
Why this matters
Backends that support dynamic shapes may need to validate input shapes before compilation, specialization, or execution.
If the .pte only exposes upper-bound tensor sizes, a backend cannot reliably recover the original valid input shape domain. This can lead to late failures, poor error messages, or backend/compiler crashes when an invalid dynamic input shape is accepted by ExecuTorch but rejected deeper in backend-specific code.
This is not specific to one backend. Any delegate backend that consumes a dynamic-shape lowered graph may need access to the same input shape contract that ExportedProgram.module(check_guards=True) enforces in eager execution.
Question
What is the intended mechanism for preserving and enforcing the ExportedProgram input shape contract after lowering to ExecuTorch?
Should ExecuTorch:
- Serialize a normalized input shape-constraint representation into the .pte?
- Preserve
ExportedProgram.range_constraintsplus symbolic placeholder shape expressions in the runtime program? - Provide a standard backend API for extracting and serializing this contract into delegate payloads?
- Provide runtime utilities for validating actual inputs against the exported shape contract before delegate execution?
- Intentionally expose only
Tensor.shape_dynamismand upper-boundTensor.sizes, leaving full validation to individual backends?
Desired outcome
It would be helpful to clarify or standardize how dynamic shape constraints are preserved across:
torch.export.ExportedProgram -> ExecuTorch lowering -> .pte serialization -> runtime/backend execution
Ideally, .pte or backend delegate metadata would preserve enough information to validate the same input shape contract enforced by ExportedProgram.module(check_guards=True), including:
- rank checks
- static dimensions
- min/max range constraints
- symbolic equality relationships
- derived symbolic expressions such as
2*s - guard-derived constraints that affect valid input shapes
This does not necessarily mean serializing _guards_fn itself. A normalized, runtime-friendly shape-constraint representation may be more appropriate.
Alternatives
No response
Additional context
No response
RFC (Optional)
No response
cc @larryliu0820 @JacobSzwejbka @lucylq
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by tracing the ExportedProgram range_constraints and symbolic placeholder shapes through ExecuTorch lowering and .pte serialization, then examine runtime/backend execution. Done means defining and documenting whether the serialized program or delegate metadata preserves enough of the input shape contract for validation, including relationships and bounds.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python, pytorch
- Domain
- ai, backend-api-design
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Needs clarification
- Newbie friendliness
- 35/100