Skip to content

Refactor ir.Function builders to use build_function from onnxscript 0.7.0 - #189

Merged
gramalingam merged 4 commits into
mainfrom
rama/functions
Apr 22, 2026
Merged

Refactor ir.Function builders to use build_function from onnxscript 0.7.0#189
gramalingam merged 4 commits into
mainfrom
rama/functions

Conversation

@gramalingam

Copy link
Copy Markdown
Collaborator

Summary

Replaces manual ir.Graph + GraphBuilder + ir.Function construction boilerplate with the new builder.build_function() utility from onnxscript 0.7.0. This eliminates ~25 lines of setup per function and automatically handles initializer lifting to Constant nodes.

Changes

  • pyproject.toml: Bump onnxscript requirement to >=0.7.0
  • causal_conv.py: Extract body into trace function; remove resolved TODO
  • linear_attention.py: Extract body into trace function; preserve per-variant input arity (see note below)
  • packed_multi_head_attention.py: Extract body; use op.Attention(...) with ir.Attr kwargs for ref_attr_name forwarding (eliminates raw ir.Node construction)
  • skip_layer_normalization.py: Both functions refactored; use op.LayerNormalization/op.RMSNormalization with ir.Attr kwargs for ref_attr_name (eliminates raw ir.Node construction and outdated docstring note)

Key findings

  • OpBuilder supports ir.Attr with ref_attr_name as kwargs — it flows through to ir.node() which accepts ir.Attr in SupportedAttrTypes. This eliminates the need for raw ir.Node construction in all three files that previously required it.
  • LinearAttention keeps per-variant arity because onnx-shape-inference (Python package) does a strict len(f.inputs) != len(node.inputs) check. ONNX's own C++ shape inference (onnx.shape_inference.infer_shapes) accepts trailing optional inputs fine, even in strict mode. A TODO is added to investigate relaxing this upstream.

Testing

All 2558 tests pass, 39 skipped (unchanged from baseline).

gramalingam and others added 4 commits April 22, 2026 16:48
….7.0

Replace manual ir.Graph + GraphBuilder + ir.Function construction
boilerplate with the new builder.build_function() utility. This
eliminates ~25 lines of setup per function and automatically handles
initializer lifting to Constant nodes.

Updated files:
- causal_conv.py: body extracted to trace function
- linear_attention.py: body extracted, conditional inputs preserved
- packed_multi_head_attention.py: body extracted, raw ir.Node via
  op._builder._graph.append() for ref_attr_name forwarding
- skip_layer_normalization.py: both functions refactored similarly
- pyproject.toml: bumped onnxscript requirement to >=0.7.0

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: G Ramalingam <grama@microsoft.com>
Replace *args unpacking with named parameters and None entries.
The function signature is now stable (6 formals) across all
update_rule variants. Absent optional inputs (decay, beta) get
placeholder formals via build_function; the trace function
receives None and branches naturally with 'if decay_v is not None'.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: G Ramalingam <grama@microsoft.com>
- skip_layer_normalization: Replace raw ir.Node with op.LayerNormalization
  and op.RMSNormalization, passing ir.Attr objects with ref_attr_name
  directly as kwargs. OpBuilder passes them through to ir.node() correctly.
  Remove outdated docstring note about OpBuilder limitation.

- packed_multi_head_attention: Replace raw ir.Node with op.Attention,
  passing ir.Attr objects with ref_attr_name for num_heads and scale.

- linear_attention: Revert to per-variant input arity. The function is
  specialized per-model, so only inputs used by the update_rule are
  declared. This matches call sites (Mamba2/Bamba pass 5 args for
  'gated', GatedDeltaNet passes 6 for 'gated_delta'). Shape inference
  does strict arity checking.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: G Ramalingam <grama@microsoft.com>
The strict arity check is in the Python onnx-shape-inference package
(onnx_shape_inference._functions.infer_function_call_output_shapes),
not in ONNX's C++ shape inference.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: G Ramalingam <grama@microsoft.com>
@github-actions

Copy link
Copy Markdown

Performance Comparison

Comparing fdd121940601c1

Model Metric Baseline Current Delta
bert (feature-extraction) model_size_bytes 359 KB 359 KB +0.0%
bert (feature-extraction) num_nodes 60 60 +0.0%
falcon model_size_bytes 364 KB 364 KB +0.0%
falcon num_nodes 66 66 +0.0%
gemma2 model_size_bytes 428 KB 428 KB +0.0%
gemma2 num_nodes 107 107 +0.0%
gpt2 model_size_bytes 388 KB 388 KB +0.0%
gpt2 num_nodes 53 53 +0.0%
llama model_size_bytes 425 KB 425 KB +0.0%
llama num_nodes 61 61 +0.0%
llama (static-cache) model_size_bytes 425 KB 425 KB +0.0%
llama (static-cache) num_nodes 58 58 +0.0%
mamba (ssm-text-generation) model_size_bytes 360 KB 360 KB +0.0%
mamba (ssm-text-generation) num_nodes 98 98 +0.0%
phi3 model_size_bytes 421 KB 421 KB +0.0%
phi3 num_nodes 59 59 +0.0%
phi3 (static-cache) model_size_bytes 421 KB 421 KB +0.0%
phi3 (static-cache) num_nodes 56 56 +0.0%
qwen2 model_size_bytes 425 KB 425 KB +0.0%
qwen2 num_nodes 61 61 +0.0%
qwen2 (static-cache) model_size_bytes 425 KB 425 KB +0.0%
qwen2 (static-cache) num_nodes 58 58 +0.0%
qwen3_5_moe (hybrid-text-generation) model_size_bytes 506 KB 506 KB +0.0%
qwen3_5_moe (hybrid-text-generation) num_nodes 275 275 +0.0%
qwen3_5_text (hybrid-text-generation) model_size_bytes 458 KB 458 KB +0.0%
qwen3_5_text (hybrid-text-generation) num_nodes 129 129 +0.0%
qwen3_5_vl (hybrid-qwen-vl) model_size_bytes 977 KB 977 KB +0.0%
qwen3_5_vl (hybrid-qwen-vl) num_nodes 408 408 +0.0%
t5 (seq2seq) model_size_bytes 836 KB 836 KB +0.0%
t5 (seq2seq) num_nodes 166 166 +0.0%
whisper (speech-to-text) model_size_bytes 1008 KB 1008 KB +0.0%
whisper (speech-to-text) num_nodes 128 128 +0.0%

No performance regressions.

@justinchuby justinchuby left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! This reminds me we can also update the call sites now.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Refactors Mobius’ standard-ONNX ir.Function fallback builders to use onnxscript._internal.builder.build_function() (onnxscript >= 0.7.0), removing manual ir.Graph/GraphBuilder boilerplate while preserving the same function signatures and attribute-forwarding behavior used by InlinePass expansion.

Changes:

  • Bump onnxscript dependency to >=0.7.0.
  • Refactor multiple ir.Function factories to define a body(op, ...) trace function and build via builder.build_function(...).
  • Replace prior raw ir.Node construction patterns with OpBuilder calls using ir.Attr(..., ref_attr_name=...) where needed.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.

Show a summary per file
File Description
pyproject.toml Updates the minimum onnxscript version to support build_function().
src/mobius/functions/causal_conv.py Switches to build_function() with a traced body, keeping the same function inputs/outputs and activation attribute.
src/mobius/functions/linear_attention.py Switches to build_function() and preserves per-variant input arity while keeping attribute forwarding.
src/mobius/functions/packed_multi_head_attention.py Switches to build_function() and emits op.Attention(...) with forwarded ir.Attr kwargs.
src/mobius/functions/skip_layer_normalization.py Switches to build_function() and uses op.LayerNormalization/op.RMSNormalization with forwarded epsilon via ir.Attr.

@github-actions

Copy link
Copy Markdown

🏗️ Architecture Diff

Comparing fdd121940601c1

Model Sub-model Changes Status
bert (feature-extraction) model 0
falcon model 0
gemma2 model 0
gemma4 (gemma4) decoder 0
gemma4 (gemma4) embedding 0
gemma4 (gemma4) vision 0
gemma4_text model 0
gpt2 model 0
llama model 0
llama (static-cache) model 0
mamba (ssm-text-generation) model 0
phi3 model 0
phi3 (static-cache) model 0
qwen model 0
qwen (static-cache) model 0
qwen2 model 0
qwen2 (static-cache) model 0
qwen2_moe model 0
qwen2_moe (static-cache) model 0
qwen3 model 0
qwen3 (static-cache) model 0
qwen3_5_moe (hybrid-text-generation) model 0
qwen3_5_text (hybrid-text-generation) model 0
qwen3_5_vl (hybrid-qwen-vl) decoder 0
qwen3_5_vl (hybrid-qwen-vl) embedding 0
qwen3_5_vl (hybrid-qwen-vl) vision 0
qwen3_moe model 0
qwen3_moe (static-cache) model 0
qwen3_next (hybrid-text-generation) model 0
t5 (seq2seq) decoder 0
t5 (seq2seq) encoder 0
whisper (speech-to-text) decoder 0
whisper (speech-to-text) encoder 0

No architecture changes detected.


Legend: ⚪ No change · 🔵 Minor (attrs/inits) · 🟡 Moderate (nodes added/removed) · 🔴 Major (interface changed)

@codecov

codecov Bot commented Apr 22, 2026

Copy link
Copy Markdown

The author of this PR, gramalingam, is not an activated member of this organization on Codecov.
Please activate this user on Codecov to display this PR comment.
Coverage data is still being uploaded to Codecov.io for purposes of overall coverage calculations.
Please don't hesitate to email us at support@codecov.io with any questions.

@gramalingam
gramalingam merged commit c0dde2e into main Apr 22, 2026
26 of 27 checks passed
@gramalingam
gramalingam deleted the rama/functions branch April 22, 2026 19:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants