RFC: fuse bias/activation epilogue through the einsum unmerge reshape (workload-dependent)#2415
Draft
czoli1976 wants to merge 1 commit into
Draft
Conversation
Pointwise conv / Einsum lower to OptMatMul -> IntoShape(unmerge) -> elementwise (per-channel bias add, ReLU). The matmul epilogue can absorb these (FusedSpec BinScalar / BinPerRow / BinPerCol) and the direct matmul->bias case already fuses, but the intervening unmerge reshape blocks it: OptMatMul::fuse's reshape-reorder only handled TypedBinOp / Cast with a uniform operand. This extends it to the codegen'd OptBinByScalar / OptBinUnicast forms and to a per-channel constant operand: the operand's single non-unary axis is tracked back through the reshape's AxesMapping to the matmul output axis, the constant is reshaped onto that axis, and a later fuse pass turns it into a BinPerRow / BinPerCol epilogue. Only fires when the axis lands on m or n; bails otherwise. Output is bit-identical (verified on 5 models). NOT for merge as-is (see PR description): a ~5-10% win on memory-bound streaming models (DeepFilterNet3) but a ~8-10% regression on compute-bound CNNs (MobileNetV2). Opening as an RFC to ask whether a cost-gated version is wanted. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This is an RFC / discussion draft — not proposed for merge as-is. It implements a real fusion, but the measurements show it's a net win only for memory-bound models and a regression for compute-bound ones, so the question is whether you'd want it behind a cost heuristic (or at all).
Observation
Pointwise conv and
Einsumlower to:The matmul epilogue can already absorb these (
FusedSpec::{BinScalar, BinPerRow, BinPerCol}), and the directmatmul → biascase does fuse inOptMatMul::fuse. But when theunmergereshape sits between them, fusion is blocked: the reshape-reorder branch inOptMatMul::fuseonly handledTypedBinOp/Castwith a uniform operand, not the codegen'dOptBinByScalar/OptBinUnicastper-channel forms.What this patch does
Extends that reorder to:
OptBinByScalar/OptBinUnicastforms (rebuilding aTypedBinOpto rewire), andAxesMapping(track_axis) to the matmul output axis, and the constant is reshaped onto that axis. A laterfusepass then turns it into aBinPerRow/BinPerColepilogue.It only fires when the tracked axis lands on
c_m_axis/c_n_axis(wherefuse_binarycan express it) and bails otherwise.Correctness
Bit-identical output (
max_abs_diff = 0) on every model I tested — DeepFilterNet3 (enc/erb_dec/df_dec), MobileNetV2 (98→44 epilogue ops fused), SqueezeNet (49→18).cargo test -p tract-corepasses (252).Performance — the catch
Paired benchmarks (
tract … -O bench, baseline vs this, interleaved to cancel thermal drift) on aarch64 macOS:encerb_dec/df_decThe MobileNet regression holds for bias-only (ReLU excluded), so it's the bias fusion itself. Intuition: fusing the epilogue into a compute-bound matmul's hot loop costs more than the cheap standalone vectorized pass it replaces, whereas on memory-bound matmuls (where the bias is a large fraction of runtime) fusing avoids a full output read-modify-write and wins.
Question
Is fusing bias/activation through the unmerge reshape something you'd want — gated by a cost heuristic (e.g. only when the matmul is memory-bound / low arithmetic intensity)? Or is it deliberately left undone for this reason? Happy to rework into a gated version (or drop it) based on your preference — I didn't want to guess a threshold from two data points.
🤖 Generated with Claude Code