Skip to content

Fold static weight layout chains after weight loading - #788

Closed
titaiwangms wants to merge 1 commit into
mainfrom
titaiwang/fold-static-weight-layouts
Closed

titaiwangms wants to merge 1 commit into
mainfrom
titaiwang/fold-static-weight-layouts

Conversation

@titaiwangms

Copy link
Copy Markdown
Contributor

Summary

Add a model-independent FoldWeightLayoutPass to the post-weight-loading pipeline. It lazily folds initializer-backed Reshape/Transpose chains, including higher-rank packed expert weights, scales, and zero points that the existing 2-D transpose pass does not handle.

  • Preserve dtype and raw values without arithmetic or casts; do not eagerly read weight payloads.
  • Accept static initializer and Constant(value/value_ints) shape vectors, including ONNX zero/inferred-dimension semantics.
  • Leave dynamic, overridable, shared, and graph-output sources untouched so tied tables are not duplicated.
  • Preserve output names and remove now-dead folded inputs in their owning graph, including subgraphs.
  • Add value, laziness, sharing, invalid-input, subgraph, and package-persistence coverage, including BF16 special-value bits.

Independence from #787

This PR targets main directly and does not contain or require the Gemma4 VLM commit from #787. The dtype helper, ModelPackage.save/load, and post-weight pipeline already exist on main.

The existing main pass order is preserved: lift constants, fold concatenations, fold transposes, run the new layout pass, then remove dead nodes. The VLM-specific pipeline reordering, runtime gates, and weight-loading changes are not included.

Validation

Validated in an isolated worktree based on main (d69efe03):

  • 236 passed across the new layout tests, existing concat/transpose/dtype tests, package tests, and component-quantization loading tests.
  • Scoped Ruff format/check and git diff --check pass.
  • The new pass passes MyPy. Checking _optimizations.py also reports an existing rules_or_pass assignment-type error; the identical diagnostic was reproduced against the unmodified origin/main file using MyPy's shadow-file baseline check. This PR does not change that loop or suppress the error.

Local GPU experiment

Separately applied the identical pass to a frozen Gemma4-26B-A4B-IT INT4 export with 30 GQA nodes (do_rotary=1). This is a frozen-artifact A/B experiment using the existing custom native runtime, not a fresh main model export or a claim that the Gemma4-specific runtime work is included here.

  • Nodes: 1,739 -> 1,469; Transpose: 90 -> 0; Reshape: 450 -> 270.
  • All 90 persisted weight-layout results match independent original-weight NumPy references bit-for-bit.
  • Full-vocabulary logits match bit-for-bit for 2K prefill plus eight cached-decode steps.
  • All 20 requests match the original 512-token outputs at 2K/8K/16K/32K input lengths.
  • Shared KV and CUDA Graph enabled on the same A100; off-timing diagnostics confirm four captures and 24 replays.

Three measured requests per context, after two warmups:

Input tokens TTFT ms, before -> after Decode tok/s, before -> after E2E tok/s, before -> after Sampled peak GiB, before -> after
2,048 131.11 -> 130.54 104.72 -> 104.79 102.19 -> 102.26 33.76 -> 32.86
8,192 493.99 -> 493.48 87.87 -> 88.06 81.15 -> 81.32 38.76 -> 37.73
16,384 1179.34 -> 1182.75 71.91 -> 72.56 61.80 -> 62.25 44.28 -> 44.75
32,768 3435.59 -> 3433.73 53.83 -> 53.76 39.60 -> 39.57 60.72 -> 59.75

Observed model-load time changed from approximately 43-44 seconds to 4.6-5.0 seconds. These are single load observations, not a controlled cold-I/O benchmark. Decode/TTFT are broadly unchanged; the three trials do not establish statistical significance. VRAM is a 20 ms sampled lower bound and does not consistently decrease.

This checks layout-only equivalence. Previously failed strict HuggingFace numerical-parity gates are unchanged and unwaived.

Add a generic lazy Reshape/Transpose initializer pass for higher-rank
weight layouts that the existing two-dimensional transpose pass misses.
Preserve dtype bits, output names, and tied-table sharing while accepting
static Constant shape vectors and cleaning dead inputs in their own graph.

Integrate the pass into the existing main post-weight pipeline without
including the Gemma4 VLM changes. Cover values, laziness, invalid shapes,
subgraph ownership, and package persistence, including BF16 special bits.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 9a2a5b82-7cd3-4a76-bb94-0998527ea723
Signed-off-by: titaiwang <titaiwang@microsoft.com>
@titaiwangms
titaiwangms requested review from a team and a balanced review from Copilot October 23, 2026 21:33
@github-actions

Copy link
Copy Markdown

🏗️ Architecture Diff

Comparing d69efe03 → 09d2ec86

Model Sub-model Changes Status

No architecture changes detected. ✅


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

@github-actions

Copy link
Copy Markdown

Performance Comparison

Comparing d69efe03 → 09d2ec86

Model Metric Baseline Current Delta
bert (feature-extraction) model_size_bytes 359 KB 359 KB +0.0% ⚪
bert (feature-extraction) num_nodes 68 68 +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 105 105 +0.0% ⚪
gpt2 model_size_bytes 324 KB 324 KB +0.0% ⚪
gpt2 num_nodes 54 54 +0.0% ⚪
llama model_size_bytes 425 KB 425 KB +0.0% ⚪
llama num_nodes 60 60 +0.0% ⚪
llama (static-cache) model_size_bytes 425 KB 425 KB +0.0% ⚪
llama (static-cache) num_nodes 56 56 +0.0% ⚪
mamba (ssm-text-generation) model_size_bytes 296 KB 296 KB +0.0% ⚪
mamba (ssm-text-generation) num_nodes 94 94 +0.0% ⚪
phi3 model_size_bytes 421 KB 421 KB +0.0% ⚪
phi3 num_nodes 58 58 +0.0% ⚪
phi3 (static-cache) model_size_bytes 421 KB 421 KB +0.0% ⚪
phi3 (static-cache) num_nodes 54 54 +0.0% ⚪
qwen2 model_size_bytes 425 KB 425 KB +0.0% ⚪
qwen2 num_nodes 60 60 +0.0% ⚪
qwen2 (static-cache) model_size_bytes 425 KB 425 KB +0.0% ⚪
qwen2 (static-cache) num_nodes 56 56 +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 269 269 +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 131 131 +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 461 461 +0.0% ⚪
t5 (seq2seq) model_size_bytes 836 KB 836 KB +0.0% ⚪
t5 (seq2seq) num_nodes 176 176 +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.

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.

🟡 Changes recommended

Standalone folding leaves dead parent-owned initializers registered when processing subgraph captures, allowing duplicate weight serialization.

1 open issue
What changed in this PR

Adds model-independent folding of static weight-layout chains after weight loading, extending existing optimizations to higher-rank tensors without including the Gemma4-specific work from #787.

Changes:

  • Lazily folds initializer-backed Reshape/Transpose chains while preserving dtype and values.
  • Integrates the pass into the existing post-weight-loading pipeline.
  • Adds coverage for layout values, laziness, sharing, invalid inputs, subgraphs, and package persistence.
File Description
src/​mobius/​_passes/​_fold_weight_layout.py Implements lazy static weight-layout folding and input cleanup.
src/​mobius/​_passes/​_fold_weight_layout_test.py Adds correctness, preservation, and persistence tests.
src/​mobius/​_passes/​__init__.py Exports and documents the new pass.
src/​mobius/​_optimizations.py Adds the pass before post-weight dead-code removal.

Review effort: Balanced

Comment thread src/mobius/_passes/_fold_weight_layout.py
@titaiwangms

Copy link
Copy Markdown
Contributor Author

Superseded by #754, which now contains the validated generic weight-layout folding and review fixes. #787 contains only shared Gemma4 modeling and is stacked on #754. Original branch/history is retained; no numerical gate is waived.

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